<commit_before>const fs = require('fs-extra');
const { join } = require('path');
const tmp = require('tmp-promise');
const Git = require('simple-git/promise');

class Storage {
  constructor() {
    let config = {};
    let git = null;
    let repoDir = null;

    Object.assign(this, {
      initRepo,
      cleanRepo,
      setBaseBranch,
      branchExists,
      commitFilesToBranch,
      createBranch,
      deleteBranch,
      getAllRenovateBranches,
      getBranchCommit,
      getBranchLastCommitTime,
      getCommitMessages,
      getFile,
      getFileList,
      isBranchStale,
      mergeBranch,
    });

    async function initRepo(args) {
      cleanRepo();
      logger.info('Git FS mode enabled');
      config = { ...args };
      repoDir = await tmp.dir({ unsafeCleanup: true });
      git = Git(repoDir.path).silent(true);
      await git.clone(config.url, '.', ['--depth=2', '--no-single-branch']);

      if (config.gitAuthor) {
        await git.raw(['config', 'user.name', config.gitAuthor.name]);
        await git.raw(['config', 'user.email', config.gitAuthor.address]);
        // not supported yet
        await git.raw(['config', 'commit.gpgsign', 'false']);
      }

      // see https://stackoverflow.com/a/44750379/1438522
      config.baseBranch =
        config.baseBranch ||
        (await git.raw(['symbolic-ref', 'refs/remotes/origin/HEAD']))
          .replace('refs/remotes/origin/', '')
          .trim();
    }

    async function createBranch(branchName, sha) {
      await git.reset('hard');
      await git.checkout(['-B', branchName, sha]);
      await git.push(['origin', branchName, '--force']);
    }

    // Return the commit SHA for a branch
    async function getBranchCommit(branchName) {
      const res = await git.revparse(['origin/' + branchName]);
      return res.trim();
    }

    async function getCommitMessages() {
      logger.debug('getCommitMessages');
      const res = await git.log({
        n: 10,
        format: { message: '%s' },
      });
      return res.all.map(commit => commit.message);
    }

    function setBaseBranch(branchName) {
      if (branchName) {
        logger.debug(`Setting baseBranch to ${branchName}`);
        config.baseBranch = branchName;
      }
    }

    async function getFileList(branchName) {
      const branch = branchName || config.baseBranch;
      const exists = await branchExists(branch);
      if (!exists) {
        return [];
      }
      const files = await git.raw([
        'ls-tree',
        '-r',
        '--name-only',
        'origin/' + branch,
      ]);
      return files.split('\n').filter(Boolean);
    }

    async function branchExists(branchName) {
      try {
        await git.raw(['show-branch', 'origin/' + branchName]);
        return true;
      } catch (ex) {
        return false;
      }
    }

    async function getAllRenovateBranches(branchPrefix) {
      const branches = await git.branch(['--remotes', '--verbose']);
      return branches.all
        .map(localName)
        .filter(branchName => branchName.startsWith(branchPrefix));
    }

    async function isBranchStale(branchName) {
      const branches = await git.branch([
        '--remotes',
        '--verbose',
        '--contains',
        config.baseBranch,
      ]);
      return !branches.all.map(localName).includes(branchName);
    }

    async function deleteBranch(branchName) {
      await git.raw(['push', '--delete', 'origin', branchName]);
      try {
        await git.deleteLocalBranch(branchName);
      } catch (ex) {
        // local branch may not exist
      }
    }

    async function mergeBranch(branchName) {
      await git.reset('hard');
      await git.checkout(['-B', branchName, 'origin/' + branchName]);
      await git.checkout(config.baseBranch);
      await git.merge([branchName]);
      await git.push('origin', config.baseBranch);
    }

    async function getBranchLastCommitTime(branchName) {
      try {
        const time = await git.show([
          '-s',
          '--format=%ai',
          'origin/' + branchName,
        ]);
        return new Date(Date.parse(time));
      } catch (ex) {
        return new Date();
      }
    }

    async function getFile(filePath, branchName) {
      if (branchName) {
        const exists = await branchExists(branchName);
        if (!exists) {
          logger.warn({ branchName }, 'getFile branch does not exist');
          return null;
        }
      }
      try {
        const content = await git.show([
          'origin/' + (branchName || config.baseBranch) + ':' + filePath,
        ]);
        return content;
      } catch (ex) {
        return null;
      }
    }

    async function commitFilesToBranch(
      branchName,
      files,
      message,
      parentBranch = config.baseBranch
    ) {
      await git.reset('hard');
      await git.checkout(['-B', branchName, 'origin/' + parentBranch]);
      for (const file of files) {
        await fs.writeFile(
          join(repoDir.path, file.name),
          Buffer.from(file.contents)
        );
      }
      await git.add(files.map(f => f.name));
      await git.commit(message);
      await git.push(['origin', branchName, '--force']);
    }

    function cleanRepo() {
      if (repoDir) {
        repoDir.cleanup();
        repoDir = null;
      }
    }
  }
}

function localName(branchName) {
  return branchName.replace(/^origin\//, '');
}

module.exports = Storage;
<commit_msg>refactor: measure git clone time<commit_after>const fs = require('fs-extra');
const { join } = require('path');
const tmp = require('tmp-promise');
const Git = require('simple-git/promise');
const convertHrtime = require('convert-hrtime');

class Storage {
  constructor() {
    let config = {};
    let git = null;
    let repoDir = null;

    Object.assign(this, {
      initRepo,
      cleanRepo,
      setBaseBranch,
      branchExists,
      commitFilesToBranch,
      createBranch,
      deleteBranch,
      getAllRenovateBranches,
      getBranchCommit,
      getBranchLastCommitTime,
      getCommitMessages,
      getFile,
      getFileList,
      isBranchStale,
      mergeBranch,
    });

    async function initRepo(args) {
      cleanRepo();
      logger.info('Initialising git repository');
      config = { ...args };
      repoDir = await tmp.dir({ unsafeCleanup: true });
      git = Git(repoDir.path).silent(true);
      const cloneStart = process.hrtime();
      await git.clone(config.url, '.', ['--depth=2', '--no-single-branch']);
      const cloneSeconds = Math.round(
        convertHrtime(process.hrtime(cloneStart)).seconds
      );
      logger.info({ cloneSeconds }, 'git clone completed');

      if (config.gitAuthor) {
        await git.raw(['config', 'user.name', config.gitAuthor.name]);
        await git.raw(['config', 'user.email', config.gitAuthor.address]);
        // not supported yet
        await git.raw(['config', 'commit.gpgsign', 'false']);
      }

      // see https://stackoverflow.com/a/44750379/1438522
      config.baseBranch =
        config.baseBranch ||
        (await git.raw(['symbolic-ref', 'refs/remotes/origin/HEAD']))
          .replace('refs/remotes/origin/', '')
          .trim();
    }

    async function createBranch(branchName, sha) {
      await git.reset('hard');
      await git.checkout(['-B', branchName, sha]);
      await git.push(['origin', branchName, '--force']);
    }

    // Return the commit SHA for a branch
    async function getBranchCommit(branchName) {
      const res = await git.revparse(['origin/' + branchName]);
      return res.trim();
    }

    async function getCommitMessages() {
      logger.debug('getCommitMessages');
      const res = await git.log({
        n: 10,
        format: { message: '%s' },
      });
      return res.all.map(commit => commit.message);
    }

    function setBaseBranch(branchName) {
      if (branchName) {
        logger.debug(`Setting baseBranch to ${branchName}`);
        config.baseBranch = branchName;
      }
    }

    async function getFileList(branchName) {
      const branch = branchName || config.baseBranch;
      const exists = await branchExists(branch);
      if (!exists) {
        return [];
      }
      const files = await git.raw([
        'ls-tree',
        '-r',
        '--name-only',
        'origin/' + branch,
      ]);
      return files.split('\n').filter(Boolean);
    }

    async function branchExists(branchName) {
      try {
        await git.raw(['show-branch', 'origin/' + branchName]);
        return true;
      } catch (ex) {
        return false;
      }
    }

    async function getAllRenovateBranches(branchPrefix) {
      const branches = await git.branch(['--remotes', '--verbose']);
      return branches.all
        .map(localName)
        .filter(branchName => branchName.startsWith(branchPrefix));
    }

    async function isBranchStale(branchName) {
      const branches = await git.branch([
        '--remotes',
        '--verbose',
        '--contains',
        config.baseBranch,
      ]);
      return !branches.all.map(localName).includes(branchName);
    }

    async function deleteBranch(branchName) {
      await git.raw(['push', '--delete', 'origin', branchName]);
      try {
        await git.deleteLocalBranch(branchName);
      } catch (ex) {
        // local branch may not exist
      }
    }

    async function mergeBranch(branchName) {
      await git.reset('hard');
      await git.checkout(['-B', branchName, 'origin/' + branchName]);
      await git.checkout(config.baseBranch);
      await git.merge([branchName]);
      await git.push('origin', config.baseBranch);
    }

    async function getBranchLastCommitTime(branchName) {
      try {
        const time = await git.show([
          '-s',
          '--format=%ai',
          'origin/' + branchName,
        ]);
        return new Date(Date.parse(time));
      } catch (ex) {
        return new Date();
      }
    }

    async function getFile(filePath, branchName) {
      if (branchName) {
        const exists = await branchExists(branchName);
        if (!exists) {
          logger.warn({ branchName }, 'getFile branch does not exist');
          return null;
        }
      }
      try {
        const content = await git.show([
          'origin/' + (branchName || config.baseBranch) + ':' + filePath,
        ]);
        return content;
      } catch (ex) {
        return null;
      }
    }

    async function commitFilesToBranch(
      branchName,
      files,
      message,
      parentBranch = config.baseBranch
    ) {
      await git.reset('hard');
      await git.checkout(['-B', branchName, 'origin/' + parentBranch]);
      for (const file of files) {
        await fs.writeFile(
          join(repoDir.path, file.name),
          Buffer.from(file.contents)
        );
      }
      await git.add(files.map(f => f.name));
      await git.commit(message);
      await git.push(['origin', branchName, '--force']);
    }

    function cleanRepo() {
      if (repoDir) {
        repoDir.cleanup();
        repoDir = null;
      }
    }
  }
}

function localName(branchName) {
  return branchName.replace(/^origin\//, '');
}

module.exports = Storage;
<|endoftext|>


<commit_before>angular.module('myApp').directive('demo', ['$routeParams', function ($routeParams) {
    return {
        restrict: 'E',
        templateUrl: 'components/demo/demo.html',

        scope: {},
        controller: function ($scope, $log, $rootScope, $location, $http, $timeout) {

            $scope.backendErrors = false;

            var container = $("#flot-moving-line-chart");

            var maximumPoints = 300;

            $scope.fitnessPlot = {};
            $scope.fitnessPlot.ys = [];
            for (var i = 0; i < maximumPoints; i++) {
                $scope.fitnessPlot.ys.push(0);
            }

            // zip the generated y values with the x values

            var res = [];
            for (var i = 0; i < $scope.fitnessPlot.ys.length; i++) {
                res.push([i, $scope.fitnessPlot.ys[i]])
            }

            $scope.fitnessPlot.series = [{
                data: res,
                lines: {
                    fill: true
                }
            }];

            //

            $scope.fitnessPlot.plot = $.plot(container, $scope.fitnessPlot.series, {
                grid: {
                    borderWidth: 1,
                    minBorderMargin: 20,
                    labelMargin: 10,
                    backgroundColor: {
                        colors: ["#fff", "#e4f4f4"]
                    },
                    margin: {
                        top: 8,
                        bottom: 20,
                        left: 20
                    },
                    markings: function (axes) {
                        var markings = [];
                        var xaxis = axes.xaxis;
                        for (var x = Math.floor(xaxis.min); x < xaxis.max; x += xaxis.tickSize * 2) {
                            markings.push({
                                xaxis: {
                                    from: x,
                                    to: x + xaxis.tickSize
                                },
                                color: "rgba(232, 232, 255, 0.2)"
                            });
                        }
                        return markings;
                    }
                },
                xaxis: {
                    tickFormatter: function () {
                        return "";
                    }
                },
                yaxis: {
                    min: 0,
                    max: 25000
                },
                legend: {
                    show: true
                }
            });

            $scope.algorithmStillRunning = false;
            $scope.settings = {};
            $scope.settings.selectedOption = {
                id: 1,
                name: "low",
                settings: {
                    "mutationProbability": 25,
                    "populationSize": 500,
                    "nrOfGenerations": 5000,
                    "fitnessThreshold": 11000,
                    "parentSelectionSize": 60,
                    "parentPoolSize": 100
                }
            };
            $scope.settings.availableAlgorithmStyles = [
                {
                    id: 0,
                    name: "single-threaded"
                },
                {
                    id: 1,
                    name: "parallel"
                }];
            $scope.settings.selectedAlgorithmStyle = $scope.settings.availableAlgorithmStyles[0];
            $scope.settings.availableOptions = [
                {
                    id: 0,
                    name: "none",
                    settings: $scope.settings.selectedOption.settings
                },
                {
                    id: 1,
                    name: "low",
                    settings: {
                        "mutationProbability": 25,
                        "populationSize": 500,
                        "nrOfGenerations": 5000,
                        "fitnessThreshold": 11000,
                        "parentSelectionSize": 60,
                        "parentPoolSize": 100
                    }
                },
                {
                    id: 2,
                    name: "medium",
                    settings: {
                        "mutationProbability": 50,
                        "populationSize": 75,
                        "nrOfGenerations": 10000,
                        "fitnessThreshold": 11000,
                        "parentSelectionSize": 30,
                        "parentPoolSize": 50
                    }
                },
                {
                    id: 3,
                    name: "high",
                    settings: {
                        "mutationProbability": 90,
                        "populationSize": 1000,
                        "nrOfGenerations": 20000,
                        "fitnessThreshold": 11000,
                        "parentSelectionSize": 6,
                        "parentPoolSize": 10
                    }
                }
            ];
            $scope.setPresetToNone = function () {
                $scope.settings.selectedOption = {
                    id: 0,
                    name: "none",
                    settings: $scope.settings.selectedOption.settings
                }
            },

                $scope.run = {"generation": 0, "bestFitness": 0};

            function setNewValues(response) {
                if(!response.data) {
                    return;
                }

                $scope.areas = response.data.route;
                $scope.run.bestFitness = response.data.fitness;
                $scope.run.generation = response.data.generation;

                $scope.fitnessPlot.ys = $scope.fitnessPlot.ys.slice(1);
                $scope.fitnessPlot.ys.push($scope.run.bestFitness);

                // zip the generated y values with the x values

                var res = [];
                for (var i = 0; i < $scope.fitnessPlot.ys.length; i++) {
                    res.push([i, $scope.fitnessPlot.ys[i]])
                }

                $scope.fitnessPlot.series[0].data = res;
                $scope.fitnessPlot.plot.setData($scope.fitnessPlot.series);
                $scope.fitnessPlot.plot.draw();
            }

            $scope.getBest = function () {
                return $http.get('http://localhost:8080/api/currentBest').then(function (response) {
                    setNewValues(response);
                }, function (response) {
                    $scope.algorithmStillRunning = false;

                    // try to get the last rating
                    $http.get('http://localhost:8080/api/latestBest').then(function (response) {
                        setNewValues(response);
                    });
                });
            };

            $scope.start = function () {
                var body = $scope.settings.selectedOption.settings;
                body.algorithmStyle = $scope.settings.selectedAlgorithmStyle.name;

                $scope.startAlgorithm(body).then(function () {
                    $scope.algorithmStillRunning = true;
                    $scope.updateCurrentBest();
                });

            };

            $scope.stop = function () {
                $http.post('http://localhost:8080/api/stopAlgorithm').
                    then(function (response) {
                        // we're good!
                    });
            }

            $scope.updateCurrentBest = function () {
                if ($scope.algorithmStillRunning) {
                    $scope.getBest().then(function (response) {
                        var route = $scope.updateRoute();

                        if ($scope.flightPath) {
                            $scope.flightPath.setMap(null);
                        }

                        $scope.flightPath = new google.maps.Polyline({
                            path: route,
                            geodesic: true,
                            strokeColor: '#FFFF66',
                            strokeOpacity: 1.0,
                            strokeWeight: 2
                        });

                        $scope.flightPath.setMap($scope.map);

                        $timeout($scope.updateCurrentBest, 250);
                    });
                }
            };

            $scope.updateRoute = function () {
                var route = [];
                for (var j = 0; j < $scope.areas.length; j++) {

                    var city = $scope.areas[j];

                    city.location = new google.maps.LatLng(city.latitude, city.longitude);
                    var marker = new google.maps.Marker({
                        position: city.location,
                        map: $scope.map,
                        title: city.name,

                    });

                    route.push({lat: city.latitude, lng: city.longitude})
                }
                return route;
            }

            $scope.startAlgorithm = function (body) {
                return $http.post('http://localhost:8080/api/startAlgorithm', body).
                    then(function (response) {
                        $scope.backendErrors = false;
                        return response;
                    }, function (response) {
                        if (response.status === -1) {
                            $scope.backendErrors = true;
                        }
                    });
            }

            $scope.stillRunning = function () {
                return $http.get('http://localhost:8080/api/stillRunning').then(function (response) {
                    return response.data;
                });
            };

            $scope.initialize = function () {
                $scope.backendErrors = false;
                if ($scope.algorithmStillRunning) {
                    $scope.stopAlgorithm;
                }
                $scope.algorithmStillRunning = false;
                $scope.run = {"generation": 0, "bestFitness": 0};
                var mapOptions = {
                    center: new google.maps.LatLng(50.521401, 9.623885),
                    zoom: 5,
                    mapTypeId: google.maps.MapTypeId.SATELLITE
                };
                $scope.map = new google.maps.Map(document.getElementById("map-canvas"),
                    mapOptions);

                $scope.fitnessPlot.ys = [];
                for (var i = 0; i < maximumPoints; i++) {
                    $scope.fitnessPlot.ys.push(0);
                }

                // zip the generated y values with the x values

                var res = [];
                for (var i = 0; i < $scope.fitnessPlot.ys.length; i++) {
                    res.push([i, $scope.fitnessPlot.ys[i]])
                }
                $scope.fitnessPlot.series[0].data = res;
                $scope.fitnessPlot.plot.setData($scope.fitnessPlot.series);
                $scope.fitnessPlot.plot.draw();

                return $http.get('http://localhost:8080/api/getCities').then(function (response) {
                    $scope.areas = response.data;
                    $scope.updateRoute();
                });

            };
            google.maps.event.addDomListener(window, 'load', $scope.initialize);
            $scope.initialize();
        }
    };
}]);<commit_msg>paralleling: added really high preset<commit_after>angular.module('myApp').directive('demo', ['$routeParams', function ($routeParams) {
    return {
        restrict: 'E',
        templateUrl: 'components/demo/demo.html',

        scope: {},
        controller: function ($scope, $log, $rootScope, $location, $http, $timeout) {

            $scope.backendErrors = false;

            var container = $("#flot-moving-line-chart");

            var maximumPoints = 300;

            $scope.fitnessPlot = {};
            $scope.fitnessPlot.ys = [];
            for (var i = 0; i < maximumPoints; i++) {
                $scope.fitnessPlot.ys.push(0);
            }

            // zip the generated y values with the x values

            var res = [];
            for (var i = 0; i < $scope.fitnessPlot.ys.length; i++) {
                res.push([i, $scope.fitnessPlot.ys[i]])
            }

            $scope.fitnessPlot.series = [{
                data: res,
                lines: {
                    fill: true
                }
            }];

            //

            $scope.fitnessPlot.plot = $.plot(container, $scope.fitnessPlot.series, {
                grid: {
                    borderWidth: 1,
                    minBorderMargin: 20,
                    labelMargin: 10,
                    backgroundColor: {
                        colors: ["#fff", "#e4f4f4"]
                    },
                    margin: {
                        top: 8,
                        bottom: 20,
                        left: 20
                    },
                    markings: function (axes) {
                        var markings = [];
                        var xaxis = axes.xaxis;
                        for (var x = Math.floor(xaxis.min); x < xaxis.max; x += xaxis.tickSize * 2) {
                            markings.push({
                                xaxis: {
                                    from: x,
                                    to: x + xaxis.tickSize
                                },
                                color: "rgba(232, 232, 255, 0.2)"
                            });
                        }
                        return markings;
                    }
                },
                xaxis: {
                    tickFormatter: function () {
                        return "";
                    }
                },
                yaxis: {
                    min: 0,
                    max: 25000
                },
                legend: {
                    show: true
                }
            });

            $scope.algorithmStillRunning = false;
            $scope.settings = {};
            $scope.settings.selectedOption = {
                id: 1,
                name: "low",
                settings: {
                    "mutationProbability": 25,
                    "populationSize": 500,
                    "nrOfGenerations": 5000,
                    "fitnessThreshold": 11000,
                    "parentSelectionSize": 60,
                    "parentPoolSize": 100
                }
            };
            $scope.settings.availableAlgorithmStyles = [
                {
                    id: 0,
                    name: "single-threaded"
                },
                {
                    id: 1,
                    name: "parallel"
                }];
            $scope.settings.selectedAlgorithmStyle = $scope.settings.availableAlgorithmStyles[0];
            $scope.settings.availableOptions = [
                {
                    id: 0,
                    name: "none",
                    settings: $scope.settings.selectedOption.settings
                },
                {
                    id: 1,
                    name: "low",
                    settings: {
                        "mutationProbability": 25,
                        "populationSize": 500,
                        "nrOfGenerations": 5000,
                        "fitnessThreshold": 11000,
                        "parentSelectionSize": 60,
                        "parentPoolSize": 100
                    }
                },
                {
                    id: 2,
                    name: "medium",
                    settings: {
                        "mutationProbability": 50,
                        "populationSize": 75,
                        "nrOfGenerations": 10000,
                        "fitnessThreshold": 11000,
                        "parentSelectionSize": 30,
                        "parentPoolSize": 50
                    }
                },
                {
                    id: 3,
                    name: "high",
                    settings: {
                        "mutationProbability": 90,
                        "populationSize": 1000,
                        "nrOfGenerations": 20000,
                        "fitnessThreshold": 11000,
                        "parentSelectionSize": 6,
                        "parentPoolSize": 10
                    }
                },
                {
                    id: 4,
                    name: "really high",
                    settings: {
                        "mutationProbability": 25,
                        "populationSize": 50000,
                        "nrOfGenerations": 5000,
                        "fitnessThreshold": 11000,
                        "parentSelectionSize": 6000,
                        "parentPoolSize": 10000
                    }
                }
            ];
            $scope.setPresetToNone = function () {
                $scope.settings.selectedOption = {
                    id: 0,
                    name: "none",
                    settings: $scope.settings.selectedOption.settings
                }
            },

                $scope.run = {"generation": 0, "bestFitness": 0};

            function setNewValues(response) {
                if(!response.data) {
                    return;
                }

                $scope.areas = response.data.route;
                $scope.run.bestFitness = response.data.fitness;
                $scope.run.generation = response.data.generation;

                $scope.fitnessPlot.ys = $scope.fitnessPlot.ys.slice(1);
                $scope.fitnessPlot.ys.push($scope.run.bestFitness);

                // zip the generated y values with the x values

                var res = [];
                for (var i = 0; i < $scope.fitnessPlot.ys.length; i++) {
                    res.push([i, $scope.fitnessPlot.ys[i]])
                }

                $scope.fitnessPlot.series[0].data = res;
                $scope.fitnessPlot.plot.setData($scope.fitnessPlot.series);
                $scope.fitnessPlot.plot.draw();
            }

            $scope.getBest = function () {
                return $http.get('http://localhost:8080/api/currentBest').then(function (response) {
                    setNewValues(response);
                }, function (response) {
                    $scope.algorithmStillRunning = false;

                    // try to get the last rating
                    $http.get('http://localhost:8080/api/latestBest').then(function (response) {
                        setNewValues(response);
                    });
                });
            };

            $scope.start = function () {
                var body = $scope.settings.selectedOption.settings;
                body.algorithmStyle = $scope.settings.selectedAlgorithmStyle.name;

                $scope.startAlgorithm(body).then(function () {
                    $scope.algorithmStillRunning = true;
                    $scope.updateCurrentBest();
                });

            };

            $scope.stop = function () {
                $http.post('http://localhost:8080/api/stopAlgorithm').
                    then(function (response) {
                        // we're good!
                    });
            }

            $scope.updateCurrentBest = function () {
                if ($scope.algorithmStillRunning) {
                    $scope.getBest().then(function (response) {
                        var route = $scope.updateRoute();

                        if ($scope.flightPath) {
                            $scope.flightPath.setMap(null);
                        }

                        $scope.flightPath = new google.maps.Polyline({
                            path: route,
                            geodesic: true,
                            strokeColor: '#FFFF66',
                            strokeOpacity: 1.0,
                            strokeWeight: 2
                        });

                        $scope.flightPath.setMap($scope.map);

                        $timeout($scope.updateCurrentBest, 250);
                    });
                }
            };

            $scope.updateRoute = function () {
                var route = [];
                for (var j = 0; j < $scope.areas.length; j++) {

                    var city = $scope.areas[j];

                    city.location = new google.maps.LatLng(city.latitude, city.longitude);
                    var marker = new google.maps.Marker({
                        position: city.location,
                        map: $scope.map,
                        title: city.name,

                    });

                    route.push({lat: city.latitude, lng: city.longitude})
                }
                return route;
            }

            $scope.startAlgorithm = function (body) {
                return $http.post('http://localhost:8080/api/startAlgorithm', body).
                    then(function (response) {
                        $scope.backendErrors = false;
                        return response;
                    }, function (response) {
                        if (response.status === -1) {
                            $scope.backendErrors = true;
                        }
                    });
            }

            $scope.stillRunning = function () {
                return $http.get('http://localhost:8080/api/stillRunning').then(function (response) {
                    return response.data;
                });
            };

            $scope.initialize = function () {
                $scope.backendErrors = false;
                if ($scope.algorithmStillRunning) {
                    $scope.stopAlgorithm;
                }
                $scope.algorithmStillRunning = false;
                $scope.run = {"generation": 0, "bestFitness": 0};
                var mapOptions = {
                    center: new google.maps.LatLng(50.521401, 9.623885),
                    zoom: 5,
                    mapTypeId: google.maps.MapTypeId.SATELLITE
                };
                $scope.map = new google.maps.Map(document.getElementById("map-canvas"),
                    mapOptions);

                $scope.fitnessPlot.ys = [];
                for (var i = 0; i < maximumPoints; i++) {
                    $scope.fitnessPlot.ys.push(0);
                }

                // zip the generated y values with the x values

                var res = [];
                for (var i = 0; i < $scope.fitnessPlot.ys.length; i++) {
                    res.push([i, $scope.fitnessPlot.ys[i]])
                }
                $scope.fitnessPlot.series[0].data = res;
                $scope.fitnessPlot.plot.setData($scope.fitnessPlot.series);
                $scope.fitnessPlot.plot.draw();

                return $http.get('http://localhost:8080/api/getCities').then(function (response) {
                    $scope.areas = response.data;
                    $scope.updateRoute();
                });

            };
            google.maps.event.addDomListener(window, 'load', $scope.initialize);
            $scope.initialize();
        }
    };
}]);<|endoftext|>


<commit_before>cabrito.PageLoad.elementReady('timer', function () {

    var timer = clock.create();
    timer.pomodoro(25, 'timer');

    cabrito.PageLoad.elementReady('pomodoro-trigger', function () {
        document.getElementById('pomodoro-trigger').removeAttribute('href');
        document.getElementById('pomodoro-trigger').addEventListener('click', function () {
            timer.pomodoro(25, 'timer');
        });
    });

    cabrito.PageLoad.elementReady('5-min-trigger', function () {
        document.getElementById('5-min-trigger').addEventListener('click', function () {
            timer.pomodoro(5, 'timer');
        });
        document.getElementById('pomodoro-interval').addEventListener('click', function () {
            timer.pomodoro(5, 'timer');
        });
    });
});
<commit_msg>Modificando ID do relógio<commit_after>cabrito.PageLoad.elementReady('time-elapsed', function () {

    var timer = clock.create();
    timer.pomodoro(25, 'time-elapsed');

    cabrito.PageLoad.elementReady('pomodoro-trigger', function () {
        document.getElementById('pomodoro-trigger').removeAttribute('href');
        document.getElementById('pomodoro-trigger').addEventListener('click', function () {
            timer.pomodoro(25, 'time-elapsed');
        });
    });

    cabrito.PageLoad.elementReady('5-min-trigger', function () {
        document.getElementById('5-min-trigger').addEventListener('click', function () {
            timer.pomodoro(5, 'time-elapsed');
        });
        document.getElementById('pomodoro-interval').addEventListener('click', function () {
            timer.pomodoro(5, 'time-elapsed');
        });
    });
});
<|endoftext|>


<commit_before>'use strict';

/* Usage:
 *
 * ProofreaderActivity.get(id).then(function (proofreaderActivity) {
 *  return proofreaderActivity.getRules();
 * }).then(function (rules) {
 *  // do something here
 * });
 *
 */

module.exports =
angular.module('quill-grammar.services.firebase.proofreaderActivity', [
  'firebase',
  'underscore',
  require('./../../../../.tmp/config.js').name,
])
/*@ngInject*/
.factory('ProofreaderActivity', function (firebaseUrl, $firebaseObject, _, $q, $firebaseArray) {
  function ProofreaderModel(data) {
    if (data) {
      _.extend(this, data);
    }
    return this;
  }
  ProofreaderModel.ref = new Firebase(firebaseUrl + '/passageProofreadings');

  // 'Class' methods

  ProofreaderModel.getById = function (id) {
    return $firebaseObject(ProofreaderModel.ref.child(id)).$loaded().then(function (data) {
      // Determine whether the activity exists.
      // This is a hack because $firebaseObject does not give access
      // to the DataSnapshot object where we'd normally call exists().
      if (!data.passage) {
        return $q.reject(new Error('Error loading activity: activity with ID ' + id + ' does not exist.'));
      }

      return new ProofreaderModel(data);
    });
  };

  /*
   * Get all Proofreader Activities from Firebase
   */
  ProofreaderModel.getAllFromFB = function () {
    return $firebaseArray(ProofreaderModel.ref).$loaded();
  };

  /*
   * Add one Proofreader Activity to Firebase
   */
  ProofreaderModel.addToFB = function (pa) {
    return $firebaseArray(ProofreaderModel.ref).$add(pa);
  };

  /*
   * Update one Proofreader Activity to Firebase
   */
  ProofreaderModel.updateToFB = function (id, pa) {
    return $firebaseObject(ProofreaderModel.ref).$loaded().then(function (pas) {
      pas[id] = pa;
      return pas.$save();
    });
  };

  return ProofreaderModel;
});
<commit_msg>Delete one proofreader activity<commit_after>'use strict';

/* Usage:
 *
 * ProofreaderActivity.get(id).then(function (proofreaderActivity) {
 *  return proofreaderActivity.getRules();
 * }).then(function (rules) {
 *  // do something here
 * });
 *
 */

module.exports =
angular.module('quill-grammar.services.firebase.proofreaderActivity', [
  'firebase',
  'underscore',
  require('./../../../../.tmp/config.js').name,
])
/*@ngInject*/
.factory('ProofreaderActivity', function (firebaseUrl, $firebaseObject, _, $q, $firebaseArray) {
  function ProofreaderModel(data) {
    if (data) {
      _.extend(this, data);
    }
    return this;
  }
  ProofreaderModel.ref = new Firebase(firebaseUrl + '/passageProofreadings');

  // 'Class' methods

  ProofreaderModel.getById = function (id) {
    return $firebaseObject(ProofreaderModel.ref.child(id)).$loaded().then(function (data) {
      // Determine whether the activity exists.
      // This is a hack because $firebaseObject does not give access
      // to the DataSnapshot object where we'd normally call exists().
      if (!data.passage) {
        return $q.reject(new Error('Error loading activity: activity with ID ' + id + ' does not exist.'));
      }

      return new ProofreaderModel(data);
    });
  };

  /*
   * Get all Proofreader Activities from Firebase
   */
  ProofreaderModel.getAllFromFB = function () {
    return $firebaseArray(ProofreaderModel.ref).$loaded();
  };

  /*
   * Add one Proofreader Activity to Firebase
   */
  ProofreaderModel.addToFB = function (pa) {
    return $firebaseArray(ProofreaderModel.ref).$add(pa);
  };

  /*
   * Update one Proofreader Activity to Firebase
   */
  ProofreaderModel.updateToFB = function (id, pa) {
    return $firebaseObject(ProofreaderModel.ref).$loaded().then(function (pas) {
      pas[id] = pa;
      return pas.$save();
    });
  };

  /*
   * Delete one Proofreader Activity from Firebase
   */
  ProofreaderModel.deleteByIdFromFB = function (id) {
    return $firebaseObject(ProofreaderModel.ref).$loaded().then(function (pas) {
      pas[id] = null;
      return pas.$save();
    });
  };

  return ProofreaderModel;
});
<|endoftext|>


<commit_before>'use strict';

module.exports =
angular.module('quill-grammar.services.proofreadingPassage', [
  'underscore',
  require('./../rule.js').name,
  require('./passageWord.js').name,
  'uuid4',
  'angulartics'
])
/*@ngInject*/
.factory('ProofreadingPassage', function (_, uuid4, PassageWord, RuleService, $analytics, localStorageService, ConceptsFBService) {
  function ProofreadingPassage(data) {
    if (data) {
      _.extend(this, data);
    }
    return this;
  }

  // 'private' methods

  function extractQuestionsFromPassage(passage) {
    var questions = {};

    passage.replace(/{\+([^-]+)-([^|]+)\|([^}]+)}/g, function (key, plus, minus, ruleNumber) {
      var genKey = uuid4.generate();
      questions[genKey] = {
        plus: plus,
        minus: minus,
        ruleNumber: ruleNumber
      };
      passage = passage.replace(key, genKey);
    });
    passage.replace(/{-([^|]+)\+([^-]+)\|([^}]+)}/g, function (key, minus, plus, ruleNumber) {
      var genKey = uuid4.generate();
      questions[genKey] = {
        plus: plus,
        minus: minus,
        ruleNumber: ruleNumber
      };
      passage = passage.replace(key, genKey);
    });
    return [questions, passage];
  }

  function removeNullWords(n) {
    return n !== '';
  }

  function parseHtmlTokens(w) {
    var matches = PassageWord.htmlMatches(w);
    if (matches) {
      _.each(matches, function (match) {
        if (w !== match) {
          w = w.replace(new RegExp(match, 'g'), ' ' + match + ' ');
        }
      });
      w = w.trim();
      return w.split(/\s/);
    }
    return w;
  }

  function loadConcepts(proofreadingPassage) {
    var ruleNumbers = _.chain(proofreadingPassage.questions)
                        .pluck('ruleNumber')
                        .map(parseInt)
                        .value();
    return ConceptsFBService.getByRuleNumbers(ruleNumbers);
  }

  /*
   * Convert a string of text from Firebase into a ProofreadingPassage object.
   */
  ProofreadingPassage.fromPassageString = function (passage) {
    var proofreadingPassage = new ProofreadingPassage({
      numChanges: 0,
      madeChange: false
    });

    var retVal = extractQuestionsFromPassage(passage);
    var questions = retVal[0];
    var convertedPassageText = retVal[1];

    function parseHangingPassageQuestionsWithNoSpace(w) {
      _.each(questions, function (v, key) {
        if (w !== key && w.indexOf(key) !== -1) {
          w = w.split(key).join(' ' + key).split(/\s/);
        }
      });
      return w;
    }

    function splitPassageIntoWords(w) {
      if (_.has(questions, w)) {
        var c = _.clone(questions[w]);
        c.text = c.minus;
        c.responseText = c.text;
        return new PassageWord(c);
      } else {
        return new PassageWord({
          text: w,
          responseText: w
        });
      }
    }

    function trimSpecialObjects(w) {
      w.text = w.text.trim();
      w.responseText = w.responseText.trim();
      return w;
    }

    function removeLeftoverSpaces(w) {
      return w.text !== '';
    }

    var words = _.chain(convertedPassageText.split(/\s/))
      .filter(removeNullWords)
      .map(parseHtmlTokens)
      .flatten()
      .map(parseHangingPassageQuestionsWithNoSpace)
      .flatten()
      .map(splitPassageIntoWords)
      .map(trimSpecialObjects)
      .filter(removeLeftoverSpaces)
      .value();

    proofreadingPassage.words = words;
    proofreadingPassage.questions = questions;
    return loadConcepts(proofreadingPassage).then(function (concepts) {
      proofreadingPassage.concepts = concepts;
      return proofreadingPassage;
    });
  };

  // 'Instance' methods

  ProofreadingPassage.prototype.getNumErrors = function () {
    return _.keys(this.questions).length;
  };

  ProofreadingPassage.prototype.getNumErrorsToSolve = function () {
    return Math.floor(this.getNumErrors() / 2);
  };

  ProofreadingPassage.prototype.getNumCorrect = function () {
    return _.where(this.results, {type: PassageWord.CORRECT}).length;
  };

  ProofreadingPassage.prototype.getResultRuleNumbers = function () {
    var ruleNumbers = _.chain(this.results)
      .pluck('passageEntry')
      .reject(function (r) {
        return r.type !== PassageWord.INCORRECT_ERROR;
      })
      .pluck('ruleNumber')
      .reject(_.isUndefined)
      .uniq()
      .value();
    return ruleNumbers;
  };

  /*
   * Save proofreading results to LocalStorage.
   *
   * Is there any reason not to save these to Firebase?
   */
  ProofreadingPassage.prototype.saveLocalResults = function (id) {
    var results = this.results;
    var concepts = this.concepts;

    function saveResults(r) {
      localStorageService.set('pf-' + id, r);
      localStorageService.remove('sw-' + id);
      localStorageService.remove('sw-temp-' + id);
    }

    /*
     * generate passage results for local results
     */
    function getLocalResults() {
      return _.chain(results)
        .pluck('passageEntry')
        .reject(function (pe) {
          return _.isUndefined(pe.ruleNumber);
        })
        .map(function (pe) {
          var concept = _.find(concepts, function(c) {
            var c1 = String(c.ruleNumber);
            var c2 = String(pe.ruleNumber);
            return c1 === c2;
          });
          if (!concept) {
            throw new Error('Could not find concept corresponding to rule number: ' + pe.ruleNumber);
          }
          return {
            title: concept.concept_level_0.name,
            correct: pe.type === PassageWord.CORRECT
          };
        })
        .groupBy('title')
        .map(function (entries, title) {
          return {
            concept: title,
            total: entries.length,
            correct: _.filter(entries, function (v) { return v.correct; }).length
          };
        })
        .value();
    }

    saveResults(getLocalResults());
  };

  /*
   * Mapping results for analytics
   */
  // TODO: -> ProofreadingPassage model
  ProofreadingPassage.prototype.sendResultsAnalytics = function () {
    var event = 'Press Check Answer';
    var passageResults = _.chain(this.results)
      .pluck('passageEntry')
      .map(function pick (p) {
        return _.pick(p, ['minus', 'ruleNumber', 'responseText', 'plus', 'type']);
      })
      .value();
    var correct = _.filter(passageResults, function (passageResult) {
      return passageResult.type === PassageWord.CORRECT;
    });
    var incorrect = _.filter(passageResults, function (passageResult) {
      return passageResult.type !== PassageWord.CORRECT;
    });

    var correctWords = _.map(correct, function (c) {
      return c.responseText;
    });

    var incorrectWords = _.map(incorrect, function (i) {
      return i.responseText;
    });

    var correctRuleNumbers = _.map(correct, function (c) {
      return c.ruleNumber;
    });

    var incorrectRuleNumbers = _.map(incorrect, function (i) {
      return i.ruleNumber;
    });

    var attrs = {
      correct: correct,
      incorrect: incorrect,
      correctWords: correctWords,
      correctRuleNumbers: correctRuleNumbers,
      incorrectRuleNumbers: incorrectRuleNumbers,
      incorrectWords: incorrectWords,
      score: Number(correct.length / this.results.length) * 100
    };
    $analytics.eventTrack(event, attrs);
  };

  ProofreadingPassage.prototype.submit = function () {
    var results = [];
    _.each(this.words, function (word, i) {
      if (!word.isValid()) {
        results.push({index: i, passageEntry: word, type: word.getErrorType()});
      }
      if (word.isValid() && _.has(word, 'minus')) {
        results.push({index: i, passageEntry: word, type: PassageWord.CORRECT});
      }
    });
    this.results = results;
    var numErrorsToSolve = this.getNumErrorsToSolve();
    var numErrorsFound = this.getNumCorrect();
    var numEdits = this.numChanges;
    var isFinished = numErrorsFound >= numErrorsToSolve ||  numEdits >= numErrorsToSolve;
    return isFinished;
  };

  ProofreadingPassage.prototype.onInputChange = function (word) {
    var nc = this.numChanges;
    if (word.responseText === '') {
      if (!word.countedChange) {
        nc++;
        word.countedChange = true;
      }
    } else if (word.responseText !== word.text) {
      if (!word.countedChange) {
        nc++;
      }
      word.countedChange = true;
    } else if (word.responseText === word.text && word.countedChange) {
      nc = Math.max(nc - 1, 0);
      word.countedChange = false;
    }
    this.numChanges = nc;
    if (!this.madeChange && nc > 0) {
      this.madeChange = true;
      $analytics.eventTrack('Edit One Passage Word', word);
    }
  };

  /*
   * Function to return the grammatical concept for a word
   * With v1, we are just using the rule title. In the future
   * we will make a data model change.
   */
  ProofreadingPassage.prototype.getGrammaticalConcept = function (word) {
    if (word.ruleNumber) {
      var concept = _.findWhere(this.concepts, {ruleNumber: Number(word.ruleNumber)});
      if (concept && concept.concept_level_0.name) {
        return concept.concept_level_0.name;
      }
    }
  };

  return ProofreadingPassage;
});
<commit_msg>Fixup lint errors<commit_after>'use strict';

module.exports =
angular.module('quill-grammar.services.proofreadingPassage', [
  'underscore',
  require('./../rule.js').name,
  require('./passageWord.js').name,
  'uuid4',
  'angulartics'
])
/*@ngInject*/
.factory('ProofreadingPassage', function (_, uuid4, PassageWord, RuleService, $analytics, localStorageService, ConceptsFBService) {
  function ProofreadingPassage(data) {
    if (data) {
      _.extend(this, data);
    }
    return this;
  }

  // 'private' methods

  function extractQuestionsFromPassage(passage) {
    var questions = {};

    passage.replace(/{\+([^-]+)-([^|]+)\|([^}]+)}/g, function (key, plus, minus, ruleNumber) {
      var genKey = uuid4.generate();
      questions[genKey] = {
        plus: plus,
        minus: minus,
        ruleNumber: ruleNumber
      };
      passage = passage.replace(key, genKey);
    });
    passage.replace(/{-([^|]+)\+([^-]+)\|([^}]+)}/g, function (key, minus, plus, ruleNumber) {
      var genKey = uuid4.generate();
      questions[genKey] = {
        plus: plus,
        minus: minus,
        ruleNumber: ruleNumber
      };
      passage = passage.replace(key, genKey);
    });
    return [questions, passage];
  }

  function removeNullWords(n) {
    return n !== '';
  }

  function parseHtmlTokens(w) {
    var matches = PassageWord.htmlMatches(w);
    if (matches) {
      _.each(matches, function (match) {
        if (w !== match) {
          w = w.replace(new RegExp(match, 'g'), ' ' + match + ' ');
        }
      });
      w = w.trim();
      return w.split(/\s/);
    }
    return w;
  }

  function loadConcepts(proofreadingPassage) {
    var ruleNumbers = _.chain(proofreadingPassage.questions)
                        .pluck('ruleNumber')
                        .map(parseInt)
                        .value();
    return ConceptsFBService.getByRuleNumbers(ruleNumbers);
  }

  /*
   * Convert a string of text from Firebase into a ProofreadingPassage object.
   */
  ProofreadingPassage.fromPassageString = function (passage) {
    var proofreadingPassage = new ProofreadingPassage({
      numChanges: 0,
      madeChange: false
    });

    var retVal = extractQuestionsFromPassage(passage);
    var questions = retVal[0];
    var convertedPassageText = retVal[1];

    function parseHangingPassageQuestionsWithNoSpace(w) {
      _.each(questions, function (v, key) {
        if (w !== key && w.indexOf(key) !== -1) {
          w = w.split(key).join(' ' + key).split(/\s/);
        }
      });
      return w;
    }

    function splitPassageIntoWords(w) {
      if (_.has(questions, w)) {
        var c = _.clone(questions[w]);
        c.text = c.minus;
        c.responseText = c.text;
        return new PassageWord(c);
      } else {
        return new PassageWord({
          text: w,
          responseText: w
        });
      }
    }

    function trimSpecialObjects(w) {
      w.text = w.text.trim();
      w.responseText = w.responseText.trim();
      return w;
    }

    function removeLeftoverSpaces(w) {
      return w.text !== '';
    }

    var words = _.chain(convertedPassageText.split(/\s/))
      .filter(removeNullWords)
      .map(parseHtmlTokens)
      .flatten()
      .map(parseHangingPassageQuestionsWithNoSpace)
      .flatten()
      .map(splitPassageIntoWords)
      .map(trimSpecialObjects)
      .filter(removeLeftoverSpaces)
      .value();

    proofreadingPassage.words = words;
    proofreadingPassage.questions = questions;
    return loadConcepts(proofreadingPassage).then(function (concepts) {
      proofreadingPassage.concepts = concepts;
      return proofreadingPassage;
    });
  };

  // 'Instance' methods

  ProofreadingPassage.prototype.getNumErrors = function () {
    return _.keys(this.questions).length;
  };

  ProofreadingPassage.prototype.getNumErrorsToSolve = function () {
    return Math.floor(this.getNumErrors() / 2);
  };

  ProofreadingPassage.prototype.getNumCorrect = function () {
    return _.where(this.results, {type: PassageWord.CORRECT}).length;
  };

  ProofreadingPassage.prototype.getResultRuleNumbers = function () {
    var ruleNumbers = _.chain(this.results)
      .pluck('passageEntry')
      .reject(function (r) {
        return r.type !== PassageWord.INCORRECT_ERROR;
      })
      .pluck('ruleNumber')
      .reject(_.isUndefined)
      .uniq()
      .value();
    return ruleNumbers;
  };

  /*
   * Save proofreading results to LocalStorage.
   *
   * Is there any reason not to save these to Firebase?
   */
  ProofreadingPassage.prototype.saveLocalResults = function (id) {
    var results = this.results;
    var concepts = this.concepts;

    function saveResults(r) {
      localStorageService.set('pf-' + id, r);
      localStorageService.remove('sw-' + id);
      localStorageService.remove('sw-temp-' + id);
    }

    /*
     * generate passage results for local results
     */
    function getLocalResults() {
      return _.chain(results)
        .pluck('passageEntry')
        .reject(function (pe) {
          return _.isUndefined(pe.ruleNumber);
        })
        .map(function (pe) {
          var concept = _.find(concepts, function (c) {
            var c1 = String(c.ruleNumber);
            var c2 = String(pe.ruleNumber);
            return c1 === c2;
          });
          if (!concept) {
            throw new Error('Could not find concept corresponding to rule number: ' + pe.ruleNumber);
          }
          return {
            title: concept.concept_level_0.name,
            correct: pe.type === PassageWord.CORRECT
          };
        })
        .groupBy('title')
        .map(function (entries, title) {
          return {
            concept: title,
            total: entries.length,
            correct: _.filter(entries, function (v) { return v.correct; }).length
          };
        })
        .value();
    }

    saveResults(getLocalResults());
  };

  /*
   * Mapping results for analytics
   */
  // TODO: -> ProofreadingPassage model
  ProofreadingPassage.prototype.sendResultsAnalytics = function () {
    var event = 'Press Check Answer';
    var passageResults = _.chain(this.results)
      .pluck('passageEntry')
      .map(function pick (p) {
        return _.pick(p, ['minus', 'ruleNumber', 'responseText', 'plus', 'type']);
      })
      .value();
    var correct = _.filter(passageResults, function (passageResult) {
      return passageResult.type === PassageWord.CORRECT;
    });
    var incorrect = _.filter(passageResults, function (passageResult) {
      return passageResult.type !== PassageWord.CORRECT;
    });

    var correctWords = _.map(correct, function (c) {
      return c.responseText;
    });

    var incorrectWords = _.map(incorrect, function (i) {
      return i.responseText;
    });

    var correctRuleNumbers = _.map(correct, function (c) {
      return c.ruleNumber;
    });

    var incorrectRuleNumbers = _.map(incorrect, function (i) {
      return i.ruleNumber;
    });

    var attrs = {
      correct: correct,
      incorrect: incorrect,
      correctWords: correctWords,
      correctRuleNumbers: correctRuleNumbers,
      incorrectRuleNumbers: incorrectRuleNumbers,
      incorrectWords: incorrectWords,
      score: Number(correct.length / this.results.length) * 100
    };
    $analytics.eventTrack(event, attrs);
  };

  ProofreadingPassage.prototype.submit = function () {
    var results = [];
    _.each(this.words, function (word, i) {
      if (!word.isValid()) {
        results.push({index: i, passageEntry: word, type: word.getErrorType()});
      }
      if (word.isValid() && _.has(word, 'minus')) {
        results.push({index: i, passageEntry: word, type: PassageWord.CORRECT});
      }
    });
    this.results = results;
    var numErrorsToSolve = this.getNumErrorsToSolve();
    var numErrorsFound = this.getNumCorrect();
    var numEdits = this.numChanges;
    var isFinished = numErrorsFound >= numErrorsToSolve ||  numEdits >= numErrorsToSolve;
    return isFinished;
  };

  ProofreadingPassage.prototype.onInputChange = function (word) {
    var nc = this.numChanges;
    if (word.responseText === '') {
      if (!word.countedChange) {
        nc++;
        word.countedChange = true;
      }
    } else if (word.responseText !== word.text) {
      if (!word.countedChange) {
        nc++;
      }
      word.countedChange = true;
    } else if (word.responseText === word.text && word.countedChange) {
      nc = Math.max(nc - 1, 0);
      word.countedChange = false;
    }
    this.numChanges = nc;
    if (!this.madeChange && nc > 0) {
      this.madeChange = true;
      $analytics.eventTrack('Edit One Passage Word', word);
    }
  };

  /*
   * Function to return the grammatical concept for a word
   * With v1, we are just using the rule title. In the future
   * we will make a data model change.
   */
  ProofreadingPassage.prototype.getGrammaticalConcept = function (word) {
    if (word.ruleNumber) {
      var concept = _.findWhere(this.concepts, {ruleNumber: Number(word.ruleNumber)});
      if (concept && concept.concept_level_0.name) {
        return concept.concept_level_0.name;
      }
    }
  };

  return ProofreadingPassage;
});
<|endoftext|>


<commit_before>'use strict';

module.exports = {
    exit: function (success, fail, args) {
        tizen.application.getCurrentApplication().exit();
    },
    launchApp: function (success, fail, args) {
        try {
            var paramAppId = args[0].appId;
            var paramData = args[0].data;
            var appCtrlDataAry = [];

            for(var keyName in paramData) {
                var temp = new tizen.ApplicationControlData(keyName, [paramData[keyName]]);
                appCtrlDataAry.push(temp);
            }

            var appCtrl = new tizen.ApplicationControl(null, null, null, null, appCtrlDataAry);
            tizen.application.launchAppControl(appCtrl, paramAppId, success, fail, null);
        }
        catch (e) {
            var error = new Error();
            error.name = e.name;
            setTimeout(function() {
                fail(error);
            }, 0);
        }
    },
    getRequestedAppInfo: function (success, fail, args) {
        try {
            var reqAppCtrl = tizen.application.getCurrentApplication().getRequestedAppControl();
            var reqCallerAppId = reqAppCtrl.callerAppId;
            var reqAppCtrlDataAry = reqAppCtrl.appControl.data;
            var appCtrlDataObj = {};

            for(var i = 0; i < reqAppCtrlDataAry.length; i++) {
                var key = reqAppCtrlDataAry[i].key;
                var value = (reqAppCtrlDataAry[i].value)[0];
                appCtrlDataObj[key] = value;
            }

            setTimeout(function() {
                success({callerAppId: reqCallerAppId, data: appCtrlDataObj});
            }, 0);
        }
        catch(e) {
            var error = new Error();
            error.name = e.name;
            setTimeout(function() {
                fail(error);
            }, 0);
        }
    }
};

require('cordova/exec/proxy').add('toast.application', module.exports);
<commit_msg>Fix the bug when caller jump to browser in launchApp()<commit_after>'use strict';

module.exports = {
    exit: function (success, fail, args) {
        tizen.application.getCurrentApplication().exit();
    },
    launchApp: function (success, fail, args) {
        try {
            var paramAppId = args[0].appId;
            var paramData = args[0].data;
            var appCtrlDataAry = [];

            for(var keyName in paramData) {
                var temp = new tizen.ApplicationControlData(keyName, [paramData[keyName]]);
                appCtrlDataAry.push(temp);
            }

            if(paramAppId == 'org.tizen.browser') { // Jump to browser
                var browserAppCtrl = new tizen.ApplicationControl(null, (appCtrlDataAry[0].value)[0], null, null, appCtrlDataAry);
                tizen.application.launchAppControl(browserAppCtrl, paramAppId, success, fail, null);
            }
            else { // Jump to widget
                var widgetAppCtrl = new tizen.ApplicationControl(null, null, null, null, appCtrlDataAry);
                tizen.application.launchAppControl(widgetAppCtrl, paramAppId, success, fail, null);
            }
        }
        catch (e) {
            var error = new Error();
            error.name = e.name;
            setTimeout(function() {
                fail(error);
            }, 0);
        }
    },
    getRequestedAppInfo: function (success, fail, args) {
        try {
            var reqAppCtrl = tizen.application.getCurrentApplication().getRequestedAppControl();
            var reqCallerAppId = reqAppCtrl.callerAppId;
            var reqAppCtrlDataAry = reqAppCtrl.appControl.data;
            var appCtrlDataObj = {};

            for(var i = 0; i < reqAppCtrlDataAry.length; i++) {
                var key = reqAppCtrlDataAry[i].key;
                var value = (reqAppCtrlDataAry[i].value)[0];
                appCtrlDataObj[key] = value;
            }

            setTimeout(function() {
                success({callerAppId: reqCallerAppId, data: appCtrlDataObj});
            }, 0);
        }
        catch(e) {
            var error = new Error();
            error.name = e.name;
            setTimeout(function() {
                fail(error);
            }, 0);
        }
    }
};

require('cordova/exec/proxy').add('toast.application', module.exports);
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const _ = require('lodash');
const Meter = require('../models/Meter');
const Reading = require('../models/Reading');
const readMamacData = require('./readMamacData');
const log = require('../log');

/**
 * Pulls new data for all the meters in the database.
 * This assumes that every meter is a MAMAC meter with a valid IP address.
 */
async function updateAllMeters() {
	const time = new Date();
	log(`Getting meter data ${time.toISOString()}`);
	try {
		const allMeters = await Meter.getAll();
		const metersToUpdate = allMeters.filter(m => m.enabled && m.type === Meter.type.MAMAC);

		// Do all the network requests in parallel, then throw out any requests that fail after logging the errors.
		const readingInsertBatches = _.filter(await Promise.all(
			metersToUpdate
				.map(readMamacData)
				.map(p => p.catch(err => {
					const uri = err.options !== undefined ? err.options.uri : '[NO URI AVAILABLE]';
					log(`ERROR ON REQUEST TO ${uri}, ${err.message}`, 'error');
					return null;
				}))
		), elem => elem !== null);

		// Flatten the batches (an array of arrays) into a single array.
		const allReadingsToInsert = [].concat(...readingInsertBatches);
		await Reading.insertOrUpdateAll(allReadingsToInsert);
		log('Update finished');
	} catch (err) {
		log(`Error updating all meters: ${err}`, 'error');
	}
}

module.exports = updateAllMeters;
<commit_msg>Remove use of ternary operator<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const _ = require('lodash');
const Meter = require('../models/Meter');
const Reading = require('../models/Reading');
const readMamacData = require('./readMamacData');
const log = require('../log');

/**
 * Pulls new data for all the meters in the database.
 * This assumes that every meter is a MAMAC meter with a valid IP address.
 */
async function updateAllMeters() {
	const time = new Date();
	log(`Getting meter data ${time.toISOString()}`);
	try {
		const allMeters = await Meter.getAll();
		const metersToUpdate = allMeters.filter(m => m.enabled && m.type === Meter.type.MAMAC);

		// Do all the network requests in parallel, then throw out any requests that fail after logging the errors.
		const readingInsertBatches = _.filter(await Promise.all(
			metersToUpdate
				.map(readMamacData)
				.map(p => p.catch(err => {
					let uri = '[NO URI AVAILABLE]';
					if (err.options !== undefined && err.options.uri !== undefined) {
						uri = err.options.uri;
					}
					log(`ERROR ON REQUEST TO ${uri}, ${err.message}`, 'error');
					return null;
				}))
		), elem => elem !== null);

		// Flatten the batches (an array of arrays) into a single array.
		const allReadingsToInsert = [].concat(...readingInsertBatches);
		await Reading.insertOrUpdateAll(allReadingsToInsert);
		log('Update finished');
	} catch (err) {
		log(`Error updating all meters: ${err}`, 'error');
	}
}

module.exports = updateAllMeters;
<|endoftext|>


<commit_before>/*
 * L.Control.Layers is a control to allow users to switch between different layers on the map.
 */

L.Control.Layers = L.Control.extend({
	options: {
		collapsed: true,
		position: 'topright',
		autoZIndex: true
	},

	initialize: function (baseLayers, overlays, options) {
		L.setOptions(this, options);

		this._layers = {};
		this._lastZIndex = 0;
		this._handlingClick = false;

		for (var i in baseLayers) {
			this._addLayer(baseLayers[i], i);
		}

		for (i in overlays) {
			this._addLayer(overlays[i], i, true);
		}
	},

	onAdd: function (map) {
		this._initLayout();
		this._update();

		map
		    .on('layeradd', this._onLayerChange, this)
		    .on('layerremove', this._onLayerChange, this);

		return this._container;
	},

	onRemove: function (map) {
		map
		    .off('layeradd', this._onLayerChange)
		    .off('layerremove', this._onLayerChange);
	},

	addBaseLayer: function (layer, name) {
		this._addLayer(layer, name);
		this._update();
		return this;
	},

	addOverlay: function (layer, name) {
		this._addLayer(layer, name, true);
		this._update();
		return this;
	},

	removeLayer: function (layer) {
		var id = L.stamp(layer);
		delete this._layers[id];
		this._update();
		return this;
	},

	_initLayout: function () {
		var className = 'leaflet-control-layers',
		    container = this._container = L.DomUtil.create('div', className);

		//Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released
		container.setAttribute('aria-haspopup', true);

		if (!L.Browser.touch) {
			L.DomEvent.disableClickPropagation(container);
			L.DomEvent.on(container, 'mousewheel', L.DomEvent.stopPropagation);
		} else {
			L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
		}

		var form = this._form = L.DomUtil.create('form', className + '-list');

		if (this.options.collapsed) {
			L.DomEvent
			    .on(container, 'mouseover', this._expand, this)
			    .on(container, 'mouseout', this._collapse, this);

			var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
			link.href = '#';
			link.title = 'Layers';

			if (L.Browser.touch) {
				L.DomEvent
				    .on(link, 'click', L.DomEvent.stop)
				    .on(link, 'click', this._expand, this);
			}
			else {
				L.DomEvent.on(link, 'focus', this._expand, this);
			}

			this._map.on('click', this._collapse, this);
			// TODO keyboard accessibility
		} else {
			this._expand();
		}

		this._baseLayersList = L.DomUtil.create('div', className + '-base', form);
		this._separator = L.DomUtil.create('div', className + '-separator', form);
		this._overlaysList = L.DomUtil.create('div', className + '-overlays', form);

		container.appendChild(form);
	},

	_addLayer: function (layer, name, overlay) {
		var id = L.stamp(layer);

		this._layers[id] = {
			layer: layer,
			name: name,
			overlay: overlay
		};

		if (this.options.autoZIndex && layer.setZIndex) {
			this._lastZIndex++;
			layer.setZIndex(this._lastZIndex);
		}
	},

	_update: function () {
		if (!this._container) {
			return;
		}

		this._baseLayersList.innerHTML = '';
		this._overlaysList.innerHTML = '';

		var baseLayersPresent = false,
		    overlaysPresent = false,
		    i, obj;

		for (i in this._layers) {
			obj = this._layers[i];
			this._addItem(obj);
			overlaysPresent = overlaysPresent || obj.overlay;
			baseLayersPresent = baseLayersPresent || !obj.overlay;
		}

		this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
	},

	_onLayerChange: function (e) {
		var obj = this._layers[L.stamp(e.layer)];

		if (!obj) { return; }

		if (!this._handlingClick) {
			this._update();
		}

		var type = obj.overlay ?
			(e.type === 'layeradd' ? 'overlayadd' : 'overlayremove') :
			(e.type === 'layeradd' ? 'baselayerchange' : null);

		if (type) {
			this._map.fire(type, obj);
		}
	},

	// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
	_createRadioElement: function (name, checked) {

		var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' + name + '"';
		if (checked) {
			radioHtml += ' checked="checked"';
		}
		radioHtml += '/>';

		var radioFragment = document.createElement('div');
		radioFragment.innerHTML = radioHtml;

		return radioFragment.firstChild;
	},

	_addItem: function (obj) {
		var label = document.createElement('label'),
		    input,
		    checked = this._map.hasLayer(obj.layer);

		if (obj.overlay) {
			input = document.createElement('input');
			input.type = 'checkbox';
			input.className = 'leaflet-control-layers-selector';
			input.defaultChecked = checked;
		} else {
			input = this._createRadioElement('leaflet-base-layers', checked);
		}

		input.layerId = L.stamp(obj.layer);

		L.DomEvent.on(input, 'click', this._onInputClick, this);

		var name = document.createElement('span');
		name.innerHTML = ' ' + obj.name;

		label.appendChild(input);
		label.appendChild(name);

		var container = obj.overlay ? this._overlaysList : this._baseLayersList;
		container.appendChild(label);

		return label;
	},

	_onInputClick: function () {
		var i, input, obj,
		    inputs = this._form.getElementsByTagName('input'),
		    inputsLen = inputs.length;

		this._handlingClick = true;

		for (i = 0; i < inputsLen; i++) {
			input = inputs[i];
			obj = this._layers[input.layerId];

			if (input.checked && !this._map.hasLayer(obj.layer)) {
				this._map.addLayer(obj.layer);

			} else if (!input.checked && this._map.hasLayer(obj.layer)) {
				this._map.removeLayer(obj.layer);
			}
		}

		this._handlingClick = false;
	},

	_expand: function () {
		L.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded');
	},

	_collapse: function () {
		this._container.className = this._container.className.replace(' leaflet-control-layers-expanded', '');
	}
});

L.control.layers = function (baseLayers, overlays, options) {
	return new L.Control.Layers(baseLayers, overlays, options);
};
<commit_msg>Don't add mouseover/out listeners to the layers control on android, otherwise your first touch will do mouseover, showing the list and click, clicking an item. Fixes #1694<commit_after>/*
 * L.Control.Layers is a control to allow users to switch between different layers on the map.
 */

L.Control.Layers = L.Control.extend({
	options: {
		collapsed: true,
		position: 'topright',
		autoZIndex: true
	},

	initialize: function (baseLayers, overlays, options) {
		L.setOptions(this, options);

		this._layers = {};
		this._lastZIndex = 0;
		this._handlingClick = false;

		for (var i in baseLayers) {
			this._addLayer(baseLayers[i], i);
		}

		for (i in overlays) {
			this._addLayer(overlays[i], i, true);
		}
	},

	onAdd: function (map) {
		this._initLayout();
		this._update();

		map
		    .on('layeradd', this._onLayerChange, this)
		    .on('layerremove', this._onLayerChange, this);

		return this._container;
	},

	onRemove: function (map) {
		map
		    .off('layeradd', this._onLayerChange)
		    .off('layerremove', this._onLayerChange);
	},

	addBaseLayer: function (layer, name) {
		this._addLayer(layer, name);
		this._update();
		return this;
	},

	addOverlay: function (layer, name) {
		this._addLayer(layer, name, true);
		this._update();
		return this;
	},

	removeLayer: function (layer) {
		var id = L.stamp(layer);
		delete this._layers[id];
		this._update();
		return this;
	},

	_initLayout: function () {
		var className = 'leaflet-control-layers',
		    container = this._container = L.DomUtil.create('div', className);

		//Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released
		container.setAttribute('aria-haspopup', true);

		if (!L.Browser.touch) {
			L.DomEvent.disableClickPropagation(container);
			L.DomEvent.on(container, 'mousewheel', L.DomEvent.stopPropagation);
		} else {
			L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
		}

		var form = this._form = L.DomUtil.create('form', className + '-list');

		if (this.options.collapsed) {
			if (!L.Browser.android) {
				L.DomEvent
				    .on(container, 'mouseover', this._expand, this)
				    .on(container, 'mouseout', this._collapse, this);
			}
			var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
			link.href = '#';
			link.title = 'Layers';

			if (L.Browser.touch) {
				L.DomEvent
				    .on(link, 'click', L.DomEvent.stop)
				    .on(link, 'click', this._expand, this);
			}
			else {
				L.DomEvent.on(link, 'focus', this._expand, this);
			}

			this._map.on('click', this._collapse, this);
			// TODO keyboard accessibility
		} else {
			this._expand();
		}

		this._baseLayersList = L.DomUtil.create('div', className + '-base', form);
		this._separator = L.DomUtil.create('div', className + '-separator', form);
		this._overlaysList = L.DomUtil.create('div', className + '-overlays', form);

		container.appendChild(form);
	},

	_addLayer: function (layer, name, overlay) {
		var id = L.stamp(layer);

		this._layers[id] = {
			layer: layer,
			name: name,
			overlay: overlay
		};

		if (this.options.autoZIndex && layer.setZIndex) {
			this._lastZIndex++;
			layer.setZIndex(this._lastZIndex);
		}
	},

	_update: function () {
		if (!this._container) {
			return;
		}

		this._baseLayersList.innerHTML = '';
		this._overlaysList.innerHTML = '';

		var baseLayersPresent = false,
		    overlaysPresent = false,
		    i, obj;

		for (i in this._layers) {
			obj = this._layers[i];
			this._addItem(obj);
			overlaysPresent = overlaysPresent || obj.overlay;
			baseLayersPresent = baseLayersPresent || !obj.overlay;
		}

		this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
	},

	_onLayerChange: function (e) {
		var obj = this._layers[L.stamp(e.layer)];

		if (!obj) { return; }

		if (!this._handlingClick) {
			this._update();
		}

		var type = obj.overlay ?
			(e.type === 'layeradd' ? 'overlayadd' : 'overlayremove') :
			(e.type === 'layeradd' ? 'baselayerchange' : null);

		if (type) {
			this._map.fire(type, obj);
		}
	},

	// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
	_createRadioElement: function (name, checked) {

		var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' + name + '"';
		if (checked) {
			radioHtml += ' checked="checked"';
		}
		radioHtml += '/>';

		var radioFragment = document.createElement('div');
		radioFragment.innerHTML = radioHtml;

		return radioFragment.firstChild;
	},

	_addItem: function (obj) {
		var label = document.createElement('label'),
		    input,
		    checked = this._map.hasLayer(obj.layer);

		if (obj.overlay) {
			input = document.createElement('input');
			input.type = 'checkbox';
			input.className = 'leaflet-control-layers-selector';
			input.defaultChecked = checked;
		} else {
			input = this._createRadioElement('leaflet-base-layers', checked);
		}

		input.layerId = L.stamp(obj.layer);

		L.DomEvent.on(input, 'click', this._onInputClick, this);

		var name = document.createElement('span');
		name.innerHTML = ' ' + obj.name;

		label.appendChild(input);
		label.appendChild(name);

		var container = obj.overlay ? this._overlaysList : this._baseLayersList;
		container.appendChild(label);

		return label;
	},

	_onInputClick: function () {
		var i, input, obj,
		    inputs = this._form.getElementsByTagName('input'),
		    inputsLen = inputs.length;

		this._handlingClick = true;

		for (i = 0; i < inputsLen; i++) {
			input = inputs[i];
			obj = this._layers[input.layerId];

			if (input.checked && !this._map.hasLayer(obj.layer)) {
				this._map.addLayer(obj.layer);

			} else if (!input.checked && this._map.hasLayer(obj.layer)) {
				this._map.removeLayer(obj.layer);
			}
		}

		this._handlingClick = false;
	},

	_expand: function () {
		L.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded');
	},

	_collapse: function () {
		this._container.className = this._container.className.replace(' leaflet-control-layers-expanded', '');
	}
});

L.control.layers = function (baseLayers, overlays, options) {
	return new L.Control.Layers(baseLayers, overlays, options);
};
<|endoftext|>


<commit_before>/*
 * L.Control.Layers is a control to allow users to switch between different layers on the map.
 */

L.Control.Layers = L.Control.extend({
	options: {
		collapsed: true,
		position: 'topright',
		autoZIndex: true
	},

	initialize: function (baseLayers, overlays, options) {
		L.setOptions(this, options);

		this._layers = {};
		this._lastZIndex = 0;
		this._handlingClick = false;

		for (var i in baseLayers) {
			this._addLayer(baseLayers[i], i);
		}

		for (i in overlays) {
			this._addLayer(overlays[i], i, true);
		}
	},

	onAdd: function (map) {
		this._initLayout();
		this._update();

		map
		    .on('layeradd', this._onLayerChange, this)
		    .on('layerremove', this._onLayerChange, this);

		return this._container;
	},

	onRemove: function (map) {
		map
		    .off('layeradd', this._onLayerChange)
		    .off('layerremove', this._onLayerChange);
	},

	addBaseLayer: function (layer, name) {
		this._addLayer(layer, name);
		this._update();
		return this;
	},

	addOverlay: function (layer, name) {
		this._addLayer(layer, name, true);
		this._update();
		return this;
	},

	removeLayer: function (layer) {
		var id = L.stamp(layer);
		delete this._layers[id];
		this._update();
		return this;
	},

	_initLayout: function () {
		var className = 'leaflet-control-layers',
		    container = this._container = L.DomUtil.create('div', className);

		//Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released
		container.setAttribute('aria-haspopup', true);

		if (!L.Browser.touch) {
			L.DomEvent
				.disableClickPropagation(container)
				.disableScrollPropagation(container);
		} else {
			L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
		}

		var form = this._form = L.DomUtil.create('form', className + '-list');

		if (this.options.collapsed) {
			if (!L.Browser.android) {
				L.DomEvent
				    .on(container, 'mouseover', this._expand, this)
				    .on(container, 'mouseout', this._collapse, this);
			}
			var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
			link.href = '#';
			link.title = 'Layers';

			if (L.Browser.touch) {
				L.DomEvent
				    .on(link, 'click', L.DomEvent.stop)
				    .on(link, 'click', this._expand, this);
			}
			else {
				L.DomEvent.on(link, 'focus', this._expand, this);
			}
			L.DomEvent.on(form, 'click', function () {
				var that = this;
				setTimeout(function () {
					//alert('l');

					that._onInputClick();
				}, 0);
			}, this);

			this._map.on('click', this._collapse, this);
			// TODO keyboard accessibility
		} else {
			this._expand();
		}

		this._baseLayersList = L.DomUtil.create('div', className + '-base', form);
		this._separator = L.DomUtil.create('div', className + '-separator', form);
		this._overlaysList = L.DomUtil.create('div', className + '-overlays', form);

		container.appendChild(form);
	},

	_addLayer: function (layer, name, overlay) {
		var id = L.stamp(layer);

		this._layers[id] = {
			layer: layer,
			name: name,
			overlay: overlay
		};

		if (this.options.autoZIndex && layer.setZIndex) {
			this._lastZIndex++;
			layer.setZIndex(this._lastZIndex);
		}
	},

	_update: function () {
		if (!this._container) {
			return;
		}

		this._baseLayersList.innerHTML = '';
		this._overlaysList.innerHTML = '';

		var baseLayersPresent = false,
		    overlaysPresent = false,
		    i, obj;

		for (i in this._layers) {
			obj = this._layers[i];
			this._addItem(obj);
			overlaysPresent = overlaysPresent || obj.overlay;
			baseLayersPresent = baseLayersPresent || !obj.overlay;
		}

		this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
	},

	_onLayerChange: function (e) {
		var obj = this._layers[L.stamp(e.layer)];

		if (!obj) { return; }

		if (!this._handlingClick) {
			this._update();
		}

		var type = obj.overlay ?
			(e.type === 'layeradd' ? 'overlayadd' : 'overlayremove') :
			(e.type === 'layeradd' ? 'baselayerchange' : null);

		if (type) {
			this._map.fire(type, obj);
		}
	},

	// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
	_createRadioElement: function (name, checked) {

		var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' + name + '"';
		if (checked) {
			radioHtml += ' checked="checked"';
		}
		radioHtml += '/>';

		var radioFragment = document.createElement('div');
		radioFragment.innerHTML = radioHtml;

		return radioFragment.firstChild;
	},

	_addItem: function (obj) {
		var label = document.createElement('label'),
		    input,
		    checked = this._map.hasLayer(obj.layer);

		if (obj.overlay) {
			input = document.createElement('input');
			input.type = 'checkbox';
			input.className = 'leaflet-control-layers-selector';
			input.defaultChecked = checked;
		} else {
			input = this._createRadioElement('leaflet-base-layers', checked);
		}

		input.layerId = L.stamp(obj.layer);

		L.DomEvent.on(input, 'click', this._onInputClick, this);

		var name = document.createElement('span');
		name.innerHTML = ' ' + obj.name;

		label.appendChild(input);
		label.appendChild(name);

		var container = obj.overlay ? this._overlaysList : this._baseLayersList;
		container.appendChild(label);

		return label;
	},

	_onInputClick: function () {
		var i, input, obj,
		    inputs = this._form.getElementsByTagName('input'),
		    inputsLen = inputs.length;

		this._handlingClick = true;

		for (i = 0; i < inputsLen; i++) {
			input = inputs[i];
			obj = this._layers[input.layerId];

			if (input.checked && !this._map.hasLayer(obj.layer)) {
				this._map.addLayer(obj.layer);

			} else if (!input.checked && this._map.hasLayer(obj.layer)) {
				this._map.removeLayer(obj.layer);
			}
		}

		this._handlingClick = false;
	},

	_expand: function () {
		L.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded');
	},

	_collapse: function () {
		this._container.className = this._container.className.replace(' leaflet-control-layers-expanded', '');
	}
});

L.control.layers = function (baseLayers, overlays, options) {
	return new L.Control.Layers(baseLayers, overlays, options);
};
<commit_msg>Comment why this hack exists and improve it with @mourner code :)<commit_after>/*
 * L.Control.Layers is a control to allow users to switch between different layers on the map.
 */

L.Control.Layers = L.Control.extend({
	options: {
		collapsed: true,
		position: 'topright',
		autoZIndex: true
	},

	initialize: function (baseLayers, overlays, options) {
		L.setOptions(this, options);

		this._layers = {};
		this._lastZIndex = 0;
		this._handlingClick = false;

		for (var i in baseLayers) {
			this._addLayer(baseLayers[i], i);
		}

		for (i in overlays) {
			this._addLayer(overlays[i], i, true);
		}
	},

	onAdd: function (map) {
		this._initLayout();
		this._update();

		map
		    .on('layeradd', this._onLayerChange, this)
		    .on('layerremove', this._onLayerChange, this);

		return this._container;
	},

	onRemove: function (map) {
		map
		    .off('layeradd', this._onLayerChange)
		    .off('layerremove', this._onLayerChange);
	},

	addBaseLayer: function (layer, name) {
		this._addLayer(layer, name);
		this._update();
		return this;
	},

	addOverlay: function (layer, name) {
		this._addLayer(layer, name, true);
		this._update();
		return this;
	},

	removeLayer: function (layer) {
		var id = L.stamp(layer);
		delete this._layers[id];
		this._update();
		return this;
	},

	_initLayout: function () {
		var className = 'leaflet-control-layers',
		    container = this._container = L.DomUtil.create('div', className);

		//Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released
		container.setAttribute('aria-haspopup', true);

		if (!L.Browser.touch) {
			L.DomEvent
				.disableClickPropagation(container)
				.disableScrollPropagation(container);
		} else {
			L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
		}

		var form = this._form = L.DomUtil.create('form', className + '-list');

		if (this.options.collapsed) {
			if (!L.Browser.android) {
				L.DomEvent
				    .on(container, 'mouseover', this._expand, this)
				    .on(container, 'mouseout', this._collapse, this);
			}
			var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
			link.href = '#';
			link.title = 'Layers';

			if (L.Browser.touch) {
				L.DomEvent
				    .on(link, 'click', L.DomEvent.stop)
				    .on(link, 'click', this._expand, this);
			}
			else {
				L.DomEvent.on(link, 'focus', this._expand, this);
			}
			//Work around for Firefox android issue https://github.com/Leaflet/Leaflet/issues/2033
			L.DomEvent.on(form, 'click', function () {
				setTimeout(L.bind(this._onInputClick, this), 0);
			}, this);

			this._map.on('click', this._collapse, this);
			// TODO keyboard accessibility
		} else {
			this._expand();
		}

		this._baseLayersList = L.DomUtil.create('div', className + '-base', form);
		this._separator = L.DomUtil.create('div', className + '-separator', form);
		this._overlaysList = L.DomUtil.create('div', className + '-overlays', form);

		container.appendChild(form);
	},

	_addLayer: function (layer, name, overlay) {
		var id = L.stamp(layer);

		this._layers[id] = {
			layer: layer,
			name: name,
			overlay: overlay
		};

		if (this.options.autoZIndex && layer.setZIndex) {
			this._lastZIndex++;
			layer.setZIndex(this._lastZIndex);
		}
	},

	_update: function () {
		if (!this._container) {
			return;
		}

		this._baseLayersList.innerHTML = '';
		this._overlaysList.innerHTML = '';

		var baseLayersPresent = false,
		    overlaysPresent = false,
		    i, obj;

		for (i in this._layers) {
			obj = this._layers[i];
			this._addItem(obj);
			overlaysPresent = overlaysPresent || obj.overlay;
			baseLayersPresent = baseLayersPresent || !obj.overlay;
		}

		this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
	},

	_onLayerChange: function (e) {
		var obj = this._layers[L.stamp(e.layer)];

		if (!obj) { return; }

		if (!this._handlingClick) {
			this._update();
		}

		var type = obj.overlay ?
			(e.type === 'layeradd' ? 'overlayadd' : 'overlayremove') :
			(e.type === 'layeradd' ? 'baselayerchange' : null);

		if (type) {
			this._map.fire(type, obj);
		}
	},

	// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
	_createRadioElement: function (name, checked) {

		var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' + name + '"';
		if (checked) {
			radioHtml += ' checked="checked"';
		}
		radioHtml += '/>';

		var radioFragment = document.createElement('div');
		radioFragment.innerHTML = radioHtml;

		return radioFragment.firstChild;
	},

	_addItem: function (obj) {
		var label = document.createElement('label'),
		    input,
		    checked = this._map.hasLayer(obj.layer);

		if (obj.overlay) {
			input = document.createElement('input');
			input.type = 'checkbox';
			input.className = 'leaflet-control-layers-selector';
			input.defaultChecked = checked;
		} else {
			input = this._createRadioElement('leaflet-base-layers', checked);
		}

		input.layerId = L.stamp(obj.layer);

		L.DomEvent.on(input, 'click', this._onInputClick, this);

		var name = document.createElement('span');
		name.innerHTML = ' ' + obj.name;

		label.appendChild(input);
		label.appendChild(name);

		var container = obj.overlay ? this._overlaysList : this._baseLayersList;
		container.appendChild(label);

		return label;
	},

	_onInputClick: function () {
		var i, input, obj,
		    inputs = this._form.getElementsByTagName('input'),
		    inputsLen = inputs.length;

		this._handlingClick = true;

		for (i = 0; i < inputsLen; i++) {
			input = inputs[i];
			obj = this._layers[input.layerId];

			if (input.checked && !this._map.hasLayer(obj.layer)) {
				this._map.addLayer(obj.layer);

			} else if (!input.checked && this._map.hasLayer(obj.layer)) {
				this._map.removeLayer(obj.layer);
			}
		}

		this._handlingClick = false;
	},

	_expand: function () {
		L.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded');
	},

	_collapse: function () {
		this._container.className = this._container.className.replace(' leaflet-control-layers-expanded', '');
	}
});

L.control.layers = function (baseLayers, overlays, options) {
	return new L.Control.Layers(baseLayers, overlays, options);
};
<|endoftext|>