<commit_before>(function() {
    'use strict';

    angular.module('chaise.viewer')

    .controller('AnnotationsController', ['annotations', 'anatomies', 'AnnotationsService', '$window', '$document', '$scope', function AnnotationsController(annotations, anatomies, AnnotationsService, $window, $document, $scope) {
        var vm = this;
        vm.annotations = annotations;
        vm.anatomies = anatomies;

        vm.filterAnnotations = filterAnnotations;

        vm.createMode = false;
        vm.newAnnotation = null;
        vm.drawAnnotation = drawAnnotation;
        vm.createAnnotation = createAnnotation;
        vm.cancelNewAnnotation = cancelNewAnnotation;

        vm.editedAnnotation = null; // Track which annotation is being edited right now; used to show/hide the right UI elements depending on which one is being edited.
        // vm.originalAnnotation = null; // Holds the original contents of annotation in the event that a user cancels an edit
        vm.editAnnotation = editAnnotation;
        vm.cancelEdit = cancelEdit;
        vm.updateAnnotation = updateAnnotation;

        vm.deleteAnnotation = deleteAnnotation;

        vm.highlightedAnnotation = null;
        vm.setHighlightedAnnotation = setHighlightedAnnotation;

        $window.addEventListener('message', function annotationControllerListener(event) {
            if (event.origin === window.location.origin) {
                var data = event.data;
                if (data.messageType === 'annotationDrawn') {
                    vm.newAnnotation = {
                        description: '',
                        shape: data.content.shape
                    };
                    $scope.$apply(function() {
                        vm.createMode = true;
                    });
                } else if (data.messageType === 'onHighlighted') {
                    var content = JSON.parse(data.content);
                    var annotation = findAnnotation(content.data.shapes[0].geometry);
                    $scope.$apply(function() {
                        vm.highlightedAnnotation = annotation.data.id;
                        // Scroll the annotation into visible part of browser
                        document.getElementById('annotation-' + vm.highlightedAnnotation).scrollIntoView({
                            block: 'start',
                            behavior: 'smooth'
                        });
                    });
                    var element = document.get
                } else if (data.messageType ==='onUnHighlighted') {
                    $scope.$apply(function() {
                        vm.highlightedAnnotation = null;
                    });
                }
            }
        });

        // Returns true if at least one of a specified subset of an object's keys contains a value that contains the query
        function filterAnnotations(keys) {
            var query = vm.query;
            return function(annotation) {
                if (!query) {
                    // If query is "" or undefined, then the annotation is considered a match
                    return true;
                } else {
                    console.log(query);
                    annotation = annotation.data;
                    query = query.toLowerCase();
                    // // If the "anatomy" key is null, make it "No Anatomy" so that a query for "No Anatomy" will match this key
                    if (!annotation.anatomy) {
                        annotation.anatomy = 'No Anatomy';
                    }
                    // Loop through the array to find matches
                    var numKeys = keys.length;
                    if (numKeys > 0) {
                        for (var i = 0; i < numKeys; i++) {
                            if (annotation[keys[i]].toLowerCase().indexOf(query) !== -1) {
                                return true;
                            }
                        }
                    }
                    // // Set the "anatomy" key back to null if it was changed to "No Anatomy" earlier
                    if (annotation.anatomy === 'No Anatomy') {
                        annotation.anatomy = null;
                    }
                }
            }
        }

        function drawAnnotation(annotation) {
            return AnnotationsService.drawAnnotation();
        }

        function createAnnotation() {
            vm.createMode = false;
            return AnnotationsService.createAnnotation(vm.newAnnotation);
        }

        function cancelNewAnnotation() {
            vm.createMode = false;
            return AnnotationsService.cancelNewAnnotation();
        }

        function editAnnotation(annotation) {
            vm.editedAnnotation = annotation.data.id;
            // vm.originalAnnotation = annotation;
        };

        function cancelEdit(annotation) {
            vm.editedAnnotation = null;
            // annotation = vm.originalAnnotation;
        };

        function updateAnnotation(annotation) {
            vm.editedAnnotation = null;
            return AnnotationsService.updateAnnotation(annotation);
        }

        function deleteAnnotation(annotation) {
            return AnnotationsService.deleteAnnotation(annotation);
        };

        function setHighlightedAnnotation(annotation) {
            if (vm.highlightedAnnotation == annotation.data.id) {
                vm.highlightedAnnotation = null;
                return;
            }

            vm.highlightedAnnotation = annotation.data.id;
            highlightAnnotation(annotation);
        }

        function highlightAnnotation(annotation) {
            return AnnotationsService.highlightAnnotation(annotation);
        }

        // Return an annotation that matches an object of coordinates
        function findAnnotation(coordinates) {
            for (var i = 0; i < vm.annotations.length; i++) {
                var annotationCoords = vm.annotations[i].data.coords;
                if (coordinates.x == annotationCoords[0] && coordinates.y == annotationCoords[1] && coordinates.width == annotationCoords[2] && coordinates.height == annotationCoords[3]) {
                    return vm.annotations[i];
                }
            }
        }
    }]);
})();
<commit_msg>Move scrolling logic to its own function<commit_after>(function() {
    'use strict';

    angular.module('chaise.viewer')

    .controller('AnnotationsController', ['annotations', 'anatomies', 'AnnotationsService', '$window', '$scope', function AnnotationsController(annotations, anatomies, AnnotationsService, $window, $scope) {
        var vm = this;
        vm.annotations = annotations;
        vm.anatomies = anatomies;

        vm.filterAnnotations = filterAnnotations;

        vm.createMode = false;
        vm.newAnnotation = null;
        vm.drawAnnotation = drawAnnotation;
        vm.createAnnotation = createAnnotation;
        vm.cancelNewAnnotation = cancelNewAnnotation;

        vm.editedAnnotation = null; // Track which annotation is being edited right now; used to show/hide the right UI elements depending on which one is being edited.
        // vm.originalAnnotation = null; // Holds the original contents of annotation in the event that a user cancels an edit
        vm.editAnnotation = editAnnotation;
        vm.cancelEdit = cancelEdit;
        vm.updateAnnotation = updateAnnotation;

        vm.deleteAnnotation = deleteAnnotation;

        vm.highlightedAnnotation = null;
        vm.setHighlightedAnnotation = setHighlightedAnnotation;

        // Listen to events of type 'message' (from Annotorious)
        $window.addEventListener('message', function annotationControllerListener(event) {
            if (event.origin === window.location.origin) {
                var data = event.data;
                var messageType = data.messageType;
                switch (messageType) {
                    case 'annotationDrawn':
                        vm.newAnnotation = {
                            description: '',
                            shape: data.content.shape
                        };
                        $scope.$apply(function() {
                            vm.createMode = true;
                        });
                        break;
                    case 'onHighlighted':
                        var content = JSON.parse(data.content);
                        var annotation = findAnnotation(content.data.shapes[0].geometry);
                        $scope.$apply(function() {
                            // Highlight the annotation in the sidebar
                            vm.highlightedAnnotation = annotation.data.id;
                        });
                        scrollIntoView('annotation-' + vm.highlightedAnnotation);
                        break;
                    case 'onUnHighlighted':
                        $scope.$apply(function() {
                            vm.highlightedAnnotation = null;
                        });
                        break;
                    default:
                        console.log('Invalid event message type "', messageType, '"');
                }
            } else {
                console.log('Invalid event origin. Event origin: ', event.origin, '. Expected origin: ', window.location.origin);
            }
        });

        // Returns true if at least one of a specified subset of an object's keys contains a value that contains the query
        function filterAnnotations(keys) {
            var query = vm.query;
            return function(annotation) {
                if (!query) {
                    // If query is "" or undefined, then the annotation is considered a match
                    return true;
                } else {
                    console.log(query);
                    annotation = annotation.data;
                    query = query.toLowerCase();
                    // // If the "anatomy" key is null, make it "No Anatomy" so that a query for "No Anatomy" will match this key
                    if (!annotation.anatomy) {
                        annotation.anatomy = 'No Anatomy';
                    }
                    // Loop through the array to find matches
                    var numKeys = keys.length;
                    if (numKeys > 0) {
                        for (var i = 0; i < numKeys; i++) {
                            if (annotation[keys[i]].toLowerCase().indexOf(query) !== -1) {
                                return true;
                            }
                        }
                    }
                    // // Set the "anatomy" key back to null if it was changed to "No Anatomy" earlier
                    if (annotation.anatomy === 'No Anatomy') {
                        annotation.anatomy = null;
                    }
                }
            }
        }

        function drawAnnotation(annotation) {
            return AnnotationsService.drawAnnotation();
        }

        function createAnnotation() {
            vm.createMode = false;
            return AnnotationsService.createAnnotation(vm.newAnnotation);
        }

        function cancelNewAnnotation() {
            vm.createMode = false;
            return AnnotationsService.cancelNewAnnotation();
        }

        function editAnnotation(annotation) {
            vm.editedAnnotation = annotation.data.id;
            // vm.originalAnnotation = annotation;
        };

        function cancelEdit(annotation) {
            vm.editedAnnotation = null;
            // annotation = vm.originalAnnotation;
        };

        function updateAnnotation(annotation) {
            vm.editedAnnotation = null;
            return AnnotationsService.updateAnnotation(annotation);
        }

        function deleteAnnotation(annotation) {
            return AnnotationsService.deleteAnnotation(annotation);
        };

        function setHighlightedAnnotation(annotation) {
            if (vm.highlightedAnnotation == annotation.data.id) {
                vm.highlightedAnnotation = null;
                return;
            }

            vm.highlightedAnnotation = annotation.data.id;
            highlightAnnotation(annotation);
        }

        // Highlights the annotation inside Annotorious
        function highlightAnnotation(annotation) {
            return AnnotationsService.highlightAnnotation(annotation);
        }

        // Return an annotation that matches an object of coordinates
        function findAnnotation(coordinates) {
            for (var i = 0; i < vm.annotations.length; i++) {
                var annotationCoords = vm.annotations[i].data.coords;
                if (coordinates.x == annotationCoords[0] && coordinates.y == annotationCoords[1] && coordinates.width == annotationCoords[2] && coordinates.height == annotationCoords[3]) {
                    return vm.annotations[i];
                }
            }
        }

        // Scroll an element into visible part of the browser
        function scrollIntoView(elementId) {
            // Scroll the annotation into visible part of browser
            document.getElementById(elementId).scrollIntoView({
                block: 'start',
                behavior: 'smooth'
            });
        }
    }]);
})();
<|endoftext|>


<commit_before>/* This module uses a give ip to visit the whole urls in the bucket assigned to it
*/
'use strict';

module.exports = function(agent , database) {
  console.log(agent.getAgent())
	//
  var ObjectId = require('mongodb').ObjectId;
	var Spooky = require('spooky');
  var EventEmitter = require('events').EventEmitter;
  var domain = require('domain');

	var bucket;
  var ipQueue = [];
  var ipQueueIndex = 0;
  var child_processes = 0;

    //
    var Buckets = database.model('Buckets');

    //
    var setBucket =  function(bucketObj){
    	 bucket = bucketObj;
         if(bucket.urls.length>0){
            for(let i=0; i < bucket.urls.length; i++){
                bucket.urls[i].visited = 0;
                bucket.urls[i].statusText = 'No status yet';
            };
         }

    	 console.log(bucket);
    	 console.log('bucket set in visitor');
         startUpdateDaemon();
    };

    //
    var getBucket = function(){
    	return bucket;
    };

    //
    var updateBucket = function(bucketObj , meta){
    	console.log(meta);
    	if(bucket){
            //
            if(bucketObj._id+'' == bucket._id){
	           if(meta.action == 0){
	           	   console.log('Deleting url in this bucket');
                   bucket.urls.splice(meta.index , 1);
	           }
	           else if(meta.action == 1) {
                   console.log('Updating url in this bucket');
                   bucket = bucketObj;
	           }
	    	}
	    	else{
	    	   console.log('Just passing by');
	    	}
    	}
    	else{
    		 console.log('Bucket empty here');
    	}
    }

    //
    var notifyDelete = function(_id){
         console.log('Bucket with'+ _id +'deleted');
         if(bucket){
             if(bucket._id == _id){
                console.log('This bucket was deleted');
                setTimeout(function(){
                    process.exit(0);
                } , 10000);
             }
             else{
                 console.log('Not this one 1..');
             }

         }
         else{
            console.log('Not this one..');
         }
    }

    //
    var visitWith = function(ip){
        console.log('Adding %s to queue' , ip);
        if(ipQueue.indexOf(ip)<0){
            ipQueue.push(ip);
        }
        else{
            console.log('ip alredy used or currently in use');
        }

        if(ipQueue.length == 1){
            startVisitingDaemon();
        }
    }

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    var V_WORKER = function(){
        var workerEvents = new EventEmitter;

        var visit = function(ip , urlObj , index , userAgent){
            console.log('visit starting with '+ip+' and '+urlObj.urlName);

            let spooky = Spooky.create({
                child: {
                    transport: 'http',
                    proxy: ip
                },

                casper: {
                    logLevel: 'debug',
                    verbose: true,
                    options: {
                        clientScripts: ['public/js/vendors/jquery.min.js'],
                        pageSettings: {
                            webSecurityEnabled: false,
                            userAgent:userAgent
                        }
                    }
                }
            },

            function(err){
               if (err) {
                    e = new Error('Failed to initialize SpookyJS');
                    e.details = err;
                    throw e;
                }

                //
                (function(url , selector , index){
                    //
                    console.log(userAgent);
                    spooky.start();
                    spooky.then(function () {
                        this.page.customHeaders = {
                            "Referer": 'http://www.minicards.xyz'
                        };
                    });
                    spooky.thenOpen(url);
                    spooky.then([{url:url , selector:selector , index:index} , function(){
                        //
                        this.done = function(err , status){
                            if(err){
                                this.emit('done', {status:this.getCurrentUrl() , index:index});
                                return phantom.clearCookies();
                            }
                            else{
                                this.emit('done', {status:this.getCurrentUrl() , index:index});
                                return phantom.clearCookies();
                            }
                        }

                       if(selector=='none'){
                            this.then(function(){
                                this.wait(10000 , function(){
                                    this.done(null , true);
                                });
                            });
                        }

                        else{
                            this.then(function(){
                                this.waitForSelector(selector , function(){
                                    this.thenClick(selector , function() {
                                        this.done(null , true);
                                    });

                                } , function(){
                                    this.done(true , null);
                                } , 10000);
                            });
                        }
                    }]);
                })(urlObj.urlName , urlObj.selector , index);

                //
                spooky.run();
            });

            //
            spooky.on('console', function (line) {
                console.log(line);
            });

            //
            spooky.on('error', function (e, stack) {
                console.error(stack||e);
                workerEvents.emit('done' , {status:stack?stack:e , index:0});
            });

            //
            spooky.on('done', function (status) {
                workerEvents.emit('done' , status);
            });

            //self destruct this instance in 8 minutes
            setTimeout(function(){
                console.log('Instance destroyed');
                spooky.destroy();
                child_processes--;
            } , 8*60000);
        };

        return {
            visit:visit,
            status:workerEvents
        }
    }
    //++++++++++++++++++++++++++++++++END++++++++++++++++++++++++++++++++++++++++++

    //updateBucket after every 120 secs of activity
    function startUpdateDaemon(){
        let timer = 0;
        console.log('Starting cron daemon');
        setInterval(function(){
            bucket.lastActive = Date.now()+'';
            Buckets.update(
                {_id : ObjectId(bucket._id)},
                bucket,
                function(err , result){
                    if(err){
                        console.log(err);
                        res.status(500).send('Database error during cron update in visitor');
                    }
                    else {
                        timer+=2;
                        if(timer >= 120){
                            console.log('Maximum uptime of three hours exceeded exiting....');
                            process.exit(0);
                        }
                        console.log('bucket updated in cron job');
                    }
                }
          );
        } , 120000);
    }

    //
    function startVisitingDaemon(){
       let v_worker = V_WORKER();

       (function fillVisiting(){
            console.log('fill visiting called');
            if(ipQueueIndex < ipQueue.length && child_processes<=20){
               child_processes+=bucket.urls.length;
               console.log(child_processes+' child_processes currently running');

               //spin all new workers for each urls
               for(let i=0; i < bucket.urls.length; i++){
                   v_worker.visit(ipQueue[ipQueueIndex] , bucket.urls[i].trim() , i , agent.getAgent());
               }

               ipQueueIndex++;
            }
            else{
                console.log('Good ip shortage');
            }

            //
            setTimeout(function(){
                return fillVisiting();
            } , 20000);
       })();

      //
      v_worker.status.on('done' , function(status){
            console.log(status);
            bucket.urls[status.index].statusText = status.status;
            bucket.urls[status.index].visited++;
        });
    }

	return {
	    visitWith:visitWith,
	    getBucket:getBucket,
	    setBucket:setBucket,
	    updateBucket:updateBucket,
      notifyDelete:notifyDelete
	}
};
<commit_msg>Signed-off-by: codemuhammed <codemuhammed@gmail.com><commit_after>/* This module uses a give ip to visit the whole urls in the bucket assigned to it
*/
'use strict';

module.exports = function(agent , database) {
  console.log(agent.getAgent())
	//
  var ObjectId = require('mongodb').ObjectId;
	var Spooky = require('spooky');
  var EventEmitter = require('events').EventEmitter;
  var domain = require('domain');

	var bucket;
  var ipQueue = [];
  var ipQueueIndex = 0;
  var child_processes = 0;

    //
    var Buckets = database.model('Buckets');

    //
    var setBucket =  function(bucketObj){
    	 bucket = bucketObj;
         if(bucket.urls.length>0){
            for(let i=0; i < bucket.urls.length; i++){
                bucket.urls[i].visited = 0;
                bucket.urls[i].statusText = 'No status yet';
            };
         }

    	 console.log(bucket);
    	 console.log('bucket set in visitor');
         startUpdateDaemon();
    };

    //
    var getBucket = function(){
    	return bucket;
    };

    //
    var updateBucket = function(bucketObj , meta){
    	console.log(meta);
    	if(bucket){
            //
            if(bucketObj._id+'' == bucket._id){
	           if(meta.action == 0){
	           	   console.log('Deleting url in this bucket');
                   bucket.urls.splice(meta.index , 1);
	           }
	           else if(meta.action == 1) {
                   console.log('Updating url in this bucket');
                   bucket = bucketObj;
	           }
	    	}
	    	else{
	    	   console.log('Just passing by');
	    	}
    	}
    	else{
    		 console.log('Bucket empty here');
    	}
    }

    //
    var notifyDelete = function(_id){
         console.log('Bucket with'+ _id +'deleted');
         if(bucket){
             if(bucket._id == _id){
                console.log('This bucket was deleted');
                setTimeout(function(){
                    process.exit(0);
                } , 10000);
             }
             else{
                 console.log('Not this one 1..');
             }

         }
         else{
            console.log('Not this one..');
         }
    }

    //
    var visitWith = function(ip){
        console.log('Adding %s to queue' , ip);
        if(ipQueue.indexOf(ip)<0){
            ipQueue.push(ip);
        }
        else{
            console.log('ip alredy used or currently in use');
        }

        if(ipQueue.length == 1){
            startVisitingDaemon();
        }
    }

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    var V_WORKER = function(){
        var workerEvents = new EventEmitter;

        var visit = function(ip , urlObj , index , userAgent){
            console.log('visit starting with '+ip+' and '+urlObj.urlName);

            let spooky = Spooky.create({
                child: {
                    transport: 'http',
                    proxy: ip
                },

                casper: {
                    logLevel: 'debug',
                    verbose: true,
                    options: {
                        clientScripts: ['public/js/vendors/jquery.min.js'],
                        pageSettings: {
                            webSecurityEnabled: false,
                            userAgent:userAgent
                        }
                    }
                }
            },

            function(err){
               if (err) {
                    e = new Error('Failed to initialize SpookyJS');
                    e.details = err;
                    throw e;
                }

                //
                (function(url , selector , index){
                    //
                    console.log(userAgent);
                    spooky.start();
                    spooky.then(function () {
                        this.page.customHeaders = {
                            "Referer": 'http://www.minicards.xyz'
                        };
                    });
                    spooky.thenOpen(url);
                    spooky.then([{url:url , selector:selector , index:index} , function(){
                        //
                        this.done = function(err , status){
                            if(err){
                                this.emit('done', {status:this.getCurrentUrl() , index:index});
                                return phantom.clearCookies();
                            }
                            else{
                                this.emit('done', {status:this.getCurrentUrl() , index:index});
                                return phantom.clearCookies();
                            }
                        }

                       if(selector=='none'){
                            this.then(function(){
                                this.wait(10000 , function(){
                                    this.done(null , true);
                                });
                            });
                        }

                        else{
                            this.then(function(){
                                this.waitForSelector(selector , function(){
                                    this.thenClick(selector , function() {
                                        this.done(null , true);
                                    });

                                } , function(){
                                    this.done(true , null);
                                } , 10000);
                            });
                        }
                    }]);
                })(urlObj.urlName , urlObj.selector , index);

                //
                spooky.run();
            });

            //
            spooky.on('console', function (line) {
                console.log(line);
            });

            //
            spooky.on('error', function (e, stack) {
                console.error(stack||e);
                workerEvents.emit('done' , {status:stack?stack:e , index:0});
            });

            //
            spooky.on('done', function (status) {
                workerEvents.emit('done' , status);
            });

            //self destruct this instance in 8 minutes
            setTimeout(function(){
                console.log('Instance destroyed');
                spooky.destroy();
                child_processes--;
            } , 8*60000);
        };

        return {
            visit:visit,
            status:workerEvents
        }
    }
    //++++++++++++++++++++++++++++++++END++++++++++++++++++++++++++++++++++++++++++

    //updateBucket after every 120 secs of activity
    function startUpdateDaemon(){
        let timer = 0;
        console.log('Starting cron daemon');
        setInterval(function(){
            bucket.lastActive = Date.now()+'';
            Buckets.update(
                {_id : ObjectId(bucket._id)},
                bucket,
                function(err , result){
                    if(err){
                        console.log(err);
                        res.status(500).send('Database error during cron update in visitor');
                    }
                    else {
                        timer+=2;
                        if(timer >= 120){
                            console.log('Maximum uptime of three hours exceeded exiting....');
                            process.exit(0);
                        }
                        console.log('bucket updated in cron job');
                    }
                }
          );
        } , 120000);
    }

    //
    function startVisitingDaemon(){
       let v_worker = V_WORKER();

       (function fillVisiting(){
            console.log('fill visiting called');
            if(ipQueueIndex < ipQueue.length && child_processes<=20){
               child_processes+=bucket.urls.length;
               console.log(child_processes+' child_processes currently running');

               //spin all new workers for each urls
               for(let i=0; i < bucket.urls.length; i++){
                   v_worker.visit(ipQueue[ipQueueIndex] , bucket.urls[i] , i , agent.getAgent());
               }

               ipQueueIndex++;
            }
            else{
                console.log('Good ip shortage');
            }

            //
            setTimeout(function(){
                return fillVisiting();
            } , 20000);
       })();

      //
      v_worker.status.on('done' , function(status){
            console.log(status);
            bucket.urls[status.index].statusText = status.status;
            bucket.urls[status.index].visited++;
        });
    }

	return {
	    visitWith:visitWith,
	    getBucket:getBucket,
	    setBucket:setBucket,
	    updateBucket:updateBucket,
      notifyDelete:notifyDelete
	}
};
<|endoftext|>


<commit_before>module.exports = function(grunt) {
  /*
   * Include grunt configuration
   */
  var gruntConfig = require( './config/grunt.conf.js' );

  /*
   * Helpers (preparing for grunt util deprecation)
   */
  var glob = require('glob');

  /*
   * Time grunt execution
   */
  require('time-grunt')(grunt);

  /*
   * JIT Grunt will automatically load other npm tasks
   */
  require('jit-grunt')(grunt);
  grunt.loadNpmTasks('grunt-protractor-runner');

  /*
   * Configuration
   */
  var gruntTasks = {
    //////////////
    pkg: grunt.file.readJSON('package.json'),
    /*
     * Placed at the top of the compiled source files.
     */
    meta: {
      banner:
        '/*\n' +
        ' * <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' +
        ' * <%= pkg.repository.url %>\n' +
        ' *\n' +
        ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
        ' * Licensed <%= pkg.licenses.type %> <<%= pkg.licenses.url %>>\n' +
        ' */\n'
    },
    //////////////
    shell: {
      run_build_server: {
        command: './server/build-server.sh'
      }
    },
    //////////////
    copy: {
      build_app_js: {
        src: [
          findModuleFilesIn('./src/app/'),
          findModuleFilesIn('./src/common/'),
          './src/app/**/*.json'
        ],
        dest: '<%= build_dir %>'
      },
      build_unit: {
        src: ['./src/**/*.spec.js'],
        dest: '<%= build_dir %>'
      },
      build_vendor_js: {
        src: ['<%= build.vendor_js %>'],
        dest: '<%= build_dir %>'
      },
      build_views: {
        cwd: './src',
        src: ['**/*.html', '!**/index.html'],
        dest: '<%= build_dir %>/views/',
        expand: true,
        flatten: true
      },
      build_index: {
        cwd: './src',
        src: ['index.html'],
        dest: '<%= build_dir %>',
        expand: true,
        flatten: true,
        options: {
          process: processBuildScripts
        }
      },
      build_assets: {
        cwd: './src',
        src: [
          'assets/**/*',
          '!assets/**/*.less',
          '!assets/**/*.css'
        ],
        dest: '<%= build_dir %>src/assets/',
        expand: true,
        flatten: true
      },
      build_fonts: {
        src: ['<%= common.vendor_fonts %>'],
        dest: '<%= build_dir %>src/assets/fonts/',
        expand: true,
        flatten: true
      },
      build_karma: {
        src: ['./config/karma.conf.js'],
        dest: '<%= build_dir %>',
        options: {
          process: processBuildScripts
        }
      },
      build_protractor: {
        cwd: './src',
        src: ['**/*.protractor.js', '**/*.e2e.js'],
        expand: true,
        flatten: true,
        dest: '<%= build_dir %>src/e2e/'
      }
    },
    /////////////////
    clean: {
      build_css_clean: ['<%= build_dir %>/src/assets/css/app.custom.css']
    },
    /////////////////
    less: {
      build_less: {
        src: ['./src/assets/**/*.less'],
        dest: '<%= build_dir %>/src/assets/css/app.custom.css',
        options: {
          cleancss: true,
          compress: true
        }
      }
    },
    /////////////////
    cssmin: {
      build_css: {
        src: [
          '<%= build.vendor_css %>',
          './src/assets/**/*.css',
          '<%= build_dir %>/src/assets/css/app.custom.css'
        ],
        dest: '<%= build_dir %>/src/assets/css/app.min.css'
      }
    },
    /////////////////
    jshint: {
      options: {
        jshintrc: true
      },
      src_js: ['./src/**/*.js'],
      gruntfiles: ['./gruntfile.js', 'grunt.conf.js']
    },
    /////////////////
    karma: {
      options: {
        configFile: '<%= build_dir %>/config/karma.conf.js'
      },
      unit: {
        port: 9191,
        background: false
      },
      continuous: {
        singleRun: false,
        autoWatch: true
      }
    },
    /////////////////
    protractor: {
      options: {
        configFile: "./config/protractor.conf.js", // Default config file
        keepAlive: true, // If false, the grunt process stops when the test fails.
        noColor: false, // If true, protractor will not use colors in its output.
        args: {}
      },
      build: {},
      /*compile: {
        options: {
          configFile: "protractor/protractor-prod.conf.js"
        }
      }*/
    },
    /////////////////
    watch: {
      options: {
        livereload: true
      },
      src_js: {
        files: ['./src/**/*.js', './src/**/*.json'],
        tasks: ['newer:jshint:src_js', 'newer:copy:build_app_js']
      },
      src_html: {
        files: ['./src/**/*.html', '!./src/index.html'],
        tasks: ['newer:copy:build_views']
      },
      src_index: {
        files: ['./src/index.html'],
        tasks: ['copy:build_index']
      },
      src_stylesheets: {
        files: ['./src/assets/**/*.less', './src/assets/**/*.css'],
        tasks: ['newer:less:build_less', 'cssmin:build_css', 'clean:build_css_clean']
      },
      src_assets: {
        files: ['./src/assets/**/*', '!./src/assets/**/*.less', '!./src/assets/**/*.css'],
        tasks: ['newer:copy:build_assets']
      },
      gruntfiles: {
        files: ['./gruntfile.js', 'grunt.conf.js'],
        tasks: ['newer:jshint:gruntfiles'],
        options: {
          livereload: false
        }
      },
      tests: {
        files: ['src/**/*.spec.js', 'src/**/*.e2e.js', 'src/**/*.protractor.js'],
        tasks: ['newer:copy:build_karma', 'newer:copy:build_unit', 'newer:copy:build_protractor']
      }
    }
  };

  /////////////////
  grunt.initConfig(
    grunt.util._.extend(gruntTasks, gruntConfig)
  );

  /*
   * Helpers
   */
   /////////////////
  function findModuleFilesIn(modulePath){
    var output = [],
        i;

    for(i = 0; i <= gruntConfig.module_file_order.length-1; i++){
      output.push(modulePath + gruntConfig.module_file_order[i]);
    }

    return output;
  }

  //////////////
  function processBuildScripts(content){
    var buildScripts = [],
        globFiles,
        customModules = gruntConfig.build.vendor_js
                        .concat(findModuleFilesIn('./src/app/'))
                        .concat(findModuleFilesIn('./src/common/'));

    customModules.forEach(function(module){
      globFiles = glob.sync(module);

      if(globFiles.length > 0){
        buildScripts = buildScripts.concat(globFiles);
      }
    });

    return grunt.template.process(content, {
      data: {
        scripts: buildScripts
      }
    });
  }

  /*
   * Tasks
   */
  grunt.registerTask('default', ['jshint', 'build', 'karma:unit', 'watch']);
  grunt.registerTask('build', ['copy:build_app_js', 'copy:build_vendor_js', 'copy:build_views', 'copy:build_fonts','copy:build_index', 'copy:build_unit', 'copy:build_protractor', 'copy:build_karma', 'copy:build_assets', 'less:build_less', 'cssmin:build_css', 'clean:build_css_clean']);
  grunt.registerTask('compile', []);
  grunt.registerTask('test:unit', ['karma:unit']);
  grunt.registerTask('test:e2e', ['protractor']);
  grunt.registerTask('test', ['karma:unit', 'protractor']);
};<commit_msg>added 2 handy shell commands for updating and starting selenium<commit_after>module.exports = function(grunt) {
  /*
   * Include grunt configuration
   */
  var gruntConfig = require( './config/grunt.conf.js' );

  /*
   * Helpers (preparing for grunt util deprecation)
   */
  var glob = require('glob');

  /*
   * Time grunt execution
   */
  require('time-grunt')(grunt);

  /*
   * JIT Grunt will automatically load other npm tasks
   */
  require('jit-grunt')(grunt);
  grunt.loadNpmTasks('grunt-protractor-runner');

  /*
   * Configuration
   */
  var gruntTasks = {
    //////////////
    pkg: grunt.file.readJSON('package.json'),
    /*
     * Placed at the top of the compiled source files.
     */
    meta: {
      banner:
        '/*\n' +
        ' * <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' +
        ' * <%= pkg.repository.url %>\n' +
        ' *\n' +
        ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
        ' * Licensed <%= pkg.licenses.type %> <<%= pkg.licenses.url %>>\n' +
        ' */\n'
    },
    //////////////
    shell: {
      run_build_server: {
        command: './server/build-server.sh'
      },
      run_selenium: {
        command: './node_modules/protractor/bin/webdriver-manager start'
      },
      update_selenium: {
        command: './node_modules/protractor/bin/webdriver-manager update'
      }
    },
    //////////////
    copy: {
      build_app_js: {
        src: [
          findModuleFilesIn('./src/app/'),
          findModuleFilesIn('./src/common/'),
          './src/app/**/*.json'
        ],
        dest: '<%= build_dir %>'
      },
      build_unit: {
        src: ['./src/**/*.spec.js'],
        dest: '<%= build_dir %>'
      },
      build_vendor_js: {
        src: ['<%= build.vendor_js %>'],
        dest: '<%= build_dir %>'
      },
      build_views: {
        cwd: './src',
        src: ['**/*.html', '!**/index.html'],
        dest: '<%= build_dir %>/views/',
        expand: true,
        flatten: true
      },
      build_index: {
        cwd: './src',
        src: ['index.html'],
        dest: '<%= build_dir %>',
        expand: true,
        flatten: true,
        options: {
          process: processBuildScripts
        }
      },
      build_assets: {
        cwd: './src',
        src: [
          'assets/**/*',
          '!assets/**/*.less',
          '!assets/**/*.css'
        ],
        dest: '<%= build_dir %>src/assets/',
        expand: true,
        flatten: true
      },
      build_fonts: {
        src: ['<%= common.vendor_fonts %>'],
        dest: '<%= build_dir %>src/assets/fonts/',
        expand: true,
        flatten: true
      },
      build_karma: {
        src: ['./config/karma.conf.js'],
        dest: '<%= build_dir %>',
        options: {
          process: processBuildScripts
        }
      },
      build_protractor: {
        cwd: './src',
        src: ['**/*.protractor.js', '**/*.e2e.js'],
        expand: true,
        flatten: true,
        dest: '<%= build_dir %>src/e2e/'
      }
    },
    /////////////////
    clean: {
      build_css_clean: ['<%= build_dir %>/src/assets/css/app.custom.css']
    },
    /////////////////
    less: {
      build_less: {
        src: ['./src/assets/**/*.less'],
        dest: '<%= build_dir %>/src/assets/css/app.custom.css',
        options: {
          cleancss: true,
          compress: true
        }
      }
    },
    /////////////////
    cssmin: {
      build_css: {
        src: [
          '<%= build.vendor_css %>',
          './src/assets/**/*.css',
          '<%= build_dir %>/src/assets/css/app.custom.css'
        ],
        dest: '<%= build_dir %>/src/assets/css/app.min.css'
      }
    },
    /////////////////
    jshint: {
      options: {
        jshintrc: true
      },
      src_js: ['./src/**/*.js'],
      gruntfiles: ['./gruntfile.js', 'grunt.conf.js']
    },
    /////////////////
    karma: {
      options: {
        configFile: '<%= build_dir %>/config/karma.conf.js'
      },
      unit: {
        port: 9191,
        background: false
      },
      continuous: {
        singleRun: false,
        autoWatch: true
      }
    },
    /////////////////
    protractor: {
      options: {
        configFile: "./config/protractor.conf.js", // Default config file
        keepAlive: true, // If false, the grunt process stops when the test fails.
        noColor: false, // If true, protractor will not use colors in its output.
        args: {}
      },
      build: {},
      /*compile: {
        options: {
          configFile: "protractor/protractor-prod.conf.js"
        }
      }*/
    },
    /////////////////
    watch: {
      options: {
        livereload: true
      },
      src_js: {
        files: ['./src/**/*.js', './src/**/*.json'],
        tasks: ['newer:jshint:src_js', 'newer:copy:build_app_js']
      },
      src_html: {
        files: ['./src/**/*.html', '!./src/index.html'],
        tasks: ['newer:copy:build_views']
      },
      src_index: {
        files: ['./src/index.html'],
        tasks: ['copy:build_index']
      },
      src_stylesheets: {
        files: ['./src/assets/**/*.less', './src/assets/**/*.css'],
        tasks: ['newer:less:build_less', 'cssmin:build_css', 'clean:build_css_clean']
      },
      src_assets: {
        files: ['./src/assets/**/*', '!./src/assets/**/*.less', '!./src/assets/**/*.css'],
        tasks: ['newer:copy:build_assets']
      },
      gruntfiles: {
        files: ['./gruntfile.js', 'grunt.conf.js'],
        tasks: ['newer:jshint:gruntfiles'],
        options: {
          livereload: false
        }
      },
      tests: {
        files: ['src/**/*.spec.js', 'src/**/*.e2e.js', 'src/**/*.protractor.js'],
        tasks: ['newer:copy:build_karma', 'newer:copy:build_unit', 'newer:copy:build_protractor']
      }
    }
  };

  /////////////////
  grunt.initConfig(
    grunt.util._.extend(gruntTasks, gruntConfig)
  );

  /*
   * Helpers
   */
   /////////////////
  function findModuleFilesIn(modulePath){
    var output = [],
        i;

    for(i = 0; i <= gruntConfig.module_file_order.length-1; i++){
      output.push(modulePath + gruntConfig.module_file_order[i]);
    }

    return output;
  }

  //////////////
  function processBuildScripts(content){
    var buildScripts = [],
        globFiles,
        customModules = gruntConfig.build.vendor_js
                        .concat(findModuleFilesIn('./src/app/'))
                        .concat(findModuleFilesIn('./src/common/'));

    customModules.forEach(function(module){
      globFiles = glob.sync(module);

      if(globFiles.length > 0){
        buildScripts = buildScripts.concat(globFiles);
      }
    });

    return grunt.template.process(content, {
      data: {
        scripts: buildScripts
      }
    });
  }

  /*
   * Tasks
   */
  grunt.registerTask('default', ['jshint', 'build', 'karma:unit', 'watch']);
  grunt.registerTask('build', ['copy:build_app_js', 'copy:build_vendor_js', 'copy:build_views', 'copy:build_fonts','copy:build_index', 'copy:build_unit', 'copy:build_protractor', 'copy:build_karma', 'copy:build_assets', 'less:build_less', 'cssmin:build_css', 'clean:build_css_clean']);
  grunt.registerTask('compile', []);
  grunt.registerTask('test:unit', ['karma:unit']);
  grunt.registerTask('test:e2e', ['protractor']);
  grunt.registerTask('test', ['karma:unit', 'protractor']);
};<|endoftext|>


<commit_before>import React from "react-native";
import Icon from "./icon";
import AvatarController from "../controllers/avatar-controller";
import TouchFeedback from "./touch-feedback";
import routes from "../utils/routes";
import timeUtils from "../../lib/time-utils";

const {
	StyleSheet,
	View,
	Text,
	TouchableHighlight,
	PixelRatio
} = React;

const styles = StyleSheet.create({
	item: {
		backgroundColor: "#fff",
		borderColor: "rgba(0, 0, 0, .08)",
		borderBottomWidth: 1 / PixelRatio.get()
	},
	note: {
		flexDirection: "row"
	},
	avatarContainer: {
		marginHorizontal: 16,
		marginVertical: 12
	},
	avatar: {
		height: 36,
		width: 36,
		borderRadius: 18,
		backgroundColor: "rgba(0, 0, 0, .16)"
	},
	image: {
		flex: 1,
		resizeMode: "cover",
		borderRadius: 18
	},
	content: {
		flex: 1,
		marginVertical: 8
	},
	title: {
		lineHeight: 21,
		color: "#999"
	},
	summary: {
		lineHeight: 18,
		fontSize: 12,
		color: "#999"
	},
	strong: {
		color: "#555"
	},
	timestampContainer: {
		flexDirection: "row"
	},
	timestamp: {
		fontSize: 11,
		marginVertical: 2,
		color: "#aaa",
		marginLeft: 4,
		paddingHorizontal: 4
	},
	icon: {
		fontSize: 12,
		color: "#000",
		marginVertical: 4,
		opacity: 0.3
	},
	close: {
		paddingVertical: 12,
		paddingHorizontal: 16
	},
	badge: {
		position: "absolute",
		alignItems: "center",
		bottom: -2,
		right: -2,
		height: 17,
		width: 17,
		borderRadius: 9,
		borderColor: "#fff",
		borderWidth: 2
	},
	badgeIcon: {
		marginVertical: 1,
		textAlign: "center",
		fontSize: 10,
		color: "#fff"
	}
});

export default class NotificationCenterItem extends React.Component {
	_extractPart(note, index) {
		return typeof note.group === "string" ? note.group.split("/")[index] : null;
	}

	_getThread(note) {
		const thread = this._extractPart(note, 1);

		return (thread === "all" || !thread) ? null : thread;
	}

	_getRoom(note) {
		return this._extractPart(note, 0);
	}

	_getSummary(note) {
		const { noteData, noteType, count } = note;

		const room = this._getRoom(this.props.note);

		const summary = [];

		switch (noteType) {
		case "mention":
			if (count > 1) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new mentions in");
			} else {
				summary.push(<Text key={1} style={styles.strong}>{noteData.from}</Text>, " mentioned you in");
			}

			if (noteData.title) {
				summary.push(" ", <Text key={2} style={styles.strong}>{noteData.title}</Text>);
			}

			summary.push(" - ", <Text key={3} style={styles.strong}>{room}</Text>);

			break;
		case "reply":
			if (count > 1) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new replies");
			} else {
				summary.push(<Text key={1} style={styles.strong}>{noteData.from}</Text>, " replied");
			}

			if (noteData.title) {
				summary.push(" to ", <Text key={2} style={styles.strong}>{noteData.title}</Text>);
			}

			summary.push(" in ", <Text key={3} style={styles.strong}>{room}</Text>);

			break;
		case "thread":
			if (count > 1) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new discussions");
			} else {
				summary.push(<Text key={1} style={styles.strong}>{noteData.from}</Text>, " started a discussion");

				if (noteData.title) {
					summary.push(" on ", <Text key={2} style={styles.strong}>{noteData.title}</Text>);
				}
			}

			summary.push(" in ", <Text key={3} style={styles.strong}>{room}</Text>);

			break;
		default:
			if (count > 1) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new notifications");
			} else {
				summary.push("New notification from ", <Text key={1} style={styles.strong}>{noteData.from}</Text>);
			}

			summary.push(" in ", <Text key={2} style={styles.strong}>{room}</Text>);
		}

		return summary;
	}

	_getIconColor() {
		const { note } = this.props;

		switch (note.noteType) {
		case "mention":
			return "#ff5722";
		case "reply":
			return "#2196F3";
		case "thread":
			return "#009688";
		default:
			return "#673ab7";
		}
	}

	_getIconName() {
		const { note } = this.props;

		switch (note.noteType) {
		case "mention":
			return "person";
		case "reply":
			return "reply";
		case "thread":
			return "create";
		default:
			return "notifications";
		}
	}

	_onPress() {
		const { note, navigator } = this.props;

		const room = this._getRoom(note);
		const thread = this._getThread(note);

		switch (note.noteType) {
		case "mention":
		case "reply":
		case "thread":
			navigator.push(routes.chat({
				thread,
				room
			}));

			break;
		default:
			navigator.push(routes.room({ room }));
		}
	}

	_onDismiss() {
		this.props.dismissNote(this.props.note);
	}

	render() {
		const { note } = this.props;

		return (
			<View style={styles.item}>
				<TouchFeedback onPress={this._onPress.bind(this)}>
					<View style={styles.note}>
						<View style={styles.avatarContainer}>
							<View style={styles.avatar}>
								<AvatarController
									size={36}
									nick={note.noteData.from}
									style={styles.image}
								/>
							</View>
							<View style={[ styles.badge, { backgroundColor: this._getIconColor() } ]}>
								<Icon name={this._getIconName()} style={styles.badgeIcon} />
							</View>
						</View>
						<View style={styles.content}>
							<View>
								<Text numberOfLines={5} style={styles.title} >{this._getSummary(note)}</Text>
							</View>
							<View>
								<Text numberOfLines={1} style={styles.summary} >{note.noteData.text}</Text>
							</View>
							<View style={styles.timestampContainer}>
								<Icon name="access-time" style={styles.icon} />
								<Text style={styles.timestamp}>{timeUtils.long(note.time)}</Text>
							</View>
						</View>
						<TouchableHighlight underlayColor="rgba(0, 0, 0, .08)" onPress={this._onDismiss.bind(this)}>
							<View style={styles.close}>
								<Icon name="close" style={styles.icon} />
							</View>
						</TouchableHighlight>
					</View>
				</TouchFeedback>
			</View>
		);
	}
}

NotificationCenterItem.propTypes = {
	note: React.PropTypes.shape({
		count: React.PropTypes.number,
		group: React.PropTypes.string.isRequired,
		noteType: React.PropTypes.string.isRequired,
		noteData: React.PropTypes.shape({
			title: React.PropTypes.string,
			text: React.PropTypes.string.isRequired,
			from: React.PropTypes.string.isRequired
		}).isRequired
	}).isRequired,
	dismissNote: React.PropTypes.func.isRequired,
	navigator: React.PropTypes.object.isRequired
};
<commit_msg>Go to room when more than 1 thread notifications<commit_after>import React from "react-native";
import Icon from "./icon";
import AvatarController from "../controllers/avatar-controller";
import TouchFeedback from "./touch-feedback";
import routes from "../utils/routes";
import timeUtils from "../../lib/time-utils";

const {
	StyleSheet,
	View,
	Text,
	TouchableHighlight,
	PixelRatio
} = React;

const styles = StyleSheet.create({
	item: {
		backgroundColor: "#fff",
		borderColor: "rgba(0, 0, 0, .08)",
		borderBottomWidth: 1 / PixelRatio.get()
	},
	note: {
		flexDirection: "row"
	},
	avatarContainer: {
		marginHorizontal: 16,
		marginVertical: 12
	},
	avatar: {
		height: 36,
		width: 36,
		borderRadius: 18,
		backgroundColor: "rgba(0, 0, 0, .16)"
	},
	image: {
		flex: 1,
		resizeMode: "cover",
		borderRadius: 18
	},
	content: {
		flex: 1,
		marginVertical: 8
	},
	title: {
		lineHeight: 21,
		color: "#999"
	},
	summary: {
		lineHeight: 18,
		fontSize: 12,
		color: "#999"
	},
	strong: {
		color: "#555"
	},
	timestampContainer: {
		flexDirection: "row"
	},
	timestamp: {
		fontSize: 11,
		marginVertical: 2,
		color: "#aaa",
		marginLeft: 4,
		paddingHorizontal: 4
	},
	icon: {
		fontSize: 12,
		color: "#000",
		marginVertical: 4,
		opacity: 0.3
	},
	close: {
		paddingVertical: 12,
		paddingHorizontal: 16
	},
	badge: {
		position: "absolute",
		alignItems: "center",
		bottom: -2,
		right: -2,
		height: 17,
		width: 17,
		borderRadius: 9,
		borderColor: "#fff",
		borderWidth: 2
	},
	badgeIcon: {
		marginVertical: 1,
		textAlign: "center",
		fontSize: 10,
		color: "#fff"
	}
});

export default class NotificationCenterItem extends React.Component {
	_extractPart(note, index) {
		return typeof note.group === "string" ? note.group.split("/")[index] : null;
	}

	_getThread(note) {
		const thread = this._extractPart(note, 1);

		return (thread === "all" || !thread) ? null : thread;
	}

	_getRoom(note) {
		return this._extractPart(note, 0);
	}

	_getSummary(note) {
		const { noteData, noteType, count } = note;

		const room = this._getRoom(this.props.note);

		const summary = [];

		switch (noteType) {
		case "mention":
			if (count > 1) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new mentions in");
			} else {
				summary.push(<Text key={1} style={styles.strong}>{noteData.from}</Text>, " mentioned you in");
			}

			if (noteData.title) {
				summary.push(" ", <Text key={2} style={styles.strong}>{noteData.title}</Text>);
			}

			summary.push(" - ", <Text key={3} style={styles.strong}>{room}</Text>);

			break;
		case "reply":
			if (count > 1) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new replies");
			} else {
				summary.push(<Text key={1} style={styles.strong}>{noteData.from}</Text>, " replied");
			}

			if (noteData.title) {
				summary.push(" to ", <Text key={2} style={styles.strong}>{noteData.title}</Text>);
			}

			summary.push(" in ", <Text key={3} style={styles.strong}>{room}</Text>);

			break;
		case "thread":
			if (count > 1) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new discussions");
			} else {
				summary.push(<Text key={1} style={styles.strong}>{noteData.from}</Text>, " started a discussion");

				if (noteData.title) {
					summary.push(" on ", <Text key={2} style={styles.strong}>{noteData.title}</Text>);
				}
			}

			summary.push(" in ", <Text key={3} style={styles.strong}>{room}</Text>);

			break;
		default:
			if (count > 1) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new notifications");
			} else {
				summary.push("New notification from ", <Text key={1} style={styles.strong}>{noteData.from}</Text>);
			}

			summary.push(" in ", <Text key={2} style={styles.strong}>{room}</Text>);
		}

		return summary;
	}

	_getIconColor() {
		const { note } = this.props;

		switch (note.noteType) {
		case "mention":
			return "#ff5722";
		case "reply":
			return "#2196F3";
		case "thread":
			return "#009688";
		default:
			return "#673ab7";
		}
	}

	_getIconName() {
		const { note } = this.props;

		switch (note.noteType) {
		case "mention":
			return "person";
		case "reply":
			return "reply";
		case "thread":
			return "create";
		default:
			return "notifications";
		}
	}

	_onPress() {
		const { note, navigator } = this.props;

		const room = this._getRoom(note);
		const thread = this._getThread(note);

		switch (note.noteType) {
		case "mention":
		case "reply":
			navigator.push(routes.chat({
				thread,
				room
			}));

			break;
		case "thread":
			if (note.count > 1) {
				navigator.push(routes.room({ room }));
			} else {
				navigator.push(routes.chat({
					thread: note.ref,
					room
				}));
			}

			break;
		default:
			navigator.push(routes.room({ room }));
		}
	}

	_onDismiss() {
		this.props.dismissNote(this.props.note);
	}

	render() {
		const { note } = this.props;

		return (
			<View style={styles.item}>
				<TouchFeedback onPress={this._onPress.bind(this)}>
					<View style={styles.note}>
						<View style={styles.avatarContainer}>
							<View style={styles.avatar}>
								<AvatarController
									size={36}
									nick={note.noteData.from}
									style={styles.image}
								/>
							</View>
							<View style={[ styles.badge, { backgroundColor: this._getIconColor() } ]}>
								<Icon name={this._getIconName()} style={styles.badgeIcon} />
							</View>
						</View>
						<View style={styles.content}>
							<View>
								<Text numberOfLines={5} style={styles.title} >{this._getSummary(note)}</Text>
							</View>
							<View>
								<Text numberOfLines={1} style={styles.summary} >{note.noteData.text}</Text>
							</View>
							<View style={styles.timestampContainer}>
								<Icon name="access-time" style={styles.icon} />
								<Text style={styles.timestamp}>{timeUtils.long(note.time)}</Text>
							</View>
						</View>
						<TouchableHighlight underlayColor="rgba(0, 0, 0, .08)" onPress={this._onDismiss.bind(this)}>
							<View style={styles.close}>
								<Icon name="close" style={styles.icon} />
							</View>
						</TouchableHighlight>
					</View>
				</TouchFeedback>
			</View>
		);
	}
}

NotificationCenterItem.propTypes = {
	note: React.PropTypes.shape({
		count: React.PropTypes.number,
		group: React.PropTypes.string.isRequired,
		noteType: React.PropTypes.string.isRequired,
		noteData: React.PropTypes.shape({
			title: React.PropTypes.string,
			text: React.PropTypes.string.isRequired,
			from: React.PropTypes.string.isRequired
		}).isRequired
	}).isRequired,
	dismissNote: React.PropTypes.func.isRequired,
	navigator: React.PropTypes.object.isRequired
};
<|endoftext|>


<commit_before>/* This module uses a give ip to visit the whole urls in the bucket assigned to it
*/
module.exports = function(bucketExplorer) {
	//
	var Spooky = require('spooky');
	var ipQueue = [];
	var ipQueueIndex = 0;
	var bucket;
	var daemonStarted = false;
	var exitFlag = false;

    //////
    var setBucket =  function(bucketObj){
    	 console.log(bucketObj);
    	 bucket = bucketObj;
    	 for(var i=0; i<bucket.urls.length; i++){
              bucket.urls[i].visited = 0;
              bucket.urls[i].statusText = 'No status yet';
    	 };
    	 console.log(bucket);
    	 console.log('bucket set in visitor');
    };

    var getBucket = function(){
    	return bucket;
    };

    var updateBucket = function(bucketObj , meta){
    	console.log(meta);
    	if(bucket){
            if(bucketObj._id+'' == bucket._id){
	           if(meta.action == 0){
	           	   console.log('Deleting url in this bucket');
                   bucket.urls.splice(meta.index , 1);
	           }
	           else if(meta.action == 1) {
                   console.log('Updating url in this bucket');
                   bucket = bucketObj;
	           }
	    	}
	    	else{
	    	   console.log('Just passing by');
	    	}
    	}
    	else{
    		 console.log('Bucket empty here');
    	}
    }

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

	var runGhostProxy = function(ip , urlsArr , index , cb){
		console.log('starting ghost');
		console.log('process starting '+ip+' '+urlsArr[index].urlName+' '+urlsArr[index].selector);

	    var spooky = new Spooky({
			child: {
				transport: 'http',
				proxy: ip
			},
			casper: {
				logLevel: 'debug',
				verbose: true,
				options: {
				   clientScripts: ['http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js'],
				   pageSettings: {
				        Referer: 'https://www.google.com.ng'
				    }
				}
			}
		 },
		 function(err){
		   if (err) {
				e = new Error('Failed to initialize SpookyJS');
				e.details = err;
				throw e;
			}

			//start the main site visiting process
			console.log('here init =========================== '+url+' '+selector);

			//
			spooky.start(url);
			spooky.then([{url:urlsArr[index].urlName , selector:urlsArr[index].selector} , function(){

                 this.viewport(1024, 768, function() {
					  console.log('Viewport size changed');

			          //
                      if(selector=='none'){
							 this.then(function(){
							 	  this.wait(10000 , function(){
								    this.emit('done', 'Hello, from ' + this.getCurrentUrl());
								    phantom.clearCookies();
							 	  	this.clear();
							 	  });

							 });
						}

						//General case
						else{
						   this.then(function(){
						   	   this.waitForSelector(selector , function(){
						   	   	  this.wait(15000 , function(){
					   	   	  	    this.thenClick(selector , function() {
										this.wait(5000 , function(){
										    this.emit('done', 'Hello, from ' + this.getCurrentUrl());
										    phantom.clearCookies();
									 	  	this.clear();
									 	});
								    });
						   	   	  });

						   	   } , function(){
						   	   	     this.emit('done', 'The selector was not found');
								     phantom.clearCookies();
							 	  	 this.clear();
						   	   } , 20000);
						   });
						}

				    });

			}]);

            //
			spooky.run();
		});

		//logs and listeners
		spooky.on('error', function (e, stack) {
			console.log('here');//
			console.error(e);
			Greeting = e;

			if (stack) {
				console.log(stack);
				Greeting = stack;
			}
		});

		//
		spooky.on('console', function (line) {
			console.log(line);
		});

		//
		spooky.on('done', function (greeting) {
			console.log(greeting);
			bucket.urls[index].statusText = greeting;
			if(index >= urlsArr.length){
               runGhostProxy(ip , urlsArr , index++ , cb);
			}
            else{
                console.log('This round done visiting');
                cb();
            }

		});
	};

	//
	var startVisitingDeamon = function(){
		if(ipQueueIndex < ipQueue.length){
            runGhostProxy(ipQueue[ipQueueIndex] , bucket.urls , 0 , function(){
            	 startVisitingDeamon();
            });
		}
		else{
           console.log('No ips in queue yet retrying in 14 secs');
           setTimeout(function(){
           	  if(!exitFlag){
                    startVisitingDeamon();
               }
               else{
                   console.log('Visiting All Done. Exiting......');
                   process.exit(0);
               }
           } ,15000);
		}
	};

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    var visitWith = function(ip){
        if(ipQueue.indexOf(ip) < 0){
        	console.log('Adding '+ip+' to visiting ip queue');
            ipQueue.push(ip);
        }
        else{
        	console.log('ip already exists in queue');
        }

        if(!daemonStarted){
        	console.log('Starting visiting daemon');
            startVisitingDeamon();
        }
    }

    //
    var exitWhenDone = function(){
         exitFlag = true;
    }

	return {
	    visitWith:visitWith,
	    getBucket:getBucket,
	    setBucket:setBucket,
	    updateBucket:updateBucket,
	    exitWhenDone:exitWhenDone
	}

};<commit_msg>Next commit<commit_after>/* This module uses a give ip to visit the whole urls in the bucket assigned to it
*/
module.exports = function(bucketExplorer) {
	//
	var Spooky = require('spooky');
	var ipQueue = [];
	var ipQueueIndex = 0;
	var bucket;
	var daemonStarted = false;
	var exitFlag = false;

    ///
    var setBucket =  function(bucketObj){
    	 console.log(bucketObj);
    	 bucket = bucketObj;
    	 for(var i=0; i<bucket.urls.length; i++){
              bucket.urls[i].visited = 0;
              bucket.urls[i].statusText = 'No status yet';
    	 };
    	 console.log(bucket);
    	 console.log('bucket set in visitor');
    };

    var getBucket = function(){
    	return bucket;
    };

    var updateBucket = function(bucketObj , meta){
    	console.log(meta);
    	if(bucket){
            if(bucketObj._id+'' == bucket._id){
	           if(meta.action == 0){
	           	   console.log('Deleting url in this bucket');
                   bucket.urls.splice(meta.index , 1);
	           }
	           else if(meta.action == 1) {
                   console.log('Updating url in this bucket');
                   bucket = bucketObj;
	           }
	    	}
	    	else{
	    	   console.log('Just passing by');
	    	}
    	}
    	else{
    		 console.log('Bucket empty here');
    	}
    }

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

	var runGhostProxy = function(ip , urlsArr , index , cb){
		console.log('starting ghost');
		console.log('process starting '+ip+' '+urlsArr[index].urlName+' '+urlsArr[index].selector);

	    var spooky = new Spooky({
			child: {
				transport: 'http',
				proxy: ip
			},
			casper: {
				logLevel: 'debug',
				verbose: true,
				options: {
				   clientScripts: ['http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js'],
				   pageSettings: {
				        Referer: 'https://www.google.com.ng'
				    }
				}
			}
		 },
		 function(err){
		   if (err) {
				e = new Error('Failed to initialize SpookyJS');
				e.details = err;
				throw e;
			}

			//start the main site visiting process
			console.log('here init =========================== '+url+' '+selector);

			//
			spooky.start(url);
			spooky.then([{url:urlsArr[index].urlName , selector:urlsArr[index].selector} , function(){

                 this.viewport(1024, 768, function() {
					  console.log('Viewport size changed');

			          //
                      if(selector=='none'){
							 this.then(function(){
							 	  this.wait(10000 , function(){
								    this.emit('done', 'Hello, from ' + this.getCurrentUrl());
								    phantom.clearCookies();
							 	  	this.clear();
							 	  });

							 });
						}

						//General case
						else{
						   this.then(function(){
						   	   this.waitForSelector(selector , function(){
						   	   	  this.wait(15000 , function(){
					   	   	  	    this.thenClick(selector , function() {
										this.wait(5000 , function(){
										    this.emit('done', 'Hello, from ' + this.getCurrentUrl());
										    phantom.clearCookies();
									 	  	this.clear();
									 	});
								    });
						   	   	  });

						   	   } , function(){
						   	   	     this.emit('done', 'The selector was not found');
								     phantom.clearCookies();
							 	  	 this.clear();
						   	   } , 20000);
						   });
						}

				    });

			}]);

            //
			spooky.run();
		});

		//logs and listeners
		spooky.on('error', function (e, stack) {
			console.log('here');//
			console.error(e);
			Greeting = e;

			if (stack) {
				console.log(stack);
				Greeting = stack;
			}
		});

		//
		spooky.on('console', function (line) {
			console.log(line);
		});

		//
		spooky.on('done', function (greeting) {
			console.log(greeting);
			bucket.urls[index].statusText = greeting;
			if(index >= urlsArr.length){
               runGhostProxy(ip , urlsArr , index++ , cb);
			}
            else{
                console.log('This round done visiting');
                cb();
            }

		});
	};

	//
	var startVisitingDeamon = function(){
		if(ipQueueIndex < ipQueue.length){
            runGhostProxy(ipQueue[ipQueueIndex] , bucket.urls , 0 , function(){
            	 startVisitingDeamon();
            });
		}
		else{
           console.log('No ips in queue yet retrying in 14 secs');
           setTimeout(function(){
           	  if(!exitFlag){
                    startVisitingDeamon();
               }
               else{
                   console.log('Visiting All Done. Exiting......');
                   process.exit(0);
               }
           } ,15000);
		}
	};

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    var visitWith = function(ip){
        if(ipQueue.indexOf(ip) < 0){
        	console.log('Adding '+ip+' to visiting ip queue');
            ipQueue.push(ip);
        }
        else{
        	console.log('ip already exists in queue');
        }

        if(!daemonStarted){
        	console.log('Starting visiting daemon');
            startVisitingDeamon();
        }
    }

    //
    var exitWhenDone = function(){
         exitFlag = true;
    }

	return {
	    visitWith:visitWith,
	    getBucket:getBucket,
	    setBucket:setBucket,
	    updateBucket:updateBucket,
	    exitWhenDone:exitWhenDone
	}

};<|endoftext|>


<commit_before>module.exports = function (grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON("package.json"),

        haxe: {
            project: {
                hxml: "build.hxml"
            },
            samples: {
                hxml: "samples.hxml"
            }
        },

        uglify: {
            options: {
                compress: {
                    drop_console: true
                },
                banner: "/*!" +
                        "\n * <%= pkg.name %> - v<%= pkg.version %>" +
                        "\n * Compiled on <%= grunt.template.today('dd-mm-yyyy hh:mm:ss') %>" +
                        "\n * <%= pkg.name %> is licensed under the MIT License." +
                        "\n * Copyright (c) 2015-2016 <%= pkg.author.name %>\n*/\n"
            },
            target: {
                files: {
                    "dist/waud.min.js": ["dist/waud.min.js"]
                }
            }
        },

        shell: {
            npm: {
                command: "mkdir npm-publish || true && cp -r src dist package.json LICENSE README.md ./npm-publish/ && npm publish ./npm-publish/ && rm -r npm-publish"
            },
            sample: {
                command: "cp ./dist/waud.min.js sample/ && cp -r ./sample/ ../adireddy.github.io/demos/waud/"
            }
        },

        zip: {
            "waud.zip": ["src/*", "haxelib.json", "README.md", "LICENSE"]
        },

        yuidoc: {
        compile: {
            name: '<%= pkg.name %>',
                description: '<%= pkg.description %>',
                version: '<%= pkg.version %>',
                url: '<%= pkg.repository.url %>',
                options: {
                linkNatives: "true",
                    attributesEmit: "true",
                    selleck: "true",
                    extension: ".hx",
                    paths: "./src",
                    outdir: "../adireddy.github.io/docs/waud/",
                    themedir: "../adireddy.github.io/docs/yui/themes/waud-theme",
                    logo: "./sample/assets/logo.png"
            }
        }
    }
    });

    grunt.loadNpmTasks("grunt-haxe");
    grunt.loadNpmTasks('grunt-contrib-yuidoc');
    grunt.loadNpmTasks("grunt-zip");
    grunt.loadNpmTasks("grunt-shell");
    grunt.registerTask("default", ["haxe"]);
};<commit_msg>build update<commit_after>module.exports = function (grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON("package.json"),

        haxe: {
            project: {
                hxml: "build.hxml"
            },
            samples: {
                hxml: "samples.hxml"
            }
        },

        uglify: {
            options: {
                compress: {
                    drop_console: true
                },
                banner: "/*!" +
                        "\n * <%= pkg.name %> - v<%= pkg.version %>" +
                        "\n * Compiled on <%= grunt.template.today('dd-mm-yyyy hh:mm:ss') %>" +
                        "\n * <%= pkg.name %> is licensed under the MIT License." +
                        "\n * Copyright (c) 2015-2016 <%= pkg.author.name %>\n*/\n"
            },
            target: {
                files: {
                    "dist/waud.min.js": ["dist/waud.min.js"]
                }
            }
        },

        shell: {
            npm: {
                command: "mkdir npm-publish || true && cp -r src dist package.json LICENSE README.md ./npm-publish/ && npm publish ./npm-publish/ && rm -r npm-publish"
            },
            samples: {
                command: "cp ./dist/waud.min.js sample/ && cp -r ./sample/ ../adireddy.github.io/demos/waud/"
            }
        },

        zip: {
            "waud.zip": ["src/*", "haxelib.json", "README.md", "LICENSE"]
        },

        yuidoc: {
        compile: {
            name: '<%= pkg.name %>',
                description: '<%= pkg.description %>',
                version: '<%= pkg.version %>',
                url: '<%= pkg.repository.url %>',
                options: {
                linkNatives: "true",
                    attributesEmit: "true",
                    selleck: "true",
                    extension: ".hx",
                    paths: "./src",
                    outdir: "../adireddy.github.io/docs/waud/",
                    themedir: "../adireddy.github.io/docs/yui/themes/waud-theme",
                    logo: "./sample/assets/logo.png"
            }
        }
    }
    });

    grunt.loadNpmTasks("grunt-haxe");
    grunt.loadNpmTasks('grunt-contrib-yuidoc');
    grunt.loadNpmTasks("grunt-zip");
    grunt.loadNpmTasks("grunt-shell");
    grunt.registerTask("default", ["haxe"]);
};<|endoftext|>


<commit_before>import Backbone from 'backbone';
import d3 from 'd3';
// import Dataset from '../../../models/Dataset';
import myTemplate from './template.html';
import libImage from '../../../images/library.svg';
// import candela from './../../../../../src';

let VisualizationLibrary = Backbone.View.extend({
  render: function () {
    let self = this;
    self.$el.html(myTemplate);

    let libraryVisSpecs = [];

    libraryVisSpecs.push({
      name: 'Scatter',
      options: [
        {
          name: 'x',
          type: 'number'
        },
        {
          name: 'y',
          type: 'number'
        },
        {
          name: 'color',
          type: 'string'
        },
        {
          name: 'size',
          type: 'number'
        },
        {
          name: 'shape',
          type: 'string'
        },
        {
          name: 'hover',
          type: 'string'
        }
      ]
    });
    /*
      TODO: build the library from the available
      candela visualizations
    */
    /*
    for (let visName of Object.keys(candela.components)) {
      let spec = {
        name: visName,
        options: candela.components[visName]
          .options.filter(function (option) {
            // TODO: this spec will change again soon
            return Dataset.COMPATIBLE_TYPES.hasOwnProperty(option.type);
          })
      };
      libraryVisSpecs.push(spec);
      console.log(spec);
    }
    */

    let libraryButtons = d3.select('div.visualizationLibrary')
      .selectAll('.circleButton')
      .data(libraryVisSpecs);

    let libraryButtonsEnter = libraryButtons.enter().append('div')
      .attr('class', 'circleButton');
    libraryButtons.exit().remove();

    libraryButtonsEnter.append('img');
    libraryButtons.selectAll('img')
      .attr('src', libImage);

    libraryButtonsEnter.append('span');
    libraryButtons.selectAll('span')
      .text((d) => d.name);

    d3.select('div.libraryInterface').selectAll('.circleButton')
      .on('click', function (d) {
        window.toolchain.setVisualization(d);
        window.layout.overlay.render(null);
      });
  }
});

export default VisualizationLibrary;
<commit_msg>Histogram view<commit_after>import Backbone from 'backbone';
import d3 from 'd3';
// import Dataset from '../../../models/Dataset';
import myTemplate from './template.html';
import libImage from '../../../images/library.svg';
// import candela from './../../../../../src';

let VisualizationLibrary = Backbone.View.extend({
  render: function () {
    let self = this;
    self.$el.html(myTemplate);

    let libraryVisSpecs = [];

    libraryVisSpecs.push({
      name: 'Scatter',
      options: [
        {
          name: 'x',
          type: 'number'
        },
        {
          name: 'y',
          type: 'number'
        },
        {
          name: 'color',
          type: 'string'
        },
        {
          name: 'size',
          type: 'number'
        },
        {
          name: 'shape',
          type: 'string'
        },
        {
          name: 'hover',
          type: 'string'
        }
      ]
    });

    libraryVisSpecs.push({
      name: 'Histogram',
      options: [
        {
          name: 'bin',
          type: 'string'
        }
      ]
    });

    /*
      TODO: build the library from the available
      candela visualizations
    */
    /*
    for (let visName of Object.keys(candela.components)) {
      let spec = {
        name: visName,
        options: candela.components[visName]
          .options.filter(function (option) {
            // TODO: this spec will change again soon
            return Dataset.COMPATIBLE_TYPES.hasOwnProperty(option.type);
          })
      };
      libraryVisSpecs.push(spec);
      console.log(spec);
    }
    */

    let libraryButtons = d3.select('div.visualizationLibrary')
      .selectAll('.circleButton')
      .data(libraryVisSpecs);

    let libraryButtonsEnter = libraryButtons.enter().append('div')
      .attr('class', 'circleButton');
    libraryButtons.exit().remove();

    libraryButtonsEnter.append('img');
    libraryButtons.selectAll('img')
      .attr('src', libImage);

    libraryButtonsEnter.append('span');
    libraryButtons.selectAll('span')
      .text((d) => d.name);

    d3.select('div.libraryInterface').selectAll('.circleButton')
      .on('click', function (d) {
        window.toolchain.setVisualization(d);
        window.layout.overlay.render(null);
      });
  }
});

export default VisualizationLibrary;
<|endoftext|>