diff --git a/lib/ChartDataProcessor.js b/lib/ChartDataProcessor.js index 8e0109b..972f867 100644 --- a/lib/ChartDataProcessor.js +++ b/lib/ChartDataProcessor.js @@ -6,6 +6,9 @@ const {Cu} = require("chrome"); Cu.import("resource://gre/modules/Services.jsm"); +function ChartDataProcessor() { +} + function TimelineDataProcessor() { } @@ -56,6 +59,128 @@ DataProcessorHelper = { }, } +ChartDataProcessor.prototype = { + _arraySum: function(arr) { + sum = 0; + for (element in arr) { + sum += parseInt(arr[element]); + } + return sum; + }, + + _daysPostEpochToDate: function(dayCount) { + return parseInt(dayCount) * 24 * 60 * 60 * 1000; + }, + + _setMaxWeightAndDateCount: function(storedData, interest, newDayWeight, date) { + if (!storedData["interests"][interest]["maxWeight"] || + newDayWeight > storedData["interests"][interest]["maxWeight"]) { + storedData["interests"][interest]["maxWeight"] = newDayWeight; + storedData["interests"][interest]["maxWeightDate"] = date; + } + storedData["interests"][interest]["dayCount"] = + Object.keys(storedData["interests"][interest]["dates"]).length; + }, + + _setXYMaxMin: function(storedData) { + let categories = Object.keys(storedData["interests"]); + let xVals = categories.map((category) => { + return storedData["interests"][category]["x"]; + }); + storedData["xMax"] = Math.max.apply(null, xVals); + storedData["xMin"] = Math.min.apply(null, xVals); + + let yVals = categories.map((category) => { + return storedData["interests"][category]["y"]; + }); + storedData["yMax"] = Math.max.apply(null, yVals); + storedData["yMin"] = Math.min.apply(null, yVals); + }, + + _cartesianDistance: function(x1, y1, x2, y2) { + return Math.sqrt(Math.pow(y1 - y2, 2) + Math.pow((x1 - x2), 2)); + }, + + consume: function(bucketData) { + DataProcessorHelper.initChartInStorage("genericChartData"); + // STEP 1 + for (let day in bucketData) { + DataProcessorHelper.iterateOverTypeNamespace(bucketData[day], storage.chartData.genericChartData, (bucketData, storedData) => { + if (!storedData["interests"]) { + storedData["interests"] = {}; + } + for (let interest in bucketData) { + if (!storedData["interests"][interest]) { + storedData["interests"][interest] = {}; + storedData["interests"][interest]["dates"] = {}; + } + let domainsToCountMap = bucketData[interest]; + let visitCountSum = this._arraySum(domainsToCountMap); + storedData["interests"][interest]["dates"][day] = + {x: this._daysPostEpochToDate(day), size: visitCountSum, domainList: domainsToCountMap}; + this._setMaxWeightAndDateCount(storedData, interest, visitCountSum, day); + } + }); + } + + let currentData = storage.chartData.genericChartData; + DataProcessorHelper.iterateOverTypeNamespace(currentData, currentData, (bucketData, storedData) => { + // STEP 2 + // Sort interests by maxWeight and dayCount. + let sortedByWeights = []; + let sortedByDayCount = []; + DataProcessorHelper.interestsToArray(storedData["interests"], sortedByWeights); + DataProcessorHelper.interestsToArray(storedData["interests"], sortedByDayCount); + sortedByWeights.sort(DataProcessorHelper.propertyComparator("maxWeight")); + sortedByDayCount.sort(DataProcessorHelper.propertyComparator("dayCount")); + + // Rank interests. + let rankMaxWeight = 1; + let rankDayCount = 1; + for (let i = 0; i < sortedByWeights.length; i++) { + if (i > 0 && (sortedByWeights[i - 1]["maxWeight"] != sortedByWeights[i]["maxWeight"])) { + rankMaxWeight++; + } + if (i > 0 && (sortedByDayCount[i - 1]["dayCount"] != sortedByDayCount[i]["dayCount"])) { + rankDayCount++; + } + + storedData["interests"][sortedByDayCount[i]["category"]]["x"] = rankDayCount; + storedData["interests"][sortedByWeights[i]["category"]]["y"] = rankMaxWeight; + storedData["interests"][sortedByWeights[i]["category"]]["maxWeightDate"] = sortedByWeights[i]["maxWeightDate"]; + } + this._setXYMaxMin(storedData); + + // STEP 3 + let intentX = storedData["xMin"]; + let intentY = storedData["yMax"]; + let interestX = storedData["xMax"]; + let interestY = storedData["yMax"]; + + let sortedInterests = []; + let sortedIntents = []; + for (let category in bucketData["interests"]) { + let categoryX = storedData["interests"][category]["x"]; + let categoryY = storedData["interests"][category]["y"]; + + storedData["interests"][category]["intentDist"] = + this._cartesianDistance(intentX, intentY, categoryX, categoryY); + storedData["interests"][category]["interestDist"] = + this._cartesianDistance(interestX, interestY, categoryX, categoryY); + } + DataProcessorHelper.interestsToArray(storedData["interests"], sortedInterests); + DataProcessorHelper.interestsToArray(storedData["interests"], sortedIntents); + sortedInterests.sort(DataProcessorHelper.propertyComparator("interestDist")); + sortedIntents.sort(DataProcessorHelper.propertyComparator("intentDist")); + + delete storedData["interests"]; + storedData["sortedIntents"] = sortedIntents; + storedData["sortedInterests"] = sortedInterests; + }); + return storage.chartData.genericChartData; + } +} + TimelineDataProcessor.prototype = { _arraySum: function(arr) { sum = 0; @@ -212,6 +337,7 @@ IntentInterestDataProcessor.prototype = { }, } +exports.ChartDataProcessor = ChartDataProcessor; exports.TimelineDataProcessor = TimelineDataProcessor; exports.WeightIntensityDataProcessor = WeightIntensityDataProcessor; exports.IntentInterestDataProcessor = IntentInterestDataProcessor; diff --git a/lib/Controller.js b/lib/Controller.js index 106eb59..c3d23ed 100644 --- a/lib/Controller.js +++ b/lib/Controller.js @@ -17,6 +17,7 @@ const {WorkerFactory} = require("WorkerFactory"); const {Pipeline} = require("Pipeline"); const {DayCountRanker} = require("DayCountRanker"); const {HostnameStripper} = require("HostnameStripper"); +const {ChartDataProcessor} = require("ChartDataProcessor"); const {TimelineDataProcessor} = require("ChartDataProcessor"); const {WeightIntensityDataProcessor} = require("ChartDataProcessor"); const {IntentInterestDataProcessor} = require("ChartDataProcessor"); @@ -47,6 +48,7 @@ function Controller(options={}) { this._workers = this._workerFactory.getCurrentWorkers(); this._rankers = this._makeRankers(); this._hostStripper = new HostnameStripper(); + this._chartDataProcessor = new ChartDataProcessor(); this._timelineDataProcessor = new TimelineDataProcessor(); this._weightIntensityDataProcessor = new WeightIntensityDataProcessor(); this._intentInterestDataProcessor = new IntentInterestDataProcessor(); @@ -56,7 +58,8 @@ function Controller(options={}) { }); this._urlClassifier = new UrlClassifier(this._workers); - this._dayBuffer = new DayBuffer(new Pipeline(this._rankers, + this._dayBuffer = new DayBuffer(new Pipeline( + this._rankers, this._chartDataProcessor, this._timelineDataProcessor, this._weightIntensityDataProcessor, this._intentInterestDataProcessor, this._dispatcher)); this._processingHistory = false;