<commit_before>process.env.NODE_ENV = 'development';

// Load environment variables from .env file. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set.
// https://github.com/motdotla/dotenv
require('dotenv').config({silent: true});

var chalk = require('chalk');
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var historyApiFallback = require('connect-history-api-fallback');
var httpProxyMiddleware = require('http-proxy-middleware');
var detect = require('detect-port');
//var clearConsole = require('react-dev-utils/clearConsole');
var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
var formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
var openBrowser = require('react-dev-utils/openBrowser');
var config = require('../config/webpack.config.dev');
var paths = require('../config/paths');

// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
  process.exit(1);
}

// Tools like Cloud9 rely on this.
var DEFAULT_PORT = process.env.PORT || 3000;
var compiler;
var handleCompile;

// You can safely remove this after ejecting.
// We only use this block for testing of Create React App itself:
var isSmokeTest = process.argv.some(arg => arg.indexOf('--smoke-test') > -1);
if (isSmokeTest) {
  handleCompile = function (err, stats) {
    if (err || stats.hasErrors() || stats.hasWarnings()) {
      process.exit(1);
    } else {
      process.exit(0);
    }
  };
}

function setupCompiler(host, port, protocol) {
  // "Compiler" is a low-level interface to Webpack.
  // It lets us listen to some events and provide our own custom messages.
  compiler = webpack(config, handleCompile);

  // "invalid" event fires when you have changed a file, and Webpack is
  // recompiling a bundle. WebpackDevServer takes care to pause serving the
  // bundle, so if you refresh, it'll wait instead of serving the old one.
  // "invalid" is short for "bundle invalidated", it doesn't imply any errors.
  compiler.plugin('invalid', function() {
    //clearConsole();
    console.log('Compiling...');
  });

  // "done" event fires when Webpack has finished recompiling the bundle.
  // Whether or not you have warnings or errors, you will get this event.
  compiler.plugin('done', function(stats) {
    //clearConsole();

    // We have switched off the default Webpack output in WebpackDevServer
    // options so we are going to "massage" the warnings and errors and present
    // them in a readable focused way.
    var messages = formatWebpackMessages(stats.toJson({}, true));
    if (!messages.errors.length && !messages.warnings.length) {
      console.log(chalk.green('Compiled successfully!'));
      console.log();
      console.log('The app is running at:');
      console.log();
      console.log('  ' + chalk.cyan(protocol + '://' + host + ':' + port + '/'));
      console.log();
      console.log('Note that the development build is not optimized.');
      console.log('To create a production build, use ' + chalk.cyan('npm run build') + '.');
      console.log();
    }

    // If errors exist, only show errors.
    if (messages.errors.length) {
      console.log(chalk.red('Failed to compile.'));
      console.log();
      messages.errors.forEach(message => {
        console.log(message);
        console.log();
      });
      return;
    }

    // Show warnings if no errors were found.
    if (messages.warnings.length) {
      console.log(chalk.yellow('Compiled with warnings.'));
      console.log();
      messages.warnings.forEach(message => {
        console.log(message);
        console.log();
      });
      // Teach some ESLint tricks.
      console.log('You may use special comments to disable some warnings.');
      console.log('Use ' + chalk.yellow('// eslint-disable-next-line') + ' to ignore the next line.');
      console.log('Use ' + chalk.yellow('/* eslint-disable */') + ' to ignore all warnings in a file.');
    }
  });
}

// We need to provide a custom onError function for httpProxyMiddleware.
// It allows us to log custom error messages on the console.
function onProxyError(proxy) {
  return function(err, req, res){
    var host = req.headers && req.headers.host;
    console.log(
      chalk.red('Proxy error:') + ' Could not proxy request ' + chalk.cyan(req.url) +
      ' from ' + chalk.cyan(host) + ' to ' + chalk.cyan(proxy) + '.'
    );
    console.log(
      'See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (' +
      chalk.cyan(err.code) + ').'
    );
    console.log();

    // And immediately send the proper error response to the client.
    // Otherwise, the request will eventually timeout with ERR_EMPTY_RESPONSE on the client side.
    if (res.writeHead && !res.headersSent) {
        res.writeHead(500);
    }
    res.end('Proxy error: Could not proxy request ' + req.url + ' from ' +
      host + ' to ' + proxy + ' (' + err.code + ').'
    );
  }
}

function addMiddleware(devServer) {
  // `proxy` lets you to specify a fallback server during development.
  // Every unrecognized request will be forwarded to it.
  var proxy = require(paths.appPackageJson).proxy;
  devServer.use(historyApiFallback({
    // Paths with dots should still use the history fallback.
    // See https://github.com/facebookincubator/create-react-app/issues/387.
    disableDotRule: true,
    // For single page apps, we generally want to fallback to /index.html.
    // However we also want to respect `proxy` for API calls.
    // So if `proxy` is specified, we need to decide which fallback to use.
    // We use a heuristic: if request `accept`s text/html, we pick /index.html.
    // Modern browsers include text/html into `accept` header when navigating.
    // However API calls like `fetch()` won’t generally accept text/html.
    // If this heuristic doesn’t work well for you, don’t use `proxy`.
    htmlAcceptHeaders: proxy ?
      ['text/html'] :
      ['text/html', '*/*']
  }));
  if (proxy) {
    if (typeof proxy !== 'string') {
      console.log(chalk.red('When specified, "proxy" in package.json must be a string.'));
      console.log(chalk.red('Instead, the type of "proxy" was "' + typeof proxy + '".'));
      console.log(chalk.red('Either remove "proxy" from package.json, or make it a string.'));
      process.exit(1);
    }

    // Otherwise, if proxy is specified, we will let it handle any request.
    // There are a few exceptions which we won't send to the proxy:
    // - /index.html (served as HTML5 history API fallback)
    // - /*.hot-update.json (WebpackDevServer uses this too for hot reloading)
    // - /sockjs-node/* (WebpackDevServer uses this for hot reloading)
    // Tip: use https://jex.im/regulex/ to visualize the regex
    var mayProxy = /^(?!\/(index\.html$|.*\.hot-update\.json$|sockjs-node\/)).*$/;
    devServer.use(mayProxy,
      // Pass the scope regex both to Express and to the middleware for proxying
      // of both HTTP and WebSockets to work without false positives.
      httpProxyMiddleware(pathname => mayProxy.test(pathname), {
        target: proxy,
        logLevel: 'silent',
        onError: onProxyError(proxy),
        secure: false,
        changeOrigin: true
      })
    );
  }
  // Finally, by now we have certainly resolved the URL.
  // It may be /index.html, so let the dev server try serving it again.
  devServer.use(devServer.middleware);
}

function runDevServer(host, port, protocol) {
  var devServer = new WebpackDevServer(compiler, {
    // Silence WebpackDevServer's own logs since they're generally not useful.
    // It will still show compile warnings and errors with this setting.
    clientLogLevel: 'none',
    // By default WebpackDevServer serves physical files from current directory
    // in addition to all the virtual build products that it serves from memory.
    // This is confusing because those files won’t automatically be available in
    // production build folder unless we copy them. However, copying the whole
    // project directory is dangerous because we may expose sensitive files.
    // Instead, we establish a convention that only files in `public` directory
    // get served. Our build script will copy `public` into the `build` folder.
    // In `index.html`, you can get URL of `public` folder with %PUBLIC_PATH%:
    // <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    // In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
    // Note that we only recommend to use `public` folder as an escape hatch
    // for files like `favicon.ico`, `manifest.json`, and libraries that are
    // for some reason broken when imported through Webpack. If you just want to
    // use an image, put it in `src` and `import` it from JavaScript instead.
    contentBase: [paths.appPublic, paths.appAssets],
    // Enable hot reloading server. It will provide /sockjs-node/ endpoint
    // for the WebpackDevServer client so it can learn when the files were
    // updated. The WebpackDevServer client is included as an entry point
    // in the Webpack development configuration. Note that only changes
    // to CSS are currently hot reloaded. JS changes will refresh the browser.
    hot: true,
    // It is important to tell WebpackDevServer to use the same "root" path
    // as we specified in the config. In development, we always serve from /.
    publicPath: config.output.publicPath,
    // WebpackDevServer is noisy by default so we emit custom message instead
    // by listening to the compiler events with `compiler.plugin` calls above.
    quiet: true,
    // Reportedly, this avoids CPU overload on some systems.
    // https://github.com/facebookincubator/create-react-app/issues/293
    watchOptions: {
      ignored: /node_modules/
    },
    // Enable HTTPS if the HTTPS environment variable is set to 'true'
    https: protocol === "https",
    host: host
  });

  // Our custom middleware proxies requests to /index.html or a remote API.
  addMiddleware(devServer);

  // Launch WebpackDevServer.
  devServer.listen(port, (err, result) => {
    if (err) {
      return console.log(err);
    }

    //clearConsole();
    console.log(chalk.cyan('Starting the development server...'));
    console.log();
    openBrowser(protocol + '://' + host + ':' + port + '/');
  });
}

function run(port) {
  var protocol = process.env.HTTPS === 'true' ? "https" : "http";
  var host = process.env.HOST || 'localhost';
  setupCompiler(host, port, protocol);
  runDevServer(host, port, protocol);
}

// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `detect()` Promise resolves to the next free port.
detect(DEFAULT_PORT).then(port => {
  if (port === DEFAULT_PORT) {
    run(port);
    return;
  }

  //clearConsole();
  var question =
    chalk.yellow('Something is already running on port ' + DEFAULT_PORT + '.') +
    '\n\nWould you like to run the app on another port instead?';
});
<commit_msg>Minor fix.<commit_after>process.env.NODE_ENV = 'development';

// Load environment variables from .env file. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set.
// https://github.com/motdotla/dotenv
require('dotenv').config({silent: true});

var chalk = require('chalk');
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var historyApiFallback = require('connect-history-api-fallback');
var httpProxyMiddleware = require('http-proxy-middleware');
var detect = require('detect-port');
//var clearConsole = require('react-dev-utils/clearConsole');
var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
var formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
var openBrowser = require('react-dev-utils/openBrowser');
var config = require('../config/webpack.config.dev');
var paths = require('../config/paths');

// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
  process.exit(1);
}

// Tools like Cloud9 rely on this.
var DEFAULT_PORT = process.env.PORT || 3000;
var compiler;
var handleCompile;

// You can safely remove this after ejecting.
// We only use this block for testing of Create React App itself:
var isSmokeTest = process.argv.some(arg => arg.indexOf('--smoke-test') > -1);
if (isSmokeTest) {
  handleCompile = function (err, stats) {
    if (err || stats.hasErrors() || stats.hasWarnings()) {
      process.exit(1);
    } else {
      process.exit(0);
    }
  };
}

function setupCompiler(host, port, protocol) {
  // "Compiler" is a low-level interface to Webpack.
  // It lets us listen to some events and provide our own custom messages.
  compiler = webpack(config, handleCompile);

  // "invalid" event fires when you have changed a file, and Webpack is
  // recompiling a bundle. WebpackDevServer takes care to pause serving the
  // bundle, so if you refresh, it'll wait instead of serving the old one.
  // "invalid" is short for "bundle invalidated", it doesn't imply any errors.
  compiler.plugin('invalid', function() {
    //clearConsole();
    console.log('Compiling...');
  });

  // "done" event fires when Webpack has finished recompiling the bundle.
  // Whether or not you have warnings or errors, you will get this event.
  compiler.plugin('done', function(stats) {
    //clearConsole();

    // We have switched off the default Webpack output in WebpackDevServer
    // options so we are going to "massage" the warnings and errors and present
    // them in a readable focused way.
    var messages = formatWebpackMessages(stats.toJson({}, true));
    if (!messages.errors.length && !messages.warnings.length) {
      console.log(chalk.green('Compiled successfully!'));
      console.log();
      console.log('The app is running at:');
      console.log();
      console.log('  ' + chalk.cyan(protocol + '://' + host + ':' + port + '/'));
      console.log();
      console.log('Note that the development build is not optimized.');
      console.log('To create a production build, use ' + chalk.cyan('npm run build') + '.');
      console.log();
    }

    // If errors exist, only show errors.
    if (messages.errors.length) {
      console.log(chalk.red('Failed to compile.'));
      console.log();
      messages.errors.forEach(message => {
        console.log(message);
        console.log();
      });
      return;
    }

    // Show warnings if no errors were found.
    if (messages.warnings.length) {
      console.log(chalk.yellow('Compiled with warnings.'));
      console.log();
      messages.warnings.forEach(message => {
        console.log(message);
        console.log();
      });
      // Teach some ESLint tricks.
      console.log('You may use special comments to disable some warnings.');
      console.log('Use ' + chalk.yellow('// eslint-disable-next-line') + ' to ignore the next line.');
      console.log('Use ' + chalk.yellow('/* eslint-disable */') + ' to ignore all warnings in a file.');
    }
  });
}

// We need to provide a custom onError function for httpProxyMiddleware.
// It allows us to log custom error messages on the console.
function onProxyError(proxy) {
  return function(err, req, res){
    var host = req.headers && req.headers.host;
    console.log(
      chalk.red('Proxy error:') + ' Could not proxy request ' + chalk.cyan(req.url) +
      ' from ' + chalk.cyan(host) + ' to ' + chalk.cyan(proxy) + '.'
    );
    console.log(
      'See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (' +
      chalk.cyan(err.code) + ').'
    );
    console.log();

    // And immediately send the proper error response to the client.
    // Otherwise, the request will eventually timeout with ERR_EMPTY_RESPONSE on the client side.
    if (res.writeHead && !res.headersSent) {
        res.writeHead(500);
    }
    res.end('Proxy error: Could not proxy request ' + req.url + ' from ' +
      host + ' to ' + proxy + ' (' + err.code + ').'
    );
  }
}

function addMiddleware(devServer) {
  // `proxy` lets you to specify a fallback server during development.
  // Every unrecognized request will be forwarded to it.
  var proxy = require(paths.appPackageJson).proxy;
  devServer.use(historyApiFallback({
    // Paths with dots should still use the history fallback.
    // See https://github.com/facebookincubator/create-react-app/issues/387.
    disableDotRule: true,
    // For single page apps, we generally want to fallback to /index.html.
    // However we also want to respect `proxy` for API calls.
    // So if `proxy` is specified, we need to decide which fallback to use.
    // We use a heuristic: if request `accept`s text/html, we pick /index.html.
    // Modern browsers include text/html into `accept` header when navigating.
    // However API calls like `fetch()` won’t generally accept text/html.
    // If this heuristic doesn’t work well for you, don’t use `proxy`.
    htmlAcceptHeaders: proxy ?
      ['text/html'] :
      ['text/html', '*/*']
  }));
  if (proxy) {
    if (typeof proxy !== 'string') {
      console.log(chalk.red('When specified, "proxy" in package.json must be a string.'));
      console.log(chalk.red('Instead, the type of "proxy" was "' + typeof proxy + '".'));
      console.log(chalk.red('Either remove "proxy" from package.json, or make it a string.'));
      process.exit(1);
    }

    // Otherwise, if proxy is specified, we will let it handle any request.
    // There are a few exceptions which we won't send to the proxy:
    // - /index.html (served as HTML5 history API fallback)
    // - /*.hot-update.json (WebpackDevServer uses this too for hot reloading)
    // - /sockjs-node/* (WebpackDevServer uses this for hot reloading)
    // Tip: use https://jex.im/regulex/ to visualize the regex
    var mayProxy = /^(?!\/(index\.html$|.*\.hot-update\.json$|sockjs-node\/)).*$/;
    devServer.use(mayProxy,
      // Pass the scope regex both to Express and to the middleware for proxying
      // of both HTTP and WebSockets to work without false positives.
      httpProxyMiddleware(pathname => mayProxy.test(pathname), {
        target: proxy,
        logLevel: 'silent',
        onError: onProxyError(proxy),
        secure: false,
        changeOrigin: true
      })
    );
  }
  // Finally, by now we have certainly resolved the URL.
  // It may be /index.html, so let the dev server try serving it again.
  devServer.use(devServer.middleware);
}

function runDevServer(host, port, protocol) {
  var devServer = new WebpackDevServer(compiler, {
    // Silence WebpackDevServer's own logs since they're generally not useful.
    // It will still show compile warnings and errors with this setting.
    clientLogLevel: 'none',
    disableHostCheck: true,
    // By default WebpackDevServer serves physical files from current directory
    // in addition to all the virtual build products that it serves from memory.
    // This is confusing because those files won’t automatically be available in
    // production build folder unless we copy them. However, copying the whole
    // project directory is dangerous because we may expose sensitive files.
    // Instead, we establish a convention that only files in `public` directory
    // get served. Our build script will copy `public` into the `build` folder.
    // In `index.html`, you can get URL of `public` folder with %PUBLIC_PATH%:
    // <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    // In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
    // Note that we only recommend to use `public` folder as an escape hatch
    // for files like `favicon.ico`, `manifest.json`, and libraries that are
    // for some reason broken when imported through Webpack. If you just want to
    // use an image, put it in `src` and `import` it from JavaScript instead.
    contentBase: [paths.appPublic, paths.appAssets],
    // Enable hot reloading server. It will provide /sockjs-node/ endpoint
    // for the WebpackDevServer client so it can learn when the files were
    // updated. The WebpackDevServer client is included as an entry point
    // in the Webpack development configuration. Note that only changes
    // to CSS are currently hot reloaded. JS changes will refresh the browser.
    hot: true,
    // It is important to tell WebpackDevServer to use the same "root" path
    // as we specified in the config. In development, we always serve from /.
    publicPath: config.output.publicPath,
    // WebpackDevServer is noisy by default so we emit custom message instead
    // by listening to the compiler events with `compiler.plugin` calls above.
    quiet: true,
    // Reportedly, this avoids CPU overload on some systems.
    // https://github.com/facebookincubator/create-react-app/issues/293
    watchOptions: {
      ignored: /node_modules/
    },
    // Enable HTTPS if the HTTPS environment variable is set to 'true'
    https: protocol === "https",
    host: host
  });

  // Our custom middleware proxies requests to /index.html or a remote API.
  addMiddleware(devServer);

  // Launch WebpackDevServer.
  devServer.listen(port, (err, result) => {
    if (err) {
      return console.log(err);
    }

    //clearConsole();
    console.log(chalk.cyan('Starting the development server...'));
    console.log();
    openBrowser(protocol + '://' + host + ':' + port + '/');
  });
}

function run(port) {
  var protocol = process.env.HTTPS === 'true' ? "https" : "http";
  var host = process.env.HOST || 'localhost';
  setupCompiler(host, port, protocol);
  runDevServer(host, port, protocol);
}

// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `detect()` Promise resolves to the next free port.
detect(DEFAULT_PORT).then(port => {
  if (port === DEFAULT_PORT) {
    run(port);
    return;
  }

  //clearConsole();
  var question =
    chalk.yellow('Something is already running on port ' + DEFAULT_PORT + '.') +
    '\n\nWould you like to run the app on another port instead?';
});
<|endoftext|>


<commit_before>/* global app:true, console:true, confirm:true */

'use strict'; // jshint -W097

/* CONTROLLERS */

app.controller('recCtrl', function ($scope, $rootScope, $location, $routeParams, Trip, Data, debounce) {
/*
  $rootScope.trips
    Array containing all trips including sensor and geo data.

  $rootScope.trip
    Array containing the temporary state of currently selected trip.
      id: currently selected trip id
      idx: index of currently selected trip
      extent: brush extent

  $rootScope.trips[$rootScope.trip.idx]
    Array containing the currently selected trip.
      domain: min/max values of all sensor data
      ...
*/

  // get all trips
  if (!$rootScope.trips) {
    var t = new Date(); // query start time
    Trip.query().then(function (data) {
      $rootScope.trips = data;
      console.info("trip data ready (" + ((new Date() - t) / 1000) + " ms)");
    }, function (data) {
      throw("Error getting trips!");
    });
  }

  // test if a trip is selected
  this.is = function (trip) {
    if ($rootScope.trip) {
      return ($rootScope.trip.id === trip.trip_id) ? true : false;
    }
  };

  this.hasData = function (trip) {
    return $rootScope.trips[$rootScope.trips.indexOf(trip)].acc.length ? true : false;
  };

  // select a trip
  this.select = function (trip) {
    if (this.is(trip)) return; // trip already selected
    $rootScope.trip = {
      'id': trip ? trip.trip_id : undefined,
      'idx': trip ? $rootScope.trips.indexOf(trip) : undefined,
      'extent': []
    };
  };

  if (!$rootScope.trip) this.select(); // create empty trip selection object

  // delete a trip
  this.destroy = function (trip) {
    var r = confirm("Are you sure? Permanently delete trip " + trip.trip_id + "?");
    if (r) {
      Trip.delete(trip.trip_id);
      $rootScope.trips.splice($rootScope.trips.indexOf(trip), 1);
      console.log("trip deleted:", trip.trip_id);
    }
  };

  // update a trip's name
  this.updateName = function (trip, data) {
    trip.name = data;
    Trip.save(trip.trip_id, {'name': data});
    console.info("trip updated:", trip.trip_id);
  };

  // change location path
  this.to = function(loc) {
    if ($rootScope.trip) {
      $location.path(loc);
    }
  };

  $rootScope.$watch('trip.id',
    function (newTrip, oldTrip) {
      if ($rootScope.trip.id) {
        if (!$rootScope.trips[$rootScope.trip.idx].updates) {
          $rootScope.trips[$rootScope.trip.idx].updates++;
          console.info("trip selected", $rootScope.trip, $rootScope.trips[$rootScope.trip.idx]);
          Data.geo();
          Data.sensor('gra');
          Data.sensor('acc');
          Data.sensor('lac');
        }
      }
    }
  );
});

app.controller('rawCtrl', function ($scope, $rootScope, $location, $timeout, Data) {
  if (!$rootScope.trip) { $location.path('/rec'); return; }
  $scope.data = $rootScope.trips[$rootScope.trip.idx];

  // update scope (called by directive)
  $scope.onBrushExtent = function(extent) {
    // EXTENT 3:
    console.log('EXTENT 3:', extent, $rootScope.trip.extent);
    $scope.$apply(function() { $rootScope.trip.extent = extent; });
  };

  // load more data (called by directive)
  $scope.loadMoreData = function(extent) {
    $rootScope.trips[$rootScope.trip.idx].updates++;
    Data.sensor('gra', extent, 'more');
    Data.sensor('acc', extent, 'more');
    Data.sensor('lac', extent, 'more');
  };
});

app.controller('harCtrl', function ($scope, $rootScope, $location) {
  if (!$rootScope.trip) { $location.path('/rec'); return; }
  $scope.data = $rootScope.trips[$rootScope.trip.idx];
});

app.controller('navCtrl', function ($scope, $rootScope, $route, Data) {
  this.is = function(loc) {
    return ($route.current && $route.current.name == loc) ? true : false;
  };

  // this.deselectTrip = function () {
  //   delete $rootScope.trip;
  // };

  // this.clearBrush = function () {
  //   $rootScope.trip.extent = undefined;
  // };

  // this.loadMoreData = function(sensor) {
  //   Data.sensor('gra', $rootScope.trip.extent, 'more');
  //   Data.sensor('acc', $rootScope.trip.extent, 'more');
  //   Data.sensor('lac', $rootScope.trip.extent, 'more');
  //   $scope.digest();
  //   // $scope.apply();
  // };
});<commit_msg>Minor cleanups.<commit_after>/* global app:true, console:true, confirm:true */

'use strict'; // jshint -W097

/* CONTROLLERS */

app.controller('recCtrl', function ($scope, $rootScope, $location, $routeParams, Trip, Data) {
/*
  $rootScope.trips
    Array containing all trips including sensor and geo data.

  $rootScope.trip
    Array containing the temporary state of currently selected trip.
      id: currently selected trip id
      idx: index of currently selected trip
      extent: brush extent

  $rootScope.trips[$rootScope.trip.idx]
    Array containing the currently selected trip.
      domain: min/max values of all sensor data
      ...
*/

  // get all trips
  if (!$rootScope.trips) {
    var t = new Date(); // query start time
    Trip.query().then(function (data) {
      $rootScope.trips = data;
      console.info("trip data ready (" + ((new Date() - t) / 1000) + " ms)");
    }, function (data) {
      throw("Error getting trips!");
    });
  }

  // test if a trip is selected
  this.is = function (trip) {
    if ($rootScope.trip) {
      return ($rootScope.trip.id === trip.trip_id) ? true : false;
    }
  };

  this.hasData = function (trip) {
    return $rootScope.trips[$rootScope.trips.indexOf(trip)].acc.length ? true : false;
  };

  // select a trip
  this.select = function (trip) {
    if (this.is(trip)) return; // trip already selected
    $rootScope.trip = {
      'id': trip ? trip.trip_id : undefined,
      'idx': trip ? $rootScope.trips.indexOf(trip) : undefined,
      'extent': []
    };
  };

  if (!$rootScope.trip) this.select(); // create empty trip selection object

  // delete a trip
  this.destroy = function (trip) {
    var r = confirm("Are you sure? Permanently delete trip " + trip.trip_id + "?");
    if (r) {
      Trip.delete(trip.trip_id);
      $rootScope.trips.splice($rootScope.trips.indexOf(trip), 1);
      console.log("trip deleted:", trip.trip_id);
    }
  };

  // update a trip's name
  this.updateName = function (trip, data) {
    trip.name = data;
    Trip.save(trip.trip_id, {'name': data});
    console.info("trip updated:", trip.trip_id);
  };

  // change location path
  this.to = function(loc) {
    if ($rootScope.trip) {
      $location.path(loc);
    }
  };

  $rootScope.$watch('trip.id',
    function (newTrip, oldTrip) {
      if ($rootScope.trip.id) {
        if (!$rootScope.trips[$rootScope.trip.idx].updates) {
          $rootScope.trips[$rootScope.trip.idx].updates++;
          console.info("trip selected", $rootScope.trip, $rootScope.trips[$rootScope.trip.idx]);
          Data.geo();
          Data.sensor('gra');
          Data.sensor('acc');
          Data.sensor('lac');
        }
      }
    }
  );
});

app.controller('rawCtrl', function ($scope, $rootScope, $location, Data) {
  if (!$rootScope.trip) { $location.path('/rec'); return; }
  $scope.data = $rootScope.trips[$rootScope.trip.idx];

  // update scope (called by directive)
  $scope.onBrushExtent = function(extent) {
    // EXTENT 3:
    console.log('CTRL  EXTENT 3:', extent, $rootScope.trip.extent);
    $scope.$apply(function() { $rootScope.trip.extent = extent; });
  };

  // load more data (called by directive)
  $scope.loadMoreData = function(extent) {
    $rootScope.trips[$rootScope.trip.idx].updates++;
    Data.sensor('gra', extent, 'more');
    Data.sensor('acc', extent, 'more');
    Data.sensor('lac', extent, 'more');
  };
});

app.controller('navCtrl', function ($scope, $rootScope, $route, Data) {
  this.is = function(loc) {
    return ($route.current && $route.current.name == loc) ? true : false;
  };

  // this.deselectTrip = function () {
  //   delete $rootScope.trip;
  // };

  // this.clearBrush = function () {
  //   $rootScope.trip.extent = undefined;
  // };

  // this.loadMoreData = function(sensor) {
  //   Data.sensor('gra', $rootScope.trip.extent, 'more');
  //   Data.sensor('acc', $rootScope.trip.extent, 'more');
  //   Data.sensor('lac', $rootScope.trip.extent, 'more');
  //   $scope.digest();
  //   // $scope.apply();
  // };
});<|endoftext|>


<commit_before>const expect = require('chai').expect;
const assert = require('chai').assert;

import { Observer } from "../observer";

describe('observer subscribe', () => {

    const observer = new Observer();
    const fn1 = () => {};

    context('subscribe',
        () => { it('should subscribe',
            () => {
                observer.subscribe(fn1);
                expect(observer.observers.length).to.equal(1)
            })
        })

    context('unsubscribe',
        () => { it('should unsubscribe',
                () => {
                    observer.unsubscribe(fn1);
                    expect(observer.observers.length).to.equal(0);
                })
        });

    let subscriberHasBeenCalled = false;
    const fn2 = (data) => subscriberHasBeenCalled = data;

    context('broadcast',
        () => {
            it('should receive',
                () => {
                    observer.subscribe(fn2);
                    observer.broadcast(true);
                    expect(subscriberHasBeenCalled).to.equal(true);
                })
        });

});
<commit_msg>More javascript and tests.<commit_after>const expect = require('chai').expect;

import { Observer } from "../observer";

describe('observer subscribe', () => {

    const observer = new Observer();
    const fn1 = () => {};

    context('subscribe',
        () => { it('should subscribe',
            () => {
                observer.subscribe(fn1);
                expect(observer.observers.length).to.equal(1)
            })
        })

    context('unsubscribe',
        () => { it('should unsubscribe',
                () => {
                    observer.unsubscribe(fn1);
                    expect(observer.observers.length).to.equal(0);
                })
        });

    let subscriberHasBeenCalled = false;
    const fn2 = (data) => subscriberHasBeenCalled = data;

    context('broadcast',
        () => {
            it('should receive',
                () => {
                    observer.subscribe(fn2);
                    observer.broadcast(true);
                    expect(subscriberHasBeenCalled).to.equal(true);
                })
        });

});
<|endoftext|>


<commit_before>// Variables
var distro = "8"

function MakeUrl(isPrint) {
	var amahi = "amahi";
	var version = "interactive";
	var currUrl = document.URL.toLowerCase();

	if( isPrint ) {
		version = 'print';
	}
	var toUrl = "/" + amahi + distro + version + ".html";

	return toUrl;
}

function MakeText(  isPrint ) {
	var amahi = "Amahi";
	var version = "Interactive";

	var url = document.URL.toLowerCase();
	if( isPrint ) {
		version = 'Print';
	}

	var text = "
Would you like to go to the
";
	text += "
" + version + " version of the
";
	text += "
" + amahi + " " + distro + " troubleshooter?
";

	return text;
}

function SetDistro(d) {
	distro = d;
	var isPrint = false;
	var url = document.URL.toLowerCase();
	if( url.indexOf("print") > -1 ) {
		isPrint = true;
	}
	ShowModal(isPrint);
}

function ShowModal(isPrint) {
	$('#go-btn').attr('href', MakeUrl(isPrint));
	$('#confirmChange .modal-body').html( MakeText(isPrint) );

	$('#confirmChange').modal('show');
}

function SetButtonState( version ){
	var amahi = "Amahi";

	var text = amahi + " " + distro + " " + version;
	$('#main-btn').html(text);

	if(version.toLowerCase() === "print") {
		$('#print-btn').addClass('active');
	}
}

function PrintClick() {
	var url = document.URL.toLowerCase();
	var isPrint = true;

	if( url.indexOf('print') > -1) {
		isPrint = false;
	}
	ShowModal(isPrint);
}

function GetState( callback ) {
	var url = document.URL.toLowerCase();

	var version = "Interactive";

	if( url.indexOf('print') > -1) {
		version = 'Print';
	}

	if( url.indexOf('7') > -1 )	{
		distro = 7;
	} else if ( url.indexOf('6') > -1 ) {
		distro = 6;
	}

	callback( version );
}

<commit_msg>select menu simplify<commit_after>// Variables
var distro = "8"

function MakeUrl(isPrint) {
	var amahi = "amahi";
	var version = "interactive";
	var currUrl = document.URL.toLowerCase();

	if( isPrint ) {
		version = 'print';
	}
	var toUrl = "/" + amahi + distro + version + ".html";

	return toUrl;
}

function MakeText(  isPrint ) {
	var amahi = "Amahi";
	var version = "Interactive";
	var text = "
Would you like to go to the
";

	var url = document.URL.toLowerCase();
	if( isPrint ) {
		version = 'Print';
		text += "
" + version + " version of the
";
	}

	text += "
" + amahi + " " + distro + " troubleshooter?
";

	return text;
}

function SetDistro(d) {
	distro = d;
	var isPrint = false;
	var url = document.URL.toLowerCase();
	if( url.indexOf("print") > -1 ) {
		isPrint = true;
	}
	ShowModal(isPrint);
}

function ShowModal(isPrint) {
	$('#go-btn').attr('href', MakeUrl(isPrint));
	$('#confirmChange .modal-body').html( MakeText(isPrint) );

	$('#confirmChange').modal('show');
}

function SetButtonState( version ){
	var amahi = "Amahi";

	var text = amahi + " " + distro;

	if(version.toLowerCase() === "print") {
		text += " " + version
		$('#print-btn').addClass('active');
	}

	$('#main-btn').html(text);
}

function PrintClick() {
	var url = document.URL.toLowerCase();
	var isPrint = true;

	if( url.indexOf('print') > -1) {
		isPrint = false;
	}
	ShowModal(isPrint);
}

function GetState( callback ) {
	var url = document.URL.toLowerCase();

	var version = "Interactive";

	if( url.indexOf('print') > -1) {
		version = 'Print';
	}

	if( url.indexOf('7') > -1 )	{
		distro = 7;
	} else if ( url.indexOf('6') > -1 ) {
		distro = 6;
	}

	callback( version );
}

<|endoftext|>


<commit_before>const bot = require('./bot');

bot.on('message', message => {
	var channel = message.channel;
	message = message.content.toLowerCase();
	//Error updating
	if(message.includes('updating') && message.includes('forever') )
	{
		channel.sendMessage('Follow this article \n http://battlelog.co/wiki.php?article=27');
	}
	//Error debugging
	if(message.includes('unkown dynamicoption'))
		{
		channel.sendMessage('Follow the second part of this article. \n http://battlelog.co/post.php?id=9744');
		}
	//Mouse stuck after launch ingame
	if(message.includes('mouse') && message.includes('stuck'))
		{
		channel.sendMessage('follow this article\nhttp://battlelog.co/wiki.php?article=7');
		}
	//Invalid CD key Fix
	if(message.includes('invalid') && message.includes('cdkey'))
	{ channel.sendMessage('follow these articles\nhttps://battlelog.co/post.php?id=16014&page=1\nhttp://battlelog.co/wiki.php?article=28');
	}
	//Installation Errors
	if(message.includes('installation') && message.includes('failed'))
	{
		channel.sendMessage('follow this article\nhttp://battlelog.co/post.php?id=17435#p57246');
	}
	//Black screen after launch
	if(message.includes('black screen') && message.includes('help'))
	{
                 channel.sendMessage('Follow this article \nhttp://battlelog.co/post.php?id=9744');
	}
	//Login Errors
	if(message.includes('error') && message.includes('api'))
	{
                 channel.sendMessage('Follow this article \n https://battlelog.co/post.php?id=17435#p93129');
	}
	//DirectX9 errors after launhcer
	if(message.includes('directx9') && message.includes('error'))
	{
                 channel.sendMessage('Follow this article \n https://battlelog.co/wiki.php?article=14');
	}
	//Server Rules Battlelog
	if(message.includes('server') && message.includes('rules'))
	{
                 channel.sendMessage('Follow this article \n https://battlelog.co/post.php?id=19581');
	}
	//Howto Report players
	if(message.includes('howto') && message.includes('report'))
	{
                 channel.sendMessage('Follow this article \n https://battlelog.co/post.php?id=15931');
	}
}
);
<commit_msg>useless help me people<commit_after>const bot = require('./bot');

bot.on('message', message => {
	var channel = message.channel;
	message = message.content.toLowerCase();
	//Error updating
	if(message.includes('updating') && message.includes('forever'))
	{
		channel.sendMessage('Follow this article \n http://battlelog.co/wiki.php?article=27');
	}
	//Error debugging
	if(message.includes('unkown dynamicoption'))
		{
		channel.sendMessage('Follow the second part of this article. \n http://battlelog.co/post.php?id=9744');
		}
	//Mouse stuck after launch ingame
	if(message.includes('mouse') && message.includes('stuck'))
		{
		channel.sendMessage('follow this article\nhttp://battlelog.co/wiki.php?article=7');
		}
	//Invalid CD key Fix
	if(message.includes('invalid') && message.includes('cdkey'))
	{ channel.sendMessage('follow these articles\nhttps://battlelog.co/post.php?id=16014&page=1\nhttp://battlelog.co/wiki.php?article=28');
	}
	//Installation Errors
	if(message.includes('installation') && message.includes('failed'))
	{
		channel.sendMessage('follow this article\nhttp://battlelog.co/post.php?id=17435#p57246');
	}
	//Black screen after launch
	if(message.includes('black screen') && message.includes('help'))
	{
                 channel.sendMessage('Follow this article \nhttp://battlelog.co/post.php?id=9744');
	}
	//Login Errors
	if(message.includes('error') && message.includes('api'))
	{
                 channel.sendMessage('Follow this article \n https://battlelog.co/post.php?id=17435#p93129');
	}
	//DirectX9 errors after launhcer
	if(message.includes('directx9') && message.includes('error'))
	{
                 channel.sendMessage('Follow this article \n https://battlelog.co/wiki.php?article=14');
	}
	//Server Rules Battlelog
	if(message.includes('server') && message.includes('rules'))
	{
                 channel.sendMessage('Follow this article \n https://battlelog.co/post.php?id=19581');
	}
	//Howto Report players
	if(message.includes('howto') && message.includes('report'))
	{
                 channel.sendMessage('Follow this article \n https://battlelog.co/post.php?id=15931');
	}
	//Howto Report players
	if(message.includes('help') && message.includes('me'))
	{
                 channel.sendMessage('Me more specific, tell us what the issue is.');
	}
}
);
<|endoftext|>


<commit_before>import linearSystem from '../index.js'
import sinon from 'sinon'
describe('linearSystem', () => {
    let linSys;
    let data;
    beforeEach(function() {
        linSys = new linearSystem();
        data = {
          s : [[2,2,6],[9,9,30]]
        };
    });
    describe('_switch', () => {
      it('should exchange places of two diffrent rows', () => {
        let thing = linSys._switch(data,0,1);
        expect(thing.s).toEqual([[9,9,30],[2,2,6]]);
        //mutation check
      });

      it('mutation check', () => {
        let thing = linSys._switch(data,0,1);
        expect(thing.s).toEqual([[9,9,30],[2,2,6]]);
        expect(data).toEqual({ s : [[2,2,6],[9,9,30]]});
      });
    });
    describe("_getRowScaledBy", () => {
      it('should return array mulitplied by scale', () => {
        let row = linSys._getRowScaledBy([2,0,6],2);
        expect(row).toEqual([4,0,12]);
      });

      it('should return array mulitplied to negitive scale', () => {
        let row = linSys._getRowScaledBy([2,0,-6],-1);
        expect(row).toEqual([-2,0,6]);
      });

      it('mutation check', () => {
        let row = linSys._getRowScaledBy([2,0,-6],-1);
        expect(data).toEqual({s : [[2,2,6],[9,9,30]]});
      });
    });

    describe("_rowReplacement", () => {
      it('should call _getRowScaledBy with data', () => {
        let scaledBy = sinon.spy(linSys, '_getRowScaledBy');
        let rowToBeReplaced = 0, otherRow = 1, scale = 2;
        linSys._rowReplacement(data, rowToBeReplaced, otherRow, scale);
        scaledBy.restore();
        sinon.assert.calledWith(scaledBy, [9,9,30], 2);
      });

      it('should return array with a row replaced by itself mulitplied to scale', () => {
        let rowToBeReplaced = 0,otherRow = 1,scale = 2;
        let newthing = linSys._rowReplacement(data, rowToBeReplaced, otherRow, scale);
        expect(newthing).toEqual({s : [[20,20,66],[9,9,30]]});
      });

      it('mutation test', () => {
        let rowToBeReplaced = 0, otherRow = 1, scale = 2;
        linSys._rowReplacement(data, rowToBeReplaced, otherRow, scale);
        expect(data).toEqual({ s : [[2,2,6],[9,9,30]]});
      });
    });

    describe("_largestAbsoluteMovedToTopOfColumn", () => {
      it('should return array with largest absolute value to top of each pivot', () => {
        let inputSystem = {
          s : [
            [0,1,2,3],
            [1,2,3,4],
            [-3,2,1,5]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        };
        let expectedOutput = {
          s : [
            [-3,2,1,5],
            [1,2,3,4],
            [0,1,2,3]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        };
        let output = linSys._largestAbsoluteMovedToTopOfColumn(inputSystem);
        expect(output).toEqual(expectedOutput);
      });

      it("calls _switch with correct values", () => {
        let switchy = sinon.spy(linSys, '_switch');
        let inputSystem = {
          s : [
            [0,1,2,3],
            [1,2,3,4],
            [-3,2,1,5]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        };
        let output = linSys._largestAbsoluteMovedToTopOfColumn(inputSystem);
        switchy.restore();
        sinon.assert.calledWith(switchy, {
          s : [
            [0,1,2,3],
            [1,2,3,4],
            [-3,2,1,5]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        });
      });
      it("mutation check", () => {
        let inputSystem = {
          s : [
            [0,1,2,3],
            [1,2,3,4],
            [-3,2,1,5]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        };
        linSys._largestAbsoluteMovedToTopOfColumn(inputSystem);
        expect(inputSystem).toEqual({
          s : [
            [0,1,2,3],
            [1,2,3,4],
            [-3,2,1,5]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        });
      });
    });

  it('_zeroAllRowsUnderThePivot returns correct value', () => {
    let inputSystem = {
      s : [
        [5,1,1,10],
        [-1,1,1,-2],
        [1,1,1,2]
      ],
      pivot : {
        column : 0,
        row : 0
      }
    };
    let outSystem = linSys._zeroAllRowsUnderThePivot(inputSystem);
    expect(outSystem.s).toEqual(
      [
        [ 5, 1, 1, 10 ],
        [ 0, 1.2, 1.2, 0 ],
        [ 0, 0.8, 0.8, 0 ]
      ]);
  });

  it('_zeroAllRowsUnderThePivot mutation check', () => {
    let inputSystem = {
      s : [
        [5,1,1,10],
        [-1,1,1,-2],
        [1,1,1,2]
      ],
      pivot : {
        column : 0,
        row : 0
      }
    };
    let outSystem = linSys._zeroAllRowsUnderThePivot(inputSystem);
    expect(inputSystem).toEqual({
      s : [
        [5,1,1,10],
        [-1,1,1,-2],
        [1,1,1,2]
      ],
      pivot : {
        column : 0,
        row : 0
      }
    });
  });
});
<commit_msg>describe block _zeroAllRowsUnderThePivot<commit_after>import linearSystem from '../index.js'
import sinon from 'sinon'
describe('linearSystem', () => {
    let linSys;
    let data;
    beforeEach(function() {
        linSys = new linearSystem();
        data = {
          s : [[2,2,6],[9,9,30]]
        };
    });
    describe('_switch', () => {
      it('should exchange places of two diffrent rows', () => {
        let thing = linSys._switch(data,0,1);
        expect(thing.s).toEqual([[9,9,30],[2,2,6]]);
        //mutation check
      });

      it('mutation check', () => {
        let thing = linSys._switch(data,0,1);
        expect(thing.s).toEqual([[9,9,30],[2,2,6]]);
        expect(data).toEqual({ s : [[2,2,6],[9,9,30]]});
      });
    });
    describe("_getRowScaledBy", () => {
      it('should return array mulitplied by scale', () => {
        let row = linSys._getRowScaledBy([2,0,6],2);
        expect(row).toEqual([4,0,12]);
      });

      it('should return array mulitplied to negitive scale', () => {
        let row = linSys._getRowScaledBy([2,0,-6],-1);
        expect(row).toEqual([-2,0,6]);
      });

      it('mutation check', () => {
        let row = linSys._getRowScaledBy([2,0,-6],-1);
        expect(data).toEqual({s : [[2,2,6],[9,9,30]]});
      });
    });

    describe("_rowReplacement", () => {
      it('should call _getRowScaledBy with data', () => {
        let scaledBy = sinon.spy(linSys, '_getRowScaledBy');
        let rowToBeReplaced = 0, otherRow = 1, scale = 2;
        linSys._rowReplacement(data, rowToBeReplaced, otherRow, scale);
        scaledBy.restore();
        sinon.assert.calledWith(scaledBy, [9,9,30], 2);
      });

      it('should return array with a row replaced by itself mulitplied to scale', () => {
        let rowToBeReplaced = 0,otherRow = 1,scale = 2;
        let newthing = linSys._rowReplacement(data, rowToBeReplaced, otherRow, scale);
        expect(newthing).toEqual({s : [[20,20,66],[9,9,30]]});
      });

      it('mutation test', () => {
        let rowToBeReplaced = 0, otherRow = 1, scale = 2;
        linSys._rowReplacement(data, rowToBeReplaced, otherRow, scale);
        expect(data).toEqual({ s : [[2,2,6],[9,9,30]]});
      });
    });

    describe("_largestAbsoluteMovedToTopOfColumn", () => {
      it('should return array with largest absolute value to top of each pivot', () => {
        let inputSystem = {
          s : [
            [0,1,2,3],
            [1,2,3,4],
            [-3,2,1,5]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        };
        let expectedOutput = {
          s : [
            [-3,2,1,5],
            [1,2,3,4],
            [0,1,2,3]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        };
        let output = linSys._largestAbsoluteMovedToTopOfColumn(inputSystem);
        expect(output).toEqual(expectedOutput);
      });

      it("calls _switch with correct values", () => {
        let switchy = sinon.spy(linSys, '_switch');
        let inputSystem = {
          s : [
            [0,1,2,3],
            [1,2,3,4],
            [-3,2,1,5]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        };
        let output = linSys._largestAbsoluteMovedToTopOfColumn(inputSystem);
        switchy.restore();
        sinon.assert.calledWith(switchy, {
          s : [
            [0,1,2,3],
            [1,2,3,4],
            [-3,2,1,5]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        });
      });
      it("mutation check", () => {
        let inputSystem = {
          s : [
            [0,1,2,3],
            [1,2,3,4],
            [-3,2,1,5]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        };
        linSys._largestAbsoluteMovedToTopOfColumn(inputSystem);
        expect(inputSystem).toEqual({
          s : [
            [0,1,2,3],
            [1,2,3,4],
            [-3,2,1,5]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        });
      });
    });

    describe("_zeroAllRowsUnderThePivot", () => {
      it('returns correct value', () => {
        let inputSystem = {
          s : [
            [5,1,1,10],
            [-1,1,1,-2],
            [1,1,1,2]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        };
        let outSystem = linSys._zeroAllRowsUnderThePivot(inputSystem);
        expect(outSystem.s).toEqual(
          [
            [ 5, 1, 1, 10 ],
            [ 0, 1.2, 1.2, 0 ],
            [ 0, 0.8, 0.8, 0 ]
          ]);
      });

      it('mutation check', () => {
        let inputSystem = {
          s : [
            [5,1,1,10],
            [-1,1,1,-2],
            [1,1,1,2]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        };
        let outSystem = linSys._zeroAllRowsUnderThePivot(inputSystem);
        expect(inputSystem).toEqual({
          s : [
            [5,1,1,10],
            [-1,1,1,-2],
            [1,1,1,2]
          ],
          pivot : {
            column : 0,
            row : 0
          }
        });
      });
    });
});
<|endoftext|>


<commit_before>const should = require('should');
const request = require('request');

describe('Requesting Challenge and Tutorial Data', () => {
	describe('Challenges', () => {
		it('Should respond with a Challenges Array', (done) => {
			request('http://localhost:3000/regex/challenges', (err, response, body) => {
				(response.statusCode).should.be.exactly(200);
				(JSON.parse(body)).should.be.instanceOf(Array);
				done();
			});
		});
	});
	describe('Tutorials', () => {
		it('Should respond with a Tutorials Array', (done) => {
			request('http://localhost:3000/regex/tutorial', (err, response, body) => {
				(response.statusCode).should.be.exactly(200);
				(JSON.parse(body)).should.be.instanceOf(Array);
				done();
			});
		});
	});
});

<commit_msg>[ BUGFIX ]<commit_after>const should = require('should');
const request = require('request');

xdescribe('Requesting Challenge and Tutorial Data', () => {
	describe('Challenges', () => {
		it('Should respond with a Challenges Array', (done) => {
			request('http://localhost:3000/regex/challenges', (err, response, body) => {
				(response.statusCode).should.be.exactly(200);
				(JSON.parse(body)).should.be.instanceOf(Array);
				done();
			});
		});
	});
	describe('Tutorials', () => {
		it('Should respond with a Tutorials Array', (done) => {
			request('http://localhost:3000/regex/tutorial', (err, response, body) => {
				(response.statusCode).should.be.exactly(200);
				(JSON.parse(body)).should.be.instanceOf(Array);
				done();
			});
		});
	});
});

<|endoftext|>


<commit_before>(function (enyo, scope) {

	var kind = enyo.kind,
		EventEmitter = enyo.EventEmitter,
		StateSupport = enyo.StateSupport;

	function update(node, src) {
		var key, val;

		if (!(node && src)) return;

		// avoid iterating over null/undefined
		for (key in src) {
			// avoid looking this value up over and over
			val = src[key];
			// don't clear current values if one wasn't returned
			if (val != null) {
				// if there isn't a value already we short-circuit the object test for efficiency
				if (!node[key] || !enyo.isObject(val)) node[key] = val;
				else update(node[key], val);
			}
		}

		return node;
	}

	/**
	*
    *
	* @class enyo.FluxStore
	* @mixes enyo.EventEmitter
	* @extends enyo.Object
	* @public
	*/
	kind(
		/** @lends enyo.FluxStore.prototype */ {
		name: 'enyo.FluxStore',

		/**
		* @private
		*/
		kind: enyo.Object,

		/**
		* @private
		*/
		data: {},

		/**
		* @name enyo.FluxStore.id
		*
		* How a store is identitified to the Flux Dispatcher
		* This ID is used for subscribing to a store's
		* state notification change
		*
		* @public
		* @type {Number}
		*
		*/
		id: -1,

		mixins: [EventEmitter, StateSupport],

		/**
		* @name enyo.FluxStore.source
		*
		* The source that this FluxStore should use to fetch new
		* data sets.
		*
		* @public
		* @type {String}
		*
		*/
		source: '',

		published: {

			/**
			* @name enyo.FluxStore.MergeRoot
			*
			* When a source sends data to the store,
			* should the data root have the new data
			* merged, otherwise it will replace.
			*
			* @public
			* @type {Boolean}
			* @default true
			*
			*/
			MergeRoot: true
		},

		/**
		* @private
		*/
		constructor: enyo.inherit(function(sup){
			return function(){
				sup.apply(this, arguments);
				if(enyo.FluxDispatcher) {
					//subscribe the store to the dispatcher
					this.id = enyo.FluxDispatcher.subscribe();
				}
			};
		}),

		/**
		* @name enyo.FluxStore.add
		*
		* Adds data to the store, is called from the store's fetch
		*
		* @param [data] - Object that has the data to be added to store.
		* @param {enyo.FluxStore~ActionOptions} [opts] - Optional configuration options.
		* @private
		*/
		add: function (data, opts) {
			if(this.MergeRoot) {
				update(this.data, data);
				return;
			}
			this.data = data;
		},

		/**
		* @name enyo.FluxStore.reset
		*
		* Clears the store's data
		*
		* @public
		*/
		reset: function () {
			this.data = {};
		},

		/**
		* @name enyo.FluxStore.fetch
		*
		* Fetches the data from a [Source]{@link enyo.Source}
		*
		* @param {enyo.FluxStore~ActionOptions} [opts] - Optional configuration options.
		* @public
		*/
		fetch: function(opts) {

			opts = opts || {};

			opts.success = opts.success || this.success.bind(this);
			opts.error = opts.error || this.error.bind(this);

			enyo.FluxDispatcher.pending[this.id] = true;
			enyo.Source.execute('fetch', this, opts);
			enyo.FluxDispatcher.pending[this.id] = false;
		},

		/**
		* @name enyo.FluxStore.success
		*
		* Success callback is called when the [Source]{@link enyo.Source} is successful
		*
		* @param {enyo.Source} [source] - The source that iniated the fetch.
		* @param {enyo.Source~Results} [res] - The result of the fetch.
		* @private
		*/
		success: function(source, res) {

			//when the result comes back from
			//the fetch add it to the store
			this.add(res);

			//tell the dispatcher to notify all subscribers
			//that the payload has been updated for this store
			enyo.FluxDispatcher.notify(this.id, this.data);
		},

		/**
		* @name enyo.FluxStore.error
		*
		* Error callback is called when the [Source]{@link enyo.Source} has failed
		*
		* @param {enyo.Source~Results} [res] - The result of the fetch.
		* @private
		*/
		error: function(res) {
			//error occured during fetch
			//todo: warn user
		}
	});

})(enyo, this);
<commit_msg>ENYO-944: Update property name.<commit_after>(function (enyo, scope) {

	var kind = enyo.kind,
		EventEmitter = enyo.EventEmitter,
		StateSupport = enyo.StateSupport;

	function update(node, src) {
		var key, val;

		if (!(node && src)) return;

		// avoid iterating over null/undefined
		for (key in src) {
			// avoid looking this value up over and over
			val = src[key];
			// don't clear current values if one wasn't returned
			if (val != null) {
				// if there isn't a value already we short-circuit the object test for efficiency
				if (!node[key] || !enyo.isObject(val)) node[key] = val;
				else update(node[key], val);
			}
		}

		return node;
	}

	/**
	*
    *
	* @class enyo.FluxStore
	* @mixes enyo.EventEmitter
	* @extends enyo.Object
	* @public
	*/
	kind(
		/** @lends enyo.FluxStore.prototype */ {
		name: 'enyo.FluxStore',

		/**
		* @private
		*/
		kind: enyo.Object,

		/**
		* @private
		*/
		data: {},

		/**
		* @name enyo.FluxStore.id
		*
		* How a store is identitified to the Flux Dispatcher
		* This ID is used for subscribing to a store's
		* state notification change
		*
		* @public
		* @type {Number}
		*
		*/
		id: -1,

		mixins: [EventEmitter, StateSupport],

		/**
		* @name enyo.FluxStore.source
		*
		* The source that this FluxStore should use to fetch new
		* data sets.
		*
		* @public
		* @type {String}
		*
		*/
		source: '',

		published: {

			/**
			* @name enyo.FluxStore.mergeRoot
			*
			* When a source sends data to the store,
			* should the data root have the new data
			* merged, otherwise it will replace.
			*
			* @public
			* @type {Boolean}
			* @default true
			*
			*/
			mergeRoot: true
		},

		/**
		* @private
		*/
		constructor: enyo.inherit(function(sup){
			return function(){
				sup.apply(this, arguments);
				if(enyo.FluxDispatcher) {
					//subscribe the store to the dispatcher
					this.id = enyo.FluxDispatcher.subscribe();
				}
			};
		}),

		/**
		* @name enyo.FluxStore.add
		*
		* Adds data to the store, is called from the store's fetch
		*
		* @param [data] - Object that has the data to be added to store.
		* @param {enyo.FluxStore~ActionOptions} [opts] - Optional configuration options.
		* @private
		*/
		add: function (data, opts) {
			if(this.mergeRoot) {
				update(this.data, data);
				return;
			}
			this.data = data;
		},

		/**
		* @name enyo.FluxStore.reset
		*
		* Clears the store's data
		*
		* @public
		*/
		reset: function () {
			this.data = {};
		},

		/**
		* @name enyo.FluxStore.fetch
		*
		* Fetches the data from a [Source]{@link enyo.Source}
		*
		* @param {enyo.FluxStore~ActionOptions} [opts] - Optional configuration options.
		* @public
		*/
		fetch: function(opts) {

			opts = opts || {};

			opts.success = opts.success || this.success.bind(this);
			opts.error = opts.error || this.error.bind(this);

			enyo.FluxDispatcher.pending[this.id] = true;
			enyo.Source.execute('fetch', this, opts);
			enyo.FluxDispatcher.pending[this.id] = false;
		},

		/**
		* @name enyo.FluxStore.success
		*
		* Success callback is called when the [Source]{@link enyo.Source} is successful
		*
		* @param {enyo.Source} [source] - The source that iniated the fetch.
		* @param {enyo.Source~Results} [res] - The result of the fetch.
		* @private
		*/
		success: function(source, res) {

			//when the result comes back from
			//the fetch add it to the store
			this.add(res);

			//tell the dispatcher to notify all subscribers
			//that the payload has been updated for this store
			enyo.FluxDispatcher.notify(this.id, this.data);
		},

		/**
		* @name enyo.FluxStore.error
		*
		* Error callback is called when the [Source]{@link enyo.Source} has failed
		*
		* @param {enyo.Source~Results} [res] - The result of the fetch.
		* @private
		*/
		error: function(res) {
			//error occured during fetch
			//todo: warn user
		}
	});

})(enyo, this);
<|endoftext|>


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

/**
 * @fileoverview Externs definitions for web-component-tester, 4.2 branch.
 *
 * @externs
 * @see https://github.com/Polymer/web-component-tester
 */

/**
 * Waits for queued tasks to finish, then calls the callback.
 * @param {!Function} cb
 */
var flush = function(cb) {};

/**
 * @param {string} tag
 * @return {{with: function(string)}}
 */
var replace = function(tag) {};

/**
 * @param {string} tag
 * @param {!Object} impl
 */
var stub = function(tag, impl) {};

/**
 * Shorthand for `document.getElementById(name).create(model)`. It is to be used
 * with the `<text-fixture>` Polymer element.
 * @param {string} name
 * @param {!Object=} opt_model
 * @return {!Element}
 */
var fixture = function(name, opt_model) {};

/**
 * @param {string} fixtureId
 * @param {!Array<string>=} ignoredRules
 * @param {!Function=} beforeEach Function to be called before each test to
 * ensure proper setup
 */
var a11ySuite = function(fixtureId, ignoredRules, beforeEach) {};
<commit_msg>Add waitFor to the web component tester externs.<commit_after>/*
 * Copyright 2016 The Closure Compiler Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Externs definitions for web-component-tester, 4.2 branch.
 *
 * @externs
 * @see https://github.com/Polymer/web-component-tester
 */

/**
 * Waits for queued tasks to finish, then calls the callback.
 * @param {!Function} cb
 */
var flush = function(cb) {};

/**
 * @param {string} tag
 * @return {{with: function(string)}}
 */
var replace = function(tag) {};

/**
 * @param {string} tag
 * @param {!Object} impl
 */
var stub = function(tag, impl) {};

/**
 * Shorthand for `document.getElementById(name).create(model)`. It is to be used
 * with the `<text-fixture>` Polymer element.
 * @param {string} name
 * @param {!Object=} opt_model
 * @return {!Element}
 */
var fixture = function(name, opt_model) {};

/**
 * @param {string} fixtureId
 * @param {!Array<string>=} ignoredRules
 * @param {!Function=} beforeEach Function to be called before each test to
 * ensure proper setup
 */
var a11ySuite = function(fixtureId, ignoredRules, beforeEach) {};

/**
 * @param {!Function} fn
 * @param {!Function} next
 * @param {(number|Element)=} intervalOrMutationEl
 * @param {number=} timeout
 * @param {Date=} timeoutTime
 */
var waitFor = function waitFor(
    fn, next, intervalOrMutationEl, timeout, timeoutTime) {}
<|endoftext|>


<commit_before>import React from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TablePagination from '@material-ui/core/TablePagination';
import TableRow from '@material-ui/core/TableRow';
import TableSortLabel from '@material-ui/core/TableSortLabel';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Paper from '@material-ui/core/Paper';
import Checkbox from '@material-ui/core/Checkbox';
import IconButton from '@material-ui/core/IconButton';
import Tooltip from '@material-ui/core/Tooltip';
import DeleteIcon from '@material-ui/icons/Delete';
import FilterListIcon from '@material-ui/icons/FilterList';
import { lighten } from '@material-ui/core/styles/colorManipulator';

let counter = 0;
function createData(name, calories, fat, carbs, protein) {
  counter += 1;
  return { id: counter, name, calories, fat, carbs, protein };
}

function getSorting(order, orderBy) {
  return order === 'desc'
    ? (a, b) => (b[orderBy]  (a[orderBy] < b[orderBy] ? -1 : 1);
}

const columnData = [
  { id: 'name', numeric: false, disablePadding: true, label: 'Dessert (100g serving)' },
  { id: 'calories', numeric: true, disablePadding: false, label: 'Calories' },
  { id: 'fat', numeric: true, disablePadding: false, label: 'Fat (g)' },
  { id: 'carbs', numeric: true, disablePadding: false, label: 'Carbs (g)' },
  { id: 'protein', numeric: true, disablePadding: false, label: 'Protein (g)' },
];

class EnhancedTableHead extends React.Component {
  createSortHandler = property => event => {
    this.props.onRequestSort(event, property);
  };

  render() {
    const { onSelectAllClick, order, orderBy, numSelected, rowCount } = this.props;

    return (
      <TableHead>
        <TableRow>
          <TableCell padding="checkbox">
            <Checkbox
              indeterminate={numSelected > 0 && numSelected < rowCount}
              checked={numSelected === rowCount}
              onChange={onSelectAllClick}
            />
          </TableCell>
          {columnData.map(column => {
            return (
              <TableCell
                key={column.id}
                numeric={column.numeric}
                padding={column.disablePadding ? 'none' : 'default'}
                sortDirection={orderBy === column.id ? order : false}
              >
                <Tooltip
                  title="Sort"
                  placement={column.numeric ? 'bottom-end' : 'bottom-start'}
                  enterDelay={300}
                >
                  <TableSortLabel
                    active={orderBy === column.id}
                    direction={order}
                    onClick={this.createSortHandler(column.id)}
                  >
                    {column.label}
                  </TableSortLabel>
                </Tooltip>
              </TableCell>
            );
          }, this)}
        </TableRow>
      </TableHead>
    );
  }
}

EnhancedTableHead.propTypes = {
  numSelected: PropTypes.number.isRequired,
  onRequestSort: PropTypes.func.isRequired,
  onSelectAllClick: PropTypes.func.isRequired,
  order: PropTypes.string.isRequired,
  orderBy: PropTypes.string.isRequired,
  rowCount: PropTypes.number.isRequired,
};

const toolbarStyles = theme => ({
  root: {
    paddingRight: theme.spacing.unit,
  },
  highlight:
    theme.palette.type === 'light'
      ? {
          color: theme.palette.secondary.main,
          backgroundColor: lighten(theme.palette.secondary.light, 0.85),
        }
      : {
          color: theme.palette.text.primary,
          backgroundColor: theme.palette.secondary.dark,
        },
  spacer: {
    flex: '1 1 100%',
  },
  actions: {
    color: theme.palette.text.secondary,
  },
  title: {
    flex: '0 0 auto',
  },
});

let EnhancedTableToolbar = props => {
  const { numSelected, classes } = props;

  return (
    <Toolbar
      className={classNames(classes.root, {
        [classes.highlight]: numSelected > 0,
      })}
    >

        {numSelected > 0 ? (
          <Typography color="inherit" variant="subheading">
            {numSelected} selected
          </Typography>
        ) : (
          <Typography variant="title" id="tableTitle">
            Nutrition
          </Typography>
        )}

        {numSelected > 0 ? (
          <Tooltip title="Delete">
            <IconButton aria-label="Delete">
              <DeleteIcon />
            </IconButton>
          </Tooltip>
        ) : (
          <Tooltip title="Filter list">
            <IconButton aria-label="Filter list">
              <FilterListIcon />
            </IconButton>
          </Tooltip>
        )}

    </Toolbar>
  );
};

EnhancedTableToolbar.propTypes = {
  classes: PropTypes.object.isRequired,
  numSelected: PropTypes.number.isRequired,
};

EnhancedTableToolbar = withStyles(toolbarStyles)(EnhancedTableToolbar);

const styles = theme => ({
  root: {
    width: '100%',
    marginTop: theme.spacing.unit * 3,
  },
  table: {
    minWidth: 1020,
  },
  tableWrapper: {
    overflowX: 'auto',
  },
});

class EnhancedTable extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      order: 'asc',
      orderBy: 'calories',
      selected: [],
      data: [
        createData('Cupcake', 305, 3.7, 67, 4.3),
        createData('Donut', 452, 25.0, 51, 4.9),
        createData('Eclair', 262, 16.0, 24, 6.0),
        createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
        createData('Gingerbread', 356, 16.0, 49, 3.9),
        createData('Honeycomb', 408, 3.2, 87, 6.5),
        createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
        createData('Jelly Bean', 375, 0.0, 94, 0.0),
        createData('KitKat', 518, 26.0, 65, 7.0),
        createData('Lollipop', 392, 0.2, 98, 0.0),
        createData('Marshmallow', 318, 0, 81, 2.0),
        createData('Nougat', 360, 19.0, 9, 37.0),
        createData('Oreo', 437, 18.0, 63, 4.0),
      ],
      page: 0,
      rowsPerPage: 5,
    };
  }

  handleRequestSort = (event, property) => {
    const orderBy = property;
    let order = 'desc';

    if (this.state.orderBy === property && this.state.order === 'desc') {
      order = 'asc';
    }

    this.setState({ order, orderBy });
  };

  handleSelectAllClick = (event, checked) => {
    if (checked) {
      this.setState(state => ({ selected: state.data.map(n => n.id) }));
      return;
    }
    this.setState({ selected: [] });
  };

  handleClick = (event, id) => {
    const { selected } = this.state;
    const selectedIndex = selected.indexOf(id);
    let newSelected = [];

    if (selectedIndex === -1) {
      newSelected = newSelected.concat(selected, id);
    } else if (selectedIndex === 0) {
      newSelected = newSelected.concat(selected.slice(1));
    } else if (selectedIndex === selected.length - 1) {
      newSelected = newSelected.concat(selected.slice(0, -1));
    } else if (selectedIndex > 0) {
      newSelected = newSelected.concat(
        selected.slice(0, selectedIndex),
        selected.slice(selectedIndex + 1),
      );
    }

    this.setState({ selected: newSelected });
  };

  handleChangePage = (event, page) => {
    this.setState({ page });
  };

  handleChangeRowsPerPage = event => {
    this.setState({ rowsPerPage: event.target.value });
  };

  isSelected = id => this.state.selected.indexOf(id) !== -1;

  render() {
    const { classes } = this.props;
    const { data, order, orderBy, selected, rowsPerPage, page } = this.state;
    const emptyRows = rowsPerPage - Math.min(rowsPerPage, data.length - page * rowsPerPage);

    return (
      <Paper className={classes.root}>
        <EnhancedTableToolbar numSelected={selected.length} />

            <EnhancedTableHead
              numSelected={selected.length}
              order={order}
              orderBy={orderBy}
              onSelectAllClick={this.handleSelectAllClick}
              onRequestSort={this.handleRequestSort}
              rowCount={data.length}
            />
            <TableBody>
              {data
                .sort(getSorting(order, orderBy))
                .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                .map(n => {
                  const isSelected = this.isSelected(n.id);
                  return (
                    <TableRow
                      hover
                      onClick={event => this.handleClick(event, n.id)}
                      role="checkbox"
                      aria-checked={isSelected}
                      tabIndex={-1}
                      key={n.id}
                      selected={isSelected}
                    >
                      <TableCell padding="checkbox">
                        <Checkbox checked={isSelected} />
                      </TableCell>
                      <TableCell component="th" scope="row" padding="none">
                        {n.name}
                      </TableCell>
                      <TableCell numeric>{n.calories}</TableCell>
                      <TableCell numeric>{n.fat}</TableCell>
                      <TableCell numeric>{n.carbs}</TableCell>
                      <TableCell numeric>{n.protein}</TableCell>
                    </TableRow>
                  );
                })}
              {emptyRows > 0 && (
                <TableRow style={{ height: 49 * emptyRows }}>
                  <TableCell colSpan={6} />
                </TableRow>
              )}
            </TableBody>

        <TablePagination
          component="div"
          count={data.length}
          rowsPerPage={rowsPerPage}
          page={page}
          backIconButtonProps={{
            'aria-label': 'Previous Page',
          }}
          nextIconButtonProps={{
            'aria-label': 'Next Page',
          }}
          onChangePage={this.handleChangePage}
          onChangeRowsPerPage={this.handleChangeRowsPerPage}
        />
      </Paper>
    );
  }
}

EnhancedTable.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(EnhancedTable);
<commit_msg>[docs] Improve the Table sorting logic (#12348)<commit_after>import React from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TablePagination from '@material-ui/core/TablePagination';
import TableRow from '@material-ui/core/TableRow';
import TableSortLabel from '@material-ui/core/TableSortLabel';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Paper from '@material-ui/core/Paper';
import Checkbox from '@material-ui/core/Checkbox';
import IconButton from '@material-ui/core/IconButton';
import Tooltip from '@material-ui/core/Tooltip';
import DeleteIcon from '@material-ui/icons/Delete';
import FilterListIcon from '@material-ui/icons/FilterList';
import { lighten } from '@material-ui/core/styles/colorManipulator';

let counter = 0;
function createData(name, calories, fat, carbs, protein) {
  counter += 1;
  return { id: counter, name, calories, fat, carbs, protein };
}

function getSorting(order, orderBy) {
  return order === 'desc' ? (a, b) => b[orderBy] - a[orderBy] : (a, b) => a[orderBy] - b[orderBy];
}

const columnData = [
  { id: 'name', numeric: false, disablePadding: true, label: 'Dessert (100g serving)' },
  { id: 'calories', numeric: true, disablePadding: false, label: 'Calories' },
  { id: 'fat', numeric: true, disablePadding: false, label: 'Fat (g)' },
  { id: 'carbs', numeric: true, disablePadding: false, label: 'Carbs (g)' },
  { id: 'protein', numeric: true, disablePadding: false, label: 'Protein (g)' },
];

class EnhancedTableHead extends React.Component {
  createSortHandler = property => event => {
    this.props.onRequestSort(event, property);
  };

  render() {
    const { onSelectAllClick, order, orderBy, numSelected, rowCount } = this.props;

    return (
      <TableHead>
        <TableRow>
          <TableCell padding="checkbox">
            <Checkbox
              indeterminate={numSelected > 0 && numSelected < rowCount}
              checked={numSelected === rowCount}
              onChange={onSelectAllClick}
            />
          </TableCell>
          {columnData.map(column => {
            return (
              <TableCell
                key={column.id}
                numeric={column.numeric}
                padding={column.disablePadding ? 'none' : 'default'}
                sortDirection={orderBy === column.id ? order : false}
              >
                <Tooltip
                  title="Sort"
                  placement={column.numeric ? 'bottom-end' : 'bottom-start'}
                  enterDelay={300}
                >
                  <TableSortLabel
                    active={orderBy === column.id}
                    direction={order}
                    onClick={this.createSortHandler(column.id)}
                  >
                    {column.label}
                  </TableSortLabel>
                </Tooltip>
              </TableCell>
            );
          }, this)}
        </TableRow>
      </TableHead>
    );
  }
}

EnhancedTableHead.propTypes = {
  numSelected: PropTypes.number.isRequired,
  onRequestSort: PropTypes.func.isRequired,
  onSelectAllClick: PropTypes.func.isRequired,
  order: PropTypes.string.isRequired,
  orderBy: PropTypes.string.isRequired,
  rowCount: PropTypes.number.isRequired,
};

const toolbarStyles = theme => ({
  root: {
    paddingRight: theme.spacing.unit,
  },
  highlight:
    theme.palette.type === 'light'
      ? {
          color: theme.palette.secondary.main,
          backgroundColor: lighten(theme.palette.secondary.light, 0.85),
        }
      : {
          color: theme.palette.text.primary,
          backgroundColor: theme.palette.secondary.dark,
        },
  spacer: {
    flex: '1 1 100%',
  },
  actions: {
    color: theme.palette.text.secondary,
  },
  title: {
    flex: '0 0 auto',
  },
});

let EnhancedTableToolbar = props => {
  const { numSelected, classes } = props;

  return (
    <Toolbar
      className={classNames(classes.root, {
        [classes.highlight]: numSelected > 0,
      })}
    >

        {numSelected > 0 ? (
          <Typography color="inherit" variant="subheading">
            {numSelected} selected
          </Typography>
        ) : (
          <Typography variant="title" id="tableTitle">
            Nutrition
          </Typography>
        )}

        {numSelected > 0 ? (
          <Tooltip title="Delete">
            <IconButton aria-label="Delete">
              <DeleteIcon />
            </IconButton>
          </Tooltip>
        ) : (
          <Tooltip title="Filter list">
            <IconButton aria-label="Filter list">
              <FilterListIcon />
            </IconButton>
          </Tooltip>
        )}

    </Toolbar>
  );
};

EnhancedTableToolbar.propTypes = {
  classes: PropTypes.object.isRequired,
  numSelected: PropTypes.number.isRequired,
};

EnhancedTableToolbar = withStyles(toolbarStyles)(EnhancedTableToolbar);

const styles = theme => ({
  root: {
    width: '100%',
    marginTop: theme.spacing.unit * 3,
  },
  table: {
    minWidth: 1020,
  },
  tableWrapper: {
    overflowX: 'auto',
  },
});

class EnhancedTable extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      order: 'asc',
      orderBy: 'calories',
      selected: [],
      data: [
        createData('Cupcake', 305, 3.7, 67, 4.3),
        createData('Donut', 452, 25.0, 51, 4.9),
        createData('Eclair', 262, 16.0, 24, 6.0),
        createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
        createData('Gingerbread', 356, 16.0, 49, 3.9),
        createData('Honeycomb', 408, 3.2, 87, 6.5),
        createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
        createData('Jelly Bean', 375, 0.0, 94, 0.0),
        createData('KitKat', 518, 26.0, 65, 7.0),
        createData('Lollipop', 392, 0.2, 98, 0.0),
        createData('Marshmallow', 318, 0, 81, 2.0),
        createData('Nougat', 360, 19.0, 9, 37.0),
        createData('Oreo', 437, 18.0, 63, 4.0),
      ],
      page: 0,
      rowsPerPage: 5,
    };
  }

  handleRequestSort = (event, property) => {
    const orderBy = property;
    let order = 'desc';

    if (this.state.orderBy === property && this.state.order === 'desc') {
      order = 'asc';
    }

    this.setState({ order, orderBy });
  };

  handleSelectAllClick = (event, checked) => {
    if (checked) {
      this.setState(state => ({ selected: state.data.map(n => n.id) }));
      return;
    }
    this.setState({ selected: [] });
  };

  handleClick = (event, id) => {
    const { selected } = this.state;
    const selectedIndex = selected.indexOf(id);
    let newSelected = [];

    if (selectedIndex === -1) {
      newSelected = newSelected.concat(selected, id);
    } else if (selectedIndex === 0) {
      newSelected = newSelected.concat(selected.slice(1));
    } else if (selectedIndex === selected.length - 1) {
      newSelected = newSelected.concat(selected.slice(0, -1));
    } else if (selectedIndex > 0) {
      newSelected = newSelected.concat(
        selected.slice(0, selectedIndex),
        selected.slice(selectedIndex + 1),
      );
    }

    this.setState({ selected: newSelected });
  };

  handleChangePage = (event, page) => {
    this.setState({ page });
  };

  handleChangeRowsPerPage = event => {
    this.setState({ rowsPerPage: event.target.value });
  };

  isSelected = id => this.state.selected.indexOf(id) !== -1;

  render() {
    const { classes } = this.props;
    const { data, order, orderBy, selected, rowsPerPage, page } = this.state;
    const emptyRows = rowsPerPage - Math.min(rowsPerPage, data.length - page * rowsPerPage);

    return (
      <Paper className={classes.root}>
        <EnhancedTableToolbar numSelected={selected.length} />

            <EnhancedTableHead
              numSelected={selected.length}
              order={order}
              orderBy={orderBy}
              onSelectAllClick={this.handleSelectAllClick}
              onRequestSort={this.handleRequestSort}
              rowCount={data.length}
            />
            <TableBody>
              {data
                .sort(getSorting(order, orderBy))
                .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                .map(n => {
                  const isSelected = this.isSelected(n.id);
                  return (
                    <TableRow
                      hover
                      onClick={event => this.handleClick(event, n.id)}
                      role="checkbox"
                      aria-checked={isSelected}
                      tabIndex={-1}
                      key={n.id}
                      selected={isSelected}
                    >
                      <TableCell padding="checkbox">
                        <Checkbox checked={isSelected} />
                      </TableCell>
                      <TableCell component="th" scope="row" padding="none">
                        {n.name}
                      </TableCell>
                      <TableCell numeric>{n.calories}</TableCell>
                      <TableCell numeric>{n.fat}</TableCell>
                      <TableCell numeric>{n.carbs}</TableCell>
                      <TableCell numeric>{n.protein}</TableCell>
                    </TableRow>
                  );
                })}
              {emptyRows > 0 && (
                <TableRow style={{ height: 49 * emptyRows }}>
                  <TableCell colSpan={6} />
                </TableRow>
              )}
            </TableBody>

        <TablePagination
          component="div"
          count={data.length}
          rowsPerPage={rowsPerPage}
          page={page}
          backIconButtonProps={{
            'aria-label': 'Previous Page',
          }}
          nextIconButtonProps={{
            'aria-label': 'Next Page',
          }}
          onChangePage={this.handleChangePage}
          onChangeRowsPerPage={this.handleChangeRowsPerPage}
        />
      </Paper>
    );
  }
}

EnhancedTable.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(EnhancedTable);
<|endoftext|>