From e393232c7a115bea290f26b95d257342ae0ed9fd Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 27 Feb 2018 15:50:04 +0100 Subject: [PATCH] Initial commit --- .gitattributes | 2 + .vs/AAMariam-Plotter/v15/.suo | Bin 0 -> 16896 bytes .vs/AAOlivia-Plotter/v15/.suo | Bin 0 -> 17920 bytes AAMariam-Plotter.njsproj | 67 ++ AAMariam-Plotter.sln | 25 + Details.js | 762 ++++++++++++++++++ History.js | 694 ++++++++++++++++ README.md | 1 + bin/Microsoft.NodejsTools.WebRole.dll | Bin 0 -> 32992 bytes ...ia-Plotter.njsproj.CoreCompileInputs.cache | 1 + ...livia-Plotter.njsproj.FileListAbsolute.txt | 3 + ...tter.njsprojResolveAssemblyReference.cache | Bin 0 -> 2216 bytes 12 files changed, 1555 insertions(+) create mode 100644 .gitattributes create mode 100644 .vs/AAMariam-Plotter/v15/.suo create mode 100644 .vs/AAOlivia-Plotter/v15/.suo create mode 100644 AAMariam-Plotter.njsproj create mode 100644 AAMariam-Plotter.sln create mode 100644 Details.js create mode 100644 History.js create mode 100644 README.md create mode 100644 bin/Microsoft.NodejsTools.WebRole.dll create mode 100644 obj/Debug/AAOlivia-Plotter.njsproj.CoreCompileInputs.cache create mode 100644 obj/Debug/AAOlivia-Plotter.njsproj.FileListAbsolute.txt create mode 100644 obj/Debug/AAOlivia-Plotter.njsprojResolveAssemblyReference.cache diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..dfe077042 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.vs/AAMariam-Plotter/v15/.suo b/.vs/AAMariam-Plotter/v15/.suo new file mode 100644 index 0000000000000000000000000000000000000000..d1501bee538092438849e0f631d8a14e119713c7 GIT binary patch literal 16896 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 literal 0 HcmV?d00001 diff --git a/AAMariam-Plotter.njsproj b/AAMariam-Plotter.njsproj new file mode 100644 index 000000000..762c10990 --- /dev/null +++ b/AAMariam-Plotter.njsproj @@ -0,0 +1,67 @@ + + + + Debug + 2.0 + {096b35ad-f86f-47b9-a99f-04ca93397da8} + + ShowAllFiles + History.js + . + . + {3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD} + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + AAMariam-Plotter + + + + + + + Code + + + + + + + + + + + False + True + 0 + / + http://localhost:48022/ + False + True + http://localhost:1337 + False + + + + + + + CurrentPage + True + False + False + False + + + + + + + + + False + False + + + + + \ No newline at end of file diff --git a/AAMariam-Plotter.sln b/AAMariam-Plotter.sln new file mode 100644 index 000000000..83a9e865a --- /dev/null +++ b/AAMariam-Plotter.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2027 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "AAMariam-Plotter", "AAMariam-Plotter.njsproj", "{096B35AD-F86F-47B9-A99F-04CA93397DA8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {096B35AD-F86F-47B9-A99F-04CA93397DA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {096B35AD-F86F-47B9-A99F-04CA93397DA8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {096B35AD-F86F-47B9-A99F-04CA93397DA8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {096B35AD-F86F-47B9-A99F-04CA93397DA8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E75EDC9D-66A7-4C54-8EA1-5ADC148CACA8} + EndGlobalSection +EndGlobal diff --git a/Details.js b/Details.js new file mode 100644 index 000000000..ae1961bf6 --- /dev/null +++ b/Details.js @@ -0,0 +1,762 @@ +function newAAMastersAAOliviaVolumes() { + + let thisObject = { + + // Main functions and properties. + + initialize: initialize, + container: undefined, + getContainer: getContainer, + setTimePeriod: setTimePeriod, + setDatetime: setDatetime, + draw: draw, + + // Secondary functions and properties. + + onLayerStatusChanged: onLayerStatusChanged + }; + + /* this is part of the module template */ + + let container = newContainer(); // Do not touch this 3 lines, they are just needed. + container.initialize(); + thisObject.container = container; + + let layerStatus = 'off'; // Since the moduleis a layer, it must handle the different possible layer status. + + let plotArea = newPlotArea(); // Needed to be able to plot on the timeline, otherwise not. + let plotAreaFrame = newPlotArea(); // This chart uses this extra object. + + let timePeriod; // This will hold the current Time Period the user is at. + let datetime; // This will hold the current Datetime the user is at. + + let marketFile; // This is the current Market File being plotted. + let fileCursor; // This is the current File Cursor being used to retrieve Daily Files. + + let fileCache; // This object will provide the different Market Files at different Time Periods. + let fileCursorCache; // This object will provide the different File Cursors at different Time Periods. + + /* these are module specific variables: */ + + let volumes = []; // Here we keep the volumes to be ploted every time the Draw() function is called by the AAWebPlatform. + + return thisObject; + + function initialize(pExchange, pMarket, pDatetime, pTimePeriod, pLayerStatus, callBackFunction) { + + let cursorCacheInProgress = false; + let finaleStepsInProgress = false; + + datetime = pDatetime; + timePeriod = pTimePeriod; + + fileCache = newFileCache(); + fileCache.initialize("AAMasters", "AAOlivia", "Market Volumes", "Market Volumes", pExchange, pMarket, onFileReady); + + function onFileReady() { + + let newMarketFile = fileCache.getFile(ONE_DAY_IN_MILISECONDS); + + if (newMarketFile !== undefined) { + + marketFile = newMarketFile; + + initializeFileCursorCache(); + + } + } + + function initializeFileCursorCache() { + + if (cursorCacheInProgress === false) { + + cursorCacheInProgress = true; + + fileCursorCache = newFileCursorCache(); + fileCursorCache.initialize("AAMasters", "AAOlivia", "Daily Volumes", "Daily Volumes", pExchange, pMarket, pDatetime, pTimePeriod, onFileCursorReady); + + } + } + + function onFileCursorReady() { + + recalculate(); + + let newFileCursor = fileCursorCache.getFileCursor(pTimePeriod); + + if (newFileCursor !== undefined) { // if the file ready is the one we need then it and we dont have it yet, then we will continue here. + + let stringDate = datetime.getUTCFullYear() + '-' + pad(datetime.getUTCMonth() + 1, 2) + '-' + pad(datetime.getUTCDate(), 2); + + let dailyFile = newFileCursor.files.get(stringDate); + + if (dailyFile !== undefined) { + + if (finaleStepsInProgress === false) { + + finaleStepsInProgress = true; + + fileCursor = newFileCursor; + + layerStatus = pLayerStatus; + + recalculateScaleX(); + recalculate(); + recalculateScaleY(); + + viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged); + canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished); + + callBackFunction(); + + } + } + } + + } + + } + + function getContainer(point) { + + if (layerStatus !== 'on') { return; } + + let container; + + /* First we check if this point is inside this space. */ + + if (this.container.frame.isThisPointHere(point) === true) { + + return this.container; + + } else { + + /* This point does not belong to this space. */ + + return undefined; + } + + } + + function setTimePeriod(pTimePeriod) { + + timePeriod = pTimePeriod; + + if (timePeriod >= _1_HOUR_IN_MILISECONDS) { + + let newMarketFile = fileCache.getFile(pTimePeriod); + + if (newMarketFile !== undefined) { + + marketFile = newMarketFile; + + recalculate(); + + } + + } else { + + fileCursorCache.setTimePeriod(pTimePeriod); + + fileCursorCache.setDatetime(datetime); + + let newFileCursor = fileCursorCache.getFileCursor(pTimePeriod); + + if (newFileCursor !== undefined) { + + fileCursor = newFileCursor; + + recalculate(); + + } + } + + if (timePeriod === _1_HOUR_IN_MILISECONDS) { + + fileCursorCache.setTimePeriod(pTimePeriod); + + fileCursorCache.setDatetime(datetime); + + } + + } + + function setDatetime(newDatetime) { + + /* If there is a change in the day, then we take some actions, otherwise, we dont. */ + + let currentDate = Math.trunc(datetime.valueOf() / ONE_DAY_IN_MILISECONDS); + let newDate = Math.trunc(newDatetime.valueOf() / ONE_DAY_IN_MILISECONDS); + + datetime = newDatetime; + + if (currentDate !== newDate) { + + if (timePeriod <= _1_HOUR_IN_MILISECONDS) { + + fileCursorCache.setDatetime(newDatetime); + + } + } + } + + function draw() { + + if (layerStatus !== 'on') { return; } + + this.container.frame.draw(); + + if (timePeriod < _1_HOUR_IN_MILISECONDS) { + + if (Math.random() * 1000 > 995) { + + recalculateScaleX(); + recalculate(); + recalculateScaleY(); + + } + } + + plotChart(); + + } + + function recalculate() { + + if (layerStatus === 'off') { return; } + + if (timePeriod >= _1_HOUR_IN_MILISECONDS) { + + recalculateUsingMarketFiles(); + + } else { + + recalculateUsingDailyFiles(); + + } + + thisObject.container.eventHandler.raiseEvent("Volumes Changed", volumes); + } + + function recalculateUsingDailyFiles() { + + if (fileCursor.files.size === 0) { return; } // We need to wait until there are files in the cursor + + let daysOnSides = getSideDays(timePeriod); + + let leftDate = getDateFromPoint(viewPort.visibleArea.topLeft, thisObject.container, plotArea); + let rightDate = getDateFromPoint(viewPort.visibleArea.topRight, thisObject.container, plotArea); + + let dateDiff = rightDate.valueOf() - leftDate.valueOf(); + + let farLeftDate = new Date(leftDate.valueOf() - dateDiff * 1.5); + let farRightDate = new Date(rightDate.valueOf() + dateDiff * 1.5); + + let currentDate = new Date(farLeftDate.valueOf()); + + volumes = []; + + while (currentDate.valueOf() <= farRightDate.valueOf() + ONE_DAY_IN_MILISECONDS) { + + let stringDate = currentDate.getFullYear() + '-' + pad(currentDate.getMonth() + 1, 2) + '-' + pad(currentDate.getDate(), 2); + + let dailyFile = fileCursor.files.get(stringDate); + + if (dailyFile !== undefined) { + + for (let i = 0; i < dailyFile.length; i++) { + + let volume = { + amountBuy: 0, + amountSell: 0, + begin: undefined, + end: undefined + }; + + volume.amountBuy = dailyFile[i][0]; + volume.amountSell = dailyFile[i][1]; + + volume.begin = dailyFile[i][2]; + volume.end = dailyFile[i][3]; + + if (volume.begin >= farLeftDate.valueOf() && volume.end <= farRightDate.valueOf()) { + + volumes.push(volume); + + if (datetime.valueOf() >= volume.begin && datetime.valueOf() <= volume.end) { + + thisObject.container.eventHandler.raiseEvent("Current Candle Changed", thisObject.currentCandle); + + } + } + } + } + + currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS); + } + + /* Lests check if all the visible screen is going to be covered by volumes. */ + + let lowerEnd = leftDate.valueOf(); + let upperEnd = rightDate.valueOf(); + + if (volumes.length > 0) { + + if (volumes[0].begin > lowerEnd || volumes[volumes.length - 1].end < upperEnd) { + + setTimeout(recalculate, 2000); + + //console.log("File missing while calculating volumes, scheduling a recalculation in 2 seconds."); + + } + } + + //console.log("Olivia > recalculateUsingDailyFiles > total volumes generated : " + volumes.length); + + } + + function recalculateUsingMarketFiles() { + + if (marketFile === undefined) { return; } // Initialization not complete yet. + + let daysOnSides = getSideDays(timePeriod); + + let leftDate = getDateFromPoint(viewPort.visibleArea.topLeft, thisObject.container, plotArea); + let rightDate = getDateFromPoint(viewPort.visibleArea.topRight, thisObject.container, plotArea); + + let dateDiff = rightDate.valueOf() - leftDate.valueOf(); + + leftDate = new Date(leftDate.valueOf() - dateDiff * 1.5); + rightDate = new Date(rightDate.valueOf() + dateDiff * 1.5); + + volumes = []; + + for (let i = 0; i < marketFile.length; i++) { + + let volume = { + amountBuy: 0, + amountSell: 0, + begin: undefined, + end: undefined + }; + + volume.amountBuy = marketFile[i][0]; + volume.amountSell = marketFile[i][1]; + + volume.begin = marketFile[i][2]; + volume.end = marketFile[i][3]; + + if (volume.begin >= leftDate.valueOf() && volume.end <= rightDate.valueOf()) { + + volumes.push(volume); + + if (datetime.valueOf() >= volume.begin && datetime.valueOf() <= volume.end) { + + thisObject.container.eventHandler.raiseEvent("Current Volume Changed", thisObject.currentCandle); + + } + } + } + + //console.log("Olivia > recalculateUsingMarketFiles > total volumes generated : " + volumes.length); + } + + function recalculateScaleX() { + + + var minValue = { + x: EARLIEST_DATE.valueOf() + }; + + var maxValue = { + x: MAX_PLOTABLE_DATE.valueOf() + }; + + plotArea.initializeX( + minValue, + maxValue, + thisObject.container.frame.width + ); + + plotAreaFrame.initializeX( + minValue, + maxValue, + thisObject.container.frame.width + ); + + } + + function recalculateScaleY() { + + var minValue = { + y: 0 + }; + + var maxValue = { + y: 0 + }; + + let timePeriodRatio = ONE_DAY_IN_MILISECONDS / timePeriod; + + maxValue.y = getMaxVolume() / (timePeriodRatio / 10); + + plotArea.initializeY( + minValue, + maxValue, + viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topLeft.y + ); + + plotAreaFrame.initializeY( + minValue, + maxValue, + thisObject.container.frame.height + ); + + function getMaxVolume() { + + let maxValue = 0; + + for (var i = 0; i < marketFile.length; i++) { + + let currentMax = (marketFile[i][0] + marketFile[i][1]) * 4; + + if (maxValue < currentMax) { + maxValue = currentMax; + } + } + + return maxValue; + + } + + } + + function plotChart() { + + if (volumes.length > 0) { + + /* Now we calculate and plot the volumes */ + + let visibleHeight = viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topLeft.y; + + let frameCorner1 = { + x: 0, + y: 0 + }; + + let frameCorner2 = { + x: thisObject.container.frame.width, + y: thisObject.container.frame.height + }; + + + /* Now the transformations. */ + + frameCorner1 = transformThisPoint(frameCorner1, thisObject.container.frame.container); + frameCorner2 = transformThisPoint(frameCorner2, thisObject.container.frame.container); + + let frameHeightInViewPort = frameCorner2.y - frameCorner1.y; + + if (volumes.length > 0) { + + for (var i = 0; i < volumes.length; i++) { + + volume = volumes[i]; + + let volumePointA1; + let volumePointA2; + let volumePointA3; + let volumePointA4; + + function calculateBuys(plot, height) { + + volumePointA1 = { + x: volume.begin + timePeriod / 7 * 2, + y: 0 + }; + + volumePointA2 = { + x: volume.begin + timePeriod / 7 * 2, + y: volume.amountBuy + }; + + volumePointA3 = { + x: volume.begin + timePeriod / 7 * 5, + y: volume.amountBuy + }; + + volumePointA4 = { + x: volume.begin + timePeriod / 7 * 5, + y: 0 + }; + + volumePointA1 = plot.inverseTransform(volumePointA1, height); + volumePointA2 = plot.inverseTransform(volumePointA2, height); + volumePointA3 = plot.inverseTransform(volumePointA3, height); + volumePointA4 = plot.inverseTransform(volumePointA4, height); + + volumePointA1 = transformThisPoint(volumePointA1, thisObject.container); + volumePointA2 = transformThisPoint(volumePointA2, thisObject.container); + volumePointA3 = transformThisPoint(volumePointA3, thisObject.container); + volumePointA4 = transformThisPoint(volumePointA4, thisObject.container); + + let baseIncrement = (volumePointA3.x - volumePointA1.x) * WIDHTER_VOLUME_BAR_BASE_FACTOR; + + volumePointA1.x = volumePointA1.x - baseIncrement; + volumePointA4.x = volumePointA4.x + baseIncrement; + + if (volumePointA4.x < viewPort.visibleArea.bottomLeft.x || volumePointA1.x > viewPort.visibleArea.bottomRight.x) { + return false; + } + + return true; + + } + + if (calculateBuys(plotAreaFrame, thisObject.container.frame.height) === false) { continue; } // We try to see if it fits in the visible area. + + if (volumePointA1.y > viewPort.visibleArea.bottomLeft.y && frameHeightInViewPort > visibleHeight * 2 / 3) { + + if (calculateBuys(plotArea, visibleHeight) === false) { continue; } // We snap t to the view port. + + /* Now we set the real value of y. */ + + volumePointA1.y = viewPort.visibleArea.bottomRight.y; + volumePointA2.y = viewPort.visibleArea.bottomRight.y - volume.amountBuy * plotArea.scale.y; + volumePointA3.y = viewPort.visibleArea.bottomRight.y - volume.amountBuy * plotArea.scale.y; + volumePointA4.y = viewPort.visibleArea.bottomRight.y; + + } + + let volumePointB1; + let volumePointB2; + let volumePointB3; + let volumePointB4; + + function calculateSells(plot, height) { + + volumePointB1 = { + x: volume.begin + timePeriod / 7 * 2, + y: height + }; + + volumePointB2 = { + x: volume.begin + timePeriod / 7 * 2, + y: height - volume.amountSell + }; + + volumePointB3 = { + x: volume.begin + timePeriod / 7 * 5, + y: height - volume.amountSell + }; + + volumePointB4 = { + x: volume.begin + timePeriod / 7 * 5, + y: height + }; + + volumePointB1 = plot.inverseTransform2(volumePointB1, height); + volumePointB2 = plot.inverseTransform2(volumePointB2, height); + volumePointB3 = plot.inverseTransform2(volumePointB3, height); + volumePointB4 = plot.inverseTransform2(volumePointB4, height); + + volumePointB1 = transformThisPoint(volumePointB1, thisObject.container); + volumePointB2 = transformThisPoint(volumePointB2, thisObject.container); + volumePointB3 = transformThisPoint(volumePointB3, thisObject.container); + volumePointB4 = transformThisPoint(volumePointB4, thisObject.container); + + } + + calculateSells(plotAreaFrame, thisObject.container.frame.height); // We try to see if it fits in the visible area. + + if (volumePointB1.y < viewPort.visibleArea.topLeft.y && frameHeightInViewPort > visibleHeight * 2 / 3) { + + calculateSells(plotArea, visibleHeight); // We snap it to the view port. + + /* Now we set the real value of y. */ + + volumePointB1.y = viewPort.visibleArea.topLeft.y; + volumePointB2.y = viewPort.visibleArea.topLeft.y + volume.amountSell * plotArea.scale.y; + volumePointB3.y = viewPort.visibleArea.topLeft.y + volume.amountSell * plotArea.scale.y; + volumePointB4.y = viewPort.visibleArea.topLeft.y; + + } + + /* We put a wider base */ + + let baseIncrement = (volumePointB3.x - volumePointB1.x) * WIDHTER_VOLUME_BAR_BASE_FACTOR; + + volumePointB1.x = volumePointB1.x - baseIncrement; + volumePointB4.x = volumePointB4.x + baseIncrement; + + /* We put a less wider top */ + + let baseDencrement = (volumePointA3.x - volumePointA2.x) * LESS_WIDHTER_VOLUME_BAR_TOP_FACTOR; + + volumePointA2.x = volumePointA2.x + baseDencrement; + volumePointA3.x = volumePointA3.x - baseDencrement; + + volumePointB2.x = volumePointB2.x + baseDencrement; + volumePointB3.x = volumePointB3.x - baseDencrement; + + + /* Everything must fit within the visible area */ + + volumePointA1 = viewPort.fitIntoVisibleArea(volumePointA1); + volumePointA2 = viewPort.fitIntoVisibleArea(volumePointA2); + volumePointA3 = viewPort.fitIntoVisibleArea(volumePointA3); + volumePointA4 = viewPort.fitIntoVisibleArea(volumePointA4); + + volumePointB1 = viewPort.fitIntoVisibleArea(volumePointB1); + volumePointB2 = viewPort.fitIntoVisibleArea(volumePointB2); + volumePointB3 = viewPort.fitIntoVisibleArea(volumePointB3); + volumePointB4 = viewPort.fitIntoVisibleArea(volumePointB4); + + /* Everything must fit within the Frame. We know that that is equivalent to say that each bar con not be higher than the base of the opposite . */ + + if (volumePointA2.y < volumePointB1.y) { + + volumePointA2.y = volumePointB1.y; + volumePointA3.y = volumePointB1.y; + + } + + if (volumePointB2.y > volumePointA1.y) { + + volumePointB2.y = volumePointA1.y; + volumePointB3.y = volumePointA1.y; + + } + + /* Now the drawing of the volume bars*/ + + browserCanvasContext.beginPath(); + + browserCanvasContext.moveTo(volumePointA1.x, volumePointA1.y); + browserCanvasContext.lineTo(volumePointA2.x, volumePointA2.y); + browserCanvasContext.lineTo(volumePointA3.x, volumePointA3.y); + browserCanvasContext.lineTo(volumePointA4.x, volumePointA4.y); + + browserCanvasContext.closePath(); + + + if (datetime !== undefined) { + + let dateValue = datetime.valueOf(); + + if (dateValue >= volume.begin && dateValue <= volume.end) { + + browserCanvasContext.fillStyle = 'rgba(255, 233, 31, 0.40)'; // Current bar accroding to time + + } else { + + browserCanvasContext.fillStyle = 'rgba(64, 217, 26, 0.40)'; + } + + } else { + + browserCanvasContext.fillStyle = 'rgba(64, 217, 26, 0.40)'; + + } + + browserCanvasContext.fill(); + browserCanvasContext.strokeStyle = 'rgba(27, 105, 7, 0.40)'; + browserCanvasContext.lineWidth = 1; + browserCanvasContext.stroke(); + + + browserCanvasContext.beginPath(); + + browserCanvasContext.moveTo(volumePointB1.x, volumePointB1.y); + browserCanvasContext.lineTo(volumePointB2.x, volumePointB2.y); + browserCanvasContext.lineTo(volumePointB3.x, volumePointB3.y); + browserCanvasContext.lineTo(volumePointB4.x, volumePointB4.y); + + browserCanvasContext.closePath(); + + if (datetime !== undefined) { + + let dateValue = datetime.valueOf(); + + if (dateValue >= volume.begin && dateValue <= volume.end) { + + browserCanvasContext.fillStyle = 'rgba(255, 233, 31, 0.40)'; // Current candle accroding to time + + } else { + + browserCanvasContext.fillStyle = 'rgba(219, 18, 18, 0.40)'; + } + + } else { + + browserCanvasContext.fillStyle = 'rgba(219, 18, 18, 0.40)'; + + } + + browserCanvasContext.strokeStyle = 'rgba(130, 9, 9, 0.40)'; + + browserCanvasContext.fill(); + browserCanvasContext.lineWidth = 1; + browserCanvasContext.stroke(); + + + + if (datetime !== undefined) { + + let dateValue = datetime.valueOf(); + + if (dateValue >= volume.begin && dateValue <= volume.end) { + + let buyInfo = { + baseWidth: volumePointA4.x - volumePointA1.x, + topWidth: volumePointA3.x - volumePointA2.x, + height: volumePointA2.y - volumePointA1.y + }; + + let sellInfo = { + baseWidth: volumePointB4.x - volumePointB1.x, + topWidth: volumePointB3.x - volumePointB2.x, + height: volumePointB2.y - volumePointB1.y + }; + + let currentVolume = { + buyInfo: buyInfo, + sellInfo: sellInfo, + period: timePeriod, + innerVolumeBar: volume + }; + + thisObject.container.eventHandler.raiseEvent("Current Volume Info Changed", currentVolume); + + } + } + } + } + } + } + + function onLayerStatusChanged(eventData) { + + if (eventData.layer === 'Olivia Volumes') { + layerStatus = eventData.status; + } + + } + + function onZoomChanged(event) { + + recalculateScaleX(); + recalculate(); + recalculateScaleY(); + + } + + function onDragFinished() { + + recalculateScaleX(); + recalculate(); + recalculateScaleY(); + + } +} + diff --git a/History.js b/History.js new file mode 100644 index 000000000..e2b70b21f --- /dev/null +++ b/History.js @@ -0,0 +1,694 @@ +function newAAMastersAAOliviaCandles() { + + let thisObject = { + + // Main functions and properties. + + initialize: initialize, + container: undefined, + getContainer: getContainer, + setTimePeriod: setTimePeriod, + setDatetime: setDatetime, + draw: draw, + + // Secondary functions and properties. + + currentCandle: undefined, + positionAtDatetime: positionAtDatetime, + onLayerStatusChanged: onLayerStatusChanged + }; + + /* this is part of the module template */ + + let container = newContainer(); // Do not touch this 3 lines, they are just needed. + container.initialize(); + thisObject.container = container; + + let layerStatus = 'off'; // Since the moduleis a layer, it must handle the different possible layer status. + + let plotArea = newPlotArea(); // Needed to be able to plot on the timeline, otherwise not. + + let timePeriod; // This will hold the current Time Period the user is at. + let datetime; // This will hold the current Datetime the user is at. + + let marketFile; // This is the current Market File being plotted. + let fileCursor; // This is the current File Cursor being used to retrieve Daily Files. + + let fileCache; // This object will provide the different Market Files at different Time Periods. + let fileCursorCache; // This object will provide the different File Cursors at different Time Periods. + + /* these are module specific variables: */ + + let candles = []; // Here we keep the candles to be ploted every time the Draw() function is called by the AAWebPlatform. + + return thisObject; + + function initialize(pExchange, pMarket, pDatetime, pTimePeriod, pLayerStatus, callBackFunction) { + + let cursorCacheInProgress = false; + let finaleStepsInProgress = false; + + datetime = pDatetime; + timePeriod = pTimePeriod; + + fileCache = newFileCache(); + fileCache.initialize("AAMasters", "AAOlivia", "Market Candles", "Market Candlesticks", pExchange, pMarket, onFileReady); + + function onFileReady() { + + let newMarketFile = fileCache.getFile(ONE_DAY_IN_MILISECONDS); + + if (newMarketFile !== undefined) { + + marketFile = newMarketFile; + + initializeFileCursorCache(); + + } + } + + function initializeFileCursorCache() { + + if (cursorCacheInProgress === false) { + + cursorCacheInProgress = true; + + fileCursorCache = newFileCursorCache(); + fileCursorCache.initialize("AAMasters", "AAOlivia", "Daily Candles", "Daily Candlesticks", pExchange, pMarket, pDatetime, pTimePeriod, onFileCursorReady); + + } + } + + function onFileCursorReady() { + + recalculate(); + + let newFileCursor = fileCursorCache.getFileCursor(pTimePeriod); + + if (newFileCursor !== undefined) { // if the file ready is the one we need then it and we dont have it yet, then we will continue here. + + let stringDate = datetime.getUTCFullYear() + '-' + pad(datetime.getUTCMonth() + 1, 2) + '-' + pad(datetime.getUTCDate(), 2); + + let dailyFile = newFileCursor.files.get(stringDate); + + if (dailyFile !== undefined) { + + if (finaleStepsInProgress === false) { + + finaleStepsInProgress = true; + + fileCursor = newFileCursor; + + recalculateScale(); // With any of the market files we can calculate the scale. + + layerStatus = pLayerStatus; + + recalculate(); + + viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged); + canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished); + + callBackFunction(); + + } + } + } + + } + + } + + function getContainer(point) { + + if (layerStatus !== 'on') { return; } + + let container; + + /* First we check if this point is inside this space. */ + + if (this.container.frame.isThisPointHere(point) === true) { + + return this.container; + + } else { + + /* This point does not belong to this space. */ + + return undefined; + } + + } + + function setTimePeriod(pTimePeriod) { + + timePeriod = pTimePeriod; + + if (timePeriod >= _1_HOUR_IN_MILISECONDS) { + + let newMarketFile = fileCache.getFile(pTimePeriod); + + if (newMarketFile !== undefined) { + + marketFile = newMarketFile; + + recalculate(); + + } + + } else { + + fileCursorCache.setTimePeriod(pTimePeriod); + + fileCursorCache.setDatetime(datetime); + + let newFileCursor = fileCursorCache.getFileCursor(pTimePeriod); + + if (newFileCursor !== undefined) { + + fileCursor = newFileCursor; + + recalculate(); + + } + } + + if (timePeriod === _1_HOUR_IN_MILISECONDS) { + + fileCursorCache.setTimePeriod(pTimePeriod); + + fileCursorCache.setDatetime(datetime); + + } + + } + + function setDatetime(newDatetime) { + + /* If there is a change in the day, then we take some actions, otherwise, we dont. */ + + let currentDate = Math.trunc(datetime.valueOf() / ONE_DAY_IN_MILISECONDS); + let newDate = Math.trunc(newDatetime.valueOf() / ONE_DAY_IN_MILISECONDS); + + datetime = newDatetime; + + if (currentDate !== newDate) { + + if (timePeriod <= _1_HOUR_IN_MILISECONDS) { + + fileCursorCache.setDatetime(newDatetime); + + } + } + } + + function positionAtDatetime(newDatetime) { + + value = newDatetime.valueOf(); + + /* Now we calculate which candle has this new time, because it will give us the y coordinate. */ + + for (let i = 0; i < candles.length; i++) { + + if (value >= candles[i].begin && value <= candles[i].end) { + + let targetPoint = { + x: value, + y: candles[i].open + }; + + targetPoint = plotArea.inverseTransform(targetPoint, thisObject.container.frame.height); + targetPoint = transformThisPoint(targetPoint, thisObject.container); + + let targetMax = { + x: value, + y: candles[i].max + }; + + targetMax = plotArea.inverseTransform(targetMax, thisObject.container.frame.height); + targetMax = transformThisPoint(targetMax, thisObject.container); + + let targetMin = { + x: value, + y: candles[i].min + }; + + targetMin = plotArea.inverseTransform(targetMin, thisObject.container.frame.height); + targetMin = transformThisPoint(targetMin, thisObject.container); + + let center = { + x: (viewPort.visibleArea.bottomRight.x - viewPort.visibleArea.bottomLeft.x) / 2, + y: (viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topRight.y) / 2 + }; + + if (targetMax.y < viewPort.visibleArea.topLeft.y || targetMin.y > viewPort.visibleArea.bottomRight.y) { + + let displaceVector = { + x: 0, + y: center.y - targetPoint.y + }; + + viewPort.displaceTarget(displaceVector); + + } + + let displaceVector = { + x: center.x - targetPoint.x, + y: 0 + }; + + viewPort.displace(displaceVector); + + return; + } + } + } + + function draw() { + + if (layerStatus !== 'on') { return; } + + this.container.frame.draw(); + + if (timePeriod < _1_HOUR_IN_MILISECONDS) { + + if (Math.random() * 1000 > 995) { + + recalculate(); + + } + } + + plotChart(); + + } + + function recalculate() { + + if (layerStatus === 'off') { return; } + + if (timePeriod >= _1_HOUR_IN_MILISECONDS) { + + recalculateUsingMarketFiles(); + + } else { + + recalculateUsingDailyFiles(); + + } + + thisObject.container.eventHandler.raiseEvent("Candles Changed", candles); + } + + function recalculateUsingDailyFiles() { + + if (fileCursor.files.size === 0) { return;} // We need to wait until there are files in the cursor + + let daysOnSides = getSideDays(timePeriod); + + let leftDate = getDateFromPoint(viewPort.visibleArea.topLeft, thisObject.container, plotArea); + let rightDate = getDateFromPoint(viewPort.visibleArea.topRight, thisObject.container, plotArea); + + let dateDiff = rightDate.valueOf() - leftDate.valueOf(); + + let farLeftDate = new Date(leftDate.valueOf() - dateDiff * 1.5); + let farRightDate = new Date(rightDate.valueOf() + dateDiff * 1.5); + + let currentDate = new Date(farLeftDate.valueOf()); + + candles = []; + + while (currentDate.valueOf() <= farRightDate.valueOf() + ONE_DAY_IN_MILISECONDS) { + + let stringDate = currentDate.getFullYear() + '-' + pad(currentDate.getMonth() + 1, 2) + '-' + pad(currentDate.getDate(), 2); + + let dailyFile = fileCursor.files.get(stringDate); + + if (dailyFile !== undefined) { + + for (let i = 0; i < dailyFile.length; i++) { + + let candle = { + open: undefined, + close: undefined, + min: 10000000000000, + max: 0, + begin: undefined, + end: undefined, + direction: undefined + }; + + candle.min = dailyFile[i][0]; + candle.max = dailyFile[i][1]; + + candle.open = dailyFile[i][2]; + candle.close = dailyFile[i][3]; + + candle.begin = dailyFile[i][4]; + candle.end = dailyFile[i][5]; + + if (candle.open > candle.close) { candle.direction = 'down'; } + if (candle.open < candle.close) { candle.direction = 'up'; } + if (candle.open === candle.close) { candle.direction = 'side'; } + + if (candle.begin >= farLeftDate.valueOf() && candle.end <= farRightDate.valueOf()) { + + candles.push(candle); + + if (datetime.valueOf() >= candle.begin && datetime.valueOf() <= candle.end) { + + thisObject.currentCandle = candle; + thisObject.container.eventHandler.raiseEvent("Current Candle Changed", thisObject.currentCandle); + + } + } + } + } + + currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS); + } + + /* Lests check if all the visible screen is going to be covered by candles. */ + + let lowerEnd = leftDate.valueOf(); + let upperEnd = rightDate.valueOf(); + + if (candles.length > 0) { + + if (candles[0].begin > lowerEnd || candles[candles.length - 1].end < upperEnd) { + + setTimeout(recalculate, 2000); + + //console.log("File missing while calculating candles, scheduling a recalculation in 2 seconds."); + + } + } + + //console.log("Olivia > recalculateUsingDailyFiles > total candles generated : " + candles.length); + + } + + function recalculateUsingMarketFiles() { + + if (marketFile === undefined) { return; } // Initialization not complete yet. + + let daysOnSides = getSideDays(timePeriod); + + let leftDate = getDateFromPoint(viewPort.visibleArea.topLeft, thisObject.container, plotArea); + let rightDate = getDateFromPoint(viewPort.visibleArea.topRight, thisObject.container, plotArea); + + let dateDiff = rightDate.valueOf() - leftDate.valueOf(); + + leftDate = new Date(leftDate.valueOf() - dateDiff * 1.5); + rightDate = new Date(rightDate.valueOf() + dateDiff * 1.5); + + candles = []; + + for (let i = 0; i < marketFile.length; i++) { + + let candle = { + open: undefined, + close: undefined, + min: 10000000000000, + max: 0, + begin: undefined, + end: undefined, + direction: undefined + }; + + candle.min = marketFile[i][0]; + candle.max = marketFile[i][1]; + + candle.open = marketFile[i][2]; + candle.close = marketFile[i][3]; + + candle.begin = marketFile[i][4]; + candle.end = marketFile[i][5]; + + if (candle.open > candle.close) { candle.direction = 'down'; } + if (candle.open < candle.close) { candle.direction = 'up'; } + if (candle.open === candle.close) { candle.direction = 'side'; } + + if (candle.begin >= leftDate.valueOf() && candle.end <= rightDate.valueOf()) { + + candles.push(candle); + + if (datetime.valueOf() >= candle.begin && datetime.valueOf() <= candle.end) { + + thisObject.currentCandle = candle; + thisObject.container.eventHandler.raiseEvent("Current Candle Changed", thisObject.currentCandle); + + } + } + } + + //console.log("Olivia > recalculateUsingMarketFiles > total candles generated : " + candles.length); + } + + function recalculateScale() { + + if (marketFile === undefined) { return; } // We need the market file to be loaded to make the calculation. + + if (plotArea.maxValue > 0) { return; } // Already calculated. + + let minValue = { + x: EARLIEST_DATE.valueOf(), + y: 0 + }; + + let maxValue = { + x: MAX_PLOTABLE_DATE.valueOf(), + y: nextPorwerOf10(getMaxRate()) + }; + + + plotArea.initialize( + minValue, + maxValue, + thisObject.container.frame.width, + thisObject.container.frame.height + ); + + function getMaxRate() { + + let maxValue = 0; + + for (let i = 0; i < marketFile.length; i++) { + + let currentMax = marketFile[i][1]; // 1 = rates. + + if (maxValue < currentMax) { + maxValue = currentMax; + } + } + + return maxValue; + + } + + } + + function plotChart() { + + if (candles.length > 0) { + + /* Now we calculate and plot the candles */ + + for (let i = 0; i < candles.length; i++) { + + candle = candles[i]; + + let candlePoint1 = { + x: candle.begin + timePeriod / 7 * 1.5, + y: candle.open + }; + + let candlePoint2 = { + x: candle.begin + timePeriod / 7 * 5.5, + y: candle.open + }; + + let candlePoint3 = { + x: candle.begin + timePeriod / 7 * 5.5, + y: candle.close + }; + + let candlePoint4 = { + x: candle.begin + timePeriod / 7 * 1.5, + y: candle.close + }; + + candlePoint1 = plotArea.inverseTransform(candlePoint1, thisObject.container.frame.height); + candlePoint2 = plotArea.inverseTransform(candlePoint2, thisObject.container.frame.height); + candlePoint3 = plotArea.inverseTransform(candlePoint3, thisObject.container.frame.height); + candlePoint4 = plotArea.inverseTransform(candlePoint4, thisObject.container.frame.height); + + candlePoint1 = transformThisPoint(candlePoint1, thisObject.container); + candlePoint2 = transformThisPoint(candlePoint2, thisObject.container); + candlePoint3 = transformThisPoint(candlePoint3, thisObject.container); + candlePoint4 = transformThisPoint(candlePoint4, thisObject.container); + + if (candlePoint2.x < viewPort.visibleArea.bottomLeft.x || candlePoint1.x > viewPort.visibleArea.bottomRight.x) { + continue; + } + + candlePoint1 = viewPort.fitIntoVisibleArea(candlePoint1); + candlePoint2 = viewPort.fitIntoVisibleArea(candlePoint2); + candlePoint3 = viewPort.fitIntoVisibleArea(candlePoint3); + candlePoint4 = viewPort.fitIntoVisibleArea(candlePoint4); + + let stickPoint1 = { + x: candle.begin + timePeriod / 7 * 3.2, + y: candle.max + }; + + let stickPoint2 = { + x: candle.begin + timePeriod / 7 * 3.8, + y: candle.max + }; + + let stickPoint3 = { + x: candle.begin + timePeriod / 7 * 3.8, + y: candle.min + }; + + let stickPoint4 = { + x: candle.begin + timePeriod / 7 * 3.2, + y: candle.min + }; + + stickPoint1 = plotArea.inverseTransform(stickPoint1, thisObject.container.frame.height); + stickPoint2 = plotArea.inverseTransform(stickPoint2, thisObject.container.frame.height); + stickPoint3 = plotArea.inverseTransform(stickPoint3, thisObject.container.frame.height); + stickPoint4 = plotArea.inverseTransform(stickPoint4, thisObject.container.frame.height); + + stickPoint1 = transformThisPoint(stickPoint1, thisObject.container); + stickPoint2 = transformThisPoint(stickPoint2, thisObject.container); + stickPoint3 = transformThisPoint(stickPoint3, thisObject.container); + stickPoint4 = transformThisPoint(stickPoint4, thisObject.container); + + stickPoint1 = viewPort.fitIntoVisibleArea(stickPoint1); + stickPoint2 = viewPort.fitIntoVisibleArea(stickPoint2); + stickPoint3 = viewPort.fitIntoVisibleArea(stickPoint3); + stickPoint4 = viewPort.fitIntoVisibleArea(stickPoint4); + + browserCanvasContext.beginPath(); + + browserCanvasContext.moveTo(stickPoint1.x, stickPoint1.y); + browserCanvasContext.lineTo(stickPoint2.x, stickPoint2.y); + browserCanvasContext.lineTo(stickPoint3.x, stickPoint3.y); + browserCanvasContext.lineTo(stickPoint4.x, stickPoint4.y); + + browserCanvasContext.closePath(); + browserCanvasContext.fillStyle = 'rgba(54, 54, 54, 1)'; + browserCanvasContext.fill(); + + if (datetime !== undefined) { + + let dateValue = datetime.valueOf(); + + if (dateValue >= candle.begin && dateValue <= candle.end) { + + browserCanvasContext.strokeStyle = 'rgba(255, 233, 31, 1)'; // Current candle accroding to time + + } else { + browserCanvasContext.strokeStyle = 'rgba(212, 206, 201, 1)'; + } + + } else { + browserCanvasContext.strokeStyle = 'rgba(212, 206, 201, 1)'; + } + + browserCanvasContext.lineWidth = 1; + browserCanvasContext.stroke(); + + browserCanvasContext.beginPath(); + + browserCanvasContext.moveTo(candlePoint1.x, candlePoint1.y); + browserCanvasContext.lineTo(candlePoint2.x, candlePoint2.y); + browserCanvasContext.lineTo(candlePoint3.x, candlePoint3.y); + browserCanvasContext.lineTo(candlePoint4.x, candlePoint4.y); + + browserCanvasContext.closePath(); + + if (candle.direction === 'up') { browserCanvasContext.strokeStyle = 'rgba(27, 105, 7, 1)'; } + if (candle.direction === 'down') { browserCanvasContext.strokeStyle = 'rgba(130, 9, 9, 1)'; } + if (candle.direction === 'side') { browserCanvasContext.strokeStyle = 'rgba(27, 7, 105, 1)'; } + + if (datetime !== undefined) { + + let dateValue = datetime.valueOf(); + + if (dateValue >= candle.begin && dateValue <= candle.end) { + + /* highlight the current candle */ + + browserCanvasContext.fillStyle = 'rgba(255, 233, 31, 1)'; // Current candle accroding to time + + let currentCandle = { + bodyWidth: candlePoint2.x - candlePoint1.x, + bodyHeight: candlePoint3.y - candlePoint2.y, + stickHeight: stickPoint4.y - stickPoint2.y, + stickWidth: stickPoint2.x - stickPoint1.x, + stickStart: candlePoint2.y - stickPoint2.y, + period: timePeriod, + innerCandle: candle + }; + + thisObject.container.eventHandler.raiseEvent("Current Candle Info Changed", currentCandle); + + } else { + + if (candle.direction === 'up') { browserCanvasContext.fillStyle = 'rgba(64, 217, 26, 1)'; } + if (candle.direction === 'down') { browserCanvasContext.fillStyle = 'rgba(219, 18, 18, 1)'; } + if (candle.direction === 'side') { browserCanvasContext.fillStyle = 'rgba(64, 26, 217, 1)'; } + } + + } else { + + if (candle.direction === 'up') { browserCanvasContext.fillStyle = 'rgba(64, 217, 26, 1)'; } + if (candle.direction === 'down') { browserCanvasContext.fillStyle = 'rgba(219, 18, 18, 1)'; } + if (candle.direction === 'side') { browserCanvasContext.fillStyle = 'rgba(64, 26, 217, 1)'; } + + } + + + + if ( + candlePoint1.x < viewPort.visibleArea.topLeft.x + 50 + || + candlePoint1.x > viewPort.visibleArea.bottomRight.x - 50 + ) { + // we leave this candles without fill. + } else { + browserCanvasContext.fill(); + } + + browserCanvasContext.lineWidth = 1; + browserCanvasContext.stroke(); + + + } + } + } + + function onLayerStatusChanged(eventData) { + + if (eventData.layer === 'Olivia Candlesticks') { + layerStatus = eventData.status; + } + + } + + function onZoomChanged(event) { + + recalculate(); + + } + + function onDragFinished() { + + recalculate(); + + } +} + diff --git a/README.md b/README.md new file mode 100644 index 000000000..1fec2f25c --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# AAMariam-Plotter diff --git a/bin/Microsoft.NodejsTools.WebRole.dll b/bin/Microsoft.NodejsTools.WebRole.dll new file mode 100644 index 0000000000000000000000000000000000000000..03b93f4a1c5dfb1659630bf8ea0ad76d2a599ed4 GIT binary patch literal 32992 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 literal 0 HcmV?d00001 diff --git a/obj/Debug/AAOlivia-Plotter.njsproj.CoreCompileInputs.cache b/obj/Debug/AAOlivia-Plotter.njsproj.CoreCompileInputs.cache new file mode 100644 index 000000000..78474ee71 --- /dev/null +++ b/obj/Debug/AAOlivia-Plotter.njsproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +573924208ee1de43c28a684e3ad9af2dcef5974d diff --git a/obj/Debug/AAOlivia-Plotter.njsproj.FileListAbsolute.txt b/obj/Debug/AAOlivia-Plotter.njsproj.FileListAbsolute.txt new file mode 100644 index 000000000..4c3907976 --- /dev/null +++ b/obj/Debug/AAOlivia-Plotter.njsproj.FileListAbsolute.txt @@ -0,0 +1,3 @@ +C:\Users\Luis\source\repos\AAOlivia-Plotter\obj\Debug\AAOlivia-Plotter.njsprojResolveAssemblyReference.cache +C:\Users\Luis\source\repos\AAOlivia-Plotter\obj\Debug\AAOlivia-Plotter.njsproj.CoreCompileInputs.cache +C:\Users\Luis\source\repos\AAOlivia-Plotter\bin\Microsoft.NodejsTools.WebRole.dll diff --git a/obj/Debug/AAOlivia-Plotter.njsprojResolveAssemblyReference.cache b/obj/Debug/AAOlivia-Plotter.njsprojResolveAssemblyReference.cache new file mode 100644 index 0000000000000000000000000000000000000000..67d5be9b7a12b38e6fe524eedeba2ea6a1a31246 GIT binary patch literal 2216 zcmb_d+iu%N5T)*RdTpA)&tW2&Cd7K4^8EmeX{a^_^}K>O{gp42hO3tnZvAqmX;w!0b$% zLwqo5wu4Tv8?;(}r^(u^M8-b7-o{|2G(-cA|0w}SaS=4l}-Sv+P}L{la~Zj;ik@ZnU73+{t7>BoTo2t|xY zl^?M%0c9A4f>A1MnAh3r&vo6t#^?SO{ja{i_ay~et&;Orkwgi_HqB_ETt;!w-5);g zpM3S*tN7z& z1%zec5=J+x+udE(@j9Qk_S$!$d2g>ow%*8Fg005XY9uC811)(xwz(ScXc_`RaeKlP z)|&@P33({J3D;QT*i`+vmr&fa$>LFzq~&f)h}d)reou<1Kxr+0lEwNEf~-B(0L2ySaRO}Wl?GcxSQfv{Ynk^4-6>1GX3bE*3e!?BQDPoj_3KYK!UMXaR= zKXkE3L_8*Q$U3Kt%Ug3DDYmgjSoijga%qms{?wJh_Q7o9~R z!~q{Ck`bHE%LQ9_KAo*O`*x>3yIPl5Li^&T{$&2IA#ja>)qYFi$(J`Vdm9Tg6092K z{U;RVEfhy|&+IoEjqZLUBiY8XvXNvP3zBUtS*Ed~kVw|rMpebX@H%}vtf-MI7j(b4 zu3;8`M#g@P%19xuV441jvv&e(-9kznuTbYrFkC