/*: * @plugindesc (v0.4.0) Makes building and using plugins easier. Comes with a dependency manager. * * Released under MIT license, https://github.com/Sivli-Embir/rpg_maker_plugins/blob/master/LICENSE * * @author Sivli Embir & Noxx Embir * * * @help * ============================================================================ * Documentation * ============================================================================ * * For RPG Maker MV 1.5+ * * If you are reading this then you are probobly using another one of my * plugins. Be aware that this plugin is safe to use (as far as I know) * but I am still doing a lot of work on it. Until I feel its done it will not * be fully documented and its version will say v0.x. * * The point of this plugin is to make creating plugins easier and reduce * avoidable bugs. Among other things it has a dependency manager, which means * if you define your plugins with this tool they will always load in the * order you want regardless of the order in the offical Plugin Manager. * * ============================================================================ * API Usage * ============================================================================ * * For details on how to use the API please read the comments in the code * for now. * * SIV_SCOPE.definePlugin (object): use dependency manager. * * SIV_SCOPE.getNotetags(object): check if game object has matching notetags * * SIV_SCOPE.registerPluginCommand (name, function): will run the funciton on * plugin command call. * * ============================================================================ * Notetag format * ============================================================================ * results in: * {name: "ExampleTag", args: []} * * results in: * { * name: "ExampleTag", * args: ['some', 'arguments'] * } * * * child 1 * child 2 * results in: * { * name: "ExampleTag", * args: ['some', 'arguments'], * children: ['child 1', 'child 2'] * } * * Be aware that the following is also valid but not encouraged: * * really not a good format. * As it is harder to read where ExampleTag ended. * /> * * ===ON EVENTS=== * SIV_SCOPE.onInit (function): DB, Plutins, and note tags are laoded. * SIV_SCOPE.onFrame (function): best to not use this... (if you must use scene * update instead) * SIV_SCOPE.onSceneEvent: (sceneObj, eventName, function): * sceneObj: (Scene_[name] The scene game object) example: Scene_Map * eventName: 'create', 'start', 'update', 'terminate', * (also for map: 'addObjects') * * ============================================================================ * Change Log * ============================================================================ * * Version 0.0.0: * - Pending v1 */ /** * Developed By Team: * ██████╗ ██████╗ ███████╗███████╗ ██████╗ ██████╗ █████╗ ██████╗ ██████╗ ███╗ ██╗ * ██╔══██╗██╔═══██╗██╔════╝██╔════╝ ██╔══██╗██╔══██╗██╔══██╗██╔════╝ ██╔═══██╗████╗ ██║ * ██████╔╝██║ ██║███████╗█████╗ ██║ ██║██████╔╝███████║██║ ███╗██║ ██║██╔██╗ ██║ * ██╔══██╗██║ ██║╚════██║██╔══╝ ██║ ██║██╔══██╗██╔══██║██║ ██║██║ ██║██║╚██╗██║ * ██║ ██║╚██████╔╝███████║███████╗ ██████╔╝██║ ██║██║ ██║╚██████╔╝╚██████╔╝██║ ╚████║ * ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝ */ ///////////////////////////////////////////////////////////////////////////////// // Some good house keeping given we don't have nice js2016+ import scoping. // // I use SIV_SCOPE to keep from bleeding into something else and hopefully not // // conflicting with other plugins. // ///////////////////////////////////////////////////////////////////////////////// var SIV_SCOPE = { _wrapper: {//global holder for PRG Maker wraps. custom: {} //plugin defined wrappers }, _plugins: {}, //all the plugins that are registered. _data: { //where I will store all SIV_SCOPE global variables. databaseHasLoaded: false, //a way to prevent queues from firing before init. notetagDictionary: { //A list of ALL the notetags in the game maps: {}, //maps require special treatment. mapEvents: {} //map events require special treatment. } }, _pluginCommands: {}, //This is where I store plugin functions. _onQueue: { //all the on[state] queue functions. onInit: [], onFrame: [], variableChange: {}, }, _extractSaveContents: [], _makeSaveContents: [], parameters: PluginManager.parameters('Siv_Plugin_Sanity') }; /////////////////////////////////////////////////////////////////////////////////// // PUBLIC API. This is for use by anyone using the plugin. Everything after this // // is not meant to be used outside of the plugin, so hack at your own risk :) // /////////////////////////////////////////////////////////////////////////////////// /** * If you use this to define your plugin Siv_Plugin_Sanity will make sure it loads and * runs at the right time. That is after the database exists and after any required * plugins. It will also load beore the onInit function, when you should do global config work. * @param {Object} definition must contain a name {string} and a plugin {function}. * It may include a require {Array} with a list of plugin names {String}. * @return {Null} */ SIV_SCOPE.definePlugin = function(definition) { if (typeof definition.name !== 'string') { console.log('Siv_Plugin_Sanity - A plugin without a name was found, skipping!'); return; } if (typeof definition.plugin !== 'function') { console.log('Siv_Plugin_Sanity - plugin: ' + definition.name + ' did not define a plugin function and does nothing!'); return; } if (definition.requires && (typeof definition.requires !== 'object' || !definition.requires.hasOwnProperty('length'))) { console.log('Siv_Plugin_Sanity - plugin: ' + definition.name + ' has invalid requirements, skipping'); return; } SIV_SCOPE._plugins[definition.name] = definition; try { SIV_SCOPE._dependencyGraph.addNode(definition.name) if (definition.requires) { for (var i = 0; i < definition.requires.length; i++) { SIV_SCOPE._dependencyGraph.addDependency(definition.name, definition.requires[i]); } } } catch (e) { if (Utils.isNwjs()) { var _debugWindow = require('nw.gui').Window.get().showDevTools(); _debugWindow.focus(); } throw e; } } /** * Will run once when: the database is loaded, the core engine variables are made, * and after all the plugins are run. WARNING! This is not onStart/onNewGame/onLoad * @param {Function} func A standard function that should contain any code that * needs to be run at startup. * @return {Null} */ SIV_SCOPE.onInit = function(func) { SIV_SCOPE._onQueue.onInit.push(func) } /** * This will run approximately 60 times a second. Unless you have a very specific * need you likely don't want to use this. This is a great way to introduce lag! * @param {Function} func A standard function that should contain any code that * needs to be run once a frame. * @return {Null} */ SIV_SCOPE.onFrame = function(func) { SIV_SCOPE._onQueue.onFrame.push(func) } SIV_SCOPE.onVariableChange = function(index, func) { if (!SIV_SCOPE._onQueue.variableChange[index]) SIV_SCOPE._onQueue.variableChange[index] = [] SIV_SCOPE._onQueue.variableChange[index].push(func) } SIV_SCOPE.onSceneEvent = function(scene, event, func) { SIV_SCOPE.onEvent(scene.name, event, func) event = event.toLowerCase(); } /** * Find out if a given game object has a notetag. This takes a query and returns * an array of all matchs. * * The query shoud have: * the (type) of object you have - currently: "actors", "armors", 'classes', * 'commonEvents', 'enemies', 'skills', 'states', 'weapons' * the (id) of the object, the index or number in the database * the (match) string. This can ether be an exact string match or regex query. * * @param {Object} obj must contain a type {String} and an id {Number} and * a name {String}. mapEvents also requires a mapId {Number} * @return {Array} This array as objects: * name {String} the name of the notetag * args {Array} all the notetag top level arguments * children {Array} this is ether undefined or an array of child data. */ SIV_SCOPE.getNotetags = function(obj) { var notes; if (obj.type === 'mapEvents') { if (!obj.mapId) { console.log('mapEvents must have mapId.'); return [] } notes = (((SIV_SCOPE._data.notetagDictionary[obj.type] || {})[obj.mapId] || {})[obj.id] || {}).notes } else { notes = ((SIV_SCOPE._data.notetagDictionary[obj.type] || {})[obj.id] || {}).notes } if (!notes || !notes.length) return []; if (!obj.name) return notes; return notes.filter(function(note) { return note.tag == obj.name; }) } /** * This lets you run plugin commands in a very fast and efficent way. * * Warning: Last write wins case, the last plugin to use the same command name * will be the only one to use the command. Breaking change from core! * * a: consider building in a namespace backend option, or front end even... * but how??? The user will only say the original name, how do we get intent? * Can we run all matchs? Should we? imo no but... * * @param {String} command A globally unique name for your command * @param {Function} func A standard function that will preform whatever * you want your plugin command to do. * @return {Null} */ SIV_SCOPE.registerPluginCommand = function(command, func) { if (command && func) SIV_SCOPE._pluginCommands[command] = func; } SIV_SCOPE.fireCustomEvent = function() { var args = []; Array.prototype.push.apply( args, arguments ); if (!args[0]) { console.log("fireCustomEvent: Missing name"); return; } if (!args[1]) { console.log("fireCustomEvent: Missing method"); return; } var name = args.shift(); var method = args.shift(); SIV_SCOPE._runOnScene.call(this, args, name, method) } SIV_SCOPE.onEvent = function(name, method, func) { name = name.toLowerCase(); method = method.toLowerCase(); if (!SIV_SCOPE._onQueue[name]) SIV_SCOPE._onQueue[name] = {} if (!SIV_SCOPE._onQueue[name][method]) SIV_SCOPE._onQueue[name][method] = [] SIV_SCOPE._onQueue[name][method].push(func); } ///////////// // API END // ///////////// /** * Builds the notetags, calls the plugin graph, build the plugins, eventuall calls onInit */ SIV_SCOPE._wrapper.data_manager_isDatabaseLoaded = DataManager.isDatabaseLoaded; DataManager.isDatabaseLoaded = function() { if (!SIV_SCOPE._wrapper.data_manager_isDatabaseLoaded.apply(this, arguments)) return false; if (SIV_SCOPE._data.databaseHasLoaded) return true; SIV_SCOPE._buildNotetagDictionary('actors', $dataActors) SIV_SCOPE._buildNotetagDictionary('armors', $dataArmors) SIV_SCOPE._buildNotetagDictionary('classes', $dataClasses) SIV_SCOPE._buildNotetagDictionary('commonEvents', $dataCommonEvents) SIV_SCOPE._buildNotetagDictionary('enemies', $dataEnemies) SIV_SCOPE._buildNotetagDictionary('skills', $dataSkills) SIV_SCOPE._buildNotetagDictionary('states', $dataStates) SIV_SCOPE._buildNotetagDictionary('weapons', $dataWeapons) var pluginList = SIV_SCOPE._dependencyGraph.overallOrder(); for (var i = 0; i < pluginList.length; i++) { SIV_SCOPE._plugins[pluginList[i]].plugin.call(window) } SIV_SCOPE._databaseHasLoaded() return true; }; /** * part of isDatabaseLoaded */ SIV_SCOPE._buildNotetagDictionary = function(type, data) { SIV_SCOPE._data.notetagDictionary[type] = {} if (type == 'commonEvents') { for (var i = 1; i < data.length; i++) { var notes = SIV_SCOPE._parseEventPageNotes(data[i], []); SIV_SCOPE._data.notetagDictionary[type][i] = {notes: notes} } } else { for (var i = 1; i < data.length; i++) { SIV_SCOPE._data.notetagDictionary[type][i] = { notes: SIV_SCOPE._parseNoteTag(data[i].note) } } } } SIV_SCOPE._parseEventPageNotes = function(page, notes) { for (var i = 0; i < page.list.length; i++) { if (page.list[i].code == 108 || page.list[i].code == 408) { for (var ii = 0; ii < page.list[i].parameters.length; ii++) { notes = notes.concat(SIV_SCOPE._parseNoteTag(page.list[i].parameters[ii])) } } } return notes; } SIV_SCOPE._parseNoteTag = function(notes) { var match, results = [], headerEndStrip = 2; if (notes && notes.length) match = notes.match(/<(?:(?!\/>).|\n)+\/>/g) if (!match || !match.length) return results; for (var i = 0; i < match.length; i++) { var note = {} , children = match[i].split('\n') //break by line, tags without children will return 1 , header = children.shift(); //this is the acutal tag if (children.length > 0) { headerEndStrip = 1 children.pop() //throw out the last line as its only the close tag note.children = children } //remove `< & >` and break up the tag and arguments header = header.trim().substring(1, header.length-headerEndStrip).split(' ').filter(function(s) { return s.length }) note.tag = header.shift() note.args = header results.push(note) } return results; } /** * part of isDatabaseLoaded */ SIV_SCOPE._databaseHasLoaded = function() { SIV_SCOPE._data.databaseHasLoaded = true; if (SIV_SCOPE._onQueue.onInit.length) { for (var i = 0; i < SIV_SCOPE._onQueue.onInit.length; i++) { SIV_SCOPE._onQueue.onInit[i].apply(this, arguments) } } } /** * mostly safe mutator, this will not give plugins game core save data. It's * still risky as they can put too much into it. Use with discretion please! */ SIV_SCOPE._wrapper.data_manager_make_save_contents = DataManager.makeSaveContents; DataManager.makeSaveContents = function() { var contents = SIV_SCOPE._wrapper.data_manager_make_save_contents.apply(this, arguments) if (!contents['SIV_SAVE_DATA']) contents['SIV_SAVE_DATA'] = {} for (var i = 0; i < SIV_SCOPE._makeSaveContents.length; i++) { SIV_SCOPE._makeSaveContents[i].call(this, contents['SIV_SAVE_DATA']) } return contents; } /** * Much safer the makeSaveContents, this just loads in the SIV_SAVE_DATA scope */ SIV_SCOPE._wrapper.data_manager_extract_save_contents = DataManager.extractSaveContents; DataManager.extractSaveContents = function() { SIV_SCOPE._wrapper.data_manager_extract_save_contents.apply(this, arguments) for (var i = 0; i < SIV_SCOPE._extractSaveContents.length; i++) { SIV_SCOPE._extractSaveContents[i].call(this, arguments[0]['SIV_SAVE_DATA']) } } /** * the On Scene Event runners */ SIV_SCOPE._wrapper.scene_base_create = Scene_Base.prototype.create; Scene_Base.prototype.create = function() { SIV_SCOPE._wrapper.scene_base_create.apply(this, arguments) if (this.constructor.name === Scene_Map.name) { //This is a horrable lie! (use pre player transfer) SIV_SCOPE._data.currentMapInstance = this; return; } else SIV_SCOPE._runOnScene.call(this, arguments, this.constructor.name, 'create') } SIV_SCOPE._wrapper.scene_base_start = Scene_Base.prototype.start; Scene_Base.prototype.start = function() { SIV_SCOPE._wrapper.scene_base_start.apply(this, arguments) if (this.constructor.name === Scene_Map.name) SIV_SCOPE._runOnMap.call(this, 'start') else SIV_SCOPE._runOnScene.call(this, arguments, this.constructor.name, 'start') } SIV_SCOPE._wrapper.scene_base_update = Scene_Base.prototype.update; Scene_Base.prototype.update = function() { SIV_SCOPE._wrapper.scene_base_update.apply(this, arguments) if (this.constructor.name === Scene_Map.name) SIV_SCOPE._runOnMap.call(this, 'update') else SIV_SCOPE._runOnScene.call(this, arguments, this.constructor.name, 'update') } SIV_SCOPE._wrapper.scene_base_terminate = Scene_Base.prototype.terminate; Scene_Base.prototype.terminate = function() { if (this.constructor.name === Scene_Map.name) SIV_SCOPE._runOnMap.call(this, 'terminate') else SIV_SCOPE._runOnScene.call(this, arguments, this.constructor.name, 'terminate') SIV_SCOPE._wrapper.scene_base_terminate.apply(this, arguments) } //fake out on map create queue to make sure the map data is actually loaded SIV_SCOPE._wrapper.game_player_perform_transfer = Game_Player.prototype.performTransfer; Game_Player.prototype.performTransfer = function() { SIV_SCOPE._runOnMap.call(SIV_SCOPE._data.currentMapInstance, 'create') SIV_SCOPE._wrapper.game_player_perform_transfer.apply(this, arguments) } SIV_SCOPE._wrapper._scene_map_create_display_objects = Scene_Map.prototype.createDisplayObjects; Scene_Map.prototype.createDisplayObjects = function() { SIV_SCOPE._wrapper._scene_map_create_display_objects.apply(this, arguments) SIV_SCOPE._runOnMap.call(this, 'addObjects') } SIV_SCOPE._runOnScene = function(args, name, event) { name = name.toLowerCase() event = event.toLowerCase() if (SIV_SCOPE._onQueue[name] && SIV_SCOPE._onQueue[name][event]) { for (var i = 0; i < SIV_SCOPE._onQueue[name][event].length; i++) { SIV_SCOPE._onQueue[name][event][i].apply(this, args) } } } SIV_SCOPE._runOnMap = function(event) { event = event.toLowerCase() if (SIV_SCOPE._onQueue.scene_map && SIV_SCOPE._onQueue.scene_map[event]) { for (var i = 0; i < SIV_SCOPE._onQueue.scene_map[event].length; i++) { var mapId, oldMapId; if ($gamePlayer.isTransferring()) { mapId = $gamePlayer.newMapId(); oldMapId = $gameMap.mapId(); } else mapId = $gameMap.mapId(); SIV_SCOPE._onQueue.scene_map[event][i].call(this, mapId, oldMapId) } } } //we should use onChange but it does not have the index or the value... SIV_SCOPE._wrapper.game_variables_set_value = Game_Variables.prototype.setValue Game_Variables.prototype.setValue = function(index) { SIV_SCOPE._wrapper.game_variables_set_value.apply(this, arguments); if (SIV_SCOPE._onQueue.variableChange[index]) { for (var i = 0; i < SIV_SCOPE._onQueue.variableChange[index].length; i++) { SIV_SCOPE._onQueue.variableChange[index][i].apply(this, arguments); } } } //117 == call common event from other event (-_- bad naming convention IMO) SIV_SCOPE._wrapper.game_interpreter_command117 = Game_Interpreter.prototype.command117; Game_Interpreter.prototype.command117 = function() { var commonEventId = this._params[0] , result = SIV_SCOPE._wrapper.game_interpreter_command117.apply(this, arguments); if (this._childInterpreter) this._childInterpreter._commonEventId = commonEventId; return result }; Game_Interpreter.prototype.getOriginEventId = function() { var isCommonEvent = (this._depth > 0) return { id: (isCommonEvent) ? this._commonEventId : this._eventId, commonEvent: isCommonEvent } } /** * BEHOLD! The Dictionary Function Switch! Lay your worship at the feet of the * JS Gods for this gift that they have given us! * * This will fire off any functions registered by their command names. This skips * all the ifs and switch logic. If its registered it will run, if nothing is registered * then nothing happens. Instant wonderful perfect switch. ( I am kinda a fan :P ) * * !!!Warning!!! Last write wins apply here. Conflicting commands will only fire * the last one defined. * */ SIV_SCOPE._wrapper._game_interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand; Game_Interpreter.prototype.pluginCommand = function(command) { SIV_SCOPE._wrapper._game_interpreter_pluginCommand.apply(this, arguments); if (SIV_SCOPE._pluginCommands[command]) SIV_SCOPE._pluginCommands[command].apply(this, arguments); }; /** * If we have not laoded the map notes yet do so now. * This is also where we should get the map event notes. */ SIV_SCOPE.onSceneEvent(Scene_Map, 'create', function(mapId, oldMapId) { if (SIV_SCOPE._preloadMapNotes) return; if ($dataMap && !SIV_SCOPE._data.notetagDictionary['maps'][mapId]) { SIV_SCOPE._data.notetagDictionary['maps'][mapId] = { notes: SIV_SCOPE._parseNoteTag($dataMap.note) } SIV_SCOPE._data.notetagDictionary['mapEvents'][mapId] = {} for (var eventId = 1; eventId < $dataMap.events.length; eventId++) { SIV_SCOPE._data.notetagDictionary['mapEvents'][mapId][eventId] = {} var notes = [] for (var pageIndex = 0; pageIndex < $dataMap.events[eventId].pages.length; pageIndex++) { notes = SIV_SCOPE._parseEventPageNotes($dataMap.events[eventId].pages[pageIndex], notes) } SIV_SCOPE._data.notetagDictionary['mapEvents'][mapId][eventId] = { notes: notes } } } }) /** * runs the onFrame queue */ SIV_SCOPE._wrapper.scene_manager_update = SceneManager.update; SceneManager.update = function() { SIV_SCOPE._wrapper.scene_manager_update.call(this); if (SIV_SCOPE._data.databaseHasLoaded && SIV_SCOPE._onQueue.onFrame.length) { for (var i = 0; i < SIV_SCOPE._onQueue.onFrame.length; i++) { SIV_SCOPE._onQueue.onFrame[i].apply(this, arguments) } } } function Window_Smart_Text() { Window_Smart_Text.prototype.initialize.apply(this, arguments) } Window_Smart_Text.prototype = Object.create(Window_Base.prototype); Window_Smart_Text.prototype.initialize = function(settings) { //It seems there must be a bug with MV 1.5 window initialize. //It does not let you grow the size of your window content (may I am missing something?) //Eather way setting it to full screen size does the trick. //We then resize with refresh so the correct window size is always displayed. Window_Base.prototype.initialize.call(this, 0, 0, Graphics.boxWidth, Graphics.boxHeight); this._defaultSettings = Object.assign({}, { positionX: 50, positionY: 50, fontSize: 20, padding: 18, textSpacing: 4, visible: true }, settings); this._textRows = [] this.contents.fontSize = settings.fontSize; this.padding = settings.padding; this.visible = settings.visible; this.refresh() } Window_Smart_Text.prototype.refresh = function() { if (this.visible) { this.contents.clear(); this._textRows = []; if (this.addContents) this.addContents(); var totalTextWidth = 0, totalTextHeight = 0; //calculate needed settings totalTextHeight = (this.contents.fontSize + this._defaultSettings.textSpacing) * (this._textRows.length) - + this._defaultSettings.textSpacing; for (var i = 0; i < this._textRows.length; i++) { totalTextWidth = Math.max( totalTextWidth, this.contents.measureTextWidth(this._textRows[i])); } //acutally draw contents for (var i = 0; i < this._textRows.length; i++) { this.contents.drawText(this._textRows[i], 0, (this.contents.fontSize + this._defaultSettings.textSpacing) * i, totalTextWidth, this.contents.fontSize, 'center'); } totalTextWidth += this.padding * 2 totalTextHeight += this.padding * 2 this.move(this.getPercentX(this._defaultSettings.positionX, totalTextWidth) , this.getPercentY(this._defaultSettings.positionY, totalTextHeight) , totalTextWidth, totalTextHeight) } }; Window_Smart_Text.prototype.addText = function(text) { this._textRows.push(text) } //the mockup of our smart window Window_Smart_Text.prototype.getPercentX = function(target, offset) { return this._percent(Graphics.boxWidth, target, offset); } Window_Smart_Text.prototype.getPercentY = function(target, offset) { return this._percent(Graphics.boxHeight, target, offset); } Window_Smart_Text.prototype._percent = function(fullSize, target, offset) { offset = offset || 0; var pix = (fullSize - offset) * (target / 100); if (pix < 0) return 0; return pix; } //////////////////////////////////////////////////////////////////////////////////// // JS EXTENTIONS & External code that makes me wish I could load npm dependances. // // I will try to keep this to a minimum. // //////////////////////////////////////////////////////////////////////////////////// Math.fmod = function (a,b) { //floor mod. This lets us match the c++ webkit style of handling timestamps return Number((a - (Math.floor(a / b) * b)).toPrecision(8)); }; /** * A simple dependency graph * https://github.com/jriecken/dependency-graph * https://github.com/jriecken/dependency-graph/blob/master/LICENSE */ !function(){function n(n,e,i){var t=[],o={};return function s(d){o[d]=!0,t.push(d),n[d].forEach(function(n){if(o[n]){if(t.indexOf(n)>=0)throw t.push(n),new Error("Dependency Cycle Found: "+t.join(" -> "))}else s(n)}),t.pop(),e&&0!==n[d].length||-1!==i.indexOf(d)||i.push(d)}}var e=function(){this.nodes={},this.outgoingEdges={},this.incomingEdges={}};e.prototype={addNode:function(n,e){this.hasNode(n)||(2===arguments.length?this.nodes[n]=e:this.nodes[n]=n,this.outgoingEdges[n]=[],this.incomingEdges[n]=[])},removeNode:function(n){this.hasNode(n)&&(delete this.nodes[n],delete this.outgoingEdges[n],delete this.incomingEdges[n],[this.incomingEdges,this.outgoingEdges].forEach(function(e){Object.keys(e).forEach(function(i){var t=e[i].indexOf(n);t>=0&&e[i].splice(t,1)},this)}))},hasNode:function(n){return this.nodes.hasOwnProperty(n)},getNodeData:function(n){if(this.hasNode(n))return this.nodes[n];throw new Error("Plugin does not exist: "+n)},setNodeData:function(n,e){if(!this.hasNode(n))throw new Error("Plugin does not exist: "+n);this.nodes[n]=e},addDependency:function(n,e){if(!this.hasNode(n))throw new Error("Plugin does not exist: "+n);if(!this.hasNode(e))throw new Error("Plugin does not exist: "+e);return-1===this.outgoingEdges[n].indexOf(e)&&this.outgoingEdges[n].push(e),-1===this.incomingEdges[e].indexOf(n)&&this.incomingEdges[e].push(n),!0},removeDependency:function(n,e){var i;this.hasNode(n)&&(i=this.outgoingEdges[n].indexOf(e))>=0&&this.outgoingEdges[n].splice(i,1),this.hasNode(e)&&(i=this.incomingEdges[e].indexOf(n))>=0&&this.incomingEdges[e].splice(i,1)},dependenciesOf:function(e,i){if(this.hasNode(e)){var t=[];n(this.outgoingEdges,i,t)(e);var o=t.indexOf(e);return o>=0&&t.splice(o,1),t}throw new Error("Plugin does not exist: "+e)},dependantsOf:function(e,i){if(this.hasNode(e)){var t=[];n(this.incomingEdges,i,t)(e);var o=t.indexOf(e);return o>=0&&t.splice(o,1),t}throw new Error("Plugin does not exist: "+e)},overallOrder:function(e){var i=this,t=[],o=Object.keys(this.nodes);if(0===o.length)return t;var s=n(this.outgoingEdges,!1,[]);o.forEach(function(n){s(n)});var d=n(this.outgoingEdges,e,t);return o.filter(function(n){return 0===i.incomingEdges[n].length}).forEach(function(n){d(n)}),t}},window.DepGraph=e}(); SIV_SCOPE._dependencyGraph = new DepGraph(); // going old school with some mustache.js // https://github.com/janl/mustache.js // https://github.com/janl/mustache.js/blob/master/LICENSE !function(b,c){"object"==typeof exports&&exports&&"string"!=typeof exports.nodeName?c(exports):"function"==typeof define&&define.amd?define(["exports"],c):(b.Mustache={},c(b.Mustache))}(this,function(b){function e(a){return"function"==typeof a}function f(a){return d(a)?"array":typeof a}function g(a){return a.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function h(a,b){return null!=a&&"object"==typeof a&&b in a}function j(a,b){return i.call(a,b)}function l(a){return!j(k,a)}function n(a){return String(a).replace(/[&<>"'`=\/]/g,function(b){return m[b]})}function t(a,c){function k(){if(i&&!j)for(;h.length;)delete f[h.pop()];else h=[];i=!1,j=!1}function x(a){if("string"==typeof a&&(a=a.split(p,2)),!d(a)||2!==a.length)throw new Error("Invalid tags: "+a);m=new RegExp(g(a[0])+"\\s*"),n=new RegExp("\\s*"+g(a[1])),t=new RegExp("\\s*"+g("}"+a[1]))}if(!a)return[];var m,n,t,e=[],f=[],h=[],i=!1,j=!1;x(c||b.tags);for(var z,A,B,C,D,E,y=new w(a);!y.eos();){if(z=y.pos,B=y.scanUntil(m))for(var F=0,G=B.length;F0?d[d.length-1][4]:b;break;default:c.push(e)}return b}function w(a){this.string=a,this.tail=a,this.pos=0}function x(a,b){this.view=a,this.cache={".":this.view},this.parent=b}function y(){this.cache={}}var c=Object.prototype.toString,d=Array.isArray||function(b){return"[object Array]"===c.call(b)},i=RegExp.prototype.test,k=/\S/,m={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="},o=/\s*/,p=/\s+/,q=/\s*=/,r=/\s*\}/,s=/#|\^|\/|>|\{|&|=|!/;w.prototype.eos=function(){return""===this.tail},w.prototype.scan=function(b){var c=this.tail.match(b);if(!c||0!==c.index)return"";var d=c[0];return this.tail=this.tail.substring(d.length),this.pos+=d.length,d},w.prototype.scanUntil=function(b){var d,c=this.tail.search(b);switch(c){case-1:d=this.tail,this.tail="";break;case 0:d="";break;default:d=this.tail.substring(0,c),this.tail=this.tail.substring(c)}return this.pos+=d.length,d},x.prototype.push=function(b){return new x(b,this)},x.prototype.lookup=function(b){var d,c=this.cache;if(c.hasOwnProperty(b))d=c[b];else{for(var g,i,f=this,j=!1;f;){if(b.indexOf(".")>0)for(d=f.view,g=b.split("."),i=0;null!=d&&i"===h?i=this.renderPartial(g,c,d,e):"&"===h?i=this.unescapedValue(g,c):"name"===h?i=this.escapedValue(g,c):"text"===h&&(i=this.rawValue(g)),void 0!==i&&(f+=i);return f},y.prototype.renderSection=function(b,c,f,g){function k(a){return h.render(a,c,f)}var h=this,i="",j=c.lookup(b[1]);if(j){if(d(j))for(var l=0,m=j.length;l