<commit_before>/* global describe, it */

'use strict';

(function () {

  var expect = require('chai').expect;
  var stub = require('sinon').stub;

  var collect = require('../src/collect');
  var Command = require('../src/command');
  var KWArg = require('../src/kwarg');
  var Flag = require('../src/flag');
  var Arg = require('../src/arg');
  var utils = require('../src/utils');

  describe('collect.js', function () {

    it('should exist', function () {
      expect(collect).to.be.ok;
      expect(typeof collect).to.equal('function');
    });

    it('should return an arg tree when no args provided', function () {
      var boundCollect = collect.bind(null, 'node', 'npm', []);

      // Without tree
      var result = boundCollect(
        Command(
          'install'
        )
      );

      expect(result).to.eql({
        command: null,
        kwargs: {},
        flags: {},
        args: {}
      });

    });

    it('should return an arg tree when no schema provided', function () {
      var boundCollect = collect.bind(null, 'node', 'npm', []);

      // Without tree
      var result = boundCollect();

      expect(result).to.eql({
        command: null,
        kwargs: {},
        flags: {},
        args: {}
      });

    });

    it('should return an arg tree for single command schema', function () {
      var boundCollect = collect.bind(null, 'node', 'npm', ['install']);

      // With single node
      var result = boundCollect(
        Command(
          'install'
        )
      );

      expect(result).to.eql({
        command: {
          name: 'install',
          command: null,
          kwargs: {},
          flags: {},
          args: {}
        },
        kwargs: {},
        flags: {},
        args: {}
      });

    });

    it('should return an arg tree with nested schema', function () {
      var boundCollect = collect.bind(null, 'node', 'npm', ['install', 'jargs']);

      // With nested nodes
      var result = boundCollect(
        Command(
          'install',
          null,
          Arg(
            'lib'
          )
        )
      );

      expect(result).to.eql({
        command: {
          name: 'install',
          command: null,
          kwargs: {},
          flags: {},
          args: {
            lib: 'jargs'
          }
        },
        kwargs: {},
        flags: {},
        args: {}
      });
    });

    it('should return an arg tree with nested schema and flags', function () {
      var boundCollect = collect.bind(null, 'node', 'npm', ['install', 'jargs', '--save']);

      // With nested nodes
      var result = boundCollect(
        Command(
          'install',
          null,
          Arg(
            'lib'
          ),
          Flag(
            'save'
          )
        )
      );

      expect(result).to.eql({
        command: {
          name: 'install',
          command: null,
          kwargs: {},
          flags: {
            save: true
          },
          args: {
            lib: 'jargs'
          }
        },
        kwargs: {},
        flags: {},
        args: {}
      });
    });

    it('should return an arg tree with kwargs, flags, and args', function () {
      var boundCollect = collect.bind(null, 'node', 'browserify',
        ['--transform', 'babelify', '--verbose', '--outfile=build/index.js', 'src/index.js']);

      // With nested nodes
      var result = boundCollect(
        Arg(
          'input'
        ),
        Flag(
          'verbose'
        ),
        KWArg(
          'outfile'
        ),
        KWArg(
          'transform'
        )
      );

      expect(result).to.eql({
        command: null,
        kwargs: {
          transform: 'babelify',
          outfile: 'build/index.js'
        },
        flags: {
          verbose: true
        },
        args: {
          input: 'src/index.js'
        }
      });
    });

    it('should return an arg tree from aliases', function () {
      var boundCollect = collect.bind(null, 'node', 'browserify',
        ['b', '-t', 'babelify', '-v', '-o=build/index.js', 'src/index.js']);

      // With nested nodes
      var result = boundCollect(
        Command(
          'build',
          {alias: 'b'},
          Arg(
            'input'
          ),
          Flag(
            'verbose',
            {alias: 'v'}
          ),
          KWArg(
            'outfile',
            {alias: 'o'}
          ),
          KWArg(
            'transform',
            {alias: 't'}
          )
        )
      );

      expect(result).to.eql({
        command: {
          name: 'build',
          command: null,
          kwargs: {
            transform: 'babelify',
            outfile: 'build/index.js'
          },
          flags: {
            verbose: true
          },
          args: {
            input: 'src/index.js'
          }
        },
        kwargs: {},
        flags: {},
        args: {}
      });
    });

    it('should throw an error for duplicate kwargs', function () {
      var throwErrorStub = stub(utils, 'throwError');
      var anError = /duplicate/i;

      var boundCollect = collect.bind(null, 'node', 'test',
        ['--kwarg=correct', '--kwarg=incorrect']);

      // With nested nodes
      boundCollect(
        Arg(
          'arg'
        ),
        KWArg(
          'kwarg'
        )
      );

      expect(throwErrorStub).to.have.been.calledWithMatch(anError);

      throwErrorStub.restore();
    });

    it('should throw an error for duplicate flags', function () {
      var throwErrorStub = stub(utils, 'throwError');
      var anError = /duplicate/i;

      var boundCollect = collect.bind(null, 'node', 'test',
        ['--flag', '--flag']);

      // With nested nodes
      boundCollect(
        Arg(
          'arg'
        ),
        Flag(
          'flag'
        )
      );

      expect(throwErrorStub).to.have.been.calledWithMatch(anError);

      throwErrorStub.restore();
    });

    it('should throw an error for unknown flags / kwargs', function () {
      var throwErrorStub = stub(utils, 'throwError');
      var anError = /unknown/i;

      var boundCollect = collect.bind(null, 'node', 'test',
        ['--version']);

      // With nested nodes
      boundCollect(
        Arg(
          'arg'
        ),
        Flag(
          'flag'
        ),
        KWArg(
          'kwarg'
        )
      );

      expect(throwErrorStub).to.have.been.calledWithMatch(anError);

      throwErrorStub.restore();
    });

    it('should throw an error for unknown commands / args', function () {
      var throwErrorStub = stub(utils, 'throwError');
      var anError = /unknown/i;

      var boundCollect = collect.bind(null, 'node', 'test',
        ['another-command']);

      // With nested nodes
      boundCollect(
        Command(
          'command'
        ),
        Flag(
          'flag'
        ),
        KWArg(
          'kwarg'
        )
      );

      expect(throwErrorStub).to.have.been.calledWithMatch(anError);

      throwErrorStub.restore();
    });

  });

})();
<commit_msg>Test prioritizing commands<commit_after>/* global describe, it */

'use strict';

(function () {

  var expect = require('chai').expect;
  var stub = require('sinon').stub;

  var collect = require('../src/collect');
  var Command = require('../src/command');
  var KWArg = require('../src/kwarg');
  var Flag = require('../src/flag');
  var Arg = require('../src/arg');
  var utils = require('../src/utils');

  describe('collect.js', function () {

    it('should exist', function () {
      expect(collect).to.be.ok;
      expect(typeof collect).to.equal('function');
    });

    it('should return an arg tree when no args provided', function () {
      var boundCollect = collect.bind(null, 'node', 'npm', []);

      // Without tree
      var result = boundCollect(
        Command(
          'install'
        )
      );

      expect(result).to.eql({
        command: null,
        kwargs: {},
        flags: {},
        args: {}
      });

    });

    it('should return an arg tree when no schema provided', function () {
      var boundCollect = collect.bind(null, 'node', 'npm', []);

      // Without tree
      var result = boundCollect();

      expect(result).to.eql({
        command: null,
        kwargs: {},
        flags: {},
        args: {}
      });

    });

    it('should return an arg tree for single command schema', function () {
      var boundCollect = collect.bind(null, 'node', 'npm', ['install']);

      // With single node
      var result = boundCollect(
        Command(
          'install'
        )
      );

      expect(result).to.eql({
        command: {
          name: 'install',
          command: null,
          kwargs: {},
          flags: {},
          args: {}
        },
        kwargs: {},
        flags: {},
        args: {}
      });

    });

    it('should return an arg tree with nested schema', function () {
      var boundCollect = collect.bind(null, 'node', 'npm', ['install', 'jargs']);

      // With nested nodes
      var result = boundCollect(
        Command(
          'install',
          null,
          Arg(
            'lib'
          )
        )
      );

      expect(result).to.eql({
        command: {
          name: 'install',
          command: null,
          kwargs: {},
          flags: {},
          args: {
            lib: 'jargs'
          }
        },
        kwargs: {},
        flags: {},
        args: {}
      });
    });

    it('should return an arg tree with nested schema and flags', function () {
      var boundCollect = collect.bind(null, 'node', 'npm', ['install', 'jargs', '--save']);

      // With nested nodes
      var result = boundCollect(
        Command(
          'install',
          null,
          Arg(
            'lib'
          ),
          Flag(
            'save'
          )
        )
      );

      expect(result).to.eql({
        command: {
          name: 'install',
          command: null,
          kwargs: {},
          flags: {
            save: true
          },
          args: {
            lib: 'jargs'
          }
        },
        kwargs: {},
        flags: {},
        args: {}
      });
    });

    it('should return an arg tree with kwargs, flags, and args', function () {
      var boundCollect = collect.bind(null, 'node', 'browserify',
        ['--transform', 'babelify', '--verbose', '--outfile=build/index.js', 'src/index.js']);

      // With nested nodes
      var result = boundCollect(
        Arg(
          'input'
        ),
        Flag(
          'verbose'
        ),
        KWArg(
          'outfile'
        ),
        KWArg(
          'transform'
        )
      );

      expect(result).to.eql({
        command: null,
        kwargs: {
          transform: 'babelify',
          outfile: 'build/index.js'
        },
        flags: {
          verbose: true
        },
        args: {
          input: 'src/index.js'
        }
      });
    });

    it('should prioritize commands and traverse their children (test 1)', function () {
      var result;
      var boundCollect = collect.bind(null, 'node', 'browserify', ['command', 'command']);

      result = boundCollect(
        Arg(
          'arg1'
        ),
        Command(
          'command',
          null,
          Arg(
            'arg2'
          )
        )
      );

      expect(result).to.eql({
        command: {
          name: 'command',
          command: null,
          kwargs: {},
          flags: {},
          args: {
            arg2: 'command'
          }
        },
        kwargs: {},
        flags: {},
        args: {}
      });
    });

    it('should prioritize commands and traverse their children (test 2)', function () {
      var result;
      var boundCollect = collect.bind(null, 'node', 'browserify', ['not-a-command']);

      result = boundCollect(
        Arg(
          'arg1'
        ),
        Command(
          'command',
          null,
          Arg(
            'arg2'
          )
        )
      );

      expect(result).to.eql({
        command: null,
        kwargs: {},
        flags: {},
        args: {
          arg1: 'not-a-command'
        }
      });
    });

    it('should return an arg tree from aliases', function () {
      var boundCollect = collect.bind(null, 'node', 'browserify',
        ['b', '-t', 'babelify', '-v', '-o=build/index.js', 'src/index.js']);

      // With nested nodes
      var result = boundCollect(
        Command(
          'build',
          {alias: 'b'},
          Arg(
            'input'
          ),
          Flag(
            'verbose',
            {alias: 'v'}
          ),
          KWArg(
            'outfile',
            {alias: 'o'}
          ),
          KWArg(
            'transform',
            {alias: 't'}
          )
        )
      );

      expect(result).to.eql({
        command: {
          name: 'build',
          command: null,
          kwargs: {
            transform: 'babelify',
            outfile: 'build/index.js'
          },
          flags: {
            verbose: true
          },
          args: {
            input: 'src/index.js'
          }
        },
        kwargs: {},
        flags: {},
        args: {}
      });
    });

    it('should throw an error for duplicate kwargs', function () {
      var throwErrorStub = stub(utils, 'throwError');
      var anError = /duplicate/i;

      var boundCollect = collect.bind(null, 'node', 'test',
        ['--kwarg=correct', '--kwarg=incorrect']);

      // With nested nodes
      boundCollect(
        Arg(
          'arg'
        ),
        KWArg(
          'kwarg'
        )
      );

      expect(throwErrorStub).to.have.been.calledWithMatch(anError);

      throwErrorStub.restore();
    });

    it('should throw an error for duplicate flags', function () {
      var throwErrorStub = stub(utils, 'throwError');
      var anError = /duplicate/i;

      var boundCollect = collect.bind(null, 'node', 'test',
        ['--flag', '--flag']);

      // With nested nodes
      boundCollect(
        Arg(
          'arg'
        ),
        Flag(
          'flag'
        )
      );

      expect(throwErrorStub).to.have.been.calledWithMatch(anError);

      throwErrorStub.restore();
    });

    it('should throw an error for unknown flags / kwargs', function () {
      var throwErrorStub = stub(utils, 'throwError');
      var anError = /unknown/i;

      var boundCollect = collect.bind(null, 'node', 'test',
        ['--version']);

      // With nested nodes
      boundCollect(
        Arg(
          'arg'
        ),
        Flag(
          'flag'
        ),
        KWArg(
          'kwarg'
        )
      );

      expect(throwErrorStub).to.have.been.calledWithMatch(anError);

      throwErrorStub.restore();
    });

    it('should throw an error for unknown commands / args', function () {
      var throwErrorStub = stub(utils, 'throwError');
      var anError = /unknown/i;

      var boundCollect = collect.bind(null, 'node', 'test',
        ['another-command']);

      // With nested nodes
      boundCollect(
        Command(
          'command'
        ),
        Flag(
          'flag'
        ),
        KWArg(
          'kwarg'
        )
      );

      expect(throwErrorStub).to.have.been.calledWithMatch(anError);

      throwErrorStub.restore();
    });

  });

})();
<|endoftext|>


<commit_before>module.exports.name = 'user';

module.exports.alias = [
  'user',
  'u'
];
module.exports.isAllowed = () => {
  return true;
};

module.exports.help = '`,u [name, @mention]` Defaults to the invoked user. Note that the name search only works if the user has said something in the past 30 days. Else, @mention them.';

const Discord = require('discord.js');
const Util = require('../classes/Util.js');
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];

module.exports.command = async (message, content, bot, server) => {
  let user = content == '' ? message.author : Util.searchUser(message, content, server);
  let record;
  let member;
  if (!user) {
    if (!(record = server.users[content])) {
      message.react('❓');
      return;
    }
  } else {
    record = server.users[user.id];
    member = await server.guild.fetchMember(user.id);

    if (record == undefined) { // the user hasn't sent anything in the past 30 days
      let embed = new Discord.RichEmbed();
      embed.title = `Stats for ${user.tag}`;
      embed.description = 'Hasn\'t said anything in the past 30 days';
      embed.color = Number('0x3A8EDB');
      if (member) { // ban check
        embed.setFooter('Joined ');
        embed.timestamp = member.joinedAt;
      }
      message.channel.send({embed});
      return;
    }
  }

  let chans = record.chans;
  let ignoreHidden = !server.hiddenChannels.includes(message.channel.id);

  // Most active channels
  let topCHannels = {};
  for (let ch in chans) {
    if (server.hiddenChannels.includes(ch) && ignoreHidden) continue;
    if (topCHannels[ch]) {
      topCHannels[ch] += chans[ch];
    } else {
      topCHannels[ch] = chans[ch];
    }
  }

  // Sorts the active channels
  let sortable = [];
  for (let c in topCHannels) {
    sortable.push([c, topCHannels[c]]);
  }
  sortable.sort(function(a, b) {
    return b[1] - a[1];
  });
  let topChans = '';
  for (let i = 0; i < 3 && i < sortable.length; i++) {
    let perc = (sortable[i][1] / record.thirty * 100).toFixed(1);
    let channel = server.guild.channels.get(sortable[i][0]);
    if (!channel) continue;
    topChans += '**#' + channel.name + '** : ' + perc + '%\n';
  }

  // Most active day in the last 4 weeks, excluding today.
  let d = new Date().getUTCDay() - 1; // Sunday = 0, do not count today.
  if (d == -1) d = 6;
  let dayArr = [0, 0, 0, 0, 0, 0, 0]; // Su Mo Tu We Th Fr Sa
  let daySum = 0;
  let count = 0;
  let week = 0;
  for (let i = server.today; i >= server.today - 28; i--) { // 4 weeks
    let chans = record.record[((i % 31) + 31) % 31]; // for under flows
    for (let ch in chans) {
      if (ch == 'jpn' || ch == 'eng' || ch == 'vc') continue;
      if (count < 7) week += chans[ch];
      if (count == 0) continue;
      dayArr[d] += chans[ch];
      daySum += chans[ch];
    }
    count++;
    d = ((d - 1) % 7 + 7) % 7;
  }
  let maxDayNum = 0;
  let maxDay = 0;
  for (let j = 0; j < 7; j++) {
    if (dayArr[j] > maxDayNum) {
      maxDayNum = dayArr[j];
      maxDay = j;
    }
  }

  let hours = Math.floor(record.vc / 60);
  let vcTime = `${hours ? hours + 'hr '  : ''}${record.vc % 60}min`;

  let embed = new Discord.RichEmbed();
  if (user) {
    let fire = member.roles.has('384286851260743680');
    embed.setAuthor(`${fire ? '🔥' : ''}Stats for ${user.tag}${member.nickname ? ' aka ' + member.nickname : ''}` , user.avatarURL);
    embed.color = fire ? Number('0xFF5500') : Number('0x3A8EDB');
    embed.setFooter('Joined this server');
    embed.timestamp = member.joinedAt;
  } else { // user left
    embed.setAuthor(`Stats for <@${content}>`);
    embed.color = Number('0x3A8EDB');
  }
  embed.description = 'For the last 30 days (UTC time)';
  let chanPercent = (maxDayNum / daySum * 100).toFixed(1);
  let jpnPercent = (record.jp / (record.jp + record.en) * 100).toFixed(2);
  embed.addField('Messages sent\n M | W', `${record.thirty} | ${week}`, true);
  embed.addField('Most active channels', topChans ? topChans : 'none', true);
  if (maxDayNum != 0) embed.addField('Most active day', days[maxDay] + `\n(${chanPercent}%)`, true);
  //embed.addField('Emojis used', , true);
  //embed.addField('Reacted', record.reactions, true);
  embed.addField('Japanese usage', jpnPercent + '%', true);
  if (message.author.id == bot.owner_ID) embed.addField('Time Spent in VC', vcTime , true);

  message.channel.send({embed});
};
<commit_msg>allow vc<commit_after>module.exports.name = 'user';

module.exports.alias = [
  'user',
  'u'
];
module.exports.isAllowed = () => {
  return true;
};

module.exports.help = '`,u [name, @mention]` Defaults to the invoked user. Note that the name search only works if the user has said something in the past 30 days. Else, @mention them.';

const Discord = require('discord.js');
const Util = require('../classes/Util.js');
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];

module.exports.command = async (message, content, bot, server) => {
  let user = content == '' ? message.author : Util.searchUser(message, content, server);
  let record;
  let member;
  if (!user) {
    if (!(record = server.users[content])) {
      message.react('❓');
      return;
    }
  } else {
    record = server.users[user.id];
    member = await server.guild.fetchMember(user.id);

    if (record == undefined) { // the user hasn't sent anything in the past 30 days
      let embed = new Discord.RichEmbed();
      embed.title = `Stats for ${user.tag}`;
      embed.description = 'Hasn\'t said anything in the past 30 days';
      embed.color = Number('0x3A8EDB');
      if (member) { // ban check
        embed.setFooter('Joined ');
        embed.timestamp = member.joinedAt;
      }
      message.channel.send({embed});
      return;
    }
  }

  let chans = record.chans;
  let ignoreHidden = !server.hiddenChannels.includes(message.channel.id);

  // Most active channels
  let topCHannels = {};
  for (let ch in chans) {
    if (server.hiddenChannels.includes(ch) && ignoreHidden) continue;
    if (topCHannels[ch]) {
      topCHannels[ch] += chans[ch];
    } else {
      topCHannels[ch] = chans[ch];
    }
  }

  // Sorts the active channels
  let sortable = [];
  for (let c in topCHannels) {
    sortable.push([c, topCHannels[c]]);
  }
  sortable.sort(function(a, b) {
    return b[1] - a[1];
  });
  let topChans = '';
  for (let i = 0; i < 3 && i < sortable.length; i++) {
    let perc = (sortable[i][1] / record.thirty * 100).toFixed(1);
    let channel = server.guild.channels.get(sortable[i][0]);
    if (!channel) continue;
    topChans += '**#' + channel.name + '** : ' + perc + '%\n';
  }

  // Most active day in the last 4 weeks, excluding today.
  let d = new Date().getUTCDay() - 1; // Sunday = 0, do not count today.
  if (d == -1) d = 6;
  let dayArr = [0, 0, 0, 0, 0, 0, 0]; // Su Mo Tu We Th Fr Sa
  let daySum = 0;
  let count = 0;
  let week = 0;
  for (let i = server.today; i >= server.today - 28; i--) { // 4 weeks
    let chans = record.record[((i % 31) + 31) % 31]; // for under flows
    for (let ch in chans) {
      if (ch == 'jpn' || ch == 'eng' || ch == 'vc') continue;
      if (count < 7) week += chans[ch];
      if (count == 0) continue;
      dayArr[d] += chans[ch];
      daySum += chans[ch];
    }
    count++;
    d = ((d - 1) % 7 + 7) % 7;
  }
  let maxDayNum = 0;
  let maxDay = 0;
  for (let j = 0; j < 7; j++) {
    if (dayArr[j] > maxDayNum) {
      maxDayNum = dayArr[j];
      maxDay = j;
    }
  }

  let hours = Math.floor(record.vc / 60);
  let vcTime = `${hours ? hours + 'hr '  : ''}${record.vc % 60}min`;

  let embed = new Discord.RichEmbed();
  if (user) {
    let fire = member.roles.has('384286851260743680');
    embed.setAuthor(`${fire ? '🔥' : ''}Stats for ${user.tag}${member.nickname ? ' aka ' + member.nickname : ''}` , user.avatarURL);
    embed.color = fire ? Number('0xFF5500') : Number('0x3A8EDB');
    embed.setFooter('Joined this server');
    embed.timestamp = member.joinedAt;
  } else { // user left
    embed.setAuthor(`Stats for <@${content}>`);
    embed.color = Number('0x3A8EDB');
  }
  embed.description = 'For the last 30 days (UTC time)';
  let chanPercent = (maxDayNum / daySum * 100).toFixed(1);
  let jpnPercent = (record.jp / (record.jp + record.en) * 100).toFixed(2);
  embed.addField('Messages sent\n M | W', `${record.thirty} | ${week}`, true);
  embed.addField('Most active channels', topChans ? topChans : 'none', true);
  if (maxDayNum != 0) embed.addField('Most active day', days[maxDay] + `\n(${chanPercent}%)`, true);
  //embed.addField('Emojis used', , true);
  //embed.addField('Reacted', record.reactions, true);
  embed.addField('Japanese usage', jpnPercent + '%', true);
  embed.addField('Time Spent in VC', vcTime , true);

  message.channel.send({embed});
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var config = require('../config'),
  express = require('express'),
  morgan = require('morgan'),
  logger = require('./logger'),
  bodyParser = require('body-parser'),
  session = require('express-session'),
  MongoStore = require('connect-mongo')(session),
  favicon = require('serve-favicon'),
  compress = require('compression'),
  methodOverride = require('method-override'),
  cookieParser = require('cookie-parser'),
  helmet = require('helmet'),
  flash = require('connect-flash'),
  consolidate = require('consolidate'),
  mongoose = require('mongoose'),
  path = require('path');

/**
 * Initialize local variables
 */
module.exports.initLocalVariables = function (app) {
  // Setting application local variables
  app.locals.title = config.app.title;
  app.locals.description = config.app.description;
  if (config.secure && config.secure.ssl === true) {
    app.locals.secure = config.secure.ssl;
  }
  app.locals.keywords = config.app.keywords;
  app.locals.googleAnalyticsTrackingID = config.app.googleAnalyticsTrackingID;
  app.locals.facebookAppId = config.facebook.clientID;
  app.locals.jsFiles = config.files.client.js;
  app.locals.cssFiles = config.files.client.css;
  app.locals.livereload = config.livereload;
  app.locals.logo = config.logo;
  app.locals.favicon = config.favicon;

    // This code happens just after app.locals variables are set.
    // Passing the request url to environment locals
    app.use(function(req, res, next) {

        // Let's check user-agents to see if this is a social bot. If so, let's serve a different layout to populate the og data so it looks pretty when sharing.
        if( req.headers['user-agent'] === 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)' ||
            req.headers['user-agent'] === 'facebookexternalhit/1.0 (+http://www.facebook.com/externalhit_uatext.php)' ||
            req.headers['user-agent'] === 'facebookexternalhit/1.1 (+https://www.facebook.com/externalhit_uatext.php)' ||
            req.headers['user-agent'] === 'facebookexternalhit/1.0 (+https://www.facebook.com/externalhit_uatext.php)' ||
            req.headers['user-agent'] === 'visionutils/0.2' ||
            req.headers['user-agent'] === 'Twitterbot/1.0' ||
            req.headers['user-agent'] === 'LinkedInBot/1.0 (compatible; Mozilla/5.0; Jakarta Commons-HttpClient/3.1 +http://www.linkedin.com)' ||
            req.headers['user-agent'] === 'Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20110814 Firefox/6.0 Google (+https://developers.google.com/+/web/snippet/)' ||
            req.headers['user-agent'] === 'Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via ggpht.com GoogleImageProxy)') {

            var urlArray = req.url.substr(1).split('/');
            var module = urlArray[0];
            var id = urlArray[1];

            if('reviews' === module){

                var Review = mongoose.model('Review');
                var ObjectId = require('mongoose').Types.ObjectId;

                Review.findOne({ _id: new ObjectId(id) }, function(err, review) {
                    if(err) {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    } else if (review !== null) {

                        var uuidPath = uuid.replace(/-/g, '').match(/.{1,3}/g).join("/");
                        // Found link. Populate data.
                        res.status(200).render('modules/core/server/views/social-layout', {

                            // Now we update layout variables with DB info.
                            socialUrl: req.protocol + '://' + req.headers.host + req.url,
                            socialTitle: review.title,
                            socialDescription: 'Reseña realizada en Galatea por ' + review.user.displayName,
                            socialImageUrl: "http://media.cervantesvirtual.com/s3/BVMC_OBRAS/" + uuidPath + "/portada/Cover.jpg",
                            socialType: 'article'
                        });
                    } else {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    }
                });
            }
            else if('groups' === module){

                var Group = mongoose.model('Group');
                var ObjectId = require('mongoose').Types.ObjectId;

                Group.findOne({ _id: new ObjectId(id) }, function(err, group) {
                    if(err) {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    } else if (group !== null) {

                        // Found link. Populate data.
                        res.status(200).render('modules/core/server/views/social-layout', {

                            // Now we update layout variables with DB info.
                            socialUrl: req.protocol + '://' + req.headers.host + req.url,
                            socialTitle: group.name,
                            socialDescription: 'Grupo creado en Galatea por ' + group.user.displayName,
                            socialImageUrl: req.protocol + '://' + req.headers.host + '/modules/core/client/img/brand/fondo_bvmc_social_gris_rojo.png',
                            socialType: 'website'
                        });
                    } else {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    }
                });
            }
            else if('booklists' === module){

                var Booklist = mongoose.model('Booklist');
                var ObjectId = require('mongoose').Types.ObjectId;

                Booklist.findOne({ _id: new ObjectId(id) }, function(err, booklist) {
                    if(err) {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    } else if (booklist !== null) {

                        // Found link. Populate data.
                        res.status(200).render('modules/core/server/views/social-layout', {

                            // Now we update layout variables with DB info.
                            socialUrl: req.protocol + '://' + req.headers.host + req.url,
                            socialTitle: booklist.title,
                            socialDescription: 'Lista de obras creado en Galatea por ' + booklist.user.displayName,
                            socialImageUrl: req.protocol + '://' + req.headers.host + '/modules/core/client/img/brand/fondo_bvmc_social_gris_rojo.png',
                            socialType: 'website'
                        });
                    } else {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    }
                });
            }
            else if('publications' === module){

                var Publication = mongoose.model('Publication');
                var ObjectId = require('mongoose').Types.ObjectId;

                Publication.findOne({ _id: new ObjectId(id) }, function(err, publication) {
                    if(err) {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    } else if (publication !== null) {

                        // Found link. Populate data.
                        res.status(200).render('modules/core/server/views/social-layout', {

                            // Now we update layout variables with DB info.
                            socialUrl: req.protocol + '://' + req.headers.host + req.url,
                            socialTitle: publication.title,
                            socialDescription: 'Publicación creada en Galatea por ' + publication.user.displayName,
                            socialImageUrl: req.protocol + '://' + req.headers.host + '/modules/core/client/img/brand/fondo_bvmc_social_gris_rojo.png',
                            socialType: 'book'
                        });
                    } else {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    }
                });
            }
        } else {
            res.locals.url = req.protocol + '://' + req.headers.host;
            next();
        }
    });
};

/**
 * Initialize application middleware
 */
module.exports.initMiddleware = function (app) {
  // Showing stack errors
  app.set('showStackError', true);

  // Enable jsonp
  app.enable('jsonp callback');

  // Should be placed before express.static
  app.use(compress({
    filter: function (req, res) {
      return (/json|text|javascript|css|font|svg/).test(res.getHeader('Content-Type'));
    },
    level: 9
  }));

  // Initialize favicon middleware
  app.use(favicon(app.locals.favicon));

  // Enable logger (morgan)
  app.use(morgan(logger.getFormat(), logger.getOptions()));

  // Environment dependent middleware
  if (process.env.NODE_ENV === 'development') {
    // Disable views cache
    app.set('view cache', false);
  } else if (process.env.NODE_ENV === 'production') {
    app.locals.cache = 'memory';
  }

  // Request body parsing middleware should be above methodOverride
  app.use(bodyParser.urlencoded({
    extended: true
  }));
  app.use(bodyParser.json());
  app.use(methodOverride());

  // Add the cookie parser and flash middleware
  app.use(cookieParser());
  app.use(flash());
};

/**
 * Configure view engine
 */
module.exports.initViewEngine = function (app) {
  // Set swig as the template engine
  app.engine('server.view.html', consolidate[config.templateEngine]);

  // Set views path and view engine
  app.set('view engine', 'server.view.html');
  app.set('views', './');
};

/**
 * Configure Express session
 */
module.exports.initSession = function (app, db) {
  // Express MongoDB session storage
  app.use(session({
    saveUninitialized: true,
    resave: true,
    secret: config.sessionSecret,
    cookie: {
      maxAge: config.sessionCookie.maxAge,
      httpOnly: config.sessionCookie.httpOnly,
      secure: config.sessionCookie.secure && config.secure.ssl
    },
    key: config.sessionKey,
    store: new MongoStore({
      mongooseConnection: db.connection,
      collection: config.sessionCollection
    })
  }));
};

/**
 * Invoke modules server configuration
 */
module.exports.initModulesConfiguration = function (app, db) {
  config.files.server.configs.forEach(function (configPath) {
    require(path.resolve(configPath))(app, db);
  });
};

/**
 * Configure Helmet headers configuration
 */
module.exports.initHelmetHeaders = function (app) {
  // Use helmet to secure Express headers
  var SIX_MONTHS = 15778476000;
  app.use(helmet.xframe());
  app.use(helmet.xssFilter());
  app.use(helmet.nosniff());
  app.use(helmet.ienoopen());
  app.use(helmet.hsts({
    maxAge: SIX_MONTHS,
    includeSubdomains: true,
    force: true
  }));
  app.disable('x-powered-by');
};

/**
 * Configure the modules static routes
 */
module.exports.initModulesClientRoutes = function (app) {
  // Setting the app router and static folder
  app.use('/', express.static(path.resolve('./public')));

  // Globbing static routing
  config.folders.client.forEach(function (staticPath) {
    app.use(staticPath, express.static(path.resolve('./' + staticPath)));
  });
};

/**
 * Configure the modules ACL policies
 */
module.exports.initModulesServerPolicies = function (app) {
  // Globbing policy files
  config.files.server.policies.forEach(function (policyPath) {
    require(path.resolve(policyPath)).invokeRolesPolicies();
  });
};

/**
 * Configure the modules server routes
 */
module.exports.initModulesServerRoutes = function (app) {
  // Globbing routing files
  config.files.server.routes.forEach(function (routePath) {
    require(path.resolve(routePath))(app);
  });
};

/**
 * Configure error handling
 */
module.exports.initErrorRoutes = function (app) {
  app.use(function (err, req, res, next) {
    // If the error object doesn't exists
    if (!err) {
      return next();
    }

    // Log it
    console.error(err.stack);

    // Redirect to error page
    res.redirect('/server-error');
  });
};

/**
 * Configure Socket.io
 */
module.exports.configureSocketIO = function (app, db) {
  // Load the Socket.io configuration
  var server = require('./socket.io')(app, db);

  // Return server object
  return server;
};

/**
 * Initialize the Express application
 */
module.exports.init = function (db) {
  // Initialize express app
  var app = express();

  // Initialize local variables
  this.initLocalVariables(app);

  // Initialize Express middleware
  this.initMiddleware(app);

  // Initialize Express view engine
  this.initViewEngine(app);

  // Initialize Helmet security headers
  this.initHelmetHeaders(app);

  // Initialize modules static client routes, before session!
  this.initModulesClientRoutes(app);

  // Initialize Express session
  this.initSession(app, db);

  // Initialize Modules configuration
  this.initModulesConfiguration(app);

  // Initialize modules server authorization policies
  this.initModulesServerPolicies(app);

  // Initialize modules server routes
  this.initModulesServerRoutes(app);

  // Initialize error routes
  this.initErrorRoutes(app);

  // Configure Socket.io
  app = this.configureSocketIO(app, db);

  return app;
};
<commit_msg>img open graph<commit_after>'use strict';

/**
 * Module dependencies.
 */
var config = require('../config'),
  express = require('express'),
  morgan = require('morgan'),
  logger = require('./logger'),
  bodyParser = require('body-parser'),
  session = require('express-session'),
  MongoStore = require('connect-mongo')(session),
  favicon = require('serve-favicon'),
  compress = require('compression'),
  methodOverride = require('method-override'),
  cookieParser = require('cookie-parser'),
  helmet = require('helmet'),
  flash = require('connect-flash'),
  consolidate = require('consolidate'),
  mongoose = require('mongoose'),
  path = require('path');

/**
 * Initialize local variables
 */
module.exports.initLocalVariables = function (app) {
  // Setting application local variables
  app.locals.title = config.app.title;
  app.locals.description = config.app.description;
  if (config.secure && config.secure.ssl === true) {
    app.locals.secure = config.secure.ssl;
  }
  app.locals.keywords = config.app.keywords;
  app.locals.googleAnalyticsTrackingID = config.app.googleAnalyticsTrackingID;
  app.locals.facebookAppId = config.facebook.clientID;
  app.locals.jsFiles = config.files.client.js;
  app.locals.cssFiles = config.files.client.css;
  app.locals.livereload = config.livereload;
  app.locals.logo = config.logo;
  app.locals.favicon = config.favicon;

    // This code happens just after app.locals variables are set.
    // Passing the request url to environment locals
    app.use(function(req, res, next) {

        // Let's check user-agents to see if this is a social bot. If so, let's serve a different layout to populate the og data so it looks pretty when sharing.
        if( req.headers['user-agent'] === 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)' ||
            req.headers['user-agent'] === 'facebookexternalhit/1.0 (+http://www.facebook.com/externalhit_uatext.php)' ||
            req.headers['user-agent'] === 'facebookexternalhit/1.1 (+https://www.facebook.com/externalhit_uatext.php)' ||
            req.headers['user-agent'] === 'facebookexternalhit/1.0 (+https://www.facebook.com/externalhit_uatext.php)' ||
            req.headers['user-agent'] === 'visionutils/0.2' ||
            req.headers['user-agent'] === 'Twitterbot/1.0' ||
            req.headers['user-agent'] === 'LinkedInBot/1.0 (compatible; Mozilla/5.0; Jakarta Commons-HttpClient/3.1 +http://www.linkedin.com)' ||
            req.headers['user-agent'] === 'Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20110814 Firefox/6.0 Google (+https://developers.google.com/+/web/snippet/)' ||
            req.headers['user-agent'] === 'Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via ggpht.com GoogleImageProxy)') {

            var urlArray = req.url.substr(1).split('/');
            var module = urlArray[0];
            var id = urlArray[1];

            if('reviews' === module){

                var Review = mongoose.model('Review');
                var ObjectId = require('mongoose').Types.ObjectId;

                Review.findOne({ _id: new ObjectId(id) }, function(err, review) {
                    if(err) {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    } else if (review !== null) {

                        var uuidPath = review.uuid.replace(/-/g, '').match(/.{1,3}/g).join("/");
                        // Found link. Populate data.
                        res.status(200).render('modules/core/server/views/social-layout', {

                            // Now we update layout variables with DB info.
                            socialUrl: req.protocol + '://' + req.headers.host + req.url,
                            socialTitle: review.title,
                            socialDescription: 'Reseña realizada en Galatea por ' + review.user.displayName,
                            socialImageUrl: "http://media.cervantesvirtual.com/s3/BVMC_OBRAS/" + uuidPath + "/portada/Cover.jpg",
                            socialType: 'article'
                        });
                    } else {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    }
                });
            }
            else if('groups' === module){

                var Group = mongoose.model('Group');
                var ObjectId = require('mongoose').Types.ObjectId;

                Group.findOne({ _id: new ObjectId(id) }, function(err, group) {
                    if(err) {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    } else if (group !== null) {

                        // Found link. Populate data.
                        res.status(200).render('modules/core/server/views/social-layout', {

                            // Now we update layout variables with DB info.
                            socialUrl: req.protocol + '://' + req.headers.host + req.url,
                            socialTitle: group.name,
                            socialDescription: 'Grupo creado en Galatea por ' + group.user.displayName,
                            socialImageUrl: req.protocol + '://' + req.headers.host + '/modules/core/client/img/brand/fondo_bvmc_social_gris_rojo.png',
                            socialType: 'website'
                        });
                    } else {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    }
                });
            }
            else if('booklists' === module){

                var Booklist = mongoose.model('Booklist');
                var ObjectId = require('mongoose').Types.ObjectId;

                Booklist.findOne({ _id: new ObjectId(id) }, function(err, booklist) {
                    if(err) {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    } else if (booklist !== null) {

                        // Found link. Populate data.
                        res.status(200).render('modules/core/server/views/social-layout', {

                            // Now we update layout variables with DB info.
                            socialUrl: req.protocol + '://' + req.headers.host + req.url,
                            socialTitle: booklist.title,
                            socialDescription: 'Lista de obras creado en Galatea por ' + booklist.user.displayName,
                            socialImageUrl: req.protocol + '://' + req.headers.host + '/modules/core/client/img/brand/fondo_bvmc_social_gris_rojo.png',
                            socialType: 'website'
                        });
                    } else {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    }
                });
            }
            else if('publications' === module){

                var Publication = mongoose.model('Publication');
                var ObjectId = require('mongoose').Types.ObjectId;

                Publication.findOne({ _id: new ObjectId(id) }, function(err, publication) {
                    if(err) {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    } else if (publication !== null) {

                        // Found link. Populate data.
                        res.status(200).render('modules/core/server/views/social-layout', {

                            // Now we update layout variables with DB info.
                            socialUrl: req.protocol + '://' + req.headers.host + req.url,
                            socialTitle: publication.title,
                            socialDescription: 'Publicación creada en Galatea por ' + publication.user.displayName,
                            socialImageUrl: req.protocol + '://' + req.headers.host + '/modules/core/client/img/brand/fondo_bvmc_social_gris_rojo.png',
                            socialType: 'book'
                        });
                    } else {
                        res.locals.url = req.protocol + '://' + req.headers.host;
                        next();
                    }
                });
            }
        } else {
            res.locals.url = req.protocol + '://' + req.headers.host;
            next();
        }
    });
};

/**
 * Initialize application middleware
 */
module.exports.initMiddleware = function (app) {
  // Showing stack errors
  app.set('showStackError', true);

  // Enable jsonp
  app.enable('jsonp callback');

  // Should be placed before express.static
  app.use(compress({
    filter: function (req, res) {
      return (/json|text|javascript|css|font|svg/).test(res.getHeader('Content-Type'));
    },
    level: 9
  }));

  // Initialize favicon middleware
  app.use(favicon(app.locals.favicon));

  // Enable logger (morgan)
  app.use(morgan(logger.getFormat(), logger.getOptions()));

  // Environment dependent middleware
  if (process.env.NODE_ENV === 'development') {
    // Disable views cache
    app.set('view cache', false);
  } else if (process.env.NODE_ENV === 'production') {
    app.locals.cache = 'memory';
  }

  // Request body parsing middleware should be above methodOverride
  app.use(bodyParser.urlencoded({
    extended: true
  }));
  app.use(bodyParser.json());
  app.use(methodOverride());

  // Add the cookie parser and flash middleware
  app.use(cookieParser());
  app.use(flash());
};

/**
 * Configure view engine
 */
module.exports.initViewEngine = function (app) {
  // Set swig as the template engine
  app.engine('server.view.html', consolidate[config.templateEngine]);

  // Set views path and view engine
  app.set('view engine', 'server.view.html');
  app.set('views', './');
};

/**
 * Configure Express session
 */
module.exports.initSession = function (app, db) {
  // Express MongoDB session storage
  app.use(session({
    saveUninitialized: true,
    resave: true,
    secret: config.sessionSecret,
    cookie: {
      maxAge: config.sessionCookie.maxAge,
      httpOnly: config.sessionCookie.httpOnly,
      secure: config.sessionCookie.secure && config.secure.ssl
    },
    key: config.sessionKey,
    store: new MongoStore({
      mongooseConnection: db.connection,
      collection: config.sessionCollection
    })
  }));
};

/**
 * Invoke modules server configuration
 */
module.exports.initModulesConfiguration = function (app, db) {
  config.files.server.configs.forEach(function (configPath) {
    require(path.resolve(configPath))(app, db);
  });
};

/**
 * Configure Helmet headers configuration
 */
module.exports.initHelmetHeaders = function (app) {
  // Use helmet to secure Express headers
  var SIX_MONTHS = 15778476000;
  app.use(helmet.xframe());
  app.use(helmet.xssFilter());
  app.use(helmet.nosniff());
  app.use(helmet.ienoopen());
  app.use(helmet.hsts({
    maxAge: SIX_MONTHS,
    includeSubdomains: true,
    force: true
  }));
  app.disable('x-powered-by');
};

/**
 * Configure the modules static routes
 */
module.exports.initModulesClientRoutes = function (app) {
  // Setting the app router and static folder
  app.use('/', express.static(path.resolve('./public')));

  // Globbing static routing
  config.folders.client.forEach(function (staticPath) {
    app.use(staticPath, express.static(path.resolve('./' + staticPath)));
  });
};

/**
 * Configure the modules ACL policies
 */
module.exports.initModulesServerPolicies = function (app) {
  // Globbing policy files
  config.files.server.policies.forEach(function (policyPath) {
    require(path.resolve(policyPath)).invokeRolesPolicies();
  });
};

/**
 * Configure the modules server routes
 */
module.exports.initModulesServerRoutes = function (app) {
  // Globbing routing files
  config.files.server.routes.forEach(function (routePath) {
    require(path.resolve(routePath))(app);
  });
};

/**
 * Configure error handling
 */
module.exports.initErrorRoutes = function (app) {
  app.use(function (err, req, res, next) {
    // If the error object doesn't exists
    if (!err) {
      return next();
    }

    // Log it
    console.error(err.stack);

    // Redirect to error page
    res.redirect('/server-error');
  });
};

/**
 * Configure Socket.io
 */
module.exports.configureSocketIO = function (app, db) {
  // Load the Socket.io configuration
  var server = require('./socket.io')(app, db);

  // Return server object
  return server;
};

/**
 * Initialize the Express application
 */
module.exports.init = function (db) {
  // Initialize express app
  var app = express();

  // Initialize local variables
  this.initLocalVariables(app);

  // Initialize Express middleware
  this.initMiddleware(app);

  // Initialize Express view engine
  this.initViewEngine(app);

  // Initialize Helmet security headers
  this.initHelmetHeaders(app);

  // Initialize modules static client routes, before session!
  this.initModulesClientRoutes(app);

  // Initialize Express session
  this.initSession(app, db);

  // Initialize Modules configuration
  this.initModulesConfiguration(app);

  // Initialize modules server authorization policies
  this.initModulesServerPolicies(app);

  // Initialize modules server routes
  this.initModulesServerRoutes(app);

  // Initialize error routes
  this.initErrorRoutes(app);

  // Configure Socket.io
  app = this.configureSocketIO(app, db);

  return app;
};
<|endoftext|>


<commit_before>/*!
* screenfull
* v3.0.0 - 2015-11-24
* (c) Sindre Sorhus; MIT License
*/
!function(){"use strict";var a="undefined"!=typeof module&&module.exports,b="undefined"!=typeof Element&&"ALLOW_KEYBOARD_INPUT"in Element,c=function(){for(var a,b,c=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],d=0,e=c.length,f={};e>d;d++)if(a=c[d],a&&a[1]in document){for(d=0,b=a.length;b>d;d++)f[c[0][d]]=a[d];return f}return!1}(),d={request:function(a){var d=c.requestFullscreen;a=a||document.documentElement,/5\.1[\.\d]* Safari/.test(navigator.userAgent)?a[d]():a[d](b&&Element.ALLOW_KEYBOARD_INPUT)},exit:function(){document[c.exitFullscreen]()},toggle:function(a){this.isFullscreen?this.exit():this.request(a)},raw:c};return c?(Object.defineProperties(d,{isFullscreen:{get:function(){return Boolean(document[c.fullscreenElement])}},element:{enumerable:!0,get:function(){return document[c.fullscreenElement]}},enabled:{enumerable:!0,get:function(){return Boolean(document[c.fullscreenEnabled])}}}),void(a?module.exports=d:window.screenfull=d)):void(a?module.exports=!1:window.screenfull=!1)}();<commit_msg>Upgrade screenful.js to 3.3.3 (Fix issue with Chrome 67+)<commit_after>/*!
* screenfull
* v3.3.3 - 2018-09-04
* (c) Sindre Sorhus; MIT License
*/

!function(){"use strict";var a="undefined"!=typeof window&&void 0!==window.document?window.document:{},b="undefined"!=typeof module&&module.exports,c="undefined"!=typeof Element&&"ALLOW_KEYBOARD_INPUT"in Element,d=function(){for(var b,c=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],d=0,e=c.length,f={};d<e;d++)if((b=c[d])&&b[1]in a){for(d=0;d<b.length;d++)f[c[0][d]]=b[d];return f}return!1}(),e={change:d.fullscreenchange,error:d.fullscreenerror},f={request:function(b){var e=d.requestFullscreen;b=b||a.documentElement,/ Version\/5\.1(?:\.\d+)? Safari\//.test(navigator.userAgent)?b[e]():b[e](c?Element.ALLOW_KEYBOARD_INPUT:{})},exit:function(){a[d.exitFullscreen]()},toggle:function(a){this.isFullscreen?this.exit():this.request(a)},onchange:function(a){this.on("change",a)},onerror:function(a){this.on("error",a)},on:function(b,c){var d=e[b];d&&a.addEventListener(d,c,!1)},off:function(b,c){var d=e[b];d&&a.removeEventListener(d,c,!1)},raw:d};if(!d)return void(b?module.exports=!1:window.screenfull=!1);Object.defineProperties(f,{isFullscreen:{get:function(){return Boolean(a[d.fullscreenElement])}},element:{enumerable:!0,get:function(){return a[d.fullscreenElement]}},enabled:{enumerable:!0,get:function(){return Boolean(a[d.fullscreenEnabled])}}}),b?module.exports=f:window.screenfull=f}();<|endoftext|>


<commit_before>angular.module('starter.controllers', [])

.controller('appCtrl', function($scope, $ionicModal, $timeout) {
    alert("creating the main app ctrl");
    $scope.openNativeSettings = function() {
        alert("about to open native settings");
    }
})

.controller('logCtrl', function($scope) {

})

.controller('sensedDataCtrl', function($scope) {

})

.controller('mapCtrl', function($scope) {

})

.controller('PlaylistsCtrl', function($scope) {
  $scope.playlists = [
    { title: 'Reggae', id: 1 },
    { title: 'Chill', id: 2 },
    { title: 'Dubstep', id: 3 },
    { title: 'Indie', id: 4 },
    { title: 'Rap', id: 5 },
    { title: 'Cowbell', id: 6 }
  ];
})

.controller('PlaylistCtrl', function($scope, $stateParams) {
});
<commit_msg>Successfully integrated with the plugin!!<commit_after>angular.module('starter.controllers', [])

.controller('appCtrl', function($scope, $ionicModal, $timeout) {
    alert("creating the main app ctrl");
    $scope.openNativeSettings = function() {
        alert("about to open native settings");
        window.cordova.plugins.BEMLaunchNative.launch("NativeSettings", function(result) {
            alert("Successfully opened screen NativeSettings, result is "+result);
        }, function(err) {
            alert("Unable to open screen NativeSettings because of err "+err);
        });
    }
})

.controller('logCtrl', function($scope) {

})

.controller('sensedDataCtrl', function($scope) {

})

.controller('mapCtrl', function($scope) {

})

.controller('PlaylistsCtrl', function($scope) {
  $scope.playlists = [
    { title: 'Reggae', id: 1 },
    { title: 'Chill', id: 2 },
    { title: 'Dubstep', id: 3 },
    { title: 'Indie', id: 4 },
    { title: 'Rap', id: 5 },
    { title: 'Cowbell', id: 6 }
  ];
})

.controller('PlaylistCtrl', function($scope, $stateParams) {
});
<|endoftext|>


<commit_before>/**
 *	@author bh-lay
 *	@github https://github.com/bh-lay/uploader
 *  @updata 2014-3-10 22:25
 *
 */
window.util = window.util || {};
/**
 * until.drag(handle_dom,dom,fn);
 */
(function uploaderClosure(exports){
	var staticID = 0;
	var upCnt_tpl = ['

'].join('');
	var up_tpl = ['
',
		'',
		'<form method="post" action="{action}" enctype="multipart/form-data" name="uploader" target="uploader{ID}">',
			//请选择图片
			'<input name="{fileinputname}" type="file" multiple="multiple" class="uploader_btn" title="\u8BF7\u9009\u62E9\u56FE\u7247"/>',
			'{data}',
		'</form>',
	'
'].join('');

	var input_tpl = '<input type="hidden" name="{name}" value="{value}" />';

	var up_css = [''].join('');

	//创建工作环境
	var global_cnt = $(upCnt_tpl);

	$('body').append(global_cnt);
	$('head').append(up_css);

	//iframe加载事件监听方法
	function iframe_load(iframe,load){
		if (iframe.attachEvent){
			iframe.attachEvent("onload", function(){
				load&&load.call(iframe.contentDocument);
			});
		}else{
			iframe.onload = function(){
				load&&load.call(iframe.contentDocument);
			};
		}
	}
	//创建新的html
	function buildDom(){
		var this_up = this;
		var data_html = '';
		var data = this.data;
		for(var i in data){
			data_html += input_tpl.replace(/{(\w*)}/g,function(result,key){
				if(key == 'name'){
					return i;
				}else if(key == 'value'){
					return data[i]
				}
			});
		}

		var html = up_tpl.replace(/{(\w*)}/g,function(result,key){
			if(key == 'ID'){
				return this_up.ID
			}else if(key == 'action'){
				return this_up.action
			}else if(key == 'fileinputname'){
				return this_up.fileinputname
			}else if(key == "data"){
				return data_html;
			}
		});
		return $(html);
	}
	//获取文件信息
	function getFilesFromInput(input){
		var returns = [];
		if(input.value.length > 0){
			if(input.files){
				for(var i=0,total=input.files.length;i<total;i++){
					returns.push({
						'name' : input.files[i]['name'],
						'size' : input.files[i]['size']
					})
				}
			}else{
				returns.push({
					'name' : input.value.split(/\\/).pop()
				});
			}
		}
		return returns;
	}
	//格式化JSON
	function parseJSON(input){
		//去除部分浏览器自动添加的标签
		input = input.replace(/<[^>]+>|<\/[^>]+>/g,'');
		var output = {};
		//尝试去解析
		try{
			output = eval('(' + input + ')');
		}catch(e){
			output = 'fail';
		}
		return output;
	}
	//构造新的单次上传模块
	function SingleUp(param){
		var this_up = this;
		this.ID = ++staticID;
		this.action = param.action;
		this.data = param['data'] || {};

		//状态 等待上传|上传中
		//    wait | uploading
		this.status = 'wait';
		this.responseParser = param['responseParser'] || null;
		this.fileinputname = param['fileinputname'] || 'photos';
		//事件集
		this.onLeave = param.onLeave || null;
		this.onMousedown = param.onMousedown || null;
		this.beforeUpload = param.beforeUpload || null;
		this.onStartUpload = param.onStartUpload || null;
		this.onFail = param.onFail || null;
		this.onSuccess = param.onSuccess || null;

		this.dom = buildDom.call(this);

		var position = param.position;

		this.dom.css({
			'top' : position.top,
			'left' : position.left,
			'width' : position.width,
			'height' : position.height
		});

		global_cnt.append(this.dom);

		/**
		 * 这个定时器是为了处理IE7异步创建iframe的BUG
		 * 如果你有好的办法，请  mail:bh_lay@126.com
		 */
		setTimeout(function(){
			this_up.init();
		},100);
	}
	//销毁自己
	SingleUp.prototype.destory = function(){
		if(this.status == 'wait'){
			this.dom.remove();
		}else{
			this.dom.hide();
		}
	};
	//处理response
	SingleUp.prototype.handleResponse = function(responseTXT){
		var ID = this.ID;
		this.status = 'wait';
		//是否已格式化数据方法
		if(this.responseParser){
			var jsonData = parseJSON(responseTXT);
			if(jsonData == 'fail'){
					//服务器数据异常！
				this.onFail && this.onFail(ID,'\u670D\u52A1\u5668\u6570\u636E\u5F02\u5E38\uFF01');
			}else{
				//数据交由开发者格式化
				var parserData = this.responseParser(jsonData);

				if(typeof(parserData) != 'object'){
					this.onFail && this.onFail(ID);
				}else{
					if(parserData['files'] && parserData['files']['length'] > 0){
						this.onSuccess && this.onSuccess(ID,parserData['files'],parserData['extra']);
					}else{
						this.onFail && this.onFail(ID,parserData['extra']);
					}
				}
			}
		}else{
			this.onFail && this.onFail(ID,'you need define method : responseParser! ');
		}
		//销毁单次上传模块
		this.destory();
	}
	//初始化单次上传模块
	SingleUp.prototype.init = function(){
		var this_up = this;

		var uploaderDom = this.dom;
		var iframe = this.dom.find('iframe')[0];
		var ID = this.ID;
		//事件处理
		uploaderDom.on('mouseleave',function(){
	//		setTimeout(function(){
				this_up.onLeave && this_up.onLeave();
				this_up.destory();
		//	},100);
		}).on('mousedown',function(){
			this_up.onMousedown && this_up.onMousedown();
		}).on('mousemove',function(e){
			var oW = uploaderDom.width();
			var oL = uploaderDom.offset().left;
			var mL = e.pageX;
			uploaderDom.find('.uploader_btn').css('right',oL+oW-mL-25);
		}).on('change','.uploader_btn',function(){
			var input = this;
			var can_start = true;
			//检测是否已选择文件
			var files = getFilesFromInput(input);
			if(files.length > 0){
				//触发上传前事件
				if(this_up.beforeUpload){
					can_start = this_up.beforeUpload(ID,files);
				}else{
					can_start = true;
				}
				if(can_start){
					uploaderDom.hide();
					//开始上传文件
					$(this).parents('form').submit();
					this_up.status = 'uploading';
					//触发上传事件
					this_up.onStartUpload && this_up.onStartUpload(ID,files);
				}else{
					//重置html
					input.outerHTML = input.outerHTML;
				}
			}
		});
		iframe_load(iframe,function(){
			var responseTXT = this.body.innerHTML;
			this_up.handleResponse(responseTXT);
		});
	};

	////

	function uploader(param){
		var this_up = this;
		//事件堆
		this.events = {};
		this.action = param['action'] || null;
		this.data = param['data'] || {};
		//绑定上传方法的DOM
		this.dom = param['dom'];
		this.fileinputname = param['fileinputname'] || 'photos';
		//是否可上传
		this.can_upload = true;
		this.responseParser = param['responseParser'] || null;

		//为按钮绑定悬停事件
		this.dom.mouseenter(function(){
			this_up.createSingleUp($(this));
		});
	}
	uploader.prototype = {
		'on' : function (eventName,callback){
			//事件堆无该事件，创建一个事件堆
			if(!this.events[eventName]){
				this.events[eventName] = [];
			}
			this.events[eventName].push(callback);
			return this;
		},
		'emit' : function (eventName,args){
			//事件堆无该事件，结束运行
			if(!this.events[eventName]){
				return
			}
			args = args || null;
			for(var i=0,total=this.events[eventName].length;i<total;i++){
				this.events[eventName][i].apply(this.event_global || this , args);
			}
		},
		'createSingleUp' : function(BTN){
			BTN.addClass('hover');
			var offset = BTN.offset();
			var this_up = this;
			var newUp = new SingleUp({
				'action' : this.action,
				'data' : this.data,
				'responseParser' : this.responseParser,
				'position' : {
					'top' : offset.top,
					'left' : offset.left,
					'width' : BTN.outerWidth(),
					'height' : BTN.outerHeight()
				},
				'beforeUpload' : function(ID,files){
					this_up.emit('beforeUpload',[ID,files]);
					if(this_up.can_upload){
						return true;
					}else{
						return false;
					}
				},
				'onStartUpload' : function(ID,files){
					this_up.emit('startUpload',[ID,files]);
				},
				'onSuccess' : function(ID,files,extra){
					this_up.emit('success',[ID,files,extra]);
				},
				'onFail' : function(ID,extra){
					this_up.emit('fail',[ID,extra]);
				},
				'onLeave' : function(){
					BTN.removeClass('hover');
					BTN.removeClass('active');
				},
				'onMousedown' : function(){
					BTN.removeClass('hover')
					BTN.addClass('active');
				}
			});
		}
	};
	exports.uploader = uploader;
})(window.util);

//提供CommonJS规范的接口
define && define(function(require,exports,module){
	//对外接口
	return window.util.uploader;
});<commit_msg>太晚了，想不起刚刚改的啥了<commit_after>/**
 *	@author bh-lay
 *	@github https://github.com/bh-lay/uploader
 *  @updata 2014-3-12 00:06
 *
 */
window.util = window.util || {};
/**
 * until.drag(handle_dom,dom,fn);
 */
(function uploaderClosure(exports){
	var staticID = 0;
	var upCnt_tpl = ['

'].join('');
	var up_tpl = ['
',
		'',
		'<form method="post" action="{action}" enctype="multipart/form-data" name="uploader" target="uploader{ID}">',
			//请选择图片
			'<input name="{fileinputname}" type="file" multiple="multiple" class="uploader_btn" title="\u8BF7\u9009\u62E9\u56FE\u7247"/>',
			'{data}',
		'</form>',
	'
'].join('');

	var input_tpl = '<input type="hidden" name="{name}" value="{value}" />';

	var up_css = [''].join('');

	//创建工作环境
	var global_cnt = $(upCnt_tpl);

	$('body').append(global_cnt);
	$('head').append(up_css);

	//iframe加载事件监听方法
	function iframe_load(iframe,load){
		if (iframe.attachEvent){
			iframe.attachEvent("onload", function(){
				load&&load.call(iframe.contentDocument);
			});
		}else{
			iframe.onload = function(){
				load&&load.call(iframe.contentDocument);
			};
		}
	}
	//创建新的html
	function buildDom(){
		var this_up = this;
		var data_html = '';
		var data = this.data;
		for(var i in data){
			data_html += input_tpl.replace(/{(\w*)}/g,function(result,key){
				if(key == 'name'){
					return i;
				}else if(key == 'value'){
					return data[i]
				}
			});
		}

		var html = up_tpl.replace(/{(\w*)}/g,function(result,key){
			if(key == 'ID'){
				return this_up.ID
			}else if(key == 'action'){
				return this_up.action
			}else if(key == 'fileinputname'){
				return this_up.fileinputname
			}else if(key == "data"){
				return data_html;
			}
		});
		return $(html);
	}
	//获取文件信息
	function getFilesFromInput(input){
		var returns = [];
		if(input.value.length > 0){
			if(input.files){
				for(var i=0,total=input.files.length;i<total;i++){
					returns.push({
						'name' : input.files[i]['name'],
						'size' : input.files[i]['size']
					})
				}
			}else{
				returns.push({
					'name' : input.value.split(/\\/).pop()
				});
			}
		}
		return returns;
	}
	//格式化JSON
	function parseJSON(input){
		//去除部分浏览器自动添加的标签
		input = input.replace(/<[^>]+>|<\/[^>]+>/g,'');
		var output = {};
		//尝试去解析
		try{
			output = eval('(' + input + ')');
		}catch(e){
			output = 'fail';
		}
		return output;
	}
	//构造新的单次上传模块
	function SingleUp(param){
		var this_up = this;
		this.ID = ++staticID;
		this.action = param.action;
		this.data = param['data'] || {};

		//状态 等待上传|上传中
		//    wait | uploading
		this.status = 'wait';
		this.responseParser = param['responseParser'] || null;
		this.fileinputname = param['fileinputname'] || 'photos';
		//事件集
		this.onHide = param.onHide || null;
		this.onMousedown = param.onMousedown || null;
		this.beforeUpload = param.beforeUpload || null;
		this.onStartUpload = param.onStartUpload || null;
		this.onFail = param.onFail || null;
		this.onSuccess = param.onSuccess || null;

		this.dom = buildDom.call(this);

		var position = param.position;

		this.dom.css({
			'top' : position.top,
			'left' : position.left,
			'width' : position.width,
			'height' : position.height
		});

		global_cnt.append(this.dom);

		/**
		 * 这个定时器是为了处理IE7异步创建iframe的BUG
		 * 如果你有好的办法，请  mail:bh_lay@126.com
		 */
		setTimeout(function(){
			this_up.init();
		},100);
	}
	//销毁自己
	SingleUp.prototype.destory = function(){
		this.onHide && this.onHide();
		if(this.status == 'wait'){
			this.dom.remove();
		}else{
			this.dom.hide();
		}
	};
	//处理response
	SingleUp.prototype.handleResponse = function(responseTXT){
		var ID = this.ID;
		this.status = 'wait';
		//是否已格式化数据方法
		if(this.responseParser){
			var jsonData = parseJSON(responseTXT);
			if(jsonData == 'fail'){
					//服务器数据异常！
				this.onFail && this.onFail(ID,'\u670D\u52A1\u5668\u6570\u636E\u5F02\u5E38\uFF01');
			}else{
				//数据交由开发者格式化
				var parserData = this.responseParser(jsonData);

				if(typeof(parserData) != 'object'){
					this.onFail && this.onFail(ID);
				}else{
					if(parserData['files'] && parserData['files']['length'] > 0){
						this.onSuccess && this.onSuccess(ID,parserData['files'],parserData['extra']);
					}else{
						this.onFail && this.onFail(ID,parserData['extra']);
					}
				}
			}
		}else{
			this.onFail && this.onFail(ID,'you need define method : responseParser! ');
		}
		//销毁单次上传模块
		this.destory();
	}
	//初始化单次上传模块
	SingleUp.prototype.init = function(){
		var this_up = this;

		var uploaderDom = this.dom;
		var iframe = this.dom.find('iframe')[0];
		var ID = this.ID;
		//事件处理
		uploaderDom.on('mouseleave',function(){
	//		setTimeout(function(){
				this_up.destory();
		//	},100);
		}).on('mousedown',function(){
			this_up.onMousedown && this_up.onMousedown();
		}).on('mousemove',function(e){
			var oW = uploaderDom.width();
			var oL = uploaderDom.offset().left;
			var mL = e.pageX;
			uploaderDom.find('.uploader_btn').css('right',oL+oW-mL-25);
		}).on('change','.uploader_btn',function(){
			var input = this;
			var can_start = true;
			//检测是否已选择文件
			var files = getFilesFromInput(input);
			if(files.length > 0){
				//触发上传前事件
				if(this_up.beforeUpload){
					can_start = this_up.beforeUpload(ID,files);
				}else{
					can_start = true;
				}
				if(can_start){
					uploaderDom.hide();
					//开始上传文件
					$(this).parents('form').submit();
					this_up.status = 'uploading';
					//触发上传事件
					this_up.onStartUpload && this_up.onStartUpload(ID,files);
				}else{
					//重置html
					input.outerHTML = input.outerHTML;
				}
			}
		});
		iframe_load(iframe,function(){
			var responseTXT = this.body.innerHTML;
			this_up.handleResponse(responseTXT);
		});
	};

	////

	function uploader(param){
		var this_up = this;
		//事件堆
		this.events = {};
		this.action = param['action'] || null;
		this.data = param['data'] || {};
		//绑定上传方法的DOM
		this.dom = param['dom'];
		this.fileinputname = param['fileinputname'] || 'photos';
		//是否可上传
		this.can_upload = true;
		this.responseParser = param['responseParser'] || null;

		//为按钮绑定悬停事件
		var delay;
		this.dom.mouseenter(function(){
			clearTimeout(delay);
			var btn = $(this);
			delay = setTimeout(function(){
				this_up.createSingleUp(btn);
			},100);
		}).mouseleave(function(){
			clearTimeout(delay);
		});
	}
	uploader.prototype = {
		'on' : function (eventName,callback){
			//事件堆无该事件，创建一个事件堆
			if(!this.events[eventName]){
				this.events[eventName] = [];
			}
			this.events[eventName].push(callback);
			return this;
		},
		'emit' : function (eventName,args){
			//事件堆无该事件，结束运行
			if(!this.events[eventName]){
				return
			}
			args = args || null;
			for(var i=0,total=this.events[eventName].length;i<total;i++){
				this.events[eventName][i].apply(this.event_global || this , args);
			}
		},
		'createSingleUp' : function(BTN){
			BTN.addClass('hover');
			var offset = BTN.offset();
			var this_up = this;
			var newUp = new SingleUp({
				'action' : this.action,
				'data' : this.data,
				'responseParser' : this.responseParser,
				'position' : {
					'top' : offset.top,
					'left' : offset.left,
					'width' : BTN.outerWidth(),
					'height' : BTN.outerHeight()
				},
				'beforeUpload' : function(ID,files){
					this_up.emit('beforeUpload',[ID,files]);
					if(this_up.can_upload){
						return true;
					}else{
						return false;
					}
				},
				'onStartUpload' : function(ID,files){
					this_up.emit('startUpload',[ID,files]);
				},
				'onSuccess' : function(ID,files,extra){
					this_up.emit('success',[ID,files,extra]);
				},
				'onFail' : function(ID,extra){
					this_up.emit('fail',[ID,extra]);
				},
				'onHide' : function(){
					BTN.removeClass('hover');
					BTN.removeClass('active');
				},
				'onMousedown' : function(){
					BTN.removeClass('hover')
					BTN.addClass('active');
				}
			});
		}
	};
	exports.uploader = uploader;
})(window.util);

//提供CommonJS规范的接口
define && define(function(require,exports,module){
	//对外接口
	return window.util.uploader;
});<|endoftext|>


<commit_before>function update()
{
	$.get('/api/snapshots', function(snapshots)
	{
		if (snapshots === null || snapshots.length == 0)
		{
			return;
		}

		var now = +moment();
		_.each(snapshots, function(snapshot, i)
		{
			snapshots[i].duration = now - +moment(snapshot.timestamp);
		});

		updateModel(snapshots[0]);

		updateBatteryRemaining(snapshots[0]);
		updateLoad(snapshots[0]);
		updateRemainingRuntime(snapshots[0]);
		updateUtilityVoltage(snapshots[0]);

		drawBatteryRemainingChart(snapshots);
		drawLoadChart(snapshots);
		drawRemainingRuntimeChart(snapshots);
		drawUtilityVoltageChart(snapshots);

		$('#last-updated').html('Last updated ').append($('<time />', {datetime: snapshots[0].timestamp}).timeago());
	}, 'json');
}

function humanizeDuration(d)
{
	var s = moment.duration(-d).humanize(true);
	s = s[0].toUpperCase() + s.substr(1);
	return s;
}

function updateModel(snapshot)
{
	$('#model').html("Model " + snapshot.modelName);
}

function updateBatteryRemaining(snapshot)
{
	$('#battery-remaining').html('
' + snapshot.batteryRemaining * 100 + ' %Battery remaining
');
}

function updateLoad(snapshot)
{
	$('#load').html('
' + snapshot.load + ' WLoad
');
}

function updateRemainingRuntime(snapshot)
{
	$('#remaining-runtime').html('
' + snapshot.remainingRuntime + ' min.Remaining runtime
');
}

function updateUtilityVoltage(snapshot)
{
	$('#utility-voltage').html('
' + snapshot.utilityVoltage + ' VUtility voltage
');
}

function getDefaultChartOptions(data)
{
	return {
		xAxis: {
			labels: {
				formatter: function() {
					return humanizeDuration(this.value);
				}
			}
		},

		legend: {
			enabled: false
		},

		plotOptions: {
			line: {
				marker: {
					enabled: false
				}
			}
		}
	};
}

function drawBatteryRemainingChart(snapshots)
{
	var data = [];
	_.each(snapshots, function(snapshot)
	{
		data.push([snapshot.duration, snapshot.batteryRemaining]);
	});

	$('#battery-remaining-chart').highcharts($.extend(true, getDefaultChartOptions(data), {
		title: {
			text: "Battery remaining",
		},

		yAxis: {
			tickInterval: 0.20,
			endOnTick: false,
			labels: {
				formatter: function() {
					return (100 * this.value) + "%";
				}
			},
			min: 0,
			max: 1.1
		},

		tooltip: {
			formatter: function() {
				return '' + humanizeDuration(this.x) + ': ' + (100 * this.y) + '%';
			}
		},

		series: [{
			name: "Battery remaining",
			data: data
		}]
	}));
}

function drawLoadChart(snapshots)
{
	var data = [];
	_.each(snapshots, function(snapshot)
	{
		data.push([snapshot.duration, snapshot.load]);
	});

	$('#load-chart').highcharts($.extend(true, getDefaultChartOptions(data), {
		title: {
			text: "Load",
		},

		yAxis: {
			endOnTick: true,
			labels: {
				formatter: function() {
					return this.value + " W";
				}
			},
			min: 0
			// max: 1 * snapshots[0].batteryCapacity
		},

		tooltip: {
			formatter: function() {
				return '' + humanizeDuration(this.x) + ': ' + this.y + ' W';
			}
		},

		series: [{
			name: "Load",
			data: data
		}]
	}));
}

function drawRemainingRuntimeChart(snapshots)
{
	var data = [];
	_.each(snapshots, function(snapshot)
	{
		data.push([snapshot.duration, snapshot.remainingRuntime]);
	});

	$('#remaining-runtime-chart').highcharts($.extend(true, getDefaultChartOptions(data), {
		title: {
			text: "Remaining runtime",
		},

		yAxis: {
			endOnTick: true,
			labels: {
				formatter: function() {
					return (this.value) + " min";
				}
			},
			min: 0
		},

		tooltip: {
			formatter: function() {
				return '' + humanizeDuration(this.x) + ': ' + (this.y) + ' min.';
			}
		},

		series: [{
			name: "Remaining runtime",
			data: data
		}]
	}));
}

function drawUtilityVoltageChart(snapshots)
{
	var data = [];
	_.each(snapshots, function(snapshot)
	{
		data.push([snapshot.duration, snapshot.utilityVoltage]);
	});

	$('#utility-voltage-chart').highcharts($.extend(true, getDefaultChartOptions(data), {
		title: {
			text: "Utility voltage",
		},

		yAxis: {
			endOnTick: true,
			labels: {
				formatter: function() {
					return (this.value) + " min";
				}
			},
			min: 0
		},

		tooltip: {
			formatter: function() {
				return '' + humanizeDuration(this.x) + ': ' + (this.y) + ' min.';
			}
		},

		series: [{
			name: "Utility voltage",
			data: data
		}]
	}));
}

function setMonitoringStartTime()
{
	$('#started').append("Monitoring started ").append($('<time />', {datetime: StartTime}).timeago());
}

function setRevision()
{
	$.get('/REVISION.json', function(revision)
	{
		$('#revision')
			.append("rev. " + revision.hex.short)
			.append(" · ")
			.append($('<time />', {datetime: revision.commit_date.iso8601}).timeago());

		$('.timeago').timeago();
	}, 'json');
}
<commit_msg>Unit fix<commit_after>function update()
{
	$.get('/api/snapshots', function(snapshots)
	{
		if (snapshots === null || snapshots.length == 0)
		{
			return;
		}

		var now = +moment();
		_.each(snapshots, function(snapshot, i)
		{
			snapshots[i].duration = now - +moment(snapshot.timestamp);
		});

		updateModel(snapshots[0]);

		updateBatteryRemaining(snapshots[0]);
		updateLoad(snapshots[0]);
		updateRemainingRuntime(snapshots[0]);
		updateUtilityVoltage(snapshots[0]);

		drawBatteryRemainingChart(snapshots);
		drawLoadChart(snapshots);
		drawRemainingRuntimeChart(snapshots);
		drawUtilityVoltageChart(snapshots);

		$('#last-updated').html('Last updated ').append($('<time />', {datetime: snapshots[0].timestamp}).timeago());
	}, 'json');
}

function humanizeDuration(d)
{
	var s = moment.duration(-d).humanize(true);
	s = s[0].toUpperCase() + s.substr(1);
	return s;
}

function updateModel(snapshot)
{
	$('#model').html("Model " + snapshot.modelName);
}

function updateBatteryRemaining(snapshot)
{
	$('#battery-remaining').html('
' + snapshot.batteryRemaining * 100 + ' %Battery remaining
');
}

function updateLoad(snapshot)
{
	$('#load').html('
' + snapshot.load + ' WLoad
');
}

function updateRemainingRuntime(snapshot)
{
	$('#remaining-runtime').html('
' + snapshot.remainingRuntime + ' min.Remaining runtime
');
}

function updateUtilityVoltage(snapshot)
{
	$('#utility-voltage').html('
' + snapshot.utilityVoltage + ' VUtility voltage
');
}

function getDefaultChartOptions(data)
{
	return {
		xAxis: {
			labels: {
				formatter: function() {
					return humanizeDuration(this.value);
				}
			}
		},

		legend: {
			enabled: false
		},

		plotOptions: {
			line: {
				marker: {
					enabled: false
				}
			}
		}
	};
}

function drawBatteryRemainingChart(snapshots)
{
	var data = [];
	_.each(snapshots, function(snapshot)
	{
		data.push([snapshot.duration, snapshot.batteryRemaining]);
	});

	$('#battery-remaining-chart').highcharts($.extend(true, getDefaultChartOptions(data), {
		title: {
			text: "Battery remaining",
		},

		yAxis: {
			tickInterval: 0.20,
			endOnTick: false,
			labels: {
				formatter: function() {
					return (100 * this.value) + "%";
				}
			},
			min: 0,
			max: 1.1
		},

		tooltip: {
			formatter: function() {
				return '' + humanizeDuration(this.x) + ': ' + (100 * this.y) + '%';
			}
		},

		series: [{
			name: "Battery remaining",
			data: data
		}]
	}));
}

function drawLoadChart(snapshots)
{
	var data = [];
	_.each(snapshots, function(snapshot)
	{
		data.push([snapshot.duration, snapshot.load]);
	});

	$('#load-chart').highcharts($.extend(true, getDefaultChartOptions(data), {
		title: {
			text: "Load",
		},

		yAxis: {
			endOnTick: true,
			labels: {
				formatter: function() {
					return this.value + " W";
				}
			},
			min: 0
			// max: 1 * snapshots[0].batteryCapacity
		},

		tooltip: {
			formatter: function() {
				return '' + humanizeDuration(this.x) + ': ' + this.y + ' W';
			}
		},

		series: [{
			name: "Load",
			data: data
		}]
	}));
}

function drawRemainingRuntimeChart(snapshots)
{
	var data = [];
	_.each(snapshots, function(snapshot)
	{
		data.push([snapshot.duration, snapshot.remainingRuntime]);
	});

	$('#remaining-runtime-chart').highcharts($.extend(true, getDefaultChartOptions(data), {
		title: {
			text: "Remaining runtime",
		},

		yAxis: {
			endOnTick: true,
			labels: {
				formatter: function() {
					return (this.value) + " min";
				}
			},
			min: 0
		},

		tooltip: {
			formatter: function() {
				return '' + humanizeDuration(this.x) + ': ' + (this.y) + ' min.';
			}
		},

		series: [{
			name: "Remaining runtime",
			data: data
		}]
	}));
}

function drawUtilityVoltageChart(snapshots)
{
	var data = [];
	_.each(snapshots, function(snapshot)
	{
		data.push([snapshot.duration, snapshot.utilityVoltage]);
	});

	$('#utility-voltage-chart').highcharts($.extend(true, getDefaultChartOptions(data), {
		title: {
			text: "Utility voltage",
		},

		yAxis: {
			endOnTick: true,
			labels: {
				formatter: function() {
					return (this.value) + " V";
				}
			},
			min: 0
		},

		tooltip: {
			formatter: function() {
				return '' + humanizeDuration(this.x) + ': ' + (this.y) + ' V';
			}
		},

		series: [{
			name: "Utility voltage",
			data: data
		}]
	}));
}

function setMonitoringStartTime()
{
	$('#started').append("Monitoring started ").append($('<time />', {datetime: StartTime}).timeago());
}

function setRevision()
{
	$.get('/REVISION.json', function(revision)
	{
		$('#revision')
			.append("rev. " + revision.hex.short)
			.append(" · ")
			.append($('<time />', {datetime: revision.commit_date.iso8601}).timeago());

		$('.timeago').timeago();
	}, 'json');
}
<|endoftext|>