<commit_before>module.exports = {
  parserOptions: {
    ecmaFeatures: {
      jsx: true
    }
  },
  plugins: ['react'],

  rules: {
    // Prevent missing displayName in a React component definition
    'react/display-name': 1,
    // Forbid certain propTypes
    'react/forbid-prop-types': 1,
    // Enforce boolean attributes notation in JSX
    'react/jsx-boolean-value': 1,
    // Validate closing bracket location in JSX
    'react/jsx-closing-bracket-location': [1, 'after-props'],
    // Enforce or disallow spaces inside of curly braces in JSX attributes
    'react/jsx-curly-spacing': 1,
    // Enforce or disallow spaces around equal signs in JSX attributes
    'react/jsx-equals-spacing': 1,
    // Enforce event handler naming conventions in JSX
    'react/jsx-handler-names': 1,
    // Validate props indentation in JSX
    'react/jsx-indent-props': [1, 4],
    // Validate JSX indentation
    'react/jsx-indent': [1, 2],
    // Validate JSX has key prop when in array or iterator
    'react/jsx-key': 1,
    // Limit maximum of props on a single line in JSX
    'react/jsx-max-props-per-line': 0,
    // Prevent usage of .bind() and arrow functions in JSX props
    'react/jsx-no-bind': 0,
    // Prevent duplicate props in JSX
    'react/jsx-no-duplicate-props': 1,
    // Prevent usage of unwrapped JSX strings
    'react/jsx-no-literals': 0,
    // Disallow undeclared variables in JSX
    'react/jsx-no-undef': 1,
    // Enforce PascalCase for user-defined JSX components
    'react/jsx-pascal-case': 1,
    // Enforce props alphabetical sorting
    'react/jsx-sort-props': 0,
    // Validate spacing before closing bracket in JSX
    'react/jsx-space-before-closing': 1,
    // Prevent React to be incorrectly marked as unused
    'react/jsx-uses-react': 1,
    // Prevent variables used in JSX to be incorrectly marked as unused
    'react/jsx-uses-vars': 1,
    // Prevent usage of dangerous JSX properties
    'react/no-danger': 1,
    // Prevent usage of deprecated methods
    'react/no-deprecated': 1,
    // Prevent usage of setState in componentDidMount
    'react/no-did-mount-set-state': 1,
    // Prevent usage of setState in componentDidUpdate
    'react/no-did-update-set-state': 1,
    // Prevent direct mutation of this.state
    'react/no-direct-mutation-state': 1,
    // Prevent usage of isMounted
    'react/no-is-mounted': 1,
    // Prevent multiple component definition per file
    'react/no-multi-comp': [1, { ignoreStateless: true }],
    // Prevent usage of setState
    'react/no-set-state': 1,
    // Prevent using string references in ref attribute
    'react/no-string-refs': 1,
    // Prevent usage of unknown DOM property
    'react/no-unknown-property': 1,
    // Enforce ES5 or ES6 class for React Components
    'react/prefer-es6-class': 1,
    // Enforce stateless React Components to be written as a pure function
    'react/prefer-stateless-function': 1,
    // Prevent missing props validation in a React component definition
    'react/prop-types': 1,
    // Prevent missing React when using JSX
    'react/react-in-jsx-scope': 1,
    // Restrict file extensions that may be required
    'react/require-extension': 1,
    // Prevent extra closing tags for components without children
    'react/self-closing-comp': 1,
    // Enforce component methods order
    'react/sort-comp': 1,
    // Enforce propTypes declarations alphabetical sorting
    'react/sort-prop-types': [1, {
      callbacksLast: true,
      ignoreCase: true,
      requiredFirst: true
    }],
    // Prevent missing parentheses around multilines JSX
    'react/wrap-multilines': 1
  }
}
<commit_msg>Disable react/prop-types rule<commit_after>module.exports = {
  parserOptions: {
    ecmaFeatures: {
      jsx: true
    }
  },
  plugins: ['react'],

  rules: {
    // Prevent missing displayName in a React component definition
    'react/display-name': 1,
    // Forbid certain propTypes
    'react/forbid-prop-types': 1,
    // Enforce boolean attributes notation in JSX
    'react/jsx-boolean-value': 1,
    // Validate closing bracket location in JSX
    'react/jsx-closing-bracket-location': [1, 'after-props'],
    // Enforce or disallow spaces inside of curly braces in JSX attributes
    'react/jsx-curly-spacing': 1,
    // Enforce or disallow spaces around equal signs in JSX attributes
    'react/jsx-equals-spacing': 1,
    // Enforce event handler naming conventions in JSX
    'react/jsx-handler-names': 1,
    // Validate props indentation in JSX
    'react/jsx-indent-props': [1, 4],
    // Validate JSX indentation
    'react/jsx-indent': [1, 2],
    // Validate JSX has key prop when in array or iterator
    'react/jsx-key': 1,
    // Limit maximum of props on a single line in JSX
    'react/jsx-max-props-per-line': 0,
    // Prevent usage of .bind() and arrow functions in JSX props
    'react/jsx-no-bind': 0,
    // Prevent duplicate props in JSX
    'react/jsx-no-duplicate-props': 1,
    // Prevent usage of unwrapped JSX strings
    'react/jsx-no-literals': 0,
    // Disallow undeclared variables in JSX
    'react/jsx-no-undef': 1,
    // Enforce PascalCase for user-defined JSX components
    'react/jsx-pascal-case': 1,
    // Enforce props alphabetical sorting
    'react/jsx-sort-props': 0,
    // Validate spacing before closing bracket in JSX
    'react/jsx-space-before-closing': 1,
    // Prevent React to be incorrectly marked as unused
    'react/jsx-uses-react': 1,
    // Prevent variables used in JSX to be incorrectly marked as unused
    'react/jsx-uses-vars': 1,
    // Prevent usage of dangerous JSX properties
    'react/no-danger': 1,
    // Prevent usage of deprecated methods
    'react/no-deprecated': 1,
    // Prevent usage of setState in componentDidMount
    'react/no-did-mount-set-state': 1,
    // Prevent usage of setState in componentDidUpdate
    'react/no-did-update-set-state': 1,
    // Prevent direct mutation of this.state
    'react/no-direct-mutation-state': 1,
    // Prevent usage of isMounted
    'react/no-is-mounted': 1,
    // Prevent multiple component definition per file
    'react/no-multi-comp': [1, { ignoreStateless: true }],
    // Prevent usage of setState
    'react/no-set-state': 1,
    // Prevent using string references in ref attribute
    'react/no-string-refs': 1,
    // Prevent usage of unknown DOM property
    'react/no-unknown-property': 1,
    // Enforce ES5 or ES6 class for React Components
    'react/prefer-es6-class': 1,
    // Enforce stateless React Components to be written as a pure function
    'react/prefer-stateless-function': 1,
    // Prevent missing props validation in a React component definition
    'react/prop-types': 0,
    // Prevent missing React when using JSX
    'react/react-in-jsx-scope': 1,
    // Restrict file extensions that may be required
    'react/require-extension': 1,
    // Prevent extra closing tags for components without children
    'react/self-closing-comp': 1,
    // Enforce component methods order
    'react/sort-comp': 1,
    // Enforce propTypes declarations alphabetical sorting
    'react/sort-prop-types': [1, {
      callbacksLast: true,
      ignoreCase: true,
      requiredFirst: true
    }],
    // Prevent missing parentheses around multilines JSX
    'react/wrap-multilines': 1
  }
}
<|endoftext|>


<commit_before>'use strict'
/**
 * Created by tungtouch on 2/9/15.
 */
var redis = require('redis');
var rClient = redis.createClient();

var message = new Buffer("Some bytes hello world bo bo bo world HEHEHEHE ahhaha hohoho hehe ban kinh dai bakbakabk efefe");
var async = require('async');

var max = 200000;

for (var i = 0; i < max; i++) {
    rClient.hset("raw", "data"+i, message, redis.print);
    console.log("Insert Data:", i);
}

console.log("Starting Benchmark!");
<commit_msg>change port 3000<commit_after>'use strict'
/**
 * Created by tungtouch on 2/9/15.
 */
var redis = require('redis');
var rClient = redis.createClient();

var message = new Buffer("Some bytes hello world bo bo bo world HEHEHEHE ahhaha hohoho hehe ban kinh dai bakbakabk efefe");
var async = require('async');

var max = 20000000;

for (var i = 0; i < max; i++) {
    rClient.hset("raw", "data"+i, message, redis.print);
    console.log("Insert Data:", i);
}

console.log("Starting Benchmark!");
<|endoftext|>


<commit_before>const geo = require('../../lib/geo');
const config = require('../../config');
const Event = require('../../models/osdi/event');
const Joi = require('joi');
const _ = require('lodash');
const moment = require('moment-timezone');
const ODATA = require('../../lib/odata');

const OPTS_SCHEMA = Joi.object().keys({
  per_page: Joi.number().integer().min(1).default(config.maxPageSize),
  page: Joi.number().integer().min(0).default(0),
  $filter: Joi.string(),
  $orderby: Joi.string(),
  $top: Joi.number().integer(),
  $inlinecount: Joi.number().integer(),

  // No ODATA standard for geometric search
  distance_postal_code: Joi.string(),
  distance_city: Joi.string(),
  distance_coords: Joi.array().items(Joi.number().required(), Joi.number().required()),
  distance_max: Joi.number().integer()
});

const get = function (opts, next) {
  Joi.validate(opts.query, OPTS_SCHEMA, function (err, query) {
    if (err) handleError(next, 'validating', err);
    const searchFilter = ODATA.createFilter(query.$filter);
    const distanceFilter = createProximityFilter(
      'location.location',
       query
    );
    const filter = _.merge(searchFilter, distanceFilter);
    const orderBy = ODATA.createOrderBy(query.$orderby);
    console.log(`mongo db filter = ${JSON.stringify(filter)} orderBy = ${JSON.stringify(orderBy)}`);
    Event.count(filter)
      .exec(function (err, count) {
        if (err) handleError(next, 'counting events', err);

        Event.find(filter)
          .sort(orderBy)
          .limit(query.per_page)
          .skip(query.per_page * query.page)
          .exec(function (err, osdiEvents) {
            if (err) handleError(next, 'finding events', err);
            const renderedEvents = osdiEvents.map(render);
            const response = {
              total_pages: Math.ceil(count / query.per_page),
              per_page: query.per_page,
              page: query.page,
              total_records: count,
              _embedded: {
                'osdi:events': renderedEvents
              }
            };
            next(null, response);
          });
      });
  });
};

const getOne = function (opts, next) {
  Event.count(opts.params)
    .exec(function (err, count) {
      if (err) handleError(next, 'counting event', err);

      Event.find(opts.params)
        .exec(function (err, osdiEvent) {
          if (err) handleError(next, 'finding event', err);
          next(null, render(osdiEvent));
        });
    });
};

const render = function (input) {
  const formatByTimezone = function (date, tz) {
    if (date) {
      var utcDate = moment.tz(date, 'UTC');
      if (tz) {
        return utcDate.tz(tz).format();
      } else {
        return utcDate.format();
      }
    } else {
      return undefined;
    }
  };

  const event = input.toJSON();
  const tz = event.timezone;
  event.start_date = formatByTimezone(event.start_date, tz);
  event.end_date = formatByTimezone(event.end_date, tz);
  delete event.timezone;
  return event;
};

const create = {
  validate: {
    payload: {
      identifiers: [Joi.string()],
      origin_system: Joi.string(),
      // name of the event for administrative display
      name: Joi.string(),
      // title of event for public display
      title: Joi.string().required(),
      // may contain text and/or HTML
      description: Joi.string().required(),
      // text-only, single paragraph. For listing pages with not enough room for description
      summary: Joi.string(),
      browser_url: Joi.string(),
      // whether event requires tickets or is open RSVP
      type: Joi.string().valid('ticketed', 'open'),
      featured_image_url: Joi.string(),
      total_accepted: Joi.number(),
      status: Joi.string().valid('confirmed', 'tentatives', 'cancelled'),
      // instructions for event shown after people have RSVPed. Text and/or HTML
      instructions: Joi.string(),
      start_date: Joi.date(),
      end_date: Joi.date(),
      add_day_date: Joi.date(),
      add_day: Joi.boolean(),
      capacity: Joi.number(),
      guests_can_invite_others: Joi.boolean(),
      facebookLink: Joi.string(),
      date: Joi.date(),
      loc: Joi.string()
    }
  },
  handler: function (req, reply) {
    return new Event(req.payload).save()
      .then(function (e) {
        reply(e);
      })
      .catch(function (err) {
        console.log('err', err);
        throw new Error(err);
      });
  }
};

const createProximityFilter = function (fieldName, query) {
  if (!query) return {};

  const maxDistance = query.distance_max;
  let coord = query.distance_coords;
  const postalCode = query.distance_postal_code;
  let city = query.distance_city;

  if (!coord) {
    if (postalCode) {
      coord = geo.postalCodeToCoords(postalCode);
    }

    if (city) {
      coord = geo.cityToCoords(city);
    }
  }
  const filter = {};
  if (fieldName && coord && maxDistance) {
    filter[fieldName] = {
      $near: {
        $geometry: {
          type: 'Point',
          coordinates: [coord[0], coord[1]]
        },
        $maxDistance: maxDistance
      }
    };
  }
  return filter;
};

const handleError = function (next, str, err) {
  console.log(str, err);
  next(err);
};

exports.create = create;
exports.get = get;
exports.getOne = getOne;

// visible for testing
exports.createProximityFilter = createProximityFilter;
exports.render = render;
<commit_msg>fix bug (#87)<commit_after>const geo = require('../../lib/geo');
const config = require('../../config');
const Event = require('../../models/osdi/event');
const Joi = require('joi');
const _ = require('lodash');
const moment = require('moment-timezone');
const ODATA = require('../../lib/odata');

const OPTS_SCHEMA = Joi.object().keys({
  per_page: Joi.number().integer().min(1).default(config.maxPageSize),
  page: Joi.number().integer().min(0).default(0),
  $filter: Joi.string(),
  $orderby: Joi.string(),
  $top: Joi.number().integer(),
  $inlinecount: Joi.number().integer(),

  // No ODATA standard for geometric search
  distance_postal_code: Joi.string(),
  distance_city: Joi.string(),
  distance_coords: Joi.array().items(Joi.number().required(), Joi.number().required()),
  distance_max: Joi.number().integer()
});

const get = function (opts, next) {
  Joi.validate(opts.query, OPTS_SCHEMA, function (err, query) {
    if (err) handleError(next, 'validating', err);
    const searchFilter = ODATA.createFilter(query.$filter);
    const distanceFilter = createProximityFilter(
      'location.location',
       query
    );
    const filter = _.merge(searchFilter, distanceFilter);
    const orderBy = ODATA.createOrderBy(query.$orderby);
    console.log(`mongo db filter = ${JSON.stringify(filter)} orderBy = ${JSON.stringify(orderBy)}`);
    Event.count(filter)
      .exec(function (err, count) {
        if (err) handleError(next, 'counting events', err);

        Event.find(filter)
          .sort(orderBy)
          .limit(query.per_page)
          .skip(query.per_page * query.page)
          .exec(function (err, osdiEvents) {
            if (err) handleError(next, 'finding events', err);
            const renderedEvents = osdiEvents.map(render);
            const response = {
              total_pages: Math.ceil(count / query.per_page),
              per_page: query.per_page,
              page: query.page,
              total_records: count,
              _embedded: {
                'osdi:events': renderedEvents
              }
            };
            next(null, response);
          });
      });
  });
};

const getOne = function (opts, next) {
  Event.count(opts.params)
    .exec(function (err, count) {
      if (err) handleError(next, 'counting event', err);

      Event.find(opts.params)
        .exec(function (err, osdiEvent) {
          if (err) handleError(next, 'finding event', err);
          next(null, render(osdiEvent));
        });
    });
};

const render = function (input) {
  const formatByTimezone = function (date, tz) {
    if (date) {
      var utcDate = moment.tz(date, 'UTC');
      if (tz) {
        return utcDate.tz(tz).format();
      } else {
        return utcDate.format();
      }
    } else {
      return undefined;
    }
  };

  const event = input;
  const tz = event.timezone;
  event.start_date = formatByTimezone(event.start_date, tz);
  event.end_date = formatByTimezone(event.end_date, tz);
  delete event.timezone;
  return event;
};

const create = {
  validate: {
    payload: {
      identifiers: [Joi.string()],
      origin_system: Joi.string(),
      // name of the event for administrative display
      name: Joi.string(),
      // title of event for public display
      title: Joi.string().required(),
      // may contain text and/or HTML
      description: Joi.string().required(),
      // text-only, single paragraph. For listing pages with not enough room for description
      summary: Joi.string(),
      browser_url: Joi.string(),
      // whether event requires tickets or is open RSVP
      type: Joi.string().valid('ticketed', 'open'),
      featured_image_url: Joi.string(),
      total_accepted: Joi.number(),
      status: Joi.string().valid('confirmed', 'tentatives', 'cancelled'),
      // instructions for event shown after people have RSVPed. Text and/or HTML
      instructions: Joi.string(),
      start_date: Joi.date(),
      end_date: Joi.date(),
      add_day_date: Joi.date(),
      add_day: Joi.boolean(),
      capacity: Joi.number(),
      guests_can_invite_others: Joi.boolean(),
      facebookLink: Joi.string(),
      date: Joi.date(),
      loc: Joi.string()
    }
  },
  handler: function (req, reply) {
    return new Event(req.payload).save()
      .then(function (e) {
        reply(e);
      })
      .catch(function (err) {
        console.log('err', err);
        throw new Error(err);
      });
  }
};

const createProximityFilter = function (fieldName, query) {
  if (!query) return {};

  const maxDistance = query.distance_max;
  let coord = query.distance_coords;
  const postalCode = query.distance_postal_code;
  let city = query.distance_city;

  if (!coord) {
    if (postalCode) {
      coord = geo.postalCodeToCoords(postalCode);
    }

    if (city) {
      coord = geo.cityToCoords(city);
    }
  }
  const filter = {};
  if (fieldName && coord && maxDistance) {
    filter[fieldName] = {
      $near: {
        $geometry: {
          type: 'Point',
          coordinates: [coord[0], coord[1]]
        },
        $maxDistance: maxDistance
      }
    };
  }
  return filter;
};

const handleError = function (next, str, err) {
  console.log(str, err);
  next(err);
};

exports.create = create;
exports.get = get;
exports.getOne = getOne;

// visible for testing
exports.createProximityFilter = createProximityFilter;
exports.render = render;
<|endoftext|>


<commit_before>/*jslint node:true*/
"use strict";
//-----------------------------------------------------------------------------
//									                  REQUIRES
//-----------------------------------------------------------------------------
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -REQUIRES
var express = require('express'),
os = require('os'),
router = express.Router(),
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CONFIG
GLOBAL = require('../../config/GLOBAL');
//-----------------------------------------------------------------------------
//									                  DECLARATIONS
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//									                  PROGRAM
//-----------------------------------------------------------------------------
router.get('/', function (req, res) {

  var nbCPU = os.cpus().length;
  var loadRAM = 1.0 * os.freemem() / os.totalmem() * 100;
  var loadCPU = [];
  var loadavg = os.loadavg();
  var hostname = os.hostname();
  var type = os.type();
  var platform = os.platform();
  var arch = os.arch();

  for (var i = 0; i < loadavg.length; i++) {
    loadCPU.push(parseFloat((1.0 * loadavg[i] / nbCPU * 100).toFixed(2)));
  }

  var data = {
    "hostname": hostname,
    "type": type,
    "platform": platform,
    "arch": arch,
    "nbCPU": nbCPU,
    "loadCPU": loadCPU,
    "loadavg": loadavg,
    "loadRAM": parseFloat(loadRAM.toFixed(2)),
  };

  var d = new Date();
  data.UTCdate = d.toISOString();
  console.log(platform);
  if (platform === "linux") {

    res.render('index', {
      scripts: [
        GLOBAL.SCRIPTS.JQUERY,
        GLOBAL.SCRIPTS.BOOTSTRAP
      ],
      links: [
        {rel: 'stylesheet', href: GLOBAL.LINKS.BOOTSTRAP},
        {rel: 'stylesheet', href: '/css/index.css'}
      ],
      data: data
    });
  } else {
    var wincpu = require('windows-cpu');
    wincpu.totalLoad(function(error, results) {
      if(error) {
        return console.log(error);
      } else {
        data.wincpu = results;
      }

      res.render('index', {
        scripts: [
          GLOBAL.SCRIPTS.JQUERY,
          GLOBAL.SCRIPTS.BOOTSTRAP
        ],
        links: [
          {rel: 'stylesheet', href: GLOBAL.LINKS.BOOTSTRAP},
          {rel: 'stylesheet', href: '/css/index.css'}
        ],
        data: data
      });

    });

  }

});
//-----------------------------------------------------------------------------
//									                  EXPORTS
//-----------------------------------------------------------------------------
module.exports = router;
//-----------------------------------------------------------------------------
//									                  END
//-----------------------------------------------------------------------------<commit_msg>roll back<commit_after>/*jslint node:true*/
"use strict";
//-----------------------------------------------------------------------------
//									                  REQUIRES
//-----------------------------------------------------------------------------
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -REQUIRES
var express = require('express'),
os = require('os'),
router = express.Router(),
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CONFIG
GLOBAL = require('../../config/GLOBAL');
//-----------------------------------------------------------------------------
//									                  DECLARATIONS
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//									                  PROGRAM
//-----------------------------------------------------------------------------
router.get('/', function (req, res) {

  var nbCPU = os.cpus().length;
  var loadRAM = 1.0 * os.freemem() / os.totalmem() * 100;
  var loadCPU = [];
  var loadavg = os.loadavg();
  var hostname = os.hostname();
  var type = os.type();
  var platform = os.platform();
  var arch = os.arch();

  for (var i = 0; i < loadavg.length; i++) {
    loadCPU.push(parseFloat((1.0 * loadavg[i] / nbCPU * 100).toFixed(2)));
  }

  var data = {
    "hostname": hostname,
    "type": type,
    "platform": platform,
    "arch": arch,
    "nbCPU": nbCPU,
    "loadCPU": loadCPU,
    "loadavg": loadavg,
    "loadRAM": parseFloat(loadRAM.toFixed(2)),
  };

  var d = new Date();
  data.UTCdate = d.toISOString();

  res.render('index', {
    scripts: [
      GLOBAL.SCRIPTS.JQUERY,
      GLOBAL.SCRIPTS.BOOTSTRAP
    ],
    links: [
      {rel: 'stylesheet', href: GLOBAL.LINKS.BOOTSTRAP},
      {rel: 'stylesheet', href: '/css/index.css'}
    ],
    data: data
  });
});
//-----------------------------------------------------------------------------
//									                  EXPORTS
//-----------------------------------------------------------------------------
module.exports = router;
//-----------------------------------------------------------------------------
//									                  END
//-----------------------------------------------------------------------------<|endoftext|>


<commit_before>/* rider.js
 * The Line Rider ragdoll entity. Has limbs and physics and stuff.
 */

/*eslint no-multi-spaces: 0 comma-spacing: 0*/
/*eslint no-loop-func: 0*/
'use strict';

var clone = require('clone');

var {
  Point,
  Stick,
  BindStick,
  RepelStick,
  ScarfStick,
  ClockwiseCrashJoint
} = require('./entities');

// I should figure out a way to generalize bodies
const
  // enum
  STICK = 0,
  BIND_STICK = 1,
  REPEL_STICK = 2,
  // physics
  ITERATE = 6,
  GRAVITY = { x: 0, y: 0.175 },
  ENDURANCE = 0.057,
  VX_INIT = 0.4,
  VY_INIT = 0,
  SCARF_FLUTTER_INTENSITY = 0.2,
  SPEED_THRESHOLD_FLUTTER = 125, // as this gets smaller, the scarf intensifies faster while speed increases
  // points
  PEG      = { id: 0 , xInit: 0    , yInit: 0    , friction: 0.8 },
  TAIL     = { id: 1 , xInit: 0    , yInit: 5    , friction: 0   },
  NOSE     = { id: 2 , xInit: 15   , yInit: 5    , friction: 0   },
  STRING   = { id: 3 , xInit: 17.5 , yInit: 0    , friction: 0   },
  BUTT     = { id: 4 , xInit: 5    , yInit: 0    , friction: 0.8 },
  SHOULDER = { id: 5 , xInit: 5    , yInit: -5.5 , friction: 0.8 },
  LHAND    = { id: 6 , xInit: 11.5 , yInit: -5   , friction: 0.1 },
  RHAND    = { id: 7 , xInit: 11.5 , yInit: -5   , friction: 0.1 },
  LFOOT    = { id: 8 , xInit: 10   , yInit: 5    , friction: 0   },
  RFOOT    = { id: 9 , xInit: 10   , yInit: 5    , friction: 0   },
  POINTS = [ PEG, TAIL, NOSE, STRING, BUTT, SHOULDER, LHAND, RHAND, LFOOT, RFOOT ],
  // constraints
  PEG_TAIL         = { id: 0  , p: PEG      , q: TAIL   , type: STICK       },
  TAIL_NOSE        = { id: 1  , p: TAIL     , q: NOSE   , type: STICK       },
  NOSE_STRING      = { id: 2  , p: NOSE     , q: STRING , type: STICK       },
  STRING_PEG       = { id: 3  , p: STRING   , q: PEG    , type: STICK       },
  PEG_NOSE         = { id: 4  , p: PEG      , q: NOSE   , type: STICK       },
  STRING_TAIL      = { id: 5  , p: STRING   , q: TAIL   , type: STICK       },
  PEG_BUTT         = { id: 6  , p: PEG      , q: BUTT   , type: BIND_STICK  },
  TAIL_BUTT        = { id: 7  , p: TAIL     , q: BUTT   , type: BIND_STICK  },
  NOSE_BUTT        = { id: 8  , p: NOSE     , q: BUTT   , type: BIND_STICK  },
  SHOULDER_BUTT    = { id: 9  , p: SHOULDER , q: BUTT   , type: STICK       },
  SHOULDER_LHAND   = { id: 10 , p: SHOULDER , q: LHAND  , type: STICK       },
  SHOULDER_RHAND   = { id: 11 , p: SHOULDER , q: RHAND  , type: STICK       },
  BUTT_LFOOT       = { id: 12 , p: BUTT     , q: LFOOT  , type: STICK       },
  BUTT_RFOOT       = { id: 13 , p: BUTT     , q: RFOOT  , type: STICK       },
  SHOULDER_RHAND_2 = { id: 14 , p: SHOULDER , q: RHAND  , type: STICK       }, // DUPLICATE!
  SHOULDER_PEG     = { id: 15 , p: SHOULDER , q: PEG    , type: BIND_STICK  },
  STRING_LHAND     = { id: 16 , p: STRING   , q: LHAND  , type: BIND_STICK  },
  STRING_RHAND     = { id: 17 , p: STRING   , q: RHAND  , type: BIND_STICK  },
  LFOOT_NOSE       = { id: 18 , p: LFOOT    , q: NOSE   , type: BIND_STICK  },
  RFOOT_NOSE       = { id: 19 , p: RFOOT    , q: NOSE   , type: BIND_STICK  },
  SHOULDER_LFOOT   = { id: 20 , p: SHOULDER , q: LFOOT  , type: REPEL_STICK },
  SHOULDER_RFOOT   = { id: 21 , p: SHOULDER , q: RFOOT  , type: REPEL_STICK },
  CONSTRAINTS = [
    PEG_TAIL, TAIL_NOSE, NOSE_STRING, STRING_PEG, PEG_NOSE, STRING_TAIL,
    PEG_BUTT, TAIL_BUTT, NOSE_BUTT,
    SHOULDER_BUTT, SHOULDER_LHAND, SHOULDER_RHAND, BUTT_LFOOT, BUTT_RFOOT, SHOULDER_RHAND_2,
    SHOULDER_PEG, STRING_LHAND, STRING_RHAND, LFOOT_NOSE, RFOOT_NOSE,
    SHOULDER_LFOOT, SHOULDER_RFOOT
  ],
  // body parts
  BODY_PARTS = [
    { name: 'sled'     , p: PEG      , q: STRING   },
    { name: 'body'     , p: BUTT     , q: SHOULDER },
    { name: 'leftArm' , p: SHOULDER , q: LHAND    },
    { name: 'rightArm'  , p: SHOULDER , q: RHAND    },
    { name: 'leftLeg' , p: BUTT     , q: LFOOT    },
    { name: 'rightLeg'  , p: BUTT     , q: RFOOT    }
  ],
  // scarf
  SCARF = {
    airFriction: 0.85,
    p: SHOULDER,
    numSegments: 7,
    segmentLength: 2
  };

// var oldCollisions = [];

/* Rider
 * - creates a new rider at (x,y) and gives the rider velocity (vx, vy)
 *
 * public:
 * - crashed
 * - bodyParts
 * - step(collideFn(p, [debugHandler(line, lineID)]), [gravity])
 * - clone
 * - states < for debugging
 *
 * private:
 * - points
 * - constraints
 * - scarfPoints
 * - scarfConstraints
 */
class Rider {
  constructor(x, y, vx = VX_INIT, vy = VY_INIT, debug = false) {
    this.debug = debug;
    this.crashed = false;
    this.sledBroken = false;

    this.makePoints();
    this.makeConstraints();
    this.makeScarf();
    this.makeJoints();

    this.initPosAndVel(x, y, vx, vy);
  }

  makePoints() {
    this.points = POINTS.map( p =>
      new Point(p.xInit, p.yInit, p.friction)
    );
  }

  makeConstraints() {
    this.constraints = CONSTRAINTS.map( c => {
      let p = this.points[c.p.id];
      let q = this.points[c.q.id];
      switch(c.type) {
        case STICK:
          return new Stick(p, q);
        case BIND_STICK:
          return new BindStick(p, q, ENDURANCE);
        case REPEL_STICK:
          let stick = new RepelStick(p, q);
          stick.restLength *= 0.5;
          return stick;
      }
      throw new Error('Unknown constraint type');
    });
  }

  makeScarf() {
    this.scarfPoints = [];
    this.scarfConstraints = [];

    for (let i = 0; i < SCARF.numSegments; i++) {
      let p = (i === 0) ? this.points[SHOULDER.id] : this.scarfPoints[i-1];
      let q = new Point(p.x - SCARF.segmentLength, p.y, 0, SCARF.airFriction);
      this.scarfPoints.push(q);
      this.scarfConstraints.push(new ScarfStick(p, q));
    }
  }

  makeJoints() {
    let pegTail = this.constraints[PEG_TAIL.id];
    let stringPeg = this.constraints[STRING_PEG.id];
    let shoulderButt = this.constraints[SHOULDER_BUTT.id];
    this.joints = [
      new ClockwiseCrashJoint(pegTail, stringPeg),
      new ClockwiseCrashJoint(shoulderButt, stringPeg)
    ];
  }

  initPosAndVel(x, y, vx, vy) {
    this.points.concat(this.scarfPoints).forEach(p => {
      p.x += x;
      p.y += y;
      p.vx = p.x - vx;
      p.vy = p.y - vy;
    });
  }

  flutterScarf() {
    let shoulder = this.points[SHOULDER.id];
    let points = this.scarfPoints;
    // deterministic psuedo-random number
    let p = points[this.scarfPoints.length-1];
    let speed = Math.sqrt(shoulder.dx * shoulder.dx + shoulder.dy * shoulder.dy);
    let randMag = (p.x * p.y) % 1;
    let randAng = (p.x + p.y) % 1;
    speed *= 1 - Math.pow(2, -speed / SPEED_THRESHOLD_FLUTTER);
    randMag *= SCARF_FLUTTER_INTENSITY * speed;
    randAng *= 2 * Math.PI;
    points[1].x += randMag * Math.cos(randAng);
    points[1].y += randMag * Math.sin(randAng);
  }

  // TODO: make this more efficient
  clone() {
    let copy = clone(this);
    delete copy.states;
    return copy;
  }

  get bodyParts() {
    let getPosition = (p, q) => {
      return {
        x: p.x,
        y: p.y,
        angle: Math.atan2(q.y - p.y, q.x - p.x)
      };
    };

    let bodyParts = {};
    BODY_PARTS.forEach(bodyPart => {
      let p = this.points[bodyPart.p.id];
      let q = this.points[bodyPart.q.id];
      bodyParts[bodyPart.name] = getPosition(p, q);
    });

    bodyParts.scarf = [];
    for (let i = 0; i < this.scarfConstraints.length; i++) {
      let p = (i === 0) ? this.points[SHOULDER.id] : this.scarfPoints[i-1];
      let q = this.scarfPoints[i];
      bodyParts.scarf.push(getPosition(p, q));
    }
    return bodyParts;
  }

  step(lineStore, gravity) {
    // var collisions = [];

    gravity = gravity || GRAVITY;

    // this.debugResetSavedStates();
    // this.debugSaveState('start');

    this.points.forEach( p => p.step(gravity) );

    // this.debugSaveState('points stepped', {
    //   points: this.points.map( (p, i) => i )
    // });

    this.flutterScarf();

    // this.debugSaveState('pre-iterate (scarf fluttered)', {
    //   scarfPoints: this.scarfPoints.map( (p, i) => i )
    // });

    this.scarfPoints.forEach( p => p.step(gravity) );

    for (let i = 0; i < ITERATE; i++) {

      this.constraints.forEach( (c, j) => {
        let alreadyCrashed = this.crashed;
        this.crashed = c.resolve(this.crashed);

        // this.debugSaveState(i.toString() + ': resolved constraint ' + j, {
        //   constraints: [j]
        // });

        if (!alreadyCrashed && this.crashed) {
          console.log('craSHED!12UI4!!~');
          if (this.debug) {
            // console.log(this.states);
          }

        }
      });

      this.points.forEach( p => lineStore.getSolidLinesAt(p.x, p.y).forEach( line => {
        line.collide(p);
        // if (this.debug) {
        //   collisions.push('iter ' + i.toString() + ', point ' + p.id + ', line ' + line.id);
        // }
      } ) );
    }

    this.scarfConstraints.forEach( c => c.resolve() );

    // this.debugSaveState('end (scarf resolved)', {
    //   scarfConstraints: this.scarfConstraints.map( (c, i) => i )
    // });
    // oldCollisions = collisions;

    this.joints.forEach( (joint, i) => {
      let alreadyCrashed = this.crashed;
      this.crashed = joint.resolve(this.crashed);
      if (!alreadyCrashed && this.crashed) {
        if (i === 0) {
          this.sledBroken = true;
          console.log('crashed because the sled broke!!2e1r');
        } else {
          console.log('bosh attempted The Cripple. now he crashed !@#$');
        }
      }
    });
  }

  // debugResetSavedStates() {
  //   if (this.debug) {
  //     this.states = [];
  //   }
  // }

  // // when you need to debug the debugger.......
  // debugSaveState(description, changed) {
  //   if (this.debug) {
  //     // console.log(description, changed);
  //     changed = changed || {};

  //     let points = clone(this.points);

  //     let state = {
  //       points: points,
  //       crashed: this.crashed,
  //       constraints: []
  //     };
  //     // console.log(state);

  //     let lines = changed.lines;
  //     delete changed.lines;
  //     _.map(changed, (entityIDs, entitiesName) => {
  //       changed[entitiesName] = entityIDs.map( i => state[entitiesName][i] );
  //     });
  //     this.states.push({
  //       description: description,
  //       changed: _.assign({
  //         points: [],
  //         constraints: [],
  //         scarfPoints: [],
  //         scarfConstraints: [],
  //         lines: lines || []
  //       }, changed),
  //       state: state
  //     });
  //   }
  // }

}

module.exports = Rider;
<commit_msg>refactor debugging + replace for loops with _.forEach<commit_after>/* rider.js
 * The Line Rider ragdoll entity. Has limbs and physics and stuff.
 */

/*eslint no-multi-spaces: 0 comma-spacing: 0*/
'use strict';

var _ = require('lodash');
var clone = require('clone');

var {
  Point,
  Stick,
  BindStick,
  RepelStick,
  ScarfStick,
  ClockwiseCrashJoint
} = require('./entities');

// I should figure out a way to generalize bodies
const
  // enum
  STICK = 0,
  BIND_STICK = 1,
  REPEL_STICK = 2,
  // physics
  ITERATE = 6,
  GRAVITY = { x: 0, y: 0.175 },
  ENDURANCE = 0.057,
  VX_INIT = 0.4,
  VY_INIT = 0,
  SCARF_FLUTTER_INTENSITY = 0.2,
  SPEED_THRESHOLD_FLUTTER = 125, // as this gets smaller, the scarf intensifies faster while speed increases
  // points
  PEG      = { id: 0 , xInit: 0    , yInit: 0    , friction: 0.8 },
  TAIL     = { id: 1 , xInit: 0    , yInit: 5    , friction: 0   },
  NOSE     = { id: 2 , xInit: 15   , yInit: 5    , friction: 0   },
  STRING   = { id: 3 , xInit: 17.5 , yInit: 0    , friction: 0   },
  BUTT     = { id: 4 , xInit: 5    , yInit: 0    , friction: 0.8 },
  SHOULDER = { id: 5 , xInit: 5    , yInit: -5.5 , friction: 0.8 },
  LHAND    = { id: 6 , xInit: 11.5 , yInit: -5   , friction: 0.1 },
  RHAND    = { id: 7 , xInit: 11.5 , yInit: -5   , friction: 0.1 },
  LFOOT    = { id: 8 , xInit: 10   , yInit: 5    , friction: 0   },
  RFOOT    = { id: 9 , xInit: 10   , yInit: 5    , friction: 0   },
  POINTS = [ PEG, TAIL, NOSE, STRING, BUTT, SHOULDER, LHAND, RHAND, LFOOT, RFOOT ],
  // constraints
  PEG_TAIL         = { id: 0  , p: PEG      , q: TAIL   , type: STICK       },
  TAIL_NOSE        = { id: 1  , p: TAIL     , q: NOSE   , type: STICK       },
  NOSE_STRING      = { id: 2  , p: NOSE     , q: STRING , type: STICK       },
  STRING_PEG       = { id: 3  , p: STRING   , q: PEG    , type: STICK       },
  PEG_NOSE         = { id: 4  , p: PEG      , q: NOSE   , type: STICK       },
  STRING_TAIL      = { id: 5  , p: STRING   , q: TAIL   , type: STICK       },
  PEG_BUTT         = { id: 6  , p: PEG      , q: BUTT   , type: BIND_STICK  },
  TAIL_BUTT        = { id: 7  , p: TAIL     , q: BUTT   , type: BIND_STICK  },
  NOSE_BUTT        = { id: 8  , p: NOSE     , q: BUTT   , type: BIND_STICK  },
  SHOULDER_BUTT    = { id: 9  , p: SHOULDER , q: BUTT   , type: STICK       },
  SHOULDER_LHAND   = { id: 10 , p: SHOULDER , q: LHAND  , type: STICK       },
  SHOULDER_RHAND   = { id: 11 , p: SHOULDER , q: RHAND  , type: STICK       },
  BUTT_LFOOT       = { id: 12 , p: BUTT     , q: LFOOT  , type: STICK       },
  BUTT_RFOOT       = { id: 13 , p: BUTT     , q: RFOOT  , type: STICK       },
  SHOULDER_RHAND_2 = { id: 14 , p: SHOULDER , q: RHAND  , type: STICK       }, // DUPLICATE!
  SHOULDER_PEG     = { id: 15 , p: SHOULDER , q: PEG    , type: BIND_STICK  },
  STRING_LHAND     = { id: 16 , p: STRING   , q: LHAND  , type: BIND_STICK  },
  STRING_RHAND     = { id: 17 , p: STRING   , q: RHAND  , type: BIND_STICK  },
  LFOOT_NOSE       = { id: 18 , p: LFOOT    , q: NOSE   , type: BIND_STICK  },
  RFOOT_NOSE       = { id: 19 , p: RFOOT    , q: NOSE   , type: BIND_STICK  },
  SHOULDER_LFOOT   = { id: 20 , p: SHOULDER , q: LFOOT  , type: REPEL_STICK },
  SHOULDER_RFOOT   = { id: 21 , p: SHOULDER , q: RFOOT  , type: REPEL_STICK },
  CONSTRAINTS = [
    PEG_TAIL, TAIL_NOSE, NOSE_STRING, STRING_PEG, PEG_NOSE, STRING_TAIL,
    PEG_BUTT, TAIL_BUTT, NOSE_BUTT,
    SHOULDER_BUTT, SHOULDER_LHAND, SHOULDER_RHAND, BUTT_LFOOT, BUTT_RFOOT, SHOULDER_RHAND_2,
    SHOULDER_PEG, STRING_LHAND, STRING_RHAND, LFOOT_NOSE, RFOOT_NOSE,
    SHOULDER_LFOOT, SHOULDER_RFOOT
  ],
  // body parts
  BODY_PARTS = [
    { name: 'sled'     , p: PEG      , q: STRING   },
    { name: 'body'     , p: BUTT     , q: SHOULDER },
    { name: 'leftArm' , p: SHOULDER , q: LHAND    },
    { name: 'rightArm'  , p: SHOULDER , q: RHAND    },
    { name: 'leftLeg' , p: BUTT     , q: LFOOT    },
    { name: 'rightLeg'  , p: BUTT     , q: RFOOT    }
  ],
  // scarf
  SCARF = {
    airFriction: 0.85,
    p: SHOULDER,
    numSegments: 7,
    segmentLength: 2
  };

// var oldCollisions = [];

/* Rider
 * - creates a new rider at (x,y) and gives the rider velocity (vx, vy)
 *
 * public:
 * - crashed
 * - bodyParts
 * - step(collideFn(p, [debugHandler(line, lineID)]), [gravity])
 * - clone
 * - states < for debugging
 *
 * private:
 * - points
 * - constraints
 * - scarfPoints
 * - scarfConstraints
 */
class Rider {
  constructor(x, y, vx = VX_INIT, vy = VY_INIT) {
    this.crashed = false;
    this.sledBroken = false;

    this.makePoints();
    this.makeConstraints();
    this.makeScarf();
    this.makeJoints();

    this.initPosAndVel(x, y, vx, vy);
  }

  makePoints() {
    this.points = POINTS.map( (p, i) => {
      let point = new Point(p.xInit, p.yInit, p.friction);
      point.id = i; // ok sure let's have IDs
      return point;
    });
  }

  makeConstraints() {
    this.constraints = CONSTRAINTS.map( (c, i) => {
      let stick;
      let p = this.points[c.p.id];
      let q = this.points[c.q.id];
      switch(c.type) {
        case STICK:
          stick = new Stick(p, q);
          break;
        case BIND_STICK:
          stick = new BindStick(p, q, ENDURANCE);
          break;
        case REPEL_STICK:
          let stick = new RepelStick(p, q);
          stick.restLength *= 0.5;
          stick = stick;
          break;
        default:
          throw new Error('Unknown constraint type');
      }
      stick.id = i; // ok sure let's have IDs
      return stick;
    });
  }

  makeScarf() {
    this.scarfPoints = [];
    this.scarfConstraints = [];

    for (let i = 0; i < SCARF.numSegments; i++) {
      let p = (i === 0) ? this.points[SHOULDER.id] : this.scarfPoints[i-1];
      let q = new Point(p.x - SCARF.segmentLength, p.y, 0, SCARF.airFriction);
      this.scarfPoints.push(q);
      this.scarfConstraints.push(new ScarfStick(p, q));
    }
  }

  makeJoints() {
    let pegTail = this.constraints[PEG_TAIL.id];
    let stringPeg = this.constraints[STRING_PEG.id];
    let shoulderButt = this.constraints[SHOULDER_BUTT.id];
    this.joints = [
      new ClockwiseCrashJoint(pegTail, stringPeg),
      new ClockwiseCrashJoint(shoulderButt, stringPeg)
    ];
  }

  initPosAndVel(x, y, vx, vy) {
    this.points.concat(this.scarfPoints).forEach(p => {
      p.x += x;
      p.y += y;
      p.vx = p.x - vx;
      p.vy = p.y - vy;
    });
  }

  // TODO: make this more efficient
  clone() {
    let copy = clone(this);
    delete copy.states;
    return copy;
  }

  get bodyParts() {
    let getPosition = (p, q) => {
      return {
        x: p.x,
        y: p.y,
        angle: Math.atan2(q.y - p.y, q.x - p.x)
      };
    };

    let bodyParts = {};
    BODY_PARTS.forEach(bodyPart => {
      let p = this.points[bodyPart.p.id];
      let q = this.points[bodyPart.q.id];
      bodyParts[bodyPart.name] = getPosition(p, q);
    });

    bodyParts.scarf = [];
    for (let i = 0; i < this.scarfConstraints.length; i++) {
      let p = (i === 0) ? this.points[SHOULDER.id] : this.scarfPoints[i-1];
      let q = this.scarfPoints[i];
      bodyParts.scarf.push(getPosition(p, q));
    }
    return bodyParts;
  }

  static getFlutter(base, seed) {
    let speed = Math.sqrt(base.dx * base.dx + base.dy * base.dy);
    let randMag = (seed.x * seed.y) % 1;
    let randAng = (seed.x + seed.y) % 1;
    speed *= 1 - Math.pow(2, -speed / SPEED_THRESHOLD_FLUTTER);
    randMag *= SCARF_FLUTTER_INTENSITY * speed;
    randAng *= 2 * Math.PI;
    return {
      x: randMag * Math.cos(randAng),
      y: randMag * Math.sin(randAng)
    };
  }

  step(lineStore, gravity = GRAVITY) {

    _.forEach(this.points, point =>
      this.stepPoint(point, gravity)
    );

    _.times(ITERATE, i => {
      _.forEach(this.constraints, constraint =>
        this.stepConstraint(constraint, i)
      );
      _.forEach(this.points, point =>
        _.forEach(this.getSolidLines(lineStore, point), line =>
          this.stepCollision(point, line, i)
        )
      );
    });

    this.stepScarf(gravity);

    _.forEach(this.joints, (joint, i) =>
      this.stepJoint(joint, i)
    );
  }

  stepPoint(point, gravity) {
    point.step(gravity);
  }

  stepScarf(gravity) {
    let base = this.points[SHOULDER.id];
    let seed = this.points[this.scarfPoints.length-1];
    let flutter = Rider.getFlutter(base, seed);
    this.scarfPoints[1].x += flutter.x;
    this.scarfPoints[1].y += flutter.y;

    _.forEach(this.scarfPoints, p => p.step(gravity) );
    _.forEach(this.scarfConstraints, c => c.resolve() );
  }

  stepConstraint(constraint, i) {
    this.crashed = constraint.resolve(this.crashed);
  }

  getSolidLines(lineStore, point) {
    return lineStore.getSolidLinesAt(point.x, point.y);
  }

  stepCollision(point, line, i) {
    line.collide(point);
  }

  stepJoint(joint, i) {
    let didCrash = joint.resolve();

    this.crashed = this.crashed || didCrash;
    this.sledBroken = this.sledBroken || i === 0 && didCrash;
  }
}

class DebugRider extends Rider {

  step(lineStore, gravity) {
    // this.initializeDebuggingthing();
    super.step(lineStore, gravity);
  }

  stepPoint(point, gravity) {
    super.stepPoint(point, gravity);
  }

  stepConstraint(constraint, i) {
    let hasCrashed = this.crashed;

    super.stepConstraint(constraint, i);

    if (!hasCrashed && this.crashed) {
      console.log('craSHED!12UI4!!~');
    }
  }

  getSolidLines(lineStore, point) {
    return lineStore.getSolidLinesAt(point.x, point.y, true);
  }

  stepCollision(point, lineData, i) {
    // lineData.cellPos
    super.stepCollision(point, lineData.line, i);
  }

  stepJoint(joint, i) {
    let hasCrashed = this.crashed;

    super.stepJoint(joint, i);

    if (!hasCrashed && this.crashed) {
      if (i === 0) {
        console.log('crashed because the sled broke!!2e1r');
      } else {
        console.log('bosh attempted The Cripple. now he crashed !@#$');
      }
    }

  }
}

module.exports = {Rider, DebugRider};
<|endoftext|>


<commit_before>/* eslint-disable prefer-template, max-len */
import serialize from 'serialize-javascript';

const replaceInline = str => str.replace(/style="([^"]*)"/, '');
export const amp = ({ helmet, cssBundle, cssMarkup, jsBundle, root, initialState }) => `
  <!DOCTYPE html>

      <meta charset="utf-8">

      <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
      <meta http-equiv="x-ua-compatible" content="ie=edge">
      <meta http-equiv="Content-Language" content="de" />
      <link rel="mask-icon" color="#FBA139" href="/logo.svg">
      <link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
      <link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
      <link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
      <link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
      <link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
      <link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
      <link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
      <link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
      <link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
      <link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png">
      <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
      <link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png">
      <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
      <link rel="manifest" href="/manifest.json">
      <meta name="msapplication-TileColor" content="#FBA139">
      <meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
      <meta name="theme-color" content="#FBA139">
      ${helmet.title.toString()}
      ${helmet.meta.toString()}
      ${helmet.link.toString()}

${root ? replaceInline(root) : ''}

`;
export default ({ helmet, cssBundle, cssMarkup, jsBundle, root, initialState }) => `
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta http-equiv="Content-Language" content="de" />
    <link rel="mask-icon" color="#FBA139" href="/logo.svg">
    <link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
    <link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
    <link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
    <link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
    <link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
    <link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
    <link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
    <link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
    <link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png">
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
    <link rel="manifest" href="/manifest.json">
    <meta name="msapplication-TileColor" content="#FBA139">
    <meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
    <meta name="theme-color" content="#FBA139">
    ${helmet.title.toString()}
    ${helmet.meta.toString()}
    ${helmet.link.toString()}
    ${cssBundle ? `<link rel="stylesheet" type="text/css" href="${cssBundle}" media="none" onload="if(media!='all')media='all'">` : ''}
    ${cssBundle ? `<noscript><link rel="stylesheet" href="${cssBundle}"></noscript>` : ''}

${root}

`;
<commit_msg>remove defer<commit_after>/* eslint-disable prefer-template, max-len */
import serialize from 'serialize-javascript';

const replaceInline = str => str.replace(/style="([^"]*)"/, '');
export const amp = ({ helmet, cssBundle, cssMarkup, jsBundle, root, initialState }) => `
  <!DOCTYPE html>

      <meta charset="utf-8">

      <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
      <meta http-equiv="x-ua-compatible" content="ie=edge">
      <meta http-equiv="Content-Language" content="de" />
      <link rel="mask-icon" color="#FBA139" href="/logo.svg">
      <link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
      <link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
      <link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
      <link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
      <link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
      <link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
      <link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
      <link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
      <link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
      <link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png">
      <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
      <link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png">
      <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
      <link rel="manifest" href="/manifest.json">
      <meta name="msapplication-TileColor" content="#FBA139">
      <meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
      <meta name="theme-color" content="#FBA139">
      ${helmet.title.toString()}
      ${helmet.meta.toString()}
      ${helmet.link.toString()}

${root ? replaceInline(root) : ''}

`;
export default ({ helmet, cssBundle, cssMarkup, jsBundle, root, initialState }) => `
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta http-equiv="Content-Language" content="de" />
    <link rel="mask-icon" color="#FBA139" href="/logo.svg">
    <link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
    <link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
    <link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
    <link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
    <link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
    <link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
    <link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
    <link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
    <link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png">
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
    <link rel="manifest" href="/manifest.json">
    <meta name="msapplication-TileColor" content="#FBA139">
    <meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
    <meta name="theme-color" content="#FBA139">
    ${helmet.title.toString()}
    ${helmet.meta.toString()}
    ${helmet.link.toString()}
    ${cssBundle ? `<link rel="stylesheet" type="text/css" href="${cssBundle}" media="none" onload="if(media!='all')media='all'">` : ''}
    ${cssBundle ? `<noscript><link rel="stylesheet" href="${cssBundle}"></noscript>` : ''}

${root}

`;
<|endoftext|>


<commit_before>var globalData = {
    totals: [],
    categories: {}
};

window.onload = function() {
    loadJSONFiles([
        [ 'appsURLs.json', onMostPopularLoaded ],
        [ 'totals.json', onTotalsLoaded ],
        [ 'categories.json', onCategoriesLoaded ]
    ]);
};

function loadJSONFiles(filesList, doneCallback) {

    doneCallback = doneCallback || function() {};

    var filesIter = iterator(filesList);
    var loadNext = function() {

        var nextValue = filesIter.next();

        if(nextValue.done) {
            doneCallback();
        } else {
            var tuple = nextValue.value;
            var request = new XMLHttpRequest();
            var jsonURL = tuple[0];
            var jsonCallback = tuple[1];

            request.open('GET', jsonURL);
            request.responseType = 'text';
            request.onload = function() {

                console.log('loaded', jsonURL);

                var data = JSON.parse(request.response);

                if(jsonCallback) {
                    jsonCallback(data);
                }

                setTimeout(loadNext, 1);
            };

            request.send();
        }
    };

    loadNext();

}

function onMostPopularLoaded(data) {
    console.log('most popular loaded', data.length);
    globalData.mostPopular = data;
}

function onTotalsLoaded(data) {
    console.log('totals loaded', data.length);
    globalData.totals = data;
}

function onCategoriesLoaded(data) {
    console.log('cats loaded', data.length);
    var catJSONs = data.map(function(d) {
        var name = d.split('/').pop();
        return [ 'category-' + name + '.json', function(catData) {
            onCategoryLoaded(name, catData);
        } ];
    });
    console.log(catJSONs);

    globalData.categories = {};

    loadJSONFiles(catJSONs, onAllDataLoaded);

}

function onCategoryLoaded(categoryName, data) {
    console.log('loaded category', categoryName);
    globalData.categories[categoryName] = data.map(function(d) {
        return d.split('=').pop();
    });
}

function* iterator(arr) {
    for(var i = 0; i < arr.length; i++) {
        yield arr[i];
    }
}

function onAllDataLoaded() {

    onDataLoaded(globalData.totals);
    makeCategorisedReport(globalData);
    makeMostPopularReport(globalData);

}

function onDataLoaded(data) {

    var totals = document.getElementById('totals');
    totals.innerHTML = '
' + data.length + ' apps
';

    makeGlobalReport('out', data.slice(0));
    makeAirReport('air', data.slice(0));

}

function makeGlobalReport(tableId, data) {

    data.sort(makeSorter('total'));

    var div = document.getElementById(tableId);
    var out = document.createElement('table');

    var groups = {
        yes: 0,
        maybe: 0,
        unlikely: 0,
        no: 0
    };

    data.forEach(function(app, appIndex) {
        var traits = app.traits;
        traits.sort(makeSorter('amount'));

        // Title
        var trTitle = out.insertRow(-1);
        trTitle.className = 'title';

        var tdCounter = trTitle.insertCell(-1);
        tdCounter.innerHTML = (appIndex + 1);

        // Build up the title:
        var title = app.info !== undefined ? app.info.title : app.name;

        var tdTotal = trTitle.insertCell(-1);
        tdTotal.innerHTML = app.total;

        var tdName = trTitle.insertCell(-1);
        tdName.innerHTML = '
' + title + '
';

        // Details

        var trDetails = out.insertRow(-1);
        trDetails.className = 'details';

        trDetails.insertCell(-1); // empty

        var tdDetails = trDetails.insertCell(-1);
        tdDetails.colSpan = 3;

        tdDetails.innerHTML = '
Play Store: ' + app.name + '
';

        var traitsTable = document.createElement('table');
        traitsTable.className = 'traits';

        traits.forEach(function(trait) {

            var traitRow = traitsTable.insertRow(-1);
            var tdAmount = traitRow.insertCell(-1);
            var tdDesc = traitRow.insertCell(-1);

            tdAmount.innerHTML = trait.amount.toFixed(2);
            tdDesc.innerHTML = trait.reason;

            var hover = trait.files.join('\n');

            traitRow.title = hover;

        });

        tdDetails.appendChild(traitsTable);

        var total = app.total;

        var className = isHTML5(total);

        groups[className]++;

        trTitle.classList.add(className);
        trDetails.classList.add(className);

    });

    // summary - chart with % of html5 likeability
    appendPieChart('#' + div.id, groups);

    div.appendChild(out);

    $('#' + tableId + ' tr.title').on('click', function() {
        $(this).next().toggle();
        this.classList.toggle('open');
    });

}

function findApp(array, pkgName) {
    for(var i = 0; i < array.length; i++) {
        var app = array[i];
        if(app.name === pkgName) {
            return app;
        }
    }
    return null;
}

function isHTML5(total) {

    var className = 'no';

    if(total > 50) {
        className = 'yes';
    } else if(total > 30) {
        className = 'maybe';
    } else if(total > 15) {
        className = 'unlikely';
    }

    return className;
}

function makeAirReport(containerId, data) {
    var airApps = data.filter(function(appInfo) {
        var airTraits = appInfo.traits.filter(function(trait) {
            if(trait.reason === 'air') {
                return trait;
            }
        });
        return airTraits.length > 0;
    });

    var container = document.getElementById(containerId);
    var percentage = (airApps.length * 100.0 / data.length).toFixed(2);

    container.innerHTML = '
' + percentage + '% of ' + data.length + ' apps
';

    var list = document.createElement('ol');
    container.appendChild(list);

    airApps.sort(function(a, b) {
        return a.info.title.toLowerCase() > b.info.title.toLowerCase();
    });

    airApps.forEach(function(app) {
        var li = document.createElement('li');
        li.innerHTML = app.info.title + ' (play store)';
        list.appendChild(li);
    });
}

function makeMostPopularReport(data) {
    // appurls -> get pck name, total has the details

    var outElement = document.getElementById('popular');
    var overview = document.createElement('div');
    var table = document.createElement('table');
    var popular = data.mostPopular;
    var numPopularApps = popular.length;
    var totalApps = data.totals;
    var aggregate = {};

    outElement.appendChild(overview);
    outElement.appendChild(table);

    popular.forEach(function(appUrl) {

        var pkgName = getAppPackageName(appUrl);
        var app = findApp(totalApps, pkgName);

        if(app !== null) {
            var tr = table.insertRow(-1);

            var tdTitle = tr.insertCell(-1);
            tdTitle.innerHTML = '' + pkgName + '';

            var tdHTML5ness = tr.insertCell(-1);
            var html5ness = isHTML5(app.total);
            tdHTML5ness.innerHTML = html5ness;

            if(aggregate[html5ness] === undefined) {
                aggregate[html5ness] = 1;
            } else {
                aggregate[html5ness]++;
            }

        }

    });

    var txtOverview = '
' + numPopularApps + ' apps' + '
';

    for(var k in aggregate) {
        var value = aggregate[k];
        txtOverview += '
' + k + ' ' + (Math.round(value * 10000 / numPopularApps) / 100 ) + '%
';
    }

    overview.innerHTML = txtOverview;

}

function makeCategorisedReport(data) {

    var categories = data.categories;
    var totals = data.totals;
    var categoryBreakdown = document.getElementById('category-breakdown');
    var outputTable = document.createElement('table');
    var results = [];
    var keys = [ 'yes', 'maybe', 'unlikely', 'no' ];

    categoryBreakdown.appendChild(outputTable);

    for(var catName in categories) {

        var catData = categories[catName];
        var groups = {};

        var appsInCategory = totals.filter(function(app) {
            var pkgName = app.name;
            return catData.indexOf(pkgName) !== -1;
        });

        var numApps = appsInCategory.length;

        // Count how many apps fall in each 'html5 likeability' group
        appsInCategory.forEach(function(app) {

            var total = app.total;
            var html5ness = isHTML5(total);

            if(groups[html5ness] === undefined) {
                groups[html5ness] = 0;
            } else {
                groups[html5ness]++;
            }

        });

        var div = document.createElement('div');
        div.id = 'categoryBreakdown-' + catName;

        categoryBreakdown.appendChild(div);

        var h3 = document.createElement('h3');
        h3.innerHTML = catName + ' ' + numApps;
        div.appendChild(h3);

        appendPieChart('#' + div.id, groups);

        var numYes = groups.yes !== undefined ? groups.yes : 0;
        var yesPerc = Math.round(numYes * 10000.0 / appsInCategory.length) / 100;

        results.push({ name: catName, groups: groups, yesPerc: yesPerc, count: appsInCategory.length });

    };

    results.sort(function(a, b) {

        var yesA = a.yesPerc;
        var yesB = b.yesPerc;

        return yesB - yesA;

    });

    var tr = outputTable.insertRow(-1);
    keys.forEach(function(k) {
        var cell = tr.insertCell(-1);
        cell.innerHTML = k;
    });

    results.forEach(function(r) {

        var row = outputTable.insertRow(-1);

        keys.forEach(function(k) {
            var cell = row.insertCell(-1);
            var value = r.groups[k];

            if(value === undefined) {
                value = 0;
            }

            cell.innerHTML = value;
        });

        row.insertCell(-1).innerHTML = r.yesPerc + '%';
        row.insertCell(-1).innerHTML = r.count;

        row.insertCell(-1).innerHTML = r.name;

    });
}

function getAppURL(packageName) {
    return 'https://play.google.com/store/apps/details?id=' + packageName;
}

function getAppPackageName(url) {
    return url.split('=').pop();
}

function makeSorter(propertyName) {
    return function(a, b) {
        var propA = Number(a[propertyName]);
        var propB = Number(b[propertyName]);
        var epsilon = propA - propB;

        if(Math.abs(epsilon) < 0.0001) {
            return 0;
        } else {
            return epsilon > 0 ? -1 : 1;
        }
    };
}

function appendPieChart(selector, values) {

    var data = [];
    var totals = 0;
    for(var k in values) {
        data.push({ label: k, value: values[k] });
        totals += values[k];
    }

    var width = 300;
    var height = 300;

    var radius = Math.min(width, height) / 2;
    var percGraph = 0.5;
    var graphRadius = radius * percGraph;
    var w = width;
    var h = height;

    var color = {
        'yes': '#00aa00',
        'maybe': '#eeff00',
        'unlikely': '#dd9900',
        'no': '#ff0000'
    };

    var vis = d3.select(selector)
        .append("svg:svg")
            .data([data])
            .attr("width", w)
            .attr("height", h)
            .append("svg:g")
                .attr("transform", "translate(" + radius + "," + radius + ")");

    var arc = d3.svg.arc()
        .outerRadius(graphRadius);

    var pie = d3.layout.pie()
        .value(function(d) { return d.value; });

    var arcs = vis.selectAll('g.slice')
        .data(pie)
        .enter()
        .append('svg:g')
        .attr('class', 'slice');

    arcs.append('svg:path')
        .attr('fill', function(d, i) { var label = data[i].label; return color[label]; } )
        .attr('d', arc);

    arcs.append('svg:text')
        .attr('dy', '5px')
        .attr('transform', function(d) {
            var alpha = (d.endAngle - d.startAngle) * 0.5 + d.startAngle;
            var dist = radius * (percGraph + 0.05);
            return 'translate(' + ( dist * Math.sin( alpha ) ) + ',' + ( - dist * Math.cos( alpha ) ) + ') rotate(' + angle(d) + ')';
        })
        .style('text-anchor', function(d) {
            var rads = ((d.endAngle - d.startAngle) / 2) + d.startAngle;
            if(rads >= 0 && rads <= Math.PI) {
                return 'start';
            } else {
                return 'end';
            }
        })
        .text(function(d, i) { return (Math.round(data[i].value * 10000.0 / totals)/100) + '% ' + data[i].label; });

    function angle(d) {
        var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
        return a > 90 ? a - 180 : a;
    }

}
<commit_msg>Better show the title instead of the package name<commit_after>var globalData = {
    totals: [],
    categories: {}
};

window.onload = function() {
    loadJSONFiles([
        [ 'appsURLs.json', onMostPopularLoaded ],
        [ 'totals.json', onTotalsLoaded ],
        [ 'categories.json', onCategoriesLoaded ]
    ]);
};

function loadJSONFiles(filesList, doneCallback) {

    doneCallback = doneCallback || function() {};

    var filesIter = iterator(filesList);
    var loadNext = function() {

        var nextValue = filesIter.next();

        if(nextValue.done) {
            doneCallback();
        } else {
            var tuple = nextValue.value;
            var request = new XMLHttpRequest();
            var jsonURL = tuple[0];
            var jsonCallback = tuple[1];

            request.open('GET', jsonURL);
            request.responseType = 'text';
            request.onload = function() {

                console.log('loaded', jsonURL);

                var data = JSON.parse(request.response);

                if(jsonCallback) {
                    jsonCallback(data);
                }

                setTimeout(loadNext, 1);
            };

            request.send();
        }
    };

    loadNext();

}

function onMostPopularLoaded(data) {
    console.log('most popular loaded', data.length);
    globalData.mostPopular = data;
}

function onTotalsLoaded(data) {
    console.log('totals loaded', data.length);
    globalData.totals = data;
}

function onCategoriesLoaded(data) {
    console.log('cats loaded', data.length);
    var catJSONs = data.map(function(d) {
        var name = d.split('/').pop();
        return [ 'category-' + name + '.json', function(catData) {
            onCategoryLoaded(name, catData);
        } ];
    });
    console.log(catJSONs);

    globalData.categories = {};

    loadJSONFiles(catJSONs, onAllDataLoaded);

}

function onCategoryLoaded(categoryName, data) {
    console.log('loaded category', categoryName);
    globalData.categories[categoryName] = data.map(function(d) {
        return d.split('=').pop();
    });
}

function* iterator(arr) {
    for(var i = 0; i < arr.length; i++) {
        yield arr[i];
    }
}

function onAllDataLoaded() {

    onDataLoaded(globalData.totals);
    makeCategorisedReport(globalData);
    makeMostPopularReport(globalData);

}

function onDataLoaded(data) {

    var totals = document.getElementById('totals');
    totals.innerHTML = '
' + data.length + ' apps
';

    makeGlobalReport('out', data.slice(0));
    makeAirReport('air', data.slice(0));

}

function makeGlobalReport(tableId, data) {

    data.sort(makeSorter('total'));

    var div = document.getElementById(tableId);
    var out = document.createElement('table');

    var groups = {
        yes: 0,
        maybe: 0,
        unlikely: 0,
        no: 0
    };

    data.forEach(function(app, appIndex) {
        var traits = app.traits;
        traits.sort(makeSorter('amount'));

        // Title
        var trTitle = out.insertRow(-1);
        trTitle.className = 'title';

        var tdCounter = trTitle.insertCell(-1);
        tdCounter.innerHTML = (appIndex + 1);

        // Build up the title:
        var title = app.info !== undefined ? app.info.title : app.name;

        var tdTotal = trTitle.insertCell(-1);
        tdTotal.innerHTML = app.total;

        var tdName = trTitle.insertCell(-1);
        tdName.innerHTML = '
' + title + '
';

        // Details

        var trDetails = out.insertRow(-1);
        trDetails.className = 'details';

        trDetails.insertCell(-1); // empty

        var tdDetails = trDetails.insertCell(-1);
        tdDetails.colSpan = 3;

        tdDetails.innerHTML = '
Play Store: ' + app.name + '
';

        var traitsTable = document.createElement('table');
        traitsTable.className = 'traits';

        traits.forEach(function(trait) {

            var traitRow = traitsTable.insertRow(-1);
            var tdAmount = traitRow.insertCell(-1);
            var tdDesc = traitRow.insertCell(-1);

            tdAmount.innerHTML = trait.amount.toFixed(2);
            tdDesc.innerHTML = trait.reason;

            var hover = trait.files.join('\n');

            traitRow.title = hover;

        });

        tdDetails.appendChild(traitsTable);

        var total = app.total;

        var className = isHTML5(total);

        groups[className]++;

        trTitle.classList.add(className);
        trDetails.classList.add(className);

    });

    // summary - chart with % of html5 likeability
    appendPieChart('#' + div.id, groups);

    div.appendChild(out);

    $('#' + tableId + ' tr.title').on('click', function() {
        $(this).next().toggle();
        this.classList.toggle('open');
    });

}

function findApp(array, pkgName) {
    for(var i = 0; i < array.length; i++) {
        var app = array[i];
        if(app.name === pkgName) {
            return app;
        }
    }
    return null;
}

function isHTML5(total) {

    var className = 'no';

    if(total > 50) {
        className = 'yes';
    } else if(total > 30) {
        className = 'maybe';
    } else if(total > 15) {
        className = 'unlikely';
    }

    return className;
}

function makeAirReport(containerId, data) {
    var airApps = data.filter(function(appInfo) {
        var airTraits = appInfo.traits.filter(function(trait) {
            if(trait.reason === 'air') {
                return trait;
            }
        });
        return airTraits.length > 0;
    });

    var container = document.getElementById(containerId);
    var percentage = (airApps.length * 100.0 / data.length).toFixed(2);

    container.innerHTML = '
' + percentage + '% of ' + data.length + ' apps
';

    var list = document.createElement('ol');
    container.appendChild(list);

    airApps.sort(function(a, b) {
        return a.info.title.toLowerCase() > b.info.title.toLowerCase();
    });

    airApps.forEach(function(app) {
        var li = document.createElement('li');
        li.innerHTML = app.info.title + ' (play store)';
        list.appendChild(li);
    });
}

function makeMostPopularReport(data) {
    // appurls -> get pck name, total has the details

    var outElement = document.getElementById('popular');
    var overview = document.createElement('div');
    var table = document.createElement('table');
    var popular = data.mostPopular;
    var numPopularApps = popular.length;
    var totalApps = data.totals;
    var aggregate = {};

    outElement.appendChild(overview);
    outElement.appendChild(table);

    popular.forEach(function(appUrl) {

        var pkgName = getAppPackageName(appUrl);
        var app = findApp(totalApps, pkgName);

        if(app !== null) {
            var tr = table.insertRow(-1);

            var tdTitle = tr.insertCell(-1);
            tdTitle.innerHTML = '' + app.info.title + '';

            var tdHTML5ness = tr.insertCell(-1);
            var html5ness = isHTML5(app.total);
            tdHTML5ness.innerHTML = html5ness;

            if(aggregate[html5ness] === undefined) {
                aggregate[html5ness] = 1;
            } else {
                aggregate[html5ness]++;
            }

        }

    });

    var txtOverview = '
' + numPopularApps + ' apps' + '
';

    for(var k in aggregate) {
        var value = aggregate[k];
        txtOverview += '
' + k + ' ' + (Math.round(value * 10000 / numPopularApps) / 100 ) + '%
';
    }

    overview.innerHTML = txtOverview;

}

function makeCategorisedReport(data) {

    var categories = data.categories;
    var totals = data.totals;
    var categoryBreakdown = document.getElementById('category-breakdown');
    var outputTable = document.createElement('table');
    var results = [];
    var keys = [ 'yes', 'maybe', 'unlikely', 'no' ];

    categoryBreakdown.appendChild(outputTable);

    for(var catName in categories) {

        var catData = categories[catName];
        var groups = {};

        var appsInCategory = totals.filter(function(app) {
            var pkgName = app.name;
            return catData.indexOf(pkgName) !== -1;
        });

        var numApps = appsInCategory.length;

        // Count how many apps fall in each 'html5 likeability' group
        appsInCategory.forEach(function(app) {

            var total = app.total;
            var html5ness = isHTML5(total);

            if(groups[html5ness] === undefined) {
                groups[html5ness] = 0;
            } else {
                groups[html5ness]++;
            }

        });

        var div = document.createElement('div');
        div.id = 'categoryBreakdown-' + catName;

        categoryBreakdown.appendChild(div);

        var h3 = document.createElement('h3');
        h3.innerHTML = catName + ' ' + numApps;
        div.appendChild(h3);

        appendPieChart('#' + div.id, groups);

        var numYes = groups.yes !== undefined ? groups.yes : 0;
        var yesPerc = Math.round(numYes * 10000.0 / appsInCategory.length) / 100;

        results.push({ name: catName, groups: groups, yesPerc: yesPerc, count: appsInCategory.length });

    };

    results.sort(function(a, b) {

        var yesA = a.yesPerc;
        var yesB = b.yesPerc;

        return yesB - yesA;

    });

    var tr = outputTable.insertRow(-1);
    keys.forEach(function(k) {
        var cell = tr.insertCell(-1);
        cell.innerHTML = k;
    });

    results.forEach(function(r) {

        var row = outputTable.insertRow(-1);

        keys.forEach(function(k) {
            var cell = row.insertCell(-1);
            var value = r.groups[k];

            if(value === undefined) {
                value = 0;
            }

            cell.innerHTML = value;
        });

        row.insertCell(-1).innerHTML = r.yesPerc + '%';
        row.insertCell(-1).innerHTML = r.count;

        row.insertCell(-1).innerHTML = r.name;

    });
}

function getAppURL(packageName) {
    return 'https://play.google.com/store/apps/details?id=' + packageName;
}

function getAppPackageName(url) {
    return url.split('=').pop();
}

function makeSorter(propertyName) {
    return function(a, b) {
        var propA = Number(a[propertyName]);
        var propB = Number(b[propertyName]);
        var epsilon = propA - propB;

        if(Math.abs(epsilon) < 0.0001) {
            return 0;
        } else {
            return epsilon > 0 ? -1 : 1;
        }
    };
}

function appendPieChart(selector, values) {

    var data = [];
    var totals = 0;
    for(var k in values) {
        data.push({ label: k, value: values[k] });
        totals += values[k];
    }

    var width = 300;
    var height = 300;

    var radius = Math.min(width, height) / 2;
    var percGraph = 0.5;
    var graphRadius = radius * percGraph;
    var w = width;
    var h = height;

    var color = {
        'yes': '#00aa00',
        'maybe': '#eeff00',
        'unlikely': '#dd9900',
        'no': '#ff0000'
    };

    var vis = d3.select(selector)
        .append("svg:svg")
            .data([data])
            .attr("width", w)
            .attr("height", h)
            .append("svg:g")
                .attr("transform", "translate(" + radius + "," + radius + ")");

    var arc = d3.svg.arc()
        .outerRadius(graphRadius);

    var pie = d3.layout.pie()
        .value(function(d) { return d.value; });

    var arcs = vis.selectAll('g.slice')
        .data(pie)
        .enter()
        .append('svg:g')
        .attr('class', 'slice');

    arcs.append('svg:path')
        .attr('fill', function(d, i) { var label = data[i].label; return color[label]; } )
        .attr('d', arc);

    arcs.append('svg:text')
        .attr('dy', '5px')
        .attr('transform', function(d) {
            var alpha = (d.endAngle - d.startAngle) * 0.5 + d.startAngle;
            var dist = radius * (percGraph + 0.05);
            return 'translate(' + ( dist * Math.sin( alpha ) ) + ',' + ( - dist * Math.cos( alpha ) ) + ') rotate(' + angle(d) + ')';
        })
        .style('text-anchor', function(d) {
            var rads = ((d.endAngle - d.startAngle) / 2) + d.startAngle;
            if(rads >= 0 && rads <= Math.PI) {
                return 'start';
            } else {
                return 'end';
            }
        })
        .text(function(d, i) { return (Math.round(data[i].value * 10000.0 / totals)/100) + '% ' + data[i].label; });

    function angle(d) {
        var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
        return a > 90 ? a - 180 : a;
    }

}
<|endoftext|>


<commit_before>const CHANGELOG_HEADER = `# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), enforced with [semantic-release](https://github.com/semantic-release/semantic-release).
`

module.exports = {
  preset: 'conventionalcommits',
  releaseRules: [
    { breaking: true, release: 'major' },
    { type: 'feat', release: 'minor' },
    { type: 'fix', release: 'patch' },
  ],
  changelogFile: 'CHANGELOG.md',
  changelogTitle: CHANGELOG_HEADER,
  tarballDir: 'pack',
  message:
    'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
  assets: ['CHANGELOG.md', 'pack/*.tgz'],
  assignees: ['hertzg'],
  plugins: [
    '@semantic-release/commit-analyzer',
    '@semantic-release/release-notes-generator',
    '@semantic-release/changelog',
    [
      '@semantic-release/exec',
      {
        prepareCmd: 'prettier --write CHANGELOG.md',
      },
    ],
    '@semantic-release/npm',
    '@semantic-release/git',
    '@semantic-release/github',
  ],
}
<commit_msg>ci(release): disable git plugin due to permission<commit_after>const CHANGELOG_HEADER = `# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), enforced with [semantic-release](https://github.com/semantic-release/semantic-release).
`

module.exports = {
  preset: 'conventionalcommits',
  releaseRules: [
    { breaking: true, release: 'major' },
    { type: 'feat', release: 'minor' },
    { type: 'fix', release: 'patch' },
  ],
  changelogFile: 'CHANGELOG.md',
  changelogTitle: CHANGELOG_HEADER,
  tarballDir: 'pack',
  message:
    'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
  assets: ['CHANGELOG.md', 'pack/*.tgz'],
  assignees: ['hertzg'],
  plugins: [
    '@semantic-release/commit-analyzer',
    '@semantic-release/release-notes-generator',
    '@semantic-release/changelog',
    [
      '@semantic-release/exec',
      {
        prepareCmd: 'prettier --write CHANGELOG.md',
      },
    ],
    '@semantic-release/npm',
    // '@semantic-release/git',
    '@semantic-release/github',
  ],
}
<|endoftext|>


<commit_before>

(function () {

  // If we'e running in Node.JS, export a module.
  if (typeof module !== 'undefined') {
    module.exports = Rusha;
  }

  // If we're running in a DOM context, export
  // the Rusha object to toplevel.
  if (typeof window !== 'undefined') {
    window.Rusha = Rusha;
  }

  // If we're running in a webworker, accept
  // messages containing a jobid and a buffer
  // or blob object, and return the hash result.
  if (typeof FileReaderSync !== 'undefined') {
    var reader = new FileReaderSync(),
        hasher = new Rusha(4 * 1024 * 1024);
    self.onmessage = function onMessage (event) {
      var hash, data = event.data.data;
      if (data instanceof Blob) {
        try {
          data = reader.readAsBinaryString(data);
        } catch (e) {
          self.postMessage({id: event.data.id, error: e.name});
          return;
        }
      }
      hash = hasher.digest(data);
      self.postMessage({id: event.data.id, hash: hash});
    };
  }

  // The Rusha object is a wrapper around the low-level RushaCore.
  // It provides means of converting different inputs to the
  // format accepted by RushaCore as well as other utility methods.
  function Rusha (sizeHint) {
    "use strict";

    // Private object structure.
    var self = {fill: 0};

    // Calculate the length of buffer that the sha1 routine uses
    // including the padding.
    var padlen = function (len) {
      return len + 1 + ((len ) % 64 < 56 ? 56 : 56 + 64) - (len ) % 64 + 8;
    };

    var padZeroes = function (bin, len) {
      for (var i = len >> 2; i < bin.length; i++) bin[i] = 0;
    };

    var padData = function (bin, len) {
      bin[len>>2] |= 0x80 << (24 - (len % 4 << 3));
      bin[(((len >> 2) + 2) & ~0x0f) + 15] = len << 3;
    };

    // Convert a binary string to a big-endian Int32Array using
    // four characters per slot and pad it per the sha1 spec.
    // A binary string is expected to only contain char codes < 256.
    var convStr = function (str, bin, len) {
      var i;
      for (i = 0; i < len; i = i + 4 |0) {
        bin[i>>2] = str.charCodeAt(i)   << 24 |
                    str.charCodeAt(i+1) << 16 |
                    str.charCodeAt(i+2) <<  8 |
                    str.charCodeAt(i+3);
      }
    };

    // Convert a buffer or array to a big-endian Int32Array using
    // four elements per slot and pad it per the sha1 spec.
    // The buffer or array is expected to only contain elements < 256.
    var convBuf = function (buf, bin, len) {
      var i, m = len % 4, j = len - m;
      for (i = 0; i < j; i = i + 4 |0) {
        bin[i>>2] = buf[i]   << 24 |
                    buf[i+1] << 16 |
                    buf[i+2] <<  8 |
                    buf[i+3];
      }
      switch (m) {
        case 0: bin[j>>2] |= buf[j+3];
        case 3: bin[j>>2] |= buf[j+2] << 8;
        case 2: bin[j>>2] |= buf[j+1] << 16;
        case 1: bin[j>>2] |= buf[j]   << 24;
      }
    };

    // Convert general data to a big-endian Int32Array written on the
    // heap and return it's length;
    var conv = function (data, bin, len) {
      if (typeof data === 'string') {
        return convStr(data, bin, len);
      } else if (data instanceof Array || (typeof global !== 'undefined' &&
                                           typeof global.Buffer !== 'undefined' &&
                                           global.Buffer.isBuffer(data))) {
        return convBuf(data, bin, len);
      } else if (data instanceof ArrayBuffer) {
        return convBuf(new Uint8Array(data), bin, len);
      } else if (data.buffer instanceof ArrayBuffer) {
        return convBuf(new Uint8Array(data.buffer), bin, len);
      } else {
        throw new Error('Unsupported data type.');
      }
    };

    // Convert an ArrayBuffer into its hexadecimal string representation.
    var hex = function (arrayBuffer) {
      var i, x, hex_tab = "0123456789abcdef", res = [], binarray = new Uint8Array(arrayBuffer);
      for (i = 0; i < binarray.length; i++) {
        x = binarray[i];
        res[i] = hex_tab.charAt((x >>  4) & 0xF) +
                 hex_tab.charAt((x >>  0) & 0xF);
      }
      return res.join('');
    };

    var ceilHeapSize = function (v) {
      // The asm.js spec says:
      // The heap object's byteLength must be either
      // 2^n for n in [12, 24) or 2^24 * n for n ≥ 1.
      var p;
      // If v is smaller than 2^12, the smallest possible solution
      // is 2^12.
      if (v <= 4096) return 4096;
      // If v < 2^24, we round up to 2^n,
      // otherwise we round up to 2^24 * n.
      if (v < 16777216) {
        for (p = 1; p < v; p = p << 1);
      } else {
        for (p = 16777216; p < v; p += p);
      }
      return p;
    };

    // Resize the internal data structures to a new capacity.
    var resize = function (size) {
      self.sizeHint = size;
      self.heap     = new ArrayBuffer(ceilHeapSize(padlen(size) + 320));
      self.core     = RushaCore({Int32Array: Int32Array, DataView: DataView}, {}, self.heap);
    };

    // On initialize, resize the datastructures according
    // to an optional size hint.
    resize(sizeHint || 0);

    // Initialize and call the RushaCore,
    // assuming an input buffer of length len * 4.
    var coreCall = function (len) {
      var h = new Int32Array(self.heap, len << 2, 5);
      h[0] =  1732584193;
      h[1] =  -271733879;
      h[2] = -1732584194;
      h[3] =   271733878;
      h[4] = -1009589776;
      self.core.hash(len);
    };

    // Calculate the hash digest as an array of 5 32bit integers.
    var rawDigest = this.rawDigest = function (str) {
      var len = str.byteLength || str.length;
      if (len > self.sizeHint) {
        resize(len);
      }
      var view = new Int32Array(self.heap, 0, padlen(len) >> 2);
      padZeroes(view, len);
      conv(str, view, len);
      padData(view, len);
      coreCall(view.length);
      var out = new Int32Array(5);
      var arr = new DataView(out.buffer);
      arr.setInt32(0,  view[0], false);
      arr.setInt32(4,  view[1], false);
      arr.setInt32(8,  view[2], false);
      arr.setInt32(12, view[3], false);
      arr.setInt32(16, view[4], false);
      return out;
    };

    // The digest and digestFrom* interface returns the hash digest
    // as a hex string.
    this.digest = this.digestFromString =
    this.digestFromBuffer = this.digestFromArrayBuffer =
    function (str) {
      return hex(rawDigest(str).buffer);
    };

  };

  // The low-level RushCore module provides the heart of Rusha,
  // a high-speed sha1 implementation working on an Int32Array heap.
  // At first glance, the implementation seems complicated, however
  // with the SHA1 spec at hand, it is obvious this almost a textbook
  // implementation that has a few functions hand-inlined and a few loops
  // hand-unrolled.
  function RushaCore (stdlib, foreign, heap) {
    "use asm";

    var H = new stdlib.Int32Array(heap);

    function hash (k) {

      k = k|0;
      var i = 0, j = 0,
          y0 = 0, z0 = 0, y1 = 0, z1 = 0,
          y2 = 0, z2 = 0, y3 = 0, z3 = 0,
          y4 = 0, z4 = 0, t0 = 0, t1 = 0;

      y0 = H[k+0<<2>>2]|0;
      y1 = H[k+1<<2>>2]|0;
      y2 = H[k+2<<2>>2]|0;
      y3 = H[k+3<<2>>2]|0;
      y4 = H[k+4<<2>>2]|0;

      for (i = 0; (i|0) < (k|0); i = i + 16 |0) {

        z0 = y0;
        z1 = y1;
        z2 = y2;
        z3 = y3;
        z4 = y4;

        for (j = 0; (j|0) < 16; j = j + 1 |0) {
          t1 = H[i+j<<2>>2]|0;
          t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 & y2 | ~y1 & y3) |0) + ((t1 + y4 | 0)  +1518500249 |0) |0);
          y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
          H[k+j<<2>>2] = t1;
        }

        for (j = k + 16 |0; (j|0) < (k + 20 |0); j = j + 1 |0) {
          t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
          t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 & y2 | ~y1 & y3) |0) + ((t1 + y4 | 0)  +1518500249 |0) |0);
          y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
          H[j<<2>>2] = t1;
        }

        for (j = k + 20 |0; (j|0) < (k + 40 |0); j = j + 1 |0) {
          t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
          t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 ^ y2 ^ y3) |0) + ((t1 + y4 | 0)  +1859775393 |0) |0);
          y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
          H[j<<2>>2] = t1;
        }

        for (j = k + 40 |0; (j|0) < (k + 60 |0); j = j + 1 |0) {
          t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
          t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 & y2 | y1 & y3 | y2 & y3) |0) + ((t1 + y4 | 0)  -1894007588 |0) |0);
          y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
          H[j<<2>>2] = t1;
        }

        for (j = k + 60 |0; (j|0) < (k + 80 |0); j = j + 1 |0) {
          t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
          t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 ^ y2 ^ y3) |0) + ((t1 + y4 | 0)  -899497514 |0) |0);
          y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
          H[j<<2>>2] = t1;
        }

        y0 = y0 + z0 |0;
        y1 = y1 + z1 |0;
        y2 = y2 + z2 |0;
        y3 = y3 + z3 |0;
        y4 = y4 + z4 |0;

      }

      H[0] = y0;
      H[1] = y1;
      H[2] = y2;
      H[3] = y3;
      H[4] = y4;

    }

    return {hash: hash};

  }

})();

<commit_msg>fix bug in rounding heap size > 2^24<commit_after>

(function () {

  // If we'e running in Node.JS, export a module.
  if (typeof module !== 'undefined') {
    module.exports = Rusha;
  }

  // If we're running in a DOM context, export
  // the Rusha object to toplevel.
  if (typeof window !== 'undefined') {
    window.Rusha = Rusha;
  }

  // If we're running in a webworker, accept
  // messages containing a jobid and a buffer
  // or blob object, and return the hash result.
  if (typeof FileReaderSync !== 'undefined') {
    var reader = new FileReaderSync(),
        hasher = new Rusha(4 * 1024 * 1024);
    self.onmessage = function onMessage (event) {
      var hash, data = event.data.data;
      if (data instanceof Blob) {
        try {
          data = reader.readAsBinaryString(data);
        } catch (e) {
          self.postMessage({id: event.data.id, error: e.name});
          return;
        }
      }
      hash = hasher.digest(data);
      self.postMessage({id: event.data.id, hash: hash});
    };
  }

  // The Rusha object is a wrapper around the low-level RushaCore.
  // It provides means of converting different inputs to the
  // format accepted by RushaCore as well as other utility methods.
  function Rusha (sizeHint) {
    "use strict";

    // Private object structure.
    var self = {fill: 0};

    // Calculate the length of buffer that the sha1 routine uses
    // including the padding.
    var padlen = function (len) {
      return len + 1 + ((len ) % 64 < 56 ? 56 : 56 + 64) - (len ) % 64 + 8;
    };

    var padZeroes = function (bin, len) {
      for (var i = len >> 2; i < bin.length; i++) bin[i] = 0;
    };

    var padData = function (bin, len) {
      bin[len>>2] |= 0x80 << (24 - (len % 4 << 3));
      bin[(((len >> 2) + 2) & ~0x0f) + 15] = len << 3;
    };

    // Convert a binary string to a big-endian Int32Array using
    // four characters per slot and pad it per the sha1 spec.
    // A binary string is expected to only contain char codes < 256.
    var convStr = function (str, bin, len) {
      var i;
      for (i = 0; i < len; i = i + 4 |0) {
        bin[i>>2] = str.charCodeAt(i)   << 24 |
                    str.charCodeAt(i+1) << 16 |
                    str.charCodeAt(i+2) <<  8 |
                    str.charCodeAt(i+3);
      }
    };

    // Convert a buffer or array to a big-endian Int32Array using
    // four elements per slot and pad it per the sha1 spec.
    // The buffer or array is expected to only contain elements < 256.
    var convBuf = function (buf, bin, len) {
      var i, m = len % 4, j = len - m;
      for (i = 0; i < j; i = i + 4 |0) {
        bin[i>>2] = buf[i]   << 24 |
                    buf[i+1] << 16 |
                    buf[i+2] <<  8 |
                    buf[i+3];
      }
      switch (m) {
        case 0: bin[j>>2] |= buf[j+3];
        case 3: bin[j>>2] |= buf[j+2] << 8;
        case 2: bin[j>>2] |= buf[j+1] << 16;
        case 1: bin[j>>2] |= buf[j]   << 24;
      }
    };

    // Convert general data to a big-endian Int32Array written on the
    // heap and return it's length;
    var conv = function (data, bin, len) {
      if (typeof data === 'string') {
        return convStr(data, bin, len);
      } else if (data instanceof Array || (typeof global !== 'undefined' &&
                                           typeof global.Buffer !== 'undefined' &&
                                           global.Buffer.isBuffer(data))) {
        return convBuf(data, bin, len);
      } else if (data instanceof ArrayBuffer) {
        return convBuf(new Uint8Array(data), bin, len);
      } else if (data.buffer instanceof ArrayBuffer) {
        return convBuf(new Uint8Array(data.buffer), bin, len);
      } else {
        throw new Error('Unsupported data type.');
      }
    };

    // Convert an ArrayBuffer into its hexadecimal string representation.
    var hex = function (arrayBuffer) {
      var i, x, hex_tab = "0123456789abcdef", res = [], binarray = new Uint8Array(arrayBuffer);
      for (i = 0; i < binarray.length; i++) {
        x = binarray[i];
        res[i] = hex_tab.charAt((x >>  4) & 0xF) +
                 hex_tab.charAt((x >>  0) & 0xF);
      }
      return res.join('');
    };

    var ceilHeapSize = function (v) {
      // The asm.js spec says:
      // The heap object's byteLength must be either
      // 2^n for n in [12, 24) or 2^24 * n for n ≥ 1.
      var p;
      // If v is smaller than 2^12, the smallest possible solution
      // is 2^12.
      if (v <= 4096) return 4096;
      // If v < 2^24, we round up to 2^n,
      // otherwise we round up to 2^24 * n.
      if (v < 16777216) {
        for (p = 1; p < v; p = p << 1);
      } else {
        for (p = 16777216; p < v; p += 16777216);
      }
      return p;
    };

    // Resize the internal data structures to a new capacity.
    var resize = function (size) {
      self.sizeHint = size;
      self.heap     = new ArrayBuffer(ceilHeapSize(padlen(size) + 320));
      self.core     = RushaCore({Int32Array: Int32Array, DataView: DataView}, {}, self.heap);
    };

    // On initialize, resize the datastructures according
    // to an optional size hint.
    resize(sizeHint || 0);

    // Initialize and call the RushaCore,
    // assuming an input buffer of length len * 4.
    var coreCall = function (len) {
      var h = new Int32Array(self.heap, len << 2, 5);
      h[0] =  1732584193;
      h[1] =  -271733879;
      h[2] = -1732584194;
      h[3] =   271733878;
      h[4] = -1009589776;
      self.core.hash(len);
    };

    // Calculate the hash digest as an array of 5 32bit integers.
    var rawDigest = this.rawDigest = function (str) {
      var len = str.byteLength || str.length;
      if (len > self.sizeHint) {
        resize(len);
      }
      var view = new Int32Array(self.heap, 0, padlen(len) >> 2);
      padZeroes(view, len);
      conv(str, view, len);
      padData(view, len);
      coreCall(view.length);
      var out = new Int32Array(5);
      var arr = new DataView(out.buffer);
      arr.setInt32(0,  view[0], false);
      arr.setInt32(4,  view[1], false);
      arr.setInt32(8,  view[2], false);
      arr.setInt32(12, view[3], false);
      arr.setInt32(16, view[4], false);
      return out;
    };

    // The digest and digestFrom* interface returns the hash digest
    // as a hex string.
    this.digest = this.digestFromString =
    this.digestFromBuffer = this.digestFromArrayBuffer =
    function (str) {
      return hex(rawDigest(str).buffer);
    };

  };

  // The low-level RushCore module provides the heart of Rusha,
  // a high-speed sha1 implementation working on an Int32Array heap.
  // At first glance, the implementation seems complicated, however
  // with the SHA1 spec at hand, it is obvious this almost a textbook
  // implementation that has a few functions hand-inlined and a few loops
  // hand-unrolled.
  function RushaCore (stdlib, foreign, heap) {
    "use asm";

    var H = new stdlib.Int32Array(heap);

    function hash (k) {

      k = k|0;
      var i = 0, j = 0,
          y0 = 0, z0 = 0, y1 = 0, z1 = 0,
          y2 = 0, z2 = 0, y3 = 0, z3 = 0,
          y4 = 0, z4 = 0, t0 = 0, t1 = 0;

      y0 = H[k+0<<2>>2]|0;
      y1 = H[k+1<<2>>2]|0;
      y2 = H[k+2<<2>>2]|0;
      y3 = H[k+3<<2>>2]|0;
      y4 = H[k+4<<2>>2]|0;

      for (i = 0; (i|0) < (k|0); i = i + 16 |0) {

        z0 = y0;
        z1 = y1;
        z2 = y2;
        z3 = y3;
        z4 = y4;

        for (j = 0; (j|0) < 16; j = j + 1 |0) {
          t1 = H[i+j<<2>>2]|0;
          t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 & y2 | ~y1 & y3) |0) + ((t1 + y4 | 0)  +1518500249 |0) |0);
          y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
          H[k+j<<2>>2] = t1;
        }

        for (j = k + 16 |0; (j|0) < (k + 20 |0); j = j + 1 |0) {
          t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
          t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 & y2 | ~y1 & y3) |0) + ((t1 + y4 | 0)  +1518500249 |0) |0);
          y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
          H[j<<2>>2] = t1;
        }

        for (j = k + 20 |0; (j|0) < (k + 40 |0); j = j + 1 |0) {
          t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
          t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 ^ y2 ^ y3) |0) + ((t1 + y4 | 0)  +1859775393 |0) |0);
          y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
          H[j<<2>>2] = t1;
        }

        for (j = k + 40 |0; (j|0) < (k + 60 |0); j = j + 1 |0) {
          t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
          t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 & y2 | y1 & y3 | y2 & y3) |0) + ((t1 + y4 | 0)  -1894007588 |0) |0);
          y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
          H[j<<2>>2] = t1;
        }

        for (j = k + 60 |0; (j|0) < (k + 80 |0); j = j + 1 |0) {
          t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
          t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 ^ y2 ^ y3) |0) + ((t1 + y4 | 0)  -899497514 |0) |0);
          y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
          H[j<<2>>2] = t1;
        }

        y0 = y0 + z0 |0;
        y1 = y1 + z1 |0;
        y2 = y2 + z2 |0;
        y3 = y3 + z3 |0;
        y4 = y4 + z4 |0;

      }

      H[0] = y0;
      H[1] = y1;
      H[2] = y2;
      H[3] = y3;
      H[4] = y4;

    }

    return {hash: hash};

  }

})();

<|endoftext|>