fable 3.0.124 → 3.0.126

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. package/debug/Harness.js +48 -24
  2. package/dist/fable.compatible.js +329 -55
  3. package/dist/fable.compatible.min.js +2 -2
  4. package/dist/fable.compatible.min.js.map +1 -1
  5. package/dist/fable.js +304 -30
  6. package/dist/fable.min.js +2 -2
  7. package/dist/fable.min.js.map +1 -1
  8. package/package.json +2 -2
  9. package/source/Fable.js +18 -0
  10. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Base.js +55 -0
  11. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ExpressionTokenizer.js +158 -0
  12. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-FunctionMap.json +22 -0
  13. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Linter.js +180 -0
  14. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Postfix.js +626 -0
  15. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-SolvePostfixedExpression.js +125 -0
  16. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-TokenMap.json +75 -0
  17. package/source/services/Fable-Service-ExpressionParser.js +210 -0
  18. package/source/services/Fable-Service-Math.js +30 -1
  19. package/source/services/Fable-Service-MetaTemplate/MetaTemplate-StringParser.js +23 -14
  20. package/source/services/Fable-Service-MetaTemplate.js +4 -2
  21. package/source/services/Fable-Service-Template.js +1 -1
  22. package/test/ExpressionParser_tests.js +184 -0
  23. package/test/MetaTemplating_tests.js +41 -1
package/dist/fable.js CHANGED
@@ -3017,15 +3017,15 @@ this.connectFable(this);// --> Bootstrapping of fable into the Service Manager i
3017
3017
  // Initialization Phase 2: Map in the default services.
3018
3018
  // They will then be available in the Default service provider set as well.
3019
3019
  this.connectPreinitServiceProviderInstance(this.UUID);this.connectPreinitServiceProviderInstance(this.Logging);this.connectPreinitServiceProviderInstance(this.SettingsManager);// Initialize and instantiate the default baked-in Data Arithmatic service
3020
- this.addAndInstantiateServiceType('EnvironmentData',require('./services/Fable-Service-EnvironmentData.js'));this.addServiceType('Template',require('./services/Fable-Service-Template.js'));this.addServiceType('MetaTemplate',require('./services/Fable-Service-MetaTemplate.js'));this.addServiceType('Anticipate',require('./services/Fable-Service-Anticipate.js'));this.addAndInstantiateServiceType('Dates',require('./services/Fable-Service-DateManipulation.js'));this.addAndInstantiateServiceType('DataFormat',require('./services/Fable-Service-DataFormat.js'));this.addAndInstantiateServiceType('DataGeneration',require('./services/Fable-Service-DataGeneration.js'));this.addAndInstantiateServiceType('Utility',require('./services/Fable-Service-Utility.js'));this.addAndInstantiateServiceType('Math',require('./services/Fable-Service-Math.js'));this.addServiceType('RestClient',require('./services/Fable-Service-RestClient.js'));this.addServiceType('Manifest',require('manyfest'));this.addServiceType('ObjectCache',require('cachetrax'));this.addAndInstantiateServiceType('ProgressTime',require('./services/Fable-Service-ProgressTime.js'));this.addServiceType('ProgressTrackerSet',require('./services/Fable-Service-ProgressTrackerSet.js'));this.addServiceType('Operation',require('./services/Fable-Service-Operation.js'));this.addServiceType('CSVParser',require('./services/Fable-Service-CSVParser.js'));this.addServiceType('FilePersistence',require('./services/Fable-Service-FilePersistence.js'));}/* State Accessors */get isFable(){return true;}get settings(){return this.SettingsManager.settings;}get settingsManager(){return this.SettingsManager;}// For backwards compatibility
3021
- getUUID(){return this.UUID.getUUID();}newAnticipate(){return this.instantiateServiceProviderWithoutRegistration('Anticipate');}/* Service Manager Methods */addServiceType(pServiceType,pServiceClass){if(this.servicesMap.hasOwnProperty(pServiceType)){// TODO: Check if any services are running?
3020
+ this.addAndInstantiateServiceType('EnvironmentData',require('./services/Fable-Service-EnvironmentData.js'));this.addServiceType('Template',require('./services/Fable-Service-Template.js'));this.addServiceType('MetaTemplate',require('./services/Fable-Service-MetaTemplate.js'));this.addServiceType('Anticipate',require('./services/Fable-Service-Anticipate.js'));this.addAndInstantiateServiceType('Dates',require('./services/Fable-Service-DateManipulation.js'));this.addAndInstantiateServiceType('DataFormat',require('./services/Fable-Service-DataFormat.js'));this.addAndInstantiateServiceType('DataGeneration',require('./services/Fable-Service-DataGeneration.js'));this.addAndInstantiateServiceType('Utility',require('./services/Fable-Service-Utility.js'));this.addAndInstantiateServiceType('Math',require('./services/Fable-Service-Math.js'));this.addServiceType('ExpressionParser',require('./services/Fable-Service-ExpressionParser.js'));this.addServiceType('RestClient',require('./services/Fable-Service-RestClient.js'));this.addServiceType('Manifest',require('manyfest'));this.addServiceType('ObjectCache',require('cachetrax'));this.addAndInstantiateServiceType('ProgressTime',require('./services/Fable-Service-ProgressTime.js'));this.addServiceType('ProgressTrackerSet',require('./services/Fable-Service-ProgressTrackerSet.js'));this.addServiceType('Operation',require('./services/Fable-Service-Operation.js'));this.addServiceType('CSVParser',require('./services/Fable-Service-CSVParser.js'));this.addServiceType('FilePersistence',require('./services/Fable-Service-FilePersistence.js'));}/* State Accessors */get isFable(){return true;}get settings(){return this.SettingsManager.settings;}get settingsManager(){return this.SettingsManager;}// For backwards compatibility
3021
+ getUUID(){return this.UUID.getUUID();}newAnticipate(){return this.instantiateServiceProviderWithoutRegistration('Anticipate');}newManyfest(pManifestDefinition){return this.instantiateServiceProviderWithoutRegistration('Manifest',pManifestDefinition);}/* Service Manager Methods */addServiceType(pServiceType,pServiceClass){if(this.servicesMap.hasOwnProperty(pServiceType)){// TODO: Check if any services are running?
3022
3022
  this.log.warn("Adding a service type [".concat(pServiceType,"] that already exists. This will change the default class prototype for this service."));}else{// Add the container for instantiated services to go in
3023
3023
  this.servicesMap[pServiceType]={};// Add the type to the list of types
3024
3024
  this.serviceTypes.push(pServiceType);}// Using the static member of the class is a much more reliable way to check if it is a service class than instanceof
3025
3025
  if(typeof pServiceClass=='function'&&pServiceClass.isFableService){// Add the class to the list of classes
3026
3026
  this.serviceClasses[pServiceType]=pServiceClass;}else{// Add the base class to the list of classes
3027
3027
  this.log.error("Attempted to add service type [".concat(pServiceType,"] with an invalid class. Using base service class, which will not crash but won't provide meaningful services."));this.serviceClasses[pServiceType]=libFableServiceBase;}return this.serviceClasses[pServiceType];}addServiceTypeIfNotExists(pServiceType,pServiceClass){if(!this.servicesMap.hasOwnProperty(pServiceType)){return this.addServiceType(pServiceType,pServiceClass);}else{return this.serviceClasses[pServiceType];}}// This is for the services that are meant to run mostly single-instance so need a default at initialization
3028
- addAndInstantiateServiceType(pServiceType,pServiceClass){this.addServiceType(pServiceType,pServiceClass);return this.instantiateServiceProvider(pServiceType,{},"".concat(pServiceType,"-Default"));}// Some services expect to be overloaded / customized class.
3028
+ addAndInstantiateServiceType(pServiceType,pServiceClass){this.addServiceType(pServiceType,pServiceClass);return this.instantiateServiceProvider(pServiceType,{},"".concat(pServiceType,"-Default"));}addAndInstantiateServiceTypeIfNotExists(pServiceType,pServiceClass){if(!this.servicesMap.hasOwnProperty(pServiceType)){return this.instantiateServiceProvider(pServiceType,{},"".concat(pServiceType,"-Default"));}else{return this.serviceClasses[pServiceType];}}// Some services expect to be overloaded / customized class.
3029
3029
  instantiateServiceProviderFromPrototype(pServiceType,pOptions,pCustomServiceHash,pServicePrototype){// Instantiate the service
3030
3030
  let tmpService=new pServicePrototype(this,pOptions,pCustomServiceHash);if(this.extraServiceInitialization){tmpService=this.extraServiceInitialization(tmpService);}// Add the service to the service map
3031
3031
  this.servicesMap[pServiceType][tmpService.Hash]=tmpService;// If this is the first service of this type, make it the default
@@ -3044,7 +3044,7 @@ this.servicesMap[tmpServiceType][tmpServiceHash]=pServiceInstance;// If this is
3044
3044
  if(!this.services.hasOwnProperty(tmpServiceType)){this.setDefaultServiceInstantiation(tmpServiceType,tmpServiceHash,false);}return pServiceInstance;}setDefaultServiceInstantiation(pServiceType,pServiceHash,pOverwriteService){// Overwrite services by default, unless told not to
3045
3045
  let tmpOverwriteService=typeof pOverwriteService==='undefined'?true:pOverwriteService;// Make sure the service exists
3046
3046
  if(this.servicesMap[pServiceType].hasOwnProperty(pServiceHash)){if(!this.hasOwnProperty(pServiceType)||tmpOverwriteService){this[pServiceType]=this.servicesMap[pServiceType][pServiceHash];}if(!this.services.hasOwnProperty(pServiceType)||tmpOverwriteService){this.services[pServiceType]=this.servicesMap[pServiceType][pServiceHash];}return true;}return false;}}// This is for backwards compatibility
3047
- function autoConstruct(pSettings){return new Fable(pSettings);}module.exports=Fable;module.exports.new=autoConstruct;module.exports.LogProviderBase=libFableLog.LogProviderBase;module.exports.ServiceProviderBase=libFableServiceBase;module.exports.CoreServiceProviderBase=libFableServiceBase.CoreServiceProviderBase;module.exports.precedent=libFableSettings.precedent;},{"./services/Fable-Service-Anticipate.js":128,"./services/Fable-Service-CSVParser.js":129,"./services/Fable-Service-DataFormat.js":130,"./services/Fable-Service-DataGeneration.js":132,"./services/Fable-Service-DateManipulation.js":133,"./services/Fable-Service-EnvironmentData.js":134,"./services/Fable-Service-FilePersistence.js":135,"./services/Fable-Service-Math.js":136,"./services/Fable-Service-MetaTemplate.js":137,"./services/Fable-Service-Operation.js":141,"./services/Fable-Service-ProgressTime.js":142,"./services/Fable-Service-ProgressTrackerSet.js":144,"./services/Fable-Service-RestClient.js":145,"./services/Fable-Service-Template.js":146,"./services/Fable-Service-Utility.js":147,"cachetrax":22,"fable-log":50,"fable-serviceproviderbase":51,"fable-settings":54,"fable-uuid":56,"manyfest":80}],128:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');class FableServiceAnticipate extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='AsyncAnticipate';// The queue of operations waiting to run.
3047
+ function autoConstruct(pSettings){return new Fable(pSettings);}module.exports=Fable;module.exports.new=autoConstruct;module.exports.LogProviderBase=libFableLog.LogProviderBase;module.exports.ServiceProviderBase=libFableServiceBase;module.exports.CoreServiceProviderBase=libFableServiceBase.CoreServiceProviderBase;module.exports.precedent=libFableSettings.precedent;},{"./services/Fable-Service-Anticipate.js":128,"./services/Fable-Service-CSVParser.js":129,"./services/Fable-Service-DataFormat.js":130,"./services/Fable-Service-DataGeneration.js":132,"./services/Fable-Service-DateManipulation.js":133,"./services/Fable-Service-EnvironmentData.js":134,"./services/Fable-Service-ExpressionParser.js":135,"./services/Fable-Service-FilePersistence.js":143,"./services/Fable-Service-Math.js":144,"./services/Fable-Service-MetaTemplate.js":145,"./services/Fable-Service-Operation.js":149,"./services/Fable-Service-ProgressTime.js":150,"./services/Fable-Service-ProgressTrackerSet.js":152,"./services/Fable-Service-RestClient.js":153,"./services/Fable-Service-Template.js":154,"./services/Fable-Service-Utility.js":155,"cachetrax":22,"fable-log":50,"fable-serviceproviderbase":51,"fable-settings":54,"fable-uuid":56,"manyfest":80}],128:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');class FableServiceAnticipate extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='AsyncAnticipate';// The queue of operations waiting to run.
3048
3048
  this.operationQueue=[];this.erroredOperations=[];this.executingOperationCount=0;this.completedOperationCount=0;this.callDepth=0;this.maxOperations=1;this.lastError=undefined;this.waitingFunctions=[];}checkQueue(){// This could be combined with the last else if stanza but the logic for errors and non-errors would be blended and more complex to follow so keeping it unrolled.
3049
3049
  if(this.lastError){// If there are no operations left, and we have waiting functions, call them.
3050
3050
  for(let i=0;i<this.waitingFunctions.length;i++){//this.log.trace('Calling waiting function.')
@@ -3340,7 +3340,272 @@ this.plugin_advancedFormat=require('dayjs/plugin/advancedFormat');this.dayJS.ext
3340
3340
  // You would do the following:
3341
3341
  // const localeDE = require('dayjs/locale/de');
3342
3342
  // _Fable.Dates.dayJS.locale('de');
3343
- }}module.exports=DateManipulation;},{"dayjs":28,"dayjs/plugin/advancedFormat":29,"dayjs/plugin/isoWeek":30,"dayjs/plugin/relativeTime":31,"dayjs/plugin/timezone":32,"dayjs/plugin/utc":33,"dayjs/plugin/weekOfYear":34,"dayjs/plugin/weekday":35,"fable-serviceproviderbase":51}],134:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');class FableServiceEnvironmentData extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='EnvironmentData';this.Environment="node.js";}}module.exports=FableServiceEnvironmentData;},{"fable-serviceproviderbase":51}],135:[function(require,module,exports){(function(process){(function(){const libFableServiceBase=require('fable-serviceproviderbase');const libFS=require('fs');const libPath=require('path');const libReadline=require('readline');class FableServiceFilePersistence extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='FilePersistence';if(!this.options.hasOwnProperty('Mode')){this.options.Mode=parseInt('0777',8)&~process.umask();}this.libFS=libFS;this.libPath=libPath;this.libReadline=libReadline;}joinPath(){return libPath.resolve(...arguments);}existsSync(pPath){return libFS.existsSync(pPath);}exists(pPath,fCallback){let tmpFileExists=this.existsSync(pPath);;return fCallback(null,tmpFileExists);}appendFileSync(pFileName,pAppendContent,pOptions){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.appendFileSync(pFileName,pAppendContent,tmpOptions);}deleteFileSync(pFileName){return libFS.unlinkSync(pFileName);}deleteFolderSync(pFileName){return libFS.rmdirSync(pFileName);}readFileSync(pFilePath,pOptions){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.readFileSync(pFilePath,tmpOptions);}readFile(pFilePath,pOptions,fCallback){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.readFile(pFilePath,tmpOptions,fCallback);}writeFileSync(pFileName,pFileContent,pOptions){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.writeFileSync(pFileName,pFileContent,tmpOptions);}writeFileSyncFromObject(pFileName,pObject){return this.writeFileSync(pFileName,JSON.stringify(pObject,null,4));}writeFileSyncFromArray(pFileName,pFileArray){if(!Array.isArray(pFileArray)){this.log.error("File Persistence Service attempted to write ".concat(pFileName," from array but the expected array was not an array (it was a ").concat(typeof pFileArray,")."));return Error('Attempted to write ${pFileName} from array but the expected array was not an array (it was a ${typeof(pFileArray)}).');}else{for(let i=0;i<pFileArray.length;i++){return this.appendFileSync(pFileName,"".concat(pFileArray[i],"\n"));}}}writeFile(pFileName,pFileContent,pOptions,fCallback){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.writeFile(pFileName,pFileContent,tmpOptions,fCallback);}lineReaderFactory(pFilePath,fOnLine,fOnComplete,fOnError){let tmpLineReader={};if(typeof pFilePath!='string'){return false;}tmpLineReader.filePath=pFilePath;tmpLineReader.fileStream=libFS.createReadStream(tmpLineReader.filePath);tmpLineReader.reader=libReadline.createInterface({input:tmpLineReader.fileStream,crlfDelay:Infinity});if(typeof fOnError==='function'){tmpLineReader.reader.on('error',fOnError);}tmpLineReader.reader.on('line',typeof fOnLine==='function'?fOnLine:()=>{});if(typeof fOnComplete==='function'){tmpLineReader.reader.on('close',fOnComplete);}return tmpLineReader;}// Folder management
3343
+ }}module.exports=DateManipulation;},{"dayjs":28,"dayjs/plugin/advancedFormat":29,"dayjs/plugin/isoWeek":30,"dayjs/plugin/relativeTime":31,"dayjs/plugin/timezone":32,"dayjs/plugin/utc":33,"dayjs/plugin/weekOfYear":34,"dayjs/plugin/weekday":35,"fable-serviceproviderbase":51}],134:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');class FableServiceEnvironmentData extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='EnvironmentData';this.Environment="node.js";}}module.exports=FableServiceEnvironmentData;},{"fable-serviceproviderbase":51}],135:[function(require,module,exports){const{PE}=require('big.js');const libFableServiceBase=require('fable-serviceproviderbase');/* Trying a different pattern for this service ...
3344
+ *
3345
+ * This service is a simple expression parser that can handle math expressions, with magic(tm) lookup of addresses with a manifest.
3346
+ *
3347
+ * Each method works multiple ways.
3348
+ *
3349
+ * 1. You can pass in a results object, and, it will put the state for that step outcome into the results object.
3350
+ * 2. It always returns the state, and works without the results object.
3351
+ *
3352
+ *
3353
+ * Learned a lot from this npm package: https://www.npmjs.com/package/math-expression-evaluator
3354
+ * And its related code at github: https://github.com/bugwheels94/math-expression-evaluator
3355
+ *
3356
+ * There were two problems with the codebase...
3357
+ *
3358
+ * First, the code was very unreadable and determining it was correct or extending it
3359
+ * was out of the question.
3360
+ *
3361
+ * Second, and this is a larger issue, is that we need the expressions to be parsed as
3362
+ * arbitrary precision. When I determined that extending the library to use string-based
3363
+ * numbers and an arbitrary precision library as the back-end would have taken a significantly
3364
+ * longer amount of time than just writing the parser from scratch, et voila.
3365
+ */class FableServiceExpressionParser extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.tokenMap=require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-TokenMap.json');// This precedence is higher than defined in our token map
3366
+ this.tokenMaxPrecedence=5;this.functionMap=require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-FunctionMap.json');this.serviceType='ExpressionParser';this.fable.addServiceTypeIfNotExists('ExpressionParser-Tokenizer',require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ExpressionTokenizer.js'));this.fable.addServiceTypeIfNotExists('ExpressionParser-Linter',require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Linter.js'));this.fable.addServiceTypeIfNotExists('ExpressionParser-Postfix',require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Postfix.js'));this.fable.addServiceTypeIfNotExists('ExpressionParser-Solver',require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-SolvePostfixedExpression.js'));this.Tokenizer=this.fable.instantiateServiceProviderWithoutRegistration('ExpressionParser-Tokenizer');this.Linter=this.fable.instantiateServiceProviderWithoutRegistration('ExpressionParser-Linter');this.Postfix=this.fable.instantiateServiceProviderWithoutRegistration('ExpressionParser-Postfix');this.Solver=this.fable.instantiateServiceProviderWithoutRegistration('ExpressionParser-Solver');// Now wire each of these up. Not in love with this pattern but better than a giant file here.
3367
+ this.Tokenizer.connectExpressionParser(this);this.Linter.connectExpressionParser(this);this.Postfix.connectExpressionParser(this);this.Solver.connectExpressionParser(this);}substituteValuesInTokenizedObjects(pTokenizedObjects,pDataSource,pResultObject,pManifestDefinition){let tmpResults=typeof pResultObject==='object'?pResultObject:{ExpressionParserLog:[]};if(!Array.isArray(pTokenizedObjects)){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.substituteValuesInTokenizedObjects was passed a non-array tokenized object list.");this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return pTokenizedObjects;}if(typeof pDataSource!=='object'){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.substituteValuesInTokenizedObjects either was passed no data source, or was passed a non-object data source.");this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return pTokenizedObjects;}let tmpDataSource=pDataSource;// TODO: Allow the calling API to pass in an already constructed manifest.
3368
+ let tmpManifest=this.fable.newManyfest(pManifestDefinition);for(let i=0;i<pTokenizedObjects.length;i++){if(typeof pTokenizedObjects[i]!=='object'){tmpResults.ExpressionParserLog.push("WARNING: ExpressionParser.substituteValuesInTokenizedObjects found a non-object tokenized object at index ".concat(i));this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);continue;}let tmpToken=pTokenizedObjects[i];if(pTokenizedObjects[i].Type==='Token.Symbol'&&!tmpToken.Resolved){// Symbols always look up values by hash first
3369
+ let tmpValue=tmpManifest.getValueByHash(tmpDataSource,tmpToken.Token);// if (!tmpValue)
3370
+ // {
3371
+ // // If no hash resolves, try by address.
3372
+ // tmpValue = tmpManifest.getValueAtAddress(tmpToken.Token, tmpDataSource);
3373
+ // }
3374
+ if(!tmpValue){tmpResults.ExpressionParserLog.push("WARNING: ExpressionParser.substituteValuesInTokenizedObjects found no value for the symbol hash or address ".concat(tmpToken.Token," at index ").concat(i));this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);continue;}else{tmpResults.ExpressionParserLog.push("INFO: ExpressionParser.substituteValuesInTokenizedObjects found a value [".concat(tmpValue,"] for the state address ").concat(tmpToken.Token," at index ").concat(i));this.log.info(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);try{let tmpValueParsed=new this.fable.Utility.bigNumber(tmpValue);tmpToken.Resolved=true;tmpToken.Value=tmpValueParsed.toString();}catch(pError){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.substituteValuesInTokenizedObjects found a non-numeric value for the state address ".concat(tmpToken.Token," at index ").concat(i));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);tmpToken.Resolved=false;}}}if(pTokenizedObjects[i].Type==='Token.StateAddress'&&!tmpToken.Resolved){// Symbols are always hashes. This gracefully works for simple shallow objects because hashes default to the address in Manyfest.
3375
+ let tmpValue=tmpManifest.getValueAtAddress(tmpDataSource,tmpToken.Token);if(!tmpValue){tmpResults.ExpressionParserLog.push("WARNING: ExpressionParser.substituteValuesInTokenizedObjects found no value for the state address ".concat(tmpToken.Token," at index ").concat(i));this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);continue;}else{tmpResults.ExpressionParserLog.push("INFO: ExpressionParser.substituteValuesInTokenizedObjects found a value [".concat(tmpValue,"] for the state address ").concat(tmpToken.Token," at index ").concat(i));this.log.info(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);try{let tmpValueParsed=new this.fable.Utility.bigNumber(tmpValue);tmpToken.Resolved=true;tmpToken.Value=tmpValueParsed.toString();}catch(pError){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.substituteValuesInTokenizedObjects found a non-numeric value for the state address ".concat(tmpToken.Token," at index ").concat(i));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);tmpToken.Resolved=false;}}}if(pTokenizedObjects[i].Type==='Token.Constant'&&!tmpToken.Resolved){tmpResults.ExpressionParserLog.push("INFO: ExpressionParser.substituteValuesInTokenizedObjects found a value [".concat(tmpToken.Token,"] for the constant ").concat(tmpToken.Token," at index ").concat(i));this.log.info(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);try{let tmpValueParsed=new this.fable.Utility.bigNumber(tmpToken.Token);tmpToken.Resolved=true;tmpToken.Value=tmpValueParsed.toString();}catch(pError){// This constant has the right symbols but apparently isn't a parsable number.
3376
+ tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.substituteValuesInTokenizedObjects found a non-numeric value for the state address ".concat(tmpToken.Token," at index ").concat(i));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);tmpToken.Resolved=false;}}}return pTokenizedObjects;}tokenize(pExpression,pResultObject){return this.Tokenizer.tokenize(pExpression,pResultObject);}lintTokenizedExpression(pTokenizedExpression,pResultObject){return this.Linter.lintTokenizedExpression(pTokenizedExpression,pResultObject);}buildPostfixedSolveList(pTokenizedExpression,pResultObject){return this.Postfix.buildPostfixedSolveList(pTokenizedExpression,pResultObject);}solvePostfixedExpression(pPostfixedExpression,pDataDestinationObject,pResultObject,pManifest){return this.Solver.solvePostfixedExpression(pPostfixedExpression,pDataDestinationObject,pResultObject,pManifest);}solve(pExpression,pDataSourceObject,pResultObject,pManifestDefinition,pDataDestinationObject){let tmpResultsObject=typeof pResultObject==='object'?pResultObject:{};let tmpDataSourceObject=typeof pDataSourceObject==='object'?pDataSourceObject:{};let tmpDataDestinationObject=typeof pDataDestinationObject==='object'?pDataDestinationObject:{};this.tokenize(pExpression,tmpResultsObject);this.lintTokenizedExpression(tmpResultsObject.RawTokens,tmpResultsObject);this.buildPostfixedSolveList(tmpResultsObject.RawTokens,tmpResultsObject);this.substituteValuesInTokenizedObjects(tmpResultsObject.PostfixTokenObjects,tmpDataSourceObject,tmpResultsObject,pManifestDefinition);return this.solvePostfixedExpression(tmpResultsObject.PostfixSolveList,tmpDataDestinationObject,tmpResultsObject,pManifestDefinition);}}module.exports=FableServiceExpressionParser;},{"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ExpressionTokenizer.js":137,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-FunctionMap.json":138,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Linter.js":139,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Postfix.js":140,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-SolvePostfixedExpression.js":141,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-TokenMap.json":142,"big.js":17,"fable-serviceproviderbase":51}],136:[function(require,module,exports){const libFableServiceProviderBase=require('fable-serviceproviderbase');class ExpressionParserOperationBase extends libFableServiceProviderBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ExpressionParserOperationBase';this.numberTest=/^-{0,1}\d*\.{0,1}\d+$/;this.ExpressionParser=false;}connectExpressionParser(pExpressionParser){this.ExpressionParser=pExpressionParser;}getTokenType(pToken){if(this.ExpressionParser.tokenMap.hasOwnProperty(pToken)){return"Token.".concat(this.ExpressionParser.tokenMap[pToken].Type);}else if(pToken.length>2&&pToken[0]==='{'&&pToken[pToken.length-1]==='}'){return'Token.StateAddress';}else if(this.numberTest.test(pToken)){return'Token.Constant';}else{return'Token.Symbol';}// Just for documentation sake:
3377
+ // There is a fifth token type, VirtualSymbol
3378
+ // This is a value that's added during solve and looked up by address in the VirtualSymbol object.
3379
+ }getTokenContainerObject(pToken,pTokenType){return{Token:pToken,Type:typeof pTokenType==='undefined'?this.getTokenType(pToken):pTokenType,Descriptor:this.ExpressionParser.tokenMap.hasOwnProperty(pToken)?this.ExpressionParser.tokenMap[pToken]:false};}}module.exports=ExpressionParserOperationBase;},{"fable-serviceproviderbase":51}],137:[function(require,module,exports){const libExpressionParserOperationBase=require('./Fable-Service-ExpressionParser-Base.js');class ExpressionTokenizer extends libExpressionParserOperationBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ExpressionParser-Tokenizer';}tokenize(pExpression,pResultObject){let tmpResults=typeof pResultObject==='object'?pResultObject:{ExpressionParserLog:[]};tmpResults.RawExpression=pExpression;tmpResults.RawTokens=[];tmpResults.ExpressionParserLog=[];if(typeof pExpression!=='string'){this.log.warn('ExpressionParser.tokenize was passed a non-string expression.');return tmpResults.RawTokens;}/* Tokenize the expression
3380
+ *
3381
+ * Current token types:
3382
+ * - Value
3383
+ * : could be a symbol representation e.g. "x", "depth", "Cost", etc. --- symbol representations are looked up first as manifest hashes
3384
+ * : could be a number e.g. "5", "3.14159", etc.
3385
+ * : could be a function name e.g. sin(x), sqrt(3+5) where sin or sqrt are known function names
3386
+ * - StateAddress
3387
+ * : these are always wrapped in squiggly brackets
3388
+ * : e.g. {Moisture.Percentage}, {Ending.Temperature.Fahrenheit}, {AppData.Download.Size}, etc.
3389
+ * - Token
3390
+ * : could be an operator e.g. "+", "-", "*", "/"
3391
+ * : could be a parenthesis e.g. "(", ")"
3392
+ */let tmpCurrentTokenType=false;let tmpCurrentToken='';for(let i=0;i<pExpression.length;i++){let tmpCharacter=pExpression[i];// [ WHITESPACE ]
3393
+ // 1. Space breaks tokens except when we're in an address that's been scoped by a {}
3394
+ if(tmpCharacter===' '&&tmpCurrentTokenType!=='StateAddress'){if(tmpCurrentToken.length>0){tmpResults.RawTokens.push(tmpCurrentToken);}tmpCurrentToken='';tmpCurrentTokenType=false;continue;}// [ STATE ADDRESS BLOCKS ]
3395
+ // 2. If we're in an address, we keep going until we hit the closing brace
3396
+ if(tmpCurrentTokenType==='StateAddress'&&tmpCharacter!=='}'){tmpCurrentToken+=tmpCharacter;continue;}// 3. If we're in an address and we hit the closing brace, we close the token, push it and reset
3397
+ if(tmpCurrentTokenType==='StateAddress'&&tmpCharacter==='}'){tmpCurrentToken+=tmpCharacter;tmpResults.RawTokens.push(tmpCurrentToken);tmpCurrentToken='';tmpCurrentTokenType=false;continue;}// 4. If we're not in an address and we hit a closing brace it's a problem
3398
+ // TODO: Should we just ignore it? We do at the moment.
3399
+ if(tmpCharacter=='}'){if(tmpCurrentToken.length>0){tmpResults.RawTokens.push(tmpCurrentToken);}tmpCurrentToken='';tmpCurrentTokenType=false;tmpResults.ExpressionParserLog.push("ExpressionParser.tokenize found a closing brace without an opening brace in the expression: ".concat(pExpression," at character index ").concat(i));this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);continue;}// 5. If we're not in an address and we hit an opening brace, we start an address
3400
+ if(tmpCharacter=='{'){if(tmpCurrentToken.length>0){tmpResults.RawTokens.push(tmpCurrentToken);}tmpCurrentToken='';tmpCurrentTokenType='StateAddress';tmpCurrentToken=tmpCharacter;continue;}// [ TOKENS ]
3401
+ if(this.ExpressionParser.tokenMap.hasOwnProperty(tmpCharacter)){if(tmpCurrentToken.length>0){tmpResults.RawTokens.push(tmpCurrentToken);}tmpCurrentToken='';tmpCurrentTokenType=false;tmpResults.RawTokens.push(tmpCharacter);continue;}// If it's not an operator, it's a number or address.
3402
+ // At the moment we aren't going to gate it on whether it's a valid address or not
3403
+ // Just treat anything not a known token on its own as a value identifier
3404
+ /* Per this stack overflow article: https://stackoverflow.com/questions/4434076/best-way-to-alphanumeric-check-in-javascript
3405
+ * We could use a regex but it is slower than the charCodeAt method.
3406
+ * This also doesn't solve the problem of unicode characters, but we won't support those for now.
3407
+ */ // if (pExpression.charAt(i) == '.')
3408
+ // {
3409
+ // console.log('Found a period')
3410
+ // }
3411
+ // let tmpCharCode = pExpression.charCodeAt(i);
3412
+ // // Match that the character code is any of...
3413
+ // if (
3414
+ // // Number [0-9]
3415
+ // (tmpCharCode > 47 && tmpCharCode < 58)
3416
+ // // Upper Case
3417
+ // || (tmpCharCode > 64 && tmpCharCode < 91)
3418
+ // // LOWER CASE
3419
+ // || (tmpCharCode > 96 && tmpCharCode < 123)
3420
+ // )
3421
+ // {
3422
+ // NOTE: Not having this guard makes a lot of interesting things possible.
3423
+ tmpCurrentTokenType='Value';tmpCurrentToken+=tmpCharacter;// continue;
3424
+ // }
3425
+ // tmpResults.ExpressionParserLog.push(`ExpressionParser.tokenize found an unknown character code ${tmpCharCode} character ${tmpCharacter} in the expression: ${pExpression} at index ${i}`);
3426
+ // this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);
3427
+ }if(tmpCurrentTokenType&&tmpCurrentToken.length>0){tmpResults.RawTokens.push(tmpCurrentToken);}return tmpResults.RawTokens;}}module.exports=ExpressionTokenizer;},{"./Fable-Service-ExpressionParser-Base.js":136}],138:[function(require,module,exports){module.exports={"sqrt":{"Name":"Square Root","Address":"fable.Math.sqrtPrecise"},"abs":{"Name":"Absolute Value","Address":"fable.Math.absPrecise"},"rad":{"Name":"Degrees to Radians","Address":"fable.Math.radPrecise"},"sin":{"Name":"Sine","Address":"fable.Math.sin"}};},{}],139:[function(require,module,exports){const libExpressionParserOperationBase=require('./Fable-Service-ExpressionParser-Base.js');class ExpressionParserLinter extends libExpressionParserOperationBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ExpressionParser-Linter';}lintTokenizedExpression(pTokenizedExpression,pResultObject){let tmpResults=typeof pResultObject==='object'?pResultObject:{ExpressionParserLog:[]};tmpResults.LinterResults=[];// Guard against bad data being passed in
3428
+ if(!Array.isArray(pTokenizedExpression)){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.lintTokenizedExpression was passed a non-array tokenized expression.");tmpResults.LinterResults.push(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return pTokenizedExpression;}if(pTokenizedExpression.length<1){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.lintTokenizedExpression was passed an empty tokenized expression.");tmpResults.LinterResults.push(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return pTokenizedExpression;}// 1. Check for balanced parenthesis
3429
+ let tmpParenthesisDepth=0;// If it is in a state address, we don't care about the parenthesis
3430
+ // State addresses are between squiggly brackets
3431
+ let tmpInStateAddress=false;for(let i=0;i<pTokenizedExpression.length;i++){if(pTokenizedExpression[i]==='('&&!tmpInStateAddress){tmpParenthesisDepth++;}if(pTokenizedExpression[i]===')'&&!tmpInStateAddress){tmpParenthesisDepth--;}if(pTokenizedExpression[i]==='{'){tmpInStateAddress=true;}if(pTokenizedExpression[i]==='}'){tmpInStateAddress=false;}if(tmpParenthesisDepth<0){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.lintTokenizedExpression found an unbalanced parenthesis in the tokenized expression at token index ".concat(i));tmpResults.LinterResults.push(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}}if(tmpParenthesisDepth>0){// TODO: Should we add the closing parenthesis?
3432
+ tmpResults.ExpressionParserLog.push("WARNING: ExpressionParser.lintTokenizedExpression found an unbalanced parenthesis in the tokenized expression (ended without closing last set of parenthesis) -- appropriate closing parenthesis will be added.");tmpResults.LinterResults.push(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}// 2. Check for balanced squiggly braces
3433
+ tmpInStateAddress=false;for(let i=0;i<pTokenizedExpression.length;i++){if(pTokenizedExpression[i]==='{'){tmpInStateAddress=true;}if(pTokenizedExpression[i]==='}'&&tmpInStateAddress){tmpInStateAddress=false;}if(pTokenizedExpression[i]==='}'&&!tmpInStateAddress){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.lintTokenizedExpression found an unbalanced closing squiggly brace \"}\" in the tokenized expression at token index ".concat(i));tmpResults.LinterResults.push(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}if(tmpInStateAddress){tmpResults.ExpressionParserLog.push("WARNING: ExpressionParser.lintTokenizedExpression found an open squiggly brace in the tokenized expression at index ".concat(i));tmpResults.LinterResults.push(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}}// 3. Check for an equality assignment
3434
+ let tmpEqualityAssignmentCount=0;let tmpEqualityAssignmentIndex=false;for(let i=0;i<pTokenizedExpression.length;i++){if(pTokenizedExpression[i]==='='){tmpEqualityAssignmentCount++;tmpEqualityAssignmentIndex=i;if(tmpEqualityAssignmentCount>1){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.lintTokenizedExpression found multiple equality assignments in the tokenized expression; equality assignment #".concat(tmpEqualityAssignmentCount," at token index ").concat(i,"."));tmpResults.LinterResults.push(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}}}if(tmpEqualityAssignmentCount<1){tmpResults.ExpressionParserLog.push("WARNING: ExpressionParser.lintTokenizedExpression found no equality assignment in the tokenized expression. One called Result will be added automatically.");tmpResults.LinterResults.push(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}// 4. Make sure the equality assignment only has a single value on the other side of it
3435
+ // (no, this is not a magical algebraic solver, do your own simplification)
3436
+ // IF there is only one equality assignment (otherwise we don't even lint this because it's syntax errors all the way down)
3437
+ if(tmpEqualityAssignmentCount===1){// If there are exactly three tokens, make sure at least one is an assignable-ish address
3438
+ // This can still fail, but we aren't linting all the way into the manifest here; just the expression
3439
+ if(pTokenizedExpression.length===3){if(// The first token in our expression is a potentially assignable symbol
3440
+ this.getTokenType(pTokenizedExpression[0])==='Token.StateAddress'||this.getTokenType(pTokenizedExpression[2])==='Token.Symbol'// NOTE: For now we are only going to support assignment to the first symbol in the expression, which seems okay.
3441
+ // OR the last token in our expression is a potentially assignable symbol
3442
+ //|| (this.getTokenType(pTokenizedExpression[2]) === 'Token.StateAddress') || (this.getTokenType(pTokenizedExpression[0]) === 'Token.Symbol')
3443
+ ){tmpResults.ExpressionParserLog.push("WARNING: ExpressionParser.lintTokenizedExpression found a single equality assignment in the tokenized expression with no assignable address on the left side of the assignment.");tmpResults.LinterResults.push(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}}}// 5. Check that there are no operators adjacent to each other
3444
+ // This is a simple lint check, not a full-blown syntax check
3445
+ let tmpTokenPrevious=false;for(let i=0;i<pTokenizedExpression.length-1;i++){if(this.ExpressionParser.tokenMap.hasOwnProperty(pTokenizedExpression[i])&&this.ExpressionParser.tokenMap[pTokenizedExpression[i]].Type!='Parenthesis'&&!tmpTokenPrevious){tmpTokenPrevious=true;}else if(this.ExpressionParser.tokenMap.hasOwnProperty(pTokenizedExpression[i])&&this.ExpressionParser.tokenMap[pTokenizedExpression[i]].Type!='Parenthesis'){// If this isn't a + or - positivity/negativity multiplier, it's an error.
3446
+ if(pTokenizedExpression[i]!=='+'&&pTokenizedExpression[i]!=='-'){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.lintTokenizedExpression found an ".concat(pTokenizedExpression[i]," operator adjacent to another operator in the tokenized expression at token index ").concat(i));tmpResults.LinterResults.push(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}}else{tmpTokenPrevious=false;}}return tmpResults.LinterResults;}}module.exports=ExpressionParserLinter;},{"./Fable-Service-ExpressionParser-Base.js":136}],140:[function(require,module,exports){const libExpressionParserOperationBase=require('./Fable-Service-ExpressionParser-Base.js');class ExpressionParserPostfix extends libExpressionParserOperationBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ExpressionParser-Postfix';}getPosfixSolveListOperation(pOperation,pLeftValue,pRightValue,pDepthSolveList,pDepthSolveIndex){let tmpOperation={VirtualSymbolName:pOperation.VirtualSymbolName,Operation:pOperation,LeftValue:pLeftValue,RightValue:pRightValue};let tmpDepthSolveList=Array.isArray(pDepthSolveList)?pDepthSolveList:false;// // Although we have a `Token.Type == "Parenthesis"` option to check on, keeping these explicit means the solver won't
3447
+ // // allow users to pass in parenthesis in the wrong order.
3448
+ // // The linter does blow up as does the postfix, but, just in case we'll leave these explicit.
3449
+ // // It really doesn't hurt anything.
3450
+ // if (pLeftValue.Token === ')')
3451
+ // {
3452
+ // // We have found a close parenthesis which needs to pull the proper virtual symbol for the last operation on this stack.
3453
+ // // This ensures we are not expressing the parenthesis virtual symbols to the solver.
3454
+ // pLeftValue.VirtualSymbolName = pLayerStackMap[pLeftValue.SolveLayerStack];
3455
+ // this.log.error(`ERROR: ExpressionParser.getPosfixSolveListOperation found a close parenthesis in the left value of an operation.`);
3456
+ // }
3457
+ // else if (pRightValue.Token === '(')
3458
+ // {
3459
+ // // We have found a close parenthesis which needs to pull the proper virtual symbol for the last operation on this stack.
3460
+ // // This ensures we are not expressing the parenthesis virtual symbols to the solver.
3461
+ // pRightValue.VirtualSymbolName = pLayerStackMap[pRightValue.SolveLayerStack];
3462
+ // this.log.error(`ERROR: ExpressionParser.getPosfixSolveListOperation found a close parenthesis in the left value of an operation.`);
3463
+ // }
3464
+ // // Set the layer stack map virtual symbol name to the last operation performed on this stack.
3465
+ // pLayerStackMap[pOperation.SolveLayerStack] = pOperation.VirtualSymbolName;
3466
+ /* These two if blocks are very complex -- they basically provide a
3467
+ * way to deal with recursion that can be expressed to the user in
3468
+ * a meaningful way.
3469
+ *
3470
+ * The reason we are doing it as such is to show exactly how the
3471
+ * solver resolves the passed-in tokens into a solvable expression.
3472
+ */if(!tmpOperation.LeftValue.VirtualSymbolName){tmpOperation.LeftValue.VirtualSymbolName=tmpOperation.VirtualSymbolName;}else{// We need to set the left value to a virtual symbol instead of the looked up value if it's already used in another operation
3473
+ tmpOperation.LeftValue=this.getTokenContainerObject(tmpOperation.LeftValue.VirtualSymbolName,'Token.VirtualSymbol');// Now walk backwards and see if we need to update a previous symbol for a previously unparsed operator
3474
+ if(tmpDepthSolveList){for(let i=pDepthSolveIndex-1;i>=0;i--){if(tmpDepthSolveList[i].Type==='Token.Operator'&&!tmpDepthSolveList[i].Parsed&&// When walking backward, we only want to mutate if the .
3475
+ tmpDepthSolveList[i].hasOwnProperty('Descriptor')&&tmpOperation.Operation.hasOwnProperty('Descriptor')&&// Anything >3 does not have commutative properties
3476
+ tmpDepthSolveList[i].Descriptor.Precedence>3){// If the symbol to its right is not the same as this operation
3477
+ if(tmpDepthSolveList[i+1].VirtualSymbolName!==tmpOperation.VirtualSymbolName){// This is the recursive "shunting" being simulated
3478
+ tmpDepthSolveList[i+1].VirtualSymbolName=tmpOperation.VirtualSymbolName;}break;}}}}if(!tmpOperation.RightValue.VirtualSymbolName){tmpOperation.RightValue.VirtualSymbolName=tmpOperation.VirtualSymbolName;}else{// We need to set the right value to a virtual symbol instead of the looked up value if it's already used in another operation
3479
+ tmpOperation.RightValue=this.getTokenContainerObject(tmpOperation.RightValue.VirtualSymbolName,'Token.VirtualSymbol');// Now walk forwards and see if we need to update an upcoming symbol for a previously unparsed operator
3480
+ if(tmpDepthSolveList){for(let i=pDepthSolveIndex+1;i<tmpDepthSolveList.length;i++){if(tmpDepthSolveList[i].Type==='Token.Operator'&&!tmpDepthSolveList[i].Parsed&&// When walking forward, we only want to mutate if the precedence hasn't been solved.
3481
+ tmpDepthSolveList[i].hasOwnProperty('Descriptor')&&tmpOperation.Operation.hasOwnProperty('Descriptor')&&// Anything >3 does not have commutative properties
3482
+ tmpDepthSolveList[i].Descriptor.Precedence>3){// If the symbol to its right is not the same as this operation
3483
+ if(tmpDepthSolveList[i-1].VirtualSymbolName!==tmpOperation.VirtualSymbolName){// This is the recursive "shunting" being simulated
3484
+ tmpDepthSolveList[i-1].VirtualSymbolName=tmpOperation.VirtualSymbolName;}break;}else if(tmpDepthSolveList[i].Type==='Token.Operator'&&!tmpDepthSolveList[i].Parsed){break;}}}}tmpOperation.Operation.Parsed=true;return tmpOperation;}buildPostfixedSolveList(pTokenizedExpression,pResultObject){let tmpResults=typeof pResultObject==='object'?pResultObject:{ExpressionParserLog:[]};tmpResults.PostfixedAssignmentAddress='Result';tmpResults.PostfixTokenObjects=[];tmpResults.PostfixSolveList=[];if(pTokenizedExpression.length<3){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.buildPostfixedSolveList was passed a tokenized expression with less than three tokens.");this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return tmpResults.PostfixTokenObjects;}// 1. Figure out the Equality Assignment
3485
+ let tmpEqualsIndex=-1;for(let i=0;i<pTokenizedExpression.length;i++){if(pTokenizedExpression[i]==='='&&tmpEqualsIndex<0){tmpEqualsIndex=i;}// If there are two equality assignments, error and bail out.
3486
+ else if(pTokenizedExpression[i]==='='){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.buildPostfixedSolveList found multiple equality assignments in the tokenized expression; equality assignment #".concat(tmpEqualsIndex," at token index ").concat(i,"."));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return tmpResults.PostfixTokenObjects;}}if(tmpEqualsIndex==-1){tmpResults.ExpressionParserLog.push("WARNING: ExpressionParser.buildPostfixedSolveList found no equality assignment in the tokenized expression; defaulting to Result");this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}else if(tmpEqualsIndex>1){tmpResults.ExpressionParserLog.push("WARNING: ExpressionParser.buildPostfixedSolveList found an equality assignment in the tokenized expression at an unexpected location (token index ".concat(tmpEqualsIndex,"); the expression cannot be parsed."));this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}else if(tmpEqualsIndex===0){// This is an implicit function -- just go to result and return the value.
3487
+ // That is... the user entered something like "= 5 + 3" so we should just return 8, and use the default Result quietly.
3488
+ }else{tmpResults.PostfixedAssignmentAddress=pTokenizedExpression[0];}// 2. Categorize tokens in the expression, put them in the "expression list" as a token object
3489
+ for(let i=tmpEqualsIndex+1;i<pTokenizedExpression.length;i++){tmpResults.PostfixTokenObjects.push(this.getTokenContainerObject(pTokenizedExpression[i]));}// 3. Decorate mathematical parsing depth and detect functions at the same time
3490
+ // Having written this a few times now, it's easier to detect functions *while* parsing depth.
3491
+ // Especially if we want our system to be able to communicate with the user when there is an issue.
3492
+ let tmpDepth=0;// The virtual symbol index is used for the abstract interim values that are generated at each step of the solve
3493
+ let tmpVirtualParenthesisIndex=0;let tmpSolveLayerStack=[];// Kick off the solve layer stack with the first solve set identifier
3494
+ tmpSolveLayerStack.push("SolveSet_".concat(tmpVirtualParenthesisIndex,"_D_").concat(tmpDepth));for(let i=0;i<tmpResults.PostfixTokenObjects.length;i++){// 1. If it's an open parenthesis, set the parenthesis at the current depth and increment the depth
3495
+ if(tmpResults.PostfixTokenObjects[i].Token==='('){// Set the depth of the open parenthesis to the current solution depth
3496
+ tmpResults.PostfixTokenObjects[i].Depth=tmpDepth;// Generate the virtual symbol name for user output
3497
+ tmpResults.PostfixTokenObjects[i].VirtualSymbolName="Pr_".concat(tmpVirtualParenthesisIndex,"_D_").concat(tmpDepth);// 1a. Detect if this parenthesis is signaling a function
3498
+ // If the previous token is a Symbol (e.g. it say sin(x) or sqrt(3+5) or something) then the parser will interpret it as a function
3499
+ if(i>0){if(tmpResults.PostfixTokenObjects[i-1].Type==='Token.Symbol'){// Set the type of this to be a function
3500
+ tmpResults.PostfixTokenObjects[i-1].Type='Token.Function';// tmpResults.PostfixTokenObjects[i-1].Descriptor = this.ExpressionParser.tokenMap[pTokenizedExpression[i-1]];
3501
+ // Rename the virtual symbol n ame to include the function
3502
+ // tmpResults.PostfixTokenObjects[i].VirtualSymbolName = `Fn_${tmpVirtualParenthesisIndex}_D_${tmpDepth}_${this.fable.DataFormat.cleanNonAlphaCharacters(tmpResults.PostfixTokenObjects[i-1].Token)}`;
3503
+ // The function and the parenthesis are at the same depth and virtual symbol
3504
+ // tmpResults.PostfixTokenObjects[i-1].VirtualSymbolName = tmpResults.PostfixTokenObjects[i].VirtualSymbolName;
3505
+ }}// Parenthesis manage the solve layer stack
3506
+ // For adding a new parenthesis solve layer, we put the parenthesis in the stack we are in and then make all the contained tokens be within the stack of the parenthesis
3507
+ tmpResults.PostfixTokenObjects[i].SolveLayerStack=tmpSolveLayerStack[tmpSolveLayerStack.length-1];tmpSolveLayerStack.push(tmpResults.PostfixTokenObjects[i].VirtualSymbolName);tmpVirtualParenthesisIndex++;tmpDepth++;}// 2. If it's a closed parenthesis, decrease the depth
3508
+ else if(tmpResults.PostfixTokenObjects[i].Token===')'){tmpDepth--;tmpResults.PostfixTokenObjects[i].Depth=tmpDepth;// Check to see that the depth of the closed parenthesis is greater than 0
3509
+ if(tmpDepth<0){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.buildPostfixedSolveList found a closing parenthesis at token index ".concat(i," with no corresponding opening parenthesis."));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}// Parenthesis manage the solve layer stack
3510
+ // For closing parenthesis solve layer with a close paren, we put it in the same stack as the opening parenthesis.
3511
+ // Give the closing parenthesis the same virtual symbol name as the opening parenthesis
3512
+ // (do the both above at the same time)
3513
+ tmpResults.PostfixTokenObjects[i].VirtualSymbolName=tmpSolveLayerStack.pop();tmpResults.PostfixTokenObjects[i].SolveLayerStack=tmpSolveLayerStack[tmpSolveLayerStack.length-1];}// 3. If it's a state address or Symbol, set depth
3514
+ // It was much more complex later on solving these as virtual symbols of their own.
3515
+ // We are saving the value resolution for the very end.
3516
+ else if(tmpResults.PostfixTokenObjects[i].Type==='Token.Symbol'){// Set the depth of the current solution depth
3517
+ tmpResults.PostfixTokenObjects[i].Depth=tmpDepth;tmpResults.PostfixTokenObjects[i].SolveLayerStack=tmpSolveLayerStack[tmpSolveLayerStack.length-1];// Generate a virtual symbol name that's somewhat human readable
3518
+ //tmpResults.PostfixTokenObjects[i].VirtualSymbolName = `Sm_${tmpVirtualParenthesisIndex}_D_${tmpDepth}_${this.fable.DataFormat.cleanNonAlphaCharacters(tmpResults.PostfixTokenObjects[i].Token)}`;
3519
+ // We've used up this virtual symbol index so increment it
3520
+ // The reason we only use these once is to make sure if we use, say, sin(x) twice at the same depth we still have unique names for each virtual solution
3521
+ //tmpVirtualParenthesisIndex++;
3522
+ }// 4. If it's an operator or constant or comment, just set the depth
3523
+ else{tmpResults.PostfixTokenObjects[i].Depth=tmpDepth;tmpResults.PostfixTokenObjects[i].SolveLayerStack=tmpSolveLayerStack[tmpSolveLayerStack.length-1];}}// 4. Walk through the decorated symbols and generate the postfix solve list
3524
+ // We are going to start by creating a map of the solve layers:
3525
+ let tmpSolveLayerMap={};let tmpSolveLayerMaxDepth=0;for(let i=0;i<tmpResults.PostfixTokenObjects.length;i++){if(!tmpSolveLayerMap.hasOwnProperty(tmpResults.PostfixTokenObjects[i].SolveLayerStack)){tmpSolveLayerMap[tmpResults.PostfixTokenObjects[i].SolveLayerStack]=[];}tmpSolveLayerMap[tmpResults.PostfixTokenObjects[i].SolveLayerStack].push(tmpResults.PostfixTokenObjects[i]);// See what our max depth is. This is super important to the postfix operation
3526
+ // The programmer in me thinks it would be funny to not track this and just use the map key length as the max size, which would work (logically impossible to have a depth > key length) but it would be quite a bit more confusing to grok the algorithm.
3527
+ if(tmpResults.PostfixTokenObjects[i].Depth>tmpSolveLayerMaxDepth){tmpSolveLayerMaxDepth=tmpResults.PostfixTokenObjects[i].Depth;}}let tmpSolveLayerKeys=Object.keys(tmpSolveLayerMap);// Reset the virtual symbol index -- it was used above for uniquenes when creating abstract symbols for parenthesis and layer stacks.
3528
+ let tmpVirtualSymbolIndex=0;tmpSolveLayerKeys.sort(// Sort the solve layers by depth.
3529
+ (pLeftLayer,pRightLayer)=>{// It is impossible to have a layer with no entries in it.
3530
+ // If that ever happens, the bug is actually above and we actively want this to blow up.
3531
+ if(tmpSolveLayerMap[pLeftLayer][0].Depth<tmpSolveLayerMap[pRightLayer][0].Depth){return 1;}if(tmpSolveLayerMap[pLeftLayer][0].Depth>tmpSolveLayerMap[pRightLayer][0].Depth){return-1;}return 0;});// 5. Generate the postfix solve list
3532
+ // The most important thing is going backwards in the depth order (a la reverse polish).
3533
+ // Specifically not using shunting yard to provide in-depth "show your work" notes
3534
+ // Yes it is possible to do a somewhat similar thing with shunting yard but the code is almost unreadable
3535
+ // 5.1 Build the Virtual Symbol Names
3536
+ // This maps layer stack addresses (which match parenthesis virtual symbol names) to the resultant value for that layer stack.
3537
+ // These values change as it solves but the last assignment is the proper assignment because math only reads forward in a line
3538
+ tmpResults.PostfixLayerstackMap={};for(let tmpSolveLayerIndex=0;tmpSolveLayerIndex<tmpSolveLayerKeys.length;tmpSolveLayerIndex++){let tmpSolveLayerTokens=tmpSolveLayerMap[tmpSolveLayerKeys[tmpSolveLayerIndex]];// For each precedence (this isn't strictly required here but makes the outcome for the user more readable)
3539
+ for(let tmpPrecedence=0;tmpPrecedence<=this.ExpressionParser.tokenMaxPrecedence;tmpPrecedence++){// Enumerate all tokens in a layer's expression.
3540
+ // There is a recursive way to do this, but given the short length of even the most complex equations we're favoring readability.
3541
+ for(let i=0;i<tmpSolveLayerTokens.length;i++){// If the token is an operator and at the current precedence, add it to the postfix solve list and mutate the array.
3542
+ if(tmpSolveLayerTokens[i].Type==='Token.Operator'&&tmpSolveLayerTokens[i].Descriptor.Precedence===tmpPrecedence){let tmpToken=tmpSolveLayerTokens[i];// If there is a token and nothing else in this layer, then it's an error.
3543
+ if(tmpSolveLayerTokens.length===1){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.buildPostfixedSolveList found a single operator in a solve layer expression at token index ".concat(i));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return tmpResults.PostfixSolveList;}// If the token is at the beginning of the expression and not a number line orientation modifier, it's an error.
3544
+ else if(i==0&&(tmpToken.Token!='+'||tmpToken.Token!='-')){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.buildPostfixedSolveList found an operator at the beginning of a solve layer expression at token index ".concat(i));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return tmpResults.PostfixSolveList;}// If the token is at the end of the expression, it is an error.
3545
+ else if(i==tmpSolveLayerTokens.length-1){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.buildPostfixedSolveList found an operator at the end of a solve layer expression at token index ".concat(i));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return tmpResults.PostfixSolveList;}// The - at the beginning of an expression is a number line orientation modifier
3546
+ else if(i==0&&tmpToken.Token=='-'){tmpToken.VirtualSymbolName="V_".concat(tmpVirtualSymbolIndex);tmpResults.PostfixLayerstackMap[tmpToken.SolveLayerStack]=tmpToken.VirtualSymbolName;tmpVirtualSymbolIndex++;}// The - after an operator or an open parenthesis is also a number line orientation modifier
3547
+ else if(i>0&&tmpToken.Token=='-'&&(tmpSolveLayerTokens[i-1].Type==='Token.Operator'||tmpSolveLayerTokens[i-1].Token==='(')){// The number line negation operator is a special case that generates a virtual constant (-1.0) and multiplies it by the next token
3548
+ tmpToken.VirtualSymbolName="V_".concat(tmpVirtualSymbolIndex);tmpVirtualSymbolIndex++;}// The + at the beginning is also a number line orientation modifier ... THAT WE IGNORE
3549
+ else if(i==0&&tmpToken.Token=='+'){continue;}// The + after an operator or a parenthesis is also a number line orientation modifier ... THAT WE IGNORE
3550
+ else if(i>0&&tmpToken.Token=='+'&&(tmpSolveLayerTokens[i-1].Type==='Token.Operator'||tmpSolveLayerTokens[i-1].Token==='(')){continue;}// If the token is next to another operator it's a parsing error
3551
+ else if(tmpSolveLayerTokens[i-1].Type==='Token.Operator'||tmpSolveLayerTokens[i+1].Type==='Token.Operator'){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.buildPostfixedSolveList found an operator at token index ".concat(i," that is not surrounded by two values."));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return tmpResults.PostfixSolveList;}// Finally add a virtual symbol name to the dang thing.
3552
+ else{tmpToken.VirtualSymbolName="V_".concat(tmpVirtualSymbolIndex);tmpResults.PostfixLayerstackMap[tmpToken.SolveLayerStack]=tmpToken.VirtualSymbolName;tmpVirtualSymbolIndex++;}}else if(tmpSolveLayerTokens[i].Type==='Token.Function'&&tmpPrecedence===0){let tmpToken=tmpSolveLayerTokens[i];tmpToken.VirtualSymbolName="V_".concat(tmpVirtualSymbolIndex);tmpVirtualSymbolIndex++;tmpResults.PostfixLayerstackMap[tmpToken.SolveLayerStack]=tmpToken.VirtualSymbolName;}}}}// 5.2: Decorate the Parenthesis with Virtual Symbol Names
3553
+ // ... this gets funny because of precedence of operations surrounding them, parenthesis and functions.
3554
+ let tmpParenthesisCacheLIFOStack=[];for(let i=0;i<tmpResults.PostfixTokenObjects.length;i++){let tmpPostfixTokenObject=tmpResults.PostfixTokenObjects[i];if(tmpPostfixTokenObject.Type==='Token.Parenthesis'){// This is just to track the parenthesis stack level in User feedback
3555
+ tmpPostfixTokenObject.ParenthesisStack=tmpPostfixTokenObject.VirtualSymbolName;if(tmpPostfixTokenObject.Token==='('){// It's an open parenthesis. If the previous token was an operator, get its precedence.
3556
+ if(i>0){if(tmpResults.PostfixTokenObjects[i-1].Type==='Token.Operator'){tmpPostfixTokenObject.PreviousPrecedence=tmpResults.PostfixTokenObjects[i-1].Descriptor.Precedence;tmpPostfixTokenObject.IsFunction=false;tmpPostfixTokenObject.PreviousVirtualSymbolName=tmpResults.PostfixTokenObjects[i-1].VirtualSymbolName;tmpPostfixTokenObject.VirtualSymbolName=tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];}// This is a function, we will create a virtual symbol for the discrete parenthesis
3557
+ else if(tmpResults.PostfixTokenObjects[i-1].Type==='Token.Function'){tmpPostfixTokenObject.PreviousPrecedence=0;tmpPostfixTokenObject.IsFunction=true;tmpPostfixTokenObject.PreviousVirtualSymbolName=tmpResults.PostfixTokenObjects[i-1].VirtualSymbolName;let tmpVirtualSymbolName=tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];if(!tmpVirtualSymbolName){// This is a parenthesis group with no operators in it; make a virtual symbol name.
3558
+ tmpVirtualSymbolName="V_".concat(tmpVirtualSymbolIndex);tmpVirtualSymbolIndex++;}tmpPostfixTokenObject.VirtualSymbolName=tmpVirtualSymbolName;if(i>1){let tmpTokenBeforeFunction=tmpResults.PostfixTokenObjects[i-2];if(tmpTokenBeforeFunction.Type==='Token.Operator'){tmpPostfixTokenObject.PreviousVirtualSymbolName=tmpResults.PostfixTokenObjects[i-2].VirtualSymbolName;}}}}else{tmpPostfixTokenObject.VirtualSymbolName=tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];}tmpParenthesisCacheLIFOStack.push(tmpPostfixTokenObject);}if(tmpPostfixTokenObject.Token===')'){// There are three options for assigning this:
3559
+ let tmpOpenParenthesis=tmpParenthesisCacheLIFOStack.pop();// It's at the end of the tokens -- use the stack's identifier
3560
+ if(i>=tmpResults.PostfixTokenObjects.length-1){if(tmpOpenParenthesis.IsFunction){tmpPostfixTokenObject.VirtualSymbolName=tmpOpenParenthesis.PreviousVirtualSymbolName;}else{tmpPostfixTokenObject.VirtualSymbolName=tmpOpenParenthesis.VirtualSymbolName;}}else{// Get the next token
3561
+ let tmpPeekedNextToken=tmpResults.PostfixTokenObjects[i+1];if(tmpPeekedNextToken.Type=='Token.Operator'&&tmpOpenParenthesis.IsFunction){// This is the most complex case -- the next token is an operator AND this is a function.
3562
+ // The following is just pointer math.
3563
+ // If the operater is at the same precedence or higher than the open parenthesis previous operator, use the previous operator's identifier
3564
+ // NOTE: This line of code is insanely complex
3565
+ tmpPostfixTokenObject.VirtualSymbolName=tmpOpenParenthesis.PreviousVirtualSymbolName;// if (tmpPeekedNextToken.Descriptor.Precedence <= tmpOpenParenthesis.PreviousPrecedence)
3566
+ // {
3567
+ // tmpPostfixTokenObject.VirtualSymbolName = tmpOpenParenthesis.PreviousVirtualSymbolName;
3568
+ // }
3569
+ // // Otherwise use this one -- it is the higher precedence. And update the previous parenthesis operator's virtual symbol to be the peeked token's virtual symbol.
3570
+ // else
3571
+ // {
3572
+ // tmpPostfixTokenObject.VirtualSymbolName = tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];
3573
+ // tmpOpenParenthesis.VirtualSymbolName = tmpPeekedNextToken.VirtualSymbolName;
3574
+ // }
3575
+ }else if(tmpPeekedNextToken.Type=='Token.Operator'&&tmpOpenParenthesis.hasOwnProperty('PreviousPrecedence')){// This is the second most complex case -- the next token is an operator.
3576
+ // If the operater is at the same precedence or higher than the open parenthesis previous operator, use the previous operator's identifier
3577
+ // NOTE: This line of code is insanely complex
3578
+ if(tmpPeekedNextToken.Descriptor.Precedence<=tmpOpenParenthesis.PreviousPrecedence){tmpPostfixTokenObject.VirtualSymbolName=tmpOpenParenthesis.PreviousVirtualSymbolName;}// Otherwise use this one -- it is the higher precedence. And update the previous parenthesis operator's virtual symbol to be the peeked token's virtual symbol.
3579
+ else{tmpPostfixTokenObject.VirtualSymbolName=tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];tmpOpenParenthesis.VirtualSymbolName=tmpPeekedNextToken.VirtualSymbolName;}}else{// If this is a function, dereference the function's previous virtual symbol name
3580
+ if(tmpOpenParenthesis.IsFunction){tmpPostfixTokenObject.VirtualSymbolName=tmpOpenParenthesis.PreviousVirtualSymbolName;}else{tmpPostfixTokenObject.VirtualSymbolName=tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];}}}// If there isn't an operator in the layer stack, push forward the assignment
3581
+ if(!tmpResults.PostfixLayerstackMap[tmpOpenParenthesis.ParenthesisStack]){tmpResults.PostfixLayerstackMap[tmpOpenParenthesis.ParenthesisStack]=tmpOpenParenthesis.VirtualSymbolName;}}}}for(let tmpSolveLayerIndex=0;tmpSolveLayerIndex<tmpSolveLayerKeys.length;tmpSolveLayerIndex++){let tmpSolveLayerTokens=tmpSolveLayerMap[tmpSolveLayerKeys[tmpSolveLayerIndex]];if(tmpSolveLayerTokens.length===1){// This is just a simple value assignment -- use a simple addition virtual operation.
3582
+ // We often see these inside functions.
3583
+ let tmpAbstractAddToken=this.getTokenContainerObject('+');//let tmpVirtualSymbolName = tmpResults.PostfixLayerstackMap[tmpSolveLayerTokens[0].SolveLayerStack];
3584
+ tmpAbstractAddToken.VirtualSymbolName=tmpResults.PostfixLayerstackMap[tmpSolveLayerTokens[0].SolveLayerStack];tmpResults.PostfixSolveList.push(this.getPosfixSolveListOperation(tmpAbstractAddToken,this.getTokenContainerObject('0.0'),tmpSolveLayerTokens[0]));}}// 5.3: Generate the Postfix Solve List
3585
+ for(let tmpSolveLayerIndex=0;tmpSolveLayerIndex<tmpSolveLayerKeys.length;tmpSolveLayerIndex++){let tmpSolveLayerTokens=tmpSolveLayerMap[tmpSolveLayerKeys[tmpSolveLayerIndex]];// For each precedence level in the layer
3586
+ for(let tmpPrecedence=0;tmpPrecedence<=this.ExpressionParser.tokenMaxPrecedence;tmpPrecedence++){// Enumerate all tokens in a layer's expression.
3587
+ // There is a recursive way to do this, but given the short length of even the most complex equations we're favoring readability.
3588
+ for(let i=0;i<tmpSolveLayerTokens.length;i++){// If the token is an operator and at the current precedence, add it to the postfix solve list and mutate the array.
3589
+ if(tmpSolveLayerTokens[i].Type==='Token.Operator'&&tmpSolveLayerTokens[i].Descriptor.Precedence===tmpPrecedence){let tmpToken=tmpSolveLayerTokens[i];// The - at the beginning of an expression is a number line orientation modifier
3590
+ if(i==0&&tmpToken.Token=='-'){// The number line negation operator is a special case that generates a virtual constant (-1.0) and multiplies it by the next token
3591
+ // This is an abstract operation that isn't in the expression.
3592
+ let tmpAbstractMultiplyToken=this.getTokenContianerObject('*');tmpAbstractMultiplyToken.VirtualSymbolName=tmpToken.VirtualSymbolName;tmpResults.PostfixSolveList.push(this.getPosfixSolveListOperation(tmpAbstractMultiplyToken,this.getTokenContainerObject('-1.0'),tmpSolveLayerTokens[i+1]));}// The - after an operator or an open parenthesis is also a number line orientation modifier
3593
+ else if(i>0&&tmpToken.Token=='-'&&(tmpSolveLayerTokens[i-1].Type==='Token.Operator'||tmpSolveLayerTokens[i-1].Token==='(')){// The number line negation operator is a special case that generates a virtual constant (-1.0) and multiplies it by the next token
3594
+ let tmpAbstractMultiplyToken=this.getTokenContianerObject('*');tmpAbstractMultiplyToken.VirtualSymbolName=tmpToken.VirtualSymbolName;tmpResults.PostfixSolveList.push(this.getPosfixSolveListOperation(tmpAbstractMultiplyToken,this.getTokenContainerObject('-1.0'),tmpSolveLayerTokens[i+1]));}// The + at the beginning is also a number line orientation modifier ... THAT WE IGNORE
3595
+ else if(i==0&&tmpToken.Token=='+'){continue;}// The + after an operator or a parenthesis is also a number line orientation modifier ... THAT WE IGNORE
3596
+ else if(i>0&&tmpToken.Token=='+'&&(tmpSolveLayerTokens[i-1].Type==='Token.Operator'||tmpSolveLayerTokens[i-1].Token==='(')){continue;}// Finally add the dang thing.
3597
+ else{tmpResults.PostfixSolveList.push(this.getPosfixSolveListOperation(tmpToken,tmpSolveLayerTokens[i-1],tmpSolveLayerTokens[i+1],tmpSolveLayerTokens,i));}}else if(tmpSolveLayerTokens[i].Type==='Token.Function'&&tmpPrecedence===0){let tmpToken=tmpSolveLayerTokens[i];// Not sure what to do with the other token.
3598
+ tmpResults.PostfixSolveList.push(this.getPosfixSolveListOperation(tmpToken,tmpSolveLayerTokens[i+1],this.getTokenContainerObject('0.0')));}}}}// Now set the assignment address.
3599
+ let tmpAssignmentInstruction=this.getPosfixSolveListOperation(this.getTokenContainerObject('Assign','Token.SolverInstruction'),this.getTokenContainerObject('DestinationHash','Token.SolverInstruction'),this.getTokenContainerObject('Resulting','Token.SolverInstruction'));tmpAssignmentInstruction.VirtualSymbolName=tmpResults.PostfixedAssignmentAddress;tmpResults.PostfixSolveList.push(tmpAssignmentInstruction);return tmpResults.PostfixSolveList;}}module.exports=ExpressionParserPostfix;},{"./Fable-Service-ExpressionParser-Base.js":136}],141:[function(require,module,exports){const libExpressionParserOperationBase=require('./Fable-Service-ExpressionParser-Base.js');class ExpressionParserSolver extends libExpressionParserOperationBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ExpressionParser-Solver';}solvePostfixedExpression(pPostfixedExpression,pDataDestinationObject,pResultObject,pManifest){let tmpResults=typeof pResultObject==='object'?pResultObject:{ExpressionParserLog:[]};let tmpManifest=typeof pManifest==='object'?pManifest:this.fable.newManyfest();let tmpDataDestinationObject=typeof pDataDestinationObject==='object'?pDataDestinationObject:{};// If there was a fable passed in (e.g. the results object was a service or such), we won't decorate
3600
+ let tmpPassedInFable=tmpResults.hasOwnProperty('fable');if(!tmpPassedInFable){tmpResults.fable=this.fable;}if(!Array.isArray(pPostfixedExpression)){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.solvePostfixedExpression was passed a non-array postfixed expression.");this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return false;}if(pPostfixedExpression.length<1){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.solvePostfixedExpression was passed an empty postfixed expression.");this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return false;}// This is how the user communication magic happens.
3601
+ tmpResults.VirtualSymbols={};for(let i=0;i<pPostfixedExpression.length;i++){if(pPostfixedExpression[i].Operation.Type==='Token.SolverInstruction'){continue;}let tmpStepResultObject={ExpressionStep:pPostfixedExpression[i],ExpressionStepIndex:i,ResultsObject:tmpResults,Manifest:tmpManifest};// Resolve the virtual symbols to their actual values
3602
+ if(tmpStepResultObject.ExpressionStep.LeftValue.Type==='Token.VirtualSymbol'){tmpStepResultObject.ExpressionStep.LeftValue.Value=tmpManifest.getValueAtAddress(tmpResults.VirtualSymbols,tmpStepResultObject.ExpressionStep.LeftValue.Token);}if(tmpStepResultObject.ExpressionStep.RightValue.Type==='Token.VirtualSymbol'){tmpStepResultObject.ExpressionStep.RightValue.Value=tmpManifest.getValueAtAddress(tmpResults.VirtualSymbols,tmpStepResultObject.ExpressionStep.RightValue.Token);}// Resolve the parenthesis to their actual values
3603
+ if(tmpStepResultObject.ExpressionStep.LeftValue.Type==='Token.Parenthesis'){tmpStepResultObject.ExpressionStep.LeftValue.Value=tmpManifest.getValueAtAddress(tmpResults.VirtualSymbols,tmpStepResultObject.ExpressionStep.LeftValue.VirtualSymbolName);}if(tmpStepResultObject.ExpressionStep.RightValue.Type==='Token.Parenthesis'){tmpStepResultObject.ExpressionStep.RightValue.Value=tmpManifest.getValueAtAddress(tmpResults.VirtualSymbols,tmpStepResultObject.ExpressionStep.RightValue.VirtualSymbolName);}if(tmpStepResultObject.ExpressionStep.Operation.Type='Operator'){// TODO: This can be optimized. A lot. If necessary. Seems pretty fast honestly for even thousands of operations. Slowest part is arbitrary precision.
3604
+ // An operator always has a left and right value.
3605
+ let tmpFunctionAddress=false;if(this.ExpressionParser.tokenMap.hasOwnProperty(tmpStepResultObject.ExpressionStep.Operation.Token)){tmpFunctionAddress="ResultsObject.".concat(tmpStepResultObject.ExpressionStep.Operation.Descriptor.Function);}else if(this.ExpressionParser.functionMap.hasOwnProperty(tmpStepResultObject.ExpressionStep.Operation.Token.toLowerCase())){tmpFunctionAddress="ResultsObject.".concat(this.ExpressionParser.functionMap[tmpStepResultObject.ExpressionStep.Operation.Token.toLowerCase()].Address);}try{this.log.trace("Solving Step ".concat(i," [").concat(tmpStepResultObject.ExpressionStep.VirtualSymbolName,"] --> [").concat(tmpStepResultObject.ExpressionStep.Operation.Token,"]: ( ").concat(tmpStepResultObject.ExpressionStep.LeftValue.Value," , ").concat(tmpStepResultObject.ExpressionStep.RightValue.Value," )"));tmpResults.VirtualSymbols[tmpStepResultObject.ExpressionStep.VirtualSymbolName]=tmpManifest.getValueAtAddress(tmpStepResultObject,"".concat(tmpFunctionAddress,"(ExpressionStep.LeftValue.Value,ExpressionStep.RightValue.Value)"));this.log.trace(" ---> Step ".concat(i,": ").concat(tmpResults.VirtualSymbols[tmpStepResultObject.ExpressionStep.VirtualSymbolName]));}catch(pError){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.solvePostfixedExpression failed to solve step ".concat(i," with function ").concat(tmpStepResultObject.ExpressionStep.Operation.Token,"."));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return false;}// Equations don't always solve in virtual symbol order.
3606
+ tmpResults.SolverFinalVirtualSymbol=tmpStepResultObject.ExpressionStep.VirtualSymbolName;}}let tmpSolverResultValue=tmpManifest.getValueAtAddress(tmpResults,"VirtualSymbols.".concat(tmpResults.SolverFinalVirtualSymbol));// Now deal with final assignment
3607
+ for(let i=0;i<pPostfixedExpression.length;i++){if(pPostfixedExpression[i].Operation.Type==='Token.SolverInstruction'&&pPostfixedExpression[i].Operation.Token=='Assign'){tmpManifest.setValueAtAddress(tmpResults.VirtualSymbols,pPostfixedExpression[i].VirtualSymbolName,tmpSolverResultValue);tmpManifest.setValueByHash(tmpDataDestinationObject,pPostfixedExpression[i].VirtualSymbolName,tmpSolverResultValue);}}// Clean up the reference if we added it to the object.
3608
+ if(!tmpPassedInFable){delete tmpResults.fable;}return tmpSolverResultValue.toString();}}module.exports=ExpressionParserSolver;},{"./Fable-Service-ExpressionParser-Base.js":136}],142:[function(require,module,exports){module.exports={"=":{"Name":"Equals","Token":"=","Precedence":0,"Type":"Assignment"},"(":{"Name":"Left Parenthesis","Token":"(","Precedence":0,"Type":"Parenthesis"},")":{"Name":"Right Parenthesis","Token":")","Precedence":0,"Type":"Parenthesis"},"*":{"Name":"Multiply","Token":"*","Function":"fable.Math.multiplyPrecise","Precedence":3,"Type":"Operator"},"/":{"Name":"Divide","Token":"/","Function":"fable.Math.dividePrecise","Precedence":3,"Type":"Operator"},"^":{"Name":"Exponent","Token":"^","Function":"fable.Math.powerPrecise","Precedence":1,"Type":"Operator"},"%":{"Name":"Modulus","Token":"%","Function":"fable.Math.modPrecise","Precedence":3,"Type":"Operator"},"+":{"Name":"Add","Token":"+","Function":"fable.Math.addPrecise","Precedence":4,"Type":"Operator"},"-":{"Name":"Subtract","Token":"-","Function":"fable.Math.subtractPrecise","Precedence":4,"Type":"Operator"}};},{}],143:[function(require,module,exports){(function(process){(function(){const libFableServiceBase=require('fable-serviceproviderbase');const libFS=require('fs');const libPath=require('path');const libReadline=require('readline');class FableServiceFilePersistence extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='FilePersistence';if(!this.options.hasOwnProperty('Mode')){this.options.Mode=parseInt('0777',8)&~process.umask();}this.libFS=libFS;this.libPath=libPath;this.libReadline=libReadline;}joinPath(){return libPath.resolve(...arguments);}existsSync(pPath){return libFS.existsSync(pPath);}exists(pPath,fCallback){let tmpFileExists=this.existsSync(pPath);;return fCallback(null,tmpFileExists);}appendFileSync(pFileName,pAppendContent,pOptions){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.appendFileSync(pFileName,pAppendContent,tmpOptions);}deleteFileSync(pFileName){return libFS.unlinkSync(pFileName);}deleteFolderSync(pFileName){return libFS.rmdirSync(pFileName);}readFileSync(pFilePath,pOptions){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.readFileSync(pFilePath,tmpOptions);}readFile(pFilePath,pOptions,fCallback){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.readFile(pFilePath,tmpOptions,fCallback);}writeFileSync(pFileName,pFileContent,pOptions){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.writeFileSync(pFileName,pFileContent,tmpOptions);}writeFileSyncFromObject(pFileName,pObject){return this.writeFileSync(pFileName,JSON.stringify(pObject,null,4));}writeFileSyncFromArray(pFileName,pFileArray){if(!Array.isArray(pFileArray)){this.log.error("File Persistence Service attempted to write ".concat(pFileName," from array but the expected array was not an array (it was a ").concat(typeof pFileArray,")."));return Error('Attempted to write ${pFileName} from array but the expected array was not an array (it was a ${typeof(pFileArray)}).');}else{for(let i=0;i<pFileArray.length;i++){return this.appendFileSync(pFileName,"".concat(pFileArray[i],"\n"));}}}writeFile(pFileName,pFileContent,pOptions,fCallback){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.writeFile(pFileName,pFileContent,tmpOptions,fCallback);}lineReaderFactory(pFilePath,fOnLine,fOnComplete,fOnError){let tmpLineReader={};if(typeof pFilePath!='string'){return false;}tmpLineReader.filePath=pFilePath;tmpLineReader.fileStream=libFS.createReadStream(tmpLineReader.filePath);tmpLineReader.reader=libReadline.createInterface({input:tmpLineReader.fileStream,crlfDelay:Infinity});if(typeof fOnError==='function'){tmpLineReader.reader.on('error',fOnError);}tmpLineReader.reader.on('line',typeof fOnLine==='function'?fOnLine:()=>{});if(typeof fOnComplete==='function'){tmpLineReader.reader.on('close',fOnComplete);}return tmpLineReader;}// Folder management
3344
3609
  makeFolderRecursive(pParameters,fCallback){let tmpParameters=pParameters;if(typeof pParameters=='string'){tmpParameters={Path:pParameters};}else if(typeof pParameters!=='object'){fCallback(new Error('Parameters object or string not properly passed to recursive folder create.'));return false;}if(typeof tmpParameters.Path!=='string'){fCallback(new Error('Parameters object needs a path to run the folder create operation.'));return false;}if(!tmpParameters.hasOwnProperty('Mode')){tmpParameters.Mode=this.options.Mode;}// Check if we are just starting .. if so, build the initial state for our recursive function
3345
3610
  if(typeof tmpParameters.CurrentPathIndex==='undefined'){// Build the tools to start recursing
3346
3611
  tmpParameters.ActualPath=libPath.normalize(tmpParameters.Path);tmpParameters.ActualPathParts=tmpParameters.ActualPath.split(libPath.sep);tmpParameters.CurrentPathIndex=0;tmpParameters.CurrentPath='';}else{// This is not our first run, so we will continue the recursion.
@@ -3350,7 +3615,7 @@ tmpParameters.CurrentPathIndex++;}// Check if the path is fully complete
3350
3615
  if(tmpParameters.CurrentPathIndex>=tmpParameters.ActualPathParts.length){return fCallback(null);}// Check if the path exists (and is a folder)
3351
3616
  libFS.open(tmpParameters.CurrentPath+libPath.sep+tmpParameters.ActualPathParts[tmpParameters.CurrentPathIndex],'r',(pError,pFileDescriptor)=>{if(pFileDescriptor){libFS.closeSync(pFileDescriptor);}if(pError&&pError.code=='ENOENT'){/* Path doesn't exist, create it */libFS.mkdir(tmpParameters.CurrentPath+libPath.sep+tmpParameters.ActualPathParts[tmpParameters.CurrentPathIndex],tmpParameters.Mode,pCreateError=>{if(!pCreateError){// We have now created our folder and there was no error -- continue.
3352
3617
  return this.makeFolderRecursive(tmpParameters,fCallback);}else if(pCreateError.code=='EEXIST'){// The folder exists -- our dev might be running this in parallel/async/whatnot.
3353
- return this.makeFolderRecursive(tmpParameters,fCallback);}else{console.log(pCreateError.code);return fCallback(pCreateError);}});}else{return this.makeFolderRecursive(tmpParameters,fCallback);}});}}module.exports=FableServiceFilePersistence;}).call(this);}).call(this,require('_process'));},{"_process":87,"fable-serviceproviderbase":51,"fs":19,"path":83,"readline":19}],136:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');/**
3618
+ return this.makeFolderRecursive(tmpParameters,fCallback);}else{console.log(pCreateError.code);return fCallback(pCreateError);}});}else{return this.makeFolderRecursive(tmpParameters,fCallback);}});}}module.exports=FableServiceFilePersistence;}).call(this);}).call(this,require('_process'));},{"_process":87,"fable-serviceproviderbase":51,"fs":19,"path":83,"readline":19}],144:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');/**
3354
3619
  * Arbitrary Precision Math Operations
3355
3620
  * @author Steven Velozo <steven@velozo.com>
3356
3621
  * @description Simple functions that perform arbitrary precision math operations and return string resultant values. Wraps big.js
@@ -3365,7 +3630,9 @@ return this.makeFolderRecursive(tmpParameters,fCallback);}else{console.log(pCrea
3365
3630
  roundHalfUp 1 ROUND_HALF_UP Rounds towards nearest neighbour. (_If equidistant, rounds away from zero._)
3366
3631
  roundHalfEven 2 ROUND_HALF_EVEN Rounds towards nearest neighbour. (_If equidistant, rounds towards even neighbour._)
3367
3632
  roundUp 3 ROUND_UP Rounds positively away from zero. (_Always round up._)
3368
- */get roundDown(){return this.fable.Utility.bigNumber.roundDown;}get roundHalfUp(){return this.fable.Utility.bigNumber.roundHalfUp;}get roundHalfEven(){return this.fable.Utility.bigNumber.roundHalfEven;}get roundUp(){return this.fable.Utility.bigNumber.roundUp;}parsePrecise(pValue,pNonNumberValue){let tmpNumber;try{tmpNumber=new this.fable.Utility.bigNumber(pValue);}catch(pError){this.log.warn("Error parsing number (type ".concat(typeof pValue,"): ").concat(pError));tmpNumber=typeof pNonNumberValue==='undefined'?"0.0":pNonNumberValue;}return tmpNumber.toString();}percentagePrecise(pIs,pOf){let tmpLeftValue=isNaN(pIs)?0:pIs;let tmpRightValue=isNaN(pOf)?0:pOf;if(tmpRightValue==0){return'0';}let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.div(tmpRightValue);tmpResult=tmpResult.times(100);return tmpResult.toString();}roundPrecise(pValue,pDecimals,pRoundingMethod){let tmpValue=isNaN(pValue)?0:pValue;let tmpDecimals=isNaN(pDecimals)?0:pDecimals;let tmpRoundingMethod=typeof pRoundingMethod==='undefined'?this.roundHalfUp:pRoundingMethod;let tmpArbitraryValue=new this.fable.Utility.bigNumber(tmpValue);let tmpResult=tmpArbitraryValue.round(tmpDecimals,tmpRoundingMethod);return tmpResult.toString();}toFixedPrecise(pValue,pDecimals,pRoundingMethod){let tmpValue=isNaN(pValue)?0:pValue;let tmpDecimals=isNaN(pDecimals)?0:pDecimals;let tmpRoundingMethod=typeof pRoundingMethod==='undefined'?this.roundHalfUp:pRoundingMethod;let tmpArbitraryValue=new this.fable.Utility.bigNumber(tmpValue);let tmpResult=tmpArbitraryValue.toFixed(tmpDecimals,tmpRoundingMethod);return tmpResult.toString();}addPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.plus(tmpRightValue);return tmpResult.toString();}subtractPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.minus(tmpRightValue);return tmpResult.toString();}powerPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.pow(tmpRightValue);return tmpResult.toString();}multiplyPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.times(tmpRightValue);return tmpResult.toString();}dividePrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.div(tmpRightValue);return tmpResult.toString();}modPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.mod(tmpRightValue);return tmpResult.toString();}sqrtPrecise(pValue){let tmpValue=isNaN(pValue)?0:pValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpValue);let tmpResult=tmpLeftArbitraryValue.sqrt();return tmpResult.toString();}absPrecise(pValue){let tmpValue=isNaN(pValue)?0:pValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpValue);let tmpResult=tmpLeftArbitraryValue.abs();return tmpResult.toString();}comparePrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);return tmpLeftArbitraryValue.cmp(tmpRightValue);}gtPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);return tmpLeftArbitraryValue.gt(tmpRightValue);}gtePrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);return tmpLeftArbitraryValue.gte(tmpRightValue);}ltPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);return tmpLeftArbitraryValue.lt(tmpRightValue);}ltePrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);return tmpLeftArbitraryValue.lt(tmpRightValue);}}module.exports=FableServiceMath;},{"fable-serviceproviderbase":51}],137:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');/**
3633
+ */get roundDown(){return this.fable.Utility.bigNumber.roundDown;}get roundHalfUp(){return this.fable.Utility.bigNumber.roundHalfUp;}get roundHalfEven(){return this.fable.Utility.bigNumber.roundHalfEven;}get roundUp(){return this.fable.Utility.bigNumber.roundUp;}parsePrecise(pValue,pNonNumberValue){let tmpNumber;try{tmpNumber=new this.fable.Utility.bigNumber(pValue);}catch(pError){this.log.warn("Error parsing number (type ".concat(typeof pValue,"): ").concat(pError));tmpNumber=typeof pNonNumberValue==='undefined'?"0.0":pNonNumberValue;}return tmpNumber.toString();}percentagePrecise(pIs,pOf){let tmpLeftValue=isNaN(pIs)?0:pIs;let tmpRightValue=isNaN(pOf)?0:pOf;if(tmpRightValue==0){return'0';}let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.div(tmpRightValue);tmpResult=tmpResult.times(100);return tmpResult.toString();}roundPrecise(pValue,pDecimals,pRoundingMethod){let tmpValue=isNaN(pValue)?0:pValue;let tmpDecimals=isNaN(pDecimals)?0:pDecimals;let tmpRoundingMethod=typeof pRoundingMethod==='undefined'?this.roundHalfUp:pRoundingMethod;let tmpArbitraryValue=new this.fable.Utility.bigNumber(tmpValue);let tmpResult=tmpArbitraryValue.round(tmpDecimals,tmpRoundingMethod);return tmpResult.toString();}toFixedPrecise(pValue,pDecimals,pRoundingMethod){let tmpValue=isNaN(pValue)?0:pValue;let tmpDecimals=isNaN(pDecimals)?0:pDecimals;let tmpRoundingMethod=typeof pRoundingMethod==='undefined'?this.roundHalfUp:pRoundingMethod;let tmpArbitraryValue=new this.fable.Utility.bigNumber(tmpValue);let tmpResult=tmpArbitraryValue.toFixed(tmpDecimals,tmpRoundingMethod);return tmpResult.toString();}addPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.plus(tmpRightValue);return tmpResult.toString();}subtractPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.minus(tmpRightValue);return tmpResult.toString();}// Bignumber does not use precision values for power -- only javascript decimals
3634
+ powerPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:parseInt(pRightValue);let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.pow(tmpRightValue);return tmpResult.toString();}multiplyPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.times(tmpRightValue);return tmpResult.toString();}dividePrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.div(tmpRightValue);return tmpResult.toString();}modPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);let tmpResult=tmpLeftArbitraryValue.mod(tmpRightValue);return tmpResult.toString();}sqrtPrecise(pValue){let tmpValue=isNaN(pValue)?0:pValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpValue);let tmpResult=tmpLeftArbitraryValue.sqrt();return tmpResult.toString();}absPrecise(pValue){let tmpValue=isNaN(pValue)?0:pValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpValue);let tmpResult=tmpLeftArbitraryValue.abs();return tmpResult.toString();}comparePrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);return tmpLeftArbitraryValue.cmp(tmpRightValue);}gtPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);return tmpLeftArbitraryValue.gt(tmpRightValue);}gtePrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);return tmpLeftArbitraryValue.gte(tmpRightValue);}ltPrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);return tmpLeftArbitraryValue.lt(tmpRightValue);}ltePrecise(pLeftValue,pRightValue){let tmpLeftValue=isNaN(pLeftValue)?0:pLeftValue;let tmpRightValue=isNaN(pRightValue)?0:pRightValue;let tmpLeftArbitraryValue=new this.fable.Utility.bigNumber(tmpLeftValue);return tmpLeftArbitraryValue.lt(tmpRightValue);}radPrecise(pDegrees){let tmpDegrees=isNaN(pDegrees)?0:pDegrees;let tmpDegreesArbitraryValue=new this.fable.Utility.bigNumber(tmpDegrees);// TODO: Const for pi in arbitrary precision?
3635
+ let tmpResult=tmpDegreesArbitraryValue.times(Math.PI).div(180);return tmpResult.toString();}sin(pRadians){let tmpRadians=isNaN(pRadians)?0:pRadians;return Math.sin(tmpRadians);}cos(pRadians){let tmpRadians=isNaN(pRadians)?0:pRadians;return Math.cos(tmpRadians);}tan(pRadians){let tmpRadians=isNaN(pRadians)?0:pRadians;return Math.tan(tmpRadians);}}module.exports=FableServiceMath;},{"fable-serviceproviderbase":51}],145:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');/**
3369
3636
  * Precedent Meta-Templating
3370
3637
  * @author Steven Velozo <steven@velozo.com>
3371
3638
  * @description Process text stream trie and postfix tree, parsing out meta-template expression functions.
@@ -3381,8 +3648,10 @@ return this.makeFolderRecursive(tmpParameters,fCallback);}else{console.log(pCrea
3381
3648
  * @method parseString
3382
3649
  * @param {string} pString - The string to parse
3383
3650
  * @param {object} pData - Data to pass in as the second argument
3651
+ * @param {function} fCallback - The callback function to call when a pattern is matched
3652
+ * @param {array} pDataContext - The history of data objects already passed in
3384
3653
  * @return {string} The result from the parser
3385
- */parseString(pString,pData,fCallback){if(this.LogNoisiness>4){this.fable.log.trace("Metatemplate parsing template string [".concat(pString,"] where the callback is a ").concat(typeof fCallback),{TemplateData:pData});}return this.StringParser.parseString(pString,this.ParseTree,pData,fCallback);}}module.exports=FableServiceMetaTemplate;},{"./Fable-Service-MetaTemplate/MetaTemplate-StringParser.js":138,"./Fable-Service-MetaTemplate/MetaTemplate-WordTree.js":139,"fable-serviceproviderbase":51}],138:[function(require,module,exports){/**
3654
+ */parseString(pString,pData,fCallback,pDataContext){if(this.LogNoisiness>4){this.fable.log.trace("Metatemplate parsing template string [".concat(pString,"] where the callback is a ").concat(typeof fCallback),{TemplateData:pData});}return this.StringParser.parseString(pString,this.ParseTree,pData,fCallback,pDataContext);}}module.exports=FableServiceMetaTemplate;},{"./Fable-Service-MetaTemplate/MetaTemplate-StringParser.js":146,"./Fable-Service-MetaTemplate/MetaTemplate-WordTree.js":147,"fable-serviceproviderbase":51}],146:[function(require,module,exports){/**
3386
3655
  * String Parser
3387
3656
  * @author Steven Velozo <steven@velozo.com>
3388
3657
  * @description Parse a string, properly processing each matched token in the word tree.
@@ -3414,42 +3683,45 @@ pParserState.Pattern=false;pParserState.PatternStartNode=false;pParserState.Star
3414
3683
  * @param {string} pCharacter - The character to append
3415
3684
  * @param {Object} pParserState - The state object for the current parsing task
3416
3685
  * @private
3417
- */parseCharacter(pCharacter,pParserState,pData){// If we are already in a pattern match traversal
3686
+ */parseCharacter(pCharacter,pParserState,pData,pDataContext){// If we are already in a pattern match traversal
3418
3687
  if(pParserState.PatternMatch){// If the pattern is still matching the start and we haven't passed the buffer
3419
3688
  if(!pParserState.StartPatternMatchComplete&&pParserState.Pattern.hasOwnProperty(pCharacter)){pParserState.Pattern=pParserState.Pattern[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else if(pParserState.EndPatternMatchBegan){if(pParserState.Pattern.PatternEnd.hasOwnProperty(pCharacter)){// This leaf has a PatternEnd tree, so we will wait until that end is met.
3420
3689
  pParserState.Pattern=pParserState.Pattern.PatternEnd[pCharacter];// Flush the output buffer.
3421
3690
  this.appendOutputBuffer(pCharacter,pParserState);// If this last character is the end of the pattern, parse it.
3422
3691
  if(pParserState.Pattern.hasOwnProperty('Parse')&&(!pParserState.Pattern.isAsync||pParserState.Pattern.isBoth)){// Run the function
3423
- pParserState.OutputBuffer=pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length,pParserState.OutputBuffer.length-(pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)),pData);return this.resetOutputBuffer(pParserState);}else{this.fable.log.info("MetaTemplate: The pattern ".concat(pParserState.Pattern.PatternStartString," is asynchronous and cannot be used in a synchronous parser."));return this.resetOutputBuffer(pParserState);}}else if(pParserState.PatternStartNode.PatternEnd.hasOwnProperty(pCharacter)){// We broke out of the end -- see if this is a new start of the end.
3692
+ pParserState.OutputBuffer=pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length,pParserState.OutputBuffer.length-(pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)),pData,pDataContext);return this.resetOutputBuffer(pParserState);}else{this.fable.log.info("MetaTemplate: The pattern ".concat(pParserState.Pattern.PatternStartString," is asynchronous and cannot be used in a synchronous parser."));return this.resetOutputBuffer(pParserState);}}else if(pParserState.PatternStartNode.PatternEnd.hasOwnProperty(pCharacter)){// We broke out of the end -- see if this is a new start of the end.
3424
3693
  pParserState.Pattern=pParserState.PatternStartNode.PatternEnd[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else{pParserState.EndPatternMatchBegan=false;this.appendOutputBuffer(pCharacter,pParserState);}}else if(pParserState.Pattern.hasOwnProperty('PatternEnd')){if(!pParserState.StartPatternMatchComplete){pParserState.StartPatternMatchComplete=true;pParserState.PatternStartNode=pParserState.Pattern;}this.appendOutputBuffer(pCharacter,pParserState);if(pParserState.Pattern.PatternEnd.hasOwnProperty(pCharacter)){// This is the first character of the end pattern.
3425
3694
  pParserState.EndPatternMatchBegan=true;// This leaf has a PatternEnd tree, so we will wait until that end is met.
3426
3695
  pParserState.Pattern=pParserState.Pattern.PatternEnd[pCharacter];// If this last character is the end of the pattern, parse it.
3427
3696
  if(pParserState.Pattern.hasOwnProperty('Parse')){if(pParserState.Pattern.isAsync&&!pParserState.Pattern.isBoth){this.fable.log.info("MetaTemplate: The pattern ".concat(pParserState.Pattern.PatternStartString," is asynchronous and cannot be used in a synchronous parser."));this.resetOutputBuffer(pParserState);}else{// Run the t*mplate function
3428
- pParserState.OutputBuffer=pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length,pParserState.OutputBuffer.length-(pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)),pData);return this.resetOutputBuffer(pParserState);}}}}else{// We are in a pattern start but didn't match one; reset and start trying again from this character.
3697
+ pParserState.OutputBuffer=pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length,pParserState.OutputBuffer.length-(pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)),pData,pDataContext);return this.resetOutputBuffer(pParserState);}}}}else{// We are in a pattern start but didn't match one; reset and start trying again from this character.
3429
3698
  this.resetOutputBuffer(pParserState);}}// If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....
3430
3699
  if(!pParserState.PatternMatch){// This may be the start of a new pattern....
3431
3700
  if(pParserState.ParseTree.hasOwnProperty(pCharacter)){// ... assign the root node as the matched node.
3432
- this.resetOutputBuffer(pParserState);this.appendOutputBuffer(pCharacter,pParserState);pParserState.Pattern=pParserState.ParseTree[pCharacter];pParserState.PatternMatch=true;return true;}else{this.appendOutputBuffer(pCharacter,pParserState);}}return false;}executePatternAsync(pParserState,pData,fCallback){// ... this is the end of a pattern, cut off the end tag and parse it.
3701
+ this.resetOutputBuffer(pParserState);this.appendOutputBuffer(pCharacter,pParserState);pParserState.Pattern=pParserState.ParseTree[pCharacter];pParserState.PatternMatch=true;return true;}else{this.appendOutputBuffer(pCharacter,pParserState);}}return false;}executePatternAsync(pParserState,pData,fCallback,pDataContext){// ... this is the end of a pattern, cut off the end tag and parse it.
3433
3702
  // Trim the start and end tags off the output buffer now
3434
3703
  if(pParserState.Pattern.isAsync&&!pParserState.Pattern.isBoth){// Run the function
3435
- return pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length,pParserState.OutputBuffer.length-(pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)),pData,(pError,pAsyncOutput)=>{if(pError){this.fable.log.info("Precedent ERROR: Async template error happened parsing ".concat(pParserState.Pattern.PatternStart," ... ").concat(pParserState.Pattern.PatternEnd,": ").concat(pError));}pParserState.OutputBuffer=pAsyncOutput;this.resetOutputBuffer(pParserState);return fCallback();});}else if(pParserState.Pattern.isAsync&&pParserState.Pattern.isBoth){// Run the function when both async and non async were provided with the pattern
3436
- return pParserState.Pattern.ParseAsync(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length,pParserState.OutputBuffer.length-(pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)),pData,(pError,pAsyncOutput)=>{if(pError){this.fable.log.info("Precedent ERROR: Async template error happened parsing ".concat(pParserState.Pattern.PatternStart," ... ").concat(pParserState.Pattern.PatternEnd,": ").concat(pError));}pParserState.OutputBuffer=pAsyncOutput;this.resetOutputBuffer(pParserState);return fCallback();});}else{// Run the t*mplate function
3437
- pParserState.OutputBuffer=pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length,pParserState.OutputBuffer.length-(pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)),pData);this.resetOutputBuffer(pParserState);return fCallback();}}/**
3704
+ return pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length,pParserState.OutputBuffer.length-(pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)),pData,(pError,pAsyncOutput)=>{if(pError){this.fable.log.info("Precedent ERROR: Async template error happened parsing ".concat(pParserState.Pattern.PatternStart," ... ").concat(pParserState.Pattern.PatternEnd,": ").concat(pError));}pParserState.OutputBuffer=pAsyncOutput;this.resetOutputBuffer(pParserState);return fCallback();},pDataContext);}else if(pParserState.Pattern.isAsync&&pParserState.Pattern.isBoth){// Run the function when both async and non async were provided with the pattern
3705
+ return pParserState.Pattern.ParseAsync(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length,pParserState.OutputBuffer.length-(pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)),pData,(pError,pAsyncOutput)=>{if(pError){this.fable.log.info("Precedent ERROR: Async template error happened parsing ".concat(pParserState.Pattern.PatternStart," ... ").concat(pParserState.Pattern.PatternEnd,": ").concat(pError));}pParserState.OutputBuffer=pAsyncOutput;this.resetOutputBuffer(pParserState);return fCallback();},pDataContext);}else{// Run the t*mplate function
3706
+ pParserState.OutputBuffer=pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length,pParserState.OutputBuffer.length-(pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)),pData,pDataContext);this.resetOutputBuffer(pParserState);return fCallback();}}/**
3438
3707
  * Parse a character in the buffer.
3439
- * @method parseCharacter
3708
+ * @method parseCharacterAsync
3440
3709
  * @param {string} pCharacter - The character to append
3441
3710
  * @param {Object} pParserState - The state object for the current parsing task
3711
+ * @param {Object} pData - The data to pass to the function as a second parameter
3712
+ * @param {function} fCallback - The callback function to call when the parse is complete
3713
+ * @param {array} pDataContext - The history of data objects/context already passed in
3442
3714
  * @private
3443
- */parseCharacterAsync(pCharacter,pParserState,pData,fCallback){// If we are already in a pattern match traversal
3715
+ */parseCharacterAsync(pCharacter,pParserState,pData,fCallback,pDataContext){// If we are already in a pattern match traversal
3444
3716
  if(pParserState.PatternMatch){// If the pattern is still matching the start and we haven't passed the buffer
3445
3717
  if(!pParserState.StartPatternMatchComplete&&pParserState.Pattern.hasOwnProperty(pCharacter)){pParserState.Pattern=pParserState.Pattern[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else if(pParserState.EndPatternMatchBegan){if(pParserState.Pattern.PatternEnd.hasOwnProperty(pCharacter)){// This leaf has a PatternEnd tree, so we will wait until that end is met.
3446
3718
  pParserState.Pattern=pParserState.Pattern.PatternEnd[pCharacter];// Flush the output buffer.
3447
3719
  this.appendOutputBuffer(pCharacter,pParserState);// If this last character is the end of the pattern, parse it.
3448
- if(pParserState.Pattern.hasOwnProperty('Parse')){return this.executePatternAsync(pParserState,pData,fCallback);}}else if(pParserState.PatternStartNode.PatternEnd.hasOwnProperty(pCharacter)){// We broke out of the end -- see if this is a new start of the end.
3720
+ if(pParserState.Pattern.hasOwnProperty('Parse')){return this.executePatternAsync(pParserState,pData,fCallback,pDataContext);}}else if(pParserState.PatternStartNode.PatternEnd.hasOwnProperty(pCharacter)){// We broke out of the end -- see if this is a new start of the end.
3449
3721
  pParserState.Pattern=pParserState.PatternStartNode.PatternEnd[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else{pParserState.EndPatternMatchBegan=false;this.appendOutputBuffer(pCharacter,pParserState);}}else if(pParserState.Pattern.hasOwnProperty('PatternEnd')){if(!pParserState.StartPatternMatchComplete){pParserState.StartPatternMatchComplete=true;pParserState.PatternStartNode=pParserState.Pattern;}this.appendOutputBuffer(pCharacter,pParserState);if(pParserState.Pattern.PatternEnd.hasOwnProperty(pCharacter)){// This is the first character of the end pattern.
3450
3722
  pParserState.EndPatternMatchBegan=true;// This leaf has a PatternEnd tree, so we will wait until that end is met.
3451
3723
  pParserState.Pattern=pParserState.Pattern.PatternEnd[pCharacter];// If this last character is the end of the pattern, parse it.
3452
- if(pParserState.Pattern.hasOwnProperty('Parse')){return this.executePatternAsync(pParserState,pData,fCallback);}}}else{// We are in a pattern start but didn't match one; reset and start trying again from this character.
3724
+ if(pParserState.Pattern.hasOwnProperty('Parse')){return this.executePatternAsync(pParserState,pData,fCallback,pDataContext);}}}else{// We are in a pattern start but didn't match one; reset and start trying again from this character.
3453
3725
  this.resetOutputBuffer(pParserState);}}// If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....
3454
3726
  else{// This may be the start of a new pattern....
3455
3727
  if(pParserState.ParseTree.hasOwnProperty(pCharacter)){// ... assign the root node as the matched node.
@@ -3462,10 +3734,12 @@ return fCallback();}/**
3462
3734
  * @param {Object} pParseTree - The parse tree to begin parsing from (usually root)
3463
3735
  * @param {Object} pData - The data to pass to the function as a second parameter
3464
3736
  * @param {function} fCallback - The callback function to call when the parse is complete
3465
- */parseString(pString,pParseTree,pData,fCallback){if(typeof fCallback!=='function'){let tmpParserState=this.newParserState(pParseTree);for(var i=0;i<pString.length;i++){// TODO: This is not fast.
3466
- this.parseCharacter(pString[i],tmpParserState,pData,fCallback);}this.flushOutputBuffer(tmpParserState);return tmpParserState.Output;}else{// This is the async mode
3467
- let tmpParserState=this.newParserState(pParseTree);tmpParserState.Asynchronous=true;let tmpAnticipate=this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');for(let i=0;i<pString.length;i++){tmpAnticipate.anticipate(fCallback=>{this.parseCharacterAsync(pString[i],tmpParserState,pData,fCallback);});}tmpAnticipate.wait(pError=>{// Flush the remaining data
3468
- this.flushOutputBuffer(tmpParserState);return fCallback(pError,tmpParserState.Output);});}}}module.exports=StringParser;},{}],139:[function(require,module,exports){/**
3737
+ * @param {array} pDataContext - The history of data objects/context already passed in
3738
+ */parseString(pString,pParseTree,pData,fCallback,pDataContext){// TODO: There is danger here if a template function attempts to functionally recurse and doesn't pass this in.
3739
+ let tmpPreviousDataContext=Array.isArray(pDataContext)?pDataContext:[];let tmpDataContext=Array.from(tmpPreviousDataContext);tmpDataContext.push(pData);if(typeof fCallback!=='function'){let tmpParserState=this.newParserState(pParseTree);for(var i=0;i<pString.length;i++){// TODO: This is not fast.
3740
+ this.parseCharacter(pString[i],tmpParserState,pData,tmpDataContext);}this.flushOutputBuffer(tmpParserState);return tmpParserState.Output;}else{// This is the async mode
3741
+ let tmpParserState=this.newParserState(pParseTree);tmpParserState.Asynchronous=true;let tmpAnticipate=this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');for(let i=0;i<pString.length;i++){tmpAnticipate.anticipate(fCallback=>{this.parseCharacterAsync(pString[i],tmpParserState,pData,fCallback,tmpDataContext);});}tmpAnticipate.wait(pError=>{// Flush the remaining data
3742
+ this.flushOutputBuffer(tmpParserState);return fCallback(pError,tmpParserState.Output);});}}}module.exports=StringParser;},{}],147:[function(require,module,exports){/**
3469
3743
  * Word Tree
3470
3744
  * @author Steven Velozo <steven@velozo.com>
3471
3745
  * @description Create a tree (directed graph) of Javascript objects, one character per object.
@@ -3505,7 +3779,7 @@ for(var i=0;i<pPatternStart.length;i++){tmpLeaf=this.addChild(tmpLeaf,pPatternSt
3505
3779
  * @param {function} fParser - 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.
3506
3780
  * @return {bool} True if adding the pattern was successful
3507
3781
  */addPatternBoth(pPatternStart,pPatternEnd,fParser,fParserAsync){let tmpLeaf=this.addPattern(pPatternStart,pPatternEnd,fParser);if(tmpLeaf){tmpLeaf.isAsync=true;tmpLeaf.isBoth=true;// When a leaf has both async and non-async versions of the functions, we store the async in fParserAsync.
3508
- tmpLeaf.ParseAsync=fParserAsync;}}}module.exports=WordTree;},{}],140:[function(require,module,exports){module.exports={"Metadata":{"UUID":false,"Hash":false,"Name":"","Summary":"","Version":0},"Status":{"Completed":false,"StepCount":0},"Steps":[],"Errors":[],"Log":[]};},{}],141:[function(require,module,exports){const{PE}=require('big.js');const libFableServiceBase=require('fable-serviceproviderbase');const _OperationStatePrototypeString=JSON.stringify(require('./Fable-Service-Operation-DefaultSettings.js'));class FableOperation extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);// Timestamps will just be the long ints
3782
+ tmpLeaf.ParseAsync=fParserAsync;}}}module.exports=WordTree;},{}],148:[function(require,module,exports){module.exports={"Metadata":{"UUID":false,"Hash":false,"Name":"","Summary":"","Version":0},"Status":{"Completed":false,"StepCount":0},"Steps":[],"Errors":[],"Log":[]};},{}],149:[function(require,module,exports){const{PE}=require('big.js');const libFableServiceBase=require('fable-serviceproviderbase');const _OperationStatePrototypeString=JSON.stringify(require('./Fable-Service-Operation-DefaultSettings.js'));class FableOperation extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);// Timestamps will just be the long ints
3509
3783
  this.timeStamps={};this.serviceType='PhasedOperation';this.state=JSON.parse(_OperationStatePrototypeString);this.stepMap={};this.stepFunctions={};// Match the service instantiation to the operation.
3510
3784
  this.state.Metadata.Hash=this.Hash;this.state.Metadata.UUID=this.UUID;this.state.Metadata.Name=typeof this.options.Name=='string'?this.options.Name:"Unnamed Operation ".concat(this.state.Metadata.UUID);this.name=this.state.Metadata.Name;this.progressTrackerSet=this.fable.instantiateServiceProviderWithoutRegistration('ProgressTrackerSet');this.state.OverallProgressTracker=this.progressTrackerSet.createProgressTracker("Overall-".concat(this.state.Metadata.UUID));// This is here to use the pass-through logging functions in the operation itself.
3511
3785
  this.log=this;}execute(fExecutionCompleteCallback){// TODO: Should the same operation be allowed to execute more than one time?
@@ -3520,9 +3794,9 @@ tmpAnticipate.wait(pError=>{if(pError){this.fable.log.error("Operation [".concat
3520
3794
  addStep(fStepFunction,pStepMetadata,pStepName,pStepDescription,pGUIDStep){let tmpStep={};// GUID is optional
3521
3795
  tmpStep.GUIDStep=typeof pGUIDStep!=='undefined'?pGUIDStep:"STEP-".concat(this.state.Steps.length,"-").concat(this.fable.DataGeneration.randomNumericString());// Name is optional
3522
3796
  tmpStep.Name=typeof pStepName!=='undefined'?pStepName:"Step [".concat(tmpStep.GUIDStep,"]");tmpStep.Description=typeof pStepDescription!=='undefined'?pStepDescription:"Step execution of ".concat(tmpStep.Name,".");tmpStep.ProgressTracker=this.progressTrackerSet.createProgressTracker(tmpStep.GUIDStep);tmpStep.Metadata=typeof pStepMetadata==='object'?pStepMetadata:{};// There is an array of steps, in the Operation State itself ... push a step there
3523
- this.state.Steps.push(tmpStep);this.stepMap[tmpStep.GUIDStep]=tmpStep;this.stepFunctions[tmpStep.GUIDStep]=typeof fStepFunction=='function'?fStepFunction:function(fDone){return fDone();};this.state.Status.StepCount++;return tmpStep;}setStepTotalOperations(pGUIDStep,pTotalOperationCount){if(!this.stepMap.hasOwnProperty(pGUIDStep)){return new Error("Step [".concat(pGUIDStep,"] does not exist in operation [").concat(this.state.Metadata.UUID,"] ").concat(this.state.Metadata.Name," when attempting to set total operations to ").concat(pTotalOperationCount,"."));}this.progressTrackerSet.setProgressTrackerTotalOperations(this.stepMap[pGUIDStep].ProgressTracker.Hash,pTotalOperationCount);}writeOperationLog(pLogLevel,pLogText,pLogObject){this.state.Log.push("[".concat(new Date().toUTCString(),"]-[").concat(pLogLevel,"]: ").concat(pLogText));if(typeof pLogObject=='object'){this.state.Log.push(JSON.stringify(pLogObject));}}writeOperationErrors(pLogText,pLogObject){this.state.Errors.push("".concat(pLogText));if(typeof pLogObject=='object'){this.state.Errors.push(JSON.stringify(pLogObject));}}trace(pLogText,pLogObject){this.writeOperationLog('TRACE',pLogText,pLogObject);this.fable.log.trace(pLogText,pLogObject);}debug(pLogText,pLogObject){this.writeOperationLog('DEBUG',pLogText,pLogObject);this.fable.log.debug(pLogText,pLogObject);}info(pLogText,pLogObject){this.writeOperationLog('INFO',pLogText,pLogObject);this.fable.log.info(pLogText,pLogObject);}warn(pLogText,pLogObject){this.writeOperationLog('WARN',pLogText,pLogObject);this.fable.log.warn(pLogText,pLogObject);}error(pLogText,pLogObject){this.writeOperationLog('ERROR',pLogText,pLogObject);this.writeOperationErrors(pLogText,pLogObject);this.fable.log.error(pLogText,pLogObject);}fatal(pLogText,pLogObject){this.writeOperationLog('FATAL',pLogText,pLogObject);this.writeOperationErrors(pLogText,pLogObject);this.fable.log.fatal(pLogText,pLogObject);}}module.exports=FableOperation;},{"./Fable-Service-Operation-DefaultSettings.js":140,"big.js":17,"fable-serviceproviderbase":51}],142:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');class FableServiceProgressTime extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ProgressTime';this.timeStamps={};}formatTimeDuration(pTimeDurationInMilliseconds){let tmpTimeDuration=typeof pTimeDurationInMilliseconds=='number'?pTimeDurationInMilliseconds:0;if(pTimeDurationInMilliseconds<0){return'unknown';}let tmpTimeDurationString='';if(tmpTimeDuration>3600000){tmpTimeDurationString+=Math.floor(tmpTimeDuration/3600000)+'h ';tmpTimeDuration=tmpTimeDuration%3600000;}if(tmpTimeDuration>60000){tmpTimeDurationString+=Math.floor(tmpTimeDuration/60000)+'m ';tmpTimeDuration=tmpTimeDuration%60000;}if(tmpTimeDuration>1000){tmpTimeDurationString+=Math.floor(tmpTimeDuration/1000)+'s ';tmpTimeDuration=tmpTimeDuration%1000;}tmpTimeDurationString+=Math.round(tmpTimeDuration)+'ms';return tmpTimeDurationString;}createTimeStamp(pTimeStampHash){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';this.timeStamps[tmpTimeStampHash]=+new Date();return this.timeStamps[tmpTimeStampHash];}getTimeStampValue(pTimeStampHash){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';return this.timeStamps.hasOwnProperty(tmpTimeStampHash)?this.timeStamps[tmpTimeStampHash]:-1;}updateTimeStampValue(pTimeStampHash,pReferenceTime){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';let tmpReferenceTime=false;// This function allows the user to pass in either a reference time in ms, or, a hash of a timestamp.
3797
+ this.state.Steps.push(tmpStep);this.stepMap[tmpStep.GUIDStep]=tmpStep;this.stepFunctions[tmpStep.GUIDStep]=typeof fStepFunction=='function'?fStepFunction:function(fDone){return fDone();};this.state.Status.StepCount++;return tmpStep;}setStepTotalOperations(pGUIDStep,pTotalOperationCount){if(!this.stepMap.hasOwnProperty(pGUIDStep)){return new Error("Step [".concat(pGUIDStep,"] does not exist in operation [").concat(this.state.Metadata.UUID,"] ").concat(this.state.Metadata.Name," when attempting to set total operations to ").concat(pTotalOperationCount,"."));}this.progressTrackerSet.setProgressTrackerTotalOperations(this.stepMap[pGUIDStep].ProgressTracker.Hash,pTotalOperationCount);}writeOperationLog(pLogLevel,pLogText,pLogObject){this.state.Log.push("[".concat(new Date().toUTCString(),"]-[").concat(pLogLevel,"]: ").concat(pLogText));if(typeof pLogObject=='object'){this.state.Log.push(JSON.stringify(pLogObject));}}writeOperationErrors(pLogText,pLogObject){this.state.Errors.push("".concat(pLogText));if(typeof pLogObject=='object'){this.state.Errors.push(JSON.stringify(pLogObject));}}trace(pLogText,pLogObject){this.writeOperationLog('TRACE',pLogText,pLogObject);this.fable.log.trace(pLogText,pLogObject);}debug(pLogText,pLogObject){this.writeOperationLog('DEBUG',pLogText,pLogObject);this.fable.log.debug(pLogText,pLogObject);}info(pLogText,pLogObject){this.writeOperationLog('INFO',pLogText,pLogObject);this.fable.log.info(pLogText,pLogObject);}warn(pLogText,pLogObject){this.writeOperationLog('WARN',pLogText,pLogObject);this.fable.log.warn(pLogText,pLogObject);}error(pLogText,pLogObject){this.writeOperationLog('ERROR',pLogText,pLogObject);this.writeOperationErrors(pLogText,pLogObject);this.fable.log.error(pLogText,pLogObject);}fatal(pLogText,pLogObject){this.writeOperationLog('FATAL',pLogText,pLogObject);this.writeOperationErrors(pLogText,pLogObject);this.fable.log.fatal(pLogText,pLogObject);}}module.exports=FableOperation;},{"./Fable-Service-Operation-DefaultSettings.js":148,"big.js":17,"fable-serviceproviderbase":51}],150:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');class FableServiceProgressTime extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ProgressTime';this.timeStamps={};}formatTimeDuration(pTimeDurationInMilliseconds){let tmpTimeDuration=typeof pTimeDurationInMilliseconds=='number'?pTimeDurationInMilliseconds:0;if(pTimeDurationInMilliseconds<0){return'unknown';}let tmpTimeDurationString='';if(tmpTimeDuration>3600000){tmpTimeDurationString+=Math.floor(tmpTimeDuration/3600000)+'h ';tmpTimeDuration=tmpTimeDuration%3600000;}if(tmpTimeDuration>60000){tmpTimeDurationString+=Math.floor(tmpTimeDuration/60000)+'m ';tmpTimeDuration=tmpTimeDuration%60000;}if(tmpTimeDuration>1000){tmpTimeDurationString+=Math.floor(tmpTimeDuration/1000)+'s ';tmpTimeDuration=tmpTimeDuration%1000;}tmpTimeDurationString+=Math.round(tmpTimeDuration)+'ms';return tmpTimeDurationString;}createTimeStamp(pTimeStampHash){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';this.timeStamps[tmpTimeStampHash]=+new Date();return this.timeStamps[tmpTimeStampHash];}getTimeStampValue(pTimeStampHash){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';return this.timeStamps.hasOwnProperty(tmpTimeStampHash)?this.timeStamps[tmpTimeStampHash]:-1;}updateTimeStampValue(pTimeStampHash,pReferenceTime){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';let tmpReferenceTime=false;// This function allows the user to pass in either a reference time in ms, or, a hash of a timestamp.
3524
3798
  if(typeof pReferenceTime=='string'){tmpReferenceTime=this.timeStamps.hasOwnProperty(tmpReference)?this.timeStamps[tmpReference]:false;}else if(typeof pReferenceTime=='number'){tmpReferenceTime=pReferenceTime;}else{tmpReferenceTime=+new Date();}if(this.timeStamps.hasOwnProperty(tmpTimeStampHash)&&tmpReferenceTime){this.timeStamps[tmpTimeStampHash]=tmpReferenceTime;return this.timeStamps[tmpTimeStampHash];}else{return-1;}}removeTimeStamp(pTimeStampHash){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';if(this.timeStamps.hasOwnProperty(tmpTimeStampHash)){delete this.timeStamps[tmpTimeStampHash];return true;}else{return false;}}getTimeStampDelta(pTimeStampHash,pReferenceTime){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';let tmpReferenceTime=false;// This function allows the user to pass in either a reference time in ms, or, a hash of a timestamp.
3525
- if(typeof pReferenceTime=='string'){tmpReferenceTime=this.timeStamps.hasOwnProperty(tmpReference)?this.timeStamps[tmpReference]:false;}else if(typeof pReferenceTime=='number'){tmpReferenceTime=pReferenceTime;}else{tmpReferenceTime=+new Date();}if(this.timeStamps.hasOwnProperty(tmpTimeStampHash)&&tmpReferenceTime){return tmpReferenceTime-this.timeStamps[tmpTimeStampHash];}else{return-1;}}getDurationBetweenTimestamps(pTimeStampHashStart,pTimeStampHashEnd){let tmpTimeStampHashStart=typeof pTimeStampHashStart=='string'?pTimeStampHashStart:'Default';let tmpTimeStampHashEnd=typeof pTimeStampHashEnd=='string'?pTimeStampHashEnd:'Default';if(this.timeStamps.hasOwnProperty(tmpTimeStampHashStart)&&this.timeStamps.hasOwnProperty(tmpTimeStampHashEnd)){return this.timeStamps[tmpTimeStampHashEnd]-this.timeStamps[tmpTimeStampHashStart];}else{return-1;}}getTimeStampDeltaMessage(pTimeStampHash,pMessage,pReferenceTime){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';let tmpMessage=typeof pMessage!=='undefined'?pMessage:"Elapsed for ".concat(tmpTimeStampHash,": ");let tmpOperationTime=this.getTimeStampDelta(tmpTimeStampHash,pReferenceTime);return"".concat(tmpMessage," ").concat(this.formatTimeDuration(tmpOperationTime));}logTimeStampDelta(pTimeStampHash,pMessage,pReferenceTime){this.fable.log.info(this.getTimeStampDeltaMessage(pTimeStampHash,pMessage,pReferenceTime));}}module.exports=FableServiceProgressTime;},{"fable-serviceproviderbase":51}],143:[function(require,module,exports){class ProgressTracker{constructor(pProgressTrackerSet,pProgressTrackerHash){this.progressTrackerSet=pProgressTrackerSet;this.progressTrackerHash=pProgressTrackerHash;this.data=this.progressTrackerSet.getProgressTrackerData(this.progressTrackerHash);}updateProgressTracker(pProgressAmount){return this.progressTrackerSet.updateProgressTracker(this.progressTrackerHash,pProgressAmount);}incrementProgressTracker(pProgressIncrementAmount){return this.progressTrackerSet.incrementProgressTracker(this.progressTrackerHash,pProgressIncrementAmount);}setProgressTrackerTotalOperations(pTotalOperationCount){return this.progressTrackerSet.setProgressTrackerTotalOperations(this.progressTrackerHash,pTotalOperationCount);}getProgressTrackerStatusString(){return this.progressTrackerSet.getProgressTrackerStatusString(this.progressTrackerHash);}}module.exports=ProgressTracker;},{}],144:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');const libProgressTrackerClass=require('./Fable-Service-ProgressTracker/ProgressTracker.js');class FableServiceProgressTrackerSet extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ProgressTrackerSet';this.progressTrackers={};// Create an internal PorgressTime service to track timestamps
3799
+ if(typeof pReferenceTime=='string'){tmpReferenceTime=this.timeStamps.hasOwnProperty(tmpReference)?this.timeStamps[tmpReference]:false;}else if(typeof pReferenceTime=='number'){tmpReferenceTime=pReferenceTime;}else{tmpReferenceTime=+new Date();}if(this.timeStamps.hasOwnProperty(tmpTimeStampHash)&&tmpReferenceTime){return tmpReferenceTime-this.timeStamps[tmpTimeStampHash];}else{return-1;}}getDurationBetweenTimestamps(pTimeStampHashStart,pTimeStampHashEnd){let tmpTimeStampHashStart=typeof pTimeStampHashStart=='string'?pTimeStampHashStart:'Default';let tmpTimeStampHashEnd=typeof pTimeStampHashEnd=='string'?pTimeStampHashEnd:'Default';if(this.timeStamps.hasOwnProperty(tmpTimeStampHashStart)&&this.timeStamps.hasOwnProperty(tmpTimeStampHashEnd)){return this.timeStamps[tmpTimeStampHashEnd]-this.timeStamps[tmpTimeStampHashStart];}else{return-1;}}getTimeStampDeltaMessage(pTimeStampHash,pMessage,pReferenceTime){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';let tmpMessage=typeof pMessage!=='undefined'?pMessage:"Elapsed for ".concat(tmpTimeStampHash,": ");let tmpOperationTime=this.getTimeStampDelta(tmpTimeStampHash,pReferenceTime);return"".concat(tmpMessage," ").concat(this.formatTimeDuration(tmpOperationTime));}logTimeStampDelta(pTimeStampHash,pMessage,pReferenceTime){this.fable.log.info(this.getTimeStampDeltaMessage(pTimeStampHash,pMessage,pReferenceTime));}}module.exports=FableServiceProgressTime;},{"fable-serviceproviderbase":51}],151:[function(require,module,exports){class ProgressTracker{constructor(pProgressTrackerSet,pProgressTrackerHash){this.progressTrackerSet=pProgressTrackerSet;this.progressTrackerHash=pProgressTrackerHash;this.data=this.progressTrackerSet.getProgressTrackerData(this.progressTrackerHash);}updateProgressTracker(pProgressAmount){return this.progressTrackerSet.updateProgressTracker(this.progressTrackerHash,pProgressAmount);}incrementProgressTracker(pProgressIncrementAmount){return this.progressTrackerSet.incrementProgressTracker(this.progressTrackerHash,pProgressIncrementAmount);}setProgressTrackerTotalOperations(pTotalOperationCount){return this.progressTrackerSet.setProgressTrackerTotalOperations(this.progressTrackerHash,pTotalOperationCount);}getProgressTrackerStatusString(){return this.progressTrackerSet.getProgressTrackerStatusString(this.progressTrackerHash);}}module.exports=ProgressTracker;},{}],152:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');const libProgressTrackerClass=require('./Fable-Service-ProgressTracker/ProgressTracker.js');class FableServiceProgressTrackerSet extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ProgressTrackerSet';this.progressTrackers={};// Create an internal PorgressTime service to track timestamps
3526
3800
  this.progressTimes=this.fable.instantiateServiceProviderWithoutRegistration('ProgressTime');// This timestamp is used and updated by *all* progress trackers.
3527
3801
  this.progressTimes.createTimeStamp('CurrentTime');}getProgressTracker(pProgressTrackerHash){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';if(!this.progressTrackers.hasOwnProperty(tmpProgressTrackerHash)){this.fable.log.warn("ProgressTracker ".concat(tmpProgressTrackerHash," does not exist! Creating a new tracker..."));this.createProgressTracker(tmpProgressTrackerHash,100);}return new libProgressTrackerClass(this,pProgressTrackerHash);}getProgressTrackerData(pProgressTrackerHash){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';if(!this.progressTrackers.hasOwnProperty(tmpProgressTrackerHash)){this.fable.log.warn("ProgressTracker ".concat(tmpProgressTrackerHash," does not exist! Creating a new tracker..."));this.createProgressTracker(tmpProgressTrackerHash,100);}return this.progressTrackers[tmpProgressTrackerHash];}createProgressTracker(pProgressTrackerHash,pTotalOperations){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';let tmpTotalOperations=typeof pTotalOperations=='number'?pTotalOperations:100;let tmpProgressTracker={Hash:tmpProgressTrackerHash,StartTimeHash:"".concat(tmpProgressTrackerHash,"-Start"),StartTimeStamp:-1,CurrentTimeStamp:-1,EndTimeHash:"".concat(tmpProgressTrackerHash,"-End"),EndTimeStamp:-1,PercentComplete:-1,// If this is set to true, PercentComplete will be calculated as CurrentCount / TotalCount even if it goes over 100%
3528
3802
  AllowTruePercentComplete:false,ElapsedTime:-1,AverageOperationTime:-1,EstimatedCompletionTime:-1,TotalCount:tmpTotalOperations,CurrentCount:-1};if(this.progressTrackers.hasOwnProperty(tmpProgressTrackerHash)){this.fable.log.warn("ProgressTracker ".concat(tmpProgressTrackerHash," already exists! Overwriting with a new tracker..."));this.progressTimes.removeTimeStamp(tmpProgressTracker.StartTimeHash);this.progressTimes.removeTimeStamp(tmpProgressTracker.EndTimeHash);}this.progressTrackers[tmpProgressTrackerHash]=tmpProgressTracker;return tmpProgressTracker;}setProgressTrackerTotalOperations(pProgressTrackerHash,pTotalOperations){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';let tmpTotalOperations=typeof pTotalOperations=='number'?pTotalOperations:100;if(!this.progressTrackers.hasOwnProperty(tmpProgressTrackerHash)){this.fable.log.warn("Attempted to set the total operations of ProgressTracker ".concat(tmpProgressTrackerHash," but it does not exist! Creating a new tracker..."));this.createProgressTracker(tmpProgressTrackerHash,tmpTotalOperations);}this.progressTrackers[tmpProgressTrackerHash].TotalCount=tmpTotalOperations;return this.progressTrackers[tmpProgressTrackerHash];}startProgressTracker(pProgressTrackerHash){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';// This is the only method to lazily create ProgressTrackers now
@@ -3545,7 +3819,7 @@ this.solveProgressTrackerStatus(tmpProgressTrackerHash);if(!this.progressTracker
3545
3819
  if(tmpProgressTracker.StartTimeStamp<1){return"ProgressTracker ".concat(tmpProgressTracker.Hash," has not been started yet.");}// 2. Started, but no operations completed
3546
3820
  if(tmpProgressTracker.CurrentCount<1&&tmpProgressTracker.EndTimeStamp<1){return"ProgressTracker ".concat(tmpProgressTracker.Hash," has no completed operations. ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.ElapsedTime)," have elapsed since it was started.");}// 3. Started, some operations completed
3547
3821
  else if(tmpProgressTracker.EndTimeStamp<1){return"ProgressTracker ".concat(tmpProgressTracker.Hash," is ").concat(tmpProgressTracker.PercentComplete.toFixed(3),"% completed - ").concat(tmpProgressTracker.CurrentCount," / ").concat(tmpProgressTracker.TotalCount," operations over ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.ElapsedTime)," (median ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.AverageOperationTime)," per). Estimated completion: ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.EstimatedCompletionTime));}// 4. Done
3548
- else{return"ProgressTracker ".concat(tmpProgressTracker.Hash," is done. ").concat(tmpProgressTracker.CurrentCount," / ").concat(tmpProgressTracker.TotalCount," operations were completed in ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.ElapsedTime)," (median ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.AverageOperationTime)," per).");}}}logProgressTrackerStatus(pProgressTrackerHash){this.fable.log.info(this.getProgressTrackerStatusString(pProgressTrackerHash));}}module.exports=FableServiceProgressTrackerSet;},{"./Fable-Service-ProgressTracker/ProgressTracker.js":143,"fable-serviceproviderbase":51}],145:[function(require,module,exports){(function(Buffer){(function(){const libFableServiceBase=require('fable-serviceproviderbase');const libSimpleGet=require('simple-get');const libCookie=require('cookie');class FableServiceRestClient extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.TraceLog=false;if(this.options.TraceLog||this.fable.TraceLog){this.TraceLog=true;}this.dataFormat=this.fable.services.DataFormat;this.serviceType='RestClient';this.cookie=false;// This is a function that can be overridden, to allow the management
3822
+ else{return"ProgressTracker ".concat(tmpProgressTracker.Hash," is done. ").concat(tmpProgressTracker.CurrentCount," / ").concat(tmpProgressTracker.TotalCount," operations were completed in ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.ElapsedTime)," (median ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.AverageOperationTime)," per).");}}}logProgressTrackerStatus(pProgressTrackerHash){this.fable.log.info(this.getProgressTrackerStatusString(pProgressTrackerHash));}}module.exports=FableServiceProgressTrackerSet;},{"./Fable-Service-ProgressTracker/ProgressTracker.js":151,"fable-serviceproviderbase":51}],153:[function(require,module,exports){(function(Buffer){(function(){const libFableServiceBase=require('fable-serviceproviderbase');const libSimpleGet=require('simple-get');const libCookie=require('cookie');class FableServiceRestClient extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.TraceLog=false;if(this.options.TraceLog||this.fable.TraceLog){this.TraceLog=true;}this.dataFormat=this.fable.services.DataFormat;this.serviceType='RestClient';this.cookie=false;// This is a function that can be overridden, to allow the management
3549
3823
  // of the request options before they are passed to the request library.
3550
3824
  this.prepareRequestOptions=pOptions=>{return pOptions;};}get simpleGet(){return libSimpleGet;}prepareCookies(pRequestOptions){if(this.cookie){let tmpCookieObject=this.cookie;if(!pRequestOptions.hasOwnProperty('headers')){pRequestOptions.headers={};}let tmpCookieKeys=Object.keys(tmpCookieObject);if(tmpCookieKeys.length>0){// Only grab the first for now.
3551
3825
  pRequestOptions.headers.cookie=libCookie.serialize(tmpCookieKeys[0],tmpCookieObject[tmpCookieKeys[0]]);}}return pRequestOptions;}preRequest(pOptions){// Validate the options object
@@ -3558,7 +3832,7 @@ if(!tmpDataBuffer){tmpDataBuffer=Buffer.from(pChunk);}else{tmpDataBuffer=Buffer.
3558
3832
  {
3559
3833
  tmpOptions.headers['Content-Type'] = 'application/json';
3560
3834
  }
3561
- */tmpOptions.RequestStartTime=this.fable.log.getTimeStamp();if(this.TraceLog){this.fable.log.debug("Beginning ".concat(tmpOptions.method," JSON request to ").concat(tmpOptions.url," at ").concat(tmpOptions.RequestStartTime));}return libSimpleGet(tmpOptions,(pError,pResponse)=>{if(pError){return fCallback(pError,pResponse);}if(this.TraceLog){let tmpConnectTime=this.fable.log.getTimeStamp();this.fable.log.debug("--> JSON ".concat(tmpOptions.method," connected in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpConnectTime),"ms code ").concat(pResponse.statusCode));}let tmpJSONData='';pResponse.on('data',pChunk=>{if(this.TraceLog){let tmpChunkTime=this.fable.log.getTimeStamp();this.fable.log.debug("--> JSON ".concat(tmpOptions.method," data chunk size ").concat(pChunk.length,"b received in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpChunkTime),"ms"));}tmpJSONData+=pChunk;});pResponse.on('end',()=>{if(this.TraceLog){let tmpCompletionTime=this.fable.log.getTimeStamp();this.fable.log.debug("==> JSON ".concat(tmpOptions.method," completed - received in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpCompletionTime),"ms"));}return fCallback(pError,pResponse,JSON.parse(tmpJSONData));});});}getJSON(pOptionsOrURL,fCallback){let tmpRequestOptions=typeof pOptionsOrURL=='object'?pOptionsOrURL:{};if(typeof pOptionsOrURL=='string'){tmpRequestOptions.url=pOptionsOrURL;}tmpRequestOptions.method='GET';return this.executeJSONRequest(tmpRequestOptions,fCallback);}putJSON(pOptions,fCallback){if(typeof pOptions.body!='object'){return fCallback(new Error("PUT JSON Error Invalid options object"));}pOptions.method='PUT';return this.executeJSONRequest(pOptions,fCallback);}postJSON(pOptions,fCallback){if(typeof pOptions.body!='object'){return fCallback(new Error("POST JSON Error Invalid options object"));}pOptions.method='POST';return this.executeJSONRequest(pOptions,fCallback);}patchJSON(pOptions,fCallback){if(typeof pOptions.body!='object'){return fCallback(new Error("PATCH JSON Error Invalid options object"));}pOptions.method='PATCH';return this.executeJSONRequest(pOptions,fCallback);}headJSON(pOptions,fCallback){if(typeof pOptions.body!='object'){return fCallback(new Error("HEAD JSON Error Invalid options object"));}pOptions.method='HEAD';return this.executeJSONRequest(pOptions,fCallback);}delJSON(pOptions,fCallback){pOptions.method='DELETE';return this.executeJSONRequest(pOptions,fCallback);}getRawText(pOptionsOrURL,fCallback){let tmpRequestOptions=typeof pOptionsOrURL=='object'?pOptionsOrURL:{};if(typeof pOptionsOrURL=='string'){tmpRequestOptions.url=pOptionsOrURL;}tmpRequestOptions.method='GET';return this.executeChunkedRequest(tmpRequestOptions,fCallback);}}module.exports=FableServiceRestClient;}).call(this);}).call(this,require("buffer").Buffer);},{"buffer":20,"cookie":27,"fable-serviceproviderbase":51,"simple-get":101}],146:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');class FableServiceTemplate extends libFableServiceBase{// Underscore and lodash have a behavior, _.template, which compiles a
3835
+ */tmpOptions.RequestStartTime=this.fable.log.getTimeStamp();if(this.TraceLog){this.fable.log.debug("Beginning ".concat(tmpOptions.method," JSON request to ").concat(tmpOptions.url," at ").concat(tmpOptions.RequestStartTime));}return libSimpleGet(tmpOptions,(pError,pResponse)=>{if(pError){return fCallback(pError,pResponse);}if(this.TraceLog){let tmpConnectTime=this.fable.log.getTimeStamp();this.fable.log.debug("--> JSON ".concat(tmpOptions.method," connected in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpConnectTime),"ms code ").concat(pResponse.statusCode));}let tmpJSONData='';pResponse.on('data',pChunk=>{if(this.TraceLog){let tmpChunkTime=this.fable.log.getTimeStamp();this.fable.log.debug("--> JSON ".concat(tmpOptions.method," data chunk size ").concat(pChunk.length,"b received in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpChunkTime),"ms"));}tmpJSONData+=pChunk;});pResponse.on('end',()=>{if(this.TraceLog){let tmpCompletionTime=this.fable.log.getTimeStamp();this.fable.log.debug("==> JSON ".concat(tmpOptions.method," completed - received in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpCompletionTime),"ms"));}return fCallback(pError,pResponse,JSON.parse(tmpJSONData));});});}getJSON(pOptionsOrURL,fCallback){let tmpRequestOptions=typeof pOptionsOrURL=='object'?pOptionsOrURL:{};if(typeof pOptionsOrURL=='string'){tmpRequestOptions.url=pOptionsOrURL;}tmpRequestOptions.method='GET';return this.executeJSONRequest(tmpRequestOptions,fCallback);}putJSON(pOptions,fCallback){if(typeof pOptions.body!='object'){return fCallback(new Error("PUT JSON Error Invalid options object"));}pOptions.method='PUT';return this.executeJSONRequest(pOptions,fCallback);}postJSON(pOptions,fCallback){if(typeof pOptions.body!='object'){return fCallback(new Error("POST JSON Error Invalid options object"));}pOptions.method='POST';return this.executeJSONRequest(pOptions,fCallback);}patchJSON(pOptions,fCallback){if(typeof pOptions.body!='object'){return fCallback(new Error("PATCH JSON Error Invalid options object"));}pOptions.method='PATCH';return this.executeJSONRequest(pOptions,fCallback);}headJSON(pOptions,fCallback){if(typeof pOptions.body!='object'){return fCallback(new Error("HEAD JSON Error Invalid options object"));}pOptions.method='HEAD';return this.executeJSONRequest(pOptions,fCallback);}delJSON(pOptions,fCallback){pOptions.method='DELETE';return this.executeJSONRequest(pOptions,fCallback);}getRawText(pOptionsOrURL,fCallback){let tmpRequestOptions=typeof pOptionsOrURL=='object'?pOptionsOrURL:{};if(typeof pOptionsOrURL=='string'){tmpRequestOptions.url=pOptionsOrURL;}tmpRequestOptions.method='GET';return this.executeChunkedRequest(tmpRequestOptions,fCallback);}}module.exports=FableServiceRestClient;}).call(this);}).call(this,require("buffer").Buffer);},{"buffer":20,"cookie":27,"fable-serviceproviderbase":51,"simple-get":101}],154:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');class FableServiceTemplate extends libFableServiceBase{// Underscore and lodash have a behavior, _.template, which compiles a
3562
3836
  // string-based template with code snippets into simple executable pieces,
3563
3837
  // with the added twist of returning a precompiled function ready to go.
3564
3838
  //
@@ -3574,11 +3848,11 @@ GuaranteedNonMatch:/.^/};// This is a helper for the escaper and unescaper funct
3574
3848
  // Right now we are going to keep what underscore is doing, but, not forever.
3575
3849
  this.templateEscapes={'\\':'\\',"'":"'",'r':'\r','\r':'r','n':'\n','\n':'n','t':'\t','\t':'t','u2028':'\u2028','\u2028':'u2028','u2029':'\u2029','\u2029':'u2029'};// This is defined as such to underscore that it is a dynamic programming
3576
3850
  // function on this class.
3577
- this.renderFunction=false;this.templateString=false;}renderTemplate(pData){return this.renderFunction(pData);}templateFunction(pData){let fRenderTemplateBound=this.renderTemplate.bind(this);return fRenderTemplateBound;}buildTemplateFunction(pTemplateText,pData){// For now this is being kept in a weird form ... this is to mimic the old
3851
+ this.renderFunction=false;this.templateString=false;}renderTemplate(pData){return this.renderFunction(pData);}templateFunction(){let fRenderTemplateBound=this.renderTemplate.bind(this);return fRenderTemplateBound;}buildTemplateFunction(pTemplateText,pData){// For now this is being kept in a weird form ... this is to mimic the old
3578
3852
  // underscore code until this is rewritten using precedent.
3579
3853
  this.TemplateSource="__p+='"+pTemplateText.replace(this.Matchers.Escaper,pMatch=>{return"\\".concat(this.templateEscapes[pMatch]);}).replace(this.Matchers.Interpolate||this.Matchers.GuaranteedNonMatch,(pMatch,pCode)=>{return"'+\n(".concat(decodeURIComponent(pCode),")+\n'");}).replace(this.Matchers.Evaluate||this.Matchers.GuaranteedNonMatch,(pMatch,pCode)=>{return"';\n".concat(decodeURIComponent(pCode),"\n;__p+='");})+"';\n";this.TemplateSource="with(pTemplateDataObject||{}){\n".concat(this.TemplateSource,"}\n");this.TemplateSource="var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n".concat(this.TemplateSource,"return __p;\n");this.renderFunction=new Function('pTemplateDataObject',this.TemplateSource);if(typeof pData!='undefined'){return this.renderFunction(pData);}// Provide the compiled function source as a convenience for build time
3580
3854
  // precompilation.
3581
- this.TemplateSourceCompiled='function(obj){\n'+this.TemplateSource+'}';return this.templateFunction();}}module.exports=FableServiceTemplate;},{"fable-serviceproviderbase":51}],147:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');// TODO: These are still pretty big -- consider the smaller polyfills
3855
+ this.TemplateSourceCompiled='function(obj){\n'+this.TemplateSource+'}';return this.templateFunction();}}module.exports=FableServiceTemplate;},{"fable-serviceproviderbase":51}],155:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');// TODO: These are still pretty big -- consider the smaller polyfills
3582
3856
  const libAsyncWaterfall=require('async.waterfall');const libAsyncEachLimit=require('async.eachlimit');const libBigNumber=require('big.js');class FableServiceUtility extends libFableServiceBase{// Underscore and lodash have a behavior, _.template, which compiles a
3583
3857
  // string-based template with code snippets into simple executable pieces,
3584
3858
  // with the added twist of returning a precompiled function ready to go.