<commit_before>define('app/controllers/monitoring', [
    'ember'
    ],
    /**
     * Monitoring Controller
     *
     * @returns Class
     */
    function() {
        return Ember.ObjectController.extend(Ember.Evented,{

            /**
             *
             * Gets all monitoring related data from
             * the server
             */
             load: function(callback) {

                 if (!Mist.authenticated) {
                    Mist.backendsController.set('checkedMonitoring', true);
                    return;
                 }

                 var that = this;
                 this.checkingMonitoring = true;
                 Mist.ajax.GET('/monitoring', {
                 }).success(function(data) {
                     that._updateMonitoringData(data);
                 }).error(function() {
                     Mist.notificationController.notify('Failed to get monitoring data');
                 }).complete(function(success, data) {
                     that.checkingMonitoring = false;
                     Mist.backendsController.set('checkedMonitoring', true);
                     that.trigger('onMonitoringDataUpdate');
                     if (callback) callback(success, data);
                 });
             }.on('init'),


            changeMonitoring: function(machine, callback) {
                 var that = this;
                 //this.set('changingMonitoring', true);
                 if (machine.hasMonitoring) {
                     machine.set('disablingMonitoring', true);
                 } else {
                     machine.set('enablingMonitoring', true);
                 }
                 Mist.ajax.POST('/backends/' + machine.backend.id + '/machines/' + machine.id + '/monitoring', {
                    'action': machine.hasMonitoring ? 'disable' : 'enable',
                    'dns_name': machine.extra.dns_name ? machine.extra.dns_name : 'n/a',
                    'public_ips': machine.public_ips ? machine.public_ips : [],
                    'name': machine.name ? machine.name : machine.id
                 }).success(function(data) {
                     if (!machine.hasMonitoring) {
                         machine.set('hasMonitoring', true);
                         machine.set('enablingMonitoring', false);
                     } else {
                         machine.set('hasMonitoring', false);
                         // Remove machine from monitored_machines
                         Mist.monitored_machines.some(function(machine_tupple) {
                            if (machine_tupple[1] == machine.id && machine_tupple[0] == machine.backend.id) {
                                Mist.monitored_machines.removeObject(machine_tupple);
                            }
                         });
                         machine.set('disablingMonitoring', false);
                     }
                     Mist.set('authenticated', true);
                 }).error(function() {
                     if (machine.hasMonitoring) {
                         machine.set('disablingMonitoring', false);
                     } else {
                         machine.set('enablingMonitoring', false);
                     }
                     Mist.notificationController.notify('Error when changing monitoring to ' + machine.name);
                 }).complete(function(success, data) {
                     //that.set('changingMonitoring', false);
                     if (callback) callback(success, data);
                 });
             },


             /**
             *
             * Updates everything in the app that has
             * to do with monitoring
             */
             _updateMonitoringData: function(data) {

                 Mist.set('monitored_machines', data.machines);
                 Mist.set('current_plan', data.current_plan);
                 Mist.rulesController.setContent(data.rules);
                 data.machines.forEach(function(machine_tuple) {
                     var machine = Mist.backendsController.getMachine(machine_tuple[1], machine_tuple[0]);
                     if (machine)
                         machine.set('hasMonitoring', true);
                 });
                 Mist.backendsController.content.forEach(function(backend) {
                    backend.machines._updateMonitoredMachines();
                 });
             },


            /*
            *
            * Initalizes Request,Graphs,History objects
            * Loads cookies and hides collapsed graphs
            * @param {object} arguments - machine,timeWindow,step,updateInterval,updatesEnabled,timeGap,callback
            */
            initialize: function(arguments){

                var self = this;

                // Reset all controller values
                this.reset();

                // Get graphs from view
                this.graphs.instances = arguments['graphs'];

                // Get cookies and show graphs that are not collapsed
                var collapsedMetrics = this.cookies.getCollapsedMetrics();

                if(collapsedMetrics != null) {
                    this.graphs.collapse(collapsedMetrics,0);
                } else{

                    // Hide graphs
                    var metrics     = this.graphs.instances;
                    var metricsKeys = [];

                    for(var key in metrics){

                        if(key == 'load') continue;
                        metricsKeys.push(key);
                    }

                    this.graphs.collapse(metricsKeys,0);
                }

                // Create and Start the request
                this.request.create({
                    machine         : arguments['machineModel'], // Send Current Machine
                    timeWindow      : 10*60*1000,                // Display 10 Minutes
                    step            : 10000,                     // Metrics Step in miliseconds
                    updateInterval  : 10000,                     // Get Updates Every x Miliseconds
                    updatesEnabled  : true,                      // Get Updates
                    timeGap         : 60,                        // Gap between current time and requested
                    callback        : function(result){
                        if(result['status'] == 'success'){
                            //console.log("%cNumber Of Data Received: " + result['data']['cpu'].length, "color:orange;background-color:black; padding: 0 15px;");
                            self.graphs.updateData(result['data']);
                        }
                    }
                });

                this.request.start();

            },


            /**
            *
            *   Resets all controller instances to the default state
            *
            */
            reset: function(){

                this.request.reset();
                this.history.reset();
                this.graphs.reset();
                this.zoom.reset();
            },


            /**
            *
            *   This object is responsible for data requests
            *
            */
            request: {


                /**
                *   Creates the request. use start() to start the request
                *   @param {number}  timeWindow     - The time window in miliseconds
                *   @param {number}  step           - Step of measurements
                *   @param {number}  updateinterval - Update every updateInterval miliseconds
                *   @param {boolean} enableUpdates  - Enable/Disable updates
                */
                create : function(arguments){

                    this.reset();

                    var self             = this;
                    var controller       = Mist.monitoringController;

                    this.step            = arguments['step'];
                    this.timeWindow      = arguments['timeWindow'];
                    this.updateInterval  = arguments['updateInterval'];
                    this.machine         = arguments['machine'];
                    this.updateData      = arguments['updatesEnabled'];
                    this.step            = arguments['step'];
                    this.callback        = ('callback' in arguments) ? arguments['callback'] : null;
                    this.timeGap         = arguments['timeGap']; // Temporary Fix , Give some time to server to collect data

                    // Calculate Start And Stop
                    this.timeStop        = Math.floor( ( (new Date()).getTime() - this.timeGap * 1000) / 1000 );
                    this.timeStart       = Math.floor(this.timeStop - this.timeWindow/1000);
                    this.lastMetrictime  = new Date(this.timeStart*1000);
                },


                /**
                *
                *   Starts the request. User create() first
                *
                */
                start : function(){

                    var self = this;

                    this.locked = true;

                    // If request stopped Re-calculate start and stop
                    if(this.initialized && !this.running){

                        this.timeStart = Math.floor( this.lastMetrictime.getTime() /1000 ) ;
                        this.timeStop  =  Math.floor( ((new Date()).getTime() - this.timeGap * 1000 ) / 1000 );

                        // Fix time when lossing precision
                        var stopRemainder = (this.timeStop - this.timeStart) % (this.step/1000);
                        this.timeStop     = this.timeStop - stopRemainder;
                    } else {

                        this.initialized = true;
                    }

                    // Show Fetching Message On Initial Request
                    this.machine.set('pendingStats', true);

                    // Do the ajax call
                    this.requestID++;
                    this.receiveData(this.timeStart, this.timeStop, this.step,this.callback);


                    // Check if Data Updates Are Enabled
                    if(this.updateData && !this.running){
                        window.monitoringInterval = window.setInterval(function() {

                            // Lock request so no other request can be done in the same time
                            self.locked = true;

                            // Calculate Start and Stop
                            self.timeStart = Math.floor( self.lastMetrictime.getTime() /1000 ) ;
                            self.timeStop  =  Math.floor( ((new Date()).getTime() - self.timeGap * 1000 ) / 1000 );

                            // Fix time when lossing precision
                            var stopRemainder = (self.timeStop - self.timeStart) % (self.step/1000);
                            self.timeStop     = self.timeStop - stopRemainder;

                            // Do the ajax call
                            this.requestID++;
                            self.receiveData(self.timeStart, self.timeStop, self.step,self.callback);

                        },this.step);
                    }

                    this.running = true;

                    return this.requestID;
                },


                /**
                *
                *   Stops current request
                *
                */
                stop : function(){

                    this.running = false;
                    window.clearInterval(window.monitoringInterval);
                },


                /**
                *
                *   Reloads current request.
                *   @param {string} reason - Reason for reloading (default: manualReload)
                */
                reload: function(reason){

                    var self = this;

                    var reload = function(){

                        // wait until previous action (request) finishes
                        if(self.locked){
                            window.setTimeout(reload,1000);
                        }
                        else{

                           // Stop Current Request
                           self.stop();

                           reason = (typeof reason == 'undefined' ? 'manualReload' : reason);

                           // Temporary Fix For Some Functions TODO change this
                           if(reason == 'updatesDisabled')
                                Mist.monitoringController.graphs.disableAnimation(false);
                           if(reason == 'updatesEnabled')
                                Mist.monitoringController.graphs.enableAnimation();

                            Mist.monitoringController.graphs.clearData();
                            // End Of Fix

                           // Re-Initialize and start request
                           self.create({
                                machine         : self.machine,
                                timeWindow      : self.timeWindow,
                                step            : self.step,
                                updateInterval  : self.updateInterval,
                                updatesEnabled  : self.updateData,
                                timeGap         : self.timeGap,
                                callback        : self.callback
                           });

                           return self.start();
                        }

                    };

                    return reload();
                },


                /**
                *
                *   Runs a custm request without destroying the previous
                *   @param {object} options - Stop,Step,Timewindow
                */
                custom : function(options){

                    // Clear Intervals
                    this.stopDataUpdates();

                    // Wait Until Requests are not locked
                    var self   = this;
                    var custom = function(){

                        // wait until previous action (request) finishes
                        if(self.locked){
                            window.setTimeout(custom,1000);
                        }
                        else{
                            //var timeGap          = 60;
                            var timeWindow  = self.timeWindow;
                            var step        = self.step;
                            var stop        = Math.floor( ( new Date()).getTime() / 1000 ); //Math.floor( ( (new Date()).getTime() - timeGap * 1000) / 1000 );
                            var start       = Math.floor( stop - timeWindow/1000 );
                            var callback    = null;

                            if(options){
                                if ('stop' in options){
                                    stop  = Math.floor(options['stop']);//Math.floor(options['stop'] - timeGap);
                                    start = Math.floor( stop - timeWindow/1000 );
                                }

                                if ('step' in options)
                                    step = options['step'];

                                if ('timeWindow' in options)
                                    timeWindowSize = options['timeWindow']; // TODO Check this size ?

                                if('callback' in options)
                                    callback = options['callback'];
                            }

                            self.locked = true;
                            self.machine.set('pendingStats', true);

                            Mist.monitoringController.graphs.disableAnimation();
                            self.receiveData(start, stop, step,callback);
                        }
                    }

                    custom();

                },


                /**
                *
                *   Resets the custom request and gets back to the original
                *
                */
                customReset : function(){
                    Mist.monitoringController.graphs.enableAnimation();
                    this.reload('customRequestReset');
                },


                /**
                *
                *   Changes current request step
                *   @param {number}  newStep     - The new step
                *   @param {boolean} reloadAfter - Change Step And Reload, Default: true
                */
                changeStep: function(newStep,reloadAfter){
                    this.step = newStep;
                    reload = (typeof reloadAfter == 'undefined' ? true : reloadAfter);
                    if(reload)
                        this.reload('stepChanged');
                },


                /**
                *
                *   Changes current time window
                *   @param {number} newTimeWindow - The new timeWindow
                *   @param {boolean} reloadAfter - Change timeWindow And Reload, Default: true
                */
                changeTimeWindow: function(newTimeWindow,reloadAfter){
                    this.timeWindow = newTimeWindow;
                    reload = (typeof reloadAfter == 'undefined' ? true : reloadAfter);
                    if(reload)
                        this.reload('timeWindowChanged');
                },


                /**
                *
                *   Enables Updates , Also Animation
                *
                */
                enableUpdates: function(){
                    this.updateData = true;
                    this.reload('updatesEnabled');
                },


                /**
                *
                *   Disables Updates , Also Animation
                *
                */
                disableUpdates: function(){
                    this.updateData = false;
                    this.reload('updatesDisabled');
                },


                /**
                *
                *   Stops data updates by clearing the interval
                *
                */
                stopDataUpdates: function(){
                    window.clearInterval(window.monitoringInterval);
                },

                /**
                *
                *   Does an ajax request to the server
                *   @param {number} start - The start time in seconds of requested measurements
                *   @param {number} stop  - The stop  time in seconds of requested measurements
                *   @param {number} step  - The step in miliseconds of requested measurements
                *   @param {function} callback - The function that will be called when request has finished.
                */
                receiveData: function(start,stop,step,callback){

                    var requestID  = this.requestID;
                    var controller = Mist.monitoringController;
                    var self = this;

                    // Set an empty function for null callbacks
                    if (callback == null) {
                      callback = function(){};
                    }

                    $.ajax({
                        url: '/backends/' + self.machine.backend.id +
                             '/machines/' + self.machine.id + '/stats',
                        type: 'GET',
                        async: true,
                        dataType: 'json',
                        data: { 'start': start,
                                'stop': stop,
                                'step': step
                              },
                        timeout: 10000,
                        success: function (data, status, xhr){

                            try {

                                var measurmentsExpected = Math.floor((stop-start) / (step/1000)) ;

                                // Throw error for none or more measurements
                                if(data.load.length == 0)
                                    throw "Error, Received none measurements";
                                else if(data.load.length > measurmentsExpected)
                                    throw ("Error, Received more measurements than expected, " +
                                            data.load.length + " instead of " + measurmentsExpected);


                                var disks = [];
                                var netInterfaces = [];

                                // Get Disks Names
                                for(disk in data['disk']['read'])
                                {
                                    disks.push(disk);
                                }

                                // Get Network Interfaces Names
                                for(netInterface in data['network'])
                                {
                                     netInterfaces.push(netInterface);
                                }


                                var receivedData = {
                                    cpuCores:   0,
                                    cpu:       [],
                                    load:      [],
                                    memory:    [],
                                    diskRead:  [],
                                    diskWrite: [],
                                    networkRX: [],
                                    networkTX: []
                                };


                                // Set CPU Cores
                                receivedData.cpuCores =  data['cpu']['cores'];

                                /* Request Debugging : TODO Remove It when requests are stable
                                console.log("Measurement Expected: " + measurmentsExpected + " For " + (stop-start) + " seconds");
                                console.log("Measurement Received: ");
                                console.log("LOAD   : " + data.load.length);
                                console.log("CPU    : " + data['cpu']['utilization'].length);
                                console.log("MEM    : " + data['memory'].length);
                                console.log("DISK R : " + data['disk']['read'][disks[0]]['disk_octets'].length);
                                console.log("DISK W : " + data['disk']['write'][disks[0]]['disk_octets'].length);
                                console.log("NET TX : " + data['network'][netInterfaces[0]]['tx'].length);
                                console.log("NET RX : " + data['network'][netInterfaces[0]]['rx'].length);
                                console.log("");
                                */

                                // Create a date with first measurement time
                                var metricTime = new Date(start*1000 + step);

                                // Get min Data Length (Quick Fix)
                                var lengths = [
                                    data['load'].length,
                                    data['cpu']['utilization'].length,
                                    data['memory'].length,
                                    data['disk']['read'][disks[0]]['disk_octets'].length,
                                    data['disk']['write'][disks[0]]['disk_octets'].length,
                                    data['network'][netInterfaces[0]]['tx'].length,
                                    data['network'][netInterfaces[0]]['rx'].length
                                ];


                                var dataLength = Math.min.apply(null, lengths);

                                // Create Custom Objects From Data
                                for(var i=0; i < dataLength; i++ )
                                {

                                    var cpuObj = {
                                        time : metricTime,
                                        value: ( (data['cpu']['utilization'][i] * data['cpu']['cores']) * 100)
                                    };
                                    var loadObj = {
                                        time : metricTime,
                                        value: data['load'][i]
                                    };
                                    var memObj = {
                                        time : metricTime,
                                        value: data['memory'][i]
                                    };

                                    // TODO Add Multiple Disks
                                    var diskReadObj = {
                                        time: metricTime,
                                        value: data['disk']['read'][disks[0]]['disk_octets'][i]
                                    };
                                    var diskWriteObj = {
                                        time: metricTime,
                                        value: data['disk']['write'][disks[0]]['disk_octets'][i]
                                        // Possible fix for Negative Disk Write And Disk read Values
                                        // value: data['disk']['write'][disks[0]]['disk_octets'][i] < 0 ? 0 : data['disk']['write'][disks[0]]['disk_octets'][i]
                                    };

                                    // TODO Add Multiple Interfaces
                                    var networkRXObj = {
                                        time: metricTime,
                                        value: data['network'][netInterfaces[0]]['rx'][i]
                                    };
                                    var networkTXObj = {
                                        time: metricTime,
                                        value: data['network'][netInterfaces[0]]['tx'][i]
                                    };

                                    // Push Objects Into Data Object
                                    receivedData.cpu.push(cpuObj);
                                    receivedData.load.push(loadObj);
                                    receivedData.memory.push(memObj);
                                    receivedData.diskRead.push(diskReadObj);
                                    receivedData.diskWrite.push(diskWriteObj);
                                    receivedData.networkRX.push(networkRXObj);
                                    receivedData.networkTX.push(networkTXObj);

                                    // Increase time by step for every new measurement
                                    metricTime = new Date(metricTime.getTime()+step);
                                }

                                self.lastMetrictime = new Date(metricTime.getTime()-step);

                                callback({
                                    status: 'success',
                                    data  : receivedData
                                });

                                $(document).trigger('finishedFetching',[requestID,'success']);
                            }
                            catch(err) {
                                error(err);

                                callback({
                                    status: 'error',
                                    error: err
                                });
<commit_msg>First attempt to make graphs work with timestamps<commit_after>define('app/controllers/monitoring', [
    'ember'
    ],
    /**
     * Monitoring Controller
     *
     * @returns Class
     */
    function() {
        return Ember.ObjectController.extend(Ember.Evented,{

            /**
             *
             * Gets all monitoring related data from
             * the server
             */
             load: function(callback) {

                 if (!Mist.authenticated) {
                    Mist.backendsController.set('checkedMonitoring', true);
                    return;
                 }

                 var that = this;
                 this.checkingMonitoring = true;
                 Mist.ajax.GET('/monitoring', {
                 }).success(function(data) {
                     that._updateMonitoringData(data);
                 }).error(function() {
                     Mist.notificationController.notify('Failed to get monitoring data');
                 }).complete(function(success, data) {
                     that.checkingMonitoring = false;
                     Mist.backendsController.set('checkedMonitoring', true);
                     that.trigger('onMonitoringDataUpdate');
                     if (callback) callback(success, data);
                 });
             }.on('init'),


            changeMonitoring: function(machine, callback) {
                 var that = this;
                 //this.set('changingMonitoring', true);
                 if (machine.hasMonitoring) {
                     machine.set('disablingMonitoring', true);
                 } else {
                     machine.set('enablingMonitoring', true);
                 }
                 Mist.ajax.POST('/backends/' + machine.backend.id + '/machines/' + machine.id + '/monitoring', {
                    'action': machine.hasMonitoring ? 'disable' : 'enable',
                    'dns_name': machine.extra.dns_name ? machine.extra.dns_name : 'n/a',
                    'public_ips': machine.public_ips ? machine.public_ips : [],
                    'name': machine.name ? machine.name : machine.id
                 }).success(function(data) {
                     if (!machine.hasMonitoring) {
                         machine.set('hasMonitoring', true);
                         machine.set('enablingMonitoring', false);
                     } else {
                         machine.set('hasMonitoring', false);
                         // Remove machine from monitored_machines
                         Mist.monitored_machines.some(function(machine_tupple) {
                            if (machine_tupple[1] == machine.id && machine_tupple[0] == machine.backend.id) {
                                Mist.monitored_machines.removeObject(machine_tupple);
                            }
                         });
                         machine.set('disablingMonitoring', false);
                     }
                     Mist.set('authenticated', true);
                 }).error(function() {
                     if (machine.hasMonitoring) {
                         machine.set('disablingMonitoring', false);
                     } else {
                         machine.set('enablingMonitoring', false);
                     }
                     Mist.notificationController.notify('Error when changing monitoring to ' + machine.name);
                 }).complete(function(success, data) {
                     //that.set('changingMonitoring', false);
                     if (callback) callback(success, data);
                 });
             },


             /**
             *
             * Updates everything in the app that has
             * to do with monitoring
             */
             _updateMonitoringData: function(data) {

                 Mist.set('monitored_machines', data.machines);
                 Mist.set('current_plan', data.current_plan);
                 Mist.rulesController.setContent(data.rules);
                 data.machines.forEach(function(machine_tuple) {
                     var machine = Mist.backendsController.getMachine(machine_tuple[1], machine_tuple[0]);
                     if (machine)
                         machine.set('hasMonitoring', true);
                 });
                 Mist.backendsController.content.forEach(function(backend) {
                    backend.machines._updateMonitoredMachines();
                 });
             },


            /*
            *
            * Initalizes Request,Graphs,History objects
            * Loads cookies and hides collapsed graphs
            * @param {object} arguments - machine,timeWindow,step,updateInterval,updatesEnabled,timeGap,callback
            */
            initialize: function(arguments){

                var self = this;

                // Reset all controller values
                this.reset();

                // Get graphs from view
                this.graphs.instances = arguments['graphs'];

                // Get cookies and show graphs that are not collapsed
                var collapsedMetrics = this.cookies.getCollapsedMetrics();

                if(collapsedMetrics != null) {
                    this.graphs.collapse(collapsedMetrics,0);
                } else{

                    // Hide graphs
                    var metrics     = this.graphs.instances;
                    var metricsKeys = [];

                    for(var key in metrics){

                        if(key == 'load') continue;
                        metricsKeys.push(key);
                    }

                    this.graphs.collapse(metricsKeys,0);
                }

                // Create and Start the request
                this.request.create({
                    machine         : arguments['machineModel'], // Send Current Machine
                    timeWindow      : 10*60*1000,                // Display 10 Minutes
                    step            : 10000,                     // Metrics Step in miliseconds
                    updateInterval  : 10000,                     // Get Updates Every x Miliseconds
                    updatesEnabled  : true,                      // Get Updates
                    timeGap         : 60,                        // Gap between current time and requested
                    callback        : function(result){
                        if(result['status'] == 'success'){
                            //console.log("%cNumber Of Data Received: " + result['data']['cpu'].length, "color:orange;background-color:black; padding: 0 15px;");
                            self.graphs.updateData(result['data']);
                        }
                    }
                });

                this.request.start();

            },


            /**
            *
            *   Resets all controller instances to the default state
            *
            */
            reset: function(){

                this.request.reset();
                this.history.reset();
                this.graphs.reset();
                this.zoom.reset();
            },


            /**
            *
            *   This object is responsible for data requests
            *
            */
            request: {


                /**
                *   Creates the request. use start() to start the request
                *   @param {number}  timeWindow     - The time window in miliseconds
                *   @param {number}  step           - Step of measurements
                *   @param {number}  updateinterval - Update every updateInterval miliseconds
                *   @param {boolean} enableUpdates  - Enable/Disable updates
                */
                create : function(arguments){

                    this.reset();

                    var self             = this;
                    var controller       = Mist.monitoringController;

                    this.step            = arguments['step'];
                    this.timeWindow      = arguments['timeWindow'];
                    this.updateInterval  = arguments['updateInterval'];
                    this.machine         = arguments['machine'];
                    this.updateData      = arguments['updatesEnabled'];
                    this.step            = arguments['step'];
                    this.callback        = ('callback' in arguments) ? arguments['callback'] : null;
                    this.timeGap         = arguments['timeGap']; // Temporary Fix , Give some time to server to collect data

                    // Calculate Start And Stop
                    this.timeStop        = Math.floor( ( (new Date()).getTime() - this.timeGap * 1000) / 1000 );
                    this.timeStart       = Math.floor(this.timeStop - this.timeWindow/1000);
                    this.lastMetrictime  = new Date(this.timeStart*1000);
                },


                /**
                *
                *   Starts the request. User create() first
                *
                */
                start : function(){

                    var self = this;

                    this.locked = true;

                    // If request stopped Re-calculate start and stop
                    if(this.initialized && !this.running){

                        this.timeStart = Math.floor( this.lastMetrictime.getTime() /1000 ) ;
                        this.timeStop  =  Math.floor( ((new Date()).getTime() - this.timeGap * 1000 ) / 1000 );

                        // Fix time when lossing precision
                        var stopRemainder = (this.timeStop - this.timeStart) % (this.step/1000);
                        this.timeStop     = this.timeStop - stopRemainder;
                    } else {

                        this.initialized = true;
                    }

                    // Show Fetching Message On Initial Request
                    this.machine.set('pendingStats', true);

                    // Do the ajax call
                    this.requestID++;
                    this.receiveData(this.timeStart, this.timeStop, this.step,this.callback);


                    // Check if Data Updates Are Enabled
                    if(this.updateData && !this.running){
                        window.monitoringInterval = window.setInterval(function() {

                            // Lock request so no other request can be done in the same time
                            self.locked = true;

                            // Calculate Start and Stop
                            self.timeStart = Math.floor( self.lastMetrictime.getTime() /1000 ) ;
                            self.timeStop  =  Math.floor( ((new Date()).getTime() - self.timeGap * 1000 ) / 1000 );

                            // Fix time when lossing precision
                            var stopRemainder = (self.timeStop - self.timeStart) % (self.step/1000);
                            self.timeStop     = self.timeStop - stopRemainder;

                            // Do the ajax call
                            this.requestID++;
                            self.receiveData(self.timeStart, self.timeStop, self.step,self.callback);

                        },this.step);
                    }

                    this.running = true;

                    return this.requestID;
                },


                /**
                *
                *   Stops current request
                *
                */
                stop : function(){

                    this.running = false;
                    window.clearInterval(window.monitoringInterval);
                },


                /**
                *
                *   Reloads current request.
                *   @param {string} reason - Reason for reloading (default: manualReload)
                */
                reload: function(reason){

                    var self = this;

                    var reload = function(){

                        // wait until previous action (request) finishes
                        if(self.locked){
                            window.setTimeout(reload,1000);
                        }
                        else{

                           // Stop Current Request
                           self.stop();

                           reason = (typeof reason == 'undefined' ? 'manualReload' : reason);

                           // Temporary Fix For Some Functions TODO change this
                           if(reason == 'updatesDisabled')
                                Mist.monitoringController.graphs.disableAnimation(false);
                           if(reason == 'updatesEnabled')
                                Mist.monitoringController.graphs.enableAnimation();

                            Mist.monitoringController.graphs.clearData();
                            // End Of Fix

                           // Re-Initialize and start request
                           self.create({
                                machine         : self.machine,
                                timeWindow      : self.timeWindow,
                                step            : self.step,
                                updateInterval  : self.updateInterval,
                                updatesEnabled  : self.updateData,
                                timeGap         : self.timeGap,
                                callback        : self.callback
                           });

                           return self.start();
                        }

                    };

                    return reload();
                },


                /**
                *
                *   Runs a custm request without destroying the previous
                *   @param {object} options - Stop,Step,Timewindow
                */
                custom : function(options){

                    // Clear Intervals
                    this.stopDataUpdates();

                    // Wait Until Requests are not locked
                    var self   = this;
                    var custom = function(){

                        // wait until previous action (request) finishes
                        if(self.locked){
                            window.setTimeout(custom,1000);
                        }
                        else{
                            //var timeGap          = 60;
                            var timeWindow  = self.timeWindow;
                            var step        = self.step;
                            var stop        = Math.floor( ( new Date()).getTime() / 1000 ); //Math.floor( ( (new Date()).getTime() - timeGap * 1000) / 1000 );
                            var start       = Math.floor( stop - timeWindow/1000 );
                            var callback    = null;

                            if(options){
                                if ('stop' in options){
                                    stop  = Math.floor(options['stop']);//Math.floor(options['stop'] - timeGap);
                                    start = Math.floor( stop - timeWindow/1000 );
                                }

                                if ('step' in options)
                                    step = options['step'];

                                if ('timeWindow' in options)
                                    timeWindowSize = options['timeWindow']; // TODO Check this size ?

                                if('callback' in options)
                                    callback = options['callback'];
                            }

                            self.locked = true;
                            self.machine.set('pendingStats', true);

                            Mist.monitoringController.graphs.disableAnimation();
                            self.receiveData(start, stop, step,callback);
                        }
                    }

                    custom();

                },


                /**
                *
                *   Resets the custom request and gets back to the original
                *
                */
                customReset : function(){
                    Mist.monitoringController.graphs.enableAnimation();
                    this.reload('customRequestReset');
                },


                /**
                *
                *   Changes current request step
                *   @param {number}  newStep     - The new step
                *   @param {boolean} reloadAfter - Change Step And Reload, Default: true
                */
                changeStep: function(newStep,reloadAfter){
                    this.step = newStep;
                    reload = (typeof reloadAfter == 'undefined' ? true : reloadAfter);
                    if(reload)
                        this.reload('stepChanged');
                },


                /**
                *
                *   Changes current time window
                *   @param {number} newTimeWindow - The new timeWindow
                *   @param {boolean} reloadAfter - Change timeWindow And Reload, Default: true
                */
                changeTimeWindow: function(newTimeWindow,reloadAfter){
                    this.timeWindow = newTimeWindow;
                    reload = (typeof reloadAfter == 'undefined' ? true : reloadAfter);
                    if(reload)
                        this.reload('timeWindowChanged');
                },


                /**
                *
                *   Enables Updates , Also Animation
                *
                */
                enableUpdates: function(){
                    this.updateData = true;
                    this.reload('updatesEnabled');
                },


                /**
                *
                *   Disables Updates , Also Animation
                *
                */
                disableUpdates: function(){
                    this.updateData = false;
                    this.reload('updatesDisabled');
                },


                /**
                *
                *   Stops data updates by clearing the interval
                *
                */
                stopDataUpdates: function(){
                    window.clearInterval(window.monitoringInterval);
                },

                /**
                *
                *   Does an ajax request to the server
                *   @param {number} start - The start time in seconds of requested measurements
                *   @param {number} stop  - The stop  time in seconds of requested measurements
                *   @param {number} step  - The step in miliseconds of requested measurements
                *   @param {function} callback - The function that will be called when request has finished.
                */
                receiveData: function(start,stop,step,callback){

                    var requestID  = this.requestID;
                    var controller = Mist.monitoringController;
                    var self = this;

                    // Set an empty function for null callbacks
                    if (callback == null) {
                      callback = function(){};
                    }

                    $.ajax({
                        url: '/backends/' + self.machine.backend.id +
                             '/machines/' + self.machine.id + '/stats',
                        type: 'GET',
                        async: true,
                        dataType: 'json',
                        data: { 'start': start,
                                'stop': stop,
                                'step': step
                              },
                        timeout: 10000,
                        success: function (data, status, xhr){

                            try {

                                var disks = [];
                                var netInterfaces = [];

                                // Get Disks Names
                                for(disk in data['disk']['read'])
                                {
                                    disks.push(disk);
                                }

                                // Get Network Interfaces Names
                                for(netInterface in data['network'])
                                {
                                     netInterfaces.push(netInterface);
                                }


                                var receivedData = {
                                    cpuCores:   0,
                                    cpu:       [],
                                    load:      [],
                                    memory:    [],
                                    diskRead:  [],
                                    diskWrite: [],
                                    networkRX: [],
                                    networkTX: []
                                };


                                // Set CPU Cores
                                receivedData.cpuCores =  data['cpu']['cores'];

                                /* Request Debugging : TODO Remove It when requests are stable
                                console.log("Measurement Expected: " + measurmentsExpected + " For " + (stop-start) + " seconds");
                                console.log("Measurement Received: ");
                                console.log("LOAD   : " + data.load.length);
                                console.log("CPU    : " + data['cpu']['utilization'].length);
                                console.log("MEM    : " + data['memory'].length);
                                console.log("DISK R : " + data['disk']['read'][disks[0]]['disk_octets'].length);
                                console.log("DISK W : " + data['disk']['write'][disks[0]]['disk_octets'].length);
                                console.log("NET TX : " + data['network'][netInterfaces[0]]['tx'].length);
                                console.log("NET RX : " + data['network'][netInterfaces[0]]['rx'].length);
                                console.log("");
                                */

                                // Get min Data Length (Quick Fix)
                                var lengths = [
                                    data['load'].length,
                                    data['cpu']['utilization'].length,
                                    data['memory'].length,
                                    data['disk']['read'][disks[0]]['disk_octets'].length,
                                    data['disk']['write'][disks[0]]['disk_octets'].length,
                                    data['network'][netInterfaces[0]]['tx'].length,
                                    data['network'][netInterfaces[0]]['rx'].length
                                ];

                                var dataLength = Math.min.apply(null, lengths);

                                data.cpu.utilization.forEach(function(item) {
                                    var cpuObj = {
                                        time: new Date(item[0]*1000),
                                        value: item[1]
                                    };
                                    receivedData.cpu.push(cpuObj);
                                });

                                data.load.forEach(function(item) {
                                    var loadObj = {
                                        time : new Date(item[0]*1000),
                                        value : item[1]
                                    };
                                    receivedData.load.push(loadObj);
                                });

                                data.memory.forEach(function(item) {
                                    var memoryObj = {
                                        time : new Date(item[0]*1000),
                                        value : item[1]
                                    };
                                    receivedData.memory.push(memoryObj);
                                });

                                data.disk.read[disks[0]].disk_octets.forEach(function(item) {
                                    var diskReadObj = {
                                        time : new Date(item[0]*1000),
                                        value : item[1]
                                    };
                                    receivedData.diskRead.push(diskReadObj);
                                });

                                data.disk.write[disks[0]].disk_octets.forEach(function(item) {
                                    var diskWriteObj = {
                                        time : new Date(item[0]*1000),
                                        value : item[1]
                                    };
                                    receivedData.diskWrite.push(diskWriteObj);
                                });

                                data.network[netInterfaces[0]].rx.forEach(function(item) {
                                    var networkRxObj = {
                                        time : new Date(item[0]*1000),
                                        value : item[1]
                                    };
                                    receivedData.networkRX.push(networkRxObj);
                                });

                               data.network[netInterfaces[0]].tx.forEach(function(item) {
                                    var networkTxObj = {
                                        time : new Date(item[0]*1000),
                                        value : item[1]
                                    };
                                    receivedData.networkTX.push(networkTxObj);
                                });

                                self.lastMetrictime = new Date(stop*1000);

                                callback({
                                    status: 'success',
                                    data  : receivedData
                                });

                                $(document).trigger('finishedFetching',[requestID,'success']);
                            }
                            catch(err) {
                                error(err);

                                callback({
                                    status: 'error',
                                    error: err
                                });

{'fraction_non_alphanumeric': 0.08956422660963446, 'fraction_numerical': 0.00592113865177354, 'mean_word_length': 0.862839248434238, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 200, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '130535', 'n_tokens_mistral': 11737, 'n_tokens_neox': 10475, 'n_words': 2276}