<commit_before>'use strict';

var crypto = require('crypto');
var uuid = require('uuid');
var step = require('step');
var fs = require('fs');
var PSQL = require('cartodb-psql');
var spawn = require('child_process').spawn;

function OgrFormat (id) {
    this.id = id;
}

OgrFormat.prototype = {

    id: 'ogr',

    is_file: true,

    getQuery: function (/* sql, options */) {
        return null; // dont execute the query
    },

    transform: function (/* result, options, callback */) {
        throw new Error('should not be called for file formats');
    },

    getContentType: function () { return this._contentType; },

    getFileExtension: function () { return this._fileExtension; },

    generateMD5: function (data) {
        var hash = crypto.createHash('md5');
        hash.update(data);
        return hash.digest('hex');
    },

    limitPathname: function (pathname) {
        if (pathname.length < 128) { return pathname; }
        return crypto.createHash('sha256').update(pathname).digest('hex');
    }

};

// Internal function usable by all OGR-driven outputs
OgrFormat.prototype.toOGR = function (options, outFormat, outFilename, callback) {
    // var gcol = options.gn;
    var sql = options.sql;
    var skipfields = options.skipfields;
    var outLayername = options.filename;

    var dbopts = options.dbopts;

    var ogr2ogr = global.settings.ogr2ogrCommand || 'ogr2ogr';
    var dbhost = dbopts.host;
    var dbport = dbopts.port;
    var dbuser = dbopts.user;
    var dbpass = dbopts.pass;
    var dbname = dbopts.dbname;

    var timeout = 5 * 60 * 1000 // 5 minutes in milliseconds

    if (Number.isFinite(global.settings.export_command_timeout)) {
        timeout = global.settings.export_command_timeout;
    }

    if (Number.isFinite(options.timeout) && options.timeout > 0) {
        timeout = options.timeout
    }

    var that = this;

    var columns = [];
    var geocol;
    var pg;
    // Drop ending semicolon (ogr doens't like it)
    sql = sql.replace(/;\s*$/, '');

    const theGeomFirst = (fieldA, fieldB) => {
        if (fieldA.name === 'the_geom') {
            return -1;
        }
        if (fieldB.name === 'the_geom') {
            return 1;
        }
        return 0;
    };

    step(

        function fetchColumns () {
            var colsql = 'SELECT * FROM (' + sql + ') as _cartodbsqlapi LIMIT 0';
            pg = new PSQL(dbopts);
            pg.query(colsql, this);
        },
        function findSRS (err, result) {
            if (err) {
                throw err;
            }

            var needSRS = that._needSRS;

            columns = result.fields
            // skip columns
                .filter(field => skipfields.indexOf(field.name) === -1)
            // put "the_geom" first (if exists)
                .sort(theGeomFirst)
            // get first geometry to calculate SRID ("the_geom" if exists)
                .map(field => {
                    if (needSRS && !geocol && pg.typeName(field.dataTypeID) === 'geometry') {
                        geocol = field.name;
                    }

                    return field;
                })
            // apply quotes to columns
                .map(field => outFormat === 'CSV' ? pg.quoteIdentifier(field.name) + '::text' : pg.quoteIdentifier(field.name));

            if (!needSRS || !geocol) {
                return null;
            }

            var next = this;

            var qgeocol = pg.quoteIdentifier(geocol);
            var sridsql = 'SELECT ST_Srid(' + qgeocol + ') as srid, GeometryType(' +
                   qgeocol + ') as type FROM (' + sql + ') as _cartodbsqlapi WHERE ' +
                   qgeocol + ' is not null limit 1';

            pg.query(sridsql, function (err, result) {
                if (err) { next(err); return; }
                if (result.rows.length) {
                    var srid = result.rows[0].srid;
                    var type = result.rows[0].type;
                    next(null, srid, type);
                } else {
                    // continue as srid and geom type are not critical when there are no results
                    next(null);
                }
            });
        },
        function spawnDumper (err, srid, type) {
            if (err) {
                throw err;
            }

            var next = this;

            var ogrsql = 'SELECT ' + columns.join(',') + ' FROM (' + sql + ') as _cartodbsqlapi';

            var ogrargs = [
                '-f', outFormat,
                '-lco', 'RESIZE=YES', /* shapefile */
                '-lco', 'ENCODING=UTF-8', /* shapefile */
                '-lco', 'STRING_QUOTING=IF_NEEDED', /* csv: Match gdal 2.2 behaviour */
                '-lco', 'LINEFORMAT=CRLF',
                outFilename,
                'PG:host=' + dbhost + ' port=' + dbport + ' user=' + dbuser + ' dbname=' + dbname + ' password=' + dbpass,
                '-sql', ogrsql
            ];

            if (srid) {
                ogrargs.push('-a_srs', 'EPSG:' + srid);
            }

            if (type) {
                ogrargs.push('-nlt', type);
            }

            if (options.cmd_params) {
                ogrargs = ogrargs.concat(options.cmd_params);
            }

            ogrargs.push('-nln', outLayername);

            // TODO: research if `exec` could fit better than `spawn`
            var child = spawn(ogr2ogr, ogrargs);

            var timedOut = false;
            var ogrTimeout;
            if (timeout > 0) {
                ogrTimeout = setTimeout(function () {
                    timedOut = true;
                    child.kill();
                }, timeout);
            }

            child.on('error', function (err) {
                clearTimeout(ogrTimeout);
                next(err);
            });

            var stderrData = [];
            child.stderr.setEncoding('utf8');
            child.stderr.on('data', function (data) {
                stderrData.push(data);
            });

            child.on('exit', function (code) {
                clearTimeout(ogrTimeout);

                if (timedOut) {
                    return next(new Error('statement timeout'));
                }

                if (code !== 0) {
                    var errMessage = 'ogr2ogr command return code ' + code;
                    if (stderrData.length > 0) {
                        errMessage += ', Error: ' + stderrData.join('\n');
                    }

                    return next(new Error(errMessage));
                }

                return next();
            });
        },
        function finish (err) {
            callback(err, outFilename);
        }
    );
};

OgrFormat.prototype.toOGR_SingleFile = function (options, fmt, callback) {
    var dbname = options.dbopts.dbname;
    var userId = options.dbopts.user;
    var gcol = options.gcol;
    var sql = options.sql;
    var skipfields = options.skipfields;
    var ext = this._fileExtension;
    var layername = options.filename;

    var tmpdir = global.settings.tmpDir || '/tmp';
    var reqKey = this.limitPathname([
        fmt,
        dbname,
        userId,
        gcol,
        this.generateMD5(layername),
        this.generateMD5(sql),
        uuid.v4()
    ].concat(skipfields).join(':'));
    var outdirpath = tmpdir + '/sqlapi-' + process.pid + '-' + reqKey;
    var dumpfile = outdirpath + ':cartodb-query.' + ext;

    // TODO: following tests:
    //  - fetch query with no "the_geom" column
    this.toOGR(options, fmt, dumpfile, callback);
};

OgrFormat.prototype.sendResponse = function (opts, callback) {
    var exportRequest = new ExportRequest(opts.sink, callback, opts.beforeSink);

    this.generate(opts, function (err, dumpfile) {
        if (opts.profiler) {
            opts.profiler.done('generate');
        }
        step(
            function sendResult () {
                if (err) {
                    exportRequest.cb(err);
                    return true;
                }
                exportRequest.sendFile(dumpfile, this);
            },
            function cleanup () {
                // unlink dump file (sync to avoid race condition)
                try { fs.unlinkSync(dumpfile); } catch (e) {
                    if (e.code !== 'ENOENT') {
                        console.log('Could not unlink dumpfile ' + dumpfile + ': ' + e);
                    }
                }
            }
        );
    });
};

function ExportRequest (ostream, callback, beforeSink) {
    this.cb = callback;
    this.beforeSink = beforeSink;
    this.ostream = ostream;
    this.istream = null;
    this.canceled = false;
    this.read = false;

    var that = this;

    this.ostream.on('close', function () {
        that.canceled = true;
        if (that.istream) {
            that.istream.destroy();
        }
    });
}

ExportRequest.prototype.sendFile = function (filename, callback) {
    if (this.canceled) {
        return callback();
    }

    var that = this;
    this.istream = fs.createReadStream(filename)
        .on('open', function () {
            if (that.beforeSink) {
                that.beforeSink();
            }

            that.istream
                .pipe(that.ostream)
                .on('end', () => {
                    that.cb();
                    callback();
                })
                .on('error', (err) => {
                    that.cb(err);
                    callback();
                });
        })
        .on('error', function (e) {
            console.log("Can't send response: " + e);
            that.read = true;
            that.ostream.end();
            that.cb(e);
            callback();
        })
        .on('end', () => {
            that.read = true;
            that.cb();
            callback();
        })
        .on('close', () => {
            if (!that.read) { // NOTE: Covering 304 responses, when the 'ostream' is closed after 'pipe'
                callback();
            }
        });
};

module.exports = OgrFormat;
<commit_msg>fix: linter<commit_after>'use strict';

var crypto = require('crypto');
var uuid = require('uuid');
var step = require('step');
var fs = require('fs');
var PSQL = require('cartodb-psql');
var spawn = require('child_process').spawn;

function OgrFormat (id) {
    this.id = id;
}

OgrFormat.prototype = {

    id: 'ogr',

    is_file: true,

    getQuery: function (/* sql, options */) {
        return null; // dont execute the query
    },

    transform: function (/* result, options, callback */) {
        throw new Error('should not be called for file formats');
    },

    getContentType: function () { return this._contentType; },

    getFileExtension: function () { return this._fileExtension; },

    generateMD5: function (data) {
        var hash = crypto.createHash('md5');
        hash.update(data);
        return hash.digest('hex');
    },

    limitPathname: function (pathname) {
        if (pathname.length < 128) { return pathname; }
        return crypto.createHash('sha256').update(pathname).digest('hex');
    }

};

// Internal function usable by all OGR-driven outputs
OgrFormat.prototype.toOGR = function (options, outFormat, outFilename, callback) {
    // var gcol = options.gn;
    var sql = options.sql;
    var skipfields = options.skipfields;
    var outLayername = options.filename;

    var dbopts = options.dbopts;

    var ogr2ogr = global.settings.ogr2ogrCommand || 'ogr2ogr';
    var dbhost = dbopts.host;
    var dbport = dbopts.port;
    var dbuser = dbopts.user;
    var dbpass = dbopts.pass;
    var dbname = dbopts.dbname;

    var timeout = 5 * 60 * 1000; // 5 minutes in milliseconds

    if (Number.isFinite(global.settings.export_command_timeout)) {
        timeout = global.settings.export_command_timeout;
    }

    if (Number.isFinite(options.timeout) && options.timeout > 0) {
        timeout = options.timeout;
    }

    var that = this;

    var columns = [];
    var geocol;
    var pg;
    // Drop ending semicolon (ogr doens't like it)
    sql = sql.replace(/;\s*$/, '');

    const theGeomFirst = (fieldA, fieldB) => {
        if (fieldA.name === 'the_geom') {
            return -1;
        }
        if (fieldB.name === 'the_geom') {
            return 1;
        }
        return 0;
    };

    step(

        function fetchColumns () {
            var colsql = 'SELECT * FROM (' + sql + ') as _cartodbsqlapi LIMIT 0';
            pg = new PSQL(dbopts);
            pg.query(colsql, this);
        },
        function findSRS (err, result) {
            if (err) {
                throw err;
            }

            var needSRS = that._needSRS;

            columns = result.fields
            // skip columns
                .filter(field => skipfields.indexOf(field.name) === -1)
            // put "the_geom" first (if exists)
                .sort(theGeomFirst)
            // get first geometry to calculate SRID ("the_geom" if exists)
                .map(field => {
                    if (needSRS && !geocol && pg.typeName(field.dataTypeID) === 'geometry') {
                        geocol = field.name;
                    }

                    return field;
                })
            // apply quotes to columns
                .map(field => outFormat === 'CSV' ? pg.quoteIdentifier(field.name) + '::text' : pg.quoteIdentifier(field.name));

            if (!needSRS || !geocol) {
                return null;
            }

            var next = this;

            var qgeocol = pg.quoteIdentifier(geocol);
            var sridsql = 'SELECT ST_Srid(' + qgeocol + ') as srid, GeometryType(' +
                   qgeocol + ') as type FROM (' + sql + ') as _cartodbsqlapi WHERE ' +
                   qgeocol + ' is not null limit 1';

            pg.query(sridsql, function (err, result) {
                if (err) { next(err); return; }
                if (result.rows.length) {
                    var srid = result.rows[0].srid;
                    var type = result.rows[0].type;
                    next(null, srid, type);
                } else {
                    // continue as srid and geom type are not critical when there are no results
                    next(null);
                }
            });
        },
        function spawnDumper (err, srid, type) {
            if (err) {
                throw err;
            }

            var next = this;

            var ogrsql = 'SELECT ' + columns.join(',') + ' FROM (' + sql + ') as _cartodbsqlapi';

            var ogrargs = [
                '-f', outFormat,
                '-lco', 'RESIZE=YES', /* shapefile */
                '-lco', 'ENCODING=UTF-8', /* shapefile */
                '-lco', 'STRING_QUOTING=IF_NEEDED', /* csv: Match gdal 2.2 behaviour */
                '-lco', 'LINEFORMAT=CRLF',
                outFilename,
                'PG:host=' + dbhost + ' port=' + dbport + ' user=' + dbuser + ' dbname=' + dbname + ' password=' + dbpass,
                '-sql', ogrsql
            ];

            if (srid) {
                ogrargs.push('-a_srs', 'EPSG:' + srid);
            }

            if (type) {
                ogrargs.push('-nlt', type);
            }

            if (options.cmd_params) {
                ogrargs = ogrargs.concat(options.cmd_params);
            }

            ogrargs.push('-nln', outLayername);

            // TODO: research if `exec` could fit better than `spawn`
            var child = spawn(ogr2ogr, ogrargs);

            var timedOut = false;
            var ogrTimeout;
            if (timeout > 0) {
                ogrTimeout = setTimeout(function () {
                    timedOut = true;
                    child.kill();
                }, timeout);
            }

            child.on('error', function (err) {
                clearTimeout(ogrTimeout);
                next(err);
            });

            var stderrData = [];
            child.stderr.setEncoding('utf8');
            child.stderr.on('data', function (data) {
                stderrData.push(data);
            });

            child.on('exit', function (code) {
                clearTimeout(ogrTimeout);

                if (timedOut) {
                    return next(new Error('statement timeout'));
                }

                if (code !== 0) {
                    var errMessage = 'ogr2ogr command return code ' + code;
                    if (stderrData.length > 0) {
                        errMessage += ', Error: ' + stderrData.join('\n');
                    }

                    return next(new Error(errMessage));
                }

                return next();
            });
        },
        function finish (err) {
            callback(err, outFilename);
        }
    );
};

OgrFormat.prototype.toOGR_SingleFile = function (options, fmt, callback) {
    var dbname = options.dbopts.dbname;
    var userId = options.dbopts.user;
    var gcol = options.gcol;
    var sql = options.sql;
    var skipfields = options.skipfields;
    var ext = this._fileExtension;
    var layername = options.filename;

    var tmpdir = global.settings.tmpDir || '/tmp';
    var reqKey = this.limitPathname([
        fmt,
        dbname,
        userId,
        gcol,
        this.generateMD5(layername),
        this.generateMD5(sql),
        uuid.v4()
    ].concat(skipfields).join(':'));
    var outdirpath = tmpdir + '/sqlapi-' + process.pid + '-' + reqKey;
    var dumpfile = outdirpath + ':cartodb-query.' + ext;

    // TODO: following tests:
    //  - fetch query with no "the_geom" column
    this.toOGR(options, fmt, dumpfile, callback);
};

OgrFormat.prototype.sendResponse = function (opts, callback) {
    var exportRequest = new ExportRequest(opts.sink, callback, opts.beforeSink);

    this.generate(opts, function (err, dumpfile) {
        if (opts.profiler) {
            opts.profiler.done('generate');
        }
        step(
            function sendResult () {
                if (err) {
                    exportRequest.cb(err);
                    return true;
                }
                exportRequest.sendFile(dumpfile, this);
            },
            function cleanup () {
                // unlink dump file (sync to avoid race condition)
                try { fs.unlinkSync(dumpfile); } catch (e) {
                    if (e.code !== 'ENOENT') {
                        console.log('Could not unlink dumpfile ' + dumpfile + ': ' + e);
                    }
                }
            }
        );
    });
};

function ExportRequest (ostream, callback, beforeSink) {
    this.cb = callback;
    this.beforeSink = beforeSink;
    this.ostream = ostream;
    this.istream = null;
    this.canceled = false;
    this.read = false;

    var that = this;

    this.ostream.on('close', function () {
        that.canceled = true;
        if (that.istream) {
            that.istream.destroy();
        }
    });
}

ExportRequest.prototype.sendFile = function (filename, callback) {
    if (this.canceled) {
        return callback();
    }

    var that = this;
    this.istream = fs.createReadStream(filename)
        .on('open', function () {
            if (that.beforeSink) {
                that.beforeSink();
            }

            that.istream
                .pipe(that.ostream)
                .on('end', () => {
                    that.cb();
                    callback();
                })
                .on('error', (err) => {
                    that.cb(err);
                    callback();
                });
        })
        .on('error', function (e) {
            console.log("Can't send response: " + e);
            that.read = true;
            that.ostream.end();
            that.cb(e);
            callback();
        })
        .on('end', () => {
            that.read = true;
            that.cb();
            callback();
        })
        .on('close', () => {
            if (!that.read) { // NOTE: Covering 304 responses, when the 'ostream' is closed after 'pipe'
                callback();
            }
        });
};

module.exports = OgrFormat;
<|endoftext|>


<commit_before>define(['angular', 'angular-growl'], function(angular) { 'use strict';

    var deps = ['ngRoute', 'ngCookies', 'angular-growl'];

    angular.defineModules(deps);

    var app = angular.module('app', deps);

    app.config(['$httpProvider', 'growlProvider', function($httpProvider, growlProvider) {

        $httpProvider.useApplyAsync(true);
        $httpProvider.interceptors.push('authenticationHttpIntercepter');
        $httpProvider.interceptors.push('machineAuthorizationHttpIntercepter');

        growlProvider.globalTimeToLive(5000);
        growlProvider.globalEnableHtml(false);

    }]);

    app.factory('machineAuthorizationHttpIntercepter', ["$q", "apiToken", "$cookies", function($q, apiToken, $cookies) {

		return {
			request: function(config) {

				var trusted = /^\/api\/\/v2014\/printsmart-requests/i.test(config.url) ||
                              /^\/api\/\/v2014\/kronos/i             .test(config.url);

				var hasAuthorization = (config.headers||{}).hasOwnProperty('machineAuthorization');

				if(!trusted || hasAuthorization) // no need to alter config
					return config;

				//Add token to http headers

                if($cookies.get("machineAuthorization")) {
                    config.headers = config.headers || {};
                    config.headers.machineAuthorization = $cookies.get("machineAuthorization");
                }
			}
		};
	}]);

    return app;
});
<commit_msg>Eensure authetication module is loaded for the required intercepter<commit_after>define(['angular', 'require', 'angular-growl'], function(angular, require) { 'use strict';

    var deps = ['ngRoute', 'ngCookies', 'angular-growl'];

    angular.defineModules(deps);

    var app = angular.module('app', deps);

    app.config(['$httpProvider', 'growlProvider', function($httpProvider, growlProvider) {

        $httpProvider.useApplyAsync(true);
        $httpProvider.interceptors.push('authenticationHttpIntercepter');
        $httpProvider.interceptors.push('machineAuthorizationHttpIntercepter');

        growlProvider.globalTimeToLive(5000);
        growlProvider.globalEnableHtml(false);

    }]);

    app.factory('machineAuthorizationHttpIntercepter', ["$q", "apiToken", "$cookies", function($q, apiToken, $cookies) {

		return {
			request: function(config) {

				var trusted = /^\/api\/\/v2014\/printsmart-requests/i.test(config.url) ||
                              /^\/api\/\/v2014\/kronos/i             .test(config.url);

				var hasAuthorization = (config.headers||{}).hasOwnProperty('machineAuthorization');

				if(!trusted || hasAuthorization) // no need to alter config
					return config;

				//Add token to http headers

                if($cookies.get("machineAuthorization")) {
                    config.headers = config.headers || {};
                    config.headers.machineAuthorization = $cookies.get("machineAuthorization");
                }
			}
		};
	}]);

    require(['authentication']);//Ensure authentication exists

    return app;
});
<|endoftext|>


<commit_before>#!/usr/local/bin/node
/*
curl -i https://api.github.com/orgs/intel-hadoop/members
curl -i 'https://api.github.com/repos/intel-hadoop/gearpump/commits?since=2014-10-16&until=2014-10-31'
curl -i 'https://api.github.com/repos/intel-hadoop/gearpump/pulls?state=closed&direction=asc'
curl -i https://api.github.com/repos/intel-hadoop/gearpump/stats/contributors
curl -i https://api.github.com/repos/intel-hadoop/gearpump/stats/participation
*/
function gitapi(uri, cb) {
  var request = require('request');
  var options = {
    url: 'https://api.github.com'+uri,
    auth: {
      'user': 'kkasravi',
      'pass': 'kdkkdk1'
    },
    headers: {
        'User-Agent': 'request'
    }
  };
  function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
      var info = JSON.parse(body);
      cb(info);
    } else {
      console.log('statusCode='+response.statusCode+' error='+error);
    }
  }
  request(options, callback);
}

MetricsInput = (function() {
  function MetricsInput() {
    this.input = null;
    this.inputCallback = this.inputCallback.bind(this);
    getInput('/repos/intel-hadoop/team-metrics','master','/input', this.inputCallback);
  }

  MetricsInput.prototype.inputCallback = function (data) {
    this.input = JSON.parse(data);
    var self = this;
    this.input.forEach(function(team) {
      new Metrics(team)
    });
  }

  return MetricsInput;
})();

Metrics = (function() {
  function Metrics(team) {
    this.team = team;
    this.members = {};
    this.repo = null;
    this.timeRange = [];
    this.membersCallback = this.membersCallback.bind(this);
    this.pullRequestCallback = this.pullRequestCallback.bind(this);
    this.statsCallback = this.statsCallback.bind(this);
    this.teamCallback = this.teamCallback.bind(this);
    getTeam(this.team.name, this.teamCallback);
  }

  Metrics.prototype.membersCallback = function (membersArray) {
    var self = this;
    membersArray.forEach(function(member) {
      self.members[member.login] = {}
    });
    this.team.repos.forEach(function(repo) {
      self.repo = repo;
      getStats(self.repo.name+'/stats/contributors',self.statsCallback);
    });
  }

  Metrics.prototype.pullRequestCallback = function(data) {
    var self = this;
    console.log(this.team.name+'\n  '+this.repo.name)
    data.forEach(function(pull) {
      if(self.members[pull.user.login]) {
        var created = new Date(pull.created_at)
        var closed = new Date(pull.closed_at)
        //if(closed.getTime() > self.timeRange[0] && closed.getTime() < self.timeRange[1]) {
//console.log(pull.base.repo.name+' '+pull.user.login+' closed '+closed.getTime()+' timeRange[0] '+self.timeRange[0]);
        if(closed.getTime() > self.timeRange[0]) {
          console.log('    '+pull.user.login);
          console.log('      '+created.toDateString()+' closed '+closed.toDateString())
        }
      }
    });
  }

  Metrics.prototype.statsCallback = function (stats) {
    console.log(this.team.name+'\n  '+this.repo.name)
    var self = this;
    var totals = {commits:0,additions:0,deletions:0};
    stats.forEach(function(stat) {
      var member = stat.author.login
      if(self.members[member]) {
        console.log('    '+member);
        self.members[member].weeks = stat.weeks.slice(-2)
        self.members[member].weeks.forEach(function(week,i) {
          var date = new Date()
          var time = parseInt(week.w+'000');
          date.setTime(time);
          if(i===0) {
//console.log('setting self.timeRange '+date.toDateString());
            self.timeRange.push(time);
          }
          var commit = parseInt(week.c);
          var additions = parseInt(week.a);
          var deletions = parseInt(week.d);
          totals.commits += commit;
          totals.additions += additions;
          totals.deletions += deletions;
          console.log('      '+date.toDateString()+' commits:'+week.c+' additions:'+week.a+' deletions:'+week.d);
        });
      }
    });
    console.log('  commits:'+totals.commits+' additions:'+totals.additions+' deletions:'+totals.deletions+'\n');
    getPullRequests(this.repo.name,this.repo.branch,this.pullRequestCallback)
  }

  Metrics.prototype.teamCallback = function (team) {
    getMembers(team.id, this.membersCallback);
  }

  return Metrics;
})();

function getInput(repo, branch, path, inputcallback) {
  function callback(repo, branch, path, data) {
    var encoded = data.content;
    var content = new Buffer(encoded, 'base64').toString('ascii');
    inputcallback(content)
  }
  gitapi(repo+'/contents'+path+'?ref='+branch,callback.bind(undefined,repo,branch,path));
}

function getTeam(team, teamcallback) {
  function teamsCallback(name, teamcallback, teams) {
    teams.some(function(team) {
      if(team.name === name) {
        teamcallback(team);
        return true;
      }
      return false;
    })
  }
  gitapi('/orgs/intel-hadoop/teams',teamsCallback.bind(undefined,team,teamcallback));
}

function getStats(repo, statscallback) {
  gitapi(repo,statscallback);
}

function getPullRequests(repo, branch, pullrequestcallback) {
  function pullRequestsCallback(repo, pullrequestcallback, data) {
    pullrequestcallback(data)
  }
  gitapi(repo+'/pulls?state=closed&branch='+branch+'&direction=desc',pullRequestsCallback.bind(undefined,repo,pullrequestcallback));
}

function getMembers(teamid,memberscallback) {
  var uri = '/teams/'+teamid+'/members';
  gitapi(uri,memberscallback);
}
function getCommits(range,commitsCallback) {
  var uri = '/teams/'+teamid+'/members';
  gitapi(uri,memberscallback);
}

new MetricsInput()
<commit_msg>Combined pullrequests with commits. Now generating report based on built output object<commit_after>#!/usr/local/bin/node
/*
curl -i https://api.github.com/orgs/intel-hadoop/members
curl -i 'https://api.github.com/repos/intel-hadoop/gearpump/commits?since=2014-10-16&until=2014-10-31'
curl -i 'https://api.github.com/repos/intel-hadoop/gearpump/pulls?state=closed&direction=asc'
curl -i https://api.github.com/repos/intel-hadoop/gearpump/stats/contributors
curl -i https://api.github.com/repos/intel-hadoop/gearpump/stats/participation
*/
function gitapi(uri, cb) {
  var request = require('request');
  var options = {
    url: 'https://api.github.com'+uri,
    auth: {
      'user': 'kkasravi',
      'pass': 'kdkkdk1'
    },
    headers: {
        'User-Agent': 'request'
    }
  };
  function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
      var info = JSON.parse(body);
      cb(info);
    } else {
      console.log('statusCode='+response.statusCode+' error='+error);
    }
  }
  request(options, callback);
}

MetricsInput = (function() {
  function MetricsInput() {
    this.input = null;
    this.inputCallback = this.inputCallback.bind(this);
    getInput('/repos/intel-hadoop/team-metrics','master','/input', this.inputCallback);
  }

  MetricsInput.prototype.inputCallback = function (data) {
    this.input = JSON.parse(data);
    var self = this;
    this.input.forEach(function(team) {
      new Metrics(team)
    });
  }

  return MetricsInput;
})();

Metrics = (function() {
  function Metrics(team) {
    this.team = team;
    this.members = {};
    this.repo = null;
    this.timeRange = [];
    this.generateReport = this.generateReport.bind(this);
    this.membersCallback = this.membersCallback.bind(this);
    this.pullRequestCallback = this.pullRequestCallback.bind(this);
    this.statsCallback = this.statsCallback.bind(this);
    this.teamCallback = this.teamCallback.bind(this);
    getTeam(this.team.name, this.teamCallback);
  }

  Metrics.prototype.generateReport = function () {
    console.log(this.team.name+'\n  '+this.repo.name)
    for(var member in this.members) {
      console.log('    '+member);
      this.members[member].weeks && this.members[member].weeks.forEach(function(week) {
        console.log('      '+week.date.toDateString()+' commits:'+week.commits+' pullrequests:'+week.pullrequests+' additions:'+week.additions+' deletions:'+week.deletions);
      });
    }
    console.log('  commits:'+this.totals.commits+' pullrequests:'+this.totals.pullrequests+' additions:'+this.totals.additions+' deletions:'+this.totals.deletions+'\n');
  }

  Metrics.prototype.membersCallback = function (membersArray) {
    var self = this;
    membersArray.forEach(function(member) {
      self.members[member.login] = {}
    });
    this.team.repos.forEach(function(repo) {
      self.repo = repo;
      getStats(self.repo.name+'/stats/contributors',self.statsCallback);
    });
  }

  Metrics.prototype.pullRequestCallback = function(data) {
    var self = this;
    data.forEach(function(pull) {
      if(self.members[pull.user.login]) {
        var created = new Date(pull.created_at)
        var closed = new Date(pull.closed_at)
        if(closed.getTime() >= self.timeRange[0] && closed.getTime() < self.timeRange[1]) {
          self.members[pull.user.login].weeks[0].pullrequests++;
        } else if(closed.getTime() >= self.timeRange[1]) {
          self.members[pull.user.login].weeks[1].pullrequests++;
        }
      }
    });
    this.generateReport()
  }

  Metrics.prototype.statsCallback = function (stats) {
    var self = this;
    self.totals = {commits:0,pullrequests:0,additions:0,deletions:0};
    stats.forEach(function(stat) {
      var member = stat.author.login
      if(self.members[member]) {
        var weeks = stat.weeks.slice(-2)
        self.members[member].weeks = [];
        weeks.forEach(function(aweek,i) {
          var week = {date:new Date(),commits:0,pullrequests:0,additions:0,deletions:0};
          var time = parseInt(aweek.w+'000');
          if(i===0) {
            self.timeRange.push(time);
          }
          week.date.setTime(time);
          week.commits = parseInt(aweek.c);
          week.additions = parseInt(aweek.a);
          week.deletions = parseInt(aweek.d);
          self.members[member].weeks.push(week);
          self.totals.commits += week.commits;
          self.totals.additions += week.additions;
          self.totals.deletions += week.deletions;
        });
      }
    });
    getPullRequests(this.repo.name,this.repo.branch,this.pullRequestCallback)
  }

  Metrics.prototype.teamCallback = function (team) {
    getMembers(team.id, this.membersCallback);
  }

  return Metrics;
})();

function getInput(repo, branch, path, inputcallback) {
  function callback(repo, branch, path, data) {
    var encoded = data.content;
    var content = new Buffer(encoded, 'base64').toString('ascii');
    inputcallback(content)
  }
  gitapi(repo+'/contents'+path+'?ref='+branch,callback.bind(undefined,repo,branch,path));
}

function getTeam(team, teamcallback) {
  function teamsCallback(name, teamcallback, teams) {
    teams.some(function(team) {
      if(team.name === name) {
        teamcallback(team);
        return true;
      }
      return false;
    })
  }
  gitapi('/orgs/intel-hadoop/teams',teamsCallback.bind(undefined,team,teamcallback));
}

function getStats(repo, statscallback) {
  gitapi(repo,statscallback);
}

function getPullRequests(repo, branch, pullrequestcallback) {
  function pullRequestsCallback(repo, pullrequestcallback, data) {
    pullrequestcallback(data)
  }
  gitapi(repo+'/pulls?state=closed&branch='+branch+'&direction=desc',pullRequestsCallback.bind(undefined,repo,pullrequestcallback));
}

function getMembers(teamid,memberscallback) {
  var uri = '/teams/'+teamid+'/members';
  gitapi(uri,memberscallback);
}
function getCommits(range,commitsCallback) {
  var uri = '/teams/'+teamid+'/members';
  gitapi(uri,memberscallback);
}

new MetricsInput()
<|endoftext|>


<commit_before>var N3Writer = require('../N3').Writer;
var chai = require('chai');
chai.should();

describe('N3Parser', function () {
  describe('The N3Writer module', function () {
    it('should be a function', function () {
      N3Writer.should.be.a('function');
    });

    it('should make N3Writer objects', function () {
      N3Writer().should.be.an.instanceof(N3Writer);
    });

    it('should be an N3Writer constructor', function () {
      new N3Writer().should.be.an.instanceof(N3Writer);
    });
  });

  describe('An N3Writer instance', function () {
    it('should serialize 0 triples',
      shouldSerialize([], ''));

    it('should serialize 1 triple',
      shouldSerialize([['abc', 'def', 'ghi']],
                      '<abc> <def> <ghi>.\n'));

    it('should serialize 2 triples',
      shouldSerialize([['abc', 'def', 'ghi'],
                       ['jkl', 'mno', 'pqr']],
                      '<abc> <def> <ghi>.\n' +
                      '<jkl> <mno> <pqr>.\n'));

    it('should serialize 3 triples',
      shouldSerialize([['abc', 'def', 'ghi'],
                       ['jkl', 'mno', 'pqr'],
                       ['stu', 'vwx', 'yz']],
                      '<abc> <def> <ghi>.\n' +
                      '<jkl> <mno> <pqr>.\n' +
                      '<stu> <vwx> <yz>.\n'));

    it('should serialize a literal',
      shouldSerialize([['a', 'b', '"cde"']],
                      '<a> <b> "cde".\n'));

    it('should serialize a literal with a type',
      shouldSerialize([['a', 'b', '"cde"^^<fgh>']],
                      '<a> <b> "cde"^^<fgh>.\n'));

    it('should serialize a literal with a language',
      shouldSerialize([['a', 'b', '"cde"@en-us']],
                      '<a> <b> "cde"@en-us.\n'));

    it('should serialize a literal containing a single quote',
      shouldSerialize([['a', 'b', '"c\'de"']],
                      '<a> <b> "c\'de".\n'));

    it('should serialize a literal containing a double quote',
      shouldSerialize([['a', 'b', '"c"de"']],
                      '<a> <b> "c\\"de".\n'));

    it('should serialize a literal containing a backspace',
      shouldSerialize([['a', 'b', '"c\\de"']],
                      '<a> <b> "c\\\\de".\n'));

    it('should serialize a literal containing a tab character',
      shouldSerialize([['a', 'b', '"c\tde"']],
                      '<a> <b> "c\\tde".\n'));

    it('should serialize a literal containing a newline character',
      shouldSerialize([['a', 'b', '"c\nde"']],
                      '<a> <b> "c\\nde".\n'));

    it('should serialize a literal containing a cariage return character',
      shouldSerialize([['a', 'b', '"c\rde"']],
                      '<a> <b> "c\\rde".\n'));

    it('should serialize a literal containing a backspace character',
      shouldSerialize([['a', 'b', '"c\bde"']],
                      '<a> <b> "c\\bde".\n'));

    it('should serialize a literal containing a form feed character',
      shouldSerialize([['a', 'b', '"c\fde"']],
                      '<a> <b> "c\\fde".\n'));

    it('should serialize blank nodes',
      shouldSerialize([['_:a', 'b', '_:c']],
                      '_:a <b> _:c.\n'));

    it('should not serialize a literal in the subject',
      shouldNotSerialize([['"a"', 'b', '"c']],
                          'A literal as subject is not allowed: "a"'));

    it('should not serialize a literal in the predicate',
      shouldNotSerialize([['a', '"b"', '"c']],
                          'A literal as predicate is not allowed: "b"'));

    it('should serialize valid prefixes',
      shouldSerialize({ a: 'http://a.org/',
                        b: 'http://a.org/b#',
                        c: 'http://a.org/b' },
                      [],
                      '@prefix a: <http://a.org/>.\n' +
                      '@prefix b: <http://a.org/b#>.\n\n'));

    it('should use prefixes when possible',
      shouldSerialize({ a: 'http://a.org/',
                        b: 'http://a.org/b#',
                        c: 'http://a.org/b' },
                      [['http://a.org/bc', 'http://a.org/b#ef', 'http://a.org/bhi'],
                       ['http://a.org/bc/de', 'http://a.org/b#e#f', 'http://a.org/b#x/t'],
                       ['http://a.org/3a', 'http://a.org/b#3a', 'http://a.org/b#a3']],
                      '@prefix a: <http://a.org/>.\n' +
                      '@prefix b: <http://a.org/b#>.\n\n' +
                      'a:bc b:ef a:bhi.\n' +
                      '<http://a.org/bc/de> <http://a.org/b#e#f> <http://a.org/b#x/t>.\n' +
                      '<http://a.org/3a> <http://a.org/b#3a> b:a3.\n'));

    it('should not repeat the same subjects',
      shouldSerialize([['abc', 'def', 'ghi'],
                       ['abc', 'mno', 'pqr'],
                       ['stu', 'vwx', 'yz']],
                      '<abc> <def> <ghi>;\n' +
                      '    <mno> <pqr>.\n' +
                      '<stu> <vwx> <yz>.\n'));

    it('should not repeat the same predicates',
      shouldSerialize([['abc', 'def', 'ghi'],
                       ['abc', 'def', 'pqr'],
                       ['abc', 'bef', 'ghi'],
                       ['abc', 'bef', 'pqr'],
                       ['stu', 'bef', 'yz']],
                      '<abc> <def> <ghi>, <pqr>;\n' +
                      '    <bef> <ghi>, <pqr>.\n' +
                      '<stu> <bef> <yz>.\n'));

    it('should write rdf:type as "a"',
      shouldSerialize([['abc', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'def']],
                      '<abc> a <def>.\n'));

    it('calls the done callback when ending the outputstream errors', function (done) {
      var writer = new N3Writer({
        write: function () {},
        end: function () { throw 'error'; },
      });
      writer.end(done);
    });

    it('sends output through end when no stream argument is given', function (done) {
      var writer = new N3Writer(), notCalled = true;
      writer.addTriple({ subject: 'a', predicate: 'b', object: 'c' }, function () { notCalled = false; });
      writer.end(function (error, output) {
        output.should.equal('<a> <b> <c>.\n');
        done(notCalled || error);
      });
    });

    it('respects the prefixes argument when no stream argument is given', function (done) {
      var writer = new N3Writer({ a: 'b#' });
      writer.addTriple({ subject: 'b#a', predicate: 'b#b', object: 'b#c' });
      writer.end(function (error, output) {
        output.should.equal('@prefix a: <b#>.\n\na:a a:b a:c.\n');
        done(error);
      });
    });

    it('should accept triples with separated components', function (done) {
      var writer = N3Writer();
      writer.addTriple('a', 'b', 'c');
      writer.addTriple('a', 'b', 'd');
      writer.end(function (error, output) {
        output.should.equal('<a> <b> <c>, <d>.\n');
        done(error);
      });
    });

    it('should accept triples in bulk', function (done) {
      var writer = N3Writer();
      writer.addTriples([{ subject: 'a', predicate: 'b', object: 'c' },
                         { subject: 'a', predicate: 'b', object: 'd' }]);
      writer.end(function (error, output) {
        output.should.equal('<a> <b> <c>, <d>.\n');
        done(error);
      });
    });
  });
});

function shouldSerialize(prefixes, tripleArrays, expectedResult) {
  if (!expectedResult)
    expectedResult = tripleArrays, tripleArrays = prefixes, prefixes = null;
  return function (done) {
    var outputStream = new QuickStream(),
        writer = N3Writer(outputStream, prefixes);
    (function next() {
      var item = tripleArrays.shift();
      if (item)
        writer.addTriple({ subject: item[0], predicate: item[1], object: item[2] }, next);
      else
        writer.end(function (error) {
          try {
            outputStream.result.should.equal(expectedResult);
            done(error);
          }
          catch (e) {
            done(e);
          }
        });
    })();
  };
}

function shouldNotSerialize(tripleArrays, expectedMessage) {
  return function (done) {
    var outputStream = new QuickStream(),
        writer = N3Writer(outputStream),
        item = tripleArrays.shift();
    writer.addTriple({ subject: item[0], predicate: item[1], object: item[2] },
                      function (error) {
                        if (error) {
                          error.message.should.equal(expectedMessage);
                          done();
                        }
                      });
  };
}

function QuickStream() {
  var stream = {}, buffer = '';
  stream.write = function (chunk, encoding, callback) { buffer += chunk; callback && callback(); };
  stream.end = function (callback) { stream.result = buffer; buffer = null; callback(); };
  return stream;
}
<commit_msg>Replace remaining hard spaces.<commit_after>var N3Writer = require('../N3').Writer;
var chai = require('chai');
chai.should();

describe('N3Parser', function () {
  describe('The N3Writer module', function () {
    it('should be a function', function () {
      N3Writer.should.be.a('function');
    });

    it('should make N3Writer objects', function () {
      N3Writer().should.be.an.instanceof(N3Writer);
    });

    it('should be an N3Writer constructor', function () {
      new N3Writer().should.be.an.instanceof(N3Writer);
    });
  });

  describe('An N3Writer instance', function () {
    it('should serialize 0 triples',
      shouldSerialize([], ''));

    it('should serialize 1 triple',
      shouldSerialize([['abc', 'def', 'ghi']],
                      '<abc> <def> <ghi>.\n'));

    it('should serialize 2 triples',
      shouldSerialize([['abc', 'def', 'ghi'],
                       ['jkl', 'mno', 'pqr']],
                      '<abc> <def> <ghi>.\n' +
                      '<jkl> <mno> <pqr>.\n'));

    it('should serialize 3 triples',
      shouldSerialize([['abc', 'def', 'ghi'],
                       ['jkl', 'mno', 'pqr'],
                       ['stu', 'vwx', 'yz']],
                      '<abc> <def> <ghi>.\n' +
                      '<jkl> <mno> <pqr>.\n' +
                      '<stu> <vwx> <yz>.\n'));

    it('should serialize a literal',
      shouldSerialize([['a', 'b', '"cde"']],
                      '<a> <b> "cde".\n'));

    it('should serialize a literal with a type',
      shouldSerialize([['a', 'b', '"cde"^^<fgh>']],
                      '<a> <b> "cde"^^<fgh>.\n'));

    it('should serialize a literal with a language',
      shouldSerialize([['a', 'b', '"cde"@en-us']],
                      '<a> <b> "cde"@en-us.\n'));

    it('should serialize a literal containing a single quote',
      shouldSerialize([['a', 'b', '"c\'de"']],
                      '<a> <b> "c\'de".\n'));

    it('should serialize a literal containing a double quote',
      shouldSerialize([['a', 'b', '"c"de"']],
                      '<a> <b> "c\\"de".\n'));

    it('should serialize a literal containing a backspace',
      shouldSerialize([['a', 'b', '"c\\de"']],
                      '<a> <b> "c\\\\de".\n'));

    it('should serialize a literal containing a tab character',
      shouldSerialize([['a', 'b', '"c\tde"']],
                      '<a> <b> "c\\tde".\n'));

    it('should serialize a literal containing a newline character',
      shouldSerialize([['a', 'b', '"c\nde"']],
                      '<a> <b> "c\\nde".\n'));

    it('should serialize a literal containing a cariage return character',
      shouldSerialize([['a', 'b', '"c\rde"']],
                      '<a> <b> "c\\rde".\n'));

    it('should serialize a literal containing a backspace character',
      shouldSerialize([['a', 'b', '"c\bde"']],
                      '<a> <b> "c\\bde".\n'));

    it('should serialize a literal containing a form feed character',
      shouldSerialize([['a', 'b', '"c\fde"']],
                      '<a> <b> "c\\fde".\n'));

    it('should serialize blank nodes',
      shouldSerialize([['_:a', 'b', '_:c']],
                      '_:a <b> _:c.\n'));

    it('should not serialize a literal in the subject',
      shouldNotSerialize([['"a"', 'b', '"c']],
                          'A literal as subject is not allowed: "a"'));

    it('should not serialize a literal in the predicate',
      shouldNotSerialize([['a', '"b"', '"c']],
                          'A literal as predicate is not allowed: "b"'));

    it('should serialize valid prefixes',
      shouldSerialize({ a: 'http://a.org/',
                        b: 'http://a.org/b#',
                        c: 'http://a.org/b' },
                      [],
                      '@prefix a: <http://a.org/>.\n' +
                      '@prefix b: <http://a.org/b#>.\n\n'));

    it('should use prefixes when possible',
      shouldSerialize({ a: 'http://a.org/',
                        b: 'http://a.org/b#',
                        c: 'http://a.org/b' },
                      [['http://a.org/bc', 'http://a.org/b#ef', 'http://a.org/bhi'],
                       ['http://a.org/bc/de', 'http://a.org/b#e#f', 'http://a.org/b#x/t'],
                       ['http://a.org/3a', 'http://a.org/b#3a', 'http://a.org/b#a3']],
                      '@prefix a: <http://a.org/>.\n' +
                      '@prefix b: <http://a.org/b#>.\n\n' +
                      'a:bc b:ef a:bhi.\n' +
                      '<http://a.org/bc/de> <http://a.org/b#e#f> <http://a.org/b#x/t>.\n' +
                      '<http://a.org/3a> <http://a.org/b#3a> b:a3.\n'));

    it('should not repeat the same subjects',
      shouldSerialize([['abc', 'def', 'ghi'],
                       ['abc', 'mno', 'pqr'],
                       ['stu', 'vwx', 'yz']],
                      '<abc> <def> <ghi>;\n' +
                      '    <mno> <pqr>.\n' +
                      '<stu> <vwx> <yz>.\n'));

    it('should not repeat the same predicates',
      shouldSerialize([['abc', 'def', 'ghi'],
                       ['abc', 'def', 'pqr'],
                       ['abc', 'bef', 'ghi'],
                       ['abc', 'bef', 'pqr'],
                       ['stu', 'bef', 'yz']],
                      '<abc> <def> <ghi>, <pqr>;\n' +
                      '    <bef> <ghi>, <pqr>.\n' +
                      '<stu> <bef> <yz>.\n'));

    it('should write rdf:type as "a"',
      shouldSerialize([['abc', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'def']],
                      '<abc> a <def>.\n'));

    it('calls the done callback when ending the outputstream errors', function (done) {
      var writer = new N3Writer({
        write: function () {},
        end: function () { throw 'error'; },
      });
      writer.end(done);
    });

    it('sends output through end when no stream argument is given', function (done) {
      var writer = new N3Writer(), notCalled = true;
      writer.addTriple({ subject: 'a', predicate: 'b', object: 'c' }, function () { notCalled = false; });
      writer.end(function (error, output) {
        output.should.equal('<a> <b> <c>.\n');
        done(notCalled || error);
      });
    });

    it('respects the prefixes argument when no stream argument is given', function (done) {
      var writer = new N3Writer({ a: 'b#' });
      writer.addTriple({ subject: 'b#a', predicate: 'b#b', object: 'b#c' });
      writer.end(function (error, output) {
        output.should.equal('@prefix a: <b#>.\n\na:a a:b a:c.\n');
        done(error);
      });
    });

    it('should accept triples with separated components', function (done) {
      var writer = N3Writer();
      writer.addTriple('a', 'b', 'c');
      writer.addTriple('a', 'b', 'd');
      writer.end(function (error, output) {
        output.should.equal('<a> <b> <c>, <d>.\n');
        done(error);
      });
    });

    it('should accept triples in bulk', function (done) {
      var writer = N3Writer();
      writer.addTriples([{ subject: 'a', predicate: 'b', object: 'c' },
                         { subject: 'a', predicate: 'b', object: 'd' }]);
      writer.end(function (error, output) {
        output.should.equal('<a> <b> <c>, <d>.\n');
        done(error);
      });
    });
  });
});

function shouldSerialize(prefixes, tripleArrays, expectedResult) {
  if (!expectedResult)
    expectedResult = tripleArrays, tripleArrays = prefixes, prefixes = null;
  return function (done) {
    var outputStream = new QuickStream(),
        writer = N3Writer(outputStream, prefixes);
    (function next() {
      var item = tripleArrays.shift();
      if (item)
        writer.addTriple({ subject: item[0], predicate: item[1], object: item[2] }, next);
      else
        writer.end(function (error) {
          try {
            outputStream.result.should.equal(expectedResult);
            done(error);
          }
          catch (e) {
            done(e);
          }
        });
    })();
  };
}

function shouldNotSerialize(tripleArrays, expectedMessage) {
  return function (done) {
    var outputStream = new QuickStream(),
        writer = N3Writer(outputStream),
        item = tripleArrays.shift();
    writer.addTriple({ subject: item[0], predicate: item[1], object: item[2] },
                      function (error) {
                        if (error) {
                          error.message.should.equal(expectedMessage);
                          done();
                        }
                      });
  };
}

function QuickStream() {
  var stream = {}, buffer = '';
  stream.write = function (chunk, encoding, callback) { buffer += chunk; callback && callback(); };
  stream.end = function (callback) { stream.result = buffer; buffer = null; callback(); };
  return stream;
}
<|endoftext|>


<commit_before>

  var canary_island,peninsula;  // Maps
  var start_center = new google.maps.LatLng(39.67660002390679,-3.6563984375000036); // Maps center position
  var start_zoom = 6;
  var previous_zoom = 6;  // Hack for jump 10 zoom
  var canary_center = new google.maps.LatLng(28.3660940558243,-15.631496093750004);
  var peninsula_center = new google.maps.LatLng(39.67660002390679,-3.6563984375000036);
  var projection = new MercatorProjection();
  var infowindow,comparewindow;
  var dragging = false;
  var baseUrl="http://chart.apis.google.com/chart?chs=256x256";
  var chco = "6B6A6ADF|65432100";
  var chf = "bg,s,65432100";
  var chld = "ES";
  var chd = "";
  var political_parties;
  var custom_map_style = [{featureType:"administrative.country",elementType:"all",stylers:[{saturation:-100},{visibility:"off"}]},{featureType:"administrative.province",elementType:"all",stylers:[{visibility:"off"}]},{featureType:"administrative.locality",elementType:"all",stylers:[{visibility:"off"}]},{featureType:"road.arterial",elementType:"all",stylers:[{visibility:"off"}]},{featureType:"all",elementType:"labels",stylers:[{visibility:"off"}]},{featureType:"all",elementType:"all",stylers:[{lightness:7},{saturation:-91}]},{featureType:"all",elementType:"all",stylers:[]}];

  function initializeMap() {

    var peninsula_ops = {zoom: start_zoom,center: start_center,disableDefaultUI: true,mapTypeId: google.maps.MapTypeId.ROADMAP,scrollwheel: false, minZoom: 6,maxZoom: 12, mapTypeControlOptions: {mapTypeIds: [google.maps.MapTypeId.ROADMAP, 'rtve']}};

    peninsula = new google.maps.Map(document.getElementById("peninsula"),peninsula_ops);

    //Custom styled map - custom_map_style
    var styledMapOptions = {name: "rtve"};
    var rtveMapType = new google.maps.StyledMapType(custom_map_style, styledMapOptions);
    peninsula.mapTypes.set('rtve', rtveMapType);
    peninsula.setMapTypeId('rtve');

    var mapChartOptions = {
        getTileUrl: function(coord, zoom) {
            var lULP = new google.maps.Point(coord.x*256,(coord.y+1)*256);
            var lLRP = new google.maps.Point((coord.x+1)*256,coord.y*256);
            var projectionMap = new MercatorProjection();
            var lULg = projectionMap.fromDivPixelToLatLng(lULP, zoom);
            var lLRg = projectionMap.fromDivPixelToLatLng(lLRP, zoom);
            return baseUrl+"&chd="+chd+"&chco="+chco+"&chld="+chld+"&chf="+chf+"&cht=map:fixed="+
               lULg.lat() +","+ lULg.lng() + "," + lLRg.lat() + "," + lLRg.lng();
        },
        tileSize: new google.maps.Size(256, 256),
        isPng: true,
        minZoom: 6,
        maxZoom: 12,
        name: "Hide rest of countries"
    };
    var mapChartType = new google.maps.ImageMapType(mapChartOptions);
    peninsula.overlayMapTypes.insertAt(0, mapChartType);

    //Political tiles
    political_parties = new google.maps.ImageMapType({
       getTileUrl: function(tile, zoom) {
         var rn=Math.ceil(Math.random()*4);
         return tiles_pngs_url.replace("{n}",rn)
          +  tiles_version +"/"+ procesos_electorales[year] +"/"+ + tile.x +"_"+ tile.y +'_'+ zoom +".png";
       },
       tileSize: new google.maps.Size(256, 256),
       opacity:0.75,
       isPng: true,
       minZoom: 6,
       maxZoom: 12,
       name: "Political parties tiles",
       alt: ""
    });
    peninsula.overlayMapTypes.insertAt(1,political_parties);

    /*Adding infowindow(over map), comparewindow(over dom) and explanationwindow(over dom) */
    infowindow        = new InfoWindow(new google.maps.LatLng(0,0),peninsula);  //new google.maps.LatLng(0,0)
    comparewindow     = new CompareWindow();
    explanationwindow = new ExplanationWindow();

    peninsula.overlayMapTypes.setAt(2, new CoordMapType(new google.maps.Size(256, 256)));

    /* initialize search component */
    initializeSearch();

    //TODO - Review this listeners (old computers dont render ok with this stuff)
    google.maps.event.addListenerOnce(peninsula, 'tilesloaded', function() {
      changeHash();
      checkZoom();

      google.maps.event.addListener(this,'dragend',function(){changeHash();});
      google.maps.event.addListener(this,'zoom_changed',function(){changeHash(); checkZoom();});
    });

    /*Go to canary islands*/
    $('a.islas_canarias').live('click',function(ev){
      ev.stopPropagation();
      ev.preventDefault();
      peninsula.setCenter(canary_center);
      peninsula.setZoom(7);
      changeHash();
    });

    $('a.peninsula').live('click',function(ev){
      ev.stopPropagation();
      ev.preventDefault();
      peninsula.setCenter(peninsula_center);
      peninsula.setZoom(6);
      changeHash();
    });

    /*zoom controls*/
    $('a.zoom_in').click(function(ev){
      ev.stopPropagation();
      ev.preventDefault();
      var zoom = peninsula.getZoom();
      peninsula.setZoom(zoom + 1);
    });
    $('a.zoom_out').click(function(ev){
      ev.stopPropagation();
      ev.preventDefault();
      var zoom = peninsula.getZoom();
      peninsula.setZoom(zoom - 1);
    });

    /*zoom slider*/
		$("span.slider").slider({orientation: "vertical",range: "min",min: 6,max: 10,value: 6,step: 1,
			stop: function( event, ui ) {
        if (ui.value==10) {
          peninsula.setZoom(12);
        } else if (ui.value==9) {
          peninsula.setZoom(11);
        } else {
          peninsula.setZoom(ui.value);
        }
        checkZoom();
			}
		});

		/*Click bubbles*/
		$(document).click(function(event){
		  var target = event.target || event.srcElement;
      var targetElement = target.nodeName.toLowerCase();

      //Clicking in first column element + Key
      if ($(target).closest('div.bubble').length>0) {
        if (!dragging) {
          var occ_id = $(target).closest('div.bubble').attr('id');
          var tile_id = $(target).closest('div.bubble').parent().attr('id');  // closest('div.tile') doesnt work in ie7 :|

          var point = hash[tile_id][occ_id];
          var height = ($(target).closest('div.bubble').height() / 2) - 5;
          var latlng = new google.maps.LatLng(point.center_latitude,point.center_longitude);
          infowindow.setPosition(latlng,height,point);
        }

        if (event.preventDefault) {
          event.preventDefault();
          event.stopPropagation();
        } else {
          event.stopPropagation();
          event.returnValue = false;
        }
      }
		});

  }

  var tileOverlayHolder = [];
  function refreshTiles() {
    // nuke old overlay tiles that may not have been removed yet due to network speed
    _.each(tileOverlayHolder, function(ele,i){
      $(ele).remove();
      delete tileOverlayHolder[i];
    });
    tileOverlayHolder = _.compact(tileOverlayHolder)

    $('div#peninsula div').each(function(i,ele){
      if ($(ele).css('opacity')>0 && $(ele).css('opacity')<1 && $(ele).children('img').length>0) {

        //work out old and new urls
        var old_image = $(ele).children('img');
        var old_url = old_image.attr('src');
        var tm = old_url.split("/");
        var old_process = tm[tm.length-2];
        var new_url = old_url.replace('/'+old_process+'/','/'+procesos_electorales[year]+'/');

        // only add if new URL is different from old one
        if (new_url != old_url){

          // duplicate tile and add to div above current tile
          var new_image = old_image.clone();
          var zindex    = old_image.css('z-index') + 1
          new_image.css({'position':'absolute', 'z-index':zindex, 'top':0, 'left':0});
          tileOverlayHolder.push(new_image);
          $(ele).prepend(new_image);

          // update new tile with new url
          old_image.attr('src',new_url);

          // when it loads the new image, fade out the old one
          old_image.unbind("load");
          old_image.one("load",function(){
            new_image.animate({opacity:0},{ duration: 800, queue: false ,complete: function() {
                $(new_image).remove();
              }
            });
          });
          if(old_image.complete) $(this).trigger("load");
        }
      }
    });
  }

  var loaded = false;
  function checkZoom(){
    //close infowindow
    infowindow.hide();

    //Jump hack
    if (peninsula.getZoom()==10 && previous_zoom<peninsula.getZoom()) {
      peninsula.setZoom(11);
      $("span.slider").slider({value: 9});
    } else if (peninsula.getZoom()==10 && previous_zoom>peninsula.getZoom()) {
      peninsula.setZoom(8);
      $("span.slider").slider({value: 8});
    } else if (peninsula.getZoom()==12) {
      $("span.slider").slider({value: 10});
    } else if (peninsula.getZoom()==11) {
      $("span.slider").slider({value: 9});
    } else if (peninsula.getZoom()==9 && previous_zoom<peninsula.getZoom()) {
        peninsula.setZoom(11);
        $("span.slider").slider({value: 9});
    } else if (peninsula.getZoom()==9 && previous_zoom>peninsula.getZoom()) {
        peninsula.setZoom(8);
        $("span.slider").slider({value: 8});
    } else {
      $("span.slider").slider({value: peninsula.getZoom()});
    }
    previous_zoom = peninsula.getZoom();
    drawNoDataBars();

    if (loaded) {
      failCircle.reset();
    } else {
      loaded = true;
    }
  }
<commit_msg>removed fusion<commit_after>

  var canary_island,peninsula;  // Maps
  var start_center = new google.maps.LatLng(39.67660002390679,-3.6563984375000036); // Maps center position
  var start_zoom = 6;
  var previous_zoom = 6;  // Hack for jump 10 zoom
  var canary_center = new google.maps.LatLng(28.3660940558243,-15.631496093750004);
  var peninsula_center = new google.maps.LatLng(39.67660002390679,-3.6563984375000036);
  var projection = new MercatorProjection();
  var infowindow,comparewindow;
  var dragging = false;
  var baseUrl="http://chart.apis.google.com/chart?chs=256x256";
  var chco = "6B6A6ADF|65432100";
  var chf = "bg,s,65432100";
  var chld = "ES";
  var chd = "";
  var political_parties;
  var custom_map_style = [{featureType:"administrative.country",elementType:"all",stylers:[{saturation:-100},{visibility:"off"}]},{featureType:"administrative.province",elementType:"all",stylers:[{visibility:"off"}]},{featureType:"administrative.locality",elementType:"all",stylers:[{visibility:"off"}]},{featureType:"road.arterial",elementType:"all",stylers:[{visibility:"off"}]},{featureType:"all",elementType:"labels",stylers:[{visibility:"off"}]},{featureType:"all",elementType:"all",stylers:[{lightness:7},{saturation:-91}]},{featureType:"all",elementType:"all",stylers:[]}];

  function initializeMap() {

    var peninsula_ops = {zoom: start_zoom,center: start_center,disableDefaultUI: true,mapTypeId: google.maps.MapTypeId.ROADMAP,scrollwheel: false, minZoom: 6,maxZoom: 12, mapTypeControlOptions: {mapTypeIds: [google.maps.MapTypeId.ROADMAP, 'rtve']}};

    peninsula = new google.maps.Map(document.getElementById("peninsula"),peninsula_ops);

    //Custom styled map - custom_map_style
    var styledMapOptions = {name: "rtve"};
    var rtveMapType = new google.maps.StyledMapType(custom_map_style, styledMapOptions);
    peninsula.mapTypes.set('rtve', rtveMapType);
    peninsula.setMapTypeId('rtve');

    var mapChartOptions = {
        getTileUrl: function(coord, zoom) {
            var lULP = new google.maps.Point(coord.x*256,(coord.y+1)*256);
            var lLRP = new google.maps.Point((coord.x+1)*256,coord.y*256);
            var projectionMap = new MercatorProjection();
            var lULg = projectionMap.fromDivPixelToLatLng(lULP, zoom);
            var lLRg = projectionMap.fromDivPixelToLatLng(lLRP, zoom);
            return baseUrl+"&chd="+chd+"&chco="+chco+"&chld="+chld+"&chf="+chf+"&cht=map:fixed="+
               lULg.lat() +","+ lULg.lng() + "," + lLRg.lat() + "," + lLRg.lng();
        },
        tileSize: new google.maps.Size(256, 256),
        isPng: true,
        minZoom: 6,
        maxZoom: 12,
        name: "Hide rest of countries"
    };
    var mapChartType = new google.maps.ImageMapType(mapChartOptions);
    peninsula.overlayMapTypes.insertAt(0, mapChartType);

    //Political tiles
    political_parties = new google.maps.ImageMapType({
       getTileUrl: function(tile, zoom) {
         var rn=Math.ceil(Math.random()*4);
         return tiles_pngs_url.replace("{n}",rn)
          +  tiles_version +"/"+ procesos_electorales[year] +"/"+ + tile.x +"_"+ tile.y +'_'+ zoom +".png";
       },
       tileSize: new google.maps.Size(256, 256),
       opacity:0.75,
       isPng: true,
       minZoom: 6,
       maxZoom: 12,
       name: "Political parties tiles",
       alt: ""
    });
    peninsula.overlayMapTypes.insertAt(1,political_parties);

    /*Adding infowindow(over map), comparewindow(over dom) and explanationwindow(over dom) */
    infowindow        = new InfoWindow(new google.maps.LatLng(0,0),peninsula);  //new google.maps.LatLng(0,0)
    comparewindow     = new CompareWindow();
    explanationwindow = new ExplanationWindow();

    peninsula.overlayMapTypes.setAt(2, new CoordMapType(new google.maps.Size(256, 256)));

    /* initialize search component */
    initializeSearch();

    //TODO - Review this listeners (old computers dont render ok with this stuff)
    google.maps.event.addListenerOnce(peninsula, 'tilesloaded', function() {
      changeHash();
      checkZoom();

      google.maps.event.addListener(this,'dragend',function(){changeHash();});
      google.maps.event.addListener(this,'zoom_changed',function(){changeHash(); checkZoom();});
    });

    /*Go to canary islands*/
    $('a.islas_canarias').live('click',function(ev){
      ev.stopPropagation();
      ev.preventDefault();
      peninsula.setCenter(canary_center);
      peninsula.setZoom(7);
      changeHash();
    });

    $('a.peninsula').live('click',function(ev){
      ev.stopPropagation();
      ev.preventDefault();
      peninsula.setCenter(peninsula_center);
      peninsula.setZoom(6);
      changeHash();
    });

    /*zoom controls*/
    $('a.zoom_in').click(function(ev){
      ev.stopPropagation();
      ev.preventDefault();
      var zoom = peninsula.getZoom();
      peninsula.setZoom(zoom + 1);
    });
    $('a.zoom_out').click(function(ev){
      ev.stopPropagation();
      ev.preventDefault();
      var zoom = peninsula.getZoom();
      peninsula.setZoom(zoom - 1);
    });

    /*zoom slider*/
		$("span.slider").slider({orientation: "vertical",range: "min",min: 6,max: 10,value: 6,step: 1,
			stop: function( event, ui ) {
        if (ui.value==10) {
          peninsula.setZoom(12);
        } else if (ui.value==9) {
          peninsula.setZoom(11);
        } else {
          peninsula.setZoom(ui.value);
        }
        checkZoom();
			}
		});

		/*Click bubbles*/
		$(document).click(function(event){
		  var target = event.target || event.srcElement;
      var targetElement = target.nodeName.toLowerCase();

      //Clicking in first column element + Key
      if ($(target).closest('div.bubble').length>0) {
        if (!dragging) {
          var occ_id = $(target).closest('div.bubble').attr('id');
          var tile_id = $(target).closest('div.bubble').parent().attr('id');  // closest('div.tile') doesnt work in ie7 :|

          var point = hash[tile_id][occ_id];
          var height = ($(target).closest('div.bubble').height() / 2) - 5;
          var latlng = new google.maps.LatLng(point.center_latitude,point.center_longitude);
          infowindow.setPosition(latlng,height,point);
        }

        if (event.preventDefault) {
          event.preventDefault();
          event.stopPropagation();
        } else {
          event.stopPropagation();
          event.returnValue = false;
        }
      }
		});

  }

  var tileOverlayHolder = [];
  function refreshTiles() {
    simpleRefreshTiles();
    // // nuke old overlay tiles that may not have been removed yet due to network speed
    // _.each(tileOverlayHolder, function(ele,i){
    //   $(ele).remove();
    //   delete tileOverlayHolder[i];
    // });
    // tileOverlayHolder = _.compact(tileOverlayHolder)
    //
    //
    // $('div#peninsula div').each(function(i,ele){
    //   if ($(ele).css('opacity')>0 && $(ele).css('opacity')<1 && $(ele).children('img').length>0) {
    //
    //     //work out old and new urls
    //     var old_image = $(ele).children('img');
    //     var old_url = old_image.attr('src');
    //     var tm = old_url.split("/");
    //     var old_process = tm[tm.length-2];
    //     var new_url = old_url.replace('/'+old_process+'/','/'+procesos_electorales[year]+'/');
    //
    //     // only add if new URL is different from old one
    //     if (new_url != old_url){
    //
    //       // duplicate tile and add to div above current tile
    //       var new_image = old_image.clone();
    //       var zindex    = old_image.css('z-index') + 1
    //       new_image.css({'position':'absolute', 'z-index':zindex, 'top':0, 'left':0});
    //       tileOverlayHolder.push(new_image);
    //       $(ele).prepend(new_image);
    //
    //       // update new tile with new url
    //       old_image.attr('src',new_url);
    //
    //       // when it loads the new image, fade out the old one
    //       old_image.unbind("load");
    //       old_image.one("load",function(){
    //         new_image.animate({opacity:0},{ duration: 800, queue: false ,complete: function() {
    //             $(new_image).remove();
    //           }
    //         });
    //       });
    //       if(old_image.complete) $(this).trigger("load");
    //     }
    //   }
    // });
  }

  function simpleRefreshTiles() {
    $('div#peninsula div').each(function(i,ele){
      if ($(ele).css('opacity')>0 && $(ele).css('opacity')<1) {
        var old_image = $(ele).children('img');
        var old_url = old_image.attr('src');
        var tm = old_url.split("/");
        var old_process = tm[tm.length-2];
        var new_url = old_url.replace('/'+old_process+'/','/'+procesos_electorales[year]+'/');
        old_image.attr('src',new_url);
      }
    });
  }

  var loaded = false;
  function checkZoom(){
    //close infowindow
    infowindow.hide();

    //Jump hack
    if (peninsula.getZoom()==10 && previous_zoom<peninsula.getZoom()) {
      peninsula.setZoom(11);
      $("span.slider").slider({value: 9});
    } else if (peninsula.getZoom()==10 && previous_zoom>peninsula.getZoom()) {
      peninsula.setZoom(8);
      $("span.slider").slider({value: 8});
    } else if (peninsula.getZoom()==12) {
      $("span.slider").slider({value: 10});
    } else if (peninsula.getZoom()==11) {
      $("span.slider").slider({value: 9});
    } else if (peninsula.getZoom()==9 && previous_zoom<peninsula.getZoom()) {
        peninsula.setZoom(11);
        $("span.slider").slider({value: 9});
    } else if (peninsula.getZoom()==9 && previous_zoom>peninsula.getZoom()) {
        peninsula.setZoom(8);
        $("span.slider").slider({value: 8});
    } else {
      $("span.slider").slider({value: peninsula.getZoom()});
    }
    previous_zoom = peninsula.getZoom();
    drawNoDataBars();

    if (loaded) {
      failCircle.reset();
    } else {
      loaded = true;
    }
  }
<|endoftext|>


<commit_before>import PropTypes from 'prop-types'
import React, { Component } from 'react'
import {
  Button,
  ButtonToolbar,
  ControlLabel,
  FormControl,
  FormGroup,
  Glyphicon,
  HelpBlock,
  Modal,
  ToggleButton,
  ToggleButtonGroup
} from 'react-bootstrap'
import styled from 'styled-components'

const allowedNotificationChannels = [
  {
    type: 'email',
    text: 'Email'
  },
  {
    type: 'sms',
    text: 'SMS'
  },
  {
    type: 'none',
    text: 'Don\'t notify me'
  }
]

// Styles
// HACK: Preverve container height.
const Details = styled.div`
  min-height: 150px;
  margin-bottom: 15px;
`
const ButtonStrip = styled.div`
  > * {
    margin-right: 4px;
  }
`

/**
 * User notification preferences pane.
 */
class NotificationPrefsPane extends Component {
  static propTypes = {
    onRequestPhoneVerificationCode: PropTypes.func,
    onSendPhoneVerificationCode: PropTypes.func,
    onUserDataChange: PropTypes.func.isRequired,
    userData: PropTypes.object.isRequired
  }

  constructor (props) {
    super(props)

    this.state = {
      // Holds the initial phone number or the last confirmed phone number
      initialPhoneNumber: props.userData.phoneNumber,
      // Set to true when the field is changed, to display validation errors subsequently.
      isPhoneFieldModified: false,
      // If true, a phone verification request has been sent and the UI is awaiting the user sending the code.
      isVerificationPending: false,
      // Holds the validation code.
      phoneValidationCode: ''
    }
  }

  _handleNotificationChannelChange = e => {
    const { onUserDataChange } = this.props
    onUserDataChange({ notificationChannel: e })
  }

  _handlePhoneNumberChange = e => {
    const { onUserDataChange } = this.props
    onUserDataChange({ phoneNumber: e.target.value })

    // Mark field as modified.
    this.setState({
      isPhoneFieldModified: true
    })
  }

  _handlePhoneValidationCodeChange = e => {
    // Update validation code state.
    this.setState({
      phoneValidationCode: e.target.value
    })
  }

  _handlePhoneValidationCancel = () => {
    // Exit the phone verification process.
    this.setState({
      isVerificationPending: false,
      phoneValidationCode: ''
    })
  }

  _handleRevertPhoneNumber = () => {
    // Revert entered phone number to the one from the user record.
    // Reset the modified and pending states.
    this.setState({
      isPhoneFieldModified: false,
      isVerificationPending: false
    })

    const { onRevertUserPhoneNumber } = this.props
    if (onRevertUserPhoneNumber) {
      onRevertUserPhoneNumber(this.state.userData)
    }
  }

  _handleRequestPhoneVerificationCode = () => {
    // Send phone verification request.
    this.props.onRequestPhoneVerificationCode()

    // Prompt for code.
    this.setState({
      isVerificationPending: true,
      phoneValidationCode: ''
    })
  }

  _handleSendPhoneVerificationCode = async () => {
    await this.props.onSendPhoneVerificationCode(this.state.phoneValidationCode)

    // Exit verification modal and update "initialPhoneNumber" if isPhoneNumberVerified was changed to true.
    // Erase the verification code in all cases.
    if (this.props.userData.isPhoneNumberVerified) {
      this.setState({
        initialPhoneNumber: this.props.userData.phoneNumber,
        isVerificationPending: false,
        phoneValidationCode: ''
      })
    } else {
      this.setState({
        phoneValidationCode: ''
      })
    }
  }

  render () {
    const { userData } = this.props
    const {
      initialPhoneNumber,
      isPhoneFieldModified,
      isVerificationPending,
      phoneValidationCode
    } = this.state
    const {
      email,
      isPhoneNumberVerified,
      notificationChannel,
      phoneNumber
    } = userData

    // Here are the states we are dealing with:
    // - First time entering a phone number (phoneNumber blank, not modified)
    //   => no color, no feedback indication.
    // - Typing backspace all the way to erase a number (phoneNumber blank, modified)
    //   => red, "[X] Please provide a number" indication.
    // - Viewing a verified phone number (phoneNumber non-blank, same as initial, verified)
    //   => green, "[V] Verified" indication.
    // - Editing a phone number (phoneNumber non-blank, different than initial or not verified)
    //   => red, "[X] Verification required" indication.

    const isPhoneNumberBlank = !(phoneNumber && phoneNumber.length)
    const isPhoneNumberSameAsInitial = phoneNumber === initialPhoneNumber

    let phoneStatusGlyph // one of the Bootstrap glyphs.
    let phoneStatusText
    let phoneFieldValidationState // one of the Bootstrap validationState values.
    let shouldVerifyPhone = false

    if (isPhoneNumberBlank) {
      if (!isPhoneFieldModified) {
        // Do not show an indication.
      } else {
        phoneStatusGlyph = 'remove'
        phoneStatusText = 'Please provide a number'
        phoneFieldValidationState = 'error'
      }
    } else if (isPhoneNumberSameAsInitial && isPhoneNumberVerified) {
      phoneStatusGlyph = 'ok'
      phoneStatusText = 'Verified'
      phoneFieldValidationState = 'success'
    } else {
      phoneStatusGlyph = 'warning-sign'
      phoneStatusText = 'Verification required'
      phoneFieldValidationState = 'warning'
      shouldVerifyPhone = true
    }

    return (

          You can receive notifications about trips you frequently take.

        <FormGroup>
          <ControlLabel>How would you like to receive notifications?</ControlLabel>
          <ButtonToolbar>
            <ToggleButtonGroup
              name='notificationChannels'
              onChange={this._handleNotificationChannelChange}
              type='radio'
              value={notificationChannel}
            >
              {allowedNotificationChannels.map(({ type, text }, index) => (
                <ToggleButton
                  bsStyle={notificationChannel === type ? 'primary' : 'default'}
                  key={index}
                  value={type}
                >
                  {text}
                </ToggleButton>
              ))}
            </ToggleButtonGroup>
          </ButtonToolbar>
        </FormGroup>

          {notificationChannel === 'email' && (
            <FormGroup>
              <ControlLabel>Notification emails will be sent out to:</ControlLabel>
              <FormControl disabled type='text' value={email} />
            </FormGroup>
          )}
          {notificationChannel === 'sms' && (

              <FormGroup validationState={phoneFieldValidationState}>
                <ControlLabel>Enter your phone number for SMS notifications:</ControlLabel>
                {/* TODO: Add field validation. */}

                <FormControl
                  onChange={this._handlePhoneNumberChange}
                  placeholder='+15555550123'
                  type='tel'
                  value={phoneNumber}
                />
                {/* Show glyphs underneath the input control with <HelpBlock>
                   (there are some alignment issues with <FormControl.Feedback /> in mobile view). */}
                <HelpBlock>
                  {phoneStatusGlyph && <Glyphicon glyph={phoneStatusGlyph} />} {phoneStatusText}
                </HelpBlock>
              </FormGroup>

              {shouldVerifyPhone && (
                <ButtonStrip>
                  <Button bsStyle='primary' onClick={this._handleRequestPhoneVerificationCode}>Verify my phone</Button>
                  <Button onClick={this._handleRevertPhoneNumber}>Revert number</Button>
                </ButtonStrip>
              )}

          )}

        {/* The dialog prompt for validation code. */}
        <Modal show={isVerificationPending}>
          <Modal.Header>
            <Modal.Title>Enter verification code</Modal.Title>
          </Modal.Header>

          <Modal.Body>

              Please check the SMS messaging app on your mobile phone
              for a text message with a verification code, and enter the code below.

            <FormGroup>
              <ControlLabel>Verification code:</ControlLabel>
              <FormControl onChange={this._handlePhoneValidationCodeChange} value={phoneValidationCode} />
            </FormGroup>

              <Button bsStyle='link' onClick={this._handleRequestPhoneVerificationCode}>Request a new code</Button>

          </Modal.Body>

          <Modal.Footer>
            <Button onClick={this._handlePhoneValidationCancel}>Cancel</Button>
            <Button bsStyle='primary' onClick={this._handleSendPhoneVerificationCode}>Verify my phone</Button>
          </Modal.Footer>
        </Modal>

    )
  }
}

export default NotificationPrefsPane
<commit_msg>docs(NotificationPrefsPane): Add comment+link regarding the fake phone number placeholder.<commit_after>import PropTypes from 'prop-types'
import React, { Component } from 'react'
import {
  Button,
  ButtonToolbar,
  ControlLabel,
  FormControl,
  FormGroup,
  Glyphicon,
  HelpBlock,
  Modal,
  ToggleButton,
  ToggleButtonGroup
} from 'react-bootstrap'
import styled from 'styled-components'

const allowedNotificationChannels = [
  {
    type: 'email',
    text: 'Email'
  },
  {
    type: 'sms',
    text: 'SMS'
  },
  {
    type: 'none',
    text: 'Don\'t notify me'
  }
]

// Styles
// HACK: Preverve container height.
const Details = styled.div`
  min-height: 150px;
  margin-bottom: 15px;
`
const ButtonStrip = styled.div`
  > * {
    margin-right: 4px;
  }
`

/**
 * User notification preferences pane.
 */
class NotificationPrefsPane extends Component {
  static propTypes = {
    onRequestPhoneVerificationCode: PropTypes.func,
    onSendPhoneVerificationCode: PropTypes.func,
    onUserDataChange: PropTypes.func.isRequired,
    userData: PropTypes.object.isRequired
  }

  constructor (props) {
    super(props)

    this.state = {
      // Holds the initial phone number or the last confirmed phone number
      initialPhoneNumber: props.userData.phoneNumber,
      // Set to true when the field is changed, to display validation errors subsequently.
      isPhoneFieldModified: false,
      // If true, a phone verification request has been sent and the UI is awaiting the user sending the code.
      isVerificationPending: false,
      // Holds the validation code.
      phoneValidationCode: ''
    }
  }

  _handleNotificationChannelChange = e => {
    const { onUserDataChange } = this.props
    onUserDataChange({ notificationChannel: e })
  }

  _handlePhoneNumberChange = e => {
    const { onUserDataChange } = this.props
    onUserDataChange({ phoneNumber: e.target.value })

    // Mark field as modified.
    this.setState({
      isPhoneFieldModified: true
    })
  }

  _handlePhoneValidationCodeChange = e => {
    // Update validation code state.
    this.setState({
      phoneValidationCode: e.target.value
    })
  }

  _handlePhoneValidationCancel = () => {
    // Exit the phone verification process.
    this.setState({
      isVerificationPending: false,
      phoneValidationCode: ''
    })
  }

  _handleRevertPhoneNumber = () => {
    // Revert entered phone number to the one from the user record.
    // Reset the modified and pending states.
    this.setState({
      isPhoneFieldModified: false,
      isVerificationPending: false
    })

    const { onRevertUserPhoneNumber } = this.props
    if (onRevertUserPhoneNumber) {
      onRevertUserPhoneNumber(this.state.userData)
    }
  }

  _handleRequestPhoneVerificationCode = () => {
    // Send phone verification request.
    this.props.onRequestPhoneVerificationCode()

    // Prompt for code.
    this.setState({
      isVerificationPending: true,
      phoneValidationCode: ''
    })
  }

  _handleSendPhoneVerificationCode = async () => {
    await this.props.onSendPhoneVerificationCode(this.state.phoneValidationCode)

    // Exit verification modal and update "initialPhoneNumber" if isPhoneNumberVerified was changed to true.
    // Erase the verification code in all cases.
    if (this.props.userData.isPhoneNumberVerified) {
      this.setState({
        initialPhoneNumber: this.props.userData.phoneNumber,
        isVerificationPending: false,
        phoneValidationCode: ''
      })
    } else {
      this.setState({
        phoneValidationCode: ''
      })
    }
  }

  render () {
    const { userData } = this.props
    const {
      initialPhoneNumber,
      isPhoneFieldModified,
      isVerificationPending,
      phoneValidationCode
    } = this.state
    const {
      email,
      isPhoneNumberVerified,
      notificationChannel,
      phoneNumber
    } = userData

    // Here are the states we are dealing with:
    // - First time entering a phone number (phoneNumber blank, not modified)
    //   => no color, no feedback indication.
    // - Typing backspace all the way to erase a number (phoneNumber blank, modified)
    //   => red, "[X] Please provide a number" indication.
    // - Viewing a verified phone number (phoneNumber non-blank, same as initial, verified)
    //   => green, "[V] Verified" indication.
    // - Editing a phone number (phoneNumber non-blank, different than initial or not verified)
    //   => red, "[X] Verification required" indication.

    const isPhoneNumberBlank = !(phoneNumber && phoneNumber.length)
    const isPhoneNumberSameAsInitial = phoneNumber === initialPhoneNumber

    let phoneStatusGlyph // one of the Bootstrap glyphs.
    let phoneStatusText
    let phoneFieldValidationState // one of the Bootstrap validationState values.
    let shouldVerifyPhone = false

    if (isPhoneNumberBlank) {
      if (!isPhoneFieldModified) {
        // Do not show an indication.
      } else {
        phoneStatusGlyph = 'remove'
        phoneStatusText = 'Please provide a number'
        phoneFieldValidationState = 'error'
      }
    } else if (isPhoneNumberSameAsInitial && isPhoneNumberVerified) {
      phoneStatusGlyph = 'ok'
      phoneStatusText = 'Verified'
      phoneFieldValidationState = 'success'
    } else {
      phoneStatusGlyph = 'warning-sign'
      phoneStatusText = 'Verification required'
      phoneFieldValidationState = 'warning'
      shouldVerifyPhone = true
    }

    return (

          You can receive notifications about trips you frequently take.

        <FormGroup>
          <ControlLabel>How would you like to receive notifications?</ControlLabel>
          <ButtonToolbar>
            <ToggleButtonGroup
              name='notificationChannels'
              onChange={this._handleNotificationChannelChange}
              type='radio'
              value={notificationChannel}
            >
              {allowedNotificationChannels.map(({ type, text }, index) => (
                <ToggleButton
                  bsStyle={notificationChannel === type ? 'primary' : 'default'}
                  key={index}
                  value={type}
                >
                  {text}
                </ToggleButton>
              ))}
            </ToggleButtonGroup>
          </ButtonToolbar>
        </FormGroup>

          {notificationChannel === 'email' && (
            <FormGroup>
              <ControlLabel>Notification emails will be sent out to:</ControlLabel>
              <FormControl disabled type='text' value={email} />
            </FormGroup>
          )}
          {notificationChannel === 'sms' && (

              <FormGroup validationState={phoneFieldValidationState}>
                <ControlLabel>Enter your phone number for SMS notifications:</ControlLabel>
                {/* TODO: Add field validation. */}

                <FormControl
                  onChange={this._handlePhoneNumberChange}
                  // Fake phone number, see https://en.wikipedia.org/wiki/555_(telephone_number)
                  placeholder='+15555550123'
                  type='tel'
                  value={phoneNumber}
                />
                {/* Show glyphs underneath the input control with <HelpBlock>
                   (there are some alignment issues with <FormControl.Feedback /> in mobile view). */}
                <HelpBlock>
                  {phoneStatusGlyph && <Glyphicon glyph={phoneStatusGlyph} />} {phoneStatusText}
                </HelpBlock>
              </FormGroup>

              {shouldVerifyPhone && (
                <ButtonStrip>
                  <Button bsStyle='primary' onClick={this._handleRequestPhoneVerificationCode}>Verify my phone</Button>
                  <Button onClick={this._handleRevertPhoneNumber}>Revert number</Button>
                </ButtonStrip>
              )}

          )}

        {/* The dialog prompt for validation code. */}
        <Modal show={isVerificationPending}>
          <Modal.Header>
            <Modal.Title>Enter verification code</Modal.Title>
          </Modal.Header>

          <Modal.Body>

              Please check the SMS messaging app on your mobile phone
              for a text message with a verification code, and enter the code below.

            <FormGroup>
              <ControlLabel>Verification code:</ControlLabel>
              <FormControl onChange={this._handlePhoneValidationCodeChange} value={phoneValidationCode} />
            </FormGroup>

              <Button bsStyle='link' onClick={this._handleRequestPhoneVerificationCode}>Request a new code</Button>

          </Modal.Body>

          <Modal.Footer>
            <Button onClick={this._handlePhoneValidationCancel}>Cancel</Button>
            <Button bsStyle='primary' onClick={this._handleSendPhoneVerificationCode}>Verify my phone</Button>
          </Modal.Footer>
        </Modal>

    )
  }
}

export default NotificationPrefsPane
<|endoftext|>


<commit_before>'use strict';

import React from 'react';
import ReactCSS from 'reactcss';

import MaterialStyleSidebar from './MaterialStyleSidebar';
import Breadcrumbs from '../common/Breadcrumbs';

export class MaterialStyle extends ReactCSS.Component {

  classes() {
    return {
      'default': {
        wrap: {
          display: 'flex',
          alignItems: 'stretch',
          Absolute: '0 0 0 0',
        },
        sidebar: {
          minWidth: '200px',
          maxWidth: '200px',
          background: '#fafafa',
        },
        content: {
          flex: '1',
        },
        divider: {
          margin: '0 15px',
          boxShadow: 'inset 0 -1px 0 #eee',
        },
      },
    };
  }

  render() {
    return (

          <MaterialStyleSidebar route={ this.props.route } />

            <Breadcrumbs route={ this.props.route } />

          Material Style

    );
  }
}

export default MaterialStyle;
<commit_msg>Text Padding<commit_after>'use strict';

import React from 'react';
import ReactCSS from 'reactcss';

import MaterialStyleSidebar from './MaterialStyleSidebar';
import Breadcrumbs from '../common/Breadcrumbs';

export class MaterialStyle extends ReactCSS.Component {

  classes() {
    return {
      'default': {
        wrap: {
          display: 'flex',
          alignItems: 'stretch',
          Absolute: '0 0 0 0',
        },
        sidebar: {
          minWidth: '200px',
          maxWidth: '200px',
          background: '#fafafa',
        },
        content: {
          flex: '1',
        },
        divider: {
          margin: '0 15px',
          boxShadow: 'inset 0 -1px 0 #eee',
        },
        body: {
          padding: '30px',
        },
      },
    };
  }

  render() {
    return (

          <MaterialStyleSidebar route={ this.props.route } />

            <Breadcrumbs route={ this.props.route } />

            Material Style

    );
  }
}

export default MaterialStyle;
<|endoftext|>