<commit_before>(function() {
    var m = angular.module('parkandride.directives.map', []);

    m.directive('polygon', function() {
        return {
            restrict: 'E',
            scope: {
                polygon: '=ngModel',
                editable: '='
            },
            template: '

',
            transclude: false,
            link: function(scope, element, attrs) {

                var view = new ol.View({
                    center: ol.proj.transform([24.941025, 60.173324], 'EPSG:4326', 'EPSG:3857'),
                    zoom: 12
                });

                var map = new ol.Map({
                    target: element.children()[0],
                    controls: ol.control.defaults().extend([
                        new ol.control.FullScreen()
                    ]),
                    layers: [
                        new ol.layer.Tile({
                            source: new ol.source.OSM()
                        })
                    ],
                    view: view
                });

                var featureOverlay = new ol.FeatureOverlay({
                    style: new ol.style.Style({
                        fill: new ol.style.Fill({
                            color: 'rgba(255, 255, 255, 0.5)'
                        }),
                        stroke: new ol.style.Stroke({
                            color: '#ffcc33',
                            width: 2
                        }),
                        image: new ol.style.Circle({
                            radius: 7,
                            fill: new ol.style.Fill({
                                color: '#ffcc33'
                            })
                        })
                    })
                });
                featureOverlay.setMap(map);

                if (attrs.editable == "true") {
                    var draw = new ol.interaction.Draw({
                        features: featureOverlay.getFeatures(),
                        type: "Polygon"
                    });
                    draw.on("drawstart", function(drawEvent) {
                        if (document.activeElement) {
                            document.activeElement.blur();
                        }
                        featureOverlay.getFeatures().clear();
                    });
                    draw.on("drawend", function(drawEvent) {
                        var polygon = drawEvent.feature.getGeometry().clone().transform('EPSG:3857', 'EPSG:4326');
                        scope.polygon = new ol.format.GeoJSON().writeGeometry(polygon);
                        scope.$apply();
                    });
                    map.addInteraction(draw);
                }

                if (scope.polygon) {
                    var polygon = new ol.format.GeoJSON().readGeometry(scope.polygon).transform('EPSG:4326', 'EPSG:3857');
                    var feature = new ol.Feature({});
                    feature.setGeometry(polygon);
                    featureOverlay.getFeatures().clear();
                    featureOverlay.addFeature(feature);

                    view.fitGeometry(
                        polygon,
                        map.getSize()
                    );
                }
            }
        };
    });

    m.directive('hubMap', function() {
        return {
            restrict: 'E',
            scope: {
                point: '=ngModel',
                editable: '=',
                findFeaturesFn: '&findFeaturesFn'
            },
            template: '

',
            transclude: false,
            link: function(scope, element, attrs) {

                var view = new ol.View({
                    center: ol.proj.transform([24.941025, 60.173324], 'EPSG:4326', 'EPSG:3857'),
                    zoom: 12
                });

                var map = new ol.Map({
                    target: element.children()[0],
                    controls: ol.control.defaults().extend([
                        new ol.control.FullScreen()
                    ]),
                    layers: [
                        new ol.layer.Tile({
                            source: new ol.source.OSM()
                        })
                    ],
                    view: view
                });

                var featureOverlay = new ol.FeatureOverlay({
                    style: new ol.style.Style({
                        fill: new ol.style.Fill({
                            color: 'rgba(255, 255, 255, 0.5)'
                        }),
                        stroke: new ol.style.Stroke({
                            color: '#ffcc33',
                            width: 2
                        }),
                        image: new ol.style.Circle({
                            radius: 7,
                            fill: new ol.style.Fill({
                                color: '#ffcc33'
                            })
                        })
                    })
                });
                featureOverlay.setMap(map);

                if (attrs.editable == "true") {
                    map.on('dblclick', function(event) {
                        var point = new ol.geom.Point(event.coordinate).transform('EPSG:3857', 'EPSG:4326');
                        scope.point = new ol.format.GeoJSON().writeGeometry(point);
                        scope.$apply();
                        setPoint(point);
                        return false;
                    });
                }

                if (scope.point) {
                    var point = new ol.format.GeoJSON().readGeometry(scope.point);
                    setPoint(point);
                }

                function setPoint(point) {
                    point.transform('EPSG:4326', 'EPSG:3857');
                    var feature = new ol.Feature({});
                    feature.setGeometry(point);
                    featureOverlay.getFeatures().clear();
                    featureOverlay.addFeature(feature);
                    view.setCenter(point.getCoordinates());
                    view.setZoom(14);
                }

                /*
                if (scope.findFeaturesFn) {
                    _.forEach(scope.findFeaturesFn(), function(f) {
                        featureOverlay.addFeature(f);
                    });
                }
                */
            }
        };
    });
})();<commit_msg>fix(map): setting point doesn't zoom nor center view<commit_after>(function() {
    var m = angular.module('parkandride.directives.map', []);

    m.directive('polygon', function() {
        return {
            restrict: 'E',
            scope: {
                polygon: '=ngModel',
                editable: '='
            },
            template: '

',
            transclude: false,
            link: function(scope, element, attrs) {

                var view = new ol.View({
                    center: ol.proj.transform([24.941025, 60.173324], 'EPSG:4326', 'EPSG:3857'),
                    zoom: 12
                });

                var map = new ol.Map({
                    target: element.children()[0],
                    controls: ol.control.defaults().extend([
                        new ol.control.FullScreen()
                    ]),
                    layers: [
                        new ol.layer.Tile({
                            source: new ol.source.OSM()
                        })
                    ],
                    view: view
                });

                var featureOverlay = new ol.FeatureOverlay({
                    style: new ol.style.Style({
                        fill: new ol.style.Fill({
                            color: 'rgba(255, 255, 255, 0.5)'
                        }),
                        stroke: new ol.style.Stroke({
                            color: '#ffcc33',
                            width: 2
                        }),
                        image: new ol.style.Circle({
                            radius: 7,
                            fill: new ol.style.Fill({
                                color: '#ffcc33'
                            })
                        })
                    })
                });
                featureOverlay.setMap(map);

                if (attrs.editable == "true") {
                    var draw = new ol.interaction.Draw({
                        features: featureOverlay.getFeatures(),
                        type: "Polygon"
                    });
                    draw.on("drawstart", function(drawEvent) {
                        if (document.activeElement) {
                            document.activeElement.blur();
                        }
                        featureOverlay.getFeatures().clear();
                    });
                    draw.on("drawend", function(drawEvent) {
                        var polygon = drawEvent.feature.getGeometry().clone().transform('EPSG:3857', 'EPSG:4326');
                        scope.polygon = new ol.format.GeoJSON().writeGeometry(polygon);
                        scope.$apply();
                    });
                    map.addInteraction(draw);
                }

                if (scope.polygon) {
                    var polygon = new ol.format.GeoJSON().readGeometry(scope.polygon).transform('EPSG:4326', 'EPSG:3857');
                    var feature = new ol.Feature({});
                    feature.setGeometry(polygon);
                    featureOverlay.getFeatures().clear();
                    featureOverlay.addFeature(feature);

                    view.fitGeometry(
                        polygon,
                        map.getSize()
                    );
                }
            }
        };
    });

    m.directive('hubMap', function() {
        return {
            restrict: 'E',
            scope: {
                point: '=ngModel',
                editable: '=',
                findFeaturesFn: '&findFeaturesFn'
            },
            template: '

',
            transclude: false,
            link: function(scope, element, attrs) {

                var view = new ol.View({
                    center: ol.proj.transform([24.941025, 60.173324], 'EPSG:4326', 'EPSG:3857'),
                    zoom: 12
                });

                var map = new ol.Map({
                    target: element.children()[0],
                    controls: ol.control.defaults().extend([
                        new ol.control.FullScreen()
                    ]),
                    layers: [
                        new ol.layer.Tile({
                            source: new ol.source.OSM()
                        })
                    ],
                    view: view
                });

                var featureOverlay = new ol.FeatureOverlay({
                    style: new ol.style.Style({
                        fill: new ol.style.Fill({
                            color: 'rgba(255, 255, 255, 0.5)'
                        }),
                        stroke: new ol.style.Stroke({
                            color: '#ffcc33',
                            width: 2
                        }),
                        image: new ol.style.Circle({
                            radius: 7,
                            fill: new ol.style.Fill({
                                color: '#ffcc33'
                            })
                        })
                    })
                });
                featureOverlay.setMap(map);

                if (attrs.editable == "true") {
                    map.on('dblclick', function(event) {
                        var point = new ol.geom.Point(event.coordinate).transform('EPSG:3857', 'EPSG:4326');
                        scope.point = new ol.format.GeoJSON().writeGeometry(point);
                        scope.$apply();
                        setPoint(point);
                        return false;
                    });
                }

                if (scope.point) {
                    var point = new ol.format.GeoJSON().readGeometry(scope.point);
                    setPoint(point);
                    view.setCenter(point.getCoordinates());
                    view.setZoom(14);
                }

                function setPoint(point) {
                    point.transform('EPSG:4326', 'EPSG:3857');
                    var feature = new ol.Feature({});
                    feature.setGeometry(point);
                    featureOverlay.getFeatures().clear();
                    featureOverlay.addFeature(feature);
                }

                /*
                if (scope.findFeaturesFn) {
                    _.forEach(scope.findFeaturesFn(), function(f) {
                        featureOverlay.addFeature(f);
                    });
                }
                */
            }
        };
    });
})();<|endoftext|>


<commit_before>'use strict';
/**
 * @file Retrieve contacts for the account
 */

var config = require('../../../config/configuration.js');
var mapper = require('../helpers/mapper.js');
var request = require('request');

/**
 * Use the Google refresh token to get a new accessToken,
 *
 * @param {String} refreshToken Refresh token issued by Google
 * @param {Function} cb First parameter is the error (if any), then the new accessToken (valid for one hour)
 */
var refreshAccessToken = function(refreshToken, cb) {

  // See https://developers.google.com/accounts/docs/OAuth2WebServer#refresh for details
  var params = {
    url: 'https://accounts.google.com/o/oauth2/token',
    form: {
      'refresh_token': refreshToken,
      'client_id': config.google_id,
      'client_secret': config.google_secret,
      'grant_type': 'refresh_token'
    },
    json: true
  };

  request.post(params, function (err, res) {
    if(err){
      return cb(err);
    }

    if(res.statusCode === 401){
      return cb(new Error("Access to this refresh_token has been revoked."));
    }

    cb(null, res.body.access_token);
  });
};

/**
 * Retrieve all contacts associated with this user account,
 *
 * @param {String} accessToken AccessToken to identify the account
 * @param {Date} since Retrieve contacts updated since this date
 * @param {Function} cb Callback. First parameter is the error (if any), then an array of all the contacts.
 */
var retrieveContacts = function(accessToken, since, cb) {

  // Pad n to have a length of width,
  // pad(1, 3) == 001
  var pad = function(n, width) {
    width = width || 2;
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(0) + n;
  };

  // Date, formatted as 2007-03-16T00:00:00
  var formattedDate = since.getFullYear() + '-' + pad(since.getMonth() + 1) + '-' + pad(since.getDate()) + 'T' + pad(since.getHours()) + ':' + pad(since.getMinutes()) + ':' + pad(since.getSeconds());

  // See https://developers.google.com/google-apps/contacts/v3/?csw=1#retrieving_contacts_using_query_parameters for details
  var params = {
    url: 'https://www.google.com/m8/feeds/contacts/default/full',
    qs: {
      alt: 'json',
      'max-results': 100000,
      'showdeleted': true,
      'orderby': 'lastmodified',
      'updated-min': formattedDate
    },
    headers: {
      'Authorization': 'OAuth ' + accessToken,
      'GData-Version': '3.0'
    },
    json: true
  };

  request.get(params, function (err, resp, body) {
    if(err) {
      return cb(err);
    }
    if(resp.statusCode === 401){
      return cb (new Error("Wrong Google Authorization provided."));
    }

    var contacts = body.feed.entry ? body.feed.entry.map(mapper):[];

    // Add google accessToken
    contacts.forEach(function(contact) {
      contact.accessToken = accessToken;
    });

    // Contacts is now full!
    cb(null, contacts);
  });
};

/**
 * Download all contacts from the specified Google Account.
 *
 * @param {String} refreshToken Refresh_token to identify the account
 * @param {Date} since Retrieve contacts updated since this date
 * @param {Function} cb Callback. First parameter is the error (if any), second an array of all the contacts.
 */
module.exports = function(refreshToken, since, cb) {
  refreshAccessToken(refreshToken, function(err, accessToken) {
    if(err) {
      cb(err);
    }

    retrieveContacts(accessToken, since, cb);
  });
};
<commit_msg>Improved error handling<commit_after>'use strict';
/**
 * @file Retrieve contacts for the account
 */

var config = require('../../../config/configuration.js');
var mapper = require('../helpers/mapper.js');
var request = require('request');

/**
 * Use the Google refresh token to get a new accessToken,
 *
 * @param {String} refreshToken Refresh token issued by Google
 * @param {Function} cb First parameter is the error (if any), then the new accessToken (valid for one hour)
 */
var refreshAccessToken = function(refreshToken, cb) {

  // See https://developers.google.com/accounts/docs/OAuth2WebServer#refresh for details
  var params = {
    url: 'https://accounts.google.com/o/oauth2/token',
    form: {
      'refresh_token': refreshToken,
      'client_id': config.google_id,
      'client_secret': config.google_secret,
      'grant_type': 'refresh_token'
    },
    json: true
  };

  request.post(params, function (err, res) {
    if(err){
      return cb(err);
    }

    if(res.statusCode === 401){
      return cb(new Error("Access to this refresh_token has been revoked."));
    }
    if(res.statusCode !== 200) {
      return cb(new Error("Google Error: " + res.body.message));
    }

    cb(null, res.body.access_token);
  });
};

/**
 * Retrieve all contacts associated with this user account,
 *
 * @param {String} accessToken AccessToken to identify the account
 * @param {Date} since Retrieve contacts updated since this date
 * @param {Function} cb Callback. First parameter is the error (if any), then an array of all the contacts.
 */
var retrieveContacts = function(accessToken, since, cb) {

  // Pad n to have a length of width,
  // pad(1, 3) == 001
  var pad = function(n, width) {
    width = width || 2;
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(0) + n;
  };

  // Date, formatted as 2007-03-16T00:00:00
  var formattedDate = since.getFullYear() + '-' + pad(since.getMonth() + 1) + '-' + pad(since.getDate()) + 'T' + pad(since.getHours()) + ':' + pad(since.getMinutes()) + ':' + pad(since.getSeconds());

  // See https://developers.google.com/google-apps/contacts/v3/?csw=1#retrieving_contacts_using_query_parameters for details
  var params = {
    url: 'https://www.google.com/m8/feeds/contacts/default/full',
    qs: {
      alt: 'json',
      'max-results': 100000,
      'showdeleted': true,
      'orderby': 'lastmodified',
      'updated-min': formattedDate
    },
    headers: {
      'Authorization': 'OAuth ' + accessToken,
      'GData-Version': '3.0'
    },
    json: true
  };

  request.get(params, function (err, resp, body) {
    if(err) {
      return cb(err);
    }
    if(resp.statusCode === 401){
      return cb (new Error("Wrong Google Authorization provided."));
    }

    var contacts = body.feed.entry ? body.feed.entry.map(mapper):[];

    // Add google accessToken
    contacts.forEach(function(contact) {
      contact.accessToken = accessToken;
    });

    // Contacts is now full!
    cb(null, contacts);
  });
};

/**
 * Download all contacts from the specified Google Account.
 *
 * @param {String} refreshToken Refresh_token to identify the account
 * @param {Date} since Retrieve contacts updated since this date
 * @param {Function} cb Callback. First parameter is the error (if any), second an array of all the contacts.
 */
module.exports = function(refreshToken, since, cb) {
  refreshAccessToken(refreshToken, function(err, accessToken) {
    if(err) {
      cb(err);
    }

    retrieveContacts(accessToken, since, cb);
  });
};
<|endoftext|>


<commit_before>"use strict";

var assert = require('assert');

var Game = function(goal) {

    var scoreBulls = function(guess, goal) {
	var bulls = 0;
	for (var i=0;i<guess.length;++i) {
	    if (guess[i] === goal[i])
		bulls++;
	}
	return bulls;
    };

    var scoreCows = function(guess, goal) {
	var cows = 0;
	for (var i=0;i<goal.length;++i) {
	    var desiredChar = goal[i];
	    for (var j=0;j<goal.length;++j) {
		if (j === i) continue;

		if (guess[j] === desiredChar) {
		    cows++;
		}
	    }
	}
	return cows;
    };

    this.score = function(guess) {
	assert(goal.length === guess.length, 'Lengths must be equivalent');

        return {
	    cows: scoreCows(guess,goal),
	    bulls: scoreBulls(guess,goal)
	};
    };

    var finishingScore = function(score) {
	return score.bulls === 4;
    };

    this.play = function(strategy) {
	var turns = 0;

	do {
	    turns++;
	    var guess = strategy.guess();
	    var score = this.score(guess);
	    strategy.update(score);
	} while (!finishingScore(score));

	return turns;
    };

    return this;
};

var asString = function(num) {
    var s = '0000' + num;
    return s.substr(s.length - 4);
};

var Player = function() {
    this.guess = function() {
	return asString(0);
    };

    return this;
};

var Naive = function() {

    this.currentGuess = 0;

    this.guess = function() {
	return asString(this.currentGuess);
    };

    this.update = function(guess, score) {
	this.currentGuess++;
    };

    return this;
};

var createGame = function(goal) {
    return new Game(goal);
};

describe("cows and bulls", function() {

    describe('playing naive', function() {
	it('should solve it within 9999 turns', function() {
	    var game = createGame('5555');
	    var turns = game.play(new Naive());

	    assert.equal(5556, turns);
	});
    });

    describe('intelligently playing', function() {

	var containsDuplicates = function(str) {
	    for (var i=0;i<str.length;++i) {
		var found = false;
		for (var j=0;j<str.length;++j) {
		    if (i === j) continue;

		    if (str[i] === str[j])
			return true;
		}
	    }
	    return false;
	};

	it('should have four unique numbers in initial guess', function() {
	    var player = new Player();

	    var initialGuess = player.guess();
	    assert(!containsDuplicates(initialGuess), 'no duplicates');
	});
    });

    describe('scoring', function() {
	it('should match the example', function() {
	    var game = createGame('8045');
	    var result = game.score('0865');

	    assert.equal(2, result.cows);
	    assert.equal(1, result.bulls);
	});

	it('no matches scores no cows or bulls', function() {
            var game = createGame('1234');

            var r = game.score('5678');
            assert.equal(0,r.cows);
	    assert.equal(0,r.bulls);
	});

	it('all correct is all bulls', function() {
	    var game = createGame('1234');

	    var r = game.score('1234');
	    assert.equal(4, r.bulls);
	    assert.equal(0, r.cows);
	});

	it('all in wrong order is all cows', function() {
	    var game = createGame('1234');

	    var r = game.score('4321');
	    assert.equal(4, r.cows);
	    assert.equal(0, r.bulls);
	});
    });
});
<commit_msg>minimum necessary pass<commit_after>"use strict";

var assert = require('assert');

var Game = function(goal) {

    var scoreBulls = function(guess, goal) {
	var bulls = 0;
	for (var i=0;i<guess.length;++i) {
	    if (guess[i] === goal[i])
		bulls++;
	}
	return bulls;
    };

    var scoreCows = function(guess, goal) {
	var cows = 0;
	for (var i=0;i<goal.length;++i) {
	    var desiredChar = goal[i];
	    for (var j=0;j<goal.length;++j) {
		if (j === i) continue;

		if (guess[j] === desiredChar) {
		    cows++;
		}
	    }
	}
	return cows;
    };

    this.score = function(guess) {
	assert(goal.length === guess.length, 'Lengths must be equivalent');

        return {
	    cows: scoreCows(guess,goal),
	    bulls: scoreBulls(guess,goal)
	};
    };

    var finishingScore = function(score) {
	return score.bulls === 4;
    };

    this.play = function(strategy) {
	var turns = 0;

	do {
	    turns++;
	    var guess = strategy.guess();
	    var score = this.score(guess);
	    strategy.update(score);
	} while (!finishingScore(score));

	return turns;
    };

    return this;
};

var asString = function(num) {
    var s = '0000' + num;
    return s.substr(s.length - 4);
};

var Player = function() {
    this.guess = function() {
	return asString(1234);
    };

    return this;
};

var Naive = function() {

    this.currentGuess = 0;

    this.guess = function() {
	return asString(this.currentGuess);
    };

    this.update = function(guess, score) {
	this.currentGuess++;
    };

    return this;
};

var createGame = function(goal) {
    return new Game(goal);
};

describe("cows and bulls", function() {

    describe('playing naive', function() {
	it('should solve it within 9999 turns', function() {
	    var game = createGame('5555');
	    var turns = game.play(new Naive());

	    assert.equal(5556, turns);
	});
    });

    describe('intelligently playing', function() {

	var containsDuplicates = function(str) {
	    for (var i=0;i<str.length;++i) {
		var found = false;
		for (var j=0;j<str.length;++j) {
		    if (i === j) continue;

		    if (str[i] === str[j])
			return true;
		}
	    }
	    return false;
	};

	it('should have four unique numbers in initial guess', function() {
	    var player = new Player();

	    var initialGuess = player.guess();
	    assert(!containsDuplicates(initialGuess), 'no duplicates');
	});
    });

    describe('scoring', function() {
	it('should match the example', function() {
	    var game = createGame('8045');
	    var result = game.score('0865');

	    assert.equal(2, result.cows);
	    assert.equal(1, result.bulls);
	});

	it('no matches scores no cows or bulls', function() {
            var game = createGame('1234');

            var r = game.score('5678');
            assert.equal(0,r.cows);
	    assert.equal(0,r.bulls);
	});

	it('all correct is all bulls', function() {
	    var game = createGame('1234');

	    var r = game.score('1234');
	    assert.equal(4, r.bulls);
	    assert.equal(0, r.cows);
	});

	it('all in wrong order is all cows', function() {
	    var game = createGame('1234');

	    var r = game.score('4321');
	    assert.equal(4, r.cows);
	    assert.equal(0, r.bulls);
	});
    });
});
<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep<commit_msg>Update character<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep <|endoftext|>


<commit_before>
var fs = require('fs');

var EXPORT_METHODS = ['dragStart', 'dragEnter', 'dragOver', 'dragLeave', 'drop', 'delay'];
var WEBDRIVER_ASYNC_EXEC_TIMEOUT = 2000;

var nextClientActionId = 1;

// using this ugly hack, since selenium seems to not pass arguments given to the execute() method
function webdriverExecuteAsync(self, script, parameters, callback) {
  var parameterAssignments = '';

  for (var paramName in parameters) {
    var paramValue = parameters[paramName];
    parameterAssignments += 'var ' + paramName + ' = ' + JSON.stringify(paramValue) + ';';
  }

  var scriptBody =
    parameterAssignments +
    'return (' +
    script +
    ')(done);';

  self.webdriver
    .timeoutsAsyncScript(WEBDRIVER_ASYNC_EXEC_TIMEOUT)
    .executeAsync(new Function('done', scriptBody), callback);
}

var DragMockClientActionBridge = function(webdriver, actionId) {
  this.webdriver = webdriver;
  this.actionId = actionId;
};

EXPORT_METHODS.forEach(function(methodName) {
  DragMockClientActionBridge.prototype[methodName] = function() {
    var self = this;

    var args = Array.prototype.slice.call(arguments);
    var callback = function () {};

    if (typeof args[args.length - 1] === 'function') {
      callback = args.pop();
    }

    var browserScript = function(done) {
      var stringStartsWith = function(string, prefix) {
        return string.indexOf(prefix) === 0;
      };

      // executed in browser context
      window._dragMockActions = window._dragMockActions || {};
      var action = window._dragMockActions[actionId] || dragMock;

      if (stringStartsWith(methodName, 'drag') || stringStartsWith(methodName, 'drop')) {
        // first argument is element selector
        args[0] = document.querySelector(args[0]);
      }
      action = action[methodName].apply(action, args);

      window._dragMockActions[actionId] = action;
      action.then(done);
    };

    var parameters = {
      methodName: methodName,
      actionId: self.actionId,
      args: args
    };

    webdriverExecuteAsync(self, browserScript, parameters, function(err) {
      // back in node.js context
      callback(err, self);
    });

    return self;
  };
});

function extendWebdriverPrototype(webdriverPrototype) {
  function createActionAndCallMethod(methodName) {
    return function() {
      var clientAction = new DragMockClientActionBridge(this, nextClientActionId++);

      clientAction[methodName].apply(clientAction, arguments);

      return clientAction;
    };
  }

  EXPORT_METHODS.forEach(function(methodName) {
    webdriverPrototype[methodName] = createActionAndCallMethod(methodName);
  });
}

function extendWebdriverFactory(webdriver) {
  var originalMethod = webdriver.remote;

  webdriver.remote = function() {
    var instance = originalMethod.apply(webdriver, arguments);

    extendWebdriverPrototype(instance.constructor.prototype);
    return instance;
  }
}

var webdriverBridge = {

  init: function(webdriver) {
    if (webdriver.version && webdriver.remote) {
      extendWebdriverFactory(webdriver);
    } else {
      extendWebdriverPrototype(webdriver.constructor.prototype);
    }
  },

  loadLibrary: function(webdriver, done) {
    var dragMockLib = fs.readFileSync(__dirname + '/../dist/drag-mock.js', { encoding: 'utf-8' });

    webdriver.execute(dragMockLib, function (error) {
      if (typeof done === 'function') { done(error); }
    });
  }

};

module.exports = webdriverBridge;
<commit_msg>Updated webdriverBridge.js<commit_after>
var fs = require('fs');

var EXPORT_METHODS = ['dragStart', 'dragEnter', 'dragOver', 'dragLeave', 'drop', 'delay'];
var WEBDRIVER_ASYNC_EXEC_TIMEOUT = 2000;

var nextClientActionId = 1;

// using this ugly hack, since selenium seems to not pass arguments given to the execute() method
function webdriverExecuteAsync(self, script, parameters, callback) {
  var parameterAssignments = '';

  for (var paramName in parameters) {
    var paramValue = parameters[paramName];
    parameterAssignments += 'var ' + paramName + ' = ' + JSON.stringify(paramValue) + ';';
  }

  var scriptBody =
    parameterAssignments +
    'return (' +
    script +
    ')(done);';

  self.webdriver
    .timeoutsAsyncScript(WEBDRIVER_ASYNC_EXEC_TIMEOUT)
    .executeAsync(new Function('done', scriptBody))
    .then(function(output) {
        callback(output)
    })
}

var DragMockClientActionBridge = function(webdriver, actionId) {
  this.webdriver = webdriver;
  this.actionId = actionId;
};

EXPORT_METHODS.forEach(function(methodName) {
  DragMockClientActionBridge.prototype[methodName] = function() {
    var self = this;

    var args = Array.prototype.slice.call(arguments);
    var callback = function () {};

    if (typeof args[args.length - 1] === 'function') {
      callback = args.pop();
    }

    var browserScript = function(done) {
      var stringStartsWith = function(string, prefix) {
        return string.indexOf(prefix) === 0;
      };

      // executed in browser context
      window._dragMockActions = window._dragMockActions || {};
      var action = window._dragMockActions[actionId] || dragMock;

      if (stringStartsWith(methodName, 'drag') || stringStartsWith(methodName, 'drop')) {
        // first argument is element selector
        args[0] = document.querySelector(args[0]);
      }
      action = action[methodName].apply(action, args);

      window._dragMockActions[actionId] = action;
      action.then(done);
    };

    var parameters = {
      methodName: methodName,
      actionId: self.actionId,
      args: args
    };

    webdriverExecuteAsync(self, browserScript, parameters, function(err) {
      // back in node.js context
      callback(err, self);
    });

    return self;
  };
});

function extendWebdriverPrototype(webdriverPrototype) {
  function createActionAndCallMethod(methodName) {
    return function() {
      var clientAction = new DragMockClientActionBridge(this, nextClientActionId++);

      clientAction[methodName].apply(clientAction, arguments);

      return clientAction;
    };
  }

  EXPORT_METHODS.forEach(function(methodName) {
    webdriverPrototype[methodName] = createActionAndCallMethod(methodName);
  });
}

function extendWebdriverFactory(webdriver) {
  var originalMethod = webdriver.remote;

  webdriver.remote = function() {
    var instance = originalMethod.apply(webdriver, arguments);

    extendWebdriverPrototype(instance.constructor.prototype);
    return instance;
  }
}

var webdriverBridge = {

  init: function(webdriver) {
    if (webdriver.version && webdriver.remote) {
      extendWebdriverFactory(webdriver);
    } else {
      extendWebdriverPrototype(webdriver.constructor.prototype);
    }
  },

  loadLibrary: function(webdriver, done) {
    var dragMockLib = fs.readFileSync(__dirname + '/../dist/drag-mock.js', { encoding: 'utf-8' });

    webdriver.execute(dragMockLib, function (error) {
      if (typeof done === 'function') { done(error); }
    });
  }

};

module.exports = webdriverBridge;
<|endoftext|>


<commit_before>(function() {
  var calendar = angular.module('calendar', ['ngRoute']);

})();
<commit_msg>Delete app.js<commit_after><|endoftext|>


<commit_before>/**
 * Settings datastore functions tests.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */

/**
 * WordPress dependencies
 */
import apiFetch from '@wordpress/api-fetch';
import { createRegistry } from '@wordpress/data';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import {
	muteConsole,
	subscribeUntil,
	unsubscribeFromAll,
} from 'tests/js/utils';
import { createSettingsStore } from './create-settings-store';

const SETTING = {
	slug: 'testSetting',
	action: 'setTestSetting',
	selector: 'getTestSetting',
	actionType: 'SET_TEST_SETTING',
};
const STORE_ARGS = [ 'core', 'site', 'settings' ];

describe( 'createSettingsStore store', () => {
	let apiFetchSpy;
	let dispatch;
	let registry;
	let select;
	let storeDefinition;
	let store;

	beforeAll( () => {
		API.setUsingCache( false );
	} );

	beforeEach( () => {
		registry = createRegistry();

		storeDefinition = createSettingsStore( ...STORE_ARGS, {
			settingSlugs: [ SETTING.slug ],
			registry,
		} );
		registry.registerStore( storeDefinition.STORE_NAME, storeDefinition );
		dispatch = registry.dispatch( storeDefinition.STORE_NAME );
		store = registry.stores[ storeDefinition.STORE_NAME ].store;
		select = registry.select( storeDefinition.STORE_NAME );

		apiFetchSpy = jest.spyOn( { apiFetch }, 'apiFetch' );
	} );

	afterAll( () => {
		API.setUsingCache( true );
	} );

	afterEach( () => {
		unsubscribeFromAll( registry );
		apiFetchSpy.mockRestore();
	} );

	describe( 'name', () => {
		it( 'returns the correct default store name', () => {
			expect( storeDefinition.STORE_NAME ).toEqual( `${ STORE_ARGS[ 0 ] }/${ STORE_ARGS[ 1 ] }` );
		} );
	} );

	describe( 'actions', () => {
		describe( 'setSettings', () => {
			it( 'requires the values param', () => {
				expect( () => {
					dispatch.setSettings();
				} ).toThrow( 'values is required.' );
			} );

			it( 'updates the respective settings', () => {
				const values1 = { setting1: 'old', setting2: 'old' };
				const values2 = { setting2: 'new' };

				dispatch.setSettings( values1 );
				expect( store.getState().settings ).toMatchObject( values1 );

				dispatch.setSettings( values2 );
				expect( store.getState().settings ).toMatchObject( { ...values1, ...values2 } );
			} );
		} );

		describe( 'fetchSettings', () => {
			it( 'does not require any params', () => {
				expect( () => {
					dispatch.fetchSettings();
				} ).not.toThrow();
			} );
		} );

		describe( 'receiveSettings', () => {
			it( 'requires the values param', () => {
				expect( () => {
					dispatch.receiveSettings();
				} ).toThrow( 'values is required.' );
			} );

			it( 'receives and sets values', () => {
				const serverValues = { setting1: 'serverside', setting2: 'serverside' };
				const clientValues = { setting1: 'clientside' };

				dispatch.setSettings( clientValues );
				dispatch.receiveSettings( serverValues );

				// Client values take precedence if they were already modified before receiving from the server.
				expect( store.getState().settings ).toMatchObject( { ...serverValues, ...clientValues } );
			} );
		} );

		describe( 'saveSettings', () => {
			it( 'does not require any params', () => {
				expect( async () => {
					fetch
						.doMockOnceIf(
							/^\/google-site-kit\/v1\/core\/site\/data\/settings/
						)
						.mockResponseOnce(
							JSON.stringify( { setting1: 'serverside' } ),
							{ status: 200 }
						);

					await dispatch.saveSettings();
				} ).not.toThrow();
			} );

			it( 'updates settings from server', async () => {
				const response = { setting1: 'serverside' };
				fetch
					.doMockIf(
						/^\/google-site-kit\/v1\/core\/site\/data\/settings/
					)
					.mockResponse(
						JSON.stringify( response ),
						{ status: 200 }
					);

				// The server is the authority. So because this won't be part of the response
				// (see above), it will be disregarded.
				dispatch.setSettings( { setting2: 'clientside' } );

				await dispatch.saveSettings();
				// Two fetch requests, one to get settings, the other to update.
				expect( fetch ).toHaveBeenCalledTimes( 2 );

				expect( store.getState().settings ).toMatchObject( response );
			} );
		} );

		describe( 'fetchSaveSettings', () => {
			it( 'requires the values param', () => {
				expect( () => {
					dispatch.receiveSaveSettings();
				} ).toThrow( 'values is required.' );
			} );

			it( 'sets isDoingSaveSettings', () => {
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/site\/data\/settings/
					)
					.mockResponseOnce(
						JSON.stringify( { setting1: true } ),
						{ status: 200 }
					);

				dispatch.fetchSaveSettings( {} );
				expect( select.isDoingSaveSettings() ).toEqual( true );
			} );
		} );

		describe( 'receiveSaveSettings', () => {
			it( 'requires the values param', () => {
				expect( () => {
					dispatch.receiveSaveSettings();
				} ).toThrow( 'values is required.' );
			} );

			it( 'receives and sets values', () => {
				const serverValues = { setting1: 'serverside', setting2: 'serverside' };
				const clientValues = { setting1: 'clientside', setting3: 'clientside' };

				dispatch.setSettings( clientValues );
				dispatch.receiveSaveSettings( serverValues );

				// Client values are ignored here, server values replace them.
				expect( store.getState().settings ).toMatchObject( { ...serverValues } );
			} );
		} );

		// Tests for "pseudo-action" setSetting, available via setting-specific "set{SettingSlug}".
		describe( 'setSetting', () => {
			it( 'has the correct action name', () => {
				expect( Object.keys( storeDefinition.actions ) ).toEqual(
					expect.arrayContaining( [ SETTING.action ] )
				);
			} );

			it( 'returns the correct action type', () => {
				const action = storeDefinition.actions[ SETTING.action ]( true );
				expect( action.type ).toEqual( SETTING.actionType );
			} );

			it( 'requires the value param', () => {
				expect( () => {
					dispatch[ SETTING.action ]();
				} ).toThrow( 'value is required.' );
			} );

			it( 'updates the respective setting', () => {
				const value = 'new';

				dispatch[ SETTING.action ]( value );
				expect( store.getState().settings ).toMatchObject( { [ SETTING.slug ]: value } );
			} );
		} );
	} );

	describe( 'selectors', () => {
		describe( 'getSettings', () => {
			it( 'uses a resolver to make a network request', async () => {
				const response = { setting1: 'value' };
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/site\/data\/settings/
					)
					.mockResponseOnce(
						JSON.stringify( response ),
						{ status: 200 }
					);

				const initialSettings = select.getSettings();
				// Settings will be their initial value while being fetched.
				expect( initialSettings ).toEqual( undefined );
				await subscribeUntil( registry,
					() => (
						select.getSettings() !== undefined
					),
				);

				const settings = select.getSettings();

				expect( fetch ).toHaveBeenCalledTimes( 1 );
				expect( settings ).toEqual( response );

				expect( fetch ).toHaveBeenCalledTimes( 1 );
				expect( select.getSettings() ).toEqual( settings );
			} );

			it( 'returns client settings even if server settings have not loaded', () => {
				const values = { setting1: 'value' };
				dispatch.setSettings( values );

				// If settings are set on the client, they must be available even
				// if settings have not been loaded from the server yet.
				muteConsole( 'error' ); // Ignore the API fetch failure here.
				expect( select.getSettings() ).toEqual( values );
			} );

			it( 'dispatches an error if the request fails', async () => {
				const response = {
					code: 'internal_server_error',
					message: 'Internal server error',
					data: { status: 500 },
				};
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/site\/data\/settings/
					)
					.mockResponseOnce(
						JSON.stringify( response ),
						{ status: 500 }
					);

				muteConsole( 'error' );
				select.getSettings();
				await subscribeUntil( registry,
					// TODO: We may want a selector for this, but for now this is fine
					// because it's internal-only.
					() => store.getState().isFetchingSettings === false,
				);

				const settings = select.getSettings();

				expect( fetch ).toHaveBeenCalledTimes( 1 );
				expect( settings ).toEqual( undefined );
			} );
		} );

		describe( 'haveSettingsChanged', () => {
			it( 'informs whether client-side settings differ from server-side ones', async () => {
				// Initially false.
				expect( select.haveSettingsChanged() ).toEqual( false );

				const serverValues = { setting1: 'serverside' };
				const clientValues = { setting1: 'clientside' };

				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/site\/data\/settings/
					)
					.mockResponseOnce(
						JSON.stringify( serverValues ),
						{ status: 200 }
					);

				select.getSettings();
				await subscribeUntil( registry,
					() => (
						select.getSettings() !== undefined
					),
				);

				// Still false after fetching settings from server.
				expect( select.haveSettingsChanged() ).toEqual( false );

				// True after updating settings on client.
				dispatch.setSettings( clientValues );
				expect( select.haveSettingsChanged() ).toEqual( true );

				// False after updating settings back to original server value on client.
				dispatch.setSettings( serverValues );
				expect( select.haveSettingsChanged() ).toEqual( false );
			} );
		} );

		// Tests for "pseudo-selector" getSetting, available via setting-specific "get{SettingSlug}".
		describe( 'getSetting', () => {
			it( 'has the correct selector name', () => {
				expect( Object.keys( storeDefinition.selectors ) ).toEqual(
					expect.arrayContaining( [ SETTING.selector ] )
				);
			} );

			it( 'uses a resolver to make a network request', async () => {
				const value = 'serverside';
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/site\/data\/settings/
					)
					.mockResponseOnce(
						JSON.stringify( {
							otherSetting: 'other-value',
							[ SETTING.slug ]: value,
						} ),
						{ status: 200 }
					);

				// Setting will have its initial value while being fetched.
				expect( select[ SETTING.selector ]() ).toEqual( undefined );
				await subscribeUntil( registry,
					() => (
						select.getSettings() !== undefined
					),
				);

				expect( fetch ).toHaveBeenCalledTimes( 1 );
				expect( select[ SETTING.selector ]() ).toEqual( value );
				expect( fetch ).toHaveBeenCalledTimes( 1 );
			} );
		} );
	} );

	describe( 'controls', () => {
		describe( 'FETCH_SETTINGS', () => {
			it( 'requests from the correct API endpoint', async () => {
				const [ type, identifier, datapoint ] = STORE_ARGS;
				const response = { type, identifier, datapoint };

				fetch
					.mockResponseOnce( async ( req ) => {
						if ( req.url.startsWith( `/google-site-kit/v1/${ type }/${ identifier }/data/${ datapoint }` ) ) {
							return Promise.resolve( {
								body: JSON.stringify( response ),
								init: { status: 200 },
							} );
						}
						return Promise.resolve( {
							body: JSON.stringify( {
								code: 'incorrect_api_endpoint',
								message: 'Incorrect API endpoint',
								data: { status: 400 },
							} ),
							init: { status: 400 },
						} );
					} );

				const result = await storeDefinition.controls.FETCH_SETTINGS();
				expect( result ).toEqual( response );
				// Ensure `console.error()` wasn't called, which will happen if the API
				// request fails.
				expect( global.console.error ).not.toHaveBeenCalled();
			} );
		} );

		describe( 'FETCH_SAVE_SETTINGS', () => {
			it( 'requests from the correct API endpoint', async () => {
				const [ type, identifier, datapoint ] = STORE_ARGS;
				const response = { type, identifier, datapoint };

				fetch
					.mockResponseOnce( async ( req ) => {
						if ( req.url.startsWith( `/google-site-kit/v1/${ type }/${ identifier }/data/${ datapoint }` ) ) {
							return Promise.resolve( {
								body: JSON.stringify( response ),
								init: { status: 200 },
							} );
						}
						return Promise.resolve( {
							body: JSON.stringify( {
								code: 'incorrect_api_endpoint',
								message: 'Incorrect API endpoint',
								data: { status: 400 },
							} ),
							init: { status: 400 },
						} );
					} );

				const result = await storeDefinition.controls.FETCH_SAVE_SETTINGS( {} );
				expect( result ).toEqual( response );
				// Ensure `console.error()` wasn't called, which will happen if the API
				// request fails.
				expect( global.console.error ).not.toHaveBeenCalled();
			} );
		} );
	} );
} );
<commit_msg>Hard-code specific setting slug, action, selector in test for code clarity.<commit_after>/**
 * Settings datastore functions tests.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */

/**
 * WordPress dependencies
 */
import apiFetch from '@wordpress/api-fetch';
import { createRegistry } from '@wordpress/data';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import {
	muteConsole,
	subscribeUntil,
	unsubscribeFromAll,
} from 'tests/js/utils';
import { createSettingsStore } from './create-settings-store';

const STORE_ARGS = [ 'core', 'site', 'settings' ];

describe( 'createSettingsStore store', () => {
	let apiFetchSpy;
	let dispatch;
	let registry;
	let select;
	let storeDefinition;
	let store;

	beforeAll( () => {
		API.setUsingCache( false );
	} );

	beforeEach( () => {
		registry = createRegistry();

		storeDefinition = createSettingsStore( ...STORE_ARGS, {
			settingSlugs: [ 'isSkyBlue' ],
			registry,
		} );
		registry.registerStore( storeDefinition.STORE_NAME, storeDefinition );
		dispatch = registry.dispatch( storeDefinition.STORE_NAME );
		store = registry.stores[ storeDefinition.STORE_NAME ].store;
		select = registry.select( storeDefinition.STORE_NAME );

		apiFetchSpy = jest.spyOn( { apiFetch }, 'apiFetch' );
	} );

	afterAll( () => {
		API.setUsingCache( true );
	} );

	afterEach( () => {
		unsubscribeFromAll( registry );
		apiFetchSpy.mockRestore();
	} );

	describe( 'name', () => {
		it( 'returns the correct default store name', () => {
			expect( storeDefinition.STORE_NAME ).toEqual( `${ STORE_ARGS[ 0 ] }/${ STORE_ARGS[ 1 ] }` );
		} );
	} );

	describe( 'actions', () => {
		describe( 'setSettings', () => {
			it( 'requires the values param', () => {
				expect( () => {
					dispatch.setSettings();
				} ).toThrow( 'values is required.' );
			} );

			it( 'updates the respective settings', () => {
				const values1 = { setting1: 'old', setting2: 'old' };
				const values2 = { setting2: 'new' };

				dispatch.setSettings( values1 );
				expect( store.getState().settings ).toMatchObject( values1 );

				dispatch.setSettings( values2 );
				expect( store.getState().settings ).toMatchObject( { ...values1, ...values2 } );
			} );
		} );

		describe( 'fetchSettings', () => {
			it( 'does not require any params', () => {
				expect( () => {
					dispatch.fetchSettings();
				} ).not.toThrow();
			} );
		} );

		describe( 'receiveSettings', () => {
			it( 'requires the values param', () => {
				expect( () => {
					dispatch.receiveSettings();
				} ).toThrow( 'values is required.' );
			} );

			it( 'receives and sets values', () => {
				const serverValues = { setting1: 'serverside', setting2: 'serverside' };
				const clientValues = { setting1: 'clientside' };

				dispatch.setSettings( clientValues );
				dispatch.receiveSettings( serverValues );

				// Client values take precedence if they were already modified before receiving from the server.
				expect( store.getState().settings ).toMatchObject( { ...serverValues, ...clientValues } );
			} );
		} );

		describe( 'saveSettings', () => {
			it( 'does not require any params', () => {
				expect( async () => {
					fetch
						.doMockOnceIf(
							/^\/google-site-kit\/v1\/core\/site\/data\/settings/
						)
						.mockResponseOnce(
							JSON.stringify( { setting1: 'serverside' } ),
							{ status: 200 }
						);

					await dispatch.saveSettings();
				} ).not.toThrow();
			} );

			it( 'updates settings from server', async () => {
				const response = { setting1: 'serverside' };
				fetch
					.doMockIf(
						/^\/google-site-kit\/v1\/core\/site\/data\/settings/
					)
					.mockResponse(
						JSON.stringify( response ),
						{ status: 200 }
					);

				// The server is the authority. So because this won't be part of the response
				// (see above), it will be disregarded.
				dispatch.setSettings( { setting2: 'clientside' } );

				await dispatch.saveSettings();
				// Two fetch requests, one to get settings, the other to update.
				expect( fetch ).toHaveBeenCalledTimes( 2 );

				expect( store.getState().settings ).toMatchObject( response );
			} );
		} );

		describe( 'fetchSaveSettings', () => {
			it( 'requires the values param', () => {
				expect( () => {
					dispatch.receiveSaveSettings();
				} ).toThrow( 'values is required.' );
			} );

			it( 'sets isDoingSaveSettings', () => {
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/site\/data\/settings/
					)
					.mockResponseOnce(
						JSON.stringify( { setting1: true } ),
						{ status: 200 }
					);

				dispatch.fetchSaveSettings( {} );
				expect( select.isDoingSaveSettings() ).toEqual( true );
			} );
		} );

		describe( 'receiveSaveSettings', () => {
			it( 'requires the values param', () => {
				expect( () => {
					dispatch.receiveSaveSettings();
				} ).toThrow( 'values is required.' );
			} );

			it( 'receives and sets values', () => {
				const serverValues = { setting1: 'serverside', setting2: 'serverside' };
				const clientValues = { setting1: 'clientside', setting3: 'clientside' };

				dispatch.setSettings( clientValues );
				dispatch.receiveSaveSettings( serverValues );

				// Client values are ignored here, server values replace them.
				expect( store.getState().settings ).toMatchObject( { ...serverValues } );
			} );
		} );

		// Tests for "pseudo-action" setSetting, available via setting-specific "set{SettingSlug}".
		describe( 'setSetting', () => {
			it( 'has the correct action name', () => {
				expect( Object.keys( storeDefinition.actions ) ).toEqual(
					// "isSkyBlue" should turn into "setIsSkyBlue".
					expect.arrayContaining( [ 'setIsSkyBlue' ] )
				);
			} );

			it( 'returns the correct action type', () => {
				const action = storeDefinition.actions.setIsSkyBlue( true );
				// "isSkyBlue" should turn into "SET_IS_SKY_BLUE".
				expect( action.type ).toEqual( 'SET_IS_SKY_BLUE' );
			} );

			it( 'requires the value param', () => {
				expect( () => {
					dispatch.setIsSkyBlue();
				} ).toThrow( 'value is required.' );
			} );

			it( 'updates the respective setting', () => {
				const value = 'new';

				dispatch.setIsSkyBlue( value );
				expect( store.getState().settings ).toMatchObject( { isSkyBlue: value } );
			} );
		} );
	} );

	describe( 'selectors', () => {
		describe( 'getSettings', () => {
			it( 'uses a resolver to make a network request', async () => {
				const response = { setting1: 'value' };
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/site\/data\/settings/
					)
					.mockResponseOnce(
						JSON.stringify( response ),
						{ status: 200 }
					);

				const initialSettings = select.getSettings();
				// Settings will be their initial value while being fetched.
				expect( initialSettings ).toEqual( undefined );
				await subscribeUntil( registry,
					() => (
						select.getSettings() !== undefined
					),
				);

				const settings = select.getSettings();

				expect( fetch ).toHaveBeenCalledTimes( 1 );
				expect( settings ).toEqual( response );

				expect( fetch ).toHaveBeenCalledTimes( 1 );
				expect( select.getSettings() ).toEqual( settings );
			} );

			it( 'returns client settings even if server settings have not loaded', () => {
				const values = { setting1: 'value' };
				dispatch.setSettings( values );

				// If settings are set on the client, they must be available even
				// if settings have not been loaded from the server yet.
				muteConsole( 'error' ); // Ignore the API fetch failure here.
				expect( select.getSettings() ).toEqual( values );
			} );

			it( 'dispatches an error if the request fails', async () => {
				const response = {
					code: 'internal_server_error',
					message: 'Internal server error',
					data: { status: 500 },
				};
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/site\/data\/settings/
					)
					.mockResponseOnce(
						JSON.stringify( response ),
						{ status: 500 }
					);

				muteConsole( 'error' );
				select.getSettings();
				await subscribeUntil( registry,
					// TODO: We may want a selector for this, but for now this is fine
					// because it's internal-only.
					() => store.getState().isFetchingSettings === false,
				);

				const settings = select.getSettings();

				expect( fetch ).toHaveBeenCalledTimes( 1 );
				expect( settings ).toEqual( undefined );
			} );
		} );

		describe( 'haveSettingsChanged', () => {
			it( 'informs whether client-side settings differ from server-side ones', async () => {
				// Initially false.
				expect( select.haveSettingsChanged() ).toEqual( false );

				const serverValues = { setting1: 'serverside' };
				const clientValues = { setting1: 'clientside' };

				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/site\/data\/settings/
					)
					.mockResponseOnce(
						JSON.stringify( serverValues ),
						{ status: 200 }
					);

				select.getSettings();
				await subscribeUntil( registry,
					() => (
						select.getSettings() !== undefined
					),
				);

				// Still false after fetching settings from server.
				expect( select.haveSettingsChanged() ).toEqual( false );

				// True after updating settings on client.
				dispatch.setSettings( clientValues );
				expect( select.haveSettingsChanged() ).toEqual( true );

				// False after updating settings back to original server value on client.
				dispatch.setSettings( serverValues );
				expect( select.haveSettingsChanged() ).toEqual( false );
			} );
		} );

		// Tests for "pseudo-selector" getSetting, available via setting-specific "get{SettingSlug}".
		describe( 'getSetting', () => {
			it( 'has the correct selector name', () => {
				expect( Object.keys( storeDefinition.selectors ) ).toEqual(
					// "isSkyBlue" should turn into "getIsSkyBlue".
					expect.arrayContaining( [ 'getIsSkyBlue' ] )
				);
			} );

			it( 'uses a resolver to make a network request', async () => {
				const value = 'serverside';
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/site\/data\/settings/
					)
					.mockResponseOnce(
						JSON.stringify( {
							otherSetting: 'other-value',
							isSkyBlue: value,
						} ),
						{ status: 200 }
					);

				// Setting will have its initial value while being fetched.
				expect( select.getIsSkyBlue() ).toEqual( undefined );
				await subscribeUntil( registry,
					() => (
						select.getSettings() !== undefined
					),
				);

				expect( fetch ).toHaveBeenCalledTimes( 1 );
				expect( select.getIsSkyBlue() ).toEqual( value );
				expect( fetch ).toHaveBeenCalledTimes( 1 );
			} );
		} );
	} );

	describe( 'controls', () => {
		describe( 'FETCH_SETTINGS', () => {
			it( 'requests from the correct API endpoint', async () => {
				const [ type, identifier, datapoint ] = STORE_ARGS;
				const response = { type, identifier, datapoint };

				fetch
					.mockResponseOnce( async ( req ) => {
						if ( req.url.startsWith( `/google-site-kit/v1/${ type }/${ identifier }/data/${ datapoint }` ) ) {
							return Promise.resolve( {
								body: JSON.stringify( response ),
								init: { status: 200 },
							} );
						}
						return Promise.resolve( {
							body: JSON.stringify( {
								code: 'incorrect_api_endpoint',
								message: 'Incorrect API endpoint',
								data: { status: 400 },
							} ),
							init: { status: 400 },
						} );
					} );

				const result = await storeDefinition.controls.FETCH_SETTINGS();
				expect( result ).toEqual( response );
				// Ensure `console.error()` wasn't called, which will happen if the API
				// request fails.
				expect( global.console.error ).not.toHaveBeenCalled();
			} );
		} );

		describe( 'FETCH_SAVE_SETTINGS', () => {
			it( 'requests from the correct API endpoint', async () => {
				const [ type, identifier, datapoint ] = STORE_ARGS;
				const response = { type, identifier, datapoint };

				fetch
					.mockResponseOnce( async ( req ) => {
						if ( req.url.startsWith( `/google-site-kit/v1/${ type }/${ identifier }/data/${ datapoint }` ) ) {
							return Promise.resolve( {
								body: JSON.stringify( response ),
								init: { status: 200 },
							} );
						}
						return Promise.resolve( {
							body: JSON.stringify( {
								code: 'incorrect_api_endpoint',
								message: 'Incorrect API endpoint',
								data: { status: 400 },
							} ),
							init: { status: 400 },
						} );
					} );

				const result = await storeDefinition.controls.FETCH_SAVE_SETTINGS( {} );
				expect( result ).toEqual( response );
				// Ensure `console.error()` wasn't called, which will happen if the API
				// request fails.
				expect( global.console.error ).not.toHaveBeenCalled();
			} );
		} );
	} );
} );
<|endoftext|>


<commit_before>/* Defer all scripts until after page load. The defer property on the script tag does not do this
properly. This is pretty much guaranteed to work */

var u = [
   /* Use a comma separated array of your scripts here, e.g. '/js/plugins.js', '/js/main.js' etc*/
]
function d() {
	for (var i = 0; i < u.length; i++) {
		var element = document.createElement("script");
		element.src = u[i];
		document.body.appendChild(element);
	};
}
if (window.addEventListener)
	window.addEventListener("load", d, false);
else if (window.attachEvent)
	window.attachEvent("onload", d);
else window.onload = d;

/* if using this in Umbraco, place this script in the master template, and then in each child template
add a section called scripts. You can then pass through scripts specific to that page as well as global
scripts like so:

var u = [
   '/scripts/main.js'
   @RenderSection("scripts", false)
]

*/<commit_msg>Added Copyright<commit_after>/*!
 * Defer JS v1.0.0
 * https://github.com/qntm/Defer-JS
 *
 * Copyright 2014 Ben Meyrick
 * Released under the MIT license
 */

/* Defer all scripts until after page load. The defer property on the script tag does not do this
properly. This is pretty much guaranteed to work */

var u = [
   /* Use a comma separated array of your scripts here, e.g. '/js/plugins.js', '/js/main.js' etc*/
]
function d() {
	for (var i = 0; i < u.length; i++) {
		var element = document.createElement("script");
		element.src = u[i];
		document.body.appendChild(element);
	};
}
if (window.addEventListener)
	window.addEventListener("load", d, false);
else if (window.attachEvent)
	window.attachEvent("onload", d);
else window.onload = d;

/* if using this in Umbraco, place this script in the master template, and then in each child template
add a section called scripts. You can then pass through scripts specific to that page as well as global
scripts like so:

var u = [
   '/scripts/main.js'
   @RenderSection("scripts", false)
]

*/<|endoftext|>


<commit_before>'use strict';

// Core module config

angular.module('core')
    .config(['$facebookProvider',
        function($facebookProvider)
        {
            $facebookProvider.setAppId('1664525490499797');
            $facebookProvider.setPermissions('email,user_likes,friends');
            $facebookProvider.setCustomInit({
                xfbml: true

            });
        }
    ]).run( function( $rootScope ) {

        var s3 = null;
        var clientId = 'amzn1.application-oa2-client.22c245e8e0d5419a87c7a287e5f9c727'; // client ID
        var roleArn = 'arn:aws:iam::274437077325 >:role/smart';

        window.onAmazonLoginReady = function() {
            amazon.Login.setClientId(clientId); // set client ID

            document.getElementById('login').onclick = function() {
                amazon.Login.authorize({scope: 'profile'}, function(response) {
                    if (!response.error) { // logged in
                        AWS.config.credentials = new AWS.WebIdentityCredentials({
                            RoleArn: roleArn,
                            ProviderId: 'www.amazon.com',
                            WebIdentityToken: response.access_token
                        });

                        s3 = new AWS.S3();

                        console.log('You are now logged in.');
                    } else {
                        console.log('There was a problem logging you in.');
                    }
                });
            };
        };
        // Load the facebook SDK asynchronously
        (function(){

            var a = document.createElement('script'); a.type = 'text/javascript';
            a.async = true; a.id = 'amazon-login-sdk';
            a.src = 'https://api-cdn.amazon.com/sdk/login1.js';

            // If we've already installed the SDK, we're done
            if (document.getElementById('facebook-jssdk')) {return;}

            // Get the first script element, which we'll use to find the parent node
            var firstScriptElement = document.getElementsByTagName('script')[0];

            // Create a new script element and set its id
            var facebookJS = document.createElement('script');
            facebookJS.id = 'facebook-jssdk';

            // Set the new script's source to the source of the Facebook JS SDK
            facebookJS.src = '//connect.facebook.net/en_US/all.js';

            // Insert the Facebook JS SDK
            firstScriptElement.parentNode.insertBefore(a, firstScriptElement);
            firstScriptElement.parentNode.insertBefore(facebookJS, firstScriptElement);
        }());
    });

<commit_msg>global declaration<commit_after>'use strict';

// Core module config

angular.module('core')
    .config(['$facebookProvider',
        function($facebookProvider)
        {
            $facebookProvider.setAppId('1664525490499797');
            $facebookProvider.setPermissions('email,user_likes,friends');
            $facebookProvider.setCustomInit({
                xfbml: true

            });
        }
    ]).run( function( $rootScope ) {

        var s3 = null;
        var clientId = 'amzn1.application-oa2-client.22c245e8e0d5419a87c7a287e5f9c727'; // client ID
        var roleArn = 'arn:aws:iam::274437077325 >:role/smart';

        window.onAmazonLoginReady = function() {
            amazon.Login.setClientId(clientId); // set client ID

            document.getElementById('login').onclick = function() {
                amazon.Login.authorize({scope: 'profile'}, function(response) {
                    if (!response.error) { // logged in
                        alert(responce);
                        AWS.config.credentials = new AWS.WebIdentityCredentials({
                            RoleArn: roleArn,
                            ProviderId: 'www.amazon.com',
                            WebIdentityToken: response.access_token
                        });

                        s3 = new AWS.S3();

                        console.log('You are now logged in.');
                    } else {
                        console.log('There was a problem logging you in.');
                    }
                });
            };
        };
        // Load the facebook SDK asynchronously
        (function(){

            var a = document.createElement('script'); a.type = 'text/javascript';
            a.async = true; a.id = 'amazon-login-sdk';
            a.src = 'https://api-cdn.amazon.com/sdk/login1.js';

            // If we've already installed the SDK, we're done
            if (document.getElementById('facebook-jssdk')) {return;}

            // Get the first script element, which we'll use to find the parent node
            var firstScriptElement = document.getElementsByTagName('script')[0];

            // Create a new script element and set its id
            var facebookJS = document.createElement('script');
            facebookJS.id = 'facebook-jssdk';

            // Set the new script's source to the source of the Facebook JS SDK
            facebookJS.src = '//connect.facebook.net/en_US/all.js';

            // Insert the Facebook JS SDK
            firstScriptElement.parentNode.insertBefore(a, firstScriptElement);
            firstScriptElement.parentNode.insertBefore(facebookJS, firstScriptElement);
        }());
    });

<|endoftext|>


<commit_before>var input = {
    "b": "two",
    "a": 1
}; //this is a json string used by matrix-org for test purposes

// obj.sort(function(a, b) {
//     return a.b.localeCompare(b.a);
// });
// //console.log(a.b.localeCompare(b.a));
function sortJSON() {
    JSON.stringify(input, Object.keys(input).sort());

} // has to be a function called sort SortJson

function CanonicalJSON(input, err) {
    for (var i = 0; i < input.length; i++) { // i guess i have to use slices innstes creating forloops
        var sorted = sortJSON(input);

        if (err != null) {
            return null;
        }
    }
    for (var j = 0; j < sorted.length; i++) {
        return compactJSON(sorted);
    }
}

//the basic idea is to reencode json and then arrange them into lexicographical order.
//gophers has a very copmplex way to do it,but JS is somewhat simple :)
// i guess there is nno need to use interfaces in js,as gophers use it to handle loosely handled or non-strictly typed json.<commit_msg>added unit tests to base64.js<commit_after>var input = {
    "b": "two",
    "a": 1
}; //this is a json string used by matrix-org for test purposes

// obj.sort(function(a, b) {
//     return a.b.localeCompare(b.a);
// });
// //console.log(a.b.localeCompare(b.a));
function sortJSON() {
    JSON.stringify(input, Object.keys(input).sort());

} // has to be a function called sort SortJson

// function CanonicalJSON(input, err) {
//     for (var i = 0; i < input.length; i++) { // i guess i have to use slices innstes creating forloops
//         var sorted = sortJSON(input);

//         if (err != null) {
//             return null;
//         }
//     }
//     for (var j = 0; j < sorted.length; i++) {
//         //return compactJSON(sorted);
//     }
// }

//the basic idea is to reencode json and then arrange them into lexicographical order.
//gophers has a very copmplex way to do it,but JS is somewhat simple :)
// i guess there is nno need to use interfaces in js,as gophers use it to handle loosely handled or non-strictly typed json.<|endoftext|>


<commit_before>(function(){
    var app = angular.module('nodeup', []);

    app.controller('UserAgentController', ['$http', '$log', '$location', '$window', function($http, $log, $location, $window){
        var agent = this;

        agent.newIdentity = function(){
            $window.location.href = '/?' + Math.random();  // note, the '?' is important here if we want to get entropy from urandom
        }

        agent.uid = $location.path().substr(1);  // remove '/' at beginning of path
        agent.msgs = [];
        agent.email = '';
        agent.emailNotify = false;
        agent.initial = true;
        agent.totalMinutesPaid = 0;
        agent.totalCoinsPaid = 0;
        agent.activeNodes = 0;

        agent.tip = 10;
        agent.exchangeRate = 100000000000;
        agent.nodeMinutes = 0;

        agent.firstName = '';

        agent.renderGreeting = function(){
            if (agent.firstName == ''){ return "Hello" }
            return "Hello " + agent.firstName;
        }

        agent.showError = false;
        agent.error = '';

        agent.status = "Waiting for payment...";
        agent.statusSymbol = "spinner";

        agent.clients = ['Bitcoin XT', 'Bitcoin Core'];
        agent.client = agent.clients[0];

        agent.months = 1;
        agent.monthsUp = function(){ agent.months += 1; agent.alertModified(); }
        agent.monthsDown = function(){ agent.months -= 1; if (agent.months < 1){ agent.months = 1; }; agent.alertModified();  }

        agent.price = function(){
            var raw_price = 5.00;
            return agent.months * (1 + agent.tip / 100.0) * raw_price;
        }

//        agent.nodesAvailable = function(){
//            if (agent.activeNodes >= 25) { return false; }
//            return true;
//        }

        agent.saveField = function(field, data){
            if (field == 'tip') { data = data / 100; }
            $http.post('/api', {method: 'saveField', params: {'field': field, 'value': data, 'uid': agent.uid}})
                .success(function(data){
                    // do something here maybe?
                    $log.log('Saved: ' + 'field' + field + ' ' + data)
                }).error(function(a,b,c,d){$log.log(a);})
        }
        agent.loadField = function(field){
            $http.post('/api', {method: 'loadField', params: {'field': field, 'uid': agent.uid}})
                .success(function(data){
                    value = data['value'];
                    $log.log(data);
                    $log.log('Setting ' + field + ": " + value);
                    if (field == 'email') {
                        agent.email = value;
                    } else if (field == 'emailNotify') {
                        agent.emailNotify = value;
                    } else if (field == 'name') {
                        agent.firstName = value;
                    } else if (field == 'tip') {
                        agent.tip = value * 100;
                    } else if (field == 'client') {
                        agent.client = value;
                    } else if (field == 'months') {
                        agent.email = value;
                    }
                })
        }
        agent.loadField('email');
        agent.loadField('emailNotify');
        agent.loadField('name');
        agent.loadField('tip');
        agent.loadField('client');

        agent.loadStats = function(){
            $http.post('/api', {method: 'getStats', params: {'uid': agent.uid}})
                .success(function(data){
                    agent.exchangeRate = data['exchangeRate'];
                    agent.nodeMinutes = data['nodeMinutes'];
                    agent.totalMinutesPaid = data['totalMinutesPaid'];
                    agent.totalCoinsPaid = data['totalCoinsPaid'];
                    agent.activeNodes = data['activeNodes'];
                    $log.log(data);
                }).error($log.log);
            setTimeout(agent.loadStats, 60 * 1000); // update once a min
        }
        agent.loadStats();

        agent.recompile = function(){
            $http.post('/api', {method: 'recompile', params:{'uid': agent.uid}})
                .success(function(data){
                    agent._updateMsgs();
                })
        }

        agent._paymentQR = new QRCode(document.getElementById("paymentQR"), {
            text: "generating qr code...",
            width: 200,
            height: 200,
            colorDark : "#000000",
            colorLight : "#ffffff",
            correctLevel : QRCode.CorrectLevel.H});
        agent._paymentVisible = false;
        agent.hidePayment = function(){
            agent._paymentVisible = false;
        };
        agent.showPayment = function(newURI){
            agent._paymentVisible = true;
            agent._paymentQR.makeCode(newURI);
            agent._paymentURI = newURI;
        };

        agent.getPaymentDetails = function(){
            agent.hidePayment();
            agent.getPaymentDetailsSilent();
        }
        agent.getPaymentDetailsSilent = function(){
            $http.post('/api', {'method': 'getPaymentDetails', params: {
                'uid': agent.uid,
                'client': agent.client,
                'months': agent.months,
            }}).success(function(data){
                    if('error' in data){
                        agent.showError = true;
                        agent.error = data['error'];
                    } else {
                        $log.log(data);
                        if (agent.initial) { agent.initial = false; }
                        agent.showPayment(data['uri']);
                        agent.status = data['status'];
                    }
                })
                .error(function(error, a,b,c){
                });
        };
        agent.getPaymentDetails();

        agent._alertTimeWait = 1500;
        agent._lastAlertModified = 0;
        agent._queued = false;
        agent.alertModified = function(field){
            if (field == 'email') {
                agent.saveField(field, agent.email);
            } else if (field == 'emailNotify') {
                agent.saveField(field, agent.emailNotify);
            } else if (field == 'name') {
                agent.saveField(field, agent.firstName);
            } else if (field == 'tip') {
                agent.saveField(field, agent.tip);
            } else if (field == 'client') {
                agent.saveField(field, agent.client);
            } else if (field == 'months') {
                agent.saveField(field, agent.email);
            }

            agent.hidePayment();
            $log.log('am');
            now = Date.now();
            delta = now - agent._lastAlertModified;
            if (delta < agent._alertTimeWait) {
                if (!agent._queued){
                    setTimeout(agent.alertModified, agent._alertTimeWait);
                    agent._queued = true;
                   }
            } else {
                agent._alertModified();
                agent._lastAlertModified = now;
                agent._queued = false;
            }
        }
        agent._alertModified = function(){
            $log.log('_am')
            agent.getPaymentDetails();
        }

        agent.randomUpdate = function(){
            agent.alertModified();  // don't call the update directly so we don't interfere too much
            setTimeout(agent.randomUpdate, 60 * 1000); // update every 1 minute regardless
        }

        agent.nMsgs = 10;
        agent._updateMsgs = function(){
            $http.post('/api', {'method': 'getMsgs', params: {'uid': agent.uid, 'n': agent.nMsgs}})
                .success(function(data){
                    agent.msgs = data['msgs'];
                    $log.log(agent.msgs);
                    if (agent.msgs.length > 0) {
                        agent.getPaymentDetailsSilent();
                    }
                }).error($log.log);
        }
        agent.updateMsgs = function(){
            var timeout = 999999999999;
            if (agent.msgs.length == 0){
                timeout = 2000;
            } else {
                timeout = 15000;
            }
            agent._updateMsgs();
            setTimeout(agent.updateMsgs, timeout);
        }
        agent.updateMsgs();
    }]);

    app.controller('TabController', ['$http', '$log', '$location', function($http, $log, $location){
        var tabs = this;

        tabs.devNotice = "{}";
        if ($location.host().substr(0, 3) == "dev"){ tabs.devNotice = "{background: #dd7700;}"; }

        var current = 'main';
        $location.hash(current);

        tabs.is = function(tabName){
            return current == tabName;
        };

        tabs.set = function(tabName){
            current = tabName;
            $location.hash(tabName);
        };
    }]);

    app.config(function($locationProvider) {
        $locationProvider.html5Mode({enabled: true}).hashPrefix('!');
    });

    app.config( [
        '$compileProvider',
        function( $compileProvider )
        {
            $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|bitcoin):/);
            // Angular before v1.2 uses $compileProvider.urlSanitizationWhitelist(...)
        }
    ]);
})();<commit_msg>colour change<commit_after>(function(){
    var app = angular.module('nodeup', []);

    app.controller('UserAgentController', ['$http', '$log', '$location', '$window', function($http, $log, $location, $window){
        var agent = this;

        agent.newIdentity = function(){
            $window.location.href = '/?' + Math.random();  // note, the '?' is important here if we want to get entropy from urandom
        }

        agent.uid = $location.path().substr(1);  // remove '/' at beginning of path
        agent.msgs = [];
        agent.email = '';
        agent.emailNotify = false;
        agent.initial = true;
        agent.totalMinutesPaid = 0;
        agent.totalCoinsPaid = 0;
        agent.activeNodes = 0;

        agent.tip = 10;
        agent.exchangeRate = 100000000000;
        agent.nodeMinutes = 0;

        agent.firstName = '';

        agent.renderGreeting = function(){
            if (agent.firstName == ''){ return "Hello" }
            return "Hello " + agent.firstName;
        }

        agent.showError = false;
        agent.error = '';

        agent.status = "Waiting for payment...";
        agent.statusSymbol = "spinner";

        agent.clients = ['Bitcoin XT', 'Bitcoin Core'];
        agent.client = agent.clients[0];

        agent.months = 1;
        agent.monthsUp = function(){ agent.months += 1; agent.alertModified(); }
        agent.monthsDown = function(){ agent.months -= 1; if (agent.months < 1){ agent.months = 1; }; agent.alertModified();  }

        agent.price = function(){
            var raw_price = 5.00;
            return agent.months * (1 + agent.tip / 100.0) * raw_price;
        }

//        agent.nodesAvailable = function(){
//            if (agent.activeNodes >= 25) { return false; }
//            return true;
//        }

        agent.saveField = function(field, data){
            if (field == 'tip') { data = data / 100; }
            $http.post('/api', {method: 'saveField', params: {'field': field, 'value': data, 'uid': agent.uid}})
                .success(function(data){
                    // do something here maybe?
                    $log.log('Saved: ' + 'field' + field + ' ' + data)
                }).error(function(a,b,c,d){$log.log(a);})
        }
        agent.loadField = function(field){
            $http.post('/api', {method: 'loadField', params: {'field': field, 'uid': agent.uid}})
                .success(function(data){
                    value = data['value'];
                    $log.log(data);
                    $log.log('Setting ' + field + ": " + value);
                    if (field == 'email') {
                        agent.email = value;
                    } else if (field == 'emailNotify') {
                        agent.emailNotify = value;
                    } else if (field == 'name') {
                        agent.firstName = value;
                    } else if (field == 'tip') {
                        agent.tip = value * 100;
                    } else if (field == 'client') {
                        agent.client = value;
                    } else if (field == 'months') {
                        agent.email = value;
                    }
                })
        }
        agent.loadField('email');
        agent.loadField('emailNotify');
        agent.loadField('name');
        agent.loadField('tip');
        agent.loadField('client');

        agent.loadStats = function(){
            $http.post('/api', {method: 'getStats', params: {'uid': agent.uid}})
                .success(function(data){
                    agent.exchangeRate = data['exchangeRate'];
                    agent.nodeMinutes = data['nodeMinutes'];
                    agent.totalMinutesPaid = data['totalMinutesPaid'];
                    agent.totalCoinsPaid = data['totalCoinsPaid'];
                    agent.activeNodes = data['activeNodes'];
                    $log.log(data);
                }).error($log.log);
            setTimeout(agent.loadStats, 60 * 1000); // update once a min
        }
        agent.loadStats();

        agent.recompile = function(){
            $http.post('/api', {method: 'recompile', params:{'uid': agent.uid}})
                .success(function(data){
                    agent._updateMsgs();
                })
        }

        agent._paymentQR = new QRCode(document.getElementById("paymentQR"), {
            text: "generating qr code...",
            width: 200,
            height: 200,
            colorDark : "#000000",
            colorLight : "#ffffff",
            correctLevel : QRCode.CorrectLevel.H});
        agent._paymentVisible = false;
        agent.hidePayment = function(){
            agent._paymentVisible = false;
        };
        agent.showPayment = function(newURI){
            agent._paymentVisible = true;
            agent._paymentQR.makeCode(newURI);
            agent._paymentURI = newURI;
        };

        agent.getPaymentDetails = function(){
            agent.hidePayment();
            agent.getPaymentDetailsSilent();
        }
        agent.getPaymentDetailsSilent = function(){
            $http.post('/api', {'method': 'getPaymentDetails', params: {
                'uid': agent.uid,
                'client': agent.client,
                'months': agent.months,
            }}).success(function(data){
                    if('error' in data){
                        agent.showError = true;
                        agent.error = data['error'];
                    } else {
                        $log.log(data);
                        if (agent.initial) { agent.initial = false; }
                        agent.showPayment(data['uri']);
                        agent.status = data['status'];
                    }
                })
                .error(function(error, a,b,c){
                });
        };
        agent.getPaymentDetails();

        agent._alertTimeWait = 1500;
        agent._lastAlertModified = 0;
        agent._queued = false;
        agent.alertModified = function(field){
            if (field == 'email') {
                agent.saveField(field, agent.email);
            } else if (field == 'emailNotify') {
                agent.saveField(field, agent.emailNotify);
            } else if (field == 'name') {
                agent.saveField(field, agent.firstName);
            } else if (field == 'tip') {
                agent.saveField(field, agent.tip);
            } else if (field == 'client') {
                agent.saveField(field, agent.client);
            } else if (field == 'months') {
                agent.saveField(field, agent.email);
            }

            agent.hidePayment();
            $log.log('am');
            now = Date.now();
            delta = now - agent._lastAlertModified;
            if (delta < agent._alertTimeWait) {
                if (!agent._queued){
                    setTimeout(agent.alertModified, agent._alertTimeWait);
                    agent._queued = true;
                   }
            } else {
                agent._alertModified();
                agent._lastAlertModified = now;
                agent._queued = false;
            }
        }
        agent._alertModified = function(){
            $log.log('_am')
            agent.getPaymentDetails();
        }

        agent.randomUpdate = function(){
            agent.alertModified();  // don't call the update directly so we don't interfere too much
            setTimeout(agent.randomUpdate, 60 * 1000); // update every 1 minute regardless
        }

        agent.nMsgs = 10;
        agent._updateMsgs = function(){
            $http.post('/api', {'method': 'getMsgs', params: {'uid': agent.uid, 'n': agent.nMsgs}})
                .success(function(data){
                    agent.msgs = data['msgs'];
                    $log.log(agent.msgs);
                    if (agent.msgs.length > 0) {
                        agent.getPaymentDetailsSilent();
                    }
                }).error($log.log);
        }
        agent.updateMsgs = function(){
            var timeout = 999999999999;
            if (agent.msgs.length == 0){
                timeout = 2000;
            } else {
                timeout = 15000;
            }
            agent._updateMsgs();
            setTimeout(agent.updateMsgs, timeout);
        }
        agent.updateMsgs();
    }]);

    app.controller('TabController', ['$http', '$log', '$location', function($http, $log, $location){
        var tabs = this;

        tabs.devNotice = "{}";
        if ($location.host().substr(0, 3) == "dev"){ tabs.devNotice = "{background: #77bb99;}"; }

        var current = 'main';
        $location.hash(current);

        tabs.is = function(tabName){
            return current == tabName;
        };

        tabs.set = function(tabName){
            current = tabName;
            $location.hash(tabName);
        };
    }]);

    app.config(function($locationProvider) {
        $locationProvider.html5Mode({enabled: true}).hashPrefix('!');
    });

    app.config( [
        '$compileProvider',
        function( $compileProvider )
        {
            $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|bitcoin):/);
            // Angular before v1.2 uses $compileProvider.urlSanitizationWhitelist(...)
        }
    ]);
})();<|endoftext|>


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

    return function() {
      var check = false;
      (function(a,b){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
      return check;
  };
});<commit_msg>fix lint error<commit_after>define([], function() {
    'use strict';

    return function() {
      var check = false;
      (function(a,b){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true;})(navigator.userAgent||navigator.vendor||window.opera);
      return check;
  };
});<|endoftext|>