<commit_before>import React, {Component} from "react";
import {connect} from "react-redux";
import Pivot from "quick-pivot";
import * as Table from "reactabular-table";
import Button from "./Button";

const tableStyles = {
  marginTop: "1em",
};

class Leaderboard extends Component {
  constructor(props) {
    super(props);
    this.togglePivot = this.togglePivot.bind(this);
    this.reversePivotKey = this.reversePivotKey.bind(this);
    this.toggleCanonFilter = this.toggleCanonFilter.bind(this);
    this.reverseCanonFilter = this.reverseCanonFilter.bind(this);
    this.state = {
      pivot_key: "owner",
      canon_filter: "canon",
    };
  }

  reversePivotKey() {
    return this.state.pivot_key === "owner" ? "character_name" : "owner";
  }

  reverseCanonFilter() {
    return this.state.canon_filter === "canon" ? "altfacts" : "canon";
  }

  togglePivot() {
    this.setState({
      pivot_key: this.reversePivotKey(),
    });
  }

  toggleCanonFilter() {
    this.setState({
      canon_filter: this.reverseCanonFilter(),
    });
  }

  render() {
    const {pivot_key} = this.state;
    const rowsToPivot = [pivot_key];
    const colsToPivot = ["episode_number"];
    const aggregationDimension = "score";
    const aggregator = "sum";

    const scores =
      this.state.canon_filter === "canon"
        ? this.props.scores.filter(score => score.canon === "canon")
        : this.props.scores;

    const pivot = new Pivot(
      scores,
      rowsToPivot,
      colsToPivot,
      aggregationDimension,
      aggregator,
    );
    const pt = pivot.data.table;
    const col_source = pt.shift();
    const cols = col_source ? col_source.value.slice(1) : [];
    const rows = pivot.data.table.map(row => {
      const row_data = {total: 0};
      const values = row.value.slice(1);
      const owner = row.value[0];
      row_data[pivot_key] = owner === "" ? "No one" : owner;

      for (let i = 0; i < cols.length; i++) {
        row_data[cols[i]] = values[i];
        row_data.total += parseInt(values[i] || 0, 10);
      }
      return row_data;
    });

    cols.sort();
    rows.sort((a, b) => (a.total > b.total ? -1 : 1));

    const owner = rows[0].owner;
    rows[0].owner = (

        {owner}

    );

    const columns = [
      {
        property: pivot_key,
        header: {
          label: pivot_key,
          props: {
            style: {
              width: 200,
              textAlign: "left",
            },
          },
        },
      },
      ...cols.map(col => ({
        property: col,
        props: {style: {textAlign: "right"}},
        header: {
          label: col,
          props: {
            style: {
              width: 100,
              textAlign: "right",
            },
          },
        },
      })),
      {
        property: "total",
        props: {style: {textAlign: "right"}},
        header: {
          label: "Total",
          props: {
            style: {
              width: 50,
              textAlign: "right",
            },
          },
        },
      },
    ];

    const pivot_key_map = {character_name: "owner", owner: "character"};
    const canon_filter_map = {canon: "AltFacts", altfacts: "Canon"};
    return (

          Scores by episode by {" "}
          <Button onClick={this.togglePivot}>
            {pivot_key_map[this.reversePivotKey()]}
          </Button>{" "}
          using {" "}
          <Button onClick={this.toggleCanonFilter}>
            {canon_filter_map[this.reverseCanonFilter()]}
          </Button>

    );
  }
}
const mapStateToProps = (state, ownProps) => ({
  scores: state.game.scores,
});

Leaderboard = connect(mapStateToProps)(Leaderboard);

export default Leaderboard;
<commit_msg>Adding filter for the players in leaderboard<commit_after>import React, {Component} from "react";
import {connect} from "react-redux";
import Pivot from "quick-pivot";
import * as Table from "reactabular-table";
import Button from "./Button";
import Select from "./Select";

const tableStyles = {
  marginTop: "1em",
};

class Leaderboard extends Component {
  constructor(props) {
    super(props);
    this.togglePivot = this.togglePivot.bind(this);
    this.reversePivotKey = this.reversePivotKey.bind(this);
    this.toggleCanonFilter = this.toggleCanonFilter.bind(this);
    this.reverseCanonFilter = this.reverseCanonFilter.bind(this);
    this.filterScores = this.filterScores.bind(this);
    this.changeOwnerFilter = this.changeOwnerFilter.bind(this);
    this.state = {
      pivot_key: "owner",
      canon_filter: "canon",
      owner_filter: "All",
    };
  }
  filterScores() {
    const scores =
      this.state.canon_filter === "altfacts"
        ? this.props.scores
        : this.props.scores.filter(
            score => score.canon === this.state.canon_filter,
          );
    return this.state.owner_filter === "All"
      ? scores
      : scores.filter(score => score.owner === this.state.owner_filter);
  }

  reversePivotKey() {
    return this.state.pivot_key === "owner" ? "character_name" : "owner";
  }

  reverseCanonFilter() {
    return this.state.canon_filter === "canon" ? "altfacts" : "canon";
  }

  changeOwnerFilter(event) {
    const owner_filter = event.target.value;
    this.setState({owner_filter});
  }

  togglePivot() {
    this.setState({
      pivot_key: this.reversePivotKey(),
    });
  }

  toggleCanonFilter() {
    this.setState({
      canon_filter: this.reverseCanonFilter(),
    });
  }

  render() {
    const {pivot_key} = this.state;
    const rowsToPivot = [pivot_key];
    const colsToPivot = ["episode_number"];
    const aggregationDimension = "score";
    const aggregator = "sum";

    const scores = this.filterScores(this.props.scores);

    const pivot = new Pivot(
      scores,
      rowsToPivot,
      colsToPivot,
      aggregationDimension,
      aggregator,
    );
    const pt = pivot.data.table;
    const col_source = pt.shift();
    const cols = col_source ? col_source.value.slice(1) : [];
    const rows = pivot.data.table.map(row => {
      const row_data = {total: 0};
      const values = row.value.slice(1);
      const owner = row.value[0];
      row_data[pivot_key] = owner === "" ? "No one" : owner;

      for (let i = 0; i < cols.length; i++) {
        row_data[cols[i]] = values[i];
        row_data.total += parseInt(values[i] || 0, 10);
      }
      return row_data;
    });

    cols.sort();
    rows.sort((a, b) => (a.total > b.total ? -1 : 1));

    const owner = rows[0].owner;
    rows[0].owner = (

        {owner}

    );

    const columns = [
      {
        property: pivot_key,
        header: {
          label: pivot_key,
          props: {
            style: {
              width: 200,
              textAlign: "left",
            },
          },
        },
      },
      ...cols.map(col => ({
        property: col,
        props: {style: {textAlign: "right"}},
        header: {
          label: col,
          props: {
            style: {
              width: 100,
              textAlign: "right",
            },
          },
        },
      })),
      {
        property: "total",
        props: {style: {textAlign: "right"}},
        header: {
          label: "Total",
          props: {
            style: {
              width: 50,
              textAlign: "right",
            },
          },
        },
      },
    ];

    const pivot_key_map = {character_name: "owner", owner: "character"};
    const canon_filter_map = {canon: "AltFacts", altfacts: "Canon"};
    return (

          Scores by episode by {" "}
          <Button onClick={this.togglePivot}>
            {pivot_key_map[this.reversePivotKey()]}
          </Button>{" "}
          using {" "}
          <Button onClick={this.toggleCanonFilter}>
            {canon_filter_map[this.reverseCanonFilter()]}
          </Button>{" "}
          for
          <Select
            options={["All", ...this.props.owners.map(owner => owner.username)]}
            onChange={this.changeOwnerFilter}
          />{" "}
          players

    );
  }
}
const mapStateToProps = (state, ownProps) => ({
  scores: state.game.scores,
  owners: state.game.owners,
});

Leaderboard = connect(mapStateToProps)(Leaderboard);

export default Leaderboard;
<|endoftext|>


<commit_before>var Box = require("./math").box
var math = require("./math")
var Vector3 = math.vec3
var Plane = math.plane
var Triangle = math.triangle

var defaultSphereShape = new Vector3(1, 1, 1)

// vel is unnormalized
function getSweptCollision(spherePos, vel, tris, sphereShape, stick) {
  if (vel.lengthSq() < Number.EPSILON) return { position: spherePos, collision: false }
  sphereShape = sphereShape instanceof Vector3 ? sphereShape : defaultSphereShape

  var newPos = new Vector3().copy(spherePos).divide(sphereShape)
    , newVel = new Vector3().copy(vel).divide(sphereShape)
    , touchPoint = new Vector3(0, 0, 0)
    , touchSpherePoint = new Vector3(0, 0, 0)
    , temp = new Vector3()
    , slidePlane = new Plane()
    , endPos = new Vector3()
    , maxIterations = 10
    , epsilon = Number.EPSILON * 2
    , collision = false
    , hit

  for (var i = 0; i < maxIterations; i++) {
    endPos.addVectors(newPos, newVel)

    var info = getCollision(newPos, newVel, tris, sphereShape)

    if (!isFinite(info.t)) {
      hit = { position: endPos, collision: collision }
      break
    }

    collision = true
    touchPoint.copy(info.collisionPoint)
    // adding this check seems to fix some of the glitches
    if (info.t > epsilon)
      touchSpherePoint.addVectors(newPos, temp.copy(newVel).multiplyScalar(info.t))
    else
      touchSpherePoint.copy(newPos)

    var slideNormal = new Vector3().subVectors(touchSpherePoint, touchPoint).normalize()
    slidePlane.setFromNormalAndCoplanarPoint(slideNormal, touchPoint)
    if (stick) {
      hit = {
        position: newPos.copy(touchSpherePoint).add(slideNormal.multiplyScalar(epsilon)),
        collision: true
      }
      break
    }
    // Projected end point
    var endTouchPoint = new Vector3().addVectors(endPos, new Vector3().copy(slidePlane.normal).multiplyScalar(-slidePlane.distanceToPoint(endPos)))

    // Can modify
    newPos.copy(touchSpherePoint).add(slideNormal.multiplyScalar(epsilon))
    newVel.subVectors(endTouchPoint, touchPoint)
  }

  if (!hit) {
    hit = {
      position: touchSpherePoint.addVectors(newPos, newVel),
      collision: collision
    }
  }

  hit.position.multiply(sphereShape)
  return hit
}

// Returns time of impact from a swept sphere against a polygon soup
// Note that collisionPoint is point on triangle that sphere collides with and t is point it takes for sphere
// to touch so p + v*getCollision().t != getCollision().collisionPoint
function getCollision(spherePos, vel, tris, sphereShape) {
  var plane = new Plane()
    , cb = new Vector3()
    , ab = new Vector3()
    , temp = new Vector3()
    , velNorm = new Vector3(vel.x, vel.y, vel.z).normalize()
    , collisionPoint = new Vector3()
    , collision = false
    , timeOfImpact = Number.POSITIVE_INFINITY
    , invVelNorm = new Vector3().copy(velNorm).negate()

  for (var i = 0; i < tris.length; i++) {
    var original = tris[i]
      , tri = new Triangle(original.a.clone().divide(sphereShape), original.b.clone().divide(sphereShape), original.c.clone().divide(sphereShape))

    var triCollision = false
    ab.subVectors(tri.a, tri.b).normalize()
    cb.subVectors(tri.c, tri.b).normalize()

    var normal = temp.crossVectors(cb, ab).normalize()
    plane.set(normal, -normal.dot(tri.a))

    var velDotNormal = velNorm.dot(normal)
    if (velDotNormal > Number.EPSILON) continue

    var parallel = velDotNormal <= Number.EPSILON && velDotNormal >= -Number.EPSILON
    if (parallel && plane.distanceToPoint(spherePos) >= 1 + Number.EPSILON) continue

    if (!parallel) {
      var collisions = getTCollisions(plane, spherePos, vel)
      var t0 = Math.min(collisions.t0, collisions.t1)
      var t1 = Math.max(collisions.t0, collisions.t1)

      if (t0 > 1 || t1 < 0) continue
      var tempPoint = new Vector3().addVectors(spherePos, new Vector3().copy(vel).multiplyScalar(t0).sub(plane.normal))
      if (math.isInside(tempPoint, tri) && t0 < timeOfImpact) {
        collision = triCollision = true
        timeOfImpact = t0
        collisionPoint = tempPoint
      }
    }

    if (!triCollision) {
      // Try edges and vertices if not on face
      var collisionInfos = [getTCollisionOnVertices(tri, spherePos, vel), getTCollisionOnEdges(tri, spherePos, vel)]

      for (var j = 0; j < 2; j++) {
        var info = collisionInfos[j]
        if (!isFinite(info.t) || info.t > timeOfImpact) continue

        collision = triCollision = true
        timeOfImpact = info.t
        collisionPoint = info.collisionPoint
      }
    }
  }

  return {
    collisionPoint: collisionPoint,
    t: collision ? timeOfImpact : Number.POSITIVE_INFINITY
  }
}

function getTCollisions(plane, spherePos, vel) {
  var dotVel = plane.normal.dot(vel)
  return {
    t0: (1 - plane.distanceToPoint(spherePos)) / dotVel,
    t1: (-1 - plane.distanceToPoint(spherePos)) / dotVel
  }
}

function getTCollisionOnVertices(tri, spherePos, vel) {
  var collision = false
    , collisionPoint

  var a = vel.lengthSq()
  var t = 1
  var temp = new Vector3()
  var pointToSphere = new Vector3()
  var points = [tri.a, tri.b, tri.c]

  for (var i = 0; i < 3; i++) {
    var point = points[i]
    pointToSphere.subVectors(spherePos, point)

    var b = 2 * vel.dot(pointToSphere)
    var c = pointToSphere.lengthSq() - 1

    var timeOfImpact = math.getLowestPositiveRoot(a, b, c, t)
    if (!isFinite(timeOfImpact)) continue

    t = timeOfImpact
    collision = true
    collisionPoint = point
  }

  return {
    collisionPoint: collisionPoint,
    t: collision ? t : Number.POSITIVE_INFINITY
  }
}

function getTCollisionOnEdges(tri, spherePos, vel) {
  var collision = false
    , collisionPoint = new Vector3()

  var t = 1
  var points = [tri.a, tri.b, tri.c]

  for (var i = 0; i < 3; i++) {
    var point = points[i]
    var edge = new Vector3().subVectors(points[(i + 1) % 3], points[i % 3])

    var edgeLenSq = edge.lengthSq()

    var sphereToPoint = new Vector3().subVectors(point, spherePos)

    var edgeDotVel = edge.dot(vel)
    var edgeDotSphereToTri = edge.dot(sphereToPoint)

    var a = edgeLenSq * -vel.lengthSq() + edgeDotVel * edgeDotVel
    var b = edgeLenSq * 2 * vel.dot(sphereToPoint) - 2 * edgeDotVel * edgeDotSphereToTri
    var c = edgeLenSq * (1 - sphereToPoint.lengthSq()) + edgeDotSphereToTri * edgeDotSphereToTri

    var timeOfImpact = math.getLowestPositiveRoot(a, b, c, t)
    if (!isFinite(timeOfImpact)) continue

    var f = (edgeDotVel * timeOfImpact - edgeDotSphereToTri) / edgeLenSq
    if (f < 0 || f > 1) continue

    t = timeOfImpact
    collision = true
    collisionPoint.copy(point).add(edge.multiplyScalar(f))
  }

  resultingCollisionPoint = collisionPoint

  return {
    collisionPoint: collisionPoint,
    t: collision ? t : Number.POSITIVE_INFINITY
  }
}

module.exports = {
  getSweptCollision: getSweptCollision,

  collides: function collides(a, b) {
    var boxA = a.box ? a.box.clone() : new Box3(new Vector3(-1, -1, -1), new Vector3(1, 1, 1))
    var boxB = b.box ? b.box.clone() : new Box3(new Vector3(-1, -1, -1), new Vector3(1, 1, 1))

    boxA.min.add(a.position)
    boxA.max.add(a.position)
    boxB.min.add(b.position)
    boxB.max.add(b.position)

    return boxA.containsBox(boxB)
  },

  collidesSwept: function collidesSwept(a, b, from, to) {
    var boxA = {
      x: from.x - 1,
      y: from.y - 1,
      z: from.z - 1,
      w: 2,
      h: 2,
      d: 2
    }
    var boxB = {
      x: b.position.x - 1,
      y: b.position.y - 1,
      z: b.position.z - 1,
      w: 2,
      h: 2,
      d: 2
    }

    var velocity = new Vector3().subVectors(from, to)
    // Inverse times
    var invEnterX, invEnterY, invEnterZ
    var invExitX, invExitY, invExitZ

    if (velocity.x > 0) {
      invEnterX = boxB.x - (boxA.x + boxA.w)
      invExitX = (boxB.x + boxB.w) - boxA.x
    }
    else {
      invEnterX = (boxB.x + boxB.w) - boxA.x
      invExitX = boxB.x - (boxA.x + boxA.w)
    }

    if (velocity.y > 0) {
      invEnterY = boxB.y - (boxA.y + boxA.h)
      invExitY = (boxB.y + boxB.h) - boxA.y
    }
    else {
      invEnterY = (boxB.y + boxB.h) - boxA.y
      invExitY = boxB.y - (boxA.y + boxA.h)
    }

    if (velocity.z > 0) {
      invEnterZ = boxB.z - (boxA.z + boxA.d)
      invExitZ = (boxB.z + boxB.d) - boxA.z
    }
    else {
      invEnterZ = (boxB.z + boxB.d) - boxA.z
      invExitZ = boxB.z - (boxA.z + boxA.d)
    }

    var entryX, entryY, entryZ
    var exitX, exitY, exitZ

    if (Math.abs(velocity.x) < Number.EPSILON) {
        entryX = Number.NEGATIVE_INFINITY
        exitX = Number.POSITIVE_INFINITY
    }
    else {
        entryX = invEnterX / velocity.x
        exitX = invExitX / velocity.x
    }

    if (Math.abs(velocity.y) < Number.EPSILON) {
        entryY = Number.NEGATIVE_INFINITY
        exitY = Number.POSITIVE_INFINITY
    }
    else {
        entryY = invEnterY / velocity.y
        exitY = invExitY / velocity.y
    }

    if (Math.abs(velocity.z) < Number.EPSILON) {
        entryZ = Number.NEGATIVE_INFINITY
        exitZ = Number.POSITIVE_INFINITY
    }
    else {
        entryZ = invEnterZ / velocity.z
        exitZ = invExitZ / velocity.z
    }

    var entry = Math.max(entryX, entryY)
    entry = Math.max(entry, entryZ)

    var exit = Math.max(exitX, exitY)
    exit = Math.max(exit, exitZ)

    if (entry > exit) return Number.POSITIVE_INFINITY
    if (entryX < 0 && entryY < 0 && entryZ < 0) return Number.POSITIVE_INFINITY
    if (entryX < 0 && (boxA.x + boxA.w < boxB.x || boxA.x > boxB.x + boxB.w)) return Number.POSITIVE_INFINITY
    if (entryY < 0 && (boxA.y + boxA.h < boxB.y || boxA.y > boxB.y + boxB.h)) return Number.POSITIVE_INFINITY
    if (entryZ < 0 && (boxA.z + boxA.d < boxB.z || boxA.z > boxB.z + boxB.d)) return Number.POSITIVE_INFINITY

    return entry
  },
}
<commit_msg>add a little more epsilon for floating point inaccuracies<commit_after>var Box = require("./math").box
var math = require("./math")
var Vector3 = math.vec3
var Plane = math.plane
var Triangle = math.triangle

var defaultSphereShape = new Vector3(1, 1, 1)

// vel is unnormalized
function getSweptCollision(spherePos, vel, tris, sphereShape, stick) {
  if (vel.lengthSq() < Number.EPSILON) return { position: spherePos, collision: false }
  sphereShape = sphereShape instanceof Vector3 ? sphereShape : defaultSphereShape

  var newPos = new Vector3().copy(spherePos).divide(sphereShape)
    , newVel = new Vector3().copy(vel).divide(sphereShape)
    , touchPoint = new Vector3(0, 0, 0)
    , touchSpherePoint = new Vector3(0, 0, 0)
    , temp = new Vector3()
    , slidePlane = new Plane()
    , endPos = new Vector3()
    , maxIterations = 10
    , epsilon = Number.EPSILON * 2
    , collision = false
    , hit

  for (var i = 0; i < maxIterations; i++) {
    endPos.addVectors(newPos, newVel)

    var info = getCollision(newPos, newVel, tris, sphereShape)

    if (!isFinite(info.t)) {
      hit = { position: endPos, collision: collision }
      break
    }

    collision = true
    touchPoint.copy(info.collisionPoint)
    // adding this check seems to fix some of the glitches
    if (info.t > epsilon)
      touchSpherePoint.addVectors(newPos, temp.copy(newVel).multiplyScalar(info.t))
    else
      touchSpherePoint.copy(newPos)

    var slideNormal = new Vector3().subVectors(touchSpherePoint, touchPoint).normalize()
    slidePlane.setFromNormalAndCoplanarPoint(slideNormal, touchPoint)
    if (stick) {
      hit = {
        position: newPos.copy(touchSpherePoint).add(slideNormal.multiplyScalar(epsilon)),
        collision: true
      }
      break
    }
    // Projected end point
    var endTouchPoint = new Vector3().addVectors(endPos, new Vector3().copy(slidePlane.normal).multiplyScalar(-slidePlane.distanceToPoint(endPos)))

    // Can modify
    newPos.copy(touchSpherePoint).add(slideNormal.multiplyScalar(epsilon*2))
    newVel.subVectors(endTouchPoint, touchPoint)
  }

  if (!hit) {
    hit = {
      position: touchSpherePoint.addVectors(newPos, newVel),
      collision: collision
    }
  }

  hit.position.multiply(sphereShape)
  return hit
}

// Returns time of impact from a swept sphere against a polygon soup
// Note that collisionPoint is point on triangle that sphere collides with and t is point it takes for sphere
// to touch so p + v*getCollision().t != getCollision().collisionPoint
function getCollision(spherePos, vel, tris, sphereShape) {
  var plane = new Plane()
    , cb = new Vector3()
    , ab = new Vector3()
    , temp = new Vector3()
    , velNorm = new Vector3(vel.x, vel.y, vel.z).normalize()
    , collisionPoint = new Vector3()
    , collision = false
    , timeOfImpact = Number.POSITIVE_INFINITY
    , invVelNorm = new Vector3().copy(velNorm).negate()

  for (var i = 0; i < tris.length; i++) {
    var original = tris[i]
      , tri = new Triangle(original.a.clone().divide(sphereShape), original.b.clone().divide(sphereShape), original.c.clone().divide(sphereShape))

    var triCollision = false
    ab.subVectors(tri.a, tri.b).normalize()
    cb.subVectors(tri.c, tri.b).normalize()

    var normal = temp.crossVectors(cb, ab).normalize()
    plane.set(normal, -normal.dot(tri.a))

    var velDotNormal = velNorm.dot(normal)
    if (velDotNormal > Number.EPSILON) continue

    var parallel = velDotNormal <= Number.EPSILON && velDotNormal >= -Number.EPSILON
    if (parallel && plane.distanceToPoint(spherePos) >= 1 + Number.EPSILON) continue

    if (!parallel) {
      var collisions = getTCollisions(plane, spherePos, vel)
      var t0 = Math.min(collisions.t0, collisions.t1)
      var t1 = Math.max(collisions.t0, collisions.t1)

      if (t0 > 1 || t1 < 0) continue
      var tempPoint = new Vector3().addVectors(spherePos, new Vector3().copy(vel).multiplyScalar(t0).sub(plane.normal))
      if (math.isInside(tempPoint, tri) && t0 < timeOfImpact) {
        collision = triCollision = true
        timeOfImpact = t0
        collisionPoint = tempPoint
      }
    }

    if (!triCollision) {
      // Try edges and vertices if not on face
      var collisionInfos = [getTCollisionOnVertices(tri, spherePos, vel), getTCollisionOnEdges(tri, spherePos, vel)]

      for (var j = 0; j < 2; j++) {
        var info = collisionInfos[j]
        if (!isFinite(info.t) || info.t > timeOfImpact) continue

        collision = triCollision = true
        timeOfImpact = info.t
        collisionPoint = info.collisionPoint
      }
    }
  }

  return {
    collisionPoint: collisionPoint,
    t: collision ? timeOfImpact : Number.POSITIVE_INFINITY
  }
}

function getTCollisions(plane, spherePos, vel) {
  var dotVel = plane.normal.dot(vel)
  return {
    t0: (1 - plane.distanceToPoint(spherePos)) / dotVel,
    t1: (-1 - plane.distanceToPoint(spherePos)) / dotVel
  }
}

function getTCollisionOnVertices(tri, spherePos, vel) {
  var collision = false
    , collisionPoint

  var a = vel.lengthSq()
  var t = 1
  var temp = new Vector3()
  var pointToSphere = new Vector3()
  var points = [tri.a, tri.b, tri.c]

  for (var i = 0; i < 3; i++) {
    var point = points[i]
    pointToSphere.subVectors(spherePos, point)

    var b = 2 * vel.dot(pointToSphere)
    var c = pointToSphere.lengthSq() - 1

    var timeOfImpact = math.getLowestPositiveRoot(a, b, c, t)
    if (!isFinite(timeOfImpact)) continue

    t = timeOfImpact
    collision = true
    collisionPoint = point
  }

  return {
    collisionPoint: collisionPoint,
    t: collision ? t : Number.POSITIVE_INFINITY
  }
}

function getTCollisionOnEdges(tri, spherePos, vel) {
  var collision = false
    , collisionPoint = new Vector3()

  var t = 1
  var points = [tri.a, tri.b, tri.c]

  for (var i = 0; i < 3; i++) {
    var point = points[i]
    var edge = new Vector3().subVectors(points[(i + 1) % 3], points[i % 3])

    var edgeLenSq = edge.lengthSq()

    var sphereToPoint = new Vector3().subVectors(point, spherePos)

    var edgeDotVel = edge.dot(vel)
    var edgeDotSphereToTri = edge.dot(sphereToPoint)

    var a = edgeLenSq * -vel.lengthSq() + edgeDotVel * edgeDotVel
    var b = edgeLenSq * 2 * vel.dot(sphereToPoint) - 2 * edgeDotVel * edgeDotSphereToTri
    var c = edgeLenSq * (1 - sphereToPoint.lengthSq()) + edgeDotSphereToTri * edgeDotSphereToTri

    var timeOfImpact = math.getLowestPositiveRoot(a, b, c, t)
    if (!isFinite(timeOfImpact)) continue

    var f = (edgeDotVel * timeOfImpact - edgeDotSphereToTri) / edgeLenSq
    if (f < 0 || f > 1) continue

    t = timeOfImpact
    collision = true
    collisionPoint.copy(point).add(edge.multiplyScalar(f))
  }

  resultingCollisionPoint = collisionPoint

  return {
    collisionPoint: collisionPoint,
    t: collision ? t : Number.POSITIVE_INFINITY
  }
}

module.exports = {
  getSweptCollision: getSweptCollision,

  collides: function collides(a, b) {
    var boxA = a.box ? a.box.clone() : new Box3(new Vector3(-1, -1, -1), new Vector3(1, 1, 1))
    var boxB = b.box ? b.box.clone() : new Box3(new Vector3(-1, -1, -1), new Vector3(1, 1, 1))

    boxA.min.add(a.position)
    boxA.max.add(a.position)
    boxB.min.add(b.position)
    boxB.max.add(b.position)

    return boxA.containsBox(boxB)
  },

  collidesSwept: function collidesSwept(a, b, from, to) {
    var boxA = {
      x: from.x - 1,
      y: from.y - 1,
      z: from.z - 1,
      w: 2,
      h: 2,
      d: 2
    }
    var boxB = {
      x: b.position.x - 1,
      y: b.position.y - 1,
      z: b.position.z - 1,
      w: 2,
      h: 2,
      d: 2
    }

    var velocity = new Vector3().subVectors(from, to)
    // Inverse times
    var invEnterX, invEnterY, invEnterZ
    var invExitX, invExitY, invExitZ

    if (velocity.x > 0) {
      invEnterX = boxB.x - (boxA.x + boxA.w)
      invExitX = (boxB.x + boxB.w) - boxA.x
    }
    else {
      invEnterX = (boxB.x + boxB.w) - boxA.x
      invExitX = boxB.x - (boxA.x + boxA.w)
    }

    if (velocity.y > 0) {
      invEnterY = boxB.y - (boxA.y + boxA.h)
      invExitY = (boxB.y + boxB.h) - boxA.y
    }
    else {
      invEnterY = (boxB.y + boxB.h) - boxA.y
      invExitY = boxB.y - (boxA.y + boxA.h)
    }

    if (velocity.z > 0) {
      invEnterZ = boxB.z - (boxA.z + boxA.d)
      invExitZ = (boxB.z + boxB.d) - boxA.z
    }
    else {
      invEnterZ = (boxB.z + boxB.d) - boxA.z
      invExitZ = boxB.z - (boxA.z + boxA.d)
    }

    var entryX, entryY, entryZ
    var exitX, exitY, exitZ

    if (Math.abs(velocity.x) < Number.EPSILON) {
        entryX = Number.NEGATIVE_INFINITY
        exitX = Number.POSITIVE_INFINITY
    }
    else {
        entryX = invEnterX / velocity.x
        exitX = invExitX / velocity.x
    }

    if (Math.abs(velocity.y) < Number.EPSILON) {
        entryY = Number.NEGATIVE_INFINITY
        exitY = Number.POSITIVE_INFINITY
    }
    else {
        entryY = invEnterY / velocity.y
        exitY = invExitY / velocity.y
    }

    if (Math.abs(velocity.z) < Number.EPSILON) {
        entryZ = Number.NEGATIVE_INFINITY
        exitZ = Number.POSITIVE_INFINITY
    }
    else {
        entryZ = invEnterZ / velocity.z
        exitZ = invExitZ / velocity.z
    }

    var entry = Math.max(entryX, entryY)
    entry = Math.max(entry, entryZ)

    var exit = Math.max(exitX, exitY)
    exit = Math.max(exit, exitZ)

    if (entry > exit) return Number.POSITIVE_INFINITY
    if (entryX < 0 && entryY < 0 && entryZ < 0) return Number.POSITIVE_INFINITY
    if (entryX < 0 && (boxA.x + boxA.w < boxB.x || boxA.x > boxB.x + boxB.w)) return Number.POSITIVE_INFINITY
    if (entryY < 0 && (boxA.y + boxA.h < boxB.y || boxA.y > boxB.y + boxB.h)) return Number.POSITIVE_INFINITY
    if (entryZ < 0 && (boxA.z + boxA.d < boxB.z || boxA.z > boxB.z + boxB.d)) return Number.POSITIVE_INFINITY

    return entry
  },
}
<|endoftext|>


<commit_before>import '/imports/startup/server';
import '/imports/api/users/methods';

Meteor.startup(function(){

    // pick up version info
    try {
      var version = {};
      version = JSON.parse(Assets.getText("version.json"));
      Meteor.settings.public.version = version;
    } catch(e) {
      Meteor.settings.public.version = {};
    }

  // if OAuth is configured, load oauth configs into active memory
  if(Package['clinical:smart-on-fhir-client']){
    Meteor.call('resyncConfiguration');
  }

  // browser content policies are an important security measure
  // to only allow connections to specific websites
  // we keep this section optional, because some people want to use
  // meteor-on-fhir during hackathons, research, and various
  // projects where HIPAA grade security isn't always needed
  if(Package['browser-policy-common']){

    // dynamic import
    import { BrowserPolicy } from 'meteor/browser-policy-common';

    console.log('Configuring content-security-policy.');
    BrowserPolicy.content.allowSameOriginForAll();
    BrowserPolicy.content.allowDataUrlForAll()
    BrowserPolicy.content.allowOriginForAll('self');
    BrowserPolicy.content.allowObjectOrigin('self')
    BrowserPolicy.content.allowOriginForAll('font src');
    BrowserPolicy.content.allowOriginForAll('*.wikipedia.com');
    BrowserPolicy.content.allowOriginForAll('*.wikipedia.org');
    BrowserPolicy.content.allowOriginForAll('fonts.googleapis.com');
    BrowserPolicy.content.allowOriginForAll('fonts.gstatic.com');
    BrowserPolicy.content.allowImageOrigin("*")
    BrowserPolicy.content.allowEval();
    BrowserPolicy.content.allowInlineScripts()
    BrowserPolicy.content.allowInlineStyles()

    BrowserPolicy.content.allowObjectOrigin( 'zygotebody.com' );
    BrowserPolicy.content.allowFrameOrigin('zygotebody.com');
    BrowserPolicy.content.allowObjectDataUrl('zygotebody.com');
    BrowserPolicy.content.allowOriginForAll('zygotebody.com');
    BrowserPolicy.content.allowConnectOrigin("zygotebody.com")
    BrowserPolicy.content.allowImageOrigin("zygotebody.com")

    BrowserPolicy.content.allowOriginForAll('fhir-timeline.meteorapp.com');
  }
})<commit_msg>allowOriginForAll(open-ic.epic.com)<commit_after>import '/imports/startup/server';
import '/imports/api/users/methods';

Meteor.startup(function(){

    // pick up version info
    try {
      var version = {};
      version = JSON.parse(Assets.getText("version.json"));
      Meteor.settings.public.version = version;
    } catch(e) {
      Meteor.settings.public.version = {};
    }

  // if OAuth is configured, load oauth configs into active memory
  if(Package['clinical:smart-on-fhir-client']){
    Meteor.call('resyncConfiguration');
  }

  // browser content policies are an important security measure
  // to only allow connections to specific websites
  // we keep this section optional, because some people want to use
  // meteor-on-fhir during hackathons, research, and various
  // projects where HIPAA grade security isn't always needed
  if(Package['browser-policy-common']){

    // dynamic import
    import { BrowserPolicy } from 'meteor/browser-policy-common';

    console.log('Configuring content-security-policy.');
    BrowserPolicy.content.allowSameOriginForAll();
    BrowserPolicy.content.allowDataUrlForAll()
    BrowserPolicy.content.allowOriginForAll('self');
    BrowserPolicy.content.allowObjectOrigin('self')
    BrowserPolicy.content.allowOriginForAll('font src');
    BrowserPolicy.content.allowOriginForAll('*.wikipedia.com');
    BrowserPolicy.content.allowOriginForAll('*.wikipedia.org');
    BrowserPolicy.content.allowOriginForAll('fonts.googleapis.com');
    BrowserPolicy.content.allowOriginForAll('fonts.gstatic.com');
    BrowserPolicy.content.allowImageOrigin("*")
    BrowserPolicy.content.allowEval();
    BrowserPolicy.content.allowInlineScripts()
    BrowserPolicy.content.allowInlineStyles()

    BrowserPolicy.content.allowObjectOrigin( 'zygotebody.com' );
    BrowserPolicy.content.allowFrameOrigin('zygotebody.com');
    BrowserPolicy.content.allowObjectDataUrl('zygotebody.com');
    BrowserPolicy.content.allowOriginForAll('zygotebody.com');
    BrowserPolicy.content.allowConnectOrigin("zygotebody.com")
    BrowserPolicy.content.allowImageOrigin("zygotebody.com")

    BrowserPolicy.content.allowOriginForAll('fhir-timeline.meteorapp.com');
    BrowserPolicy.content.allowOriginForAll('open-ic-epic.com');
  }
})<|endoftext|>


<commit_before>const ObjectID = require('mongodb').ObjectID;

class BasketController {
    constructor(data) {
        this.data = data;
    }

    loadBasketPage(req, res) {
        const userId = req.user._id;
        const user = req.user;

        const products = (req.body);
        let tripId,
            date,
            shopperId;

        const arr = [];

        for (const key in products) {
            if (products.hasOwnProperty(key)) {
                const item = JSON.parse(products[key]);

                if (item.userId == userId) {
                    console.log(item);
                    arr.push((item));
                    tripId = item.tripId;
                    date = item.tripDate;
                    shopperId = item.userId;

                }

            }
        }

        res.render('basket', {
            products: arr,
            user: user,
            tripId: tripId,
            date: date
        });
    }

    basketCheckOut(req, res) {
        const products = (req.body);
        const basket = [];
        let tripID;
        let shopperId;
        const userId = req.user._id;

        for (const key in products) {
            if (products.hasOwnProperty(key)) {
                const item = JSON.parse(products[key]);
                if (item.userId == userId) {
                    basket.push((item));
//proverka dali itemite sa ot picha kadeto gi e porachal server chasta,item.userId ne e implementirano za momenta
//tripId=item.tripId
                }
                console.log(basket);

                shopperId = item.shopperId;

                tripID = item.tripId;

            }
        }

        const basketTripshops = {
            basket: basket,
            buyer: {
                username: req.user.username,
                buyersId: req.user._id
            }
        };
        return Promise.all(
            [
                this.data.users.filterBy({_id: userId}),
                this.data.tripshops.filterBy({id: tripID}),
                this.data.users.filterBy({_id: new ObjectID(shopperId)})

            ]
        ).then(([user, tripshop, shopper]) => {
            return Promise.all([
                this.data.users.addBasketToUser(user[0], basket),
                this.data.tripshops.addBasketToTripshop(tripshop[0], basketTripshops),
                this.data.users.addBuyersBasketToUser(shopper[0], basketTripshops)

            ])
        }).then(() =>
            res.redirect('/profile'))

    }
}

const init = (data) => {
    return new BasketController(data);
};

module.exports = {init};<commit_msg>basket controller updated<commit_after>const ObjectID = require('mongodb').ObjectID;

class BasketController {
    constructor(data) {
        this.data = data;
    }

    loadBasketPage(req, res) {
        const userId = req.user._id;
        const user = req.user;

        const products = (req.body);
        let tripId,
            date,
            shopperId;

        const arr = [];

        for (const key in products) {
            if (products.hasOwnProperty(key)) {
                const item = JSON.parse(products[key]);

                if (item.userId == userId) {
                    arr.push((item));
                    tripId = item.tripId;
                    date = item.tripDate;
                    shopperId = item.userId;
                }
            }
        }

        res.render('basket', {
            products: arr,
            user: user,
            tripId: tripId,
            date: date
        });
    }

    basketCheckOut(req, res) {
        const products = (req.body);
        const basket = [];
        let tripID;
        let shopperId;
        const userId = req.user._id;

        for (const key in products) {
            if (products.hasOwnProperty(key)) {
                const item = JSON.parse(products[key]);
                if (item.userId == userId) {
                    console.log(item);

//proverka dali itemite sa ot picha kadeto gi e porachal server chasta,item.userId ne e implementirano za momenta
//tripId=item.tripId
                }
                basket.push((item));

                shopperId = item.shopperId;

                tripID = item.tripId;
            }
        }

        const basketTripshops = {
            basket: basket,
            buyer: {
                username: req.user.username,
                buyersId: req.user._id
            }
        };
        return Promise.all(
            [
                this.data.users.filterBy({ _id: new ObjectID(userId) }),

                this.data.users.filterBy({ _id: new ObjectID(shopperId) })

            ]
        ).then(([user, shopper]) => {
            return Promise.all([
                this.data.users.addBasketToUser(user[0], basket),

                this.data.users.addBuyersBasketToUser(shopper[0], basketTripshops)

            ]);
        }).then(() =>
            res.redirect('/profile'));
    }
}

const init = (data) => {
    return new BasketController(data);
};

module.exports = { init };<|endoftext|>


<commit_before>import TriggerButton from './TriggerButton';
import PopupModal from './PopupModal';
import setupGhostApi from '../utils/api';
import {ParentContext} from './ParentContext';

const React = require('react');

export default class ParentContainer extends React.Component {
    constructor(props) {
        super(props);

        // Setup custom trigger button handling
        this.setupCustomTriggerButton();

        this.state = {
            page: 'loading',
            showPopup: false,
            action: 'init:running',
            initStatus: 'running',
            lastPage: null
        };
    }

    componentDidUpdate(prevProps, prevState) {
        if (prevState.showPopup !== this.state.showPopup) {
            this.handleCustomTriggerClassUpdate();
        }
    }

    handleCustomTriggerClassUpdate() {
        const popupOpenClass = 'gh-members-popup-open';
        const popupCloseClass = 'gh-members-popup-close';
        if (this.customTriggerButton) {
            const elAddClass = this.state.showPopup ? popupOpenClass : popupCloseClass;
            const elRemoveClass = this.state.showPopup ? popupCloseClass : popupOpenClass;
            this.customTriggerButton.classList.add(elAddClass);
            this.customTriggerButton.classList.remove(elRemoveClass);
        }
    }

    getStripeUrlParam() {
        const url = new URL(window.location);
        return url.searchParams.get('stripe');
    }

    componentDidMount() {
        this.fetchData();
    }

    getDefaultPage({member = this.state.member, stripeParam} = {}) {
        // Loads default page and popup state for local UI testing
        if (process.env.NODE_ENV === 'development') {
            return {
                page: 'signup',
                showPopup: true
            };
        }
        if (!member && stripeParam === 'success') {
            return {page: 'magiclink', showPopup: true};
        }
        if (member) {
            return {
                page: 'accountHome'
            };
        }
        return {
            page: 'signup'
        };
    }

    // Fetch site and member session data with Ghost Apis
    async fetchData() {
        try {
            this.GhostApi = setupGhostApi();
            const {site, member} = await this.GhostApi.init();
            site.isStripeConfigured = (site.isStripeConfigured === undefined) || site.isStripeConfigured;
            const stripeParam = this.getStripeUrlParam();
            const {page, showPopup = false} = this.getDefaultPage({member, stripeParam});
            this.setState({
                site,
                member,
                page,
                showPopup,
                action: 'init:success',
                initStatus: 'success'
            });
        } catch (e) {
            /* eslint-disable no-console */
            console.error(`[Members.js] Failed to initialize`);
            /* eslint-enable no-console */
            this.setState({
                action: 'init:failed',
                initStatus: 'failed'
            });
        }
    }

    setupCustomTriggerButton() {
        const customTriggerSelector = '[data-members-trigger-button]';
        const popupCloseClass = 'gh-members-popup-close';
        this.customTriggerButton = document.querySelector(customTriggerSelector);

        if (this.customTriggerButton) {
            const clickHandler = (event) => {
                event.preventDefault();
                this.onAction('togglePopup');
            };
            this.customTriggerButton.classList.add(popupCloseClass);
            this.customTriggerButton.addEventListener('click', clickHandler);
        }
    }

    getActionData(action) {
        const [type, status, reason] = action.split(':');
        return {type, status, reason};
    }

    getBrandColor() {
        return (this.state.site && this.state.site.brand && this.state.site.brand.primaryColor) || '#3db0ef';
    }

    async onAction(action, data) {
        this.setState({
            action: `${action}:running`
        });
        try {
            if (action === 'switchPage') {
                this.setState({
                    page: data.page,
                    lastPage: data.lastPage || null
                });
            } else if (action === 'togglePopup') {
                this.setState({
                    showPopup: !this.state.showPopup
                });
            } else if (action === 'back') {
                if (this.state.lastPage) {
                    this.setState({
                        page: this.state.lastPage
                    });
                }
            } else if (action === 'closePopup') {
                const {page: defaultPage} = this.getDefaultPage();
                this.setState({
                    showPopup: false,
                    page: this.state.page === 'magiclink' ? defaultPage : this.state.page
                });
            } else if (action === 'signout') {
                await this.GhostApi.member.signout();
                this.setState({
                    action: 'signout:success'
                });
            } else if (action === 'signin') {
                await this.GhostApi.member.sendMagicLink(data);
                this.setState({
                    action: 'signin:success',
                    page: 'magiclink'
                });
            } else if (action === 'signup') {
                const {plan, email, name} = data;
                if (plan.toLowerCase() === 'free') {
                    await this.GhostApi.member.sendMagicLink(data);
                } else {
                    await this.GhostApi.member.checkoutPlan({plan, email, name});
                }
                this.setState({
                    action: 'signup:success',
                    page: 'magiclink'
                });
            } else if (action === 'updateEmail') {
                await this.GhostApi.member.sendMagicLink(data);
                this.setState({
                    action: 'updateEmail:success'
                });
            } else if (action === 'checkoutPlan') {
                const {plan} = data;
                await this.GhostApi.member.checkoutPlan({
                    plan
                });
            } else if (action === 'updateSubscription') {
                const {plan, subscriptionId, cancelAtPeriodEnd} = data;
                await this.GhostApi.member.updateSubscription({
                    planName: plan, subscriptionId, cancelAtPeriodEnd
                });
                const member = await this.GhostApi.member.sessionData();
                this.setState({
                    action: 'updateSubscription:success',
                    page: 'accountHome',
                    member: member
                });
            } else if (action === 'editBilling') {
                await this.GhostApi.member.editBilling();
            } else if (action === 'updateMember') {
                const {name, subscribed} = data;
                const member = await this.GhostApi.member.update({name, subscribed});
                if (!member) {
                    this.setState({
                        action: 'updateMember:failed'
                    });
                } else {
                    this.setState({
                        action: 'updateMember:success',
                        member: member
                    });
                }
            }
            setTimeout(() => {
                this.setState({
                    action: ''
                });
            }, 5000);
        } catch (e) {
            this.setState({
                action: `${action}:failed`
            });
        }
    }

    renderPopup() {
        if (this.state.showPopup) {
            return (
                <PopupModal />
            );
        }
        return null;
    }

    renderTriggerButton() {
        if (!this.customTriggerButton) {
            return (
                <TriggerButton
                    isPopupOpen={this.state.showPopup}
                />
            );
        }

        return null;
    }

    render() {
        if (this.state.initStatus === 'success') {
            const {site, member} = this.state;

            return (
                <ParentContext.Provider value={{
                    site,
                    member,
                    action: this.state.action,
                    brandColor: this.getBrandColor(),
                    page: this.state.page,
                    lastPage: this.state.lastPage,
                    onAction: (action, data) => this.onAction(action, data)
                }}>
                    {this.renderPopup()}
                    {this.renderTriggerButton()}
                </ParentContext.Provider>
            );
        }
        return null;
    }
}
<commit_msg>Allowed multiple custom trigger buttons with start page<commit_after>import TriggerButton from './TriggerButton';
import PopupModal from './PopupModal';
import setupGhostApi from '../utils/api';
import {ParentContext} from './ParentContext';

const React = require('react');

export default class ParentContainer extends React.Component {
    constructor(props) {
        super(props);

        // Setup custom trigger button handling
        this.setupCustomTriggerButton();

        this.state = {
            page: 'loading',
            showPopup: false,
            action: 'init:running',
            initStatus: 'running',
            lastPage: null
        };
    }

    componentDidMount() {
        this.fetchData();
    }

    componentDidUpdate(prevProps, prevState) {
        if (prevState.showPopup !== this.state.showPopup) {
            this.handleCustomTriggerClassUpdate();
        }
    }

    componentWillUnmount() {
        this.customTriggerButtons.forEach((customTriggerButton) => {
            customTriggerButton.addEventListener('click', this.clickHandler);
        });
    }

    handleCustomTriggerClassUpdate() {
        const popupOpenClass = 'gh-members-popup-open';
        const popupCloseClass = 'gh-members-popup-close';
        this.customTriggerButtons.forEach((customButton) => {
            const elAddClass = this.state.showPopup ? popupOpenClass : popupCloseClass;
            const elRemoveClass = this.state.showPopup ? popupCloseClass : popupOpenClass;
            customButton.classList.add(elAddClass);
            customButton.classList.remove(elRemoveClass);
        });
    }

    getStripeUrlParam() {
        const url = new URL(window.location);
        return url.searchParams.get('stripe');
    }

    getDefaultPage({member = this.state.member, stripeParam} = {}) {
        // Loads default page and popup state for local UI testing
        if (process.env.NODE_ENV === 'development') {
            return {
                page: 'signup',
                showPopup: true
            };
        }
        if (!member && stripeParam === 'success') {
            return {page: 'magiclink', showPopup: true};
        }
        if (member) {
            return {
                page: 'accountHome'
            };
        }
        return {
            page: 'signup'
        };
    }

    // Fetch site and member session data with Ghost Apis
    async fetchData() {
        try {
            this.GhostApi = setupGhostApi();
            const {site, member} = await this.GhostApi.init();
            site.isStripeConfigured = (site.isStripeConfigured === undefined) || site.isStripeConfigured;
            const stripeParam = this.getStripeUrlParam();
            const {page, showPopup = false} = this.getDefaultPage({member, stripeParam});
            this.setState({
                site,
                member,
                page,
                showPopup,
                action: 'init:success',
                initStatus: 'success'
            });
        } catch (e) {
            /* eslint-disable no-console */
            console.error(`[Members.js] Failed to initialize`);
            /* eslint-enable no-console */
            this.setState({
                action: 'init:failed',
                initStatus: 'failed'
            });
        }
    }

    setupCustomTriggerButton() {
        // Handler for custom buttons
        this.clickHandler = (event) => {
            const target = event.currentTarget;
            const page = target && target.dataset.membersTriggerButton;

            event.preventDefault();
            this.onAction('openPopup', {page});
        };
        const customTriggerSelector = '[data-members-trigger-button]';
        const popupCloseClass = 'gh-members-popup-close';
        this.customTriggerButtons = document.querySelectorAll(customTriggerSelector) || [];
        this.customTriggerButtons.forEach((customTriggerButton) => {
            customTriggerButton.classList.add(popupCloseClass);
            customTriggerButton.addEventListener('click', this.clickHandler);
        });
    }

    getActionData(action) {
        const [type, status, reason] = action.split(':');
        return {type, status, reason};
    }

    getBrandColor() {
        return (this.state.site && this.state.site.brand && this.state.site.brand.primaryColor) || '#3db0ef';
    }

    async onAction(action, data) {
        this.setState({
            action: `${action}:running`
        });
        try {
            if (action === 'switchPage') {
                this.setState({
                    page: data.page,
                    lastPage: data.lastPage || null
                });
            } else if (action === 'togglePopup') {
                this.setState({
                    showPopup: !this.state.showPopup
                });
            } else if (action === 'openPopup') {
                this.setState({
                    showPopup: true,
                    page: data.page
                });
            } else if (action === 'back') {
                if (this.state.lastPage) {
                    this.setState({
                        page: this.state.lastPage
                    });
                }
            } else if (action === 'closePopup') {
                const {page: defaultPage} = this.getDefaultPage();
                this.setState({
                    showPopup: false,
                    page: this.state.page === 'magiclink' ? defaultPage : this.state.page
                });
            } else if (action === 'signout') {
                await this.GhostApi.member.signout();
                this.setState({
                    action: 'signout:success'
                });
            } else if (action === 'signin') {
                await this.GhostApi.member.sendMagicLink(data);
                this.setState({
                    action: 'signin:success',
                    page: 'magiclink'
                });
            } else if (action === 'signup') {
                const {plan, email, name} = data;
                if (plan.toLowerCase() === 'free') {
                    await this.GhostApi.member.sendMagicLink(data);
                } else {
                    await this.GhostApi.member.checkoutPlan({plan, email, name});
                }
                this.setState({
                    action: 'signup:success',
                    page: 'magiclink'
                });
            } else if (action === 'updateEmail') {
                await this.GhostApi.member.sendMagicLink(data);
                this.setState({
                    action: 'updateEmail:success'
                });
            } else if (action === 'checkoutPlan') {
                const {plan} = data;
                await this.GhostApi.member.checkoutPlan({
                    plan
                });
            } else if (action === 'updateSubscription') {
                const {plan, subscriptionId, cancelAtPeriodEnd} = data;
                await this.GhostApi.member.updateSubscription({
                    planName: plan, subscriptionId, cancelAtPeriodEnd
                });
                const member = await this.GhostApi.member.sessionData();
                this.setState({
                    action: 'updateSubscription:success',
                    page: 'accountHome',
                    member: member
                });
            } else if (action === 'editBilling') {
                await this.GhostApi.member.editBilling();
            } else if (action === 'updateMember') {
                const {name, subscribed} = data;
                const member = await this.GhostApi.member.update({name, subscribed});
                if (!member) {
                    this.setState({
                        action: 'updateMember:failed'
                    });
                } else {
                    this.setState({
                        action: 'updateMember:success',
                        member: member
                    });
                }
            }
            setTimeout(() => {
                this.setState({
                    action: ''
                });
            }, 5000);
        } catch (e) {
            this.setState({
                action: `${action}:failed`
            });
        }
    }

    renderPopup() {
        if (this.state.showPopup) {
            return (
                <PopupModal />
            );
        }
        return null;
    }

    renderTriggerButton() {
        if (!this.customTriggerButtons || this.customTriggerButtons.length === 0) {
            return (
                <TriggerButton
                    isPopupOpen={this.state.showPopup}
                />
            );
        }

        return null;
    }

    render() {
        if (this.state.initStatus === 'success') {
            const {site, member} = this.state;

            return (
                <ParentContext.Provider value={{
                    site,
                    member,
                    action: this.state.action,
                    brandColor: this.getBrandColor(),
                    page: this.state.page,
                    lastPage: this.state.lastPage,
                    onAction: (action, data) => this.onAction(action, data)
                }}>
                    {this.renderPopup()}
                    {this.renderTriggerButton()}
                </ParentContext.Provider>
            );
        }
        return null;
    }
}
<|endoftext|>


<commit_before>/**
 * Created by chensiwei on 2017/7/27.
 */
const webpack = require('webpack')
const path = require('path')
const glob = require('glob')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const src = path.resolve(process.cwd(), 'src')
const entries = {}
const outputHtml = []
/*const init = () => {
    glob.sync(`${src}/entry/!**!/!*.js`, {}, (er, files) => {
        if (er !== null) {
            console.log('glob error:', er)
            return
        } else {
            files.forEach((filePath) => {
                const p = filePath.split('entry')[1]
                const fileEntryName = p.substring(p.indexOf('/') + 1, p.lastIndexOf('/'))
                const conf = {
                    template: `${src}/entry/${fileEntryName}/index.html`,
                    filename: `${fileEntryName}/index.html`,
                    chunksSortMode: 'dependency'
                }
                new HtmlWebpackPlugin(conf)
                outputHtml.push(new HtmlWebpackPlugin(conf))
                entries[fileEntryName] = filePath
            })
            /!*const config = {
                entry: entries,
                output: {
                    path: path.resolve(process.cwd(), 'dist'),
                    publicPath: process.env.NODE_ENV === 'production' ? '/assets' : '/',
                    filename: '[name].[hash:8].js'
                },
                module: {
                    loaders: [
                        {
                            test: /\.html$/,
                            loader: 'html-loader'
                        }
                    ],
                },
                plugins:[
                    new webpack.HotModuleReplacementPlugin()
                ].concat(outputHtml),
                devServer: {
                    compress: true,
                    hot: true,
                    proxy: {
                        '/api': {
                            target: 'http://localhost:3000',
                            pathRewrite: {'^/api' : ''}
                        }
                    },
                    port: 8081
                }
            }
            return config*!/
        }
    })
}*/
/*glob(`${src}/entry/!**!/!*.js`, {}, (er, files) => {
    if (er !== null) {
        console.log('glob error:', er)
        return
    } else {
        const arr = []
        files.forEach((filePath) => {
            const o = {}
            const p = filePath.split('entry')[1]
            const fileEntryName = p.substring(p.indexOf('/') + 1, p.lastIndexOf('/'))
            // console.log('-----', filePath, filename)
            console.log('-----', fileEntryName)
            o.entry = {
                app: filePath
            }
            o.output = {
                path: path.resolve(process.cwd(), 'dist'),
                publicPath: process.env.NODE_ENV === 'production' ? '/assets' : '/',
                filename: '[name].[hash:8].js'
            }
            o.module = {
                loaders: [
                    {
                        test: /\.html$/,
                        loader: 'html-loader'
                    }
                ]
            }
            o.plugins = [
                new webpack.HotModuleReplacementPlugin(),
                new HtmlWebpackPlugin({
                    template: `${src}/entry/${fileEntryName}/index.html`,
                    filename: `${fileEntryName}/index.html`
                })
            ]
        })
    }
    // files is an array of filenames.
    // If the `nonull` option is set, and nothing
    // was found, then files is ["**!/!*.js"]
    // er is an error object or null.
})*/

const files = glob.sync(`${src}/entry/**/*.js`)
files.forEach((filePath) => {
    const p = filePath.split('entry')[1]
    const fileEntryName = p.substring(p.indexOf('/') + 1, p.lastIndexOf('/'))
    const conf = {
        template: `${src}/entry/${fileEntryName}/index.html`,
        filename: `${fileEntryName}/index.html`,
        chunksSortMode: 'dependency'
    }
    new HtmlWebpackPlugin(conf)
    outputHtml.push(new HtmlWebpackPlugin(conf))
    entries[fileEntryName] = filePath
})
console.log('+++++++++++++++++++++', files, outputHtml, entries)
/*module.exports = {
    entry: {
        app: `${src}/entry/page1/index.js`
    },
    output: {
        path: path.resolve(process.cwd(), 'dist'),
        publicPath: process.env.NODE_ENV === 'production' ? '/assets' : '/',
        filename: '[name].[hash:8].js'
    },
    module: {
        loaders: [
            {
                test: /\.html$/,
                loader: 'html-loader'
            }
        ],
    },
    plugins:[
        new webpack.HotModuleReplacementPlugin(),
        new HtmlWebpackPlugin({
            template: `${src}/entry/page1/index.html`,
            filename: 'page1/index.html'
        })
    ],
    devServer: {
        compress: true,
        hot: true,
        proxy: {
            '/api': {
                target: 'http://localhost:3000',
                pathRewrite: {'^/api' : ''}
            }
        },
        port: 8083
    }
};*/

module.exports = {
    devtool: 'source-map',
    entry: Object.assign(entries, {}),
    output: {
        path: path.resolve(process.cwd(), 'dist'),
        publicPath: process.env.NODE_ENV === 'production' ? '/assets' : '/',
        filename: '[name].[hash:8].js'
    },
    module: {
        loaders: [
            {
                test: /\.html$/,
                loader: 'html-loader'
            }
        ],
    },
    plugins:[
        new webpack.HotModuleReplacementPlugin()
    ].concat(outputHtml),
    devServer: {
        compress: true,
        hot: true,
        proxy: {
            '/api': {
                target: 'http://localhost:3000',
                pathRewrite: {'^/api' : ''}
            }
        },
        port: 8083
    }
}
<commit_msg>Limit html-webpack-plugin's chunks to be used<commit_after>/**
 * Created by chensiwei on 2017/7/27.
 */
const webpack = require('webpack')
const path = require('path')
const glob = require('glob')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const src = path.resolve(process.cwd(), 'src')
const entries = {}
const outputHtml = []
const files = glob.sync(`${src}/entry/**/*.js`)
files.forEach((filePath) => {
    const p = filePath.split('entry')[1]
    const fileEntryName = p.substring(p.indexOf('/') + 1, p.lastIndexOf('/'))
    const conf = {
        template: `${src}/entry/${fileEntryName}/index.html`,
        filename: `${fileEntryName}/index.html`,
        chunks: [fileEntryName],
        chunksSortMode: 'dependency'
    }
    new HtmlWebpackPlugin(conf)
    outputHtml.push(new HtmlWebpackPlugin(conf))
    entries[fileEntryName] = filePath
})

module.exports = {
    devtool: 'source-map',
    entry: Object.assign(entries, {}),
    output: {
        path: path.resolve(process.cwd(), 'dist'),
        publicPath: process.env.NODE_ENV === 'production' ? '/assets' : '/',
        filename: '[name].[hash:8].js'
    },
    module: {
        loaders: [
            {
                test: /\.html$/,
                loader: 'html-loader'
            }
        ],
    },
    plugins:[
        new webpack.HotModuleReplacementPlugin()
    ].concat(outputHtml),
    devServer: {
        compress: true,
        hot: true,
        proxy: {
            '/api': {
                target: 'http://localhost:3000',
                pathRewrite: {'^/api' : ''}
            }
        },
        port: 8083
    }
}
<|endoftext|>


<commit_before>/**
 * Copyright 2014 Solinea, Inc.
 *
 * Licensed under the Solinea Software License Agreement (goldstone),
 * Version 1.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *     http://www.solinea.com/goldstone/LICENSE.pdf
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var ReportsReportView = GoldstoneBaseView.extend({

    defaults: {},

    urlGen: function(report) {

        // fetches only the latest result for a particular report
        var urlRouteConstruction = '/core/reports?name=' +
            report + '&page_size=1&node=' +
            this.defaults.hostName;
        return urlRouteConstruction;
    },

    initialize: function(options) {
        this.options = options || {};
        this.defaults = _.clone(this.defaults);
        this.el = options.el;
        this.defaults.width = options.width;
        this.defaults.hostName = options.nodeName;
        this.defaults.globalLookback = options.globalLookback;

        var ns = this.defaults;
        var self = this;

        // appends html elements and initial dataTable to this.el
        this.render();

        // required in case spinner loading takes
        // longer than chart loading
        ns.spinnerDisplay = 'inline';

        var spinnerLocation = '.reports-spinner-container';
        $('').load(function() {
            $(this).appendTo(spinnerLocation).css({
                'position': 'relative',
                'margin-top': -32,
                'margin-left': (ns.width / 2),
                'display': ns.spinnerDisplay
            });
        });

        this.update();

        // triggered whenever this.collection finishes fetching
        this.collection.on('sync', function() {

            // clears existing 'Reports Available' in dropdown
            $(self.el).find('.reports-available-dropdown-menu > li').remove();

            // if no reports available, appends 'No reports available'
            if (self.collection.toJSON()[0].result.length === 0) {

                $(self.el).find('.reports-available-dropdown-menu').append('
No reports available
');

            } else {
                self.populateReportsDropdown();
            }

            self.clearDataErrorMessage();
        });

        this.collection.on('error', this.dataErrorMessage, this);

        // this is triggered by a listener set on nodeReportView.js
        this.on('selectorChanged', function() {

            // reconstructs the url to fetch in this.collection
            self.collection.defaults.globalLookback = $('#global-lookback-range').val();

            // fetches reports available as far back as the global lookback period
            self.collection.retrieveData();

        });

    },

    update: function() {

        var ns = this.defaults;
        var self = this;

        // sets css for spinner to hidden in case
        // spinner callback resolves
        // after chart data callback
        ns.spinnerDisplay = 'none';
        $(this.el).find('#spinner').hide();

    },

    render: function() {
        $(this.el).append(this.template());
        $(this.el).find('.refreshed-report-container').append(this.dataTableTemplate());
        return this;
    },

    dataPrep: function(tableData) {

        var ns = this.defaults;
        var self = this;

        // initialize array that will be returned after processing
        var finalResults = [];

        if (typeof(tableData[0]) === "object") {

            // chained underscore function that will scan for the existing
            // object keys, and return a list of the unique keys
            // as not every object contains every key
            var uniqueObjectKeys = _.uniq(_.flatten(_.map(tableData, function(item) {
                return Object.keys(item);
            })));

            // if there is a unique key with "name" somewhere in it,
            // reorder the keys so that it is first

            var keysWithName = [];
            for (var i = 0; i < uniqueObjectKeys.length; i++) {
                var item = uniqueObjectKeys[i];
                if (item.indexOf('name') === -1) {
                    continue;
                } else {
                    var spliced = uniqueObjectKeys.splice(i, 1);
                    keysWithName.push(spliced);
                    i--;
                }
            }
            _.each(keysWithName, function(item) {
                uniqueObjectKeys.unshift(item[0]);
            });

            // append data table headers that match the unique keys
            _.each(uniqueObjectKeys, function(item) {
                $('.data-table-header-container').append('' + item + '	');
            });

            // iterate through tableData, and push object values to results
            // array, inserting '' where there is no existing value

            _.each(tableData, function(value) {
                var subresult = [];
                _.each(uniqueObjectKeys, function(item) {
                    if (value[item] === undefined) {
                        subresult.push('');
                    } else {
                        subresult.push(value[item]);
                    }
                });
                finalResults.push(subresult);
            });

        } else {

            $('.data-table-header-container').append('Result	');
            _.each(tableData, function(item) {
                finalResults.push([item]);
            });
        }
        return finalResults;
    },

    drawSearchTable: function(location, data) {

        var ns = this.defaults;
        var self = this;
        var oTable;

        // removes initial placeholder message
        $(this.el).find('.reports-info-container').remove();

        if ($.fn.dataTable.isDataTable(location)) {

            // if dataTable already exists:
            oTable = $(location).DataTable();

            // complete remove it from memory and the dom
            oTable.destroy({
                remove: true
            });

            // and re-append the table structure that will be repopulated
            // with the new data
            $(this.el).find('.refreshed-report-container')
                .html(this.dataTableTemplate());
        }

        data = this.dataPrep(data);
        var oTableParams = {
            "info": true,
            "processing": false,
            "lengthChange": true,
            "paging": true,
            "searching": true,
            "order": [
                [0, 'asc']
            ],
            "ordering": true,
            "data": data,
            "serverSide": false,
        };
        oTable = $(location).DataTable(oTableParams);

    },

    populateReportsDropdown: function() {
        var ns = this.defaults;
        var self = this;

        _.each(self.collection.models[0].attributes.result, function(item) {
            $(self.el).find('.reports-available-dropdown-menu').append('
' + item + "
");
        });

        // add click listeners to dropdown entries
        $(self.el).find('.reports-available-dropdown-menu > li').on('click', function(e) {
            ns.spinnerDisplay = "inline";
            $(self.el).find('#spinner').show();

            // $.get report based on
            var reportUrl = self.urlGen(e.currentTarget.innerText);

            $.ajax({
                url: reportUrl,
                success: function(data) {
                    $(self.el).find('.panel-header-report-title').text(': ' + e.currentTarget.innerText);
                    $(self.el).find('#spinner').hide();

                    // render data table:
                    self.drawSearchTable('#reports-result-table', data.results[0].value);
                    self.clearDataErrorMessage();
                },
                error: function(data) {
                    self.dataErrorMessage(null, data);
                }
            });

        });
    },

    template: _.template(

        // render dropdown button
        '
' +
        '<button id="dLabel" type="button" class="btn btn-default" data-toggle="dropdown" aria-haspopup="true" role="button" aria-expanded="false">' +
        'Reports Available ' +
        '' +
        '</button>' +
        '
' +
        '
Reports list loading or not available
' +
        '
' +
        '

' +

        // spinner container
        '

' +

        // render report data title bar
        '
' +
        '
' +
        '
 Report Data' +
        '' +
        '
' +
        '
' +

        // initially rendered message this will be overwritten by dataTable
        '

' +
        '
' +
        '
Selecting a report from the dropdown above will populate this area with the report results.' +
        '
' +

        '
' +
        '

'
    ),

    dataTableTemplate: _.template(
        '
' +
        '
' +
        '
' +

        // necessary  is appended here by jQuery in this.dataPrep()
        '
' +
        '
' +
        '

' +
        '
'
    )

});
<commit_msg>Extends goldstoneBaseView into reportReportsView (the 'reports' tab of the nodeReport page).<commit_after>/**
 * Copyright 2014 Solinea, Inc.
 *
 * Licensed under the Solinea Software License Agreement (goldstone),
 * Version 1.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *     http://www.solinea.com/goldstone/LICENSE.pdf
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
This view makes up the "Reports" tab of nodeReportView.js
It is sub-classed from GoldstoneBaseView.
*/

var ReportsReportView = GoldstoneBaseView.extend({

    defaults: {},

    urlGen: function(report) {

        // request page_size=1 in order to only
        // retrieve the latest result

        var urlRouteConstruction = '/core/reports?name=' +
            report + '&page_size=1&node=' +
            this.defaults.hostName;
        return urlRouteConstruction;
    },

    initialize: function(options) {

        ReportsReportView.__super__.initialize.apply(this, arguments);
    },

    processOptions: function() {
        ReportsReportView.__super__.processOptions.apply(this, arguments);

        this.defaults.hostName = this.options.nodeName;
        this.defaults.globalLookback = this.options.globalLookback;

    },

    processListeners: function() {

        var ns = this.defaults;
        var self = this;

        // triggered whenever this.collection finishes fetching
        this.collection.on('sync', function() {

            // removes spinner that was appended
            // during chart-load
            self.hideSpinner();

            // clears existing 'Reports Available' in dropdown
            $(self.el).find('.reports-available-dropdown-menu > li').remove();

            // if no reports available, appends 'No reports available'
            if (self.collection.toJSON()[0].result.length === 0) {

                $(self.el).find('.reports-available-dropdown-menu').append('
No reports available
');

            } else {
                self.populateReportsDropdown();
            }

            self.clearDataErrorMessage();
        });

        this.collection.on('error', this.dataErrorMessage, this);

        // this is triggered by a listener set on nodeReportView.js
        this.on('selectorChanged', function() {

            // reconstructs the url to fetch in this.collection
            self.collection.defaults.globalLookback = $('#global-lookback-range').val();

            // fetches reports available as far back as the global lookback period
            self.collection.retrieveData();

        });
    },

    processMargins: function() {
        // overwritten so as not to conflict with super-class'
        // method that will calculate irrelevant margins.
        return null;
    },

    render: function() {
        $(this.el).append(this.template());
        $(this.el).find('.refreshed-report-container').append(this.dataTableTemplate());
        return this;
    },

    standardInit: function() {
        // overwritten so as not to conflict with super-class'
        // method that will calculate irrelevant margins.
        return null;
    },

    dataPrep: function(tableData) {

        var ns = this.defaults;
        var self = this;

        // initialize array that will be returned after processing
        var finalResults = [];

        if (typeof(tableData[0]) === "object") {

            // chained underscore function that will scan for the existing
            // object keys, and return a list of the unique keys
            // as not every object contains every key
            var uniqueObjectKeys = _.uniq(_.flatten(_.map(tableData, function(item) {
                return Object.keys(item);
            })));

            // if there is a unique key with "name" somewhere in it,
            // reorder the keys so that it is first

            var keysWithName = [];
            for (var i = 0; i < uniqueObjectKeys.length; i++) {
                var item = uniqueObjectKeys[i];
                if (item.indexOf('name') === -1) {
                    continue;
                } else {
                    var spliced = uniqueObjectKeys.splice(i, 1);
                    keysWithName.push(spliced);
                    i--;
                }
            }
            _.each(keysWithName, function(item) {
                uniqueObjectKeys.unshift(item[0]);
            });

            // append data table headers that match the unique keys
            _.each(uniqueObjectKeys, function(item) {
                $('.data-table-header-container').append('' + item + '	');
            });

            // iterate through tableData, and push object values to results
            // array, inserting '' where there is no existing value

            _.each(tableData, function(value) {
                var subresult = [];
                _.each(uniqueObjectKeys, function(item) {
                    if (value[item] === undefined) {
                        subresult.push('');
                    } else {
                        subresult.push(value[item]);
                    }
                });
                finalResults.push(subresult);
            });

        } else {

            $('.data-table-header-container').append('Result	');
            _.each(tableData, function(item) {
                finalResults.push([item]);
            });
        }
        return finalResults;
    },

    drawSearchTable: function(location, data) {

        var ns = this.defaults;
        var self = this;
        var oTable;

        // removes initial placeholder message
        $(this.el).find('.reports-info-container').remove();

        if ($.fn.dataTable.isDataTable(location)) {

            // if dataTable already exists:
            oTable = $(location).DataTable();

            // complete remove it from memory and the dom
            oTable.destroy({
                remove: true
            });

            // and re-append the table structure that will be repopulated
            // with the new data
            $(this.el).find('.refreshed-report-container')
                .html(this.dataTableTemplate());
        }

        data = this.dataPrep(data);
        var oTableParams = {
            "info": true,
            "processing": false,
            "lengthChange": true,
            "paging": true,
            "searching": true,
            "order": [
                [0, 'asc']
            ],
            "ordering": true,
            "data": data,
            "serverSide": false,
        };
        oTable = $(location).DataTable(oTableParams);

    },

    populateReportsDropdown: function() {
        var ns = this.defaults;
        var self = this;

        _.each(self.collection.models[0].attributes.result, function(item) {
            $(self.el).find('.reports-available-dropdown-menu').append('
' + item + "
");
        });

        // add click listeners to dropdown entries
        $(self.el).find('.reports-available-dropdown-menu > li').on('click', function(e) {
            ns.spinnerDisplay = "inline";
            $(self.el).find('#spinner').show();

            // $.get report based on
            var reportUrl = self.urlGen(e.currentTarget.innerText);

            $.ajax({
                url: reportUrl,
                success: function(data) {
                    $(self.el).find('.panel-header-report-title').text(': ' + e.currentTarget.innerText);
                    $(self.el).find('#spinner').hide();

                    // render data table:
                    self.drawSearchTable('#reports-result-table', data.results[0].value);
                    self.clearDataErrorMessage();
                },
                error: function(data) {
                    self.dataErrorMessage(null, data);
                }
            });

        });
    },

    template: _.template(

        // render dropdown button
        '
' +
        '<button id="dLabel" type="button" class="btn btn-default" data-toggle="dropdown" aria-haspopup="true" role="button" aria-expanded="false">' +
        'Reports Available ' +
        '' +
        '</button>' +
        '
' +
        '
Reports list loading or not available
' +
        '
' +
        '

' +

        // spinner container
        '

' +

        // render report data title bar
        '
' +
        '
' +
        '
 Report Data' +
        '' +
        '
' +
        '
' +

        // initially rendered message this will be overwritten by dataTable
        '

' +
        '
' +
        '
Selecting a report from the dropdown above will populate this area with the report results.' +
        '
' +

        '
' +
        '

'
    ),

    dataTableTemplate: _.template(
        '
' +
        '
' +
        '
' +

        // necessary  is appended here by jQuery in this.dataPrep()
        '
' +
        '
' +
        '

' +
        '
'
    )

});
<|endoftext|>


<commit_before>// #DROPZONE#
// This script implements the dropzone settings
'use strict';

/* global Dropzone */
(function ($) {
    $(function () {
        var dropzoneSelector = '.js-dropzone';
        var dropzone = $(dropzoneSelector);
        var dropzoneUrl = dropzone.data('url');
        var filerFile = $('.filerFile');

        if (dropzone.length && Dropzone) {
            Dropzone.autoDiscover = false;
            new Dropzone(dropzoneSelector, {
                url: dropzoneUrl,
                paramName: 'file', // The name that will be used to transfer the file
                maxFilesize: 2, // MB
                addRemoveLinks: true,
                maxFiles: 1,
                clickable: false,
                maxfilesexceeded: function (file) {
                    this.removeAllFiles();
                    this.addFile(file);
                },
                drop: function () {
                    filerFile.hide();
                    $('.filerClearer').click();
                },
                init: function () {
                    this.on('removedfile', function () {
                        filerFile.show();
                        this.removeAllFiles();
                    });
                }
            });
        }
    });
})(jQuery);
<commit_msg>remove dropzone hover on reset<commit_after>// #DROPZONE#
// This script implements the dropzone settings
'use strict';

/* global Dropzone */
(function ($) {
    $(function () {
        var dropzoneSelector = '.js-dropzone';
        var dropzone = $(dropzoneSelector);
        var dropzoneUrl = dropzone.data('url');
        var filerFile = $('.filerFile');

        if (dropzone.length && Dropzone) {
            Dropzone.autoDiscover = false;
            new Dropzone(dropzoneSelector, {
                url: dropzoneUrl,
                paramName: 'file', // The name that will be used to transfer the file
                maxFilesize: 2, // MB
                addRemoveLinks: true,
                maxFiles: 1,
                clickable: false,
                maxfilesexceeded: function (file) {
                    this.removeAllFiles();
                    this.addFile(file);
                },
                drop: function (element) {
                    filerFile.hide();
                    $('.filerClearer').click();
                    dropzone.removeClass('dz-drag-hover');
                },
                init: function () {
                    this.on('removedfile', function () {
                        filerFile.show();
                        this.removeAllFiles();
                    });
                }
            });
        }
    });
})(jQuery);
<|endoftext|>


<commit_before>var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    devtool: 'cheap-eval-source-map',
    entry: [
        'webpack-dev-server/client?http://localhost:8080',
        'webpack/hot/only-dev-server',
        './example/index',
        './src/js/simple-list-item-selector',
    ],
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js',
        libraryTarget: 'umd',
        library: 'SimpleListItemSelector'
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new HtmlWebpackPlugin({
            template: './example/index.html',
            inject: 'body',
        })
    ],
    module: {
        loaders: [{
            test: /\.html$/,
            loader: "raw-loader"
        }, {
            exclude: /node_modules/,
            test: /\.js$/,
            loaders: ['babel-loader']
        }],

    },
    devServer: {
        contentBase: path.join(__dirname, "dist"),
        //publicPath: path.join(__dirname, "dist")
        hot: true
    }
}<commit_msg>Remove redundant property in web pack config<commit_after>var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    devtool: 'cheap-eval-source-map',
    entry: [
        'webpack-dev-server/client?http://localhost:8080',
        'webpack/hot/only-dev-server',
        './example/index',
        './src/js/simple-list-item-selector',
    ],
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js',
        libraryTarget: 'umd',
        library: 'SimpleListItemSelector'
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new HtmlWebpackPlugin({
            template: './example/index.html'
        })
    ],
    module: {
        loaders: [{
            test: /\.html$/,
            loader: "raw-loader"
        }, {
            exclude: /node_modules/,
            test: /\.js$/,
            loaders: ['babel-loader']
        }],

    },
    devServer: {
        contentBase: path.join(__dirname, "dist"),
        //publicPath: path.join(__dirname, "dist")
        hot: true
    }
}<|endoftext|>