<commit_before>import { startAtLogin,
  enterName,
  enterEmail,
  enterContactNumber,
  enterPassword,
  enterConfirmedPassword,
  enterGroupName,
  enterGroupDescription,
  selectGroup,
  clickEditCurrentGroup,
  clickEditOrganiser,
  clickLogin,
  clickNewOrganiser,
  clickNewGroup,
  clickSave,
  title,
  waitForExisting,
  waitForGroupOption,
} from './pages/adminPage';

function login(email, password) {
  return enterEmail(email)
    .then(() => enterPassword(password))
    .then(clickLogin);
}

function fillNewOrganiser() {
  return enterEmail('organiser@email.com')
    .then(() => enterName('Sasha'))
    .then(() => enterContactNumber('0401-223-443'))
    .then(() => enterPassword('a long password'))
    .then(() => enterConfirmedPassword('a long password'))
    .then(() => clickSave());
}

function editLastOrganiser() {
  return enterName('Sashana')
    .then(clickSave);
}

const adminTriesToLoginWithWrongPassword = {
  description: 'I should not be able to login with the wrong credentials',
  testRun: test => {
    startAtLogin()
    .then(() => test.assertEquals(title(), 'Login', 'I am on the login page'))
    .then(() => login('orgnsr@thelab.org', 'bad password'))
    .then(() => test.assertEquals(title(), 'Login', 'I am on the login page'));
  },
};

const adminLogsIn = {
  description: 'As an admin I should be able to login',
  testRun: test => {
    startAtLogin()
    .then(() => test.assertEquals(title(), 'Login', 'I am on the login page'))
    .then(() => login('admin@rr.com', 'apassword'))
    .then(() => test.assertEquals(title(), 'Rabble Rouser Admin', 'I am on the admin page'));
  },
};

const adminCanAddAnOrganiser = {
  description: 'As an admin I should be able to add an organiser to a lab',
  testRun: () => {
    startAtLogin()
    .then(() => login('admin@rr.com', 'apassword'))
    .then(() =>
      window.casper.waitForUrl(/dashboard\/admin$/)
    )
    .then(clickNewOrganiser)
    .then(fillNewOrganiser)
    .then(() => waitForExisting('Sasha'));
  },
};

const adminCanEditAnOrganiser = {
  description: 'As an admin I should be able to edit an organiser for a lab',
  testRun: () => {
    startAtLogin()
    .then(() => login('admin@rr.com', 'apassword'))
    .then(() =>
      window.casper.waitForUrl(/dashboard\/admin$/)
    )
    .then(() => waitForExisting('Sasha'))
    .then(clickEditOrganiser)
    .then(editLastOrganiser)
    .then(() => waitForExisting('Sashana'));
  },
};

function editGroup() {
  return enterGroupName('A group changed')
    .then(clickSave);
}

function fillNewGroup() {
  return enterGroupName('A group')
    .then(() => enterGroupDescription('This group does things'))
    .then(() => clickSave());
}

const adminCanAddAGroup = {
  description: 'As an admin I should be able to add a group',
  testRun: () => {
    startAtLogin()
    .then(() => login('admin@rr.com', 'apassword'))
    .then(() =>
      window.casper.waitForUrl(/dashboard\/admin$/)
    )
    .then(clickNewGroup)
    .then(fillNewGroup)
    .then(() => waitForGroupOption('A group'))
    .then(() => selectGroup('A group'))
    .then(() => waitForExisting('This group does things'));
  },
};

const adminCanEditAGroup = {
  description: 'As an admin I should be able to edit a group',
  testRun: () => {
    startAtLogin()
    .then(() => login('admin@rr.com', 'apassword'))
    .then(() =>
      window.casper.waitForUrl(/dashboard\/admin$/)
    )
    .then(() => waitForGroupOption('A group'))
    .then(() => selectGroup('A group'))
    .then(clickEditCurrentGroup)
    .then(editGroup)
    .then(() => waitForGroupOption('A group changed'));
  },
};

// Admin can edit a participnt
// Admin can add a lab
// Admin can edit a lab
// Admin can add an admin
// Admin can edit an admin

export default [
  adminLogsIn,
  adminTriesToLoginWithWrongPassword,
  adminCanAddAnOrganiser,
  adminCanEditAnOrganiser,
  adminCanAddAGroup,
  adminCanEditAGroup,
];
<commit_msg>Pull out common login steps into a function<commit_after>import { startAtLogin,
  enterName,
  enterEmail,
  enterContactNumber,
  enterPassword,
  enterConfirmedPassword,
  enterGroupName,
  enterGroupDescription,
  selectGroup,
  clickEditCurrentGroup,
  clickEditOrganiser,
  clickLogin,
  clickNewOrganiser,
  clickNewGroup,
  clickSave,
  title,
  waitForExisting,
  waitForGroupOption,
} from './pages/adminPage';

function login(email, password) {
  return enterEmail(email)
    .then(() => enterPassword(password))
    .then(clickLogin);
}

const adminTriesToLoginWithWrongPassword = {
  description: 'I should not be able to login with the wrong credentials',
  testRun: test => {
    startAtLogin()
    .then(() => test.assertEquals(title(), 'Login', 'I am on the login page'))
    .then(() => login('orgnsr@thebranch.org', 'bad password'))
    .then(() => test.assertEquals(title(), 'Login', 'I am on the login page'));
  },
};

function adminLogin() {
  return startAtLogin()
  .then(() => login('admin@rr.com', 'apassword'))
  .then(() =>
    window.casper.waitForUrl(/dashboard\/admin$/)
  );
}

const adminLogsIn = {
  description: 'As an admin I should be able to login',
  testRun: test => {
    adminLogin()
    .then(() => test.assertEquals(title(), 'Rabble Rouser Admin', 'I am on the admin page'));
  },
};

function fillNewOrganiser() {
  return enterEmail('organiser@email.com')
    .then(() => enterName('Sasha'))
    .then(() => enterContactNumber('0401-223-443'))
    .then(() => enterPassword('a long password'))
    .then(() => enterConfirmedPassword('a long password'))
    .then(() => clickSave());
}

function editLastOrganiser() {
  return enterName('Sashana')
    .then(clickSave);
}

const adminCanAddAnOrganiser = {
  description: 'As an admin I should be able to add an organiser to a branch',
  testRun: () => {
    adminLogin()
    .then(clickNewOrganiser)
    .then(fillNewOrganiser)
    .then(() => waitForExisting('Sasha'));
  },
};

const adminCanEditAnOrganiser = {
  description: 'As an admin I should be able to edit an organiser for a branch',
  testRun: () => {
    adminLogin()
    .then(() => waitForExisting('Sasha'))
    .then(clickEditOrganiser)
    .then(editLastOrganiser)
    .then(() => waitForExisting('Sashana'));
  },
};

function editGroup() {
  return enterGroupName('A group changed')
    .then(clickSave);
}

function fillNewGroup() {
  return enterGroupName('A group')
    .then(() => enterGroupDescription('This group does things'))
    .then(() => clickSave());
}

const adminCanAddAGroup = {
  description: 'As an admin I should be able to add a group',
  testRun: () => {
    adminLogin()
    .then(clickNewGroup)
    .then(fillNewGroup)
    .then(() => waitForGroupOption('A group'))
    .then(() => selectGroup('A group'))
    .then(() => waitForExisting('This group does things'));
  },
};

const adminCanEditAGroup = {
  description: 'As an admin I should be able to edit a group',
  testRun: () => {
    adminLogin()
    .then(() => waitForGroupOption('A group'))
    .then(() => selectGroup('A group'))
    .then(clickEditCurrentGroup)
    .then(editGroup)
    .then(() => waitForGroupOption('A group changed'));
  },
};

// Admin can edit a participnt
// Admin can add a lab
// Admin can edit a lab
// Admin can add an admin
// Admin can edit an admin

export default [
  adminLogsIn,
  adminTriesToLoginWithWrongPassword,
  adminCanAddAnOrganiser,
  adminCanEditAnOrganiser,
  adminCanAddAGroup,
  adminCanEditAGroup,
];
<|endoftext|>


<commit_before>/**
 * Sessions controller (authentication)
 * @author Alexandre Cazala <alexandre.cazala@gmail.com>
 * @module controller/session
 */
'use strict';

var mongoose = require('mongoose'),
    passport = require('passport');

/**
 * Session
 * returns info on authenticated user
 */
exports.session = function (req, res) {
    res.set('Access-Control-Allow-Origin','*');
    res.json(req.user.user_info);
};

/**
 * Logout
 * returns nothing
 */
exports.logout = function (req, res) {
    if(req.user) {
        req.logout();
        res.set('Access-Control-Allow-Origin','*');
        res.send(200);
    } else {
        res.set('Access-Control-Allow-Origin','*');
        res.status(400).send("Not logged in");
    }
};

/**
 *  Login
 *  requires: {email, password}
 */
exports.login = function (req, res, next) {
    passport.authenticate('local', function(err, user, info) {
        var error = err || info;
        if (error) {
            console.error(error);
            res.set('Access-Control-Allow-Origin','*');
            return res.json(400, error);
        }
        req.logIn(user, function(err) {
            if (err) {
                return res.send(err);
            }
            res.set('Access-Control-Allow-Origin','*');
            res.json(req.user.user_info);
        });
    })(req, res, next);
}<commit_msg>testCORS<commit_after>/**
 * Sessions controller (authentication)
 * @author Alexandre Cazala <alexandre.cazala@gmail.com>
 * @module controller/session
 */
'use strict';

var mongoose = require('mongoose'),
    passport = require('passport');

/**
 * Session
 * returns info on authenticated user
 */
exports.session = function (req, res) {
    res.header('Access-Control-Allow-Origin','*');
    res.json(req.user.user_info);
};

/**
 * Logout
 * returns nothing
 */
exports.logout = function (req, res) {
    if(req.user) {
        req.logout();
        res.set('Access-Control-Allow-Origin','*');
        res.send(200);
    } else {
        res.set('Access-Control-Allow-Origin','*');
        res.status(400).send("Not logged in");
    }
};

/**
 *  Login
 *  requires: {email, password}
 */
exports.login = function (req, res, next) {
    passport.authenticate('local', function(err, user, info) {
        var error = err || info;
        if (error) {
            console.error(error);
            res.header('Access-Control-Allow-Origin','*');
            return res.json(400, error);
        }
        req.logIn(user, function(err) {
            if (err) {
                return res.send(err);
            }
            res.header('Access-Control-Allow-Origin','*');
            res.json(req.user.user_info);
        });
    })(req, res, next);
};<|endoftext|>


<commit_before>const fs = require('fs')
const path = require('path')
const url = require('url')
const _ = require('lodash')
const async = require('async')
const mkdirp = require('mkdirp')
const mapboxFileSniff = require('@mapbox/mapbox-file-sniff')
const shapefileFairy = require('@mapbox/shapefile-fairy')
const tilelive = require('@mapbox/tilelive')
const mbtiles = require('mbtiles')
const tileliveOmnivore = require('@mapbox/tilelive-omnivore')
const Tileset = require('../models/tileset')

mbtiles.registerProtocols(tilelive)
tileliveOmnivore.registerProtocols(tilelive)

module.exports.list = function(req, res, next) {
  const owner = req.params.owner

  Tileset.find({owner}, (err, tilesets) => {
    if (err) return next(err)

    res.json(tilesets)
  })
}

module.exports.get = function(req, res, next) {
  const owner = req.params.owner
  const tilesetId = req.params.tilesetId
  const tilesetPath = path.join('tilesets', owner, tilesetId)

  Tileset.findOne({owner, tilesetId}, (err, tileset) => {
    if (err) return next(err)
    if (!tileset) return res.sendStatus(404)

    const source = 'mbtiles://' + path.resolve(tilesetPath)
    tilelive.info(source, (err, info) => {
      if (err) return next(err)

      const urlObject = url.parse(req.originalUrl)
      urlObject.protocol = req.protocol
      urlObject.host = req.get('host')
      urlObject.path = urlObject.pathname + '/{z}/{x}/{y}.' + info.format
      info.tiles = [url.format(urlObject)]
      info.scheme = 'xyz'
      res.json(Object.assign(info, tileset.toJSON()))
    })
  })
}

module.exports.create = function(req, res, next) {
  const owner = req.params.owner
  const tilesetId = req.params.tilesetId
  const filePath = path.resolve(req.files[0].path)
  const originalname = req.files[0].originalname

  async.autoInject({
    tileset: callback => {
      if (!tilesetId) {
        const tileset = new Tileset({owner})
        return tileset.save((err, tileset) => callback(err, tileset))
      }

      Tileset.findOne({owner, tilesetId}, (err, tileset) => {
        if (err) return callback(err)
        if (!tileset) return callback({status: 404})

        callback(null, tileset)
      })
    },

    fileinfo: callback => {
      mapboxFileSniff.fromFile(filePath, callback)
    },

    source: (fileinfo, callback) => {
      if (fileinfo.protocol !== 'omnivore:' && fileinfo.protocol !== 'mbtiles:') {
        return callback({status: 400, message: 'Unsupport file format.'})
      }

      if (fileinfo.type === 'zip') {
        return shapefileFairy(filePath, (err, path) => {
          callback(err, fileinfo.protocol + '//' + path)
        })
      }

      callback(null, fileinfo.protocol + '//' + filePath)
    },

    info: (source, callback) => {
      tilelive.info(source, callback)
    },

    writeDB: (tileset, info, callback) => {
      tileset.name = tileset.name || info.name || path.basename(originalname, path.extname(originalname))
      tileset.description = tileset.description || info.description
      tileset.complete = false
      tileset.progress = 0
      tileset.err = undefined
      tileset.save((err, tileset) => callback(err, tileset))
    }
  }, (err, results) => {
    if (err) return next(err)

    res.json(results.writeDB)

    // Import Tiles
    const tileset = results.writeDB
    const source = results.source

    const tilesetDir = path.join('tilesets', owner)
    mkdirp(tilesetDir, err => {
      if (err) return tileset.save()

      const dest = `mbtiles://${path.resolve(tilesetDir)}/${tileset.tilesetId}`
      const options = {
        retry: 2,
        timeout: 120000,
        close: true,
        progress: _.throttle((stats, p) => {
          tileset.update({progress: Math.round(p.percentage)})
        })
      }

      tilelive.copy(source, dest, options, err => {
        tileset.update({complete: true, error: err})
        fs.unlink(filePath)
      })
    })
  })
}

module.exports.update = function(req, res, next) {
  const owner = req.params.owner
  const tilesetId = req.params.tilesetId
  const update = _.pick(req.body, ['name', 'description'])

  Tileset.findOneAndUpdate({owner, tilesetId}, update, {new: true}, (err, tileset) => {
    if (err) return next(err)
    if (!tileset) res.sendStatus(404)

    res.json(tileset)
  })
}

module.exports.delete = function(req, res, next) {
  const owner = req.params.owner
  const tilesetId = req.params.tilesetId
  const tilesetPath = path.join('tilesets', owner, tilesetId)

  Tileset.findOneAndRemove({owner, tilesetId}, (err, tileset) => {
    if (err) return next(err)
    if (!tileset) return res.sendStatus(404)

    fs.unlink(tilesetPath, err => {
      if (err) return next(err)

      res.sendStatus(204)
    })
  })
}

module.exports.getTile = function(req, res, next) {
  const owner = req.params.owner
  const tilesetId = req.params.tilesetId
  const z = +req.params.z || 0
  const x = +req.params.x || 0
  const y = +req.params.y || 0

  const tilesetPath = path.join('tilesets', owner, tilesetId)
  const source = 'mbtiles://' + path.resolve(tilesetPath)
  tilelive.load(source, (err, source) => {
    if (err) return next(err)

    source.getTile(z, x, y, (err, data, headers) => {
      if (err) return next(err)

      res.set(headers)
      res.send(data)
    })
  })
}
<commit_msg>bugfix tileset upload<commit_after>const fs = require('fs')
const path = require('path')
const url = require('url')
const _ = require('lodash')
const async = require('async')
const mkdirp = require('mkdirp')
const mapboxFileSniff = require('@mapbox/mapbox-file-sniff')
const shapefileFairy = require('@mapbox/shapefile-fairy')
const tilelive = require('@mapbox/tilelive')
const mbtiles = require('mbtiles')
const tileliveOmnivore = require('@mapbox/tilelive-omnivore')
const Tileset = require('../models/tileset')

mbtiles.registerProtocols(tilelive)
tileliveOmnivore.registerProtocols(tilelive)

module.exports.list = function(req, res, next) {
  const owner = req.params.owner

  Tileset.find({owner}, (err, tilesets) => {
    if (err) return next(err)

    res.json(tilesets)
  })
}

module.exports.get = function(req, res, next) {
  const owner = req.params.owner
  const tilesetId = req.params.tilesetId
  const tilesetPath = path.join('tilesets', owner, tilesetId)

  Tileset.findOne({owner, tilesetId}, (err, tileset) => {
    if (err) return next(err)
    if (!tileset) return res.sendStatus(404)

    const source = 'mbtiles://' + path.resolve(tilesetPath)
    tilelive.info(source, (err, info) => {
      if (err) return next(err)

      const urlObject = url.parse(req.originalUrl)
      urlObject.protocol = req.protocol
      urlObject.host = req.get('host')
      urlObject.path = urlObject.pathname + '/{z}/{x}/{y}.' + info.format
      info.tiles = [url.format(urlObject)]
      info.scheme = 'xyz'
      res.json(Object.assign(info, tileset.toJSON()))
    })
  })
}

module.exports.create = function(req, res, next) {
  const owner = req.params.owner
  const tilesetId = req.params.tilesetId
  const filePath = path.resolve(req.files[0].path)
  const originalname = req.files[0].originalname

  async.autoInject({
    tileset: callback => {
      if (!tilesetId) {
        const tileset = new Tileset({owner})
        return tileset.save((err, tileset) => callback(err, tileset))
      }

      Tileset.findOne({owner, tilesetId}, (err, tileset) => {
        if (err) return callback(err)
        if (!tileset) return callback({status: 404})

        callback(null, tileset)
      })
    },

    fileinfo: callback => {
      mapboxFileSniff.fromFile(filePath, callback)
    },

    source: (fileinfo, callback) => {
      if (fileinfo.protocol !== 'omnivore:' && fileinfo.protocol !== 'mbtiles:') {
        return callback({status: 400, message: 'Unsupport file format.'})
      }

      if (fileinfo.type === 'zip') {
        return shapefileFairy(filePath, (err, path) => {
          callback(err, fileinfo.protocol + '//' + path)
        })
      }

      callback(null, fileinfo.protocol + '//' + filePath)
    },

    info: (source, callback) => {
      tilelive.info(source, callback)
    },

    tilesetDir: (callback) => {
      const dir = path.join('tilesets', owner)
      mkdirp(dir, err => callback(err, dir))
    },

    copy: (tileset, source, tilesetDir, callback) => {
      const dest = `mbtiles://${path.resolve(tilesetDir)}/${tileset.tilesetId}`
      const options = {
        retry: 2,
        timeout: 120000
      }

      tilelive.copy(source, dest, options, callback)
    },

    writeDB: (tileset, info, callback) => {
      tileset.name = tileset.name || info.name || path.basename(originalname, path.extname(originalname))
      tileset.description = tileset.description || info.description
      tileset.save((err, tileset) => callback(err, tileset))
    }
  }, (err, results) => {
    if (err) return next(err)

    res.json(results.writeDB)
  })
}

module.exports.update = function(req, res, next) {
  const owner = req.params.owner
  const tilesetId = req.params.tilesetId
  const update = _.pick(req.body, ['name', 'description'])

  Tileset.findOneAndUpdate({owner, tilesetId}, update, {new: true}, (err, tileset) => {
    if (err) return next(err)
    if (!tileset) res.sendStatus(404)

    res.json(tileset)
  })
}

module.exports.delete = function(req, res, next) {
  const owner = req.params.owner
  const tilesetId = req.params.tilesetId
  const tilesetPath = path.join('tilesets', owner, tilesetId)

  Tileset.findOneAndRemove({owner, tilesetId}, (err, tileset) => {
    if (err) return next(err)
    if (!tileset) return res.sendStatus(404)

    fs.unlink(tilesetPath, err => {
      if (err) return next(err)

      res.sendStatus(204)
    })
  })
}

module.exports.getTile = function(req, res, next) {
  const owner = req.params.owner
  const tilesetId = req.params.tilesetId
  const z = +req.params.z || 0
  const x = +req.params.x || 0
  const y = +req.params.y || 0

  const tilesetPath = path.join('tilesets', owner, tilesetId)
  const source = 'mbtiles://' + path.resolve(tilesetPath)
  tilelive.load(source, (err, source) => {
    if (err) return next(err)

    source.getTile(z, x, y, (err, data, headers) => {
      if (err) return next(err)

      res.set(headers)
      res.send(data)
    })
  })
}
<|endoftext|>


<commit_before>var Twitter = require('node-tweet-stream');

var MINIMUM_IMAGE_WIDTH = 300;
var MINIMUM_IMAGE_HEIGHT = 300;

function isLargeEnoughMedia(media) {
  if (
    media.sizes
    && media.sizes.medium
    && media.sizes.medium.w
    && media.sizes.medium.w >= MINIMUM_IMAGE_WIDTH
    && media.sizes.medium.h
    && media.sizes.medium.h >= MINIMUM_IMAGE_HEIGHT
  ) {
    return true;
  }

  return false;
}

function isValidMedia(tweet) {
  if (
    tweet.entities
    && tweet.entities.media
    && tweet.entities.media[0]
    && tweet.entities.media[0].type
    && tweet.entities.media[0].type === "photo"
    && isLargeEnoughMedia(tweet.entities.media[0])
  ) {
    return true;
  }

  return false;
}

var isValidTweet = function (tweet, config) {

  //
  // Check that track keywords are part of tweet's text
  //
  var trackKeywords = config.application.trackKeywords.replace(/[, ]/g, '|');
  var trackKeywordsRegex = new RegExp(trackKeywords, 'gim');

  if (! tweet.text.match(trackKeywordsRegex)) {
    return false;
  }

  //
  // Check that exclude keywords are NOT part of tweet's text
  //
  var excludeKeywords = config.application.excludeKeywords.replace(/[, ]/g, '|');
  var excludeKeywordsRegex = new RegExp(excludeKeywords, 'gim');

  if (tweet.text.match(excludeKeywordsRegex)) {
    return false;
  }

  if (! isValidMedia(tweet)) {
    return false;
  }

  var validTweet = true;

  // Validate tweet with filters
  config.application.filters.forEach(function (filter) {
    if (validTweet) {
      validTweet = require('../filters/' + filter).isValid(tweet);
    }
  });

  return validTweet;
};

module.exports = function (config, handleTweet) {
  var TWITTER_CONSUMER_KEY = config.twitter.api.consumerKey;
  var TWITTER_CONSUMER_SECRET = config.twitter.api.consumerSecret;
  var TWITTER_ACCESS_TOKEN_KEY = config.twitter.api.accessTokenKey;
  var TWITTER_ACCESS_TOKEN_SECRET = config.twitter.api.accessTokenSecret;
  var TWITTER_PICTURE_TRACK_KEYWORD = "pic twitter com";

  var keywords = TWITTER_PICTURE_TRACK_KEYWORD;
  var keywords = [TWITTER_PICTURE_TRACK_KEYWORD, config.application.trackKeywords].join(' ');

  var twitter = new Twitter({
    consumer_key: TWITTER_CONSUMER_KEY,
    consumer_secret: TWITTER_CONSUMER_SECRET,
    token: TWITTER_ACCESS_TOKEN_KEY,
    token_secret: TWITTER_ACCESS_TOKEN_SECRET
  });

  twitter.on('tweet', function (tweet) {
    if (isValidTweet(tweet, config)) {
      handleTweet(tweet);
    }
  });

  twitter.on('error', function (error) {
    console.error('[Snapkite][Error] ' + error);
  })

  twitter.track(keywords);
};
<commit_msg>Fix tracking keywords<commit_after>var Twitter = require('node-tweet-stream');

var MINIMUM_IMAGE_WIDTH = 300;
var MINIMUM_IMAGE_HEIGHT = 300;

function isLargeEnoughMedia(media) {
  if (
    media.sizes
    && media.sizes.medium
    && media.sizes.medium.w
    && media.sizes.medium.w >= MINIMUM_IMAGE_WIDTH
    && media.sizes.medium.h
    && media.sizes.medium.h >= MINIMUM_IMAGE_HEIGHT
  ) {
    return true;
  }

  return false;
}

function isValidMedia(tweet) {
  if (
    tweet.entities
    && tweet.entities.media
    && tweet.entities.media[0]
    && tweet.entities.media[0].type
    && tweet.entities.media[0].type === "photo"
    && isLargeEnoughMedia(tweet.entities.media[0])
  ) {
    return true;
  }

  return false;
}

var isValidTweet = function (tweet, config) {

  //
  // Check that track keywords are part of tweet's text
  //
  var trackKeywords = config.application.trackKeywords.replace(/[, ]/g, '|');
  var trackKeywordsRegex = new RegExp(trackKeywords, 'gim');

  if (! tweet.text.match(trackKeywordsRegex)) {
    return false;
  }

  //
  // Check that exclude keywords are NOT part of tweet's text
  //
  var excludeKeywords = config.application.excludeKeywords.replace(/[, ]/g, '|');
  var excludeKeywordsRegex = new RegExp(excludeKeywords, 'gim');

  if (tweet.text.match(excludeKeywordsRegex)) {
    return false;
  }

  if (! isValidMedia(tweet)) {
    return false;
  }

  var validTweet = true;

  // Validate tweet with filters
  config.application.filters.forEach(function (filter) {
    if (validTweet) {
      validTweet = require('../filters/' + filter).isValid(tweet);
    }
  });

  return validTweet;
};

module.exports = function (config, handleTweet) {
  var TWITTER_CONSUMER_KEY = config.twitter.api.consumerKey;
  var TWITTER_CONSUMER_SECRET = config.twitter.api.consumerSecret;
  var TWITTER_ACCESS_TOKEN_KEY = config.twitter.api.accessTokenKey;
  var TWITTER_ACCESS_TOKEN_SECRET = config.twitter.api.accessTokenSecret;
  var TWITTER_PICTURE_TRACK_KEYWORD = "pic twitter com";

  var keywords = config.application.trackKeywords.split(',').map(function (keyword) {
    return (TWITTER_PICTURE_TRACK_KEYWORD + ' ' + keyword);
  });

  var twitter = new Twitter({
    consumer_key: TWITTER_CONSUMER_KEY,
    consumer_secret: TWITTER_CONSUMER_SECRET,
    token: TWITTER_ACCESS_TOKEN_KEY,
    token_secret: TWITTER_ACCESS_TOKEN_SECRET
  });

  twitter.on('tweet', function (tweet) {
    if (isValidTweet(tweet, config)) {
      handleTweet(tweet);
    }
  });

  twitter.on('error', function (error) {
    console.error('[Snapkite][Error] ' + error);
  })

  twitter.track(keywords);
};
<|endoftext|>


<commit_before>import Moment from 'moment';

export default class Dates {

    static DATE_FORMAT = 'DD/MM/YYYY'
    static DATETIME_FORMAT = 'DD/MM/YYYY hh:mm'
    static MILLIS = 'millis'
    static DAYS = 'days'
    static MONTHS = 'months'
    static YEARS = 'years'

    static format(date, pattern = Dates.DATE_FORMAT) {
        return date == null ? '' : Moment(date).format(pattern)
    }

    static formatDatetime(dateTime) {
        return Dates.format(dateTime, Dates.DATETIME_FORMAT)
    }

    static compare(date1, date2, datePart) {
        if (! datePart) {
            datePart = Dates.MILLIS
        }
        const d1 = new Date(date1.getTime())
        const d2 = new Date(date2.getTime())

        switch(datePart) {
            case Dates.YEARS:
                d1.setMonth(0)
                d2.setMonth(0)
            case Dates.MONTHS:
                d1.setDate(1)
                d2.setDate(1)
            case Dates.DAYS:
            default:
                d1.setHours(0, 0, 0, 0)
                d2.setHours(0, 0, 0, 0)
        }
        return d1.getTime() < d2.getTime() ? -1 : d1.getTime() > d2.getTime() ? 1 : 0
    }
}
    <commit_msg>Fixed wrong date time formatting<commit_after>import Moment from 'moment';

export default class Dates {

    static DATE_FORMAT = 'DD/MM/YYYY'
    static DATETIME_FORMAT = 'DD/MM/YYYY HH:mm'
    static MILLIS = 'millis'
    static DAYS = 'days'
    static MONTHS = 'months'
    static YEARS = 'years'

    static format(date, pattern = Dates.DATE_FORMAT) {
        return date == null ? '' : Moment(date).format(pattern)
    }

    static formatDatetime(dateTime) {
        return Dates.format(dateTime, Dates.DATETIME_FORMAT)
    }

    static compare(date1, date2, datePart) {
        if (! datePart) {
            datePart = Dates.MILLIS
        }
        const d1 = new Date(date1.getTime())
        const d2 = new Date(date2.getTime())

        switch(datePart) {
            case Dates.YEARS:
                d1.setMonth(0)
                d2.setMonth(0)
            case Dates.MONTHS:
                d1.setDate(1)
                d2.setDate(1)
            case Dates.DAYS:
            default:
                d1.setHours(0, 0, 0, 0)
                d2.setHours(0, 0, 0, 0)
        }
        return d1.getTime() < d2.getTime() ? -1 : d1.getTime() > d2.getTime() ? 1 : 0
    }
}
    <|endoftext|>


<commit_before>var express = require("express");
var rp = require("request-promise");
var router = express.Router(); // eslint-disable-line new-cap

/* GET administration page. */
router.get("/", function handleIndexRequest(req, res) {
  res.render("Administration");
});

router.get("/is_crawling", function handleIsCrawingRequest(req, res) {
  if (!process.env.CRAWLING_SERVICE_URL) {
    res.json({
      "status": "failure",
      "msg": "Need to set CRAWLING_SERVICE_URL to use crawler"
    });
  } else {
    rp.get(process.env.CRAWLING_SERVICE_URL + "/is_crawling").then(function(json) {
      res.json({
        "status": "success",
        "data": json
      });
    }).catch(function onError(err) {
      res.json({
        "status": "failure"
      });
    });
  }
});

router.post("/start_crawling", function handleStartCrawlingRequest(req, res) {
  if (!process.env.CRAWLING_SERVICE_URL) {
    res.json({
      "status": "failure",
      "msg": "Need to set CRAWLING_SERVICE_URL to use crawler"
    });
  } else {
    rp.post(process.env.CRAWLING_SERVICE_URL + "/start_crawling").then(function(json) {
      res.json({
        status: JSON.parse(json).status === "started" ? "success" : "failure"
      });
    }).catch(function onError(err) {
      res.json({
        "status": "failure",
        "data": String(err)
      });
    });
  }
});

module.exports = router;
<commit_msg>administration: Additional eslint errors<commit_after>var express = require("express");
var rp = require("request-promise");
var router = express.Router(); // eslint-disable-line new-cap

/* GET administration page. */
router.get("/", function handleIndexRequest(req, res) {
  res.render("Administration");
});

router.get("/is_crawling", function handleIsCrawingRequest(req, res) {
  if (!process.env.CRAWLING_SERVICE_URL) {
    res.json({
      status: "failure",
      msg: "Need to set CRAWLING_SERVICE_URL to use crawler"
    });
  } else {
    rp.get(process.env.CRAWLING_SERVICE_URL + "/is_crawling").then(function onCheckCrawling(json) {
      res.json({
        status: "success",
        data: json
      });
    }).catch(function onError() {
      res.json({
        status: "failure"
      });
    });
  }
});

router.post("/start_crawling", function handleStartCrawlingRequest(req, res) {
  if (!process.env.CRAWLING_SERVICE_URL) {
    res.json({
      status: "failure",
      msg: "Need to set CRAWLING_SERVICE_URL to use crawler"
    });
  } else {
    rp.post(process.env.CRAWLING_SERVICE_URL + "/start_crawling").then(function onStartCrawling(json) {
      res.json({
        status: JSON.parse(json).status === "started" ? "success" : "failure"
      });
    }).catch(function onError(err) {
      res.json({
        status: "failure",
        data: String(err)
      });
    });
  }
});

module.exports = router;
<|endoftext|>


<commit_before>/*
 * @class LayerChooser
 * @aka window.LayerChooser
 * @inherits L.Controls.Layers
 *
 * Provides 'persistence' of layers display state between sessions.
 *
 * Also some additional methods provided, see below.
 */

'use strict';

var LayerChooser = L.Control.Layers.extend({
  options: {
    // @option sortLayers: Boolean = true
    // Ensures stable sort order (based on initial), while still providing ability
    // to enforce specific order with `addBaseLayer`/`addOverlay`
    // `sortPriority` option.
    sortLayers: true,

    sortFunction: function (layerA, layerB) {
      var a = layerA._chooser.sortPriority;
      var b = layerB._chooser.sortPriority;
      return a < b ? -1 : (b < a ? 1 : 0);
    }
  },

  initialize: function (baseLayers, overlays, options) {
    this._overlayStatus = {};
    var layersJSON = localStorage['ingress.intelmap.layergroupdisplayed'];
    if (layersJSON) {
      try {
        this._overlayStatus = JSON.parse(layersJSON);
      } catch (e) {
        log.error(e);
      }
    }
    this._mapToAdd = options && options.map;
    this.lastBaseLayerName = localStorage['iitc-base-map'];
    this._lastPriority = -1000; // initial layers get priority <0
    L.Control.Layers.prototype.initialize.apply(this, arguments);
    this._lastPriority = 0; // any following gets >0
  },

  _addLayer: function (layer, label, overlay, options) {
    options = options || {};
    // stored on first add (with .addBaseLayer/.addOverlay)
    var data = layer._chooser;
    if (!data) {
      data = {
        // name should be unique, otherwise behavior of other methods is undefined
        // (typically: first found will be taken)
        name: label,
        overlay: overlay,
        persistent: 'persistent' in options ? options.persistent : true
      };
      layer._chooser = data;
    } else {
      label = label || data.label || data.name;
    }
    // provide stable sort order
    if ('sortPriority' in options) {
      data.sortPriority = options.sortPriority;
    } else if (!('sortPriority' in data)) {
      this._lastPriority = this._lastPriority + 10;
      data.sortPriority = this._lastPriority;
    }
    L.Control.Layers.prototype._addLayer.call(this, layer, label, overlay);
    if (data.overlay) {
      data.default = 'default' in options ? options.default : true;
    }
    var map = this._map || this._mapToAdd;
    if (!data.persistent) {
      if (!data.overlay) { return; }
      if ('enable' in options ? options.enable : data.default) {
        layer.addTo(map);
      }
      return;
    }
    if (overlay) {
      data.statusTracking = function (e) {
        this._storeOverlayState(data.name, e.type === 'add');
      };
      layer.on('add remove', data.statusTracking, this);
      if ('enable' in options) { // do as explicitly specified
        map[options.enable ? 'addLayer' : 'removeLayer'](layer);
      } else if (layer._map) { // already on map, only store state
        this._storeOverlayState(data.name, true);
      } else { // restore at recorded state
        if (this._isOverlayDisplayed(data.name, data.default)) {
          layer.addTo(map);
        }
      }
    } else {
      data.statusTracking = function () {
        localStorage['iitc-base-map'] = data.name;
      };
      layer.on('add', data.statusTracking);
    }
  },

  // @miniclass LayersEntry options (LayerChooser)
  // @aka layersEntry options

  // @option persistent: Boolean = true
  // * When `false` - baselayer's status is not tracked.

  // @option sortPriority: Number = *
  // Enforces specific order in control, lower value means layer's upper position.
  // If not specified - the value will be assigned implicitly in increasing manner.

  // @method addBaseLayer(layer: Layer, name: String, options?: LayersEntry options): this
  // Adds a base layer (radio button entry) with the given name to the control.
  addBaseLayer: function (layer, name, options) {
    this._addLayer(layer, name, false, options);
    return (this._map) ? this._update() : this;
  },

  // @miniclass AddOverlay options (LayerChooser)
  // @aka addOverlay options
  // @inherits LayersEntry options

  // @option persistent: Boolean = true
  // * When `true` (or not specified) - adds overlay to the map as well,
  //   if it's last state was active.
  //   If no record exists then value specified in `default` option is used.
  // * When `false` - overlay status is not tracked, `default` option is honored too.

  // @option default: Boolean = true
  // Default state of overlay (used only when no record about previous state found).

  // @option enable: Boolean
  // Enforce specified state ignoring previously saved.

  // @method addOverlay(layer: L.Layer, name: String, options?: AddOverlay options): this
  // Adds an overlay (checkbox entry) with the given name to the control.
  addOverlay: function (layer, name, options) {
    this._addLayer(layer, name, true, options);
    return (this._map) ? this._update() : this;
  },

  // @method removeLayer(layer: Layer|String, keepOnMap?: Boolean): this
  // Removes the given layer from the control.
  // Either layer object or it's name in the control must be specified.
  // Layer is removed from the map as well, except `keepOnMap` argument is true. // todo?? {keepOnMap: true}
  removeLayer: function (layer, keepOnMap) {
    layer = this.getLayer(layer);
    if (layer) {
      var data = layer._chooser;
      if (data.statusTracking) {
        layer.off('add remove', data.statusTracking, this);
        delete data.statusTracking;
      }
      L.Control.Layers.prototype.removeLayer.apply(this, arguments);
      if (this._map && !keepOnMap) {
        map.removeLayer(layer);
      }
    } else {
      log.warn('Layer not found');
    }
    return this;
  },

  _storeOverlayState: function (name, isDisplayed) {
    this._overlayStatus[name] = isDisplayed;
    localStorage['ingress.intelmap.layergroupdisplayed'] = JSON.stringify(this._overlayStatus);
  },

  _isOverlayDisplayed: function (name, defaultState) {
    if (name in this._overlayStatus) {
      return this._overlayStatus[name];
    }
    return defaultState;
  },

  __byName: function (el) {
    var name = this.toString();
    return el.layer._chooser.name === name ||
      el.name === name;
  },

  __byLayer: function (el) {
    return el.layer === this;
  },

  // layer: either Layer or it's name in the control
  _layerInfo: function (layer) {
    var fn = layer instanceof L.Layer
      ? this.__byLayer
      : this.__byName;
    return this._layers.find(fn, layer);
  },

  // @method getLayer(name: String|Layer): Layer
  // Returns layer by it's name in the control, or by layer object itself.
  // The latter can be used to ensure the layer is in layerChooser.
  getLayer: function (layer) {
    var info = this._layerInfo(layer);
    return info && info.layer;
  },

  // @method showLayer(layer: Layer|String|Number, display?: Boolean): this
  // Switches layer's display state to given value (true by default).
  // Layer can be specified also by it's name in the control.
  showLayer: function (layer, display) {
    var info = this._layers[layer]; // layer is index, private use only
    if (info) {
      layer = info.layer;
    } else {
      layer = this.getLayer(layer);
      if (!layer) {
        log.warn('Layer not found');
        return this;
      }
    }
    var map = this._map;
    if (display || arguments.length === 1) {
      if (!map.hasLayer(layer)) {
        if (!layer._chooser.overlay) {
          // if it's a base layer, remove any others
          this._layers.forEach(function (el) {
            if (!el.overlay && el.layer !== layer) {
              map.removeLayer(el.layer);
            }
          });
        }
        map.addLayer(layer);
      }
    } else {
      map.removeLayer(layer);
    }
    return this;
  },

  // @method setLabel(layer: String|Layer, label?: String): this
  // Sets layers label to specified label text (html),
  // or resets it to original name when label is not specified.
  setLabel: function (layer, label) {
    var fn = layer instanceof L.Layer
      ? this.__byLayer
      : this.__byName;
    var idx = this._layers.findIndex(fn, layer);
    if (idx === -1) {
      log.warn('Layer not found');
      return this;
    }
    var info = this._layers[idx];
    label = label || info.layer._chooser.name;
    info.name = label;
    var nameEl = this._layerControlInputs[idx].closest('label').querySelector('span');
    nameEl.innerHTML = ' ' + label;
    return this;
  },

  // adds listeners to the overlays list to make inputs toggleable.
  _initLayout: function () {
    L.Control.Layers.prototype._initLayout.call(this);
    $(this._overlaysList).on('click taphold', 'label', function (e) {
      if (!(e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.type === 'taphold')) {
        return;
      }
      // e.preventDefault(); // seems no effect
      var input = e.target.closest('label').querySelector('input');
      var idx = this._layerControlInputs.indexOf(input);
      this._toggleOverlay(idx);
    }.bind(this));
  },

  _filterOverlays: function (el) {
    return el.overlay &&
      ['DEBUG Data Tiles', 'Resistance', 'Enlightened'].indexOf(el.layer._chooser.name) === -1;
  },

  // Hides all the control's overlays except given one,
  // or restores all, if it was the only one displayed (or none was displayed).
  _toggleOverlay: function (idx) {
    var info = this._layers[idx];
    if (!info || !info.overlay) {
      log.warn('Overlay not found: ', info);
      return;
    }
    var map = this._map;

    var isChecked = map.hasLayer(info.layer);
    var checked = 0;
    var overlays = this._layers.filter(this._filterOverlays);
    overlays.forEach(function (el) {
      if (map.hasLayer(el.layer)) { checked++; }
    });

    if (checked === 0 || isChecked && checked === 1) {
      // if nothing is selected, or specified overlay is exclusive,
      // assume all boxes should be checked again
      overlays.forEach(function (el) {
        if (el.layer._chooser.default) {
          map.addLayer(el.layer);
        }
      });
    } else {
      // uncheck all, check specified
      overlays.forEach(function (el) {
        if (el.layer === info.layer) {
          map.addLayer(el.layer);
        } else {
          map.removeLayer(el.layer);
        }
      });
    }
  },

  _stripHtmlTags: function (str) {
    return str.replace(/(<([^>]+)>)/gi, ''); // https://css-tricks.com/snippets/javascript/strip-html-tags-in-javascript/
  },

  // !!deprecated
  getLayers: function () {
    var baseLayers = [];
    var overlayLayers = [];
    this._layers.forEach(function (info, idx) {
      (info.overlay ? overlayLayers : baseLayers).push({
        layerId: idx,
        name: this._stripHtmlTags(info.name), // IITCm does not support html in layers labels
        active: this._map.hasLayer(info.layer)
      });
    }, this);

    return {
      baseLayers: baseLayers,
      overlayLayers: overlayLayers
    };
  }
});

window.LayerChooser = LayerChooser;

function debounce (callback, time) { // https://gist.github.com/nmsdvid/8807205#gistcomment-2641356
  var timeout;
  return function () {
    var context = this;
    var args = arguments;
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(function () {
      timeout = null;
      callback.apply(context, args);
    }, time);
  };
}

if (typeof android !== 'undefined' && android && android.setLayers) {
  // hook some additional code into the LayerControl so it's easy for the mobile app to interface with it
  LayerChooser.include({
    _setAndroidLayers: debounce(function () { // update layer menu in IITCm
      var l = this.getLayers();
      android.setLayers(JSON.stringify(l.baseLayers), JSON.stringify(l.overlayLayers));
    }, 1000),

    setLabel: (function (setLabel) {
      return function () {
        this._setAndroidLayers();
        return setLabel.apply(this, arguments);
      };
    })(LayerChooser.prototype.setLabel),

    _update: function () {
      this._setAndroidLayers();
      return L.Control.Layers.prototype._update.apply(this, arguments);
    }
  });
}

// contains current status(on/off) of overlay layerGroups.
// !!deprecated: use `map.hasLayer` instead (https://leafletjs.com/reference.html#map-haslayer)
window.overlayStatus = {}; // to be set in constructor

// Reads recorded layerGroup status (as it may not be added to map yet),
// return `defaultDisplay` if no record found.
// !!deprecated: for most use cases prefer `getLayer()` method
// or `map.hasLayer` (https://leafletjs.com/reference.html#map-haslayer)
// window.isLayerGroupDisplayed = function (name, defaultDisplay) { // ...
window.isLayerGroupDisplayed = L.Util.falseFn; // to be set in constructor

LayerChooser.addInitHook(function () {
  window.overlayStatus = this._overlayStatus;
  window.isLayerGroupDisplayed = this._isOverlayDisplayed.bind(this);
});

// !!deprecated: use `layerChooser.addOverlay` directly
window.addLayerGroup = function (name, layerGroup, defaultDisplay) {
  var options = {default: defaultDisplay};
  if (arguments.length < 3) { options = undefined; }
  window.layerChooser.addOverlay(layerGroup, name, options);
};

// !!deprecated: use `layerChooser.removeLayer` directly
// our method differs from inherited (https://leafletjs.com/reference.html#control-layers-removelayer),
// as (by default) layer is removed from the map as well, see description for more details.
window.removeLayerGroup = function (layerGroup) {
  window.layerChooser.removeLayer(layerGroup);
};
<commit_msg>layerchooser.js: use option object in removeLayer (instead of boolean keepOnMap arg)<commit_after>/*
 * @class LayerChooser
 * @aka window.LayerChooser
 * @inherits L.Controls.Layers
 *
 * Provides 'persistence' of layers display state between sessions.
 *
 * Also some additional methods provided, see below.
 */

'use strict';

var LayerChooser = L.Control.Layers.extend({
  options: {
    // @option sortLayers: Boolean = true
    // Ensures stable sort order (based on initial), while still providing ability
    // to enforce specific order with `addBaseLayer`/`addOverlay`
    // `sortPriority` option.
    sortLayers: true,

    sortFunction: function (layerA, layerB) {
      var a = layerA._chooser.sortPriority;
      var b = layerB._chooser.sortPriority;
      return a < b ? -1 : (b < a ? 1 : 0);
    }
  },

  initialize: function (baseLayers, overlays, options) {
    this._overlayStatus = {};
    var layersJSON = localStorage['ingress.intelmap.layergroupdisplayed'];
    if (layersJSON) {
      try {
        this._overlayStatus = JSON.parse(layersJSON);
      } catch (e) {
        log.error(e);
      }
    }
    this._mapToAdd = options && options.map;
    this.lastBaseLayerName = localStorage['iitc-base-map'];
    this._lastPriority = -1000; // initial layers get priority <0
    L.Control.Layers.prototype.initialize.apply(this, arguments);
    this._lastPriority = 0; // any following gets >0
  },

  _addLayer: function (layer, label, overlay, options) {
    options = options || {};
    // stored on first add (with .addBaseLayer/.addOverlay)
    var data = layer._chooser;
    if (!data) {
      data = {
        // name should be unique, otherwise behavior of other methods is undefined
        // (typically: first found will be taken)
        name: label,
        overlay: overlay,
        persistent: 'persistent' in options ? options.persistent : true
      };
      layer._chooser = data;
    } else {
      label = label || data.label || data.name;
    }
    // provide stable sort order
    if ('sortPriority' in options) {
      data.sortPriority = options.sortPriority;
    } else if (!('sortPriority' in data)) {
      this._lastPriority = this._lastPriority + 10;
      data.sortPriority = this._lastPriority;
    }
    L.Control.Layers.prototype._addLayer.call(this, layer, label, overlay);
    if (data.overlay) {
      data.default = 'default' in options ? options.default : true;
    }
    var map = this._map || this._mapToAdd;
    if (!data.persistent) {
      if (!data.overlay) { return; }
      if ('enable' in options ? options.enable : data.default) {
        layer.addTo(map);
      }
      return;
    }
    if (overlay) {
      data.statusTracking = function (e) {
        this._storeOverlayState(data.name, e.type === 'add');
      };
      layer.on('add remove', data.statusTracking, this);
      if ('enable' in options) { // do as explicitly specified
        map[options.enable ? 'addLayer' : 'removeLayer'](layer);
      } else if (layer._map) { // already on map, only store state
        this._storeOverlayState(data.name, true);
      } else { // restore at recorded state
        if (this._isOverlayDisplayed(data.name, data.default)) {
          layer.addTo(map);
        }
      }
    } else {
      data.statusTracking = function () {
        localStorage['iitc-base-map'] = data.name;
      };
      layer.on('add', data.statusTracking);
    }
  },

  // @miniclass LayersEntry options (LayerChooser)
  // @aka layersEntry options

  // @option persistent: Boolean = true
  // * When `false` - baselayer's status is not tracked.

  // @option sortPriority: Number = *
  // Enforces specific order in control, lower value means layer's upper position.
  // If not specified - the value will be assigned implicitly in increasing manner.

  // @method addBaseLayer(layer: Layer, name: String, options?: LayersEntry options): this
  // Adds a base layer (radio button entry) with the given name to the control.
  addBaseLayer: function (layer, name, options) {
    this._addLayer(layer, name, false, options);
    return (this._map) ? this._update() : this;
  },

  // @miniclass AddOverlay options (LayerChooser)
  // @aka addOverlay options
  // @inherits LayersEntry options

  // @option persistent: Boolean = true
  // * When `true` (or not specified) - adds overlay to the map as well,
  //   if it's last state was active.
  //   If no record exists then value specified in `default` option is used.
  // * When `false` - overlay status is not tracked, `default` option is honored too.

  // @option default: Boolean = true
  // Default state of overlay (used only when no record about previous state found).

  // @option enable: Boolean
  // Enforce specified state ignoring previously saved.

  // @method addOverlay(layer: L.Layer, name: String, options?: AddOverlay options): this
  // Adds an overlay (checkbox entry) with the given name to the control.
  addOverlay: function (layer, name, options) {
    this._addLayer(layer, name, true, options);
    return (this._map) ? this._update() : this;
  },

  // @method removeLayer(layer: Layer|String, options?: Object): this
  // Removes the given layer from the control.
  // Either layer object or it's name in the control must be specified.
  // Layer is removed from the map as well, except `.keepOnMap` option is true.
  removeLayer: function (layer, options) {
    layer = this.getLayer(layer);
    if (layer) {
      options = options || {};
      var data = layer._chooser;
      if (data.statusTracking) {
        layer.off('add remove', data.statusTracking, this);
        delete data.statusTracking;
      }
      L.Control.Layers.prototype.removeLayer.apply(this, arguments);
      if (this._map && !options.keepOnMap) {
        map.removeLayer(layer);
      }
      // ?? optionally delete layer._chooser
    } else {
      log.warn('Layer not found');
    }
    return this;
  },

  _storeOverlayState: function (name, isDisplayed) {
    this._overlayStatus[name] = isDisplayed;
    localStorage['ingress.intelmap.layergroupdisplayed'] = JSON.stringify(this._overlayStatus);
  },

  _isOverlayDisplayed: function (name, defaultState) {
    if (name in this._overlayStatus) {
      return this._overlayStatus[name];
    }
    return defaultState;
  },

  __byName: function (el) {
    var name = this.toString();
    return el.layer._chooser.name === name ||
      el.name === name;
  },

  __byLayer: function (el) {
    return el.layer === this;
  },

  // layer: either Layer or it's name in the control
  _layerInfo: function (layer) {
    var fn = layer instanceof L.Layer
      ? this.__byLayer
      : this.__byName;
    return this._layers.find(fn, layer);
  },

  // @method getLayer(name: String|Layer): Layer
  // Returns layer by it's name in the control, or by layer object itself.
  // The latter can be used to ensure the layer is in layerChooser.
  getLayer: function (layer) {
    var info = this._layerInfo(layer);
    return info && info.layer;
  },

  // @method showLayer(layer: Layer|String|Number, display?: Boolean): this
  // Switches layer's display state to given value (true by default).
  // Layer can be specified also by it's name in the control.
  showLayer: function (layer, display) {
    var info = this._layers[layer]; // layer is index, private use only
    if (info) {
      layer = info.layer;
    } else {
      layer = this.getLayer(layer);
      if (!layer) {
        log.warn('Layer not found');
        return this;
      }
    }
    var map = this._map;
    if (display || arguments.length === 1) {
      if (!map.hasLayer(layer)) {
        if (!layer._chooser.overlay) {
          // if it's a base layer, remove any others
          this._layers.forEach(function (el) {
            if (!el.overlay && el.layer !== layer) {
              map.removeLayer(el.layer);
            }
          });
        }
        map.addLayer(layer);
      }
    } else {
      map.removeLayer(layer);
    }
    return this;
  },

  // @method setLabel(layer: String|Layer, label?: String): this
  // Sets layers label to specified label text (html),
  // or resets it to original name when label is not specified.
  setLabel: function (layer, label) {
    var fn = layer instanceof L.Layer
      ? this.__byLayer
      : this.__byName;
    var idx = this._layers.findIndex(fn, layer);
    if (idx === -1) {
      log.warn('Layer not found');
      return this;
    }
    var info = this._layers[idx];
    label = label || info.layer._chooser.name;
    info.name = label;
    var nameEl = this._layerControlInputs[idx].closest('label').querySelector('span');
    nameEl.innerHTML = ' ' + label;
    return this;
  },

  // adds listeners to the overlays list to make inputs toggleable.
  _initLayout: function () {
    L.Control.Layers.prototype._initLayout.call(this);
    $(this._overlaysList).on('click taphold', 'label', function (e) {
      if (!(e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.type === 'taphold')) {
        return;
      }
      // e.preventDefault(); // seems no effect
      var input = e.target.closest('label').querySelector('input');
      var idx = this._layerControlInputs.indexOf(input);
      this._toggleOverlay(idx);
    }.bind(this));
  },

  _filterOverlays: function (el) {
    return el.overlay &&
      ['DEBUG Data Tiles', 'Resistance', 'Enlightened'].indexOf(el.layer._chooser.name) === -1;
  },

  // Hides all the control's overlays except given one,
  // or restores all, if it was the only one displayed (or none was displayed).
  _toggleOverlay: function (idx) {
    var info = this._layers[idx];
    if (!info || !info.overlay) {
      log.warn('Overlay not found: ', info);
      return;
    }
    var map = this._map;

    var isChecked = map.hasLayer(info.layer);
    var checked = 0;
    var overlays = this._layers.filter(this._filterOverlays);
    overlays.forEach(function (el) {
      if (map.hasLayer(el.layer)) { checked++; }
    });

    if (checked === 0 || isChecked && checked === 1) {
      // if nothing is selected, or specified overlay is exclusive,
      // assume all boxes should be checked again
      overlays.forEach(function (el) {
        if (el.layer._chooser.default) {
          map.addLayer(el.layer);
        }
      });
    } else {
      // uncheck all, check specified
      overlays.forEach(function (el) {
        if (el.layer === info.layer) {
          map.addLayer(el.layer);
        } else {
          map.removeLayer(el.layer);
        }
      });
    }
  },

  _stripHtmlTags: function (str) {
    return str.replace(/(<([^>]+)>)/gi, ''); // https://css-tricks.com/snippets/javascript/strip-html-tags-in-javascript/
  },

  // !!deprecated
  getLayers: function () {
    var baseLayers = [];
    var overlayLayers = [];
    this._layers.forEach(function (info, idx) {
      (info.overlay ? overlayLayers : baseLayers).push({
        layerId: idx,
        name: this._stripHtmlTags(info.name), // IITCm does not support html in layers labels
        active: this._map.hasLayer(info.layer)
      });
    }, this);

    return {
      baseLayers: baseLayers,
      overlayLayers: overlayLayers
    };
  }
});

window.LayerChooser = LayerChooser;

function debounce (callback, time) { // https://gist.github.com/nmsdvid/8807205#gistcomment-2641356
  var timeout;
  return function () {
    var context = this;
    var args = arguments;
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(function () {
      timeout = null;
      callback.apply(context, args);
    }, time);
  };
}

if (typeof android !== 'undefined' && android && android.setLayers) {
  // hook some additional code into the LayerControl so it's easy for the mobile app to interface with it
  LayerChooser.include({
    _setAndroidLayers: debounce(function () { // update layer menu in IITCm
      var l = this.getLayers();
      android.setLayers(JSON.stringify(l.baseLayers), JSON.stringify(l.overlayLayers));
    }, 1000),

    setLabel: (function (setLabel) {
      return function () {
        this._setAndroidLayers();
        return setLabel.apply(this, arguments);
      };
    })(LayerChooser.prototype.setLabel),

    _update: function () {
      this._setAndroidLayers();
      return L.Control.Layers.prototype._update.apply(this, arguments);
    }
  });
}

// contains current status(on/off) of overlay layerGroups.
// !!deprecated: use `map.hasLayer` instead (https://leafletjs.com/reference.html#map-haslayer)
window.overlayStatus = {}; // to be set in constructor

// Reads recorded layerGroup status (as it may not be added to map yet),
// return `defaultDisplay` if no record found.
// !!deprecated: for most use cases prefer `getLayer()` method
// or `map.hasLayer` (https://leafletjs.com/reference.html#map-haslayer)
// window.isLayerGroupDisplayed = function (name, defaultDisplay) { // ...
window.isLayerGroupDisplayed = L.Util.falseFn; // to be set in constructor

LayerChooser.addInitHook(function () {
  window.overlayStatus = this._overlayStatus;
  window.isLayerGroupDisplayed = this._isOverlayDisplayed.bind(this);
});

// !!deprecated: use `layerChooser.addOverlay` directly
window.addLayerGroup = function (name, layerGroup, defaultDisplay) {
  var options = {default: defaultDisplay};
  if (arguments.length < 3) { options = undefined; }
  window.layerChooser.addOverlay(layerGroup, name, options);
};

// !!deprecated: use `layerChooser.removeLayer` directly
// our method differs from inherited (https://leafletjs.com/reference.html#control-layers-removelayer),
// as (by default) layer is removed from the map as well, see description for more details.
window.removeLayerGroup = function (layerGroup) {
  window.layerChooser.removeLayer(layerGroup);
};
<|endoftext|>


<commit_before>/**
 * Log event broadcaster.
 *
 * This layer allows us to broadcast periodical updates to the counter stats
 * independently of writes (which use increment operations).
 *
 * @package  StopTheSpies API
 * @author   Sam Pospischil <pospi@spadgos.com>
 * @since    2014-08-30
 */

var async = require('async');
var mongo = require(__dirname + '/../../lib/database');

module.exports = function(app, delay)
{
  var theTotals = null;

  mongo.get().then(function(db) {
    setTimeout(function pollStats() {
      db.collection('log_totals').find({_id : 'overall_totals'}, function(err, res) {
        if (err) throw err;
        res.toArray(function(err, totals) {
          if (err) throw err;

          totals = totals[0];

          if (!theTotals ||
              theTotals.views !== totals.views ||
              theTotals.emails !== totals.emails ||
              theTotals.calls !== totals.calls) {
            console.log('Broadcast stats');
            app.io.broadcast('stats:update', [totals]);
          }

          theTotals = totals;

          setTimeout(pollStats, delay);
        });
      });
    }, delay);
  });
};
<commit_msg>send counts for all electorates back in stats responses, not just aggregates<commit_after>/**
 * Log event broadcaster.
 *
 * This layer allows us to broadcast periodical updates to the counter stats
 * independently of writes (which use increment operations).
 *
 * @package  StopTheSpies API
 * @author   Sam Pospischil <pospi@spadgos.com>
 * @since    2014-08-30
 */

var async = require('async');
var mongo = require(__dirname + '/../../lib/database');

var theTotals = null;

function send(app, totals)
{
	console.log('Broadcast stats');
	app.io.broadcast('stats:update', totals);

	theTotals = totals;
}

module.exports = function(app, delay)
{
  mongo.get().then(function(db) {
    setTimeout(function pollStats() {
      db.collection('log_totals').find({}, {sort: '_id'}, function(err, res) {
        if (err) throw err;
        res.toArray(function(err, totals) {
          if (err) throw err;

          if (!theTotals) {
	          send(app, totals);
          } else {
	          for (var i = 0, l = totals.length; i < l; ++i) {
	          	if (theTotals[i].views !== totals[i].views ||
	              theTotals[i].emails !== totals[i].emails ||
	              theTotals[i].calls !== totals[i].calls) {
	          		send(app, totals);
		          	break;
	          	}
	          }
	      }

          setTimeout(pollStats, delay);
        });
      });
    }, delay);
  });
};
<|endoftext|>


<commit_before>$(document).ready(function() {
    'use strict';

    var MAX_NAME_LENGTH = 50;
    var BANNER_HEIGHT = 160;

    // Prep templates located in the HTML
    var name_tmpl = $('#name_tmpl').html();
    var progress_tmpl = $('#progress_tmpl').html();
    var progress_container_tmpl = $('#progress_container_tmpl').html();
    var progress_popover_tmpl = $('#progress_popover_tmpl').html();

    // Compile templates for speedup
    Mustache.parse(name_tmpl);
    Mustache.parse(progress_tmpl);
    Mustache.parse(progress_container_tmpl);
    Mustache.parse(progress_popover_tmpl);

    // Handle vertical resizing of the table
    function calcHeight() {
        return $(window).height() - BANNER_HEIGHT;
    }

    $(window).on('resize', function() {
        // The joy of fitting vertically!
        $('.dataTables_scrollBody').height(calcHeight()).css('max-height', 'inherit');
    });

    // Cluster status table.
    var cluster_table = $("#yarn_status").DataTable({
        ajax: YARNITOR_BASE_URL+"/api/cluster",
        paging: false,
        searching: false,
        ordering: false,
        dom: 't',
        columns: [
            {
                data: "totalNodes",
                title: "Nodes",
                render: function(data, type, row) {
                    return (data - row['unhealthyNodes']) + ' / ' + data;
                }
            },
            {
                data: "totalVirtualCores",
                title: "VCPUs",
                render: function(data, type, row) {
                    return row['availableVirtualCores'] + ' / ' + data;
                }
            },
            {
               data: "totalMB",
               title: "RAM (GB)",
               render: function(data, type, row) {
                    return Math.round(row['availableMB'] / 1024) + ' / ' + Math.round(data / 1024);
               }
            }
        ]
    });

    // Main applications table
    var table = $('#yarn_applications').DataTable({
        ajax: YARNITOR_BASE_URL+"/api/applications",
        rowId: "id",
        scrollX: true,
        scrollY: calcHeight(),
        paging: false,
        order: [4, 'desc'],
        language: {
            "search": "",
            "searchPlaceholder": "Filter records"
        },
        dom: ("<'row'<'col-xs-8'l><'col-xs-4'f>>" +
             "<'row'<'col-xs-12'tr>>" +
             "<'row'<'col-xs-6'i><'col-xs-6 dataTables_refreshed'>>"),
        columns: [
            {
                data: "name",
                title: "Name",
                render: function(data, type, row, meta) {
                    if(data.length > MAX_NAME_LENGTH) {
                        data = data.substr(0, MAX_NAME_LENGTH) + '...';
                    }
                    var html = Mustache.render(name_tmpl, {
                        name: data,
                        trackingUrl: row.trackingUrl,
                        id: row.id
                    });
                    return html;
                }
            },
            {data: "user", title: "User"},
            {data: "state", title: "State"},
            {
                title: "Progress",
                render: function(data, type, row, meta) {
                    // progress bars
                    var bar_htmls = row.progress.map(function(progress) {
                        var total = progress.completed + progress.running + progress.failed;
                        total = (progress.total > total) ? progress.total : total;
                        var args = {
                            completed: progress.completed,
                            completed_ratio: progress.completed / progress.total * 100,
                            running: progress.running,
                            running_ratio: progress.running / progress.total * 100,
                            failed: progress.failed,
                            failed_ratio: progress.failed / progress.total * 100,
                            total: progress.total
                        };

                        return Mustache.render(progress_tmpl, args);
                    });

                    return Mustache.render(progress_container_tmpl, {
                        progress_html: bar_htmls.join('\n'),
                        popover_html : Mustache.render(progress_popover_tmpl, row)
                    });
                }
            },
            {data: "allocatedVCores", title: "VCPUs"},
            {
                data: "allocatedMB",
                title: "Memory (GB)",
                render: function(data) {
                    return Math.round(data / 1024);
                }
            },
            {
              "title": "Mem/VCPU Ratio",
              "render": function(data, type, row, meta) {
                return (row.allocatedMB / row.allocatedVCores / 1024).toFixed(2);
              }
            },
            {"data": "applicationType", "title": "Job Type"},
            {"data": "queue", "title": "Queue"},
            {
                "data": "startedTime",
                "title": "Local Start Time",
                "render": function(data, type, row, meta) {
                    return (new Date(data)).toLocaleString();
                }
            },
        ]
    });

    var pageScrollPos = 0;

    table.on('draw.dt', function() {
        console.log('yarnitor:draw.dt');
        // Remove shown popovers
        $('.popover').remove();
        $('[data-toggle="popover"]').popover();
        // rescroll
        $('div.dataTables_scrollBody').scrollTop(pageScrollPos);
    });

    table.on('xhr.dt', function() {
        console.log('yarnitor:xhr.dt');
        // destroy the popovers before the draw phase kicks in.
        $('[data-toggle="popover"]').popover("destroy");
        pageScrollPos = $('div.dataTables_scrollBody').scrollTop();
    });

    var reloadDatetime = function() {
        $.get({
            url: YARNITOR_BASE_URL+"/api/status",
            dataType: 'json'
        }).done(function(data) {
            // Show datetime data was last refreshed from the YARN API
            // if that information is available, else leave the display alone
            if(data.refresh_datetime) {
                var d = (new Date(data.refresh_datetime)).toLocaleString();
                $('.dataTables_refreshed').text('Showing data from ' + d);
            }
        });
    }

    setInterval(function() {
        console.log('yarnitor:refresh');
        table.ajax.reload();
        cluster_table.ajax.reload();
        reloadDatetime();
    }, YARNITOR_REFRESH_INTERVAL_S * 1000);

    // Throw exceptions in the console, not in alert dialogs
    $.fn.dataTable.ext.errMode = 'throw';
    // Immediately try to fetch datetime of last data refresh
    reloadDatetime();

    console.log('yarnitor:dom-ready');
});
<commit_msg>BUG: Fix start datetime column sorting<commit_after>$(document).ready(function() {
    'use strict';

    var MAX_NAME_LENGTH = 50;
    var BANNER_HEIGHT = 160;

    // Prep templates located in the HTML
    var name_tmpl = $('#name_tmpl').html();
    var progress_tmpl = $('#progress_tmpl').html();
    var progress_container_tmpl = $('#progress_container_tmpl').html();
    var progress_popover_tmpl = $('#progress_popover_tmpl').html();

    // Compile templates for speedup
    Mustache.parse(name_tmpl);
    Mustache.parse(progress_tmpl);
    Mustache.parse(progress_container_tmpl);
    Mustache.parse(progress_popover_tmpl);

    // Handle vertical resizing of the table
    function calcHeight() {
        return $(window).height() - BANNER_HEIGHT;
    }

    $(window).on('resize', function() {
        // The joy of fitting vertically!
        $('.dataTables_scrollBody').height(calcHeight()).css('max-height', 'inherit');
    });

    // Cluster status table.
    var cluster_table = $("#yarn_status").DataTable({
        ajax: YARNITOR_BASE_URL+"/api/cluster",
        paging: false,
        searching: false,
        ordering: false,
        dom: 't',
        columns: [
            {
                data: "totalNodes",
                title: "Nodes",
                render: function(data, type, row) {
                    return (data - row['unhealthyNodes']) + ' / ' + data;
                }
            },
            {
                data: "totalVirtualCores",
                title: "VCPUs",
                render: function(data, type, row) {
                    return row['availableVirtualCores'] + ' / ' + data;
                }
            },
            {
               data: "totalMB",
               title: "RAM (GB)",
               render: function(data, type, row) {
                    return Math.round(row['availableMB'] / 1024) + ' / ' + Math.round(data / 1024);
               }
            }
        ]
    });

    // Main applications table
    var table = $('#yarn_applications').DataTable({
        ajax: YARNITOR_BASE_URL+"/api/applications",
        rowId: "id",
        scrollX: true,
        scrollY: calcHeight(),
        paging: false,
        order: [4, 'desc'],
        language: {
            "search": "",
            "searchPlaceholder": "Filter records"
        },
        dom: ("<'row'<'col-xs-8'l><'col-xs-4'f>>" +
             "<'row'<'col-xs-12'tr>>" +
             "<'row'<'col-xs-6'i><'col-xs-6 dataTables_refreshed'>>"),
        columns: [
            {
                data: "name",
                title: "Name",
                render: function(data, type, row, meta) {
                    if(data.length > MAX_NAME_LENGTH) {
                        data = data.substr(0, MAX_NAME_LENGTH) + '...';
                    }
                    var html = Mustache.render(name_tmpl, {
                        name: data,
                        trackingUrl: row.trackingUrl,
                        id: row.id
                    });
                    return html;
                }
            },
            {data: "user", title: "User"},
            {data: "state", title: "State"},
            {
                title: "Progress",
                render: function(data, type, row, meta) {
                    // progress bars
                    var bar_htmls = row.progress.map(function(progress) {
                        var total = progress.completed + progress.running + progress.failed;
                        total = (progress.total > total) ? progress.total : total;
                        var args = {
                            completed: progress.completed,
                            completed_ratio: progress.completed / progress.total * 100,
                            running: progress.running,
                            running_ratio: progress.running / progress.total * 100,
                            failed: progress.failed,
                            failed_ratio: progress.failed / progress.total * 100,
                            total: progress.total
                        };

                        return Mustache.render(progress_tmpl, args);
                    });

                    return Mustache.render(progress_container_tmpl, {
                        progress_html: bar_htmls.join('\n'),
                        popover_html : Mustache.render(progress_popover_tmpl, row)
                    });
                }
            },
            {data: "allocatedVCores", title: "VCPUs"},
            {
                data: "allocatedMB",
                title: "Memory (GB)",
                render: function(data) {
                    return Math.round(data / 1024);
                }
            },
            {
              "title": "Mem/VCPU Ratio",
              "render": function(data, type, row, meta) {
                return (row.allocatedMB / row.allocatedVCores / 1024).toFixed(2);
              }
            },
            {"data": "applicationType", "title": "Job Type"},
            {"data": "queue", "title": "Queue"},
            {
                "data": "startedTime",
                "type": "date",
                "title": "Local Start Time",
                "render": function(data, type, row, meta) {
                    return (new Date(data)).toLocaleString();
                }
            },
        ]
    });

    var pageScrollPos = 0;

    table.on('draw.dt', function() {
        console.log('yarnitor:draw.dt');
        // Remove shown popovers
        $('.popover').remove();
        $('[data-toggle="popover"]').popover();
        // rescroll
        $('div.dataTables_scrollBody').scrollTop(pageScrollPos);
    });

    table.on('xhr.dt', function() {
        console.log('yarnitor:xhr.dt');
        // destroy the popovers before the draw phase kicks in.
        $('[data-toggle="popover"]').popover("destroy");
        pageScrollPos = $('div.dataTables_scrollBody').scrollTop();
    });

    var reloadDatetime = function() {
        $.get({
            url: YARNITOR_BASE_URL+"/api/status",
            dataType: 'json'
        }).done(function(data) {
            // Show datetime data was last refreshed from the YARN API
            // if that information is available, else leave the display alone
            if(data.refresh_datetime) {
                var d = (new Date(data.refresh_datetime)).toLocaleString();
                $('.dataTables_refreshed').text('Showing data from ' + d);
            }
        });
    }

    setInterval(function() {
        console.log('yarnitor:refresh');
        table.ajax.reload();
        cluster_table.ajax.reload();
        reloadDatetime();
    }, YARNITOR_REFRESH_INTERVAL_S * 1000);

    // Throw exceptions in the console, not in alert dialogs
    $.fn.dataTable.ext.errMode = 'throw';
    // Immediately try to fetch datetime of last data refresh
    reloadDatetime();

    console.log('yarnitor:dom-ready');
});
<|endoftext|>


<commit_before>/**
 * @module Input
 * @submodule Time & Date
 * @for p5
 * @requires core
 */

'use strict';

var p5 = require('../core/core');

/**
 * p5.js communicates with the clock on your computer. The day() function
 * returns the current day as a value from 1 - 31.
 *
 * @method day
 * @return {Number} the current day
 * @example
 *

 *
 * var day = day();
 * text("Current day: \n" + day, 5, 50);
 *
 *

 */
p5.prototype.day = function() {
  return new Date().getDate();
};

/**
 * p5.js communicates with the clock on your computer. The hour() function
 * returns the current hour as a value from 0 - 23.
 *
 * @method hour
 * @return {Number} the current hour
 * @example
 *

 *
 * var hour = hour();
 * text("Current hour:\n" + hour, 5, 50);
 *
 *

 */
p5.prototype.hour = function() {
  return new Date().getHours();
};

/**
 * p5.js communicates with the clock on your computer. The minute() function
 * returns the current minute as a value from 0 - 59.
 *
 * @method minute
 * @return {Number} the current minute
 * @example
 *

 *
 * var minute = minute();
 * text("Current minute: \n" + minute, 5, 50);
 *
 *

 */
p5.prototype.minute = function() {
  return new Date().getMinutes();
};

/**
 * Returns the number of milliseconds (thousandths of a second) since
 * starting the program. This information is often used for timing events and
 * animation sequences.
 *
 * @method millis
 * @return {Number} the number of milliseconds since starting the program
 * @example
 *

 *
 * var millisecond = millis();
 * text("Milliseconds \nrunning: \n" + millisecond, 5, 40);
 *
 *

 */
p5.prototype.millis = function() {
  return window.performance.now();
};

/**
 * p5.js communicates with the clock on your computer. The month() function
 * returns the current month as a value from 1 - 12.
 *
 * @method month
 * @return {Number} the current month
 * @example
 *

 *
 * var month = month();
 * text("Current month: \n" + month, 5, 50);
 *
 *

 */
p5.prototype.month = function() {
  return new Date().getMonth() + 1; //January is 0!
};

/**
 * p5.js communicates with the clock on your computer. The second() function
 * returns the current second as a value from 0 - 59.
 *
 * @method second
 * @return {Number} the current second
 * @example
 *

 *
 * var second = second();
 * text("Current second: \n" + second, 5, 50);
 *
 *

 */
p5.prototype.second = function() {
  return new Date().getSeconds();
};

/**
 * p5.js communicates with the clock on your computer. The year() function
 * returns the current year as an integer (2014, 2015, 2016, etc).
 *
 * @method year
 * @return {Number} the current year
 * @example
 *

 *
 * var year = year();
 * text("Current year: \n" + year, 5, 50);
 *
 *

 */
p5.prototype.year = function() {
  return new Date().getFullYear();
};

module.exports = p5;
<commit_msg>updating time/date examples to not use p5 func names fixes #1375<commit_after>/**
 * @module Input
 * @submodule Time & Date
 * @for p5
 * @requires core
 */

'use strict';

var p5 = require('../core/core');

/**
 * p5.js communicates with the clock on your computer. The day() function
 * returns the current day as a value from 1 - 31.
 *
 * @method day
 * @return {Number} the current day
 * @example
 *

 *
 * var d = day();
 * text("Current day: \n" + d, 5, 50);
 *
 *

 */
p5.prototype.day = function() {
  return new Date().getDate();
};

/**
 * p5.js communicates with the clock on your computer. The hour() function
 * returns the current hour as a value from 0 - 23.
 *
 * @method hour
 * @return {Number} the current hour
 * @example
 *

 *
 * var h = hour();
 * text("Current hour:\n" + h, 5, 50);
 *
 *

 */
p5.prototype.hour = function() {
  return new Date().getHours();
};

/**
 * p5.js communicates with the clock on your computer. The minute() function
 * returns the current minute as a value from 0 - 59.
 *
 * @method minute
 * @return {Number} the current minute
 * @example
 *

 *
 * var m = minute();
 * text("Current minute: \n" + m, 5, 50);
 *
 *

 */
p5.prototype.minute = function() {
  return new Date().getMinutes();
};

/**
 * Returns the number of milliseconds (thousandths of a second) since
 * starting the program. This information is often used for timing events and
 * animation sequences.
 *
 * @method millis
 * @return {Number} the number of milliseconds since starting the program
 * @example
 *

 *
 * var millisecond = millis();
 * text("Milliseconds \nrunning: \n" + millisecond, 5, 40);
 *
 *

 */
p5.prototype.millis = function() {
  return window.performance.now();
};

/**
 * p5.js communicates with the clock on your computer. The month() function
 * returns the current month as a value from 1 - 12.
 *
 * @method month
 * @return {Number} the current month
 * @example
 *

 *
 * var m = month();
 * text("Current month: \n" + m, 5, 50);
 *
 *

 */
p5.prototype.month = function() {
  return new Date().getMonth() + 1; //January is 0!
};

/**
 * p5.js communicates with the clock on your computer. The second() function
 * returns the current second as a value from 0 - 59.
 *
 * @method second
 * @return {Number} the current second
 * @example
 *

 *
 * var s = second();
 * text("Current second: \n" + s, 5, 50);
 *
 *

 */
p5.prototype.second = function() {
  return new Date().getSeconds();
};

/**
 * p5.js communicates with the clock on your computer. The year() function
 * returns the current year as an integer (2014, 2015, 2016, etc).
 *
 * @method year
 * @return {Number} the current year
 * @example
 *

 *
 * var y = year();
 * text("Current year: \n" + y, 5, 50);
 *
 *

 */
p5.prototype.year = function() {
  return new Date().getFullYear();
};

module.exports = p5;
<|endoftext|>


<commit_before><commit_msg>fixes search with small words<commit_after><|endoftext|>


<commit_before>'use strict';

const cloneDeepWith = require('lodash.clonedeepwith');

/**
 * Formats a date in ISO 8601 format with the correct time zone offset
 * @param {undefined|Date} date
 * @returns {string}
 */
function formatDate(date) {
    const dateStr = (date || new Date()).toISOString();
    return dateStr.replace('Z', formatTZ(date));
}

/**
 * Returns the time zone offset as a string
 * adapted from https://github.com/sindresorhus/time-zone
 * @param {undefined|Date} date
 * @returns {string}
 */
function formatTZ(date) {
    const offset = (date || new Date()).getTimezoneOffset();
    const absOffset = Math.abs(offset);

    if (absOffset === 0) {
        return 'Z';
    }

    const hours = Math.floor(absOffset / 60);
    const hoursOut = absOffset > 0 ? ('0' + hours).slice(-2) : '';
    const minutes = absOffset % 60;
    const minutesOut = ':' + ('0' + minutes).slice(-2);

    return (offset < 0 ? '+' : '-') + hoursOut + minutesOut;
}

/**
 * Date replacer function
 * @param {*} name object key name
 * @param {*} val value
 */
function replacer(val) {
    if (val instanceof Date) {
        return formatDate(val);
    }
}

/**
 * Date stringify function
 * @param {*} value
 */
function dateStringify(value) {
    return cloneDeepWith(value, replacer);
}

module.exports = dateStringify;
<commit_msg>fixing timezone offset issue<commit_after>'use strict';

const cloneDeepWith = require('lodash.clonedeepwith');

/**
 * Formats a date in ISO 8601 format with the correct time zone offset
 * @param {undefined|Date} date
 * @returns {string}
 */
function formatDate(date) {
    const dateClone = date ? new Date(date.getTime()) : new Date();

    // subtract the timezone offset
    dateClone.setMinutes(dateClone.getMinutes() - dateClone.getTimezoneOffset());

    const dateStr = dateClone.toISOString();
    return dateStr.replace('Z', formatTZ(dateClone));
}

/**
 * Returns the time zone offset as a string
 * adapted from https://github.com/sindresorhus/time-zone
 * @param {undefined|Date} date
 * @returns {string}
 */
function formatTZ(date) {
    const offset = (date || new Date()).getTimezoneOffset();
    const absOffset = Math.abs(offset);

    if (absOffset === 0) {
        return 'Z';
    }

    const hours = Math.floor(absOffset / 60);
    const hoursOut = absOffset > 0 ? ('0' + hours).slice(-2) : '';
    const minutes = absOffset % 60;
    const minutesOut = ':' + ('0' + minutes).slice(-2);

    return (offset < 0 ? '+' : '-') + hoursOut + minutesOut;
}

/**
 * Date replacer function
 * @param {*} name object key name
 * @param {*} val value
 */
function replacer(val) {
    if (val instanceof Date) {
        return formatDate(val);
    }
}

/**
 * Date stringify function
 * @param {*} value
 */
function dateStringify(value) {
    return cloneDeepWith(value, replacer);
}

module.exports = dateStringify;
<|endoftext|>


<commit_before>/* global Kiwi, _ */
'use strict';

var HelixPiEditor = HelixPiEditor || {};

HelixPiEditor.Play = new Kiwi.State('Play');

var Actor = function (sprite, genes, api, fitness) {
  return {
    play: function () {
      _.each(genes, function (gene) {
        gene(api);
      });
    }
  };
};

HelixPiEditor.Play.create = function () {
  this.currentKeyFrame = 0;
  this.currentFrame = 0;
  this.play = true;
  this.compiledApi = HelixPiEditor.Editor.api(this.entity);

  HelixPiEditor.buttons.cleanUp();
  var backToEditorButton = HelixPiEditor.buttons.create(
    this,
    'Back to Editor',
    180,
    5
  )

  var that = this;
  this.actors = HelixPiEditor.results().map(function (result) {
    var sprite = new Kiwi.GameObjects.Sprite(
      that,
      that.textures.entity,
      100, // TODO - fix origin
      100,
      true
    );

    that.addChild(sprite);

    var compiledApi = HelixPiEditor.Editor.api(sprite);
    return new Actor(sprite, result.individual, compiledApi, result.fitness);
  });
};

HelixPiEditor.Play.update = function () {
  _.each(this.actors, function (actor) {
    actor.play();
  });

  // this.displayProgressIndicator(this.currentFrame / (this.highestFrame * 60));
  this.currentFrame += 1;
};

<commit_msg>Hide editor buttons on play screen<commit_after>/* global Kiwi, _ */
'use strict';

var HelixPiEditor = HelixPiEditor || {};

HelixPiEditor.Play = new Kiwi.State('Play');

var Actor = function (sprite, genes, api, fitness) {
  return {
    play: function () {
      _.each(genes, function (gene) {
        gene(api);
      });
    }
  };
};

HelixPiEditor.Play.create = function () {
  this.currentKeyFrame = 0;
  this.currentFrame = 0;
  this.play = true;
  this.compiledApi = HelixPiEditor.Editor.api(this.entity);

  this.game.huds.defaultHUD.removeAllWidgets();
  var backToEditorButton = HelixPiEditor.buttons.create(
    this,
    'Back to Editor',
    180,
    5
  )

  var that = this;
  this.actors = HelixPiEditor.results().map(function (result) {
    var sprite = new Kiwi.GameObjects.Sprite(
      that,
      that.textures.entity,
      100, // TODO - fix origin
      100,
      true
    );

    that.addChild(sprite);

    var compiledApi = HelixPiEditor.Editor.api(sprite);
    return new Actor(sprite, result.individual, compiledApi, result.fitness);
  });
};

HelixPiEditor.Play.update = function () {
  _.each(this.actors, function (actor) {
    actor.play();
  });

  // this.displayProgressIndicator(this.currentFrame / (this.highestFrame * 60));
  this.currentFrame += 1;
};

<|endoftext|>


<commit_before>'use strict';
var fs = require('fs');
var JSONStream = require('JSONStream');
var eventStream = require('event-stream');
var os = require('os');
var path = require('path');
var sha1 = require('sha1');
var _ = require('underscore');
var folder = os.tmpDir();
//These are the most usual ids which come in geojson files.
var ids = ['id', '_id', '_fromWay', '_toWay'];

module.exports = {
  formatGeojson,
  formatFeature
};

function handleData(data, file, es) {
  data = formatFeature(data);
  var row = `${JSON.stringify(data)}\n`;
  fs.appendFile(file, row, function(err) {
    if (err) console.log(err);
    es.resume();
  });
}

/**
 * Stream a GeoJSON file to count the number of rows
 * @param {string} geojsonFile path to a local GeoJSON file
 * @param {object} task metadata
 * @param {function} cb success callback passing updated task as parameter
 * @returns {object} task with `items` property
 */
function formatGeojson(geojsonFile, task, cb) {
  var numRows = 0;
  var file = path.join(folder, task.idtask);
  fs.writeFile(file, '');
  var fileStream = fs.createReadStream(geojsonFile, {
    encoding: 'utf8'
  });
  fileStream.pipe(JSONStream.parse('features.*')).pipe(eventStream.through(function(data) {
    numRows++;
    this.pause();
    handleData(data, file, this);
    return data;
  }, function end() {
    task.value.stats[task.value.stats.length - 1].date = task.value.updated;
    task.value.stats[task.value.stats.length - 1].items = numRows;
    cb(task);
    this.emit('end');
  }));
}

/**
 * Format the data
 * - add _key, hash of the feature
 * - add _time, current time
 * - add _osmId , which is the id of osm object
 * - add _osmType, which is the type of osm object
 * @param {object} a feature of geojson
 * @returns {object} a feature which will be a item in ES
 */
function formatFeature(data) {
  var hash = sha1(JSON.stringify(data));
  var time = Math.round((new Date()).getTime() / 1000);
  data.properties._key = hash;
  data.properties._time = time;
  if (data.geometry.type === 'MultiPoint' || data.geometry.type === 'LineString' || data.geometry.type === 'MultiLineString' || data.geometry.type === 'Polygon' || data.geometry.type === 'MultiPolygon') {
    data.properties._osmType = 'way';
  } else if (data.geometry.type === 'Point') {
    data.properties._osmType = 'node';
  }
  data = replaceSC(data);
  for (var i = 0; i < ids.length; i++) {
    var id = ids[i];
    if (data.properties[id]) {
      data.properties._osmId = data.properties[id];
      //format overpass geojson files
      var typeId = data.properties._osmId.toString().split('\_');
      if (typeId.length === 2) {
        data.properties._osmId = typeId[1];
        data.properties._osmType = typeId[0];
      }
    }
  }
  return data;
}

function replaceSC(obj) {
  if (_.isArray(obj)) {
    for (var k = 0; k < obj.length; k++) {
      obj[k] = replaceSC(obj[k]);
    }
  } else {
    var keys = _.keys(obj);
    for (var i = 0; i < keys.length; i++) {
      var key = keys[i].replace(/[^A-Za-z]/g, '_');
      if (key !== keys[i]) {
        obj[key] = obj[keys[i]];
        delete obj[keys[i]];
      }
      /*eslint valid-typeof: "error"*/
      if (_.isObject(obj[key]) && key !== 'geometry') {
        obj[key] = replaceSC(obj[key]);
      } else if (typeof obj[key] === 'string' || obj[key] instanceof String) {
        obj[key] = obj[key].replace(/[^a-zA-Z0-9]/g, '_');
      }
    }
  }
  return obj;
}
<commit_msg>fix duplicate items count<commit_after>'use strict';
var fs = require('fs');
var JSONStream = require('JSONStream');
var eventStream = require('event-stream');
var os = require('os');
var path = require('path');
var sha1 = require('sha1');
var _ = require('underscore');
var folder = os.tmpDir();
//These are the most usual ids which come in geojson files.
var ids = ['id', '_id', '_fromWay', '_toWay'];
var avoidDuplicates = [];
module.exports = {
  formatGeojson,
  formatFeature
};

function handleData(data, file, es) {
  data = formatFeature(data);
  if (avoidDuplicates.indexOf(data.properties._key) < 1) {
    var row = `${JSON.stringify(data)}\n`;
    fs.appendFile(file, row, function(err) {
      if (err) console.log(err);
      es.resume();
    });
    avoidDuplicates.push(data.properties._key);
  } else {
    es.resume();
  }
}

/**
 * Stream a GeoJSON file to count the number of rows
 * @param {string} geojsonFile path to a local GeoJSON file
 * @param {object} task metadata
 * @param {function} cb success callback passing updated task as parameter
 * @returns {object} task with `items` property
 */
function formatGeojson(geojsonFile, task, cb) {
  avoidDuplicates = [];
  var numRows = 0;
  var file = path.join(folder, task.idtask);
  fs.writeFile(file, '');
  var fileStream = fs.createReadStream(geojsonFile, {
    encoding: 'utf8'
  });
  fileStream.pipe(JSONStream.parse('features.*')).pipe(eventStream.through(function(data) {
    numRows++;
    this.pause();
    handleData(data, file, this);
    return data;
  }, function end() {
    task.value.stats[task.value.stats.length - 1].date = task.value.updated;
    task.value.stats[task.value.stats.length - 1].items = avoidDuplicates.length;
    cb(task);
    this.emit('end');
  }));
}

/**
 * Format the data
 * - add _key, hash of the feature
 * - add _time, current time
 * - add _osmId , which is the id of osm object
 * - add _osmType, which is the type of osm object
 * @param {object} a feature of geojson
 * @returns {object} a feature which will be a item in ES
 */
function formatFeature(data) {
  var hash = sha1(JSON.stringify(data));
  var time = Math.round((new Date()).getTime() / 1000);
  data.properties._key = hash;
  data.properties._time = time;
  if (data.geometry.type === 'MultiPoint' || data.geometry.type === 'LineString' || data.geometry.type === 'MultiLineString' || data.geometry.type === 'Polygon' || data.geometry.type === 'MultiPolygon') {
    data.properties._osmType = 'way';
  } else if (data.geometry.type === 'Point') {
    data.properties._osmType = 'node';
  }
  data = replaceSC(data);
  for (var i = 0; i < ids.length; i++) {
    var id = ids[i];
    if (data.properties[id]) {
      data.properties._osmId = data.properties[id];
      //format overpass geojson files
      var typeId = data.properties._osmId.toString().split('\_');
      if (typeId.length === 2) {
        data.properties._osmId = typeId[1];
        data.properties._osmType = typeId[0];
      }
    }
  }
  return data;
}

function replaceSC(obj) {
  if (_.isArray(obj)) {
    for (var k = 0; k < obj.length; k++) {
      obj[k] = replaceSC(obj[k]);
    }
  } else {
    var keys = _.keys(obj);
    for (var i = 0; i < keys.length; i++) {
      var key = keys[i].replace(/[^A-Za-z]/g, '_');
      if (key !== keys[i]) {
        obj[key] = obj[keys[i]];
        delete obj[keys[i]];
      }
      /*eslint valid-typeof: "error"*/
      if (_.isObject(obj[key]) && key !== 'geometry') {
        obj[key] = replaceSC(obj[key]);
      } else if (typeof obj[key] === 'string' || obj[key] instanceof String) {
        obj[key] = obj[key].replace(/[^a-zA-Z0-9]/g, '_');
      }
    }
  }
  return obj;
}
<|endoftext|>