<commit_before>angular.module('cg.fileupload', []);

/*

 */
angular.module('cg.fileupload').directive('cgFileUpload', function(cgFileUploadCtrl, $parse) {
  return {
    restrict: 'A',
    scope: {
      accept: '@',
      progress: '=?',
      filename: '=?',
      onupload: '&',
      onerror: '&',
      uploadUrl: '@'
    },
    link: function(scope, elem, attrs) {
      var _finally, _onError, _onLoad, _onProgress, _onUploadStart, ctrl, dropStyle, events, options;
      elem = elem[0];
      _onUploadStart = function(arg) {
        var filename, progress, size;
        size = arg.size, filename = arg.filename, progress = arg.progress;
        scope.size = size;
        scope.filename = filename;
        scope.progress = progress;
        attrs.$set('disabled', true);
        return scope.$evalAsync();
      };
      _onProgress = function(progress) {
        scope.progress = progress;
        return scope.$evalAsync();
      };
      _onLoad = function(file) {
        if (typeof scope.onupload === "function") {
          scope.onupload({
            $file: file
          });
        }
        return _finally();
      };
      _onError = function(e) {
        if (typeof scope.onerror === "function") {
          scope.onerror({
            $error: e
          });
        }
        return _finally();
      };
      _finally = function() {
        attrs.$set('disabled', false);
        scope.progress = 100;
        return scope.$evalAsync();
      };
      attrs.$observe('disabled', function(disabled) {
        if (disabled) {
          return elem.style.cursor = 'not-allowed';
        } else {
          return elem.style.cursor = null;
        }
      });
      options = {
        accept: scope.accept,
        uploadUrl: scope.uploadUrl,
        awscredentials: $parse(attrs.awscredentials)(scope)
      };
      events = {
        onUploadStart: _onUploadStart,
        onProgress: _onProgress,
        onLoad: _onLoad,
        onError: _onError
      };
      ctrl = new cgFileUploadCtrl(elem, options, events);
      if (attrs.droppable === 'true') {
        dropStyle = 'dropping';
        elem.addEventListener('dragenter', function(e) {
          e.preventDefault();
          return true;
        });
        elem.addEventListener('dragleave', function(e) {
          elem.classList.remove(dropStyle);
          return true;
        });
        elem.addEventListener('dragover', function(e) {
          e.preventDefault();
          elem.classList.add(dropStyle);
          return false;
        });
        return elem.addEventListener('drop', function(e) {
          e.preventDefault();
          e.stopPropagation();
          elem.classList.remove(dropStyle);
          ctrl.upload(e.dataTransfer.files[0]);
          return false;
        });
      }
    }
  };
});

var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

angular.module('cg.fileupload').factory('cgFileUploadCtrl', function($timeout, $q) {
  var cgFileUploadCtrl;
  cgFileUploadCtrl = (function() {
    function cgFileUploadCtrl(elem, arg, arg1) {
      this.elem = elem != null ? elem : null;
      this.accept = arg.accept, this.uploadUrl = arg.uploadUrl, this.awscredentials = arg.awscredentials;
      this.onUploadStart = arg1.onUploadStart, this.onProgress = arg1.onProgress, this.onLoad = arg1.onLoad, this.onError = arg1.onError;
      this._errorHandler = bind(this._errorHandler, this);
      this.start = bind(this.start, this);
      this._createInput();
    }

    cgFileUploadCtrl.prototype._createInput = function() {
      var ref;
      if ((ref = this._input) != null) {
        ref.parentElement.removeChild(this._input);
      }
      this._input = document.createElement('input');
      this._input.type = 'file';
      this._input.style.display = 'none';
      if (this.accept) {
        this._input.accept = this.accept;
      }
      this._input.addEventListener('change', (function(_this) {
        return function() {
          return _this.upload(_this._input.files[0]);
        };
      })(this));
      if (this.elem) {
        this.elem.parentElement.appendChild(this._input);
        return this.elem.addEventListener('click', this.start);
      } else {
        return document.body.appendChild(this._input);
      }
    };

    cgFileUploadCtrl.prototype.start = function() {
      if (this._disabled) {
        return;
      }
      return $timeout((function(_this) {
        return function() {
          return _this._input.click();
        };
      })(this));
    };

    cgFileUploadCtrl.prototype._loadHandler = function(file) {
      try {
        if (typeof file !== 'object') {
          file = JSON.parse(file);
        }
        file.size = this._size;
      } catch (undefined) {}
      if (typeof this.onLoad === "function") {
        this.onLoad(file);
      }
      this._disabled = false;
      return this._createInput();
    };

    cgFileUploadCtrl.prototype._errorHandler = function(e) {
      if (typeof this.onError === "function") {
        this.onError(e);
      }
      this._disabled = false;
      return this._createInput();
    };

    cgFileUploadCtrl.prototype._uploadS3 = function(file) {
      var _fileName, _prefixRand, awsS3, bucket, defer, fileParams;
      defer = $q.defer();
      awsS3 = this.awscredentials;
      AWS.config.update({
        signatureVersion: 'v4',
        region: awsS3.region
      });
      AWS.config.credentials = new AWS.Credentials({
        accessKeyId: awsS3.accessKeyId,
        sessionToken: awsS3.sessionToken,
        secretAccessKey: awsS3.secretAccessKey
      });
      bucket = new AWS.S3({
        params: {
          Bucket: awsS3.bucket
        }
      });
      _prefixRand = (Math.floor(Math.random() * 10000)) + "-" + (Date.now()) + "_";
      _fileName = awsS3.destFolder ? awsS3.destFolder + "/" + file.name : file.name;
      _fileName = "" + _prefixRand + _fileName;
      fileParams = {
        Key: _fileName,
        ContentType: file.type,
        Body: file,
        ACL: "public-read"
      };
      bucket.upload(fileParams, function(err, data) {
        if (err) {
          return defer.reject(err);
        } else {
          return defer.resolve({
            url: data.Location
          });
        }
      });
      return defer.promise;
    };

    cgFileUploadCtrl.prototype._uploadWorker = function(file) {
      var data, defer, script, worker, workerUrl;
      defer = $q.defer();
      script = document.querySelectorAll('[src*="file-upload"]')[0];
      workerUrl = script.src.replace('file-upload.js', 'file-upload-worker.js');
      worker = new Worker(workerUrl);
      worker.onmessage = function(e) {
        switch (e.data.message) {
          case 'load':
            return defer.resolve(e.data.body);
          case 'progress':
            return defer.notify(e.data.body);
        }
      };
      worker.onerror = defer.reject;
      data = {
        file: file,
        url: this.uploadUrl
      };
      worker.postMessage(data);
      return defer.promise;
    };

    cgFileUploadCtrl.prototype.upload = function(file) {
      var func;
      if (!file) {
        return;
      }
      this._size = (file.size / Math.pow(1024, 2)).toFixed(2);
      if (typeof this.onUploadStart === "function") {
        this.onUploadStart({
          size: this._size,
          filename: file.name,
          progress: 0
        });
      }
      this._disabled = true;
      func = this.awscredentials ? '_uploadS3' : '_uploadWorker';
      return this[func](file).then((function(_this) {
        return function(data) {
          return _this._loadHandler(data);
        };
      })(this), (function(_this) {
        return function(err) {
          return _this._errorHandler(err);
        };
      })(this), (function(_this) {
        return function(data) {
          return typeof _this.onProgress === "function" ? _this.onProgress(data) : void 0;
        };
      })(this));
    };

    return cgFileUploadCtrl;

  })();
  return cgFileUploadCtrl;
});
<commit_msg>v1.0.8<commit_after>angular.module('cg.fileupload', []);

/*

 */
angular.module('cg.fileupload').directive('cgFileUpload', function(cgFileUploadCtrl, $parse) {
  return {
    restrict: 'A',
    scope: {
      accept: '@',
      progress: '=?',
      filename: '=?',
      onupload: '&',
      onerror: '&',
      uploadUrl: '@'
    },
    link: function(scope, elem, attrs) {
      var _finally, _onError, _onLoad, _onProgress, _onUploadStart, ctrl, dropStyle, events, options;
      elem = elem[0];
      _onUploadStart = function(arg) {
        var filename, progress, size;
        size = arg.size, filename = arg.filename, progress = arg.progress;
        scope.size = size;
        scope.filename = filename;
        scope.progress = progress;
        attrs.$set('disabled', true);
        return scope.$evalAsync();
      };
      _onProgress = function(progress) {
        scope.progress = progress;
        return scope.$evalAsync();
      };
      _onLoad = function(file) {
        if (typeof scope.onupload === "function") {
          scope.onupload({
            $file: file
          });
        }
        return _finally();
      };
      _onError = function(e) {
        if (typeof scope.onerror === "function") {
          scope.onerror({
            $error: e
          });
        }
        return _finally();
      };
      _finally = function() {
        attrs.$set('disabled', false);
        scope.progress = 100;
        return scope.$evalAsync();
      };
      attrs.$observe('disabled', function(disabled) {
        if (disabled) {
          return elem.style.cursor = 'not-allowed';
        } else {
          return elem.style.cursor = null;
        }
      });
      options = {
        accept: scope.accept,
        uploadUrl: scope.uploadUrl,
        awscredentials: $parse(attrs.awscredentials)(scope)
      };
      events = {
        onUploadStart: _onUploadStart,
        onProgress: _onProgress,
        onLoad: _onLoad,
        onError: _onError
      };
      ctrl = new cgFileUploadCtrl(elem, options, events);
      if (attrs.droppable === 'true') {
        dropStyle = 'dropping';
        elem.addEventListener('dragenter', function(e) {
          e.preventDefault();
          return true;
        });
        elem.addEventListener('dragleave', function(e) {
          elem.classList.remove(dropStyle);
          return true;
        });
        elem.addEventListener('dragover', function(e) {
          e.preventDefault();
          elem.classList.add(dropStyle);
          return false;
        });
        return elem.addEventListener('drop', function(e) {
          e.preventDefault();
          e.stopPropagation();
          elem.classList.remove(dropStyle);
          ctrl.upload(e.dataTransfer.files[0]);
          return false;
        });
      }
    }
  };
});

var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

angular.module('cg.fileupload').factory('cgFileUploadCtrl', function($timeout, $q) {
  var cgFileUploadCtrl;
  cgFileUploadCtrl = (function() {
    function cgFileUploadCtrl(elem, arg, arg1) {
      this.elem = elem != null ? elem : null;
      this.accept = arg.accept, this.uploadUrl = arg.uploadUrl, this.awscredentials = arg.awscredentials;
      this.onUploadStart = arg1.onUploadStart, this.onProgress = arg1.onProgress, this.onLoad = arg1.onLoad, this.onError = arg1.onError;
      this._errorHandler = bind(this._errorHandler, this);
      this.start = bind(this.start, this);
      this._createInput();
    }

    cgFileUploadCtrl.prototype._createInput = function() {
      var ref;
      if ((ref = this._input) != null) {
        ref.parentElement.removeChild(this._input);
      }
      this._input = document.createElement('input');
      this._input.type = 'file';
      this._input.style.display = 'none';
      if (this.accept) {
        this._input.accept = this.accept;
      }
      this._input.addEventListener('change', (function(_this) {
        return function() {
          return _this.upload(_this._input.files[0]);
        };
      })(this));
      if (this.elem) {
        this.elem.parentElement.appendChild(this._input);
        return this.elem.addEventListener('click', this.start);
      } else {
        return document.body.appendChild(this._input);
      }
    };

    cgFileUploadCtrl.prototype.start = function() {
      if (this._disabled) {
        return;
      }
      return $timeout((function(_this) {
        return function() {
          return _this._input.click();
        };
      })(this));
    };

    cgFileUploadCtrl.prototype._loadHandler = function(file) {
      try {
        if (typeof file !== 'object') {
          file = JSON.parse(file);
        }
        file.size = this._size;
      } catch (undefined) {}
      if (typeof this.onLoad === "function") {
        this.onLoad(file);
      }
      this._disabled = false;
      return this._createInput();
    };

    cgFileUploadCtrl.prototype._errorHandler = function(e) {
      if (typeof this.onError === "function") {
        this.onError(e);
      }
      this._disabled = false;
      return this._createInput();
    };

    cgFileUploadCtrl.prototype._uploadS3 = function(file) {
      var _fileName, _prefixRand, awsS3, bucket, defer, fileParams;
      defer = $q.defer();
      awsS3 = this.awscredentials;
      AWS.config.update({
        signatureVersion: 'v4',
        region: awsS3.region
      });
      AWS.config.credentials = new AWS.Credentials({
        accessKeyId: awsS3.accessKeyId,
        sessionToken: awsS3.sessionToken,
        secretAccessKey: awsS3.secretAccessKey
      });
      bucket = new AWS.S3({
        params: {
          Bucket: awsS3.bucket
        }
      });
      _prefixRand = (Math.floor(Math.random() * 10000)) + "-" + (Date.now()) + "_";
      _fileName = awsS3.destFolder ? awsS3.destFolder + "/" + _prefixRand + file.name : "" + _prefixRand + file.name;
      fileParams = {
        Key: _fileName,
        ContentType: file.type,
        Body: file,
        ACL: "public-read"
      };
      bucket.upload(fileParams, function(err, data) {
        if (err) {
          return defer.reject(err);
        } else {
          return defer.resolve({
            url: data.Location
          });
        }
      });
      return defer.promise;
    };

    cgFileUploadCtrl.prototype._uploadWorker = function(file) {
      var data, defer, script, worker, workerUrl;
      defer = $q.defer();
      script = document.querySelectorAll('[src*="file-upload"]')[0];
      workerUrl = script.src.replace('file-upload.js', 'file-upload-worker.js');
      worker = new Worker(workerUrl);
      worker.onmessage = function(e) {
        switch (e.data.message) {
          case 'load':
            return defer.resolve(e.data.body);
          case 'progress':
            return defer.notify(e.data.body);
        }
      };
      worker.onerror = defer.reject;
      data = {
        file: file,
        url: this.uploadUrl
      };
      worker.postMessage(data);
      return defer.promise;
    };

    cgFileUploadCtrl.prototype.upload = function(file) {
      var func;
      if (!file) {
        return;
      }
      this._size = (file.size / Math.pow(1024, 2)).toFixed(2);
      if (typeof this.onUploadStart === "function") {
        this.onUploadStart({
          size: this._size,
          filename: file.name,
          progress: 0
        });
      }
      this._disabled = true;
      func = this.awscredentials ? '_uploadS3' : '_uploadWorker';
      return this[func](file).then((function(_this) {
        return function(data) {
          return _this._loadHandler(data);
        };
      })(this), (function(_this) {
        return function(err) {
          return _this._errorHandler(err);
        };
      })(this), (function(_this) {
        return function(data) {
          return typeof _this.onProgress === "function" ? _this.onProgress(data) : void 0;
        };
      })(this));
    };

    return cgFileUploadCtrl;

  })();
  return cgFileUploadCtrl;
});
<|endoftext|>


<commit_before>var fs = require('fs'),
    http = require('http'),
    exec = require('child_process').exec,
	_ = require('underscore'),
    Geo = require('./geo');

function dpc(t,fn) { if(typeof(t) == 'function') setTimeout(t,0); else setTimeout(fn,t); }

function Scanner(options) {

	var self = this;
    self.options = options;

    var config = eval('('+fs.readFileSync("scanner.cfg",'utf8')+')');
    var upload = fs.existsSync('upload.cfg') ? eval('('+fs.readFileSync("upload.cfg",'utf8')+')') : null;

    self.addr_pending = { }     // list of addresses waiting scan
    self.addr_digested = { }    // list of scanned addresses
    self.addr_working = { }     // list of working addresses

    self.geo = new Geo({ timeout : config.http_socket_timeout });

  	// -----------------------------------------
   	// local http server interface
    if(config.http_port)
    {
        var express = require('express');
        var app = express();
        app.configure(function(){
            app.use(express.bodyParser());
        });
        app.get('/', function(req, res) {
            var str = self.render();
            res.write(str);
            res.end();
        });
	app.get('/api', function(req, res) {
	    var str = self.json();
            res.write(str);
            res.end();
	});
	app.get('/urls', function(req, res) {
	    var urls = [];
            for(var url in self.addr_working) {
                urls.push(url);
	    }

	    res.write(JSON.stringify(urls));
            res.end();
	});

        http.createServer(app).listen(config.http_port, function() {
            console.log("HTTP server listening on port: ",config.http_port);
        });
    }

    var logo = fs.readFileSync("resources/"+config.currency.toLowerCase()+".png","base64");
    if(logo)
        logo = "data:image/png;base64,"+logo;

    self.json = function() {
        return JSON.stringify(self.addr_working);
    };

    self.render = function() {
        var str = ""
            +""
            +"";
        if(logo)
            str += "

";
        str += "PEER TO PEER "+(config.currency.toUpperCase())+" MINING NETWORK - PUBLIC NODE LIST
GENERATED ON: "+(new Date())+"
"
        if(self.poolstats)
            str += "Pool speed: "+(self.poolstats.pool_hash_rate/1000000).toFixed(2)+" "+config.speed_abbrev+"";
        str += "Currently observing "+(self.nodes_total || "N/A")+" nodes.
"+_.size(self.addr_working)+" nodes are public with following IPs:
";
        str += "
";
        str += "

IPs

Version

Fee

Uptime

Location
";
        str += "

";

        var list = _.sortBy(_.toArray(self.addr_working), function(o) { return o.stats ? -o.stats.uptime : 0; })

        var row = 0;
        _.each(list, function(info) {
            var ip = info.ip;

            var version = info.stats.version;
            var uptime = (info.stats.uptime / 60 / 60 / 24).toFixed(1);
            var fee = (info.fee || 0).toFixed(2);

            str += "

"+ip+":"+9171+"

"+version+"

"+fee+"%

"+uptime+" days
";
            str += "
";
            if(info.geo) {
                str += ""+info.geo.country+" "+"";
            }
            str += "
";
            str += "
";
            str += "
";
        })
        str += "

";
        str += ""
        return str;
    }

    // setup flushing of rendered HTML page to a file (useful for uploading to other sites)
    if(config.flush_to_file_every_N_msec && config.flush_filename) {
        function flush_rendering() {
            var str = self.render();
            fs.writeFile(config.flush_filename, str, { encoding : 'utf8'});
            dpc(config.flush_to_file_every_N_msec, flush_rendering);
        }

        dpc(5000, flush_rendering);
    }

    // defer init
    dpc(function(){
        self.restore_working();
        self.update();
    })

    var p2pool_init = true;

    // main function that reloads 'addr' file from p2pool
    self.update = function() {
        var filename = config.addr_file;
        if(!fs.existsSync(filename)) {
            console.error("Unable to fetch p2pool address list from:",config.addr_file);
            filename = config.init_file;    // if we can't read p2pool's addr file, we just cycle on the local default init...
        }

        fs.readFile(filename, { encoding : 'utf8' }, function(err, data) {
            if(err) {
                console.error(err);
            }
            else {
                try {
                    var addr_list = JSON.parse(data);
                    self.inject(addr_list);

                    // main init
                    if(p2pool_init) {
                        p2pool_init = false;

                        // if we can read p2pool addr file, also add our pre-collected IPs
                        // if(filename != config.init_file) {
                            var init_addr = JSON.parse(fs.readFileSync(config.init_file, 'utf8'));
                            self.inject(init_addr);
                        //}

                        for(var i = 0; i < (config.probe_N_IPs_simultaneously || 1); i++)
                            self.digest();
                        dpc(60*1000, function() { self.store_working(); })
                    }
                }
                catch(ex) {
                    console.error("Unable to parse p2pool address list");
                    console.error(ex);
                }
            }

            dpc(1000 * 60, self.update);
        })
    }

    // store public pools in a file that reloads at startup
    self.store_working = function() {
        var data = JSON.stringify(self.addr_working);
        fs.writeFile(config.store_file, data, { encoding : 'utf8' }, function(err) {
            dpc(60*1000, self.store_working);
        })
    }

    // reload public list at startup
    self.restore_working = function() {
        try {
            self.addr_working = JSON.parse(fs.readFileSync(config.store_file, 'utf8'));
        } catch(ex) { console.log(ex); }
    }

    // inject new IPs from p2pool addr file
    self.inject = function(addr_list) {
        _.each(addr_list, function(info) {
            var ip = info[0][0];
            var port = info[0][1];

            if(!self.addr_digested[ip] && !self.addr_pending[ip]) {
                self.addr_pending[ip] = { ip : ip, port : port }
            }

            self.nodes_total = _.size(self.addr_digested) + _.size(self.addr_pending);
        });
    }

    // as we scan pools, we fetch global info from them to update the page
    self.update_global_stats = function(poolstats) {
        self.poolstats = poolstats;
    }

    // execute scan of a single IP
    self.digest = function() {
        if(!_.size(self.addr_pending))
            return self.list_complete();

        var info = _.find(self.addr_pending, function() { return true; });
        delete self.addr_pending[info.ip];

	if(info.ip == "0.0.0.0" || info.ip == "127.0.0.1") {
	    return;
	}

        self.addr_digested[info.ip] = info;
        console.log("P2POOL DIGESTING:" + info.ip + ":" + 9171);

	var allowedVersions = ["fdc4e2d-dirty",
			       "20e6354-dirty",
			       "8542674-dirty",
			       "c174c98-dirty",
			       "fcfb6ad-dirty",
			       "3877fc7-dirty",
			       "fdc4e2d",
                               "20e6354",
                               "8542674",
                               "c174c98",
                               "fcfb6ad",
                               "3877fc7",
                               "e0909bc-dirty",
                               "e0909bc",
                               "952287c",
                               "952287c-dirty",
                               "b092f6b",
                               "b092f6b-dirty",
			       "649807a",
			       "649807a-dirty"
                               "d7ddaa4",
                               "d7ddaa4-dirty"];

        digest_ip(info, function(err, fee){
            if(!err) {
                digest_local_stats(info, function(err, stats) {
		    if(!err && allowedVersions.indexOf(stats.version) >= 0) {
                    	info.fee = fee;
		        info.stats = stats;
	                console.log("FOUND WORKING POOL: " + info.ip + ":9171 " + info.stats.version);
                	self.addr_working[info.ip] = info;
		digest_global_stats(info, function(err, stats) {
                        if(!err)
                            self.update_global_stats(stats);

                        if(!info.geo)
                            self.geo.get(info.ip, function(err, geo) {
                                if(!err)
                                    info.geo = geo;

                                continue_digest();
                            });
                        else
                            continue_digest();
                    });
		}
                });
            }
            else {
                delete self.addr_working[info.ip];
		/*if(!err && allowedVersions.indexOf(info.stats.version) < 0) {
		   console.log("Node was wrong version: " + info.stats.version);
		}*/
                continue_digest();
            }

            function continue_digest() {
                self.working_size = _.size(self.addr_working);
                dpc(self.digest);
            }
        });
    }

    // schedule restar of the scan once all IPs are done
    self.list_complete = function() {
        self.addr_pending = self.addr_digested;
        self.addr_digested = { }
        dpc(config.rescan_list_delay, self.digest);
    }

    // functions to fetch data from target node IP

    function digest_ip(info, callback) {

        var options = {
          host: info.ip,
          port: 9171,
          path: '/fee',
          method: 'GET'
        };

        self.request(options, callback);
    }

    function digest_local_stats(info, callback) {

        var options = {
          host: info.ip,
          port: 9171,
          path: '/local_stats',
          method: 'GET'
        };

        self.request(options, callback);
    }

    function digest_global_stats(info, callback) {

        var options = {
          host: info.ip,
          port: 9171,
          path: '/global_stats',
          method: 'GET'
        };

        self.request(options, callback);
    }

    // make http request to the target node ip
    self.request = function(options, callback, is_plain)
    {
        http_handler = http;
        var req = http_handler.request(options, function(res) {
            res.setEncoding('utf8');
            var result = '';
            res.on('data', function (data) {
                result += data;
            });

            res.on('end', function () {
		if(options.plain)
                    callback(null, result);
                else {
                    try {
                        var o = JSON.parse(result);
			callback(null, o);
                    } catch(ex) {
                        console.error(ex);
                        callback(ex);
                    }
                }
            });
        });

        req.on('socket', function (socket) {
            socket.setTimeout(config.http_socket_timeout);
            socket.on('timeout', function() {
                req.abort();
            });
        });

        req.on('error', function(e) {
            callback(e);
        });

        req.end();
    }

    if(upload && process.platform != 'win32') {

        function do_upload() {

            if(upload.ftp) {
                var ftp = upload.ftp;
                if(!ftp.address || !ftp.username || !ftp.password)
                    return console.error("upload.cfg ftp configuration must contain target address, username and password");
                var cmd = "curl -T "+config.flush_filename+" "+ftp.address+" --user "+ftp.address+":"+ftp.password;
                exec(cmd, function(error){ if(error) console.error(error); });
            }

            if(upload.scp) {
                var scp = upload.scp;
                if(!scp.address)
                    return console.error("upload.cfg scp configuration must contain target address");
                var cmd = "scp -q ./"+config.flush_filename+" "+scp.address;
                exec(cmd, function(error){ if(error) console.error(error); });
            }

            dpc(config.upload_interval, do_upload);
        }

        dpc(5000, do_upload);
    }
    else
        console.log("upload.cfg not found, rendering available only on the local interface");
}

GLOBAL.scanner = new Scanner();

<commit_msg>Add missing comma<commit_after>var fs = require('fs'),
    http = require('http'),
    exec = require('child_process').exec,
	_ = require('underscore'),
    Geo = require('./geo');

function dpc(t,fn) { if(typeof(t) == 'function') setTimeout(t,0); else setTimeout(fn,t); }

function Scanner(options) {

	var self = this;
    self.options = options;

    var config = eval('('+fs.readFileSync("scanner.cfg",'utf8')+')');
    var upload = fs.existsSync('upload.cfg') ? eval('('+fs.readFileSync("upload.cfg",'utf8')+')') : null;

    self.addr_pending = { }     // list of addresses waiting scan
    self.addr_digested = { }    // list of scanned addresses
    self.addr_working = { }     // list of working addresses

    self.geo = new Geo({ timeout : config.http_socket_timeout });

  	// -----------------------------------------
   	// local http server interface
    if(config.http_port)
    {
        var express = require('express');
        var app = express();
        app.configure(function(){
            app.use(express.bodyParser());
        });
        app.get('/', function(req, res) {
            var str = self.render();
            res.write(str);
            res.end();
        });
	app.get('/api', function(req, res) {
	    var str = self.json();
            res.write(str);
            res.end();
	});
	app.get('/urls', function(req, res) {
	    var urls = [];
            for(var url in self.addr_working) {
                urls.push(url);
	    }

	    res.write(JSON.stringify(urls));
            res.end();
	});

        http.createServer(app).listen(config.http_port, function() {
            console.log("HTTP server listening on port: ",config.http_port);
        });
    }

    var logo = fs.readFileSync("resources/"+config.currency.toLowerCase()+".png","base64");
    if(logo)
        logo = "data:image/png;base64,"+logo;

    self.json = function() {
        return JSON.stringify(self.addr_working);
    };

    self.render = function() {
        var str = ""
            +""
            +"";
        if(logo)
            str += "

";
        str += "PEER TO PEER "+(config.currency.toUpperCase())+" MINING NETWORK - PUBLIC NODE LIST
GENERATED ON: "+(new Date())+"
"
        if(self.poolstats)
            str += "Pool speed: "+(self.poolstats.pool_hash_rate/1000000).toFixed(2)+" "+config.speed_abbrev+"";
        str += "Currently observing "+(self.nodes_total || "N/A")+" nodes.
"+_.size(self.addr_working)+" nodes are public with following IPs:
";
        str += "
";
        str += "

IPs

Version

Fee

Uptime

Location
";
        str += "

";

        var list = _.sortBy(_.toArray(self.addr_working), function(o) { return o.stats ? -o.stats.uptime : 0; })

        var row = 0;
        _.each(list, function(info) {
            var ip = info.ip;

            var version = info.stats.version;
            var uptime = (info.stats.uptime / 60 / 60 / 24).toFixed(1);
            var fee = (info.fee || 0).toFixed(2);

            str += "

"+ip+":"+9171+"

"+version+"

"+fee+"%

"+uptime+" days
";
            str += "
";
            if(info.geo) {
                str += ""+info.geo.country+" "+"";
            }
            str += "
";
            str += "
";
            str += "
";
        })
        str += "

";
        str += ""
        return str;
    }

    // setup flushing of rendered HTML page to a file (useful for uploading to other sites)
    if(config.flush_to_file_every_N_msec && config.flush_filename) {
        function flush_rendering() {
            var str = self.render();
            fs.writeFile(config.flush_filename, str, { encoding : 'utf8'});
            dpc(config.flush_to_file_every_N_msec, flush_rendering);
        }

        dpc(5000, flush_rendering);
    }

    // defer init
    dpc(function(){
        self.restore_working();
        self.update();
    })

    var p2pool_init = true;

    // main function that reloads 'addr' file from p2pool
    self.update = function() {
        var filename = config.addr_file;
        if(!fs.existsSync(filename)) {
            console.error("Unable to fetch p2pool address list from:",config.addr_file);
            filename = config.init_file;    // if we can't read p2pool's addr file, we just cycle on the local default init...
        }

        fs.readFile(filename, { encoding : 'utf8' }, function(err, data) {
            if(err) {
                console.error(err);
            }
            else {
                try {
                    var addr_list = JSON.parse(data);
                    self.inject(addr_list);

                    // main init
                    if(p2pool_init) {
                        p2pool_init = false;

                        // if we can read p2pool addr file, also add our pre-collected IPs
                        // if(filename != config.init_file) {
                            var init_addr = JSON.parse(fs.readFileSync(config.init_file, 'utf8'));
                            self.inject(init_addr);
                        //}

                        for(var i = 0; i < (config.probe_N_IPs_simultaneously || 1); i++)
                            self.digest();
                        dpc(60*1000, function() { self.store_working(); })
                    }
                }
                catch(ex) {
                    console.error("Unable to parse p2pool address list");
                    console.error(ex);
                }
            }

            dpc(1000 * 60, self.update);
        })
    }

    // store public pools in a file that reloads at startup
    self.store_working = function() {
        var data = JSON.stringify(self.addr_working);
        fs.writeFile(config.store_file, data, { encoding : 'utf8' }, function(err) {
            dpc(60*1000, self.store_working);
        })
    }

    // reload public list at startup
    self.restore_working = function() {
        try {
            self.addr_working = JSON.parse(fs.readFileSync(config.store_file, 'utf8'));
        } catch(ex) { console.log(ex); }
    }

    // inject new IPs from p2pool addr file
    self.inject = function(addr_list) {
        _.each(addr_list, function(info) {
            var ip = info[0][0];
            var port = info[0][1];

            if(!self.addr_digested[ip] && !self.addr_pending[ip]) {
                self.addr_pending[ip] = { ip : ip, port : port }
            }

            self.nodes_total = _.size(self.addr_digested) + _.size(self.addr_pending);
        });
    }

    // as we scan pools, we fetch global info from them to update the page
    self.update_global_stats = function(poolstats) {
        self.poolstats = poolstats;
    }

    // execute scan of a single IP
    self.digest = function() {
        if(!_.size(self.addr_pending))
            return self.list_complete();

        var info = _.find(self.addr_pending, function() { return true; });
        delete self.addr_pending[info.ip];

	if(info.ip == "0.0.0.0" || info.ip == "127.0.0.1") {
	    return;
	}

        self.addr_digested[info.ip] = info;
        console.log("P2POOL DIGESTING:" + info.ip + ":" + 9171);

	var allowedVersions = ["fdc4e2d-dirty",
			       "20e6354-dirty",
			       "8542674-dirty",
			       "c174c98-dirty",
			       "fcfb6ad-dirty",
			       "3877fc7-dirty",
			       "fdc4e2d",
                               "20e6354",
                               "8542674",
                               "c174c98",
                               "fcfb6ad",
                               "3877fc7",
                               "e0909bc-dirty",
                               "e0909bc",
                               "952287c",
                               "952287c-dirty",
                               "b092f6b",
                               "b092f6b-dirty",
			       "649807a",
			       "649807a-dirty",
                               "d7ddaa4",
                               "d7ddaa4-dirty"];

        digest_ip(info, function(err, fee){
            if(!err) {
                digest_local_stats(info, function(err, stats) {
		    if(!err && allowedVersions.indexOf(stats.version) >= 0) {
                    	info.fee = fee;
		        info.stats = stats;
	                console.log("FOUND WORKING POOL: " + info.ip + ":9171 " + info.stats.version);
                	self.addr_working[info.ip] = info;
		digest_global_stats(info, function(err, stats) {
                        if(!err)
                            self.update_global_stats(stats);

                        if(!info.geo)
                            self.geo.get(info.ip, function(err, geo) {
                                if(!err)
                                    info.geo = geo;

                                continue_digest();
                            });
                        else
                            continue_digest();
                    });
		}
                });
            }
            else {
                delete self.addr_working[info.ip];
		/*if(!err && allowedVersions.indexOf(info.stats.version) < 0) {
		   console.log("Node was wrong version: " + info.stats.version);
		}*/
                continue_digest();
            }

            function continue_digest() {
                self.working_size = _.size(self.addr_working);
                dpc(self.digest);
            }
        });
    }

    // schedule restar of the scan once all IPs are done
    self.list_complete = function() {
        self.addr_pending = self.addr_digested;
        self.addr_digested = { }
        dpc(config.rescan_list_delay, self.digest);
    }

    // functions to fetch data from target node IP

    function digest_ip(info, callback) {

        var options = {
          host: info.ip,
          port: 9171,
          path: '/fee',
          method: 'GET'
        };

        self.request(options, callback);
    }

    function digest_local_stats(info, callback) {

        var options = {
          host: info.ip,
          port: 9171,
          path: '/local_stats',
          method: 'GET'
        };

        self.request(options, callback);
    }

    function digest_global_stats(info, callback) {

        var options = {
          host: info.ip,
          port: 9171,
          path: '/global_stats',
          method: 'GET'
        };

        self.request(options, callback);
    }

    // make http request to the target node ip
    self.request = function(options, callback, is_plain)
    {
        http_handler = http;
        var req = http_handler.request(options, function(res) {
            res.setEncoding('utf8');
            var result = '';
            res.on('data', function (data) {
                result += data;
            });

            res.on('end', function () {
		if(options.plain)
                    callback(null, result);
                else {
                    try {
                        var o = JSON.parse(result);
			callback(null, o);
                    } catch(ex) {
                        console.error(ex);
                        callback(ex);
                    }
                }
            });
        });

        req.on('socket', function (socket) {
            socket.setTimeout(config.http_socket_timeout);
            socket.on('timeout', function() {
                req.abort();
            });
        });

        req.on('error', function(e) {
            callback(e);
        });

        req.end();
    }

    if(upload && process.platform != 'win32') {

        function do_upload() {

            if(upload.ftp) {
                var ftp = upload.ftp;
                if(!ftp.address || !ftp.username || !ftp.password)
                    return console.error("upload.cfg ftp configuration must contain target address, username and password");
                var cmd = "curl -T "+config.flush_filename+" "+ftp.address+" --user "+ftp.address+":"+ftp.password;
                exec(cmd, function(error){ if(error) console.error(error); });
            }

            if(upload.scp) {
                var scp = upload.scp;
                if(!scp.address)
                    return console.error("upload.cfg scp configuration must contain target address");
                var cmd = "scp -q ./"+config.flush_filename+" "+scp.address;
                exec(cmd, function(error){ if(error) console.error(error); });
            }

            dpc(config.upload_interval, do_upload);
        }

        dpc(5000, do_upload);
    }
    else
        console.log("upload.cfg not found, rendering available only on the local interface");
}

GLOBAL.scanner = new Scanner();

<|endoftext|>


<commit_before>/*
 * Waltz - Enterprise Architecture
 * Copyright (C) 2016, 2017, 2018, 2019 Waltz open source project
 * See README.md for more information
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific
 *
 */

import _ from "lodash";
import moment from "moment";
import {extent, max} from "d3-array";
import {axisBottom, axisLeft} from "d3-axis";
import {nest} from "d3-collection";
import {scaleLinear} from "d3-scale";
import {select} from "d3-selection";
import {curveLinear, line} from "d3-shape";
import {timeFormat} from "d3-time-format";
import "d3-selection-multi";

import {initialiseData, isEmpty} from "../../../common";
import {variableScale} from "../../../common/colors";
import template from "./entity-statistic-history-chart.html";

const bindings = {
    points: "<",
    onHover: "<",
    highlightedDate: "<"
};

const initialState = {
};

function prepareSections(svg) {
    const chart = svg
        .append("g");
    const xAxis = chart
        .append("g")
        .classed("weshc-axis", true);
    const yAxis = chart
        .append("g")
        .classed("weshc-axis", true);
    return {
        svg,
        chart,
        xAxis,
        yAxis
    };
}

function mkDimensions(width = 400) {
    const height = 200;

    const margins = {
        left: 60,
        right: 20,
        top: 20,
        bottom: 30
    };

    const chart = {
        width: width - (margins.left + margins.right),
        height: height - (margins.top + margins.bottom),
    };

    return {
        width,
        height,
        margins,
        chart
    };
}

function mkScales(points = [], dimensions) {
    const countExtent = [0, max(points, d => d.count)];
    const dateExtent = extent(points, d => d.date);

    const xRange = [0, dimensions.width - (dimensions.margins.left + dimensions.margins.right)];
    const yRange = [dimensions.height - (dimensions.margins.top + dimensions.margins.bottom), 0];

    return {
        x: scaleLinear()
            .domain(dateExtent)
            .range(xRange),
        y: scaleLinear()
            .domain(countExtent)
            .range(yRange)
    };
}

function drawPoints(section, points = [], scales) {
    const pointSelection = section
        .selectAll(".point")
        .data(points, p => p.date + "_" + p.series);

    const newPoints = pointSelection
        .enter()
        .append("circle")
        .classed("point", true)
        .attr("fill", d => variableScale(d.series))
        .attr("opacity", 0.7)
        .attr("r", 0);

    pointSelection
        .exit()
        .remove();

    pointSelection
        .merge(newPoints)
        .attr("cx", p => scales.x(p.date))
        .attr("cy", p => scales.y(p.count))
        .attr("r", 3);

}

function drawLines(section, points = [], scales) {
    const lineFunction = line()
        .x(d => scales.x(d.date))
        .y(d => scales.y(d.count))
        .curve(curveLinear);

    const bySeries = nest()
        .key(d => d.series)
        .entries(points);

    const pathSelector = section
        .selectAll(".line")
        .data(bySeries, s => s.key);

    const newLines = pathSelector
        .enter()
        .append("path")
        .classed("line", true)
        .attr("stroke", d => variableScale(d.key))
        .attr("stroke-width", 1)
        .attr("fill", "none")
        .attr("opacity", 0.7);

    pathSelector
        .exit()
        .remove();

    pathSelector
        .merge(newLines)
        .attr("d", d => lineFunction(d.values))
}

function adjustSections(sections, dimensions) {
    sections
        .svg
        .attr("width", dimensions.width)
        .attr("height", dimensions.height);

    sections
        .chart
        .attr("transform", `translate(${ dimensions.margins.left }, ${ dimensions.margins.top })`);

    sections
        .xAxis
        .attr("transform", `translate(0, ${ dimensions.height - (dimensions.margins.top + dimensions.margins.bottom) })`);
}

function tryInvoke(callback, arg) {
    if (callback) callback(arg);
    else console.log("No callback registed");
}

function drawBands(section,
                   points,
                   scales,
                   onHover) {

    const numDates = _.uniqBy(_.map(points, "date"), d => d + "").length;
    const width = scales.x.range()[1];
    const bandWidth = width / numDates;
    const extraHeight = 30;

    const dates = _
        .chain(points)
        .map("date")
        .uniqBy(d => d.getTime())
        .value();

    const bands = section
        .selectAll("rect.band")
        .data(dates, d => d.getTime());

    const newBands = bands
        .enter()
        .append("rect")
        .classed("band", true)
        .attr("pointer-events", "all")
        .style("visibility", "hidden")
        .on("mouseenter.band-hover", (e, d) => tryInvoke(onHover, d))
        .on("mouseleave.band-hover", () => tryInvoke(onHover, null))
       ;

    bands
        .merge(newBands)
        .attr("x", d => scales.x(d) - (bandWidth / 2))
        .attr("y", extraHeight / 2 * -1)
        .attr("width", bandWidth)
        .attr("height", scales.y.range()[0] + extraHeight);
}

function pickDatesForXAxis(scale) {
    const dateDomain = scale.domain();
    const start = moment(dateDomain[0]);
    const end = moment(dateDomain[1]);

    const diff = end.diff(start, "days");
    const jump = Math.ceil(diff / 16);

    if (diff < 2) {
        return _.map(
            _.range(diff + 1),
            x => start.add(x, "days").toDate().getTime());
    }

    let ptr = start.add(jump, "days");
    const dates = [];
    while (ptr.isBefore(end)) {
        dates.push(ptr.toDate().getTime());
        ptr = ptr.add(jump * 2, "days");
    }

    return dates;
}

function drawXAxis(section, points = [], scale) {
    if (isEmpty(points)) return;

    const dates = pickDatesForXAxis(scale);
    const dateFormat = timeFormat("%d/%m");

    const xAxis = axisBottom()
        .tickValues(dates)
        .tickSize(6)
        .scale(scale)
        .tickFormat(d => { return dateFormat(new Date(d)); });

    section
        .call(xAxis);
}

function drawYAxis(section, scale) {
    const yAxis = axisLeft()
        .ticks(5)
        .scale(scale);

    section
        .call(yAxis);
}

function drawAxes(sections, points = [], scales) {
    drawXAxis(sections.xAxis, points, scales.x);
    drawYAxis(sections.yAxis, scales.y);
}

function draw(sections,
              width,
              points = [],
              onHover = () => console.log("weshc: no onHover provided")) {
    const dimensions = mkDimensions(width);
    const scales = mkScales(points, dimensions);

    adjustSections(sections, dimensions);
    drawAxes(sections, points, scales);
    drawLines(sections.chart, points, scales);
    drawPoints(sections.chart, points, scales);
    drawBands(sections.chart, points, scales, onHover);
}

/**
 * Note: it is v. important the $element is an element with some width,
 * simply placing this in a element like a waltz-section will cause it
 * to render with 0x0....
 * @param $element
 * @param $window
 */
function controller($element, $window) {

    const vm = initialiseData(this, initialState);
    const svg = select($element.find("svg")[0]);

    const svgSections = prepareSections(svg);

    const render = () => {
        const elemWidth = $element
            .parent()[0]
            .clientWidth;
        draw(svgSections, elemWidth, vm.points, vm.onHover);
    };

    const debouncedRender = _.debounce(render, 100);

    const isHighlighted = p => vm.highlightedDate && p.date.getTime() === vm.highlightedDate.getTime();

    vm.$onChanges = (changes) => {
        if (changes.highlightedDate) {
            svg.selectAll(".point")
                .attr("r", p => isHighlighted(p) ? 6 : 3);
        }
        if (changes.points) {
            debouncedRender();
        }
    };

    vm.$onInit = () => angular
        .element($window)
        .on("resize", debouncedRender);

    vm.$onDestroy = () => angular
        .element($window)
        .off("resize", debouncedRender);
}

controller.$inject = [
    "$element",
    "$window"
];

const component = {
    bindings,
    template,
    controller
};

export default component;
<commit_msg>Revert "entity stats"<commit_after>/*
 * Waltz - Enterprise Architecture
 * Copyright (C) 2016, 2017, 2018, 2019 Waltz open source project
 * See README.md for more information
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific
 *
 */

import _ from "lodash";
import moment from "moment";
import {extent, max} from "d3-array";
import {axisBottom, axisLeft} from "d3-axis";
import {nest} from "d3-collection";
import {scaleLinear} from "d3-scale";
import {select} from "d3-selection";
import {curveLinear, line} from "d3-shape";
import {timeFormat} from "d3-time-format";
import "d3-selection-multi";

import {initialiseData, isEmpty} from "../../../common";
import {variableScale} from "../../../common/colors";
import template from "./entity-statistic-history-chart.html";

const bindings = {
    points: "<",
    onHover: "<",
    highlightedDate: "<"
};

const initialState = {
};

function prepareSections(svg) {
    const chart = svg
        .append("g");
    const xAxis = chart
        .append("g")
        .classed("weshc-axis", true);
    const yAxis = chart
        .append("g")
        .classed("weshc-axis", true);
    return {
        svg,
        chart,
        xAxis,
        yAxis
    };
}

function mkDimensions(width = 400) {
    const height = 200;

    const margins = {
        left: 60,
        right: 20,
        top: 20,
        bottom: 30
    };

    const chart = {
        width: width - (margins.left + margins.right),
        height: height - (margins.top + margins.bottom),
    };

    return {
        width,
        height,
        margins,
        chart
    };
}

function mkScales(points = [], dimensions) {
    const countExtent = [0, max(points, d => d.count)];
    const dateExtent = extent(points, d => d.date);

    const xRange = [0, dimensions.width - (dimensions.margins.left + dimensions.margins.right)];
    const yRange = [dimensions.height - (dimensions.margins.top + dimensions.margins.bottom), 0];

    return {
        x: scaleLinear()
            .domain(dateExtent)
            .range(xRange),
        y: scaleLinear()
            .domain(countExtent)
            .range(yRange)
    };
}

function drawPoints(section, points = [], scales) {
    const pointSelection = section
        .selectAll(".point")
        .data(points, p => p.date + "_" + p.series);

    const newPoints = pointSelection
        .enter()
        .append("circle")
        .classed("point", true)
        .attrs({
            fill: d => variableScale(d.series),
            opacity: 0.7,
            r: 0
        });

    pointSelection
        .exit()
        .remove();

    pointSelection
        .merge(newPoints)
        .attr("cx", p => scales.x(p.date))
        .attr("cy", p => scales.y(p.count))
        .attr("r", 3);

}

function drawLines(section, points = [], scales) {
    const lineFunction = line()
        .x(d => scales.x(d.date))
        .y(d => scales.y(d.count))
        .curve(curveLinear);

    const bySeries = nest()
        .key(d => d.series)
        .entries(points);

    const pathSelector = section
        .selectAll(".line")
        .data(bySeries, s => s.key);

    const newLines = pathSelector
        .enter()
        .append("path")
        .classed("line", true)
        .attrs({
            stroke: d => variableScale(d.key),
            "stroke-width": 1,
            fill: "none",
            opacity: 0.7
        });

    pathSelector
        .exit()
        .remove();

    pathSelector
        .merge(newLines)
        .attr("d", d => lineFunction(d.values))
}

function adjustSections(sections, dimensions) {
    sections
        .svg
        .attrs({
            width: dimensions.width,
            height: dimensions.height
        });

    sections
        .chart
        .attr("transform", `translate(${ dimensions.margins.left }, ${ dimensions.margins.top })`);

    sections
        .xAxis
        .attr("transform", `translate(0, ${ dimensions.height - (dimensions.margins.top + dimensions.margins.bottom) })`);
}

function tryInvoke(callback, arg) {
    if (callback) callback(arg);
    else console.log("No callback registed");
}

function drawBands(section,
                   points,
                   scales,
                   onHover) {

    const numDates = _.uniqBy(_.map(points, "date"), d => d + "").length;
    const width = scales.x.range()[1];
    const bandWidth = width / numDates;
    const extraHeight = 30;

    const dates = _.chain(points)
        .map("date")
        .uniqBy(d => d.getTime())
        .value();

    const bands = section
        .selectAll("rect.band")
        .data(dates, d => d.getTime());

    const newBands = bands
        .enter()
        .append("rect")
        .classed("band", true)
        .attr("pointer-events", "all")
        .style("visibility", "hidden")
        .on("mouseenter.band-hover", d => {
            tryInvoke(onHover, d);
        })
        .on("mouseleave.band-hover", () => {
            tryInvoke(onHover, null);
        })
       ;

    bands
        .merge(newBands)
        .attrs({
            x: d => scales.x(d) - (bandWidth / 2),
            y: extraHeight / 2 * -1,
            width: bandWidth,
            height: scales.y.range()[0] + extraHeight,
        });
}

function pickDatesForXAxis(scale) {
    const dateDomain = scale.domain();
    const start = moment(dateDomain[0]);
    const end = moment(dateDomain[1]);

    const diff = end.diff(start, "days");
    const jump = Math.ceil(diff / 16);

    if (diff < 2) {
        return _.map(
            _.range(diff + 1),
            x => start.add(x, "days").toDate().getTime());
    }

    let ptr = start.add(jump, "days");
    const dates = [];
    while (ptr.isBefore(end)) {
        dates.push(ptr.toDate().getTime());
        ptr = ptr.add(jump * 2, "days");
    }

    return dates;
}

function drawXAxis(section, points = [], scale) {
    if (isEmpty(points)) return;

    const dates = pickDatesForXAxis(scale);
    const dateFormat = timeFormat("%d/%m");

    const xAxis = axisBottom()
        .tickValues(dates)
        .tickSize(6)
        .scale(scale)
        .tickFormat(d => { return dateFormat(new Date(d)); });

    section
        .call(xAxis);
}

function drawYAxis(section, scale) {
    const yAxis = axisLeft()
        .ticks(5)
        .scale(scale);

    section
        .call(yAxis);
}

function drawAxes(sections, points = [], scales) {
    drawXAxis(sections.xAxis, points, scales.x);
    drawYAxis(sections.yAxis, scales.y);
}

function draw(sections,
              width,
              points = [],
              onHover = () => console.log("weshc: no onHover provided")) {
    const dimensions = mkDimensions(width);
    const scales = mkScales(points, dimensions);

    adjustSections(sections, dimensions);
    drawAxes(sections, points, scales);
    drawLines(sections.chart, points, scales);
    drawPoints(sections.chart, points, scales);
    drawBands(sections.chart, points, scales, onHover);
}

/**
 * Note: it is v. important the $element is an element with some width,
 * simply placing this in a element like a waltz-section will cause it
 * to render with 0x0....
 * @param $element
 * @param $window
 */
function controller($element, $window) {

    const vm = initialiseData(this, initialState);
    const svg = select($element.find("svg")[0]);

    const svgSections = prepareSections(svg);

    const render = () => {
        const elemWidth = $element
            .parent()[0]
            .clientWidth;
        draw(svgSections, elemWidth, vm.points, vm.onHover);
    };

    const debouncedRender = _.debounce(render, 100);

    const isHighlighted = p => vm.highlightedDate && p.date.getTime() === vm.highlightedDate.getTime();

    vm.$onChanges = (changes) => {
        if (changes.highlightedDate) {
            svg.selectAll(".point")
                .attr("r", p => isHighlighted(p) ? 6 : 3);
        }
        if (changes.points) {
            debouncedRender();
        }
    };

    vm.$onInit = () => angular
        .element($window)
        .on("resize", debouncedRender);

    vm.$onDestroy = () => angular
        .element($window)
        .off("resize", debouncedRender);
}

controller.$inject = [
    "$element",
    "$window"
];

const component = {
    bindings,
    template,
    controller
};

export default component;
<|endoftext|>


<commit_before>'use strict';

var setupTestHooks     = require('ember-cli-blueprint-test-helpers/lib/helpers/setup');
var BlueprintHelpers   = require('ember-cli-blueprint-test-helpers/lib/helpers/blueprint-helper');
var generateAndDestroy = BlueprintHelpers.generateAndDestroy;

describe('Acceptance: ember generate and destroy initializer-addon', function() {
  setupTestHooks(this);

  it('initializer-addon foo', function() {
    // pass any additional command line options in the arguments array
    return generateAndDestroy(['initializer-addon', 'foo'], {
      // define files to assert, and their contents
      target: 'addon',
      files: [
        {
          file: 'app/initializers/foo.js',
          contains: "export { default, initialize } from 'my-addon/initializers/foo';"
        }
      ]
    });
  });

});
<commit_msg>tests/initializer-addon: Use alternative blueprint test helpers<commit_after>'use strict';

var blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers');
var setupTestHooks = blueprintHelpers.setupTestHooks;
var emberNew = blueprintHelpers.emberNew;
var emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy;

var chai = require('ember-cli-blueprint-test-helpers/chai');
var expect = chai.expect;

describe('Acceptance: ember generate and destroy initializer-addon', function() {
  setupTestHooks(this);

  it('initializer-addon foo', function() {
    var args = ['initializer-addon', 'foo'];

    return emberNew({ target: 'addon' })
      .then(() => emberGenerateDestroy(args, _file => {
        expect(_file('app/initializers/foo.js'))
          .to.contain("export { default, initialize } from 'my-addon/initializers/foo';");
      }));
  });
});
<|endoftext|>


<commit_before>/**
 * Pimcore
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.pimcore.org/license
 *
 * @copyright  Copyright (c) 2009-2010 elements.at New Media Solutions GmbH (http://www.elements.at)
 * @license    http://www.pimcore.org/license     New BSD License
 */

pimcore.registerNS("pimcore.object.tags.hotspotimage");
pimcore.object.tags.hotspotimage = Class.create(pimcore.object.tags.image, {
    hotspotCount: 0,
    type: "hotspotimage",

    data: null,
    hotspots: {},
    initialize: function (data, layoutConf) {
        if (data) {
            this.data = data.image;
            if(data.hotspots && data.hotspots != "null") {
                this.loadedHotspots = data.hotspots;
            }
        }
        this.layoutConf = layoutConf;

    },

    getLayoutEdit: function () {

        if (intval(this.layoutConf.width) < 1) {
            this.layoutConf.width = 100;
        }
        if (intval(this.layoutConf.height) < 1) {
            this.layoutConf.height = 100;
        }

        var conf = {
            width: this.layoutConf.width,
            height: this.layoutConf.height,
            tbar: [{
                xtype: "tbspacer",
                width: 20,
                height: 16,
                cls: "pimcore_icon_droptarget"
            },
            {
                xtype: "tbtext",
                text: "" + this.layoutConf.title + ""
            },"->",{
                xtype: "button",
                iconCls: "pimcore_icon_add",
                handler: this.addSelector.bind(this)
            },{
                xtype: "button",
                iconCls: "pimcore_icon_edit",
                handler: this.openImage.bind(this)
            }, {
                xtype: "button",
                iconCls: "pimcore_icon_delete",
                handler: this.empty.bind(this)
            },{
                xtype: "button",
                iconCls: "pimcore_icon_search",
                handler: this.openSearchEditor.bind(this)
            }]
        };

        this.layout = new Ext.Panel(conf);
        this.createImagePanel();

        return this.layout;
    },

    createImagePanel: function() {
        this.panel = new Ext.Panel({
            width: this.layoutConf.width,
            height: this.layoutConf.height-27,
            bodyCssClass: "pimcore_droptarget_image"}
        );
        this.layout.add(this.panel);

        this.panel.on("render", function (el) {

            // add drop zone
            new Ext.dd.DropZone(el.getEl(), {
                reference: this,
                ddGroup: "element",
                getTargetFromEvent: function(e) {
                    return this.reference.layout.getEl();
                },

                onNodeOver : function(target, dd, e, data) {

                    if (data.node.attributes.type == "image") {
                        return Ext.dd.DropZone.prototype.dropAllowed;
                    } else {
                        return Ext.dd.DropZone.prototype.dropNotAllowed;
                    }

                },

                onNodeDrop : this.onNodeDrop.bind(this)
            });

            el.getEl().on("contextmenu", this.onContextMenu.bind(this));

            if (this.data) {
                this.updateImage();
            }

        }.bind(this));

        this.layout.doLayout();

    },

    updateImage: function () {
        var path = "/admin/asset/get-image-thumbnail/id/" + this.data + "/width/" + (this.layoutConf.width - 20) + "/aspectratio/true";
        this.panel.getEl().update('');

        console.log(this.loadedHotspots);
        if(this.loadedHotspots.length > 0) {
            for(var i = 0; i < this.loadedHotspots.length; i++) {
                this.addHotspot(this.loadedHotspots[i]);
            }

        }

    },

    addSelector: function() {
        Ext.MessageBox.prompt(t('hotspotimage_add_selector'), t('hotspotimage_enter_name_of_new_hotspot'), this.completeAddSelector.bind(this), null, null, "");
    },

    completeAddSelector: function(button, value, object) {
        if(button == "ok") {
            var hotspot = {
                name: value,
                top: 10,
                left: 10,
                width: 100,
                height: 100
            };
            this.addHotspot(hotspot);
        }
    },

    addHotspot: function(hotspot) {
        this.hotspotCount++;
        var number = this.hotspotCount;
        console.log("add hotspot: " + hotspot.name + " => " + number);

        this.panel.getEl().createChild({
            tag: 'div',
            id: 'selector' + number,
            style: 'cursor:move; position: absolute; top: ' + hotspot.top + '; left: ' + hotspot.left + ';z-index:9000;',
            html: this.getSelectorHtml(hotspot.name)
        });

        var resizer = new Ext.Resizable('selector' + number, {
            pinned:true,
            minWidth:50,
            minHeight: 50,
            preserveRatio: false,
            dynamic:true,
            handles: 'all',
            draggable:true,
            width: hotspot.width,
            height: hotspot.height

        });

        this.hotspots[number] = hotspot;
        this.dirty = true;

        resizer.addListener("resize", function(item, width, height, e) {
            this.handleSelectorChanged(number);
        }.bind(this));

        Ext.get('selector' + number).on('mouseup', function(){
            this.handleSelectorChanged(number);
        }.bind(this));

        Ext.get('selector' + number).on("contextmenu", this.onSelectorContextMenu.bind(this, number));
    },

    getSelectorHtml: function(text) {
        return '
' + text + '
';
    },

    handleSelectorChanged: function(selectorNumber) {
        var dimensions = Ext.get("selector" + selectorNumber).getStyles("top","left","width","height");
        this.hotspots[selectorNumber].top = dimensions.top;
        this.hotspots[selectorNumber].left = dimensions.left;
        this.hotspots[selectorNumber].width = dimensions.width;
        this.hotspots[selectorNumber].height = dimensions.height;

        this.dirty = true;
    },

    onSelectorContextMenu: function (id, e) {
        var menu = new Ext.menu.Menu();
        menu.add(new Ext.menu.Item({
            text: t('delete'),
            iconCls: "pimcore_icon_delete",
            handler: function (item) {
                console.log(id);
                console.log(item);
                Ext.get('selector' + id).hide();
                Ext.get('selector' + id).remove();
            }.bind(this)
        }));

//        menu.add(new Ext.menu.Item({
//            text: t('edit'),
//            iconCls: "pimcore_icon_open",
//            handler: function (item) {
//                item.parentMenu.destroy();
//
//                this.openImage();
//            }.bind(this)
//        }));

        menu.showAt(e.getXY());

        e.stopEvent();
    },

    empty: function () {
        this.data = null;
        this.hotspots = null;
        this.dirty = true;
        this.layout.removeAll();
        this.createImagePanel();
    },

    getValue: function () {
        return {image: this.data, hotspots: this.hotspots};
    }
});<commit_msg><commit_after>/**
 * Pimcore
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.pimcore.org/license
 *
 * @copyright  Copyright (c) 2009-2010 elements.at New Media Solutions GmbH (http://www.elements.at)
 * @license    http://www.pimcore.org/license     New BSD License
 */

pimcore.registerNS("pimcore.object.tags.hotspotimage");
pimcore.object.tags.hotspotimage = Class.create(pimcore.object.tags.image, {
    hotspotCount: 0,
    type: "hotspotimage",

    marginTop: 10,
    marginLeft: 8,

    data: null,
    hotspots: {},
    initialize: function (data, layoutConf) {
        if (data) {
            this.data = data.image;
            if(data.hotspots && data.hotspots != "null") {
                this.loadedHotspots = data.hotspots;
            }
        }
        this.layoutConf = layoutConf;

    },

    getLayoutEdit: function () {

        if (intval(this.layoutConf.width) < 1) {
            this.layoutConf.width = 100;
        }
        if (intval(this.layoutConf.height) < 1) {
            this.layoutConf.height = 100;
        }

        var conf = {
            width: this.layoutConf.width,
            height: this.layoutConf.height,
            tbar: [{
                xtype: "tbspacer",
                width: 20,
                height: 16,
                cls: "pimcore_icon_droptarget"
            },
            {
                xtype: "tbtext",
                text: "" + this.layoutConf.title + ""
            },"->",{
                xtype: "button",
                iconCls: "pimcore_icon_add",
                handler: this.addSelector.bind(this)
            },{
                xtype: "button",
                iconCls: "pimcore_icon_edit",
                handler: this.openImage.bind(this)
            }, {
                xtype: "button",
                iconCls: "pimcore_icon_delete",
                handler: this.empty.bind(this)
            },{
                xtype: "button",
                iconCls: "pimcore_icon_search",
                handler: this.openSearchEditor.bind(this)
            }]
        };

        this.layout = new Ext.Panel(conf);
        this.createImagePanel();

        return this.layout;
    },

    createImagePanel: function() {
        this.panel = new Ext.Panel({
            width: this.layoutConf.width,
            height: this.layoutConf.height-27,
            bodyCssClass: "pimcore_droptarget_image"}
        );
        this.layout.add(this.panel);

        this.panel.on("render", function (el) {

            // add drop zone
            new Ext.dd.DropZone(el.getEl(), {
                reference: this,
                ddGroup: "element",
                getTargetFromEvent: function(e) {
                    return this.reference.layout.getEl();
                },

                onNodeOver : function(target, dd, e, data) {

                    if (data.node.attributes.type == "image") {
                        return Ext.dd.DropZone.prototype.dropAllowed;
                    } else {
                        return Ext.dd.DropZone.prototype.dropNotAllowed;
                    }

                },

                onNodeDrop : this.onNodeDrop.bind(this)
            });

            el.getEl().on("contextmenu", this.onContextMenu.bind(this));

            if (this.data) {
                this.updateImage();
            }

        }.bind(this));

        this.layout.doLayout();

    },

    updateImage: function () {
        var path = "/admin/asset/get-image-thumbnail/id/" + this.data + "/width/" + (this.layoutConf.width - 20) + "/aspectratio/true";
        this.panel.getEl().update('');

        if(this.loadedHotspots.length > 0) {
            for(var i = 0; i < this.loadedHotspots.length; i++) {
                this.addHotspot(this.loadedHotspots[i]);
            }

        }

    },

    addSelector: function() {
        Ext.MessageBox.prompt(t('hotspotimage_add_selector'), t('hotspotimage_enter_name_of_new_hotspot'), this.completeAddSelector.bind(this), null, null, "");
    },

    completeAddSelector: function(button, value, object) {
        if(button == "ok") {
            var hotspot = {
                name: value,
                top: 0,
                left: 0,
                width: 20,
                height: 20
            };
            this.addHotspot(hotspot);
        }
    },

    addHotspot: function(hotspot) {
        this.hotspotCount++;
        var number = this.hotspotCount;

        var box = Ext.get(this.getName() + '_selectorImage').getBox();
        var height = this.convertToAbsolute(hotspot.height, box.height);
        var width = this.convertToAbsolute(hotspot.width, box.width);
        var left = this.convertToAbsolute(hotspot.left, box.width) + this.marginLeft;
        var top = this.convertToAbsolute(hotspot.top, box.height) + this.marginTop;

        this.panel.getEl().createChild({
            tag: 'div',
            id: 'selector' + number,
            style: 'cursor:move; position: absolute; top: ' + top + 'px; left: ' + left + 'px;z-index:9000;',
            html: this.getSelectorHtml(hotspot.name)
        });

        var resizer = new Ext.Resizable('selector' + number, {
            pinned:true,
            minWidth:50,
            minHeight: 50,
            preserveRatio: false,
            dynamic:true,
            handles: 'all',
            draggable:true,
            width: width,
            height: height

        });

        this.hotspots[number] = hotspot;
        this.dirty = true;

        resizer.addListener("resize", function(item, width, height, e) {
            this.handleSelectorChanged(number);
        }.bind(this));

        Ext.get('selector' + number).on('mouseup', function(){
            this.handleSelectorChanged(number);
        }.bind(this));

        Ext.get('selector' + number).on("contextmenu", this.onSelectorContextMenu.bind(this, number));
    },

    getSelectorHtml: function(text) {
        return '
' + text + '
';
    },

    handleSelectorChanged: function(selectorNumber) {
        var dimensions = Ext.get("selector" + selectorNumber).getStyles("top","left","width","height");
        var box = Ext.get(this.getName() + '_selectorImage').getBox();
        this.hotspots[selectorNumber].top = this.convertToRelative(intval(dimensions.top) - this.marginTop, box.height);
        this.hotspots[selectorNumber].left = this.convertToRelative(intval(dimensions.left) - this.marginLeft, box.width);
        this.hotspots[selectorNumber].width = this.convertToRelative(intval(dimensions.width), box.width);
        this.hotspots[selectorNumber].height = this.convertToRelative(intval(dimensions.height), box.height);

        this.dirty = true;
    },

    convertToRelative: function(value, totalValue) {
        return value * 100 / totalValue;
    },

    convertToAbsolute: function(value, totalValue) {
        return value / 100 * totalValue;
    },

    onSelectorContextMenu: function (id, e) {
        var menu = new Ext.menu.Menu();
        menu.add(new Ext.menu.Item({
            text: t('delete'),
            iconCls: "pimcore_icon_delete",
            handler: function (item) {
                Ext.get('selector' + id).hide();
                Ext.get('selector' + id).remove();
                delete this.hotspots[id];
            }.bind(this)
        }));

        menu.showAt(e.getXY());

        e.stopEvent();
    },

    empty: function () {
        this.data = null;
        this.hotspots = null;
        this.dirty = true;
        this.layout.removeAll();
        this.createImagePanel();
    },

    getValue: function () {
        return {image: this.data, hotspots: this.hotspots};
    }
});<|endoftext|>


<commit_before>describe('featuremanager/FeatureManagerService', function() {
  var featureManagerService, $httpBackend;
  var mapService = {};
  var createLayer = function(id, config) {
    data = {
      uniqueID: id,
      config: config
    };
    return {
      metadata: data,
      get: function(key) {
        return this.metadata;
      }
    };
  };
  beforeEach(module('MapLoom'));
  beforeEach(module('loom_feature_manager'));

  beforeEach(inject(function(_featureManagerService_, _$httpBackend_) {
    featureManagerService = _featureManagerService_;
    $httpBackend = _$httpBackend_;
  }));

  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });
  describe('#getSelectedItemProperties', function() {
    var feature, layerSpy;
    beforeEach(function() {
      feature = { properties: { name: 'Ocean Beach' }};
      var layer = createLayer(1, {});
      layerSpy = spyOn(featureManagerService, 'getSelectedItemLayer')
      layerSpy.andReturn({layer: layer});
    });
    it('returns the properties properties', function() {
      featureManagerService.show(feature);
      expect(featureManagerService.getSelectedItemProperties()).toEqual([ ['name', 'Ocean Beach']]);
    });
  });

});
<commit_msg>Test masking of features<commit_after>describe('featuremanager/FeatureManagerService', function() {
  var featureManagerService, $httpBackend;
  var mapService = {};
  var createLayer = function(id, config) {
    data = {
      uniqueID: id,
      config: config
    };
    return {
      metadata: data,
      get: function(key) {
        return this.metadata;
      }
    };
  };
  beforeEach(module('MapLoom'));
  beforeEach(module('loom_feature_manager'));

  beforeEach(inject(function(_featureManagerService_, _$httpBackend_) {
    featureManagerService = _featureManagerService_;
    $httpBackend = _$httpBackend_;
  }));

  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });
  describe('#getSelectedItemProperties', function() {
    var feature, layerSpy;
    beforeEach(function() {
      feature = { properties: { name: 'Ocean Beach' }};
      var layer = createLayer(1, {});
      layerSpy = spyOn(featureManagerService, 'getSelectedItemLayer')
      layerSpy.andReturn({layer: layer});
    });
    it('returns the properties properties', function() {
      featureManagerService.show(feature);
      expect(featureManagerService.getSelectedItemProperties()).toEqual([ ['name', 'Ocean Beach']]);
    });
    describe('has saved maskings', function() {
      beforeEach(function() {
        var layer = createLayer(1, { maskings: { name: { alias: 'Feature Name', show: true }}});
        layerSpy.andReturn({layer: layer});
      });
      it('returns the properties properties', function() {
        featureManagerService.show(feature);
        expect(featureManagerService.getSelectedItemProperties()).toEqual([ ['Feature Name', 'Ocean Beach']]);
      });
      describe('hides feature', function() {
        beforeEach(function() {
          var layer = createLayer(1, { maskings: { name: { alias: 'Feature Name', show: false }}});
          layerSpy.andReturn({layer: layer});
        });
        it('does not return the feature', function() {
          featureManagerService.show(feature);
          expect(featureManagerService.getSelectedItemProperties()).toEqual([ ]);
        });
      });
    });
  });

});
<|endoftext|>


<commit_before>/****************************************************************************
 Copyright (c) 2008-2010 Ricardo Quesada
 Copyright (c) 2011-2012 cocos2d-x.org
 Copyright (c) 2013-2014 Chukong Technologies Inc.

 http://www.cocos2d-x.org

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 ****************************************************************************/

var sp = sp || {};

var ANIMATION_TYPE = {
    ANIMATION_START:      0,
    ANIMATION_END:        1,
    ANIMATION_COMPLETE:   2,
    ANIMATION_EVENT:      3
};

SpineTestScene = TestScene.extend({

    runThisTest:function () {
        var layer = SpineTest.create();
        this.addChild(layer);

        director.runScene(this);
    }
});

touchcount = 0;

SpineTest = BaseTestLayer.extend({
    _spineboy:null,
    _debugMode: 0,
    ctor:function () {
        this._super(cc.color(0,0,0,255), cc.color(98,99,117,255));

        cc.eventManager.addListener({
            event: cc.EventListener.TOUCH_ALL_AT_ONCE,
            onTouchesBegan: function(touches, event){
                var target = event.getCurrentTarget();
                target._debugMode ++;
                target._debugMode = target._debugMode % 3;
                if (target._debugMode == 0) {
                    target._spineboy.setDebugBones(false);
                    target._spineboy.setDebugSolots(false);
                    return;
                }

                if (target._debugMode == 1) {
                    target._spineboy.setDebugBones(true);
                    target._spineboy.setDebugSolots(false);
                    return;
                }

                if (target._debugMode == 2) {
                    target._spineboy.setDebugBones(false);
                    target._spineboy.setDebugSolots(true);
                }
            }
        }, this);
        var size = director.getWinSize();

        /////////////////////////////
        // Make Spine's Animated skeleton Node
        // You need 'json + atlas + image' resource files to make it.
        // No JS binding for spine-c in this version. So, only file loading is supported.
        var spineBoy = sp.SkeletonAnimation.create('res/skeletons/spineboy.json', 'res/skeletons/spineboy.atlas');
        spineBoy.setPosition(cc.p(size.width / 2, size.height / 2 - 150));
        spineBoy.setAnimation(0, 'walk', true);
        spineBoy.setMix('walk', 'jump', 0.2);
        spineBoy.setMix('jump', 'walk', 0.4);
        spineBoy.setAnimationListener(this, this.animationStateEvent);
        this.addChild(spineBoy, 4);
        this._spineboy = spineBoy;
    },
    onBackCallback:function (sender) {
    },
    onRestartCallback:function (sender) {
    },
    onNextCallback:function (sender) {
        touchcount++;
        this._spineboy.setAnimation(0, ['walk', 'jump'][touchcount % 2], true);
    },
    subtitle:function () {
        return "Spine test";
    },
    title:function () {
        return "Spine test";
    },

    animationStateEvent: function(obj, trackIndex, type, event, loopCount) {
        var entry = this._spineboy.getCurrent();
        var animationName = (entry && entry.animation) ? entry.animation.name : 0;

        switch(type)
        {
            case ANIMATION_TYPE.ANIMATION_START:
                cc.log(trackIndex + " start: " + animationName);
                break;
            case ANIMATION_TYPE.ANIMATION_END:
                cc.log(trackIndex + " end:" + animationName);
                break;
            case ANIMATION_TYPE.ANIMATION_EVENT:
                cc.log(trackIndex + " event: " + animationName);
                break;
            case ANIMATION_TYPE.ANIMATION_COMPLETE:
                cc.log(trackIndex + " complete: " + animationName + "," + loopCount);
                break;
            default :
                break;
        }
    },

    // automation
    numberOfPendingTests:function() {
        return 1;
    },
    getTestNumber:function() {
        return 0;
    }

});

SpineTest.create = function () {
    return new SpineTest();
};
<commit_msg>issue #5685: replace create with new in SpineTest.js<commit_after>/****************************************************************************
 Copyright (c) 2008-2010 Ricardo Quesada
 Copyright (c) 2011-2012 cocos2d-x.org
 Copyright (c) 2013-2014 Chukong Technologies Inc.

 http://www.cocos2d-x.org

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 ****************************************************************************/

var sp = sp || {};

var ANIMATION_TYPE = {
    ANIMATION_START:      0,
    ANIMATION_END:        1,
    ANIMATION_COMPLETE:   2,
    ANIMATION_EVENT:      3
};

SpineTestScene = TestScene.extend({

    runThisTest:function () {
        var layer = new SpineTest();
        this.addChild(layer);

        director.runScene(this);
    }
});

touchcount = 0;

SpineTest = BaseTestLayer.extend({
    _spineboy:null,
    _debugMode: 0,
    ctor:function () {
        this._super(cc.color(0,0,0,255), cc.color(98,99,117,255));

        cc.eventManager.addListener({
            event: cc.EventListener.TOUCH_ALL_AT_ONCE,
            onTouchesBegan: function(touches, event){
                var target = event.getCurrentTarget();
                target._debugMode ++;
                target._debugMode = target._debugMode % 3;
                if (target._debugMode == 0) {
                    target._spineboy.setDebugBones(false);
                    target._spineboy.setDebugSolots(false);
                    return;
                }

                if (target._debugMode == 1) {
                    target._spineboy.setDebugBones(true);
                    target._spineboy.setDebugSolots(false);
                    return;
                }

                if (target._debugMode == 2) {
                    target._spineboy.setDebugBones(false);
                    target._spineboy.setDebugSolots(true);
                }
            }
        }, this);
        var size = director.getWinSize();

        /////////////////////////////
        // Make Spine's Animated skeleton Node
        // You need 'json + atlas + image' resource files to make it.
        // No JS binding for spine-c in this version. So, only file loading is supported.
        var spineBoy = new sp.SkeletonAnimation('res/skeletons/spineboy.json', 'res/skeletons/spineboy.atlas');
        spineBoy.setPosition(cc.p(size.width / 2, size.height / 2 - 150));
        spineBoy.setAnimation(0, 'walk', true);
        spineBoy.setMix('walk', 'jump', 0.2);
        spineBoy.setMix('jump', 'walk', 0.4);
        spineBoy.setAnimationListener(this, this.animationStateEvent);
        this.addChild(spineBoy, 4);
        this._spineboy = spineBoy;
    },
    onBackCallback:function (sender) {
    },
    onRestartCallback:function (sender) {
    },
    onNextCallback:function (sender) {
        touchcount++;
        this._spineboy.setAnimation(0, ['walk', 'jump'][touchcount % 2], true);
    },
    subtitle:function () {
        return "Spine test";
    },
    title:function () {
        return "Spine test";
    },

    animationStateEvent: function(obj, trackIndex, type, event, loopCount) {
        var entry = this._spineboy.getCurrent();
        var animationName = (entry && entry.animation) ? entry.animation.name : 0;

        switch(type)
        {
            case ANIMATION_TYPE.ANIMATION_START:
                cc.log(trackIndex + " start: " + animationName);
                break;
            case ANIMATION_TYPE.ANIMATION_END:
                cc.log(trackIndex + " end:" + animationName);
                break;
            case ANIMATION_TYPE.ANIMATION_EVENT:
                cc.log(trackIndex + " event: " + animationName);
                break;
            case ANIMATION_TYPE.ANIMATION_COMPLETE:
                cc.log(trackIndex + " complete: " + animationName + "," + loopCount);
                break;
            default :
                break;
        }
    },

    // automation
    numberOfPendingTests:function() {
        return 1;
    },
    getTestNumber:function() {
        return 0;
    }

});
<|endoftext|>


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

  angular
    .module('app.main.chat.bot')
    .controller('ChatBotController', ChatBotController);

  /** @ngInject */
  function ChatBotController($timeout, $document, $mdDialog, Bot, Util, User, user) {
    const vm = this;

    // Data

    vm.working = false;
    vm.grow = false;
    vm.query = '';
    vm.thread = [];
    vm.user = user;

    // Methods

    vm.about = about;
    vm.clear = clear;
    vm.conversate = conversate;

    //////////

    init();

    async function init() {
      vm.user = await User.update(user, { token: null });
    }

    function about($event) {
      const html = [
        'I\'m a bot that can answer questions about courses.',
        'Start by asking me a question.',
        'For example, "What\'s the hardest?" or "What\'s the easiest?"'
      ].join('

');

      const dialog = $mdDialog.alert()
        .title('About')
        .htmlContent(html)
        .ok('OK')
        .targetEvent($event);

      $mdDialog.show(dialog);
    }

    function clear() {
      _reset();

      if (vm.thread.length) {
        vm.thread = [];
        Util.toast('Messages cleared!');
      } else {
        Util.toast('Nothing to clear!');
      }
    }

    async function conversate($event, fromClick) {
      if ($event && $event.keyCode === 13 && $event.shiftKey) {
        vm.grow = true;
        return;
      }

      if ($event && $event.keyCode !== 13 && !fromClick) {
        return;
      }

      if (!vm.query) {
        _reset();
        return;
      }

      const query = vm.query;

      _reset();

      _log({ by: 'user', text: query });

      vm.working = true;
      try {
        _log({ by: 'bot', text: await Bot.conversate(query) });
      } catch (error) {
        Util.toast('Oops, I encountered an error! Please try again.');
      }
      vm.working = false;
    }

    function _reset() {
      vm.grow = false;
      vm.query = '';
    }

    function _log(message) {
      $timeout(() => {
        vm.thread.push(_.assign({}, message, { time: moment.utc().format() }));
        _scroll();
        _focus();
      });
    }

    function _scroll() {
      $timeout(() => {
        const chatContent = angular.element($document.find('#gt-chat-content'));
        chatContent.animate({
          scrollTop: chatContent[0].scrollHeight
        }, 400);
      });
    }

    function _focus() {
      $timeout(() => {
        angular.element('#gt-chat textarea').focus();
      });
    }
  }
})();
<commit_msg>add more sample questions<commit_after>(function () {
  'use strict';

  angular
    .module('app.main.chat.bot')
    .controller('ChatBotController', ChatBotController);

  /** @ngInject */
  function ChatBotController($timeout, $document, $mdDialog, Bot, Util, User, user) {
    const vm = this;

    // Data

    vm.working = false;
    vm.grow = false;
    vm.query = '';
    vm.thread = [];
    vm.user = user;

    // Methods

    vm.about = about;
    vm.clear = clear;
    vm.conversate = conversate;

    //////////

    init();

    async function init() {
      vm.user = await User.update(user, { token: null });
    }

    function about($event) {
      const html = [
        'I\'m a bot that can answer questions about courses.',
        'Start by asking me a question.',
        'Some examples:,'
        '"What\'s the hardest?" or "How is the math in AI?"',
        'or "Which languages should I know for BD4H?"'
      ].join('

');

      const dialog = $mdDialog.alert()
        .title('About')
        .htmlContent(html)
        .ok('OK')
        .targetEvent($event);

      $mdDialog.show(dialog);
    }

    function clear() {
      _reset();

      if (vm.thread.length) {
        vm.thread = [];
        Util.toast('Messages cleared!');
      } else {
        Util.toast('Nothing to clear!');
      }
    }

    async function conversate($event, fromClick) {
      if ($event && $event.keyCode === 13 && $event.shiftKey) {
        vm.grow = true;
        return;
      }

      if ($event && $event.keyCode !== 13 && !fromClick) {
        return;
      }

      if (!vm.query) {
        _reset();
        return;
      }

      const query = vm.query;

      _reset();

      _log({ by: 'user', text: query });

      vm.working = true;
      try {
        _log({ by: 'bot', text: await Bot.conversate(query) });
      } catch (error) {
        Util.toast('Oops, I encountered an error! Please try again.');
      }
      vm.working = false;
    }

    function _reset() {
      vm.grow = false;
      vm.query = '';
    }

    function _log(message) {
      $timeout(() => {
        vm.thread.push(_.assign({}, message, { time: moment.utc().format() }));
        _scroll();
        _focus();
      });
    }

    function _scroll() {
      $timeout(() => {
        const chatContent = angular.element($document.find('#gt-chat-content'));
        chatContent.animate({
          scrollTop: chatContent[0].scrollHeight
        }, 400);
      });
    }

    function _focus() {
      $timeout(() => {
        angular.element('#gt-chat textarea').focus();
      });
    }
  }
})();
<|endoftext|>