text: function newPlottersManager() {
      const MODULE_NAME = 'Plotters Manager'
      const ERROR_LOG = true
      const logger = newWebDebugLog()
  
  
      let timeFrame = INITIAL_TIME_PERIOD
      let datetime = NEW_SESSION_INITIAL_DATE
  
      let thisObject = {
          fitFunction: undefined,
          container: undefined,
          payload: undefined,
          connectors: [],
          setDatetime: setDatetime,
          setTimeFrame: setTimeFrame,
          setCoordinateSystem: setCoordinateSystem,
          physics: physics,
          draw: draw,
          getContainer: getContainer,
          initialize: initialize,
          finalize: finalize
      }
  
      thisObject.connectors = []
  
      let initializationReady = false
      let layersPanel
      let onLayerStatusChangedEventSuscriptionId
      let coordinateSystem
  
      setupContainer()
      return thisObject
  
      function setupContainer() {
          thisObject.container = newContainer()
          thisObject.container.initialize(MODULE_NAME)
      }
  
      function finalize() {
          layersPanel.container.eventHandler.stopListening(onLayerStatusChangedEventSuscriptionId)
          layersPanel = undefined
  
          for (let i = 0; i < thisObject.connectors.length; i++) {
              let connector = thisObject.connectors[i]
              /* Then the panels. */
              for (let j = 0; j < connector.panels.length; j++) {
                  UI.projects.foundations.spaces.panelSpace.destroyPanel(connector.panels[j])
                  connector.panels[j] = undefined
              }
              connector.panels = undefined
  
              /* Finalize the plotters */
              if (connector.plotter.finalize !== undefined) {
                  connector.plotter.container.eventHandler.stopListening(connector.plotter.onRecordChangeEventsSubscriptionId)
                  connector.plotter.finalize()
              }
              connector.plotter = undefined
  
              /* Finally the Storage Objects */
              finalizeStorage(connector.storage)
              connector.storage = undefined
  
              connector = undefined
          }
          thisObject.connectors = []
          coordinateSystem = undefined
  
          thisObject.container.finalize()
          thisObject.container = undefined
          thisObject.payload = undefined
      }
  
      function finalizeStorage(storage) {
          storage.eventHandler.stopListening(storage.onMarketFileLoadedLayerEventsSubscriptionId)
          storage.eventHandler.stopListening(storage.onDailyFileLoadedLayerEventsSubscriptionId)
          storage.eventHandler.stopListening(storage.onSingleFileLoadedLayerEventsSubscriptionId)
          storage.eventHandler.stopListening(storage.onFileSequenceLoadedLayerEventsSubscriptionId)
          storage.eventHandler.stopListening(storage.onDailyFileLoadedPlotterEventsSubscriptionId)
          storage.finalize()
      }
  
      function initialize(pLayersPanel) {
          /* Remember this */
          layersPanel = pLayersPanel
  
          /* Listen to the event of change of status */
          onLayerStatusChangedEventSuscriptionId = layersPanel.container.eventHandler.listenToEvent('Layer Status Changed', onLayerStatusChanged)
      }
  
      function initializePlotter(layer) {
          try {
              /* Before Initializing a Plotter, we need the Storage it will use, loaded with the files it will initially need. */
              let storage = newProductStorage(layer.payload.node.id)
  
              /*
              Before Initializing the Storage, we will put the Layer to listen to the events the storage will raise every time a file is loaded,
              so that the UI can somehow show this. There are different types of events.
              */
              for (let i = 0; i < layer.definition.referenceParent.referenceParent.datasets.length; i++) {
                  let dataset = layer.definition.referenceParent.referenceParent.datasets[i]
  
                  switch (dataset.config.type) {
                      case 'Market Files': {
                          storage.onMarketFileLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('Market File Loaded', layer.onMarketFileLoaded)
                      }
                          break
                      case 'Daily Files': {
                          storage.onDailyFileLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('Daily File Loaded', layer.onDailyFileLoaded)
                      }
                          break
                      case 'Single File': {
                          storage.onSingleFileLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('Single File Loaded', layer.onSingleFileLoaded)
                      }
                          break
                      case 'File Sequence': {
                          storage.onFileSequenceLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('File Sequence Loaded', layer.onFileSequenceLoaded)
                      }
                          break
                      default: {
                          if (ERROR_LOG === true) {
                              logger.write('[ERROR] initializePlotter -> Dataset Type Incorrect or Undefined -> dataset.type = ' + dataset.type)
                          }
                          return
                      }
                  }
              }
  
              let baseAsset = layer.baseAsset.config.codeName
              let quotedAsset = layer.quotedAsset.config.codeName
              let market = {
                  baseAsset: baseAsset,
                  quotedAsset: quotedAsset
              }
              let productDefinition = layer.productDefinition
              let bot = layer.bot
              let mine = layer.mine
              let exchange = layer.exchange
              let plotterModule = layer.plotterModule
              let session
              let tradingOrLearningSystem
              let tradingOrLearningEngine
  
              /*
              A layer can be referencing a Data Product in 3 different branches of the Network hierarchy.
              Two of those branches have sessions.
              */
              let sessionReference = UI.projects.visualScripting.utilities.meshes.findNodeInNodeMesh(layer.definition, 'Trading Session Reference', undefined, false, true, true, true)
              if (sessionReference === undefined) {
                  sessionReference = UI.projects.visualScripting.utilities.meshes.findNodeInNodeMesh(layer.definition, 'Learning Session Reference', undefined, false, true, true, true)
              }
  
              if (sessionReference !== undefined) {
                  session = sessionReference.referenceParent
                  if (session === undefined) {
                      logger.write('[ERROR] initializePlotter -> Session Reference without a Reference Parent -> Plotter will not be loaded. ')
                      return
                  }
                  /* From the session we might be able to reach the Trading System or the Trading Engine */
                  if (session.tradingSystemReference !== undefined) {
                      tradingOrLearningSystem = session.tradingSystemReference.referenceParent
                  }
                  if (session.tradingEngineReference !== undefined) {
                      tradingOrLearningEngine = session.tradingEngineReference.referenceParent
                  }
                  if (session.learningSystemReference !== undefined) {
                      tradingOrLearningSystem = session.learningSystemReference.referenceParent
                  }
                  if (session.learningEngineReference !== undefined) {
                      tradingOrLearningEngine = session.learningEngineReference.referenceParent
                  }
              }
  
              let host = layer.lanNetworkNode.config.host
              let webPort = layer.lanNetworkNode.config.webPort
              let extWSURL = layer.lanNetworkNode.config.webSocketsExternalURL
              let scheme = 'http'
              if (host === undefined) { host = window.location.hostname }
              if (webPort === undefined) { webPort = window.location.port }
              if (extWSURL !== undefined) { 
              	host = window.location.hostname
              	webPort = window.location.port
              	scheme = window.location.protocol.slice(0,-1)
              }
  
              let eventsServerClient = UI.projects.foundations.spaces.designSpace.workspace.eventsServerClients.get(layer.lanNetworkNode.id)
  
              storage.initialize(
                  mine,
                  bot,
                  session,
                  productDefinition,
                  exchange,
                  market,
                  datetime,
                  timeFrame,
                  host,
                  webPort,
                  eventsServerClient,
                  onProductStorageInitialized,
                  scheme,
              )
  
              function onProductStorageInitialized(err) {
                  if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
                      /* Now we have all the initial data loaded and ready to be delivered to the new instance of the plotter. */
                      let plotter
  
                      if (plotterModule.config.isLegacy !== true) {
                          plotter = newPlotter()
                      } else {
                          plotter = getNewPlotter(mine.config.codeName, plotterModule.parentNode.config.codeName, plotterModule.config.codeName)
                      }
  
                      plotter.container.connectToParent(thisObject.container, true, true, false, true, true, true, false, false, true)
                      plotter.container.frame.position.x = thisObject.container.frame.width / 2 - plotter.container.frame.width / 2
                      plotter.container.frame.position.y = thisObject.container.frame.height / 2 - plotter.container.frame.height / 2
                      plotter.fitFunction = thisObject.fitFunction
                      plotter.initialize(storage, datetime, timeFrame, coordinateSystem, onPlotterInizialized, productDefinition)
  
                      function onPlotterInizialized() {
                          let connector = {
                              layer: layer,
                              plotter: plotter,
                              storage: storage
                          }
                          /* Let the Plotter listen to the event of Cursor Files loaded, so that it can react recalculating if needed. */
                          plotter.onDailyFileLoadedPlotterEventsSubscriptionId = storage.eventHandler.listenToEvent('Daily File Loaded', plotter.onDailyFileLoaded)
                          /* Lets load now this plotter panels. */
                          connector.panels = []
  
                          if (productDefinition !== undefined) {
                              /* Here we setup the panels associated with this plotter */
                              for (let i = 0; i < plotterModule.panels.length; i++) {
                                  let panel = plotterModule.panels[i]
  
                                  let parameters = {
                                      mine: mine.config.codeName,
                                      plotterCodeName: plotterModule.parentNode.config.codeName,
                                      moduleCodeName: plotterModule.config.codeName,
                                      panelNode: panel
                                  }
  
                                  let owner = thisObject.payload.node.payload.parentNode.id // Panels are owned by the time machine.
                                  let plotterPanelHandle = UI.projects.foundations.spaces.panelSpace.createNewPanel('Plotter Panel', parameters, owner, layer.session)
                                  let plotterPanel = UI.projects.foundations.spaces.panelSpace.getPanel(plotterPanelHandle)
  
                                  /* Connect Panel to the Plotter via an Event. */
                                  connector.plotter.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', plotterPanel.onRecordChange)
                                  connector.panels.push(plotterPanelHandle)
                              }
                              connector.layer.panels = connector.panels
  
                              /*
                              Next we will check the different types of Plotting related to connecting to an existing node branch.
                              */
                              if (plotterModule.nodesHighlights !== undefined && plotterModule.config.connectTo !== undefined) {
                                  connector.nodesHighlights = newNodesHighlights()
                                  switch (plotterModule.config.connectTo) {
                                      case 'Trading System':
                                          connector.nodesHighlights.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Trading Engine':
                                          connector.nodesHighlights.initialize(tradingOrLearningEngine)
                                          break
                                      case 'Learning System':
                                          connector.nodesHighlights.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Learning Engine':
                                          connector.nodesHighlights.initialize(tradingOrLearningEngine)
                                          break
                                  }
                                  connector.nodesHighlights.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesHighlights.onRecordChange)
                              }
                              if (plotterModule.nodesValues !== undefined && plotterModule.config.connectTo !== undefined) {
                                  connector.nodesValues = newNodesValues()
                                  switch (plotterModule.config.connectTo) {
                                      case 'Trading System':
                                          connector.nodesValues.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Trading Engine':
                                          connector.nodesValues.initialize(tradingOrLearningEngine)
                                          break
                                      case 'Learning System':
                                          connector.nodesValues.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Learning Engine':
                                          connector.nodesValues.initialize(tradingOrLearningEngine)
                                          break
                                  }
                                  connector.nodesValues.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesValues.onRecordChange)
                              }
                              if (plotterModule.nodesErrors !== undefined && plotterModule.config.connectTo !== undefined) {
                                  connector.nodesErrors = newNodesErrors()
                                  switch (plotterModule.config.connectTo) {
                                      case 'Trading System':
                                          connector.nodesErrors.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Trading Engine':
                                          connector.nodesErrors.initialize(tradingOrLearningEngine)
                                          break
                                      case 'Learning System':
                                          connector.nodesErrors.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Learning Engine':
                                          connector.nodesErrors.initialize(tradingOrLearningEngine)
                                          break
                                  }
                                  connector.nodesErrors.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesErrors.onRecordChange)
                              }
                              if (plotterModule.nodesWarnings !== undefined && plotterModule.config.connectTo !== undefined) {
                                  connector.nodesWarnings = newNodesWarnings()
                                  switch (plotterModule.config.connectTo) {
                                      case 'Trading System':
                                          connector.nodesWarnings.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Trading Engine':
                                          connector.nodesWarnings.initialize(tradingOrLearningEngine)
                                          break
                                      case 'Learning System':
                                          connector.nodesWarnings.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Learning Engine':
                                          connector.nodesWarnings.initialize(tradingOrLearningEngine)
                                          break
                                  }
                                  connector.nodesWarnings.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesWarnings.onRecordChange)
                              }
                              if (plotterModule.nodesInfos !== undefined && plotterModule.config.connectTo !== undefined) {
                                  connector.nodesInfos = newNodesInfos()
                                  switch (plotterModule.config.connectTo) {
                                      case 'Trading System':
                                          connector.nodesInfos.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Trading Engine':
                                          connector.nodesInfos.initialize(tradingOrLearningEngine)
                                          break
                                      case 'Learning System':
                                          connector.nodesInfos.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Learning Engine':
                                          connector.nodesInfos.initialize(tradingOrLearningEngine)
                                          break
                                  }
                                  connector.nodesInfos.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesInfos.onRecordChange)
                              }
                              if (plotterModule.nodesRunning !== undefined && plotterModule.config.connectTo !== undefined) {
                                  connector.nodesRunning = newNodesRunning()
                                  switch (plotterModule.config.connectTo) {
                                      case 'Trading System':
                                          connector.nodesRunning.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Trading Engine':
                                          connector.nodesRunning.initialize(tradingOrLearningEngine)
                                          break
                                      case 'Learning System':
                                          connector.nodesRunning.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Learning Engine':
                                          connector.nodesRunning.initialize(tradingOrLearningEngine)
                                          break
                                  }
                                  connector.nodesRunning.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesRunning.onRecordChange)
                              }
                              if (plotterModule.nodesStatus !== undefined && plotterModule.config.connectTo !== undefined) {
                                  connector.nodesStatus = newNodesStatus()
                                  switch (plotterModule.config.connectTo) {
                                      case 'Trading System':
                                          connector.nodesStatus.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Trading Engine':
                                          connector.nodesStatus.initialize(tradingOrLearningEngine)
                                          break
                                      case 'Learning System':
                                          connector.nodesStatus.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Learning Engine':
                                          connector.nodesStatus.initialize(tradingOrLearningEngine)
                                          break
                                  }
                                  connector.nodesStatus.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesStatus.onRecordChange)
                              }
                              if (plotterModule.nodesProgress !== undefined && plotterModule.config.connectTo !== undefined) {
                                  connector.nodesProgress = newNodesProgress()
                                  switch (plotterModule.config.connectTo) {
                                      case 'Trading System':
                                          connector.nodesProgress.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Trading Engine':
                                          connector.nodesProgress.initialize(tradingOrLearningEngine)
                                          break
                                      case 'Learning System':
                                          connector.nodesProgress.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Learning Engine':
                                          connector.nodesProgress.initialize(tradingOrLearningEngine)
                                          break
                                  }
                                  connector.nodesProgress.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesProgress.onRecordChange)
                              }
                              if (plotterModule.nodesAnnouncements !== undefined && plotterModule.config.connectTo !== undefined) {
                                  connector.nodesAnnounements = newNodesAnnouncements()
                                  switch (plotterModule.config.connectTo) {
                                      case 'Trading System':
                                          connector.nodesAnnounements.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Trading Engine':
                                          connector.nodesAnnounements.initialize(tradingOrLearningEngine)
                                          break
                                      case 'Learning System':
                                          connector.nodesAnnounements.initialize(tradingOrLearningSystem)
                                          break
                                      case 'Learning Engine':
                                          connector.nodesAnnounements.initialize(tradingOrLearningEngine)
                                          break
                                  }
                                  connector.nodesAnnounements.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesAnnounements.onRecordChange)
                              }
                              /*
                              Another type of plotting is with Record Values. This method uses the record definition to find the target node
                              and from there is looks into its children all based on the Record Definition configuration.
                              */
                              if (plotterModule.recordValues !== undefined) {
                                  connector.recordValues = newRecordValues()
                                  connector.recordValues.initialize(tradingOrLearningSystem, tradingOrLearningEngine, productDefinition)
                                  connector.recordValues.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.recordValues.onRecordChange)
                              }
                          }
                          thisObject.connectors.push(connector)
                      }
                  }
              }
          } catch (err) {
              if (ERROR_LOG === true) { logger.write('[ERROR] initializePlotter -> err = ' + err.stack) }
          }
      }
  
      function onLayerStatusChanged(layer) {
          if (layer.status === LAYER_STATUS.LOADING) {
              /* Lets see if we can find the Plotter of this card on our Active Plotters list, other wise we will initialize it */
              let found = false
              for (let i = 0; i < thisObject.connectors.length; i++) {
                  let connector = thisObject.connectors[i]
                  if (connector.layer.payload.node.id === layer.payload.node.id) {
                      found = true
                  }
              }
              if (found === false) {
                  initializePlotter(layer)
              }
          }
          if (layer.status === LAYER_STATUS.OFF) {
              /* If the plotter of this card is not on our Active Plotters list, then we remove it. */
              for (let i = 0; i < thisObject.connectors.length; i++) {
                  let connector = thisObject.connectors[i]
                  if (connector.layer.payload.node.id === layer.payload.node.id) {
                      /* Then the panels. */
                      for (let j = 0; j < connector.panels.length; j++) {
                          UI.projects.foundations.spaces.panelSpace.destroyPanel(connector.panels[j])
                      }
                      /* Finally the Storage Objects */
                      finalizeNodesPlotting(connector)
                      if (connector.plotter.finalize !== undefined) {
                          connector.plotter.container.eventHandler.stopListening(connector.plotter.onRecordChangeEventsSubscriptionId)
                          connector.plotter.container.finalize()
                          connector.plotter.finalize()
                      }
                      finalizeStorage(connector.storage)
                      thisObject.connectors.splice(i, 1) // Delete item from array.
                      return // We already found the product with changes and processed it.
                  }
              }
          }
      }
  
      function finalizeNodesPlotting(connector) {
          if (connector.nodesHighlights !== undefined) {
              connector.plotter.container.eventHandler.stopListening(connector.nodesHighlights.onRecordChangeEventsSubscriptionId)
              connector.nodesHighlights.finalize()
          }
          if (connector.nodesValues !== undefined) {
              connector.plotter.container.eventHandler.stopListening(connector.nodesValues.onRecordChangeEventsSubscriptionId)
              connector.nodesValues.finalize()
          }
          if (connector.nodesErrors !== undefined) {
              connector.plotter.container.eventHandler.stopListening(connector.nodesErrors.onRecordChangeEventsSubscriptionId)
              connector.nodesErrors.finalize()
          }
          if (connector.nodesWarnings !== undefined) {
              connector.plotter.container.eventHandler.stopListening(connector.nodesWarnings.onRecordChangeEventsSubscriptionId)
              connector.nodesWarnings.finalize()
          }
          if (connector.nodesInfos !== undefined) {
              connector.plotter.container.eventHandler.stopListening(connector.nodesInfos.onRecordChangeEventsSubscriptionId)
              connector.nodesInfos.finalize()
          }
          if (connector.nodesStatus !== undefined) {
              connector.plotter.container.eventHandler.stopListening(connector.nodesStatus.onRecordChangeEventsSubscriptionId)
              connector.nodesStatus.finalize()
          }
          if (connector.nodesProgress !== undefined) {
              connector.plotter.container.eventHandler.stopListening(connector.Progress.onRecordChangeEventsSubscriptionId)
              connector.Progress.finalize()
          }
          if (connector.nodesRunning !== undefined) {
              connector.plotter.container.eventHandler.stopListening(connector.nodesRunning.onRecordChangeEventsSubscriptionId)
              connector.nodesRunning.finalize()
          }
          if (connector.recordValues !== undefined) {
              connector.plotter.container.eventHandler.stopListening(connector.recordValues.onRecordChangeEventsSubscriptionId)
              connector.recordValues.finalize()
          }
      }
  
      function setTimeFrame(pTimeFrame) {
          timeFrame = pTimeFrame
          for (let i = 0; i < thisObject.connectors.length; i++) {
              let connector = thisObject.connectors[i]
              connector.layer.setTimeFrame(timeFrame)
              connector.storage.setTimeFrame(timeFrame)
              connector.plotter.setTimeFrame(timeFrame)
          }
      }
  
      function setDatetime(pDatetime) {
          datetime = pDatetime
          for (let i = 0; i < thisObject.connectors.length; i++) {
              let connector = thisObject.connectors[i]
              connector.layer.setDatetime(pDatetime)
              connector.storage.setDatetime(pDatetime)
              connector.plotter.setDatetime(pDatetime)
          }
      }
  
      function setCoordinateSystem(pCoordinateSystem) {
          coordinateSystem = pCoordinateSystem
          for (let i = 0; i < thisObject.connectors.length; i++) {
              let connector = thisObject.connectors[i]
              connector.plotter.setCoordinateSystem(coordinateSystem)
          }
      }
  
      function getContainer(point) {
      }
  
      function draw() {
          if (thisObject.connectors === undefined) { return } // We need to wait
          /* First the Product Plotters. */
          let maxElementsPlotted = 0
          for (let i = 0; i < thisObject.connectors.length; i++) {
              let connector = thisObject.connectors[thisObject.connectors.length - i - 1]
              let elementsPlotted = connector.plotter.draw()
              if (elementsPlotted !== undefined) {
                  if (elementsPlotted > maxElementsPlotted) {
                      maxElementsPlotted = elementsPlotted
                  }
              }
          }
          return maxElementsPlotted
      }
  
      function physics() {
          if (thisObject.connectors === undefined) { return } // We need to wait
          for (let i = 0; i < thisObject.connectors.length; i++) {
              let connector = thisObject.connectors[thisObject.connectors.length - i - 1]
              if (connector.plotter.physics !== undefined) {
                  connector.plotter.physics()
              }
          }
      }
  }
  