<commit_before>angular.module('ZoumProfiler')
    .directive('import', function() {
        return {
            restrict: 'E',
            templateUrl: 'import/import.html'
        };
    })
    .controller('ImportController', ['$scope', '$filter', '$http', 'base', 'profiling', function ($scope, $filter, $http, base, profiling) {

        /* ********************************************* */
        /* **             Contextual data             ** */
        /* ********************************************* */

        $scope.import = {};
        $scope._mhToZoumprofilerCompsIndex = {
            '1': 'bs',
            '2': 'ra',
            '3': 'am',
            '4': 'camou',
            '5': 'idc',
            '6': 'balayage',
            '7': 'frene',
            '8': 'cdb',
            '9': 'ap',
            '10': 'parer',
            '11': 'ca',
            '12': 'de',
            '14': 'charger',
            '15': 'piege_feu',
            '16': 'cdm',
            '17': 'he',
            '18': 'insultes',
            '19': 'em',
            '21': 'pistage',
            '23': 'lancer',
            '24': 'bidouiller',
            '25': 'melange',
            '26': 'grattage',
            '27': 'dressage',
            '28': 'shamaner',
            '29': 'miner',
            '30': 'tailler',
            '33': 'necro',
            '35': 'planter',
            '37': 'marquage',
            '38': 'retraite',
            '40': 'reparation',
            '41': 'golem_cuir',
            '42': 'rotobaffe',
            '43': 'baroufle',
            '44': 'course',
            '45': 'interposer',
            '46': 'painthure'
        };
        $scope._mhToZoumprofilerSortsIndex = {
             '1': 'projo',
             '2': 'hypno',
             '3': 'vampi',
             '4': 'rp',
             '5': 'add',
             '6': 'ada',
             '7': 'ade',
             '8': 'explo',
             '9': 'vl',
            '10': 'idt',
            '11': 'vt',
            '12': 'fp',
            '13': 'tp',
            '14': 'siphon',
            '15': 'invi',
            '16': 'ae',
            '17': 'sacro',
            '18': 'glue',
            '19': 'fa',
            '20': 'aa',
            '21': 'projection',
            '22': 'va',
            '23': 'vlc',
            '24': 'telek',
            '27': 'bam',
            '28': 'gds',
            '29': 'bum',
            '33': 'levitation',
            '34': 'prem',
            '35': 'pum',
            '36': 'obsi'
        };

        /* ********************************************* */
        /* **          Controller's methods           ** */
        /* ********************************************* */

        $scope._toComparable = function(profile) {
            var result = angular.copy(profile);
            delete result['_id'];
            delete result['_internal'];
            delete result['type'];
            return result;
        };

        $scope._importProfile = function(newProfile) {
            if (newProfile.comps) {
                angular.forEach(base.comps, function (comp) {
                    if (comp.levels > 1) {
                        for (var lvl = comp.levels; lvl >= 1; lvl--) {
                            var compIdHigherLvl = base.getCompId(comp, lvl + 1);
                            if (newProfile.comps[compIdHigherLvl] === true) {
                                var compId = base.getCompId(comp, lvl);
                                newProfile.comps[compId] = true;
                            }
                        }
                    }
                });
            }

            var profileAlreadyExists = false;
            angular.forEach($scope.profiles, function(profile) {
                var areEquals = angular.equals($scope._toComparable(profile), $scope._toComparable(newProfile));
                if (!areEquals && profile.id == newProfile.id) {
                    newProfile.id = $scope._randomId();
                }
                profileAlreadyExists |= areEquals;
            });
            if (profileAlreadyExists) {
                $scope._addWarningMessage("Un profil identique existe déjà dans votre liste de profils");
            } else {
                if ($scope.isAuthenticated()) {
                    newProfile.type = "remote";
                } else {
                    newProfile.type = "local";
                }
                $scope.profiles.push(newProfile);
                $scope._save(newProfile);
                $scope._addSuccessMessage("Le profil " + $filter('prettyName')(newProfile) + " a bien été ajouté à votre liste de profils");
            }
            $scope._reset();
        };

        $scope._importProfileFromJson = function(profileJson) {
            var newProfile = angular.fromJson(profileJson);
            delete newProfile['_id'];
            delete newProfile['_internal'];
            $scope._importProfile(newProfile);
        };

        $scope.importProfileFromJson = function() {
            $scope._importProfileFromJson($scope.import.json);
            delete $scope.import.spTrollId;
            delete $scope.import.spTrollPassword;
            delete $scope.import.json;
        };

        $scope.importProfileFromSp = function() {

            var newProfile = { comps : {cdm1 : true}, sorts : {idt : true}, id : $scope._randomId() };
            profiling.checkCaracMin(newProfile);
            profiling.checkBonus(newProfile);

            var importDuringLast24h = false;

            var lastImportTxt = localStorage.getItem("lastImportFor" + $scope.import.spTrollId);
            if (lastImportTxt) {
                var lastImport = parseInt(lastImportTxt);
                var now = new Date().getTime();
                importDuringLast24h = (now - lastImport < 86400000);
                $scope._addErrorMessage("Vous avez déjà fait un import de ce profil dans les dernières 24h.");
            }

            if (!importDuringLast24h) {
                // FIXME AThimel 13/12/2014 This XHR success cascade is ugly, find a better way

                var urlCaract = "proxy/sp.php?script=SP_Caract.php&trollId=" + $scope.import.spTrollId + "&trollPassword=" + $scope.import.spTrollPassword;
                $http.get(urlCaract).
                    success(function (dataCaract) {

                        if (dataCaract.substring(0, 6) == "Erreur") {
                            $scope._addErrorMessage(dataCaract);
                        } else {
                            var caractLines = dataCaract.split('\n');
                            angular.forEach(caractLines, function (line) {

                                // Type; Attaque; Esquive; Dégats; Régénération; PVMax; PVActuels; Portée deVue; RM; MM; Armure; Duree du Tour; Poids; Concentration
                                var cells = line.split(';');

                                if (cells.length >= 12) {
                                    var tab;
                                    var type = cells[0];
                                    switch (type) {
                                        case 'CAR':
                                            tab = newProfile.caracs;
                                            break;
                                        case 'BMM':
                                            tab = newProfile.bm;
                                            break;
                                        case 'BMP':
                                            tab = newProfile.bp;
                                            break;
                                    }
                                    tab['ATT'] = parseInt(cells[1]);
                                    tab['ESQ'] = parseInt(cells[2]);
                                    tab['DEG'] = parseInt(cells[3]);
                                    tab['REG'] = parseInt(cells[4]);
                                    if (type == 'CAR') {
                                        tab['PV'] = parseInt(cells[5]);
                                        tab['VUE'] = parseInt(cells[7]);
                                    } else { // Put all in BM
                                        newProfile.bm['PV'] = newProfile.bm['PV'] + parseInt(cells[5]);
                                        newProfile.bm['VUE'] = newProfile.bm['VUE'] + parseInt(cells[7]);
                                    }

                                    tab['ARM'] = parseInt(cells[10]);
                                    if (type == 'CAR') {
                                        tab['TOUR'] = parseInt(cells[11]);
                                    }
                                }
                            });

                            var urlComp = "proxy/sp.php?script=SP_Aptitudes2.php&trollId=" + $scope.import.spTrollId + "&trollPassword=" + $scope.import.spTrollPassword;
                            $http.get(urlComp).
                                success(function (dataComp) {

                                    if (dataComp.substring(0, 6) == "Erreur") {
                                        $scope._addErrorMessage(dataComp);
                                    } else {
                                        var compsLines = dataComp.split('\n');
                                        angular.forEach(compsLines, function (line) {

                                            var cells = line.split(';');

                                            if (cells.length >= 5) {
                                                switch (cells[0]) {
                                                    case "C":
                                                        var mhBaseCompId = cells[1];
                                                        var baseCompId = $scope._mhToZoumprofilerCompsIndex[mhBaseCompId];
                                                        var compLvl = cells[4];
                                                        var compId = baseCompId + compLvl;
                                                        var comp = base.getCompOrSort(compId);
                                                        newProfile.comps[comp.id] = true;
                                                        break;
                                                    case "S":
                                                        var mhBaseSortId = cells[1];
                                                        var baseSortId = $scope._mhToZoumprofilerSortsIndex[mhBaseSortId];
                                                        var sortId = baseSortId;
                                                        var sort = base.getCompOrSort(sortId);
                                                        newProfile.sorts[sort.id] = true;
                                                        break;
                                                }
                                            }
                                        });

                                        var urlProfile = "proxy/sp.php?script=SP_ProfilPublic2.php&trollId=" + $scope.import.spTrollId + "&trollPassword=" + $scope.import.spTrollPassword;
                                        $http.get(urlProfile).
                                            success(function (dataProfile) {

                                                if (dataProfile.substring(0, 6) == "Erreur") {
                                                    $scope._addErrorMessage(dataProfile);
                                                } else {
                                                    var cells = dataProfile.split(';');

                                                    if (cells.length >= 4) {
                                                        newProfile.name = cells[1];
                                                        newProfile.profile = "sp" + cells[3];
                                                        newProfile.race = cells[2];

                                                        localStorage.setItem("lastImportFor" + $scope.import.spTrollId, "" + new Date().getTime());

                                                        $scope._importProfile(newProfile);

                                                        delete $scope.import.spTrollId;
                                                        delete $scope.import.spTrollPassword;
                                                        delete $scope.import.json;

                                                        $scope._addWarningMessage(
                                                            "Le profil importé tient compte de vos bonus/malus en " +
                                                            "cours, pensez à ajuster votre profil après l'import !");

                                                    }
                                                }

                                            }).
                                            error(function (data) {
                                                $scope._addErrorMessage("Import impossible: " + data);
                                            });

                                    }
                                }).
                                error(function (data) {
                                    $scope._addErrorMessage("Import impossible: " + data);
                                });

                        }

                    }).
                    error(function (data) {
                        $scope._addErrorMessage("Import impossible: " + data);
                    });
            }

        };

        /* ********************************************* */
        /* **                 Startup                 ** */
        /* ********************************************* */

        if (angular.isDefined($scope.importContext.startupImportJson)) {
            $scope._importProfileFromJson($scope.importContext.startupImportJson);
            delete $scope.importContext.startupImportJson;
        }

    }]);

<commit_msg>fixes #3 Correction de la condition d'affichage du message<commit_after>angular.module('ZoumProfiler')
    .directive('import', function() {
        return {
            restrict: 'E',
            templateUrl: 'import/import.html'
        };
    })
    .controller('ImportController', ['$scope', '$filter', '$http', 'base', 'profiling', function ($scope, $filter, $http, base, profiling) {

        /* ********************************************* */
        /* **             Contextual data             ** */
        /* ********************************************* */

        $scope.import = {};
        $scope._mhToZoumprofilerCompsIndex = {
            '1': 'bs',
            '2': 'ra',
            '3': 'am',
            '4': 'camou',
            '5': 'idc',
            '6': 'balayage',
            '7': 'frene',
            '8': 'cdb',
            '9': 'ap',
            '10': 'parer',
            '11': 'ca',
            '12': 'de',
            '14': 'charger',
            '15': 'piege_feu',
            '16': 'cdm',
            '17': 'he',
            '18': 'insultes',
            '19': 'em',
            '21': 'pistage',
            '23': 'lancer',
            '24': 'bidouiller',
            '25': 'melange',
            '26': 'grattage',
            '27': 'dressage',
            '28': 'shamaner',
            '29': 'miner',
            '30': 'tailler',
            '33': 'necro',
            '35': 'planter',
            '37': 'marquage',
            '38': 'retraite',
            '40': 'reparation',
            '41': 'golem_cuir',
            '42': 'rotobaffe',
            '43': 'baroufle',
            '44': 'course',
            '45': 'interposer',
            '46': 'painthure'
        };
        $scope._mhToZoumprofilerSortsIndex = {
             '1': 'projo',
             '2': 'hypno',
             '3': 'vampi',
             '4': 'rp',
             '5': 'add',
             '6': 'ada',
             '7': 'ade',
             '8': 'explo',
             '9': 'vl',
            '10': 'idt',
            '11': 'vt',
            '12': 'fp',
            '13': 'tp',
            '14': 'siphon',
            '15': 'invi',
            '16': 'ae',
            '17': 'sacro',
            '18': 'glue',
            '19': 'fa',
            '20': 'aa',
            '21': 'projection',
            '22': 'va',
            '23': 'vlc',
            '24': 'telek',
            '27': 'bam',
            '28': 'gds',
            '29': 'bum',
            '33': 'levitation',
            '34': 'prem',
            '35': 'pum',
            '36': 'obsi'
        };

        /* ********************************************* */
        /* **          Controller's methods           ** */
        /* ********************************************* */

        $scope._toComparable = function(profile) {
            var result = angular.copy(profile);
            delete result['_id'];
            delete result['_internal'];
            delete result['type'];
            return result;
        };

        $scope._importProfile = function(newProfile) {
            if (newProfile.comps) {
                angular.forEach(base.comps, function (comp) {
                    if (comp.levels > 1) {
                        for (var lvl = comp.levels; lvl >= 1; lvl--) {
                            var compIdHigherLvl = base.getCompId(comp, lvl + 1);
                            if (newProfile.comps[compIdHigherLvl] === true) {
                                var compId = base.getCompId(comp, lvl);
                                newProfile.comps[compId] = true;
                            }
                        }
                    }
                });
            }

            var profileAlreadyExists = false;
            angular.forEach($scope.profiles, function(profile) {
                var areEquals = angular.equals($scope._toComparable(profile), $scope._toComparable(newProfile));
                if (!areEquals && profile.id == newProfile.id) {
                    newProfile.id = $scope._randomId();
                }
                profileAlreadyExists |= areEquals;
            });
            if (profileAlreadyExists) {
                $scope._addWarningMessage("Un profil identique existe déjà dans votre liste de profils");
            } else {
                if ($scope.isAuthenticated()) {
                    newProfile.type = "remote";
                } else {
                    newProfile.type = "local";
                }
                $scope.profiles.push(newProfile);
                $scope._save(newProfile);
                $scope._addSuccessMessage("Le profil " + $filter('prettyName')(newProfile) + " a bien été ajouté à votre liste de profils");
            }
            $scope._reset();
        };

        $scope._importProfileFromJson = function(profileJson) {
            var newProfile = angular.fromJson(profileJson);
            delete newProfile['_id'];
            delete newProfile['_internal'];
            $scope._importProfile(newProfile);
        };

        $scope.importProfileFromJson = function() {
            $scope._importProfileFromJson($scope.import.json);
            delete $scope.import.spTrollId;
            delete $scope.import.spTrollPassword;
            delete $scope.import.json;
        };

        $scope.importProfileFromSp = function() {

            var newProfile = { comps : {cdm1 : true}, sorts : {idt : true}, id : $scope._randomId() };
            profiling.checkCaracMin(newProfile);
            profiling.checkBonus(newProfile);

            var importDuringLast24h = false;

            var lastImportTxt = localStorage.getItem("lastImportFor" + $scope.import.spTrollId);
            if (lastImportTxt) {
                var lastImport = parseInt(lastImportTxt);
                var now = new Date().getTime();
                importDuringLast24h = (now - lastImport < 86400000);
            }

            if (importDuringLast24h) {
                $scope._addErrorMessage("Vous avez déjà fait un import de ce profil dans les dernières 24h.");
            } else {
                // FIXME AThimel 13/12/2014 This XHR success cascade is ugly, find a better way

                var urlCaract = "proxy/sp.php?script=SP_Caract.php&trollId=" + $scope.import.spTrollId + "&trollPassword=" + $scope.import.spTrollPassword;
                $http.get(urlCaract).
                    success(function (dataCaract) {

                        if (dataCaract.substring(0, 6) == "Erreur") {
                            $scope._addErrorMessage(dataCaract);
                        } else {
                            var caractLines = dataCaract.split('\n');
                            angular.forEach(caractLines, function (line) {

                                // Type; Attaque; Esquive; Dégats; Régénération; PVMax; PVActuels; Portée deVue; RM; MM; Armure; Duree du Tour; Poids; Concentration
                                var cells = line.split(';');

                                if (cells.length >= 12) {
                                    var tab;
                                    var type = cells[0];
                                    switch (type) {
                                        case 'CAR':
                                            tab = newProfile.caracs;
                                            break;
                                        case 'BMM':
                                            tab = newProfile.bm;
                                            break;
                                        case 'BMP':
                                            tab = newProfile.bp;
                                            break;
                                    }
                                    tab['ATT'] = parseInt(cells[1]);
                                    tab['ESQ'] = parseInt(cells[2]);
                                    tab['DEG'] = parseInt(cells[3]);
                                    tab['REG'] = parseInt(cells[4]);
                                    if (type == 'CAR') {
                                        tab['PV'] = parseInt(cells[5]);
                                        tab['VUE'] = parseInt(cells[7]);
                                    } else { // Put all in BM
                                        newProfile.bm['PV'] = newProfile.bm['PV'] + parseInt(cells[5]);
                                        newProfile.bm['VUE'] = newProfile.bm['VUE'] + parseInt(cells[7]);
                                    }

                                    tab['ARM'] = parseInt(cells[10]);
                                    if (type == 'CAR') {
                                        tab['TOUR'] = parseInt(cells[11]);
                                    }
                                }
                            });

                            var urlComp = "proxy/sp.php?script=SP_Aptitudes2.php&trollId=" + $scope.import.spTrollId + "&trollPassword=" + $scope.import.spTrollPassword;
                            $http.get(urlComp).
                                success(function (dataComp) {

                                    if (dataComp.substring(0, 6) == "Erreur") {
                                        $scope._addErrorMessage(dataComp);
                                    } else {
                                        var compsLines = dataComp.split('\n');
                                        angular.forEach(compsLines, function (line) {

                                            var cells = line.split(';');

                                            if (cells.length >= 5) {
                                                switch (cells[0]) {
                                                    case "C":
                                                        var mhBaseCompId = cells[1];
                                                        var baseCompId = $scope._mhToZoumprofilerCompsIndex[mhBaseCompId];
                                                        var compLvl = cells[4];
                                                        var compId = baseCompId + compLvl;
                                                        var comp = base.getCompOrSort(compId);
                                                        newProfile.comps[comp.id] = true;
                                                        break;
                                                    case "S":
                                                        var mhBaseSortId = cells[1];
                                                        var baseSortId = $scope._mhToZoumprofilerSortsIndex[mhBaseSortId];
                                                        var sortId = baseSortId;
                                                        var sort = base.getCompOrSort(sortId);
                                                        newProfile.sorts[sort.id] = true;
                                                        break;
                                                }
                                            }
                                        });

                                        var urlProfile = "proxy/sp.php?script=SP_ProfilPublic2.php&trollId=" + $scope.import.spTrollId + "&trollPassword=" + $scope.import.spTrollPassword;
                                        $http.get(urlProfile).
                                            success(function (dataProfile) {

                                                if (dataProfile.substring(0, 6) == "Erreur") {
                                                    $scope._addErrorMessage(dataProfile);
                                                } else {
                                                    var cells = dataProfile.split(';');

                                                    if (cells.length >= 4) {
                                                        newProfile.name = cells[1];
                                                        newProfile.profile = "sp" + cells[3];
                                                        newProfile.race = cells[2];

                                                        localStorage.setItem("lastImportFor" + $scope.import.spTrollId, "" + new Date().getTime());

                                                        $scope._importProfile(newProfile);

                                                        delete $scope.import.spTrollId;
                                                        delete $scope.import.spTrollPassword;
                                                        delete $scope.import.json;

                                                        $scope._addWarningMessage(
                                                            "Le profil importé tient compte de vos bonus/malus en " +
                                                            "cours, pensez à ajuster votre profil après l'import !");

                                                    }
                                                }

                                            }).
                                            error(function (data) {
                                                $scope._addErrorMessage("Import impossible: " + data);
                                            });

                                    }
                                }).
                                error(function (data) {
                                    $scope._addErrorMessage("Import impossible: " + data);
                                });

                        }

                    }).
                    error(function (data) {
                        $scope._addErrorMessage("Import impossible: " + data);
                    });
            }

        };

        /* ********************************************* */
        /* **                 Startup                 ** */
        /* ********************************************* */

        if (angular.isDefined($scope.importContext.startupImportJson)) {
            $scope._importProfileFromJson($scope.importContext.startupImportJson);
            delete $scope.importContext.startupImportJson;
        }

    }]);

<|endoftext|>


<commit_before>var express = require('express')
  , auth = require('mongoose-auth')
  , env = require('./env')
  , util = require('util')
  , port = env.port
  , secrets = env.secrets
  , EventEmitter = require('events').EventEmitter
  , Stats = require('../models/stats')
  , Twitter = require('../models/twitter')
  , ratchetio = require('ratchetio');
require('jadevu');

// express
var app = module.exports = express();

// some paths
app.paths = {
  public: __dirname + '/../public',
  views: __dirname + '/../views'
};

// uncaught error handling
ratchetio.handleUncaughtExceptions('a99bad94e4ba4ec0b78dc90e033743b1');

process.on('uncaughtException', function(e) {
  util.debug(e.stack.red);
});

// utilities & hacks
require('colors');
require('../lib/render2');
require('../lib/underscore.shuffle');
require('../lib/regexp-extensions');

// events
app.events = new EventEmitter();

// db
app.db = require('../models')(env.mongo_url);
app.db.app = app;  // sooo hacky

// stats (kinda hacky)
app.stats = new Stats(app.db, function(err) {
  if (err) throw err;
});
app.stats.on('change', function(stats) {
  app.events.emit('updateStats', stats);
});

// twitter
app.twitter = new Twitter(secrets.twitterUser)

// state (getting pretty gross)
app.enable('pre-registration');  // just the countdown
app.disable('registration');  // months beforehand
app.disable('pre-coding');     // week beforehand
app.disable('coding');        // coding + several hours before
app.disable('voting');        // after
app.disable('winners');        // after winners are selected

app.configure(function() {
  var assetManager = require('./assetmanager')(app);

  app.use(express.compress());
  app.use(assetManager);
  app.locals({ assetManager: assetManager });
});

app.configure('development', function() {
  app.use(express.static(app.paths.public));
  require('../lib/mongo-log')(app.db.mongo);
});
app.configure('production', function() {
  app.use(express.static(app.paths.public, { maxAge: 1000*60*5 }));
  app.use(function(req, res, next) {
    return next();
    if (req.connection.remoteAddress !== '127.0.0.1' && req.headers.host !== 'nodeknockout.com')
      res.redirect('http://nodeknockout.com' + req.url);
    else
      next();
  });
});

app.configure(function() {
  var RedisStore = require('connect-redis')(express);

  // cookies and sessions
  app.use(express.cookieParser());
  app.use(express.session({
    secret: secrets.session,
    store: new RedisStore,
    cookie: { path: '/', httpOnly: true, maxAge: 1000*60*60*24*28 }
  }));

  app.use(express.bodyParser());
  app.use(express.methodOverride());

  // hacky solution for post commit hooks not to check csrf
  // app.use(require('../controllers/commits')(app));
  // app.use(require('../controllers/deploys')(app));

  // csrf protection
  // app.use(express.csrf());
  // app.use(function(req, res, next) {
  //   if (req.body) delete req.body._csrf;
  //   next();
  // });

  // helpers
  // auth.helpExpress(app);
  require('../helpers')(app);

  app.use(express.logger());
  app.use(auth.middleware());
  app.use(app.router);

  // request error handling
  var ratchetErroHandler = ratchetio.errorHandler();
  app.use(function(err, req, res, next) {
    if (typeof(err) !== 'number') {
      ratchetErroHandler(err, req, res, next);
    } else {
      next(err, req, res);
    }
  });

  app.use(function(e, req, res, next) {
    if (typeof(e) === 'number')
      return res.render2('errors/' + e, { status: e });

    if (typeof(e) === 'string')
      e = Error(e);

    console.error(e.stack);
    res.render2('errors/500', { error: e });
  });

  app.set('views', app.paths.views);
  app.set('view engine', 'jade');
});

app.listen(port);
app.ws = require('socket.io').listen(app);
app.ws.set('log level', 1);
app.ws.set('browser client minification', true);

app.on('listening', function() {
  require('util').log('listening on ' + ('0.0.0.0:' + port).cyan);

  // if run as root, downgrade to the owner of this file
  if (env.production && process.getuid() === 0)
    require('fs').stat(__filename, function(err, stats) {
      if (err) return util.log(err)
      process.setuid(stats.uid);
    });
});
<commit_msg>Revert "disable csrf"<commit_after>var express = require('express')
  , auth = require('mongoose-auth')
  , env = require('./env')
  , util = require('util')
  , port = env.port
  , secrets = env.secrets
  , EventEmitter = require('events').EventEmitter
  , Stats = require('../models/stats')
  , Twitter = require('../models/twitter')
  , ratchetio = require('ratchetio');
require('jadevu');

// express
var app = module.exports = express();

// some paths
app.paths = {
  public: __dirname + '/../public',
  views: __dirname + '/../views'
};

// uncaught error handling
ratchetio.handleUncaughtExceptions('a99bad94e4ba4ec0b78dc90e033743b1');

process.on('uncaughtException', function(e) {
  util.debug(e.stack.red);
});

// utilities & hacks
require('colors');
require('../lib/render2');
require('../lib/underscore.shuffle');
require('../lib/regexp-extensions');

// events
app.events = new EventEmitter();

// db
app.db = require('../models')(env.mongo_url);
app.db.app = app;  // sooo hacky

// stats (kinda hacky)
app.stats = new Stats(app.db, function(err) {
  if (err) throw err;
});
app.stats.on('change', function(stats) {
  app.events.emit('updateStats', stats);
});

// twitter
app.twitter = new Twitter(secrets.twitterUser)

// state (getting pretty gross)
app.enable('pre-registration');  // just the countdown
app.disable('registration');  // months beforehand
app.disable('pre-coding');     // week beforehand
app.disable('coding');        // coding + several hours before
app.disable('voting');        // after
app.disable('winners');        // after winners are selected

app.configure(function() {
  var assetManager = require('./assetmanager')(app);

  app.use(express.compress());
  app.use(assetManager);
  app.locals({ assetManager: assetManager });
});

app.configure('development', function() {
  app.use(express.static(app.paths.public));
  require('../lib/mongo-log')(app.db.mongo);
});
app.configure('production', function() {
  app.use(express.static(app.paths.public, { maxAge: 1000*60*5 }));
  app.use(function(req, res, next) {
    return next();
    if (req.connection.remoteAddress !== '127.0.0.1' && req.headers.host !== 'nodeknockout.com')
      res.redirect('http://nodeknockout.com' + req.url);
    else
      next();
  });
});

app.configure(function() {
  var RedisStore = require('connect-redis')(express);

  // cookies and sessions
  app.use(express.cookieParser());
  app.use(express.session({
    secret: secrets.session,
    store: new RedisStore,
    cookie: { path: '/', httpOnly: true, maxAge: 1000*60*60*24*28 }
  }));

  app.use(express.bodyParser());
  app.use(express.methodOverride());

  // hacky solution for post commit hooks not to check csrf
  // app.use(require('../controllers/commits')(app));
  // app.use(require('../controllers/deploys')(app));

  // csrf protection
  app.use(express.csrf());
  app.use(function(req, res, next) {
    if (req.body) delete req.body._csrf;
    next();
  });

  // helpers
  // auth.helpExpress(app);
  require('../helpers')(app);

  app.use(express.logger());
  app.use(auth.middleware());
  app.use(app.router);

  // request error handling
  var ratchetErroHandler = ratchetio.errorHandler();
  app.use(function(err, req, res, next) {
    if (typeof(err) !== 'number') {
      ratchetErroHandler(err, req, res, next);
    } else {
      next(err, req, res);
    }
  });

  app.use(function(e, req, res, next) {
    if (typeof(e) === 'number')
      return res.render2('errors/' + e, { status: e });

    if (typeof(e) === 'string')
      e = Error(e);

    console.error(e.stack);
    res.render2('errors/500', { error: e });
  });

  app.set('views', app.paths.views);
  app.set('view engine', 'jade');
});

app.listen(port);
app.ws = require('socket.io').listen(app);
app.ws.set('log level', 1);
app.ws.set('browser client minification', true);

app.on('listening', function() {
  require('util').log('listening on ' + ('0.0.0.0:' + port).cyan);

  // if run as root, downgrade to the owner of this file
  if (env.production && process.getuid() === 0)
    require('fs').stat(__filename, function(err, stats) {
      if (err) return util.log(err)
      process.setuid(stats.uid);
    });
});
<|endoftext|>


<commit_before>import { getNode, getNodes, logger } from '../../utils/core'
import { deepAssign, each, nextUniqueId } from '../../utils/generic'
import style from '../functions/style'
import initialize from '../functions/initialize'

export default function reveal (target, options, interval, sync) {

	/**
	 * The reveal method has an optional 2nd parameter,
	 * so here we just shuffle things around to accept
	 * the interval being passed as the 2nd argument.
	 */
	if (typeof options === 'number') {
		interval = parseInt(options)
		options = {}
	} else {
		options = options || {}
	}

	const containers = this.store.containers
	const container = getNode(options.container || this.defaults.container)
	const targets = getNodes(target, container)

	if (!targets.length) {
		logger('Reveal cannot be performed on 0 elements.')
		return this
	}

	/**
	 * Sequence intervals must be at least 16ms (60fps)
	 * but can be negative for sequencing in reverse.
	 */
	let sequence
	if (typeof interval === 'number' && Math.abs(interval) > 15) {
		const sequenceId = nextUniqueId()
		sequence = this.store.sequences[sequenceId] = {
			elementIds: [],
			firstActiveIndex: 0,
			id: sequenceId,
			interval,
			lastActiveIndex: 0,
		}
	}

	let containerId
	each(containers, (storedContainer, id) => {
		if (storedContainer.node === container) {
			containerId = parseInt(id)
		}
	})

	if (containerId === undefined) {
		containerId = nextUniqueId()
	}

	try {
		const elements = targets.map(node => {
			const element = {}
			const existingId = node.getAttribute('data-sr-id')

			if (existingId) {
				deepAssign(element, this.store.elements[existingId])
			} else {
				deepAssign(element, {
					id: nextUniqueId(),
					config: {},
					containerId,
					node,
				})
			}

			if (sequence) {
				element.sequence = {
					id: sequence.id,
					index: sequence.elementIds.length,
				}
				sequence.elementIds.push(element.id)
			}

			element.config = deepAssign({}, this.defaults, element.config, options)
			element.styles = style(element)

			return element
		})

		/**
		* Modifying the DOM via setAttribute needs to be handled
		* separately from reading computed styles in the map above
		* for the browser to batch DOM changes (limiting reflows)
		*/
		each(elements, element => {
			this.store.elements[element.id] = element
			element.node.setAttribute('data-sr-id', element.id)
		})

	} catch (error) {
		logger(error.message)
		return this
	}

	if (!containers[containerId]) {
		containers[containerId] = { node: container }
	}

	/**
	* If reveal wasn't invoked by sync, we want to make
	* sure to add this call to the history.
	*/
	if (!sync) {
		this.store.history.push({ target, options, interval })

		/**
		* Push initialization to the event queue, giving chained
		* reveal calls time to be interpretted.
		*/
		if (this.initTimeout) {
			window.clearTimeout(this.initTimeout)
		}
		this.initTimeout = window.setTimeout(initialize.bind(this), 0)
	}

	return this
}
<commit_msg>add container id to both new and existing elements<commit_after>import { getNode, getNodes, logger } from '../../utils/core'
import { deepAssign, each, nextUniqueId } from '../../utils/generic'
import style from '../functions/style'
import initialize from '../functions/initialize'

export default function reveal (target, options, interval, sync) {

	/**
	 * The reveal method has an optional 2nd parameter,
	 * so here we just shuffle things around to accept
	 * the interval being passed as the 2nd argument.
	 */
	if (typeof options === 'number') {
		interval = parseInt(options)
		options = {}
	} else {
		options = options || {}
	}

	const containers = this.store.containers
	const container = getNode(options.container || this.defaults.container)
	const targets = getNodes(target, container)

	if (!targets.length) {
		logger('Reveal cannot be performed on 0 elements.')
		return this
	}

	/**
	 * Sequence intervals must be at least 16ms (60fps)
	 * but can be negative for sequencing in reverse.
	 */
	let sequence
	if (typeof interval === 'number' && Math.abs(interval) > 15) {
		const sequenceId = nextUniqueId()
		sequence = this.store.sequences[sequenceId] = {
			elementIds: [],
			firstActiveIndex: 0,
			id: sequenceId,
			interval,
			lastActiveIndex: 0,
		}
	}

	let containerId
	each(containers, (storedContainer, id) => {
		if (storedContainer.node === container) {
			containerId = parseInt(id)
		}
	})

	if (containerId === undefined) {
		containerId = nextUniqueId()
	}

	try {
		const elements = targets.map(node => {
			const element = {}
			const existingId = node.getAttribute('data-sr-id')

			if (existingId) {
				deepAssign(element, this.store.elements[existingId])
			} else {
				deepAssign(element, {
					id: nextUniqueId(),
					config: {},
					node,
				})
			}

			/**
			 * Both existing elements and new elements
			 * need a reference to the latest container.
			 */
			element.containerId = containerId

			if (sequence) {
				element.sequence = {
					id: sequence.id,
					index: sequence.elementIds.length,
				}
				sequence.elementIds.push(element.id)
			}

			element.config = deepAssign({}, this.defaults, element.config, options)
			element.styles = style(element)

			return element
		})

		/**
		* Modifying the DOM via setAttribute needs to be handled
		* separately from reading computed styles in the map above
		* for the browser to batch DOM changes (limiting reflows)
		*/
		each(elements, element => {
			this.store.elements[element.id] = element
			element.node.setAttribute('data-sr-id', element.id)
		})

	} catch (error) {
		logger(error.message)
		return this
	}

	if (!containers[containerId]) {
		containers[containerId] = { node: container }
	}

	/**
	* If reveal wasn't invoked by sync, we want to make
	* sure to add this call to the history.
	*/
	if (!sync) {
		this.store.history.push({ target, options, interval })

		/**
		* Push initialization to the event queue, giving chained
		* reveal calls time to be interpretted.
		*/
		if (this.initTimeout) {
			window.clearTimeout(this.initTimeout)
		}
		this.initTimeout = window.setTimeout(initialize.bind(this), 0)
	}

	return this
}
<|endoftext|>


<commit_before>var asNEAT = require('asNEAT/asNEAT')['default'],
    ForceVisualization = require('asNEAT/forceVisualization')['default'],
    context = asNEAT.context;

var scriptNodes = {};
var keep = (function() {
  var nextNodeID = 1;
  return function(node) {
    node.id = node.id || (nextNodeID++);
    scriptNodes[node.id] = node;
    return node;
  };
}());
var drop = function(node) {
  delete scriptNodes[node.id];
  return node;
};

var InstrumentVisualization = function(parameters) {
  _.defaults(this, parameters, this.defaultParameters);
};
InstrumentVisualization.prototype.defaultParameters = {
  network: null,
  // (num) for px, or (string) for %
  width: "100%",
  height: 512,
  selector: '.instrumentVisualization',

  // the colors used in the vis
  colorScaleColors: ['#000000', '#ff0000', '#ffff00', '#ffffff'],
  colorScalePositions: [0, 0.25, 0.75, 1],

  blankStepsUntilPause: 50
};

var id = 0;
InstrumentVisualization.prototype.init = function() {
  var canvas = document.createElement('canvas'),
      ctx = canvas.getContext('2d'),
      tempCanvas = document.createElement('canvas'),
      tempCtx = tempCanvas.getContext('2d'),
      networkDiv = document.createElement('div');
  this.canvas = canvas;
  this.ctx = ctx;
  this.tempCanvas = tempCanvas;
  this.tempCtx = tempCtx;
  this.networkDiv = networkDiv;

  this.$canvas = $(canvas);
  this.$tempCanvas = $(tempCanvas);
  this.networkDivClass = 'network'+(++id);
  $(this.selector)
    .addClass('asNEATInstrumentVis');
  this.$networkDiv = $(networkDiv)
    .addClass(this.networkDivClass)
    .addClass('asNEATInstrumentVisNetwork')
    .hide();

  this.colorScale = new chroma.scale(
    this.colorScaleColors,
    this.colorScalePositions);
  this.colorScale.domain([0, 300]);

  this.outNode = this.network.nodes[0];
};

InstrumentVisualization.prototype.start = function() {
  var self = this,
      canvas = this.canvas,
      ctx = this.ctx,
      tempCanvas = this.tempCanvas,
      tempCtx = this.tempCtx,
      outNode = this.outNode,
      jsNode, analyserNode;

  $(this.selector).append(this.$canvas);
  $(this.selector).append(this.$networkDiv);

  this.forceVis = new ForceVisualization({
    network: this.network,
    selector: "."+this.networkDivClass,
    width:'100%',
    height:'100%'
  });
  this.forceVis.init();

  this.$canvas.css({
    width: this.width,
    height: this.height
  });
  this.$tempCanvas.css({
    width: this.width,
    height: this.fftSize
  });

  var oldBounds = self.getBounds();
  this.fftSize = roundToPowerOf2(oldBounds.height);
  canvas.width = oldBounds.width;
  canvas.height = oldBounds.height;
  tempCanvas.width =  oldBounds.width;
  tempCanvas.height = this.fftSize/2;
  this.onResize = function() {
    var bounds = self.getBounds();
    tempCtx.drawImage(canvas,
      0, 0, canvas.width, canvas.height,
      0, 0, tempCanvas.width, tempCanvas.height);
    canvas.width = bounds.width;
    canvas.height = bounds.height;
    oldBounds = bounds;
    clear();
    ctx.drawImage(tempCanvas,
      0, 0, tempCanvas.width, tempCanvas.height,
      0, 0, canvas.width, canvas.height);
    tempCanvas.width = bounds.width;
    tempCanvas.height = self.fftSize/2;
  };
  $(window).on('resize', this.onResize);

  function clear() {
    ctx.fillStyle=self.colorScale(0).hex();
    ctx.fillRect(0,0,oldBounds.width,oldBounds.height);
  }
  clear();

  jsNode = keep(context.createScriptProcessor(2048, 1, 1));
  jsNode.connect(context.destination);
  this.jsNode = jsNode;

  analyserNode = context.createAnalyser();
  analyserNode.smoothingTimeConstant = 0;
  analyserNode.fftSize = this.fftSize;
  this.analyserNode = analyserNode;

  // swap out outnode with custom one with
  var oldNode = outNode.node;
  var tempFrontGain = context.createGain();
  tempFrontGain.gain.value = 1.0;

  outNode.node = tempFrontGain;
  outNode.node.connect(analyserNode);
  analyserNode.connect(jsNode);

  var blankArray = new Uint8Array(analyserNode.frequencyBinCount),
      lastSum = 0,
      numRepeats = 0,
      numBlank = 0,
      blankStepsUntilPause = this.blankStepsUntilPause;

  jsNode.onaudioprocess = function() {
    var freqData = new Uint8Array(analyserNode.frequencyBinCount);
    analyserNode.getByteFrequencyData(freqData);

    var sum = _.reduce(freqData, function(sum, val) {
      return sum + val;
    }, 0);

    // Send blank data if the same sum has been used more than twice
    // And don't even send anything after a set number of blanks
    if (sum===lastSum) {
      ++numRepeats;
      if (numRepeats >= 2) {
        ++numBlank;
        if (numBlank < blankStepsUntilPause)
          self.initUpdateCanvas(blankArray);
        else {
          jsNode.onaudioprocess = null;
          drop(jsNode);
        }
      }
      else {
        self.initUpdateCanvas(freqData);
        numBlank = 0;
      }
    }
    else {
      numRepeats = 0;
      numBlank = 0;
      self.initUpdateCanvas(freqData);
    }

    lastSum = sum;
  };

  this.network.play();
  outNode.node = oldNode;
};

/**
  @param freqData {Uint8Array}
*/
var x=0;
InstrumentVisualization.prototype.initUpdateCanvas = function(freqData) {
  var canvas = this.canvas,
      tempCanvas = this.tempCanvas,
      tempCtx = this.tempCtx,
      ctx = this.ctx,
      colorScale = this.colorScale,
      bounds = this.getBounds(),
      i, len, val;
  // See if the canvas even exists
  if (typeof bounds === "undefined")
    return;

  //ctx.translate(-1, 0);
  for (i=0,len = freqData.length; i<len; ++i) {
    val = freqData[i];
    ctx.fillStyle = colorScale(val).hex();
    ctx.fillRect(x, bounds.height-i, 1, 1);
  }
  ++x;
};

InstrumentVisualization.prototype.hasPlayStarted = false;
InstrumentVisualization.prototype.playStart = function() {
  if (this.hasPlayStarted)
    return;
  this.hasPlayStarted = true;

  var self = this,
      canvas = this.canvas,
      ctx = this.ctx,
      tempCanvas = this.tempCanvas,
      tempCtx = this.tempCtx,
      outNode = this.outNode,
      jsNode, analyserNode;

  jsNode = keep(context.createScriptProcessor(2048, 1, 1));
  jsNode.connect(context.destination);
  this.jsNode = jsNode;

  analyserNode = context.createAnalyser();
  analyserNode.smoothingTimeConstant = 0;
  analyserNode.fftSize = this.fftSize;
  this.analyserNode = analyserNode;

  outNode.node.connect(analyserNode);
  analyserNode.connect(jsNode);

  var blankArray = new Uint8Array(analyserNode.frequencyBinCount),
      lastSum = 0,
      numRepeats = 0,
      numBlank = 0,
      blankStepsUntilPause = this.blankStepsUntilPause;

  jsNode.onaudioprocess = function() {

    var freqData = new Uint8Array(analyserNode.frequencyBinCount);
    analyserNode.getByteFrequencyData(freqData);

    var sum = _.reduce(freqData, function(sum, val) {
      return sum + val;
    }, 0);

    // go untill a set number of blank iterations then kill the jsNode
    if (sum===lastSum) {
      ++numRepeats;
      if (numRepeats >= 2) {
        ++numBlank;
        if (numBlank < blankStepsUntilPause)
          self.updateCanvas(blankArray);
      }
      else {
        self.updateCanvas(freqData);
        numBlank = 0;
      }
    }
    else {
      numRepeats = 0;
      numBlank = 0;
      self.updateCanvas(freqData);
    }

    lastSum = sum;
  };
};
InstrumentVisualization.prototype.playStop = function() {
  // TODO: Return back to orig offline display?
  this.hasPlayStarted = false;
};
InstrumentVisualization.prototype.showNetwork = function() {
  if(this.$networkDiv.is(':visible'))
    return;
  this.$networkDiv.show();
  this.forceVis.start();
};
InstrumentVisualization.prototype.hideNetwork = function() {
  if(!this.$networkDiv.is(':visible'))
    return;
  this.forceVis.stop();
  this.$networkDiv.hide();
};

InstrumentVisualization.prototype.stop = function() {
  this.$canvas.remove();
  $(window).off('resize', this.onResize);
  this.jsNode.disconnect(this.context.destination);
  this.analyserNode.disconnect(this.jsNode);
  drop(this.jsNode);
};

InstrumentVisualization.prototype.refresh = function() {

};

/**
  @param freqData {Uint8Array}
*/
InstrumentVisualization.prototype.updateCanvas = function(freqData) {
  var canvas = this.canvas,
      tempCanvas = this.tempCanvas,
      tempCtx = this.tempCtx,
      ctx = this.ctx,
      colorScale = this.colorScale,
      bounds = this.getBounds(),
      i, len, val;

  // See if the canvas even exists
  if (typeof bounds === "undefined")
    return;

  // shift the temp canvas left and draw in next section
  var imageData = tempCtx.getImageData(1, 0, tempCtx.canvas.width-1, tempCtx.canvas.height);
  tempCtx.putImageData(imageData, 0, 0);
  for (i=0,len = freqData.length; i<len; ++i) {
    val = freqData[i];
    tempCtx.fillStyle = colorScale(val).hex();
    tempCtx.fillRect(bounds.width-1, bounds.height-i, 1, 1);
  }

  // map temp canvas that with height=fftSize
  ctx.drawImage(tempCanvas, 0, 0, tempCanvas.width, tempCanvas.height,
                            0, 0, canvas.width, canvas.height);
};

InstrumentVisualization.prototype.getBounds = function() {
  return this.canvas.getClientRects()[0];
};

function roundToPowerOf2(v) {
  v--;
  v|=v>>1;
  v|=v>>2;
  v|=v>>4;
  v|=v>>8;
  v|=v>>16;
  return ++v;
}

export default InstrumentVisualization;
<commit_msg>fix not scaling initial spectrogram correctly<commit_after>var asNEAT = require('asNEAT/asNEAT')['default'],
    ForceVisualization = require('asNEAT/forceVisualization')['default'],
    context = asNEAT.context;

// TODO: Clean this up... it's so bad :'(

var scriptNodes = {};
var keep = (function() {
  var nextNodeID = 1;
  return function(node) {
    node.id = node.id || (nextNodeID++);
    scriptNodes[node.id] = node;
    return node;
  };
}());
var drop = function(node) {
  delete scriptNodes[node.id];
  return node;
};

var InstrumentVisualization = function(parameters) {
  _.defaults(this, parameters, this.defaultParameters);
};
InstrumentVisualization.prototype.defaultParameters = {
  network: null,
  // (num) for px, or (string) for %
  width: "100%",
  height: 512,
  selector: '.instrumentVisualization',

  // the colors used in the vis
  colorScaleColors: ['#000000', '#ff0000', '#ffff00', '#ffffff'],
  colorScalePositions: [0, 0.25, 0.75, 1],

  blankStepsUntilPause: 50
};

var id = 0;
InstrumentVisualization.prototype.init = function() {
  var canvas = document.createElement('canvas'),
      ctx = canvas.getContext('2d'),
      tempCanvas = document.createElement('canvas'),
      tempCtx = tempCanvas.getContext('2d'),
      networkDiv = document.createElement('div');
  this.canvas = canvas;
  this.ctx = ctx;
  this.tempCanvas = tempCanvas;
  this.tempCtx = tempCtx;
  this.networkDiv = networkDiv;

  this.$canvas = $(canvas);
  this.$tempCanvas = $(tempCanvas);
  this.networkDivClass = 'network'+(++id);
  $(this.selector)
    .addClass('asNEATInstrumentVis');
  this.$networkDiv = $(networkDiv)
    .addClass(this.networkDivClass)
    .addClass('asNEATInstrumentVisNetwork')
    .hide();

  this.colorScale = new chroma.scale(
    this.colorScaleColors,
    this.colorScalePositions);
  this.colorScale.domain([0, 300]);

  this.outNode = this.network.nodes[0];
};

InstrumentVisualization.prototype.start = function() {
  var self = this,
      canvas = this.canvas,
      ctx = this.ctx,
      tempCanvas = this.tempCanvas,
      tempCtx = this.tempCtx,
      outNode = this.outNode,
      jsNode, analyserNode;

  $(this.selector).append(this.$canvas);
  $(this.selector).append(this.$networkDiv);

  this.forceVis = new ForceVisualization({
    network: this.network,
    selector: "."+this.networkDivClass,
    width:'100%',
    height:'100%'
  });
  this.forceVis.init();

  this.$canvas.css({
    width: this.width,
    height: this.height
  });
  this.$tempCanvas.css({
    width: this.width,
    height: this.fftSize
  });

  var oldBounds = self.getBounds();
  this.fftSize = roundToPowerOf2(oldBounds.height);
  canvas.width = oldBounds.width;
  canvas.height = oldBounds.height;
  tempCanvas.width =  oldBounds.width;
  tempCanvas.height = this.fftSize/2;
  this.onResize = function() {
    var bounds = self.getBounds();
    tempCtx.drawImage(canvas,
      0, 0, canvas.width, canvas.height,
      0, 0, tempCanvas.width, tempCanvas.height);
    canvas.width = bounds.width;
    canvas.height = bounds.height;
    oldBounds = bounds;
    clear();
    ctx.drawImage(tempCanvas,
      0, 0, tempCanvas.width, tempCanvas.height,
      0, 0, canvas.width, canvas.height);
    tempCanvas.width = bounds.width;
    tempCanvas.height = self.fftSize/2;
  };
  $(window).on('resize', this.onResize);

  function clear() {
    ctx.fillStyle=self.colorScale(0).hex();
    ctx.fillRect(0,0,oldBounds.width,oldBounds.height);
  }
  clear();

  jsNode = keep(context.createScriptProcessor(2048, 1, 1));
  jsNode.connect(context.destination);
  this.jsNode = jsNode;

  analyserNode = context.createAnalyser();
  analyserNode.smoothingTimeConstant = 0;
  analyserNode.fftSize = this.fftSize;
  this.analyserNode = analyserNode;

  // swap out outnode with custom one with
  var oldNode = outNode.node;
  var tempFrontGain = context.createGain();
  tempFrontGain.gain.value = 1.0;

  outNode.node = tempFrontGain;
  outNode.node.connect(analyserNode);
  analyserNode.connect(jsNode);

  var blankArray = new Uint8Array(analyserNode.frequencyBinCount),
      lastSum = 0,
      numRepeats = 0,
      numBlank = 0,
      blankStepsUntilPause = this.blankStepsUntilPause;

  jsNode.onaudioprocess = function() {
    var freqData = new Uint8Array(analyserNode.frequencyBinCount);
    analyserNode.getByteFrequencyData(freqData);

    var sum = _.reduce(freqData, function(sum, val) {
      return sum + val;
    }, 0);

    // Send blank data if the same sum has been used more than twice
    // And don't even send anything after a set number of blanks
    if (sum===lastSum) {
      ++numRepeats;
      if (numRepeats >= 2) {
        ++numBlank;
        if (numBlank < blankStepsUntilPause)
          self.initUpdateCanvas(blankArray);
        else {
          jsNode.onaudioprocess = null;
          drop(jsNode);
        }
      }
      else {
        self.initUpdateCanvas(freqData);
        numBlank = 0;
      }
    }
    else {
      numRepeats = 0;
      numBlank = 0;
      self.initUpdateCanvas(freqData);
    }

    lastSum = sum;
  };

  this.network.play();
  outNode.node = oldNode;
};

/**
  @param freqData {Uint8Array}
*/
var x=0;
InstrumentVisualization.prototype.initUpdateCanvas = function(freqData) {
  var tempCtx = this.tempCtx,
      colorScale = this.colorScale,
      bounds = this.getBounds(),
      i, len, val;
  // See if the canvas even exists
  if (typeof bounds === "undefined")
    return;

  for (i=0,len = freqData.length; i<len; ++i) {
    val = freqData[i];
    tempCtx.fillStyle = colorScale(val).hex();
    tempCtx.fillRect(x, bounds.height-i, 1, 1);
  }
  ++x;
  copyFromTempCanvas.call(this);
};

InstrumentVisualization.prototype.hasPlayStarted = false;
InstrumentVisualization.prototype.playStart = function() {
  if (this.hasPlayStarted)
    return;
  this.hasPlayStarted = true;

  var self = this,
      canvas = this.canvas,
      ctx = this.ctx,
      tempCanvas = this.tempCanvas,
      tempCtx = this.tempCtx,
      outNode = this.outNode,
      jsNode, analyserNode;

  jsNode = keep(context.createScriptProcessor(2048, 1, 1));
  jsNode.connect(context.destination);
  this.jsNode = jsNode;

  analyserNode = context.createAnalyser();
  analyserNode.smoothingTimeConstant = 0;
  analyserNode.fftSize = this.fftSize;
  this.analyserNode = analyserNode;

  outNode.node.connect(analyserNode);
  analyserNode.connect(jsNode);

  var blankArray = new Uint8Array(analyserNode.frequencyBinCount),
      lastSum = 0,
      numRepeats = 0,
      numBlank = 0,
      blankStepsUntilPause = this.blankStepsUntilPause;

  jsNode.onaudioprocess = function() {

    var freqData = new Uint8Array(analyserNode.frequencyBinCount);
    analyserNode.getByteFrequencyData(freqData);

    var sum = _.reduce(freqData, function(sum, val) {
      return sum + val;
    }, 0);

    // go untill a set number of blank iterations then kill the jsNode
    if (sum===lastSum) {
      ++numRepeats;
      if (numRepeats >= 2) {
        ++numBlank;
        if (numBlank < blankStepsUntilPause)
          self.updateCanvas(blankArray);
      }
      else {
        self.updateCanvas(freqData);
        numBlank = 0;
      }
    }
    else {
      numRepeats = 0;
      numBlank = 0;
      self.updateCanvas(freqData);
    }

    lastSum = sum;
  };
};
InstrumentVisualization.prototype.playStop = function() {
  // TODO: Return back to orig offline display?
  this.hasPlayStarted = false;
};
InstrumentVisualization.prototype.showNetwork = function() {
  if(this.$networkDiv.is(':visible'))
    return;
  this.$networkDiv.show();
  this.forceVis.start();
};
InstrumentVisualization.prototype.hideNetwork = function() {
  if(!this.$networkDiv.is(':visible'))
    return;
  this.forceVis.stop();
  this.$networkDiv.hide();
};

InstrumentVisualization.prototype.stop = function() {
  this.$canvas.remove();
  $(window).off('resize', this.onResize);
  this.jsNode.disconnect(this.context.destination);
  this.analyserNode.disconnect(this.jsNode);
  drop(this.jsNode);
};

InstrumentVisualization.prototype.refresh = function() {

};

/**
  @param freqData {Uint8Array}
*/
InstrumentVisualization.prototype.updateCanvas = function(freqData) {
  var tempCtx = this.tempCtx,
      colorScale = this.colorScale,
      bounds = this.getBounds(),
      i, len, val;

  // See if the canvas even exists
  if (typeof bounds === "undefined")
    return;

  // shift the temp canvas left and draw in next section
  shiftTempCanvasLeft.call(this);
  for (i=0,len = freqData.length; i<len; ++i) {
    val = freqData[i];
    tempCtx.fillStyle = colorScale(val).hex();
    tempCtx.fillRect(bounds.width-1, bounds.height-i, 1, 1);
  }

  copyFromTempCanvas.call(this);
};

InstrumentVisualization.prototype.getBounds = function() {
  return this.canvas.getClientRects()[0];
};

function shiftTempCanvasLeft() {
  var tempCtx = this.tempCtx,
      imageData = tempCtx.getImageData(1, 0, tempCtx.canvas.width-1, tempCtx.canvas.height);
  tempCtx.putImageData(imageData, 0, 0);
}

function copyFromTempCanvas() {
  var canvas = this.canvas,
      tempCanvas = this.tempCanvas;
  // map temp canvas that with height=fftSize
  this.ctx.drawImage(tempCanvas,
    0, 0, tempCanvas.width, tempCanvas.height,
    0, 0, canvas.width, canvas.height);
}

function roundToPowerOf2(v) {
  v--;
  v|=v>>1;
  v|=v>>2;
  v|=v>>4;
  v|=v>>8;
  v|=v>>16;
  return ++v;
}

export default InstrumentVisualization;
<|endoftext|>


<commit_before>module.exports = {

    public_host_name: process.env.WATCHMEN_BASE_URL, // required for OAuth dance

    auth: {
        GOOGLE_CLIENT_ID: process.env.WATCHMEN_GOOGLE_CLIENT_ID || '<Create credentials in Google Dev Console>',
        GOOGLE_CLIENT_SECRET: process.env.WATCHMEN_GOOGLE_CLIENT_SECRET || '<Create credentials in Google Dev Console>'
    },

    port: process.env.WATCHMEN_WEB_PORT, // default port

    admins: process.env.WATCHMEN_ADMINS,

    ga_analytics_ID: process.env.WATCHMEN_GOOGLE_ANALYTICS_ID,

    baseUrl: '/'
};
<commit_msg>feat: add no_auth setting to config<commit_after>module.exports = {

    no_auth: false,

    public_host_name: process.env.WATCHMEN_BASE_URL, // required for OAuth dance

    auth: {
        GOOGLE_CLIENT_ID: process.env.WATCHMEN_GOOGLE_CLIENT_ID || '<Create credentials in Google Dev Console>',
        GOOGLE_CLIENT_SECRET: process.env.WATCHMEN_GOOGLE_CLIENT_SECRET || '<Create credentials in Google Dev Console>'
    },

    port: process.env.WATCHMEN_WEB_PORT, // default port

    admins: process.env.WATCHMEN_ADMINS,

    ga_analytics_ID: process.env.WATCHMEN_GOOGLE_ANALYTICS_ID,

    baseUrl: '/'
};
<|endoftext|>


<commit_before>'use strict';

var React = require('react/addons'),
    PubSub = require('../mixins/PubSub'),
    Utils = require('../utils'),
    classSet = React.addons.classSet;

module.exports = React.createClass({
    displayName: 'InputItem',

    mixins: [PubSub],

    getInitialState: function() {
      return {
        style: {},
        classes: [],
        counter: {
          current: 0,
          maximum: 50
        },
        inputClasses: {
          'e-input': true,
          'empty': true
        },
        inputValue: ''
      };
    },

    componentDidMount: function () {
      var self = this,
          parentClass = self.props.classes || [],
          inputClasses = self.state.inputClasses,
          inputValue = self.props.inputValue || self.state.inputValue || '',
          counter = self.state.counter;

      if (self.props.counter && parseInt(self.props.counter) > 0 ) {
        counter.maximum = parseInt(self.props.counter);
      }

      self.subscribe('actions:input', function (data) {
        if (data.action === "setValue") {
          if (self.props.name === data.id) {
            inputValue = data.value;
            inputClasses['empty'] = false;
            self.setState({
              inputClasses: inputClasses,
              inputValue: inputValue
            });
          }
        }
      });

      self.setState({
        classes: parentClass,
        inputClasses: inputClasses,
        inputValue: inputValue,
        counter: counter
      });
    },

    handleClick: function () {
      var self = this,
          actionClick = self.props.actionClick || false,
          actionType = self.props.actionType || false;

      if (actionClick && actionType) {
        self.publish('actions:'+actionClick, actionType);
      }

      if (self.props.onClick) {
        return self.props.onClick;
      }
    },

    handleChange: function (eventChange) {
      var self = this,
          counter = self.state.counter,
          inputClasses = self.state.inputClasses || [],
          inputValue = eventChange.target.value;

      if (inputValue.length >= counter.maximum && self.props.counter) {
        inputValue = inputValue.substr(0, counter.maximum);
      }

      counter.current = inputValue.length;

      if (inputValue.length > 0) {
        inputClasses['empty'] = false;
      }

      self.setState({
        counter: counter,
        inputValue: inputValue,
        inputClasses: inputClasses
      });
    },

    renderLabel: function () {
      if (!this.props.label || this.props.placeholder) {
        return null;
      }

      return (

          {this.props.label}

      );
    },

    renderHint: function () {
      if (!this.props.hint) {
        return null;
      }

      return (

          {this.props.hint}

      );
    },

    renderCounter: function () {
      var self = this;
      if (!self.props.counter) {
        return null;
      }

      return (

          {self.state.counter.current}/{self.state.counter.maximum}

      );
    },

    renderEffect: function () {
      return (

      );
    },

    renderInput: function () {
      var self = this,
          placeholder = self.props.placeholder || '',
          isRequired = (self.props.required ? true : false),
          isDisabled = (self.props.disabled ? true : false),
          type = self.props.type || 'text',
          value = self.props.value || self.state.inputValue || '',
          name = self.props.name || '',
          inputClasses = classSet(Utils.classNames(self.state.inputClasses, self.props.inputClasses));

      if (type === 'textarea') {
        return (
          <textarea
            className={inputClasses}
            ref={this.props.ref}
            type={type}
            name={name}
            defaultValue={value}
            value={value}
            required={isRequired}
            disabled={isDisabled}
            placeholder={placeholder}
            onChange={self.handleChange}
            onClick={self.handleClick}
            onTouch={self.handleClick}/>
        );
      }

      return (
        <input
          className={inputClasses}
          ref={this.props.ref}
          type={type}
          name={name}
          defaultValue={value}
          value={value}
          required={isRequired}
          disabled={isDisabled}
          placeholder={placeholder}
          onChange={self.handleChange}
          onClick={self.handleClick}
          onTouch={self.handleClick}/>
      );
    },

    render: function () {
      var self = this,
          classes = classSet(self.state.classes);

      return (

          {self.renderInput()}
          {self.renderCounter()}
          {self.renderEffect()}
          {self.renderLabel()}
          {self.renderHint()}

      );
    }
});
<commit_msg>Essence - InputItem class empty=false when value is set<commit_after>'use strict';

var React = require('react/addons'),
    PubSub = require('../mixins/PubSub'),
    Utils = require('../utils'),
    classSet = React.addons.classSet;

module.exports = React.createClass({
    displayName: 'InputItem',

    mixins: [PubSub],

    getInitialState: function() {
      return {
        style: {},
        classes: [],
        counter: {
          current: 0,
          maximum: 50
        },
        inputClasses: {
          'e-input': true,
          'empty': true
        },
        inputValue: ''
      };
    },

    componentDidMount: function () {
      var self = this,
          parentClass = self.props.classes || [],
          inputClasses = self.state.inputClasses,
          inputValue = self.props.value || self.props.inputValue || self.state.inputValue || '',
          counter = self.state.counter;

      if (self.props.counter && parseInt(self.props.counter) > 0 ) {
        counter.maximum = parseInt(self.props.counter);
      }

      self.subscribe('actions:input', function (data) {
        if (data.action === "setValue") {
          if (self.props.name === data.id) {
            inputValue = data.value;
            inputClasses['empty'] = false;
            self.setState({
              inputClasses: inputClasses,
              inputValue: inputValue
            });
          }
        }
      });

      if (inputValue.length > 1) {
        inputClasses['empty'] = false;
      }

      self.setState({
        classes: parentClass,
        inputClasses: inputClasses,
        inputValue: inputValue,
        counter: counter
      });
    },

    handleClick: function () {
      var self = this,
          actionClick = self.props.actionClick || false,
          actionType = self.props.actionType || false;

      if (actionClick && actionType) {
        self.publish('actions:'+actionClick, actionType);
      }

      if (self.props.onClick) {
        return self.props.onClick;
      }
    },

    handleChange: function (eventChange) {
      var self = this,
          counter = self.state.counter,
          inputClasses = self.state.inputClasses || [],
          inputValue = eventChange.target.value;

      if (inputValue.length >= counter.maximum && self.props.counter) {
        inputValue = inputValue.substr(0, counter.maximum);
      }

      counter.current = inputValue.length;

      if (inputValue.length > 0) {
        inputClasses['empty'] = false;
      }

      self.setState({
        counter: counter,
        inputValue: inputValue,
        inputClasses: inputClasses
      });
    },

    renderLabel: function () {
      if (!this.props.label || this.props.placeholder) {
        return null;
      }

      return (

          {this.props.label}

      );
    },

    renderHint: function () {
      if (!this.props.hint) {
        return null;
      }

      return (

          {this.props.hint}

      );
    },

    renderCounter: function () {
      var self = this;
      if (!self.props.counter) {
        return null;
      }

      return (

          {self.state.counter.current}/{self.state.counter.maximum}

      );
    },

    renderEffect: function () {
      return (

      );
    },

    renderInput: function () {
      var self = this,
          placeholder = self.props.placeholder || '',
          isRequired = (self.props.required ? true : false),
          isDisabled = (self.props.disabled ? true : false),
          type = self.props.type || 'text',
          value = self.props.value || self.state.inputValue || '',
          name = self.props.name || '',
          inputClasses = classSet(Utils.classNames(self.state.inputClasses, self.props.inputClasses));

      if (type === 'textarea') {
        return (
          <textarea
            className={inputClasses}
            ref={this.props.ref}
            type={type}
            name={name}
            defaultValue={value}
            value={value}
            required={isRequired}
            disabled={isDisabled}
            placeholder={placeholder}
            onChange={self.handleChange}
            onClick={self.handleClick}
            onTouch={self.handleClick}/>
        );
      }

      return (
        <input
          className={inputClasses}
          ref={this.props.ref}
          type={type}
          name={name}
          defaultValue={value}
          value={value}
          required={isRequired}
          disabled={isDisabled}
          placeholder={placeholder}
          onChange={self.handleChange}
          onClick={self.handleClick}
          onTouch={self.handleClick}/>
      );
    },

    render: function () {
      var self = this,
          classes = classSet(self.state.classes);

      return (

          {self.renderInput()}
          {self.renderCounter()}
          {self.renderEffect()}
          {self.renderLabel()}
          {self.renderHint()}

      );
    }
});
<|endoftext|>


<commit_before>'use strict';

angular.module('copayApp.controllers').controller('tabSendController', function($scope, $rootScope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, bwcError, gettextCatalog, scannerService, configService, bitcoinCashJsService, $ionicNavBarDelegate) {

  var originalList;
  var CONTACTS_SHOW_LIMIT;
  var currentContactsPage;
  $scope.isChromeApp = platformInfo.isChromeApp;
  $scope.sectionDisplay = {
    transferToWallet: false
  };

  var hasWallets = function() {
    $scope.wallets = profileService.getWallets({
      onlyComplete: true
    });
    $scope.hasWallets = lodash.isEmpty($scope.wallets) ? false : true;
  };

  // THIS is ONLY to show the 'buy bitcoins' message
  // does not has any other function.

  var updateHasFunds = function() {

    if ($rootScope.everHasFunds) {
      $scope.hasFunds = true;
      return;
    }

    $scope.hasFunds = false;
    var index = 0;
    lodash.each($scope.wallets, function(w) {
      walletService.getStatus(w, {}, function(err, status) {

        ++index;
        if (err && !status) {
          $log.error(err);
          // error updating the wallet. Probably a network error, do not show
          // the 'buy bitcoins' message.

          $scope.hasFunds = true;
        } else if (status.availableBalanceSat > 0) {
          $scope.hasFunds = true;
          $rootScope.everHasFunds = true;
        }

        if (index == $scope.wallets.length) {
          $scope.checkingBalance = false;
          $timeout(function() {
            $scope.$apply();
          });
        }
      });
    });
  };

  var updateWalletsList = function() {
    var config = configService.getSync();
    var networkResult = lodash.countBy($scope.wallets, 'network');

    $scope.showTransferCard = $scope.hasWallets && (networkResult.livenet > 1 || networkResult.testnet > 1);

    if ($scope.showTransferCard) {
      var walletsToTransfer = $scope.wallets;
      if (!(networkResult.livenet > 1)) {
        walletsToTransfer = lodash.filter(walletsToTransfer, function(item) {
          return item.network == 'testnet';
        });
      }
      if (!(networkResult.testnet > 1)) {
        walletsToTransfer = lodash.filter(walletsToTransfer, function(item) {
          return item.network == 'livenet';
        });
      }

      var walletList = [];
      lodash.each(walletsToTransfer, function(v) {
        var displayBalanceAsFiat =
            v.status.alternativeBalanceAvailable &&
            config.wallet.settings.priceDisplay === 'fiat';

        walletList.push({
          color: v.color,
          name: v.name,
          recipientType: 'wallet',
          coin: v.coin,
          network: v.network,
          balanceString: displayBalanceAsFiat ?
              v.status.totalBalanceAlternative + ' ' + v.status.alternativeIsoCode :
              v.cachedBalance,
          getAddress: function(cb) {
            walletService.getAddress(v, false, cb);
          },
        });
      });
      originalList = originalList.concat(walletList);
    }
  }

  var updateContactsList = function(cb) {
    var config = configService.getSync();
    var defaults = configService.getDefaults();
    addressbookService.list(function(err, ab) {
      if (err) $log.error(err);

      $scope.hasContacts = lodash.isEmpty(ab) ? false : true;
      if (!$scope.hasContacts) return cb();

      var completeContacts = [];
      lodash.each(ab, function(v, k) {
        completeContacts.push({
          name: lodash.isObject(v) ? v.name : v,
          address: k,
          email: lodash.isObject(v) ? v.email : null,
          recipientType: 'contact',
          coin: v.coin,
          displayCoin:  (v.coin == 'bch'
                        ? (config.bitcoinCashAlias || defaults.bitcoinCashAlias)
                        : (config.bitcoinAlias || defaults.bitcoinAlias)).toUpperCase(),
          getAddress: function(cb) {
            return cb(null, k);
          },
        });
      });
      var contacts = completeContacts.slice(0, (currentContactsPage + 1) * CONTACTS_SHOW_LIMIT);
      $scope.contactsShowMore = completeContacts.length > contacts.length;
      originalList = originalList.concat(contacts);
      return cb();
    });
  };

  var updateList = function() {
    $scope.list = lodash.clone(originalList);
    $timeout(function() {
      $ionicScrollDelegate.resize();
      $scope.$apply();
    }, 10);
  };

  $scope.openScanner = function() {
    var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP;

    if (!isWindowsPhoneApp) {
      $state.go('tabs.scan');
      return;
    }

    scannerService.useOldScanner(function(err, contents) {
      if (err) {
        popupService.showAlert(gettextCatalog.getString('Error'), err);
        return;
      }
      incomingData.redir(contents);
    });
  };

  $scope.showMore = function() {
    currentContactsPage++;
    updateWalletsList();
  };

  $scope.searchInFocus = function() {
    $scope.searchFocus = true;
  };

  $scope.searchBlurred = function() {
    if ($scope.formData.search == null || $scope.formData.search.length == 0) {
      $scope.searchFocus = false;
    }
  };

  $scope.findContact = function(search) {

    if (incomingData.redir(search)) {
      return;
    }

    if (!search || search.length < 2) {
      $scope.list = originalList;
      $timeout(function() {
        $scope.$apply();
      });
      return;
    }

    var result = lodash.filter(originalList, function(item) {
      var val = item.name;
      return lodash.includes(val.toLowerCase(), search.toLowerCase());
    });

    $scope.list = result;
  };

  $scope.goToAmount = function(item) {
    $timeout(function() {
      item.getAddress(function(err, addr) {
        if (err || !addr) {
          //Error is already formated
          return popupService.showAlert(err);
        }

        if (item.recipientType && item.recipientType == 'contact') {
          if (addr.indexOf('bch') == 0 || addr.indexOf('btc') == 0) {
            addr = addr.substring(3);
          }
        }

        $log.debug('Got toAddress:' + addr + ' | ' + item.name);
        return $state.transitionTo('tabs.send.amount', {
          recipientType: item.recipientType,
          displayAddress: item.coin == 'bch' ? bitcoinCashJsService.translateAddresses(addr).cashaddr : addr,
          toAddress: addr,
          toName: item.name,
          toEmail: item.email,
          toColor: item.color,
          coin: item.coin
        });
      });
    });
  };

  // This could probably be enhanced refactoring the routes abstract states
  $scope.createWallet = function() {
    $state.go('tabs.home').then(function() {
      $state.go('tabs.add.create-personal');
    });
  };

  $scope.buyBitcoin = function() {
    $state.go('tabs.home').then(function() {
      $state.go('tabs.buyandsell');
    });
  };

  $scope.$on("$ionicView.beforeEnter", function(event, data) {
    $scope.checkingBalance = true;
    $scope.formData = {
      search: null
    };
    originalList = [];
    CONTACTS_SHOW_LIMIT = 10;
    currentContactsPage = 0;
    hasWallets();
  });

  $scope.$on("$ionicView.enter", function(event, data) {
    $ionicNavBarDelegate.showBar(true);
    if (!$scope.hasWallets) {
      $scope.checkingBalance = false;
      return;
    }
    updateHasFunds();
    updateWalletsList();
    updateContactsList(function() {
      updateList();
    });
  });

  $scope.toggle = function(section) {
    $scope.sectionDisplay[section] = !$scope.sectionDisplay[section];
    $timeout(function() {
      $ionicScrollDelegate.resize();
      $scope.$apply();
    }, 10);
  };
});
<commit_msg>Bugfix for undefined wallet status on send tab.<commit_after>'use strict';

angular.module('copayApp.controllers').controller('tabSendController', function($scope, $rootScope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, bwcError, gettextCatalog, scannerService, configService, bitcoinCashJsService, $ionicNavBarDelegate) {

  var originalList;
  var CONTACTS_SHOW_LIMIT;
  var currentContactsPage;
  $scope.isChromeApp = platformInfo.isChromeApp;
  $scope.sectionDisplay = {
    transferToWallet: false
  };

  var hasWallets = function() {
    $scope.wallets = profileService.getWallets({
      onlyComplete: true
    });
    $scope.hasWallets = lodash.isEmpty($scope.wallets) ? false : true;
  };

  // THIS is ONLY to show the 'buy bitcoins' message
  // does not has any other function.

  var updateHasFunds = function() {

    if ($rootScope.everHasFunds) {
      $scope.hasFunds = true;
      return;
    }

    $scope.hasFunds = false;
    var index = 0;
    lodash.each($scope.wallets, function(w) {
      walletService.getStatus(w, {}, function(err, status) {

        ++index;
        if (err && !status) {
          $log.error(err);
          // error updating the wallet. Probably a network error, do not show
          // the 'buy bitcoins' message.

          $scope.hasFunds = true;
        } else if (status.availableBalanceSat > 0) {
          $scope.hasFunds = true;
          $rootScope.everHasFunds = true;
        }

        if (index == $scope.wallets.length) {
          $scope.checkingBalance = false;
          $timeout(function() {
            $scope.$apply();
          });
        }
      });
    });
  };

  var updateWalletsList = function() {
    var config = configService.getSync();
    var networkResult = lodash.countBy($scope.wallets, 'network');

    $scope.showTransferCard = $scope.hasWallets && (networkResult.livenet > 1 || networkResult.testnet > 1);

    if ($scope.showTransferCard) {
      var walletsToTransfer = $scope.wallets;
      if (!(networkResult.livenet > 1)) {
        walletsToTransfer = lodash.filter(walletsToTransfer, function(item) {
          return item.network == 'testnet';
        });
      }
      if (!(networkResult.testnet > 1)) {
        walletsToTransfer = lodash.filter(walletsToTransfer, function(item) {
          return item.network == 'livenet';
        });
      }

      var walletList = [];
      lodash.each(walletsToTransfer, function(v) {
        var displayBalanceAsFiat =
          // BD got v.status as undefined here once during development, just
          // after creating a new wallet.
          v.status &&
          v.status.alternativeBalanceAvailable &&
          config.wallet.settings.priceDisplay === 'fiat';

        walletList.push({
          color: v.color,
          name: v.name,
          recipientType: 'wallet',
          coin: v.coin,
          network: v.network,
          balanceString: displayBalanceAsFiat ?
              v.status.totalBalanceAlternative + ' ' + v.status.alternativeIsoCode :
              v.cachedBalance,
          getAddress: function(cb) {
            walletService.getAddress(v, false, cb);
          },
        });
      });
      originalList = originalList.concat(walletList);
    }
  }

  var updateContactsList = function(cb) {
    var config = configService.getSync();
    var defaults = configService.getDefaults();
    addressbookService.list(function(err, ab) {
      if (err) $log.error(err);

      $scope.hasContacts = lodash.isEmpty(ab) ? false : true;
      if (!$scope.hasContacts) return cb();

      var completeContacts = [];
      lodash.each(ab, function(v, k) {
        completeContacts.push({
          name: lodash.isObject(v) ? v.name : v,
          address: k,
          email: lodash.isObject(v) ? v.email : null,
          recipientType: 'contact',
          coin: v.coin,
          displayCoin:  (v.coin == 'bch'
                        ? (config.bitcoinCashAlias || defaults.bitcoinCashAlias)
                        : (config.bitcoinAlias || defaults.bitcoinAlias)).toUpperCase(),
          getAddress: function(cb) {
            return cb(null, k);
          },
        });
      });
      var contacts = completeContacts.slice(0, (currentContactsPage + 1) * CONTACTS_SHOW_LIMIT);
      $scope.contactsShowMore = completeContacts.length > contacts.length;
      originalList = originalList.concat(contacts);
      return cb();
    });
  };

  var updateList = function() {
    $scope.list = lodash.clone(originalList);
    $timeout(function() {
      $ionicScrollDelegate.resize();
      $scope.$apply();
    }, 10);
  };

  $scope.openScanner = function() {
    var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP;

    if (!isWindowsPhoneApp) {
      $state.go('tabs.scan');
      return;
    }

    scannerService.useOldScanner(function(err, contents) {
      if (err) {
        popupService.showAlert(gettextCatalog.getString('Error'), err);
        return;
      }
      incomingData.redir(contents);
    });
  };

  $scope.showMore = function() {
    currentContactsPage++;
    updateWalletsList();
  };

  $scope.searchInFocus = function() {
    $scope.searchFocus = true;
  };

  $scope.searchBlurred = function() {
    if ($scope.formData.search == null || $scope.formData.search.length == 0) {
      $scope.searchFocus = false;
    }
  };

  $scope.findContact = function(search) {

    if (incomingData.redir(search)) {
      return;
    }

    if (!search || search.length < 2) {
      $scope.list = originalList;
      $timeout(function() {
        $scope.$apply();
      });
      return;
    }

    var result = lodash.filter(originalList, function(item) {
      var val = item.name;
      return lodash.includes(val.toLowerCase(), search.toLowerCase());
    });

    $scope.list = result;
  };

  $scope.goToAmount = function(item) {
    $timeout(function() {
      item.getAddress(function(err, addr) {
        if (err || !addr) {
          //Error is already formated
          return popupService.showAlert(err);
        }

        if (item.recipientType && item.recipientType == 'contact') {
          if (addr.indexOf('bch') == 0 || addr.indexOf('btc') == 0) {
            addr = addr.substring(3);
          }
        }

        $log.debug('Got toAddress:' + addr + ' | ' + item.name);
        return $state.transitionTo('tabs.send.amount', {
          recipientType: item.recipientType,
          displayAddress: item.coin == 'bch' ? bitcoinCashJsService.translateAddresses(addr).cashaddr : addr,
          toAddress: addr,
          toName: item.name,
          toEmail: item.email,
          toColor: item.color,
          coin: item.coin
        });
      });
    });
  };

  // This could probably be enhanced refactoring the routes abstract states
  $scope.createWallet = function() {
    $state.go('tabs.home').then(function() {
      $state.go('tabs.add.create-personal');
    });
  };

  $scope.buyBitcoin = function() {
    $state.go('tabs.home').then(function() {
      $state.go('tabs.buyandsell');
    });
  };

  $scope.$on("$ionicView.beforeEnter", function(event, data) {
    $scope.checkingBalance = true;
    $scope.formData = {
      search: null
    };
    originalList = [];
    CONTACTS_SHOW_LIMIT = 10;
    currentContactsPage = 0;
    hasWallets();
  });

  $scope.$on("$ionicView.enter", function(event, data) {
    $ionicNavBarDelegate.showBar(true);
    if (!$scope.hasWallets) {
      $scope.checkingBalance = false;
      return;
    }
    updateHasFunds();
    updateWalletsList();
    updateContactsList(function() {
      updateList();
    });
  });

  $scope.toggle = function(section) {
    $scope.sectionDisplay[section] = !$scope.sectionDisplay[section];
    $timeout(function() {
      $ionicScrollDelegate.resize();
      $scope.$apply();
    }, 10);
  };
});
<|endoftext|>