<commit_before>// AST walker module for Mozilla Parser API compatible trees

// A simple walk is one where you simply specify callbacks to be
// called on specific nodes. The last two arguments are optional. A
// simple use would be
//
//     walk.simple(myTree, {
//         Expression: function(node) { ... }
//     });
//
// to do something with all expressions. All Parser API node types
// can be used to identify node types, as well as Expression,
// Statement, and ScopeBody, which denote categories of nodes.
//
// The base argument can be used to pass a custom (recursive)
// walker, and state can be used to give this walked an initial
// state.

export function simple(node, visitors, base, state, override) {
  if (!base) base = exports.base
  ;(function c(node, st, override) {
    let type = override || node.type, found = visitors[type]
    base[type](node, st, c)
    if (found) found(node, st)
  })(node, state, override)
}

// An ancestor walk builds up an array of ancestor nodes (including
// the current node) and passes them to the callback as the state parameter.
export function ancestor(node, visitors, base, state) {
  if (!base) base = exports.base
  if (!state) state = []
  ;(function c(node, st, override) {
    let type = override || node.type, found = visitors[type]
    if (node != st[st.length - 1]) {
      st = st.slice()
      st.push(node)
    }
    base[type](node, st, c)
    if (found) found(node, st)
  })(node, state)
}

// A recursive walk is one where your functions override the default
// walkers. They can modify and replace the state parameter that's
// threaded through the walk, and can opt how and whether to walk
// their child nodes (by calling their third argument on these
// nodes).
export function recursive(node, state, funcs, base, override) {
  let visitor = funcs ? exports.make(funcs, base) : base
  ;(function c(node, st, override) {
    visitor[override || node.type](node, st, c)
  })(node, state, override)
}

function makeTest(test) {
  if (typeof test == "string")
    return type => type == test
  else if (!test)
    return () => true
  else
    return test
}

class Found {
  constructor(node, state) { this.node = node; this.state = state }
}

// Find a node with a given start, end, and type (all are optional,
// null can be used as wildcard). Returns a {node, state} object, or
// undefined when it doesn't find a matching node.
export function findNodeAt(node, start, end, test, base, state) {
  test = makeTest(test)
  if (!base) base = exports.base
  try {
    ;(function c(node, st, override) {
      let type = override || node.type
      if ((start == null || node.start <= start) &&
          (end == null || node.end >= end))
        base[type](node, st, c)
      if ((start == null || node.start == start) &&
          (end == null || node.end == end) &&
          test(type, node))
        throw new Found(node, st)
    })(node, state)
  } catch (e) {
    if (e instanceof Found) return e
    throw e
  }
}

// Find the innermost node of a given type that contains the given
// position. Interface similar to findNodeAt.
export function findNodeAround(node, pos, test, base, state) {
  test = makeTest(test)
  if (!base) base = exports.base
  try {
    ;(function c(node, st, override) {
      let type = override || node.type
      if (node.start > pos || node.end < pos) return
      base[type](node, st, c)
      if (test(type, node)) throw new Found(node, st)
    })(node, state)
  } catch (e) {
    if (e instanceof Found) return e
    throw e
  }
}

// Find the outermost matching node after a given position.
export function findNodeAfter(node, pos, test, base, state) {
  test = makeTest(test)
  if (!base) base = exports.base
  try {
    ;(function c(node, st, override) {
      if (node.end < pos) return
      let type = override || node.type
      if (node.start >= pos && test(type, node)) throw new Found(node, st)
      base[type](node, st, c)
    })(node, state)
  } catch (e) {
    if (e instanceof Found) return e
    throw e
  }
}

// Find the outermost matching node before a given position.
export function findNodeBefore(node, pos, test, base, state) {
  test = makeTest(test)
  if (!base) base = exports.base
  let max
  ;(function c(node, st, override) {
    if (node.start > pos) return
    let type = override || node.type
    if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node))
      max = new Found(node, st)
    base[type](node, st, c)
  })(node, state)
  return max
}

// Used to create a custom walker. Will fill in all missing node
// type properties with the defaults.
export function make(funcs, base) {
  if (!base) base = exports.base
  let visitor = {}
  for (var type in base) visitor[type] = base[type]
  for (var type in funcs) visitor[type] = funcs[type]
  return visitor
}

function skipThrough(node, st, c) { c(node, st) }
function ignore(_node, _st, _c) {}

// Node walkers.

export const base = {}

base.Program = base.BlockStatement = (node, st, c) => {
  for (let i = 0; i < node.body.length; ++i)
    c(node.body[i], st, "Statement")
}
base.Statement = skipThrough
base.EmptyStatement = ignore
base.ExpressionStatement = base.ParenthesizedExpression =
  (node, st, c) => c(node.expression, st, "Expression")
base.IfStatement = (node, st, c) => {
  c(node.test, st, "Expression")
  c(node.consequent, st, "Statement")
  if (node.alternate) c(node.alternate, st, "Statement")
}
base.LabeledStatement = (node, st, c) => c(node.body, st, "Statement")
base.BreakStatement = base.ContinueStatement = ignore
base.WithStatement = (node, st, c) => {
  c(node.object, st, "Expression")
  c(node.body, st, "Statement")
}
base.SwitchStatement = (node, st, c) => {
  c(node.discriminant, st, "Expression")
  for (let i = 0; i < node.cases.length; ++i) {
    let cs = node.cases[i]
    if (cs.test) c(cs.test, st, "Expression")
    for (let j = 0; j < cs.consequent.length; ++j)
      c(cs.consequent[j], st, "Statement")
  }
}
base.ReturnStatement = base.YieldExpression = (node, st, c) => {
  if (node.argument) c(node.argument, st, "Expression")
}
base.ThrowStatement = base.SpreadElement =
  (node, st, c) => c(node.argument, st, "Expression")
base.TryStatement = (node, st, c) => {
  c(node.block, st, "Statement")
  if (node.handler) {
    c(node.handler.param, st, "Pattern")
    c(node.handler.body, st, "ScopeBody")
  }
  if (node.finalizer) c(node.finalizer, st, "Statement")
}
base.WhileStatement = base.DoWhileStatement = (node, st, c) => {
  c(node.test, st, "Expression")
  c(node.body, st, "Statement")
}
base.ForStatement = (node, st, c) => {
  if (node.init) c(node.init, st, "ForInit")
  if (node.test) c(node.test, st, "Expression")
  if (node.update) c(node.update, st, "Expression")
  c(node.body, st, "Statement")
}
base.ForInStatement = base.ForOfStatement = (node, st, c) => {
  c(node.left, st, "ForInit")
  c(node.right, st, "Expression")
  c(node.body, st, "Statement")
}
base.ForInit = (node, st, c) => {
  if (node.type == "VariableDeclaration") c(node, st)
  else c(node, st, "Expression")
}
base.DebuggerStatement = ignore

base.FunctionDeclaration = (node, st, c) => c(node, st, "Function")
base.VariableDeclaration = (node, st, c) => {
  for (let i = 0; i < node.declarations.length; ++i)
    c(node.declarations[i], st)
}
base.VariableDeclarator = (node, st, c) => {
  c(node.id, st, "Pattern")
  if (node.init) c(node.init, st, "Expression")
}

base.Function = (node, st, c) => {
  for (let i = 0; i < node.params.length; i++)
    c(node.params[i], st, "Pattern")
  c(node.body, st, node.expression ? "ScopeExpression" : "ScopeBody")
}
// FIXME drop these node types in next major version
// (They are awkward, and in ES6 every block can be a scope.)
base.ScopeBody = (node, st, c) => c(node, st, "Statement")
base.ScopeExpression = (node, st, c) => c(node, st, "Expression")

base.Pattern = (node, st, c) => {
  if (node.type == "Identifier")
    c(node, st, "VariablePattern")
  else if (node.type == "MemberExpression")
    c(node, st, "MemberPattern")
  else
    c(node, st)
}
base.VariablePattern = ignore
base.MemberPattern = skipThrough
base.RestElement = (node, st, c) => c(node.argument, st, "Pattern")
base.ArrayPattern =  (node, st, c) => {
  for (let i = 0; i < node.elements.length; ++i) {
    let elt = node.elements[i]
    if (elt) c(elt, st, "Pattern")
  }
}
base.ObjectPattern = (node, st, c) => {
  for (let i = 0; i < node.properties.length; ++i)
    c(node.properties[i].value, st, "Pattern")
}

base.Expression = skipThrough
base.ThisExpression = base.Super = base.MetaProperty = ignore
base.ArrayExpression = (node, st, c) => {
  for (let i = 0; i < node.elements.length; ++i) {
    let elt = node.elements[i]
    if (elt) c(elt, st, "Expression")
  }
}
base.ObjectExpression = (node, st, c) => {
  for (let i = 0; i < node.properties.length; ++i)
    c(node.properties[i], st)
}
base.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration
base.SequenceExpression = base.TemplateLiteral = (node, st, c) => {
  for (let i = 0; i < node.expressions.length; ++i)
    c(node.expressions[i], st, "Expression")
}
base.UnaryExpression = base.UpdateExpression = (node, st, c) => {
  c(node.argument, st, "Expression")
}
base.BinaryExpression = base.LogicalExpression = (node, st, c) => {
  c(node.left, st, "Expression")
  c(node.right, st, "Expression")
}
base.AssignmentExpression = base.AssignmentPattern = (node, st, c) => {
  c(node.left, st, "Pattern")
  c(node.right, st, "Expression")
}
base.ConditionalExpression = (node, st, c) => {
  c(node.test, st, "Expression")
  c(node.consequent, st, "Expression")
  c(node.alternate, st, "Expression")
}
base.NewExpression = base.CallExpression = (node, st, c) => {
  c(node.callee, st, "Expression")
  if (node.arguments) for (let i = 0; i < node.arguments.length; ++i)
    c(node.arguments[i], st, "Expression")
}
base.MemberExpression = (node, st, c) => {
  c(node.object, st, "Expression")
  if (node.computed) c(node.property, st, "Expression")
}
base.ExportNamedDeclaration = base.ExportDefaultDeclaration = (node, st, c) => {
  if (node.declaration) c(node.declaration, st)
  if (node.source) c(node.source, st, "Expression")
}
base.ExportAllDeclaration = (node, st, c) => {
  c(node.source, st, "Expression")
}
base.ImportDeclaration = (node, st, c) => {
  for (let i = 0; i < node.specifiers.length; i++)
    c(node.specifiers[i], st)
  c(node.source, st, "Expression")
}
base.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.Literal = ignore

base.TaggedTemplateExpression = (node, st, c) => {
  c(node.tag, st, "Expression")
  c(node.quasi, st)
}
base.ClassDeclaration = base.ClassExpression = (node, st, c) => c(node, st, "Class")
base.Class = (node, st, c) => {
  if (node.id) c(node.id, st, "Pattern")
  if (node.superClass) c(node.superClass, st, "Expression")
  for (let i = 0; i < node.body.body.length; i++)
    c(node.body.body[i], st)
}
base.MethodDefinition = base.Property = (node, st, c) => {
  if (node.computed) c(node.key, st, "Expression")
  c(node.value, st, "Expression")
}
base.ComprehensionExpression = (node, st, c) => {
  for (let i = 0; i < node.blocks.length; i++)
    c(node.blocks[i].right, st, "Expression")
  c(node.body, st, "Expression")
}
<commit_msg>[walker] Walk function ids<commit_after>// AST walker module for Mozilla Parser API compatible trees

// A simple walk is one where you simply specify callbacks to be
// called on specific nodes. The last two arguments are optional. A
// simple use would be
//
//     walk.simple(myTree, {
//         Expression: function(node) { ... }
//     });
//
// to do something with all expressions. All Parser API node types
// can be used to identify node types, as well as Expression,
// Statement, and ScopeBody, which denote categories of nodes.
//
// The base argument can be used to pass a custom (recursive)
// walker, and state can be used to give this walked an initial
// state.

export function simple(node, visitors, base, state, override) {
  if (!base) base = exports.base
  ;(function c(node, st, override) {
    let type = override || node.type, found = visitors[type]
    base[type](node, st, c)
    if (found) found(node, st)
  })(node, state, override)
}

// An ancestor walk builds up an array of ancestor nodes (including
// the current node) and passes them to the callback as the state parameter.
export function ancestor(node, visitors, base, state) {
  if (!base) base = exports.base
  if (!state) state = []
  ;(function c(node, st, override) {
    let type = override || node.type, found = visitors[type]
    if (node != st[st.length - 1]) {
      st = st.slice()
      st.push(node)
    }
    base[type](node, st, c)
    if (found) found(node, st)
  })(node, state)
}

// A recursive walk is one where your functions override the default
// walkers. They can modify and replace the state parameter that's
// threaded through the walk, and can opt how and whether to walk
// their child nodes (by calling their third argument on these
// nodes).
export function recursive(node, state, funcs, base, override) {
  let visitor = funcs ? exports.make(funcs, base) : base
  ;(function c(node, st, override) {
    visitor[override || node.type](node, st, c)
  })(node, state, override)
}

function makeTest(test) {
  if (typeof test == "string")
    return type => type == test
  else if (!test)
    return () => true
  else
    return test
}

class Found {
  constructor(node, state) { this.node = node; this.state = state }
}

// Find a node with a given start, end, and type (all are optional,
// null can be used as wildcard). Returns a {node, state} object, or
// undefined when it doesn't find a matching node.
export function findNodeAt(node, start, end, test, base, state) {
  test = makeTest(test)
  if (!base) base = exports.base
  try {
    ;(function c(node, st, override) {
      let type = override || node.type
      if ((start == null || node.start <= start) &&
          (end == null || node.end >= end))
        base[type](node, st, c)
      if ((start == null || node.start == start) &&
          (end == null || node.end == end) &&
          test(type, node))
        throw new Found(node, st)
    })(node, state)
  } catch (e) {
    if (e instanceof Found) return e
    throw e
  }
}

// Find the innermost node of a given type that contains the given
// position. Interface similar to findNodeAt.
export function findNodeAround(node, pos, test, base, state) {
  test = makeTest(test)
  if (!base) base = exports.base
  try {
    ;(function c(node, st, override) {
      let type = override || node.type
      if (node.start > pos || node.end < pos) return
      base[type](node, st, c)
      if (test(type, node)) throw new Found(node, st)
    })(node, state)
  } catch (e) {
    if (e instanceof Found) return e
    throw e
  }
}

// Find the outermost matching node after a given position.
export function findNodeAfter(node, pos, test, base, state) {
  test = makeTest(test)
  if (!base) base = exports.base
  try {
    ;(function c(node, st, override) {
      if (node.end < pos) return
      let type = override || node.type
      if (node.start >= pos && test(type, node)) throw new Found(node, st)
      base[type](node, st, c)
    })(node, state)
  } catch (e) {
    if (e instanceof Found) return e
    throw e
  }
}

// Find the outermost matching node before a given position.
export function findNodeBefore(node, pos, test, base, state) {
  test = makeTest(test)
  if (!base) base = exports.base
  let max
  ;(function c(node, st, override) {
    if (node.start > pos) return
    let type = override || node.type
    if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node))
      max = new Found(node, st)
    base[type](node, st, c)
  })(node, state)
  return max
}

// Used to create a custom walker. Will fill in all missing node
// type properties with the defaults.
export function make(funcs, base) {
  if (!base) base = exports.base
  let visitor = {}
  for (var type in base) visitor[type] = base[type]
  for (var type in funcs) visitor[type] = funcs[type]
  return visitor
}

function skipThrough(node, st, c) { c(node, st) }
function ignore(_node, _st, _c) {}

// Node walkers.

export const base = {}

base.Program = base.BlockStatement = (node, st, c) => {
  for (let i = 0; i < node.body.length; ++i)
    c(node.body[i], st, "Statement")
}
base.Statement = skipThrough
base.EmptyStatement = ignore
base.ExpressionStatement = base.ParenthesizedExpression =
  (node, st, c) => c(node.expression, st, "Expression")
base.IfStatement = (node, st, c) => {
  c(node.test, st, "Expression")
  c(node.consequent, st, "Statement")
  if (node.alternate) c(node.alternate, st, "Statement")
}
base.LabeledStatement = (node, st, c) => c(node.body, st, "Statement")
base.BreakStatement = base.ContinueStatement = ignore
base.WithStatement = (node, st, c) => {
  c(node.object, st, "Expression")
  c(node.body, st, "Statement")
}
base.SwitchStatement = (node, st, c) => {
  c(node.discriminant, st, "Expression")
  for (let i = 0; i < node.cases.length; ++i) {
    let cs = node.cases[i]
    if (cs.test) c(cs.test, st, "Expression")
    for (let j = 0; j < cs.consequent.length; ++j)
      c(cs.consequent[j], st, "Statement")
  }
}
base.ReturnStatement = base.YieldExpression = (node, st, c) => {
  if (node.argument) c(node.argument, st, "Expression")
}
base.ThrowStatement = base.SpreadElement =
  (node, st, c) => c(node.argument, st, "Expression")
base.TryStatement = (node, st, c) => {
  c(node.block, st, "Statement")
  if (node.handler) {
    c(node.handler.param, st, "Pattern")
    c(node.handler.body, st, "ScopeBody")
  }
  if (node.finalizer) c(node.finalizer, st, "Statement")
}
base.WhileStatement = base.DoWhileStatement = (node, st, c) => {
  c(node.test, st, "Expression")
  c(node.body, st, "Statement")
}
base.ForStatement = (node, st, c) => {
  if (node.init) c(node.init, st, "ForInit")
  if (node.test) c(node.test, st, "Expression")
  if (node.update) c(node.update, st, "Expression")
  c(node.body, st, "Statement")
}
base.ForInStatement = base.ForOfStatement = (node, st, c) => {
  c(node.left, st, "ForInit")
  c(node.right, st, "Expression")
  c(node.body, st, "Statement")
}
base.ForInit = (node, st, c) => {
  if (node.type == "VariableDeclaration") c(node, st)
  else c(node, st, "Expression")
}
base.DebuggerStatement = ignore

base.FunctionDeclaration = (node, st, c) => c(node, st, "Function")
base.VariableDeclaration = (node, st, c) => {
  for (let i = 0; i < node.declarations.length; ++i)
    c(node.declarations[i], st)
}
base.VariableDeclarator = (node, st, c) => {
  c(node.id, st, "Pattern")
  if (node.init) c(node.init, st, "Expression")
}

base.Function = (node, st, c) => {
  if (node.id) c(node.id, st, "Pattern")
  for (let i = 0; i < node.params.length; i++)
    c(node.params[i], st, "Pattern")
  c(node.body, st, node.expression ? "ScopeExpression" : "ScopeBody")
}
// FIXME drop these node types in next major version
// (They are awkward, and in ES6 every block can be a scope.)
base.ScopeBody = (node, st, c) => c(node, st, "Statement")
base.ScopeExpression = (node, st, c) => c(node, st, "Expression")

base.Pattern = (node, st, c) => {
  if (node.type == "Identifier")
    c(node, st, "VariablePattern")
  else if (node.type == "MemberExpression")
    c(node, st, "MemberPattern")
  else
    c(node, st)
}
base.VariablePattern = ignore
base.MemberPattern = skipThrough
base.RestElement = (node, st, c) => c(node.argument, st, "Pattern")
base.ArrayPattern =  (node, st, c) => {
  for (let i = 0; i < node.elements.length; ++i) {
    let elt = node.elements[i]
    if (elt) c(elt, st, "Pattern")
  }
}
base.ObjectPattern = (node, st, c) => {
  for (let i = 0; i < node.properties.length; ++i)
    c(node.properties[i].value, st, "Pattern")
}

base.Expression = skipThrough
base.ThisExpression = base.Super = base.MetaProperty = ignore
base.ArrayExpression = (node, st, c) => {
  for (let i = 0; i < node.elements.length; ++i) {
    let elt = node.elements[i]
    if (elt) c(elt, st, "Expression")
  }
}
base.ObjectExpression = (node, st, c) => {
  for (let i = 0; i < node.properties.length; ++i)
    c(node.properties[i], st)
}
base.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration
base.SequenceExpression = base.TemplateLiteral = (node, st, c) => {
  for (let i = 0; i < node.expressions.length; ++i)
    c(node.expressions[i], st, "Expression")
}
base.UnaryExpression = base.UpdateExpression = (node, st, c) => {
  c(node.argument, st, "Expression")
}
base.BinaryExpression = base.LogicalExpression = (node, st, c) => {
  c(node.left, st, "Expression")
  c(node.right, st, "Expression")
}
base.AssignmentExpression = base.AssignmentPattern = (node, st, c) => {
  c(node.left, st, "Pattern")
  c(node.right, st, "Expression")
}
base.ConditionalExpression = (node, st, c) => {
  c(node.test, st, "Expression")
  c(node.consequent, st, "Expression")
  c(node.alternate, st, "Expression")
}
base.NewExpression = base.CallExpression = (node, st, c) => {
  c(node.callee, st, "Expression")
  if (node.arguments) for (let i = 0; i < node.arguments.length; ++i)
    c(node.arguments[i], st, "Expression")
}
base.MemberExpression = (node, st, c) => {
  c(node.object, st, "Expression")
  if (node.computed) c(node.property, st, "Expression")
}
base.ExportNamedDeclaration = base.ExportDefaultDeclaration = (node, st, c) => {
  if (node.declaration) c(node.declaration, st)
  if (node.source) c(node.source, st, "Expression")
}
base.ExportAllDeclaration = (node, st, c) => {
  c(node.source, st, "Expression")
}
base.ImportDeclaration = (node, st, c) => {
  for (let i = 0; i < node.specifiers.length; i++)
    c(node.specifiers[i], st)
  c(node.source, st, "Expression")
}
base.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.Literal = ignore

base.TaggedTemplateExpression = (node, st, c) => {
  c(node.tag, st, "Expression")
  c(node.quasi, st)
}
base.ClassDeclaration = base.ClassExpression = (node, st, c) => c(node, st, "Class")
base.Class = (node, st, c) => {
  if (node.id) c(node.id, st, "Pattern")
  if (node.superClass) c(node.superClass, st, "Expression")
  for (let i = 0; i < node.body.body.length; i++)
    c(node.body.body[i], st)
}
base.MethodDefinition = base.Property = (node, st, c) => {
  if (node.computed) c(node.key, st, "Expression")
  c(node.value, st, "Expression")
}
base.ComprehensionExpression = (node, st, c) => {
  for (let i = 0; i < node.blocks.length; i++)
    c(node.blocks[i].right, st, "Expression")
  c(node.body, st, "Expression")
}
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import Paper from '@material-ui/core/Paper'
import Typography from '@material-ui/core/Typography'
import SetV4BetaMutation from 'js/mutations/SetV4BetaMutation'
import optIntoV4Beta from 'js/utils/v4-beta-opt-in'
import { goToDashboard } from 'js/navigation/navigation'
import catImage from 'js/assets/catCharity.png'
import Button from '@material-ui/core/Button'
import localStorageMgr from 'js/utils/localstorage-mgr'
import { STORAGE_NEW_USER_IS_TAB_V4_BETA } from 'js/constants'
class SwitchToCatCharity extends React.Component {
  async switchToV4() {
    await optIntoV4Beta()
    await localStorageMgr.setItem(STORAGE_NEW_USER_IS_TAB_V4_BETA, 'true')
    await SetV4BetaMutation({
      userId: this.props.user.id,
      enabled: true,
    })
    goToDashboard()
  }
  render() {
    return (
      <Paper
        style={Object.assign(
          {},
          {
            minWidth: 250,
            maxWidth: 360,
            margin: 6,
          }
        )}
      >

            <img
              alt={`Logo for the charity Tab For Cats`}
              style={{
                cursor: 'pointer',
                maxWidth: '100%',
                minWidth: '100%',
                maxHeight: '150px',
                minHeight: '150px',
              }}
              src={catImage}
            />

          <Typography
            variant={'h5'}
            style={{
              padding: 16,
              display: 'block',
              textAlign: 'center',
            }}
          >
            Help Shelter Cats (Beta)
          </Typography>
          <Typography
            variant={'body2'}
            style={{
              boxSizing: 'border-box',
              paddingLeft: 16,
              paddingRight: 16,
              textAlign: 'center',
              display: 'block',
            }}
          >
            Turn your tabs into helping shelter cats get adopted!{' '}
            Still in beta:
            {''} some features like widgets are missing, but you can always
            switch back to Tab for a Cause.
          </Typography>

            <Button
              color={'primary'}
              variant={'contained'}
              onClick={this.switchToV4.bind(this)}
            >
              Try Tab For Cats
            </Button>

      </Paper>
    )
  }
}

SwitchToCatCharity.propTypes = { userId: PropTypes.string }

SwitchToCatCharity.defaultProps = {}

export default SwitchToCatCharity
<commit_msg>reload the page<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import Paper from '@material-ui/core/Paper'
import Typography from '@material-ui/core/Typography'
import SetV4BetaMutation from 'js/mutations/SetV4BetaMutation'
import optIntoV4Beta from 'js/utils/v4-beta-opt-in'
import catImage from 'js/assets/catCharity.png'
import Button from '@material-ui/core/Button'
import localStorageMgr from 'js/utils/localstorage-mgr'
import { STORAGE_NEW_USER_IS_TAB_V4_BETA } from 'js/constants'
class SwitchToCatCharity extends React.Component {
  async switchToV4() {
    await optIntoV4Beta()
    await localStorageMgr.setItem(STORAGE_NEW_USER_IS_TAB_V4_BETA, 'true')
    await SetV4BetaMutation({
      userId: this.props.user.id,
      enabled: true,
    })
    window.location.reload()
  }
  render() {
    return (
      <Paper
        style={Object.assign(
          {},
          {
            minWidth: 250,
            maxWidth: 360,
            margin: 6,
          }
        )}
      >

            <img
              alt={`Logo for the charity Tab For Cats`}
              style={{
                cursor: 'pointer',
                maxWidth: '100%',
                minWidth: '100%',
                maxHeight: '150px',
                minHeight: '150px',
              }}
              src={catImage}
            />

          <Typography
            variant={'h5'}
            style={{
              padding: 16,
              display: 'block',
              textAlign: 'center',
            }}
          >
            Help Shelter Cats (Beta)
          </Typography>
          <Typography
            variant={'body2'}
            style={{
              boxSizing: 'border-box',
              paddingLeft: 16,
              paddingRight: 16,
              textAlign: 'center',
              display: 'block',
            }}
          >
            Turn your tabs into helping shelter cats get adopted!{' '}
            Still in beta:
            {''} some features like widgets are missing, but you can always
            switch back to Tab for a Cause.
          </Typography>

            <Button
              color={'primary'}
              variant={'contained'}
              onClick={this.switchToV4.bind(this)}
            >
              Try Tab For Cats
            </Button>

      </Paper>
    )
  }
}

SwitchToCatCharity.propTypes = { userId: PropTypes.string }

SwitchToCatCharity.defaultProps = {}

export default SwitchToCatCharity
<|endoftext|>


<commit_before>/*
	Yarno Boelens
	Soundboard index.js
	created on: 25 06 2017
*/

var files = [
    {
        name:"flokkie_Pak ze",
        title:"Pak ze",
        author:"flokkie"
    },

    {
        name:"jos_Hey! klootzak",
        title:"Hey! Klootzak!",
        author:"jos"
    },

    {
        name:"flokkie_Hey Evert",
        title:"Hey Evert",
        author:"flokkie"
    },

    {
        name:"wim_Goed gehydrateerd blijven",
        title:"Goed gehydrateerd blijven",
        author:"wim"
    },

    {
        name:"flokkie_Koekoek",
        title:"Koekoek",
        author:"flokkie"
    },

    {
        name:"yarno_Best Reload Moment Ever",
        title:"Best Reload Moment Ever",
        author:"yarno"
    },

    {
        name:"flokkie_Twee men",
        title:"Twee men",
        author:"flokkie"
    },

    {
        name:"jelle_Kutkutkut",
        title:"Kutkutkut",
        author:"jelle"
    },

    {
        name:"flokkie_Verkeerde knopje",
        title:"Verkeerde knopje",
        author:"flokkie"
    },

    {
        name:"wim_Ha! Ik heb mijn neus dicht",
        title:"Ha! Ik heb mijn neus dicht",
        author:"wim"
    },

    {
        name:"flokkie_WTF Ricardo",
        title:"WTF Ricardo?!",
        author:"flokkie"
    },
     {
        name:"yarno_Nou nou",
        title:"Nou nou",
        author:"yarno"
    },
    {
        name:"flokkie_Wat doet ie nou",
        title:"Wat doet ie nou",
        author:"flokkie"
    },

    {
        name:"yarno_Zo jammer",
        title:"Zo jammer",
        author:"yarno"
    },

    {
        name:"flokkie_Wat doe je nou Jos",
        title:"Wat doe je nou Jos?",
        author:"flokkie"
    },
    {
        name:"wim_Hoezo ben ik nou de piemel",
        title:"Hoezo ben ik nou de piemel?",
        author:"wim"
    },

    {
        name:"flokkie_Zo fucking kansloos",
        title:"Zo fucking kansloos",
        author:"flokkie"
    },

    {
	name: "yarno_Flokkie Flokstra!",
	title: "Flokkie FLokstra!",
	author: "yarno"
    },

    {
        name:"flokkie_I'm coming for you Jos",
        title:"I'm coming for you!",
        author:"flokkie"
    },

    {
        name:"flokkie_Jaja ja",
        title:"Jaja ja",
        author:"flokkie"
    },

    {
        name:"flokkie_Are you the aardappel",
        title:"Are you the aardappel?",
        author:"flokkie"
    },

    {
	name: "yarno_Wat is dit nou weer",
	title: "Wat is dit nou weer",
	author: "yarno"
    },

    {
        name:"flokkie_I am the aardappel",
        title:"I am the aardappel",
        author:"flokkie"
    }

];

var audio = new Audio(),
    pageBody = document.getElementById('page-body');

files.forEach(function(file){
    var p = document.createElement("p"),
        text = document.createTextNode(file.title);
    p.appendChild(text);
    var div = document.createElement("div");
    div.appendChild(p);
    div.className += "soundItem " + file.author;
    div.onclick = function(){
        play(file.name);
    };
    pageBody.appendChild(div);
});

function play(file) {
    audio.pause()
    audio = new Audio('../audio/'+file+'.ogg');
    audio.play();
}
<commit_msg>[WEB] Fixed type in file name.<commit_after>/*
	Yarno Boelens
	Soundboard index.js
	created on: 25 06 2017
*/

var files = [
    {
        name:"flokkie_Pak ze",
        title:"Pak ze",
        author:"flokkie"
    },

    {
        name:"jos_Hey! Klootzak",
        title:"Hey! Klootzak!",
        author:"jos"
    },

    {
        name:"flokkie_Hey Evert",
        title:"Hey Evert",
        author:"flokkie"
    },

    {
        name:"wim_Goed gehydrateerd blijven",
        title:"Goed gehydrateerd blijven",
        author:"wim"
    },

    {
        name:"flokkie_Koekoek",
        title:"Koekoek",
        author:"flokkie"
    },

    {
        name:"yarno_Best Reload Moment Ever",
        title:"Best Reload Moment Ever",
        author:"yarno"
    },

    {
        name:"flokkie_Twee men",
        title:"Twee men",
        author:"flokkie"
    },

    {
        name:"jelle_Kutkutkut",
        title:"Kutkutkut",
        author:"jelle"
    },

    {
        name:"flokkie_Verkeerde knopje",
        title:"Verkeerde knopje",
        author:"flokkie"
    },

    {
        name:"wim_Ha! Ik heb mijn neus dicht",
        title:"Ha! Ik heb mijn neus dicht",
        author:"wim"
    },

    {
        name:"flokkie_WTF Ricardo",
        title:"WTF Ricardo?!",
        author:"flokkie"
    },
     {
        name:"yarno_Nou nou",
        title:"Nou nou",
        author:"yarno"
    },
    {
        name:"flokkie_Wat doet ie nou",
        title:"Wat doet ie nou",
        author:"flokkie"
    },

    {
        name:"yarno_Zo jammer",
        title:"Zo jammer",
        author:"yarno"
    },

    {
        name:"flokkie_Wat doe je nou Jos",
        title:"Wat doe je nou Jos?",
        author:"flokkie"
    },
    {
        name:"wim_Hoezo ben ik nou de piemel",
        title:"Hoezo ben ik nou de piemel?",
        author:"wim"
    },

    {
        name:"flokkie_Zo fucking kansloos",
        title:"Zo fucking kansloos",
        author:"flokkie"
    },

    {
	name: "yarno_Flokkie Flokstra!",
	title: "Flokkie FLokstra!",
	author: "yarno"
    },

    {
        name:"flokkie_I'm coming for you Jos",
        title:"I'm coming for you!",
        author:"flokkie"
    },

    {
        name:"flokkie_Jaja ja",
        title:"Jaja ja",
        author:"flokkie"
    },

    {
        name:"flokkie_Are you the aardappel",
        title:"Are you the aardappel?",
        author:"flokkie"
    },

    {
	name: "yarno_Wat is dit nou weer",
	title: "Wat is dit nou weer",
	author: "yarno"
    },

    {
        name:"flokkie_I am the aardappel",
        title:"I am the aardappel",
        author:"flokkie"
    }

];

var audio = new Audio(),
    pageBody = document.getElementById('page-body');

files.forEach(function(file){
    var p = document.createElement("p"),
        text = document.createTextNode(file.title);
    p.appendChild(text);
    var div = document.createElement("div");
    div.appendChild(p);
    div.className += "soundItem " + file.author;
    div.onclick = function(){
        play(file.name);
    };
    pageBody.appendChild(div);
});

function play(file) {
    audio.pause()
    audio = new Audio('../audio/'+file+'.ogg');
    audio.play();
}
<|endoftext|>


<commit_before>var fs = require("fs");

// Browsers to run on Sauce Labs
var customLaunchers = {
    sl_chrome: {
        base: "SauceLabs",
        browserName: "chrome",
        platform: "Windows 7",
        version: "37"
    },
    sl_firefox: {
        base: "SauceLabs",
        browserName: "firefox",
        platform: "Windows 7",
        version: "31"
    },
    // sl_ie_10: {
    //     base: "SauceLabs",
    //     browserName: "internet explorer",
    //     platform: "Windows 7",
    //     version: "10"
    // },
    el_opera_12: {
        base: "SauceLabs",
        browserName: "opera",
        platform: "Windows 7",
        version: "12"
    },
    sl_safari: {
        base: "SauceLabs",
        browserName: "safari",
        platform: "OS X 10.9",
        version: "7",
        deviceName: ""
    },
    sl_ie_11: {
        base: "SauceLabs",
        browserName: "internet explorer",
        platform: "Windows 7",
        version: "11"
    },
    sl_ie_8: {
        base: "SauceLabs",
        browserName: "internet explorer",
        platform: "Windows XP",
        version: "8"
    },
    // sl_ie_9: {
    //     base: "SauceLabs",
    //     browserName: "internet explorer",
    //     platform: "Windows 7",
    //     version: "9"
    // },
    // sl_ios_safari_7: {
    //     base: "SauceLabs",
    //     browserName: "iphone",
    //     platform: "OS X 10.9",
    //     version: "7.1"
    // },
    sl_android_4_4: {
        base: "SauceLabs",
        browserName: "android",
        platform: "Linux",
        version: "4.4"
    },
};

module.exports = function(config) {
    // Use ENV vars on Travis and sauce.json locally to get credentials
    if (!process.env.SAUCE_USERNAME) {
        if (!fs.existsSync("sauce.json")) {
            console.log("Create a sauce.json with your credentials based on the https://github.com/saucelabs/karma-sauce-example/blob/master/sauce-sample.json file.");
            process.exit(1);
        } else {
            process.env.SAUCE_USERNAME = require("../sauce").username;
            process.env.SAUCE_ACCESS_KEY = require("../sauce").accessKey;
        }
    }

    config.set({
        basePath: "..",
        frameworks: ["jasmine"],
        singleRun: true,

        reporters: ["saucelabs"],

        colors: true,
        captureTimeout: 180000,
        logLevel: config.LOG_INFO,

        sauceLabs: {
            testName: "better-dom",
            startConnect: !process.env.TRAVIS_JOB_NUMBER,
            tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER
        },

        // start these browsers
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: Object.keys(customLaunchers),
        customLaunchers: customLaunchers
    });
};
<commit_msg>disable ie8 because of the bug, try to enable ios<commit_after>var fs = require("fs");

// Browsers to run on Sauce Labs
var customLaunchers = {
    sl_chrome: {
        base: "SauceLabs",
        browserName: "chrome",
        platform: "Windows 7",
        version: "37"
    },
    sl_firefox: {
        base: "SauceLabs",
        browserName: "firefox",
        platform: "Windows 7",
        version: "31"
    },
    // sl_ie_10: {
    //     base: "SauceLabs",
    //     browserName: "internet explorer",
    //     platform: "Windows 7",
    //     version: "10"
    // },
    el_opera_12: {
        base: "SauceLabs",
        browserName: "opera",
        platform: "Windows 7",
        version: "12"
    },
    sl_safari: {
        base: "SauceLabs",
        browserName: "safari",
        platform: "OS X 10.9",
        version: "7",
        deviceName: ""
    },
    sl_ie_11: {
        base: "SauceLabs",
        browserName: "internet explorer",
        platform: "Windows 7",
        version: "11"
    },
    // sl_ie_8: {
    //     base: "SauceLabs",
    //     browserName: "internet explorer",
    //     platform: "Windows XP",
    //     version: "8"
    // },
    // sl_ie_9: {
    //     base: "SauceLabs",
    //     browserName: "internet explorer",
    //     platform: "Windows 7",
    //     version: "9"
    // },
    sl_ios_safari_7: {
        base: "SauceLabs",
        browserName: "iphone",
        platform: "OS X 10.9",
        version: "7.1"
    },
    sl_android_4_4: {
        base: "SauceLabs",
        browserName: "android",
        platform: "Linux",
        version: "4.4"
    },
};

module.exports = function(config) {
    // Use ENV vars on Travis and sauce.json locally to get credentials
    if (!process.env.SAUCE_USERNAME) {
        if (!fs.existsSync("sauce.json")) {
            console.log("Create a sauce.json with your credentials based on the https://github.com/saucelabs/karma-sauce-example/blob/master/sauce-sample.json file.");
            process.exit(1);
        } else {
            process.env.SAUCE_USERNAME = require("../sauce").username;
            process.env.SAUCE_ACCESS_KEY = require("../sauce").accessKey;
        }
    }

    config.set({
        basePath: "..",
        frameworks: ["jasmine"],
        singleRun: true,

        reporters: ["saucelabs"],

        colors: true,
        captureTimeout: 180000,
        logLevel: config.LOG_INFO,

        sauceLabs: {
            testName: "better-dom",
            startConnect: !process.env.TRAVIS_JOB_NUMBER,
            tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER
        },

        // start these browsers
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: Object.keys(customLaunchers),
        customLaunchers: customLaunchers
    });
};
<|endoftext|>


<commit_before>/* eslint-env node */
var webpack = require('webpack');
var path = require('path');

module.exports = {

  context: __dirname,
  entry: [
    './app/app.jsx',
    'webpack-dev-server/client?http://localhost:8899',
    'webpack/hot/only-dev-server'
  ],
  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, '/dist'),
    publicPath: 'http://localhost:8899/assets/dist/',
    chunkFilename: '[id].chunk.js'
  },

  resolve: {
    modulesDirectories: [ 'node_modules', 'bower_components' ],
    alias: {
      'setup': path.join(__dirname, 'app/project-setup'),
      'actions': path.join(__dirname, 'app/actions'),
      'screens': path.join(__dirname, 'app/screens'),
      'stores': path.join(__dirname, 'app/stores'),
      'common': path.join(__dirname, 'app/common'),
      'mixins': path.join(__dirname, 'app/common/mixins'),
      'helpers': path.join(__dirname, 'app/common/helpers'),
      'services': path.join(__dirname, 'app/common/services')
    },
    extensions: [ '', '.js', '.jsx' ]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        loaders: [ 'react-hot', 'babel' ],
        exclude: /(node_modules|bower_components)/
      },
      // style! attaches the css to the DOM automatically,
      // which is not optimal for components
      {
        test: /project-setup\/.*\.scss$/,
        loader: 'css!autoprefixer!sass?' +
          'includePaths[]=' + path.join(__dirname, 'app/project-setup') +
          '&includePaths[]=' + path.join(__dirname, 'bower_components/foundation/scss')
      },
      {
        test: /\/(screens|common)\/.*\.scss$/,
        loader: 'style/useable!css!autoprefixer!sass?' +
          'includePaths[]=' + path.join(__dirname, 'app/project-setup') +
          '&includePaths[]=' + path.join(__dirname, 'bower_components/foundation/scss')
      },
      { test: /\.(png|jpg)$/, loader: 'url?limit=32768' },
      { test: /\.jade$/, loader: 'jade' },
      {
        test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        loader: 'url?limit=10000&minetype=application/font-woff'
      },
      { test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url' }
    ],
    noParse: []
  },
  externals: {},
  devtool: 'eval'
};
<commit_msg>Undo erroneous commit with config<commit_after>/* eslint-env node */
var webpack = require('webpack');
var path = require('path');

module.exports = {

  context: __dirname,
  entry: [
    './app/app.jsx',
    'webpack-dev-server/client?http://localhost:8899',
    'webpack/hot/only-dev-server'
  ],
  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, '/dist'),
    publicPath: 'http://localhost:8899/assets/dist/',
    chunkFilename: '[id].chunk.js'
  },

  resolve: {
    modulesDirectories: [ 'node_modules', 'bower_components' ],
    alias: {
      'setup': path.join(__dirname, 'app/project-setup'),
      'actions': path.join(__dirname, 'app/actions'),
      'screens': path.join(__dirname, 'app/screens'),
      'stores': path.join(__dirname, 'app/stores'),
      'common': path.join(__dirname, 'app/common'),
      'mixins': path.join(__dirname, 'app/common/mixins'),
      'helpers': path.join(__dirname, 'app/common/helpers'),
      'services': path.join(__dirname, 'app/common/services')
    },
    extensions: [ '', '.js', '.jsx' ]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        loaders: [ 'react-hot', 'babel' ],
        exclude: /(node_modules|bower_components)/
      },
      // style! attaches the css to the DOM automatically,
      // which is not optimal for components
      {
        test: /project-setup\/.*\.scss$/,
        loader: 'css!autoprefixer!sass?' +
          'includePaths[]=' + path.join(__dirname, 'app/project-setup') +
          '&includePaths[]=' + path.join(__dirname, 'bower_components/foundation/scss')
      },
      {
        test: /\/(screens|common)\/.*\.scss$/,
        loader: 'style/useable!css!autoprefixer!sass?' +
          'includePaths[]=' + path.join(__dirname, 'app/project-setup') +
          '&includePaths[]=' + path.join(__dirname, 'bower_components/foundation/scss')
      },
      { test: /\.(png|jpg)$/, loader: 'url?limit=32768' },
      { test: /\.jade$/, loader: 'jade' },
      {
        test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        loader: 'url?limit=10000&mimetype=application/font-woff'
      },
      { test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url?limit=10000' }
    ],
    noParse: []
  },
  externals: {},
  devtool: 'eval'
};
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import { Match } from 'meteor/check';
import { Mongo } from 'meteor/mongo';
import { MongoID } from 'meteor/mongo-id';
import { EventEmitter } from 'events';

const validMongoId = Match.OneOf(String, Mongo.ObjectID);

/*
  This class describes something like Subscription in
  meteor/meteor/packages/ddp/livedata_server.js, but instead of sending
  over a socket it just collects data.
*/
PublicationCollector = class PublicationCollector extends EventEmitter {

  constructor(opts = {}) {
    super();
    check(opts.userId, Match.Optional(String));
    check(opts.delayInMs, Match.Optional(Match.Integer));

    // Object where the keys are collection names, and then the keys are _ids
    this._documents = {};
    this.unblock = () => {};
    this.userId = opts.userId;
    this._idFilter = {
      idStringify: MongoID.idStringify,
      idParse: MongoID.idParse
    };
    this._isDeactivated = () => {};

    this.delayInMs = opts.delayInMs;
  }

  collect(name, ...args) {
    let callback;
    // extracts optional callback from latest argument
    if (_.isFunction(args[args.length - 1])) {
      callback = args.pop();
    }

    const completeCollecting = (collections) => {
      if (_.isFunction(callback)) {
        callback(collections);
      }

      // stop the subscription
      this.stop();
    };

    // adds a one time listener function for the "ready" event
    this.once('ready', (collections) => {
      if (this.delayInMs) {
        Meteor.setTimeout(() => {
          completeCollecting(this._generateResponse());
        }, this.delayInMs);
      } else {
        // immediately complete
        completeCollecting(collections);
      }
    });

    const handler = Meteor.server.publish_handlers[name];
    const result = handler.call(this, ...args);

    this._publishHandlerResult(result);
  }

  /**
   * Reproduces "_publishHandlerResult" processing
   * @see {@link https://github.com/meteor/meteor/blob/master/packages/ddp-server/livedata_server.js#L1045}
   */
  _publishHandlerResult(res) {
    const cursors = [];

    // publication handlers can return a collection cursor, an array of cursors or nothing.
    if (this._isCursor(res)) {
      cursors.push(res);
    } else if (Array.isArray(res)) {
      // check all the elements are cursors
      const areCursors = res.reduce((valid, cur) => valid && this._isCursor(cur), true);
      if (!areCursors) {
        this.error(new Error('Publish function returned an array of non-Cursors'));
        return;
      }
      // find duplicate collection names
      const collectionNames = {};
      for (let i = 0; i < res.length; ++i) {
        const collectionName = res[i]._getCollectionName();
        if ({}.hasOwnProperty.call(collectionNames, collectionName)) {
          this.error(new Error(
            `Publish function returned multiple cursors for collection ${collectionName}`
          ));
          return;
        }
        collectionNames[collectionName] = true;
        cursors.push(res[i]);
      }
    }

    if (cursors.length > 0) {
      try {
        // for each cursor we call _publishCursor method which starts observing the cursor and
        // publishes the results.
        cursors.forEach((cur) => {
          this._ensureCollectionInRes(cur._getCollectionName());
          cur._publishCursor(this);
        });
      } catch (e) {
        this.error(e);
        return;
      }
      // mark subscription as ready (_publishCursor does NOT call ready())
      this.ready();
    } else if (res) {
      // truthy values other than cursors or arrays are probably a
      // user mistake (possible returning a Mongo document via, say,
      // `coll.findOne()`).
      this.error(new Error('Publish function can only return a Cursor or an array of Cursors'));
    }
  }

  added(collection, id, fields) {
    check(collection, String);
    check(id, validMongoId);

    this._ensureCollectionInRes(collection);

    // Make sure to ignore the _id in fields
    const addedDocument = _.extend({_id: id}, _.omit(fields, '_id'));
    this._documents[collection][id] = addedDocument;
  }

  changed(collection, id, fields) {
    check(collection, String);
    check(id, validMongoId);

    this._ensureCollectionInRes(collection);

    const existingDocument = this._documents[collection][id];
    const fieldsNoId = _.omit(fields, '_id');

    if (existingDocument) {
      _.extend(existingDocument, fieldsNoId);

      // Delete all keys that were undefined in fields (except _id)
      _.forEach(fields, (value, key) => {
        if (value === undefined) {
          delete existingDocument[key];
        }
      });
    }
  }

  removed(collection, id) {
    check(collection, String);
    check(id, validMongoId);

    this._ensureCollectionInRes(collection);

    delete this._documents[collection][id];

    if (_.isEmpty(this._documents[collection])) {
      delete this._documents[collection];
    }
  }

  ready() {
    // Synchronously calls each of the listeners registered for the "ready" event
    this.emit('ready', this._generateResponse());
  }

  onStop(callback) {
    // Adds a one time listener function for the "stop" event
    this.once('stop', callback);
  }

  stop() {
    // Synchronously calls each of the listeners registered for the "stop" event
    this.emit('stop');
  }

  error(error) {
    throw error;
  }

  _isCursor(c) {
    return c && c._publishCursor;
  }

  _ensureCollectionInRes(collection) {
    this._documents[collection] = this._documents[collection] || {};
  }

  _generateResponse() {
    const output = {};

    _.forEach(this._documents, (documents, collectionName) => {
      output[collectionName] = _.values(documents);
    });

    return output;
  }
};
<commit_msg>Explain use of _generateResponse()<commit_after>import { Meteor } from 'meteor/meteor';
import { Match } from 'meteor/check';
import { Mongo } from 'meteor/mongo';
import { MongoID } from 'meteor/mongo-id';
import { EventEmitter } from 'events';

const validMongoId = Match.OneOf(String, Mongo.ObjectID);

/*
  This class describes something like Subscription in
  meteor/meteor/packages/ddp/livedata_server.js, but instead of sending
  over a socket it just collects data.
*/
PublicationCollector = class PublicationCollector extends EventEmitter {

  constructor(opts = {}) {
    super();
    check(opts.userId, Match.Optional(String));
    check(opts.delayInMs, Match.Optional(Match.Integer));

    // Object where the keys are collection names, and then the keys are _ids
    this._documents = {};
    this.unblock = () => {};
    this.userId = opts.userId;
    this._idFilter = {
      idStringify: MongoID.idStringify,
      idParse: MongoID.idParse
    };
    this._isDeactivated = () => {};

    this.delayInMs = opts.delayInMs;
  }

  collect(name, ...args) {
    let callback;
    // extracts optional callback from latest argument
    if (_.isFunction(args[args.length - 1])) {
      callback = args.pop();
    }

    const completeCollecting = (collections) => {
      if (_.isFunction(callback)) {
        callback(collections);
      }

      // stop the subscription
      this.stop();
    };

    // adds a one time listener function for the "ready" event
    this.once('ready', (collections) => {
      if (this.delayInMs) {
        Meteor.setTimeout(() => {
          // collections is out of date, so we need to regenerate
          collections = this._generateResponse();
          completeCollecting(collections);
        }, this.delayInMs);
      } else {
        // immediately complete
        completeCollecting(collections);
      }
    });

    const handler = Meteor.server.publish_handlers[name];
    const result = handler.call(this, ...args);

    this._publishHandlerResult(result);
  }

  /**
   * Reproduces "_publishHandlerResult" processing
   * @see {@link https://github.com/meteor/meteor/blob/master/packages/ddp-server/livedata_server.js#L1045}
   */
  _publishHandlerResult(res) {
    const cursors = [];

    // publication handlers can return a collection cursor, an array of cursors or nothing.
    if (this._isCursor(res)) {
      cursors.push(res);
    } else if (Array.isArray(res)) {
      // check all the elements are cursors
      const areCursors = res.reduce((valid, cur) => valid && this._isCursor(cur), true);
      if (!areCursors) {
        this.error(new Error('Publish function returned an array of non-Cursors'));
        return;
      }
      // find duplicate collection names
      const collectionNames = {};
      for (let i = 0; i < res.length; ++i) {
        const collectionName = res[i]._getCollectionName();
        if ({}.hasOwnProperty.call(collectionNames, collectionName)) {
          this.error(new Error(
            `Publish function returned multiple cursors for collection ${collectionName}`
          ));
          return;
        }
        collectionNames[collectionName] = true;
        cursors.push(res[i]);
      }
    }

    if (cursors.length > 0) {
      try {
        // for each cursor we call _publishCursor method which starts observing the cursor and
        // publishes the results.
        cursors.forEach((cur) => {
          this._ensureCollectionInRes(cur._getCollectionName());
          cur._publishCursor(this);
        });
      } catch (e) {
        this.error(e);
        return;
      }
      // mark subscription as ready (_publishCursor does NOT call ready())
      this.ready();
    } else if (res) {
      // truthy values other than cursors or arrays are probably a
      // user mistake (possible returning a Mongo document via, say,
      // `coll.findOne()`).
      this.error(new Error('Publish function can only return a Cursor or an array of Cursors'));
    }
  }

  added(collection, id, fields) {
    check(collection, String);
    check(id, validMongoId);

    this._ensureCollectionInRes(collection);

    // Make sure to ignore the _id in fields
    const addedDocument = _.extend({_id: id}, _.omit(fields, '_id'));
    this._documents[collection][id] = addedDocument;
  }

  changed(collection, id, fields) {
    check(collection, String);
    check(id, validMongoId);

    this._ensureCollectionInRes(collection);

    const existingDocument = this._documents[collection][id];
    const fieldsNoId = _.omit(fields, '_id');

    if (existingDocument) {
      _.extend(existingDocument, fieldsNoId);

      // Delete all keys that were undefined in fields (except _id)
      _.forEach(fields, (value, key) => {
        if (value === undefined) {
          delete existingDocument[key];
        }
      });
    }
  }

  removed(collection, id) {
    check(collection, String);
    check(id, validMongoId);

    this._ensureCollectionInRes(collection);

    delete this._documents[collection][id];

    if (_.isEmpty(this._documents[collection])) {
      delete this._documents[collection];
    }
  }

  ready() {
    // Synchronously calls each of the listeners registered for the "ready" event
    this.emit('ready', this._generateResponse());
  }

  onStop(callback) {
    // Adds a one time listener function for the "stop" event
    this.once('stop', callback);
  }

  stop() {
    // Synchronously calls each of the listeners registered for the "stop" event
    this.emit('stop');
  }

  error(error) {
    throw error;
  }

  _isCursor(c) {
    return c && c._publishCursor;
  }

  _ensureCollectionInRes(collection) {
    this._documents[collection] = this._documents[collection] || {};
  }

  _generateResponse() {
    const output = {};

    _.forEach(this._documents, (documents, collectionName) => {
      output[collectionName] = _.values(documents);
    });

    return output;
  }
};
<|endoftext|>


<commit_before>/* eslint-disable import/no-dynamic-require */
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const helmet = require('helmet');

const rootPath = path.join(process.cwd());

const app = express();

// Security
app.use(helmet());
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'", 'https://*'],
    styleSrc: ["'self'", "'unsafe-inline'", 'https://*'],
    scriptSrc: ["'self'", "'unsafe-eval'", "'unsafe-inline'", 'https://*'],
    imgSrc: ["'self'", 'data:', 'https://*'],
    formAction: ["'self'", 'https://*']
  }
}));
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
// Serving assets from public folder
app.use(express.static(path.join(rootPath, 'public')));

// Proxy for iframes
require('./routes/iframeProxy')(app);
// Url shorter
require('./routes/shortUrl')(app);
// Twitter feed
require('./routes/twitterFeed')(app);
// Contact mail
require('./routes/contact')(app);

// Load environment config
require(path.join(__dirname, 'environments', process.env.NODE_ENV || 'development'))(app);

module.exports = app;
<commit_msg>added font policy<commit_after>/* eslint-disable import/no-dynamic-require */
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const helmet = require('helmet');

const rootPath = path.join(process.cwd());

const app = express();

// Security
app.use(helmet());
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'", 'https://*'],
    styleSrc: ["'self'", "'unsafe-inline'", 'https://*'],
    scriptSrc: ["'self'", "'unsafe-eval'", "'unsafe-inline'", 'https://*'],
    fontSrc: ["'self'", 'data:', 'https://*'],
    imgSrc: ["'self'", 'data:', 'https://*'],
    formAction: ["'self'", 'https://*']
  }
}));
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
// Serving assets from public folder
app.use(express.static(path.join(rootPath, 'public')));

// Proxy for iframes
require('./routes/iframeProxy')(app);
// Url shorter
require('./routes/shortUrl')(app);
// Twitter feed
require('./routes/twitterFeed')(app);
// Contact mail
require('./routes/contact')(app);

// Load environment config
require(path.join(__dirname, 'environments', process.env.NODE_ENV || 'development'))(app);

module.exports = app;
<|endoftext|>


<commit_before>'use strict';

var WaveSurfer = {
    defaultParams: {
        height        : 128,
        waveColor     : '#999',
        progressColor : '#555',
        cursorColor   : '#333',
        cursorWidth   : 1,
        markerWidth   : 1,
        skipLength    : 2,
        minPxPerSec   : 1,
        samples       : 3,
        pixelRatio    : window.devicePixelRatio,
        fillParent    : true,
        scrollParent  : false,
        normalize     : false,
        audioContext  : null,
        container     : null,
        renderer      : 'Canvas'
    },

    init: function (params) {
        // Extract relevant parameters (or defaults)
        this.params = WaveSurfer.util.extend({}, this.defaultParams, params);

        // Marker objects
        this.markers = {};
        this.once('marked', this.bindMarks.bind(this));

        // Used to save the current volume when muting so we can
        // restore once unmuted
        this.savedVolume = 0;
        // The current muted state
        this.isMuted = false;

        this.createBackend();
        this.createDrawer();
    },

    createDrawer: function () {
        var my = this;

        this.drawer = Object.create(WaveSurfer.Drawer[this.params.renderer]);
        this.drawer.init(this.params);

        this.drawer.on('redraw', function () {
            my.drawBuffer();
        });

        this.drawer.on('click', function (progress) {
            my.seekTo(progress);
        });

        this.on('progress', function (progress) {
            my.drawer.progress(progress);
        });
    },

    createBackend: function () {
        var my = this;

        this.backend = Object.create(WaveSurfer.WebAudio);

        this.backend.on('play', function () {
            my.fireEvent('play');
        });

        this.on('play', function () {
            my.restartAnimationLoop();
        });

        this.backend.init(this.params);
    },

    restartAnimationLoop: function () {
        var my = this;
        var requestFrame = window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame;
        var frame = function () {
            my.fireEvent('progress', my.backend.getPlayedPercents());
            if (!my.backend.isPaused()) {
                requestFrame(frame);
            }
        };
        frame();
    },

    playAt: function (percents) {
        this.backend.play(this.backend.getDuration() * percents);
    },

    play: function () {
        this.backend.play();
    },

    pause: function () {
        this.backend.pause();
    },

    playPause: function () {
        this.backend.isPaused() ? this.play() : this.pause();
    },

    skipBackward: function (seconds) {
        this.skip(seconds || -this.params.skipLength);
    },

    skipForward: function (seconds) {
        this.skip(seconds || this.params.skipLength);
    },

    skip: function (offset) {
        var timings = this.timings(offset);
        var progress = timings[0] / timings[1];

        this.seekTo(progress);
    },

    seekTo: function (progress) {
        var paused = this.backend.isPaused();
        this.playAt(progress);
        if (paused) {
            this.pause();
        }
        this.fireEvent('seek', progress);
    },

    stop: function () {
        this.playAt(0);
        this.pause();
        this.drawer.progress(0);
    },

    /**
     * Set the playback volume.
     *
     * @param {Number} newVolume A value between 0 and 1, 0 being no
     * volume and 1 being full volume.
     */
    setVolume: function (newVolume) {
        this.backend.setVolume(newVolume);
    },

    /**
     * Toggle the volume on and off. It not currenly muted it will
     * save the current volume value and turn the volume off.
     * If currently muted then it will restore the volume to the saved
     * value, and then rest the saved value.
     */
    toggleMute: function () {
        if (this.isMuted) {
            // If currently muted then restore to the saved volume
            // and update the mute properties
            this.backend.setVolume(this.savedVolume);
            this.isMuted = false;
        } else {
            // If currently not muted then save current volume,
            // turn off the volume and update the mute properties
            this.savedVolume = this.backend.getVolume();
            this.backend.setVolume(0);
            this.isMuted = true;
        }
    },

    mark: function (options) {
        if (options.id && options.id in this.markers) {
            return this.markers[options.id].update(options);
        }

        var my = this;

        var opts = WaveSurfer.util.extend({
            id: WaveSurfer.util.getId(),
            position: this.backend.getCurrentTime(),
            width: this.params.markerWidth
        }, options);

        var marker = Object.create(WaveSurfer.Mark);

        marker.on('update', function () {
            var duration = my.backend.getDuration() || 1;
            if (null == marker.position) {
                marker.position = marker.percentage * duration;
            }
            // validate percentage
            marker.percentage = marker.position / duration;
            my.markers[marker.id] = marker;

            // redraw marker
            my.drawer.addMark(marker);
        });

        marker.on('remove', function () {
            my.drawer.removeMark(marker);
            delete my.markers[marker.id];
        });

        this.fireEvent('marked', marker);

        return marker.init(opts);
    },

    redrawMarks: function () {
        Object.keys(this.markers).forEach(function (id) {
            var marker = this.markers[id];
            this.drawer.addMark(marker);
        }, this);
    },

    clearMarks: function () {
        Object.keys(this.markers).forEach(function (id) {
            this.markers[id].remove();
        }, this);
    },

    timings: function (offset) {
        var position = this.backend.getCurrentTime() || 0;
        var duration = this.backend.getDuration() || 1;
        position = Math.max(0, Math.min(duration, position + (offset || 0)));
        return [ position, duration ];
    },

    drawBuffer: function () {
        this.drawer.clear();
        this.drawer.progress(this.backend.getPlayedPercents());
        this.redrawMarks();

        if (this.params.fillParent && !this.params.scrollParent) {
            var length = this.drawer.getWidth();
        } else {
            length = this.backend.getDuration() * this.params.minPxPerSec;
        }

        var peaks = this.backend.getPeaks(length);
        this.drawer.drawPeaks(peaks, length);
    },

    loadBuffer: function (data) {
        var my = this;
        this.pause();
        this.backend.loadBuffer(data, function () {
            my.clearMarks();
            my.drawBuffer();
            my.fireEvent('ready');
        }, function () {
            my.fireEvent('error', 'Error decoding audio');
        });
    },

    onProgress: function (e) {
        if (e.lengthComputable) {
            var percentComplete = e.loaded / e.total;
        } else {
            // Approximate progress with an asymptotic
            // function, and assume downloads in the 1-3 MB range.
            percentComplete = e.loaded / (e.loaded + 1000000);
        }
        this.fireEvent('loading', Math.round(percentComplete * 100), e.target);
    },

    /**
     * Loads an audio file via XHR.
     */
    load: function (url) {
        var my = this;
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.send();
        xhr.responseType = 'arraybuffer';
        xhr.addEventListener('progress', function (e) {
            my.onProgress(e);
        });
        xhr.addEventListener('load', function (e) {
            if (200 == xhr.status) {
                my.loadBuffer(xhr.response);
            } else {
                my.fireEvent('error', 'Server response: ' + xhr.statusText);
            }
        });
        xhr.addEventListener('error', function (e) {
            my.fireEvent('error', 'Error loading audio');
        });
        this.empty();
    },

    /**
     * Listens to drag'n'drop.
     * @param {HTMLElement|String} dropTarget Element or selector.
     */
    bindDragNDrop: function (dropTarget) {
        var my = this;

        // Create file reader
        var reader = new FileReader();
        reader.addEventListener('progress', function (e) {
            my.onProgress(e);
        });
        reader.addEventListener('load', function (e) {
            my.loadBuffer(e.target.result);
        });
        reader.addEventListener('error', function () {
            my.fireEvent('error', 'Error reading file');
        });

        // Bind drop event
        if (typeof dropTarget == 'string') {
            dropTarget = document.querySelector(dropTarget);
        }
        var dropActiveCl = 'wavesurfer-dragover';
        dropTarget.addEventListener('drop', function (e) {
            e.stopPropagation();
            e.preventDefault();
            dropTarget.classList.remove(dropActiveCl);
            var file = e.dataTransfer.files[0];
            if (file) {
                my.empty();
                reader.readAsArrayBuffer(file);
            } else {
                my.fireEvent('error', 'Not a file');
            }
        });
        // Bind dragover & dragleave
        dropTarget.addEventListener('dragover', function (e) {
            e.stopPropagation();
            e.preventDefault();
            dropTarget.classList.add(dropActiveCl);
        });
        dropTarget.addEventListener('dragleave', function (e) {
            e.stopPropagation();
            e.preventDefault();
            dropTarget.classList.remove(dropActiveCl);
        });
    },

    bindMarks: function () {
        var my = this;
        var prevTime = 0;

        this.backend.on('play', function () {
            // Reset marker events
            Object.keys(my.markers).forEach(function (id) {
                my.markers[id].played = false;
            });
        });

        this.backend.on('audioprocess', function (time) {
            Object.keys(my.markers).forEach(function (id) {
                var marker = my.markers[id];
                if (!marker.played) {
                    if (marker.position <= time && marker.position >= prevTime) {
                        // Prevent firing the event more than once per playback
                        marker.played = true;

                        my.fireEvent('mark', marker);
                        marker.fireEvent('reached');
                    }
                }
            });
            prevTime = time;
        });
    },

    empty: function () {
        this.pause();
        this.clearMarks();
        this.backend.loadEmpty();
        this.drawer.drawPeaks({ length: this.drawer.getWidth() }, 0);
    }
};

/* Mark */
WaveSurfer.Mark = {
    defaultParams: {
        id: null,
        position: 0,
        percentage: 0,
        width: 1,
        color: '#333'
    },

    init: function (options) {
        return this.update(
            WaveSurfer.util.extend({}, this.defaultParams, options)
        );
    },

    getTitle: function () {
        var d = new Date(this.position * 1000);
        return d.getMinutes() + ':' + d.getSeconds();
    },

    update: function (options) {
        Object.keys(options).forEach(function (key) {
            if (key in this.defaultParams) {
                this[key] = options[key];
            }
        }, this);

        // If percentage is specified, but position is undefined,
        // let the subscribers to recalculate the position
        if (null == options.position && null != options.percentage) {
            this.position = null;
        }

        this.fireEvent('update');
        return this;
    },

    remove: function () {
        this.fireEvent('remove');
    }
};

/* Observer */
WaveSurfer.Observer = {
    on: function (event, fn) {
        if (!this.handlers) { this.handlers = {}; }

        var handlers = this.handlers[event];
        if (!handlers) {
            handlers = this.handlers[event] = [];
        }
        handlers.push(fn);
    },

    un: function (event, fn) {
        if (!this.handlers) { return; }

        var handlers = this.handlers[event];
        if (handlers) {
            if (fn) {
                for (var i = handlers.length - 1; i >= 0; i--) {
                    if (handlers[i] == fn) {
                        handlers.splice(i, 1);
                    }
                }
            } else {
                handlers.length = 0;
            }
        }
    },

    once: function (event, handler) {
        var fn = (function () {
            handler();
            this.un(event, fn);
        }).bind(this);
        this.on(event, fn);
    },

    fireEvent: function (event) {
        if (!this.handlers) { return; }

        var handlers = this.handlers[event];
        var args = Array.prototype.slice.call(arguments, 1);
        if (handlers) {
            for (var i = 0, len = handlers.length; i < len; i += 1) {
                handlers[i].apply(null, args);
            }
        }
    }
};

/* Common utilities */
WaveSurfer.util = {
    extend: function (dest) {
        var sources = Array.prototype.slice.call(arguments, 1);
        sources.forEach(function (source) {
            if (source != null) {
                Object.keys(source).forEach(function (key) {
                    dest[key] = source[key];
                });
            }
        });
        return dest;
    },

    getId: function () {
        return 'wavesurfer_' + Math.random().toString(32).substring(2);
    },

    max: function (values) {
        var max = -Infinity;
        for (var i = 0, len = values.length; i < len; i++) {
            var val = values[i];
            if (val > max) { max = val; }
        }
        return max;
    }
};

WaveSurfer.util.extend(WaveSurfer, WaveSurfer.Observer);
WaveSurfer.util.extend(WaveSurfer.Mark, WaveSurfer.Observer);
<commit_msg>Add a unregisteredEvent method to clean registeredEvent, to allow gabage collection of waveform instance<commit_after>'use strict';

var WaveSurfer = {
    defaultParams: {
        height        : 128,
        waveColor     : '#999',
        progressColor : '#555',
        cursorColor   : '#333',
        cursorWidth   : 1,
        markerWidth   : 1,
        skipLength    : 2,
        minPxPerSec   : 1,
        samples       : 3,
        pixelRatio    : window.devicePixelRatio,
        fillParent    : true,
        scrollParent  : false,
        normalize     : false,
        audioContext  : null,
        container     : null,
        renderer      : 'Canvas'
    },

    init: function (params) {
        // Extract relevant parameters (or defaults)
        this.params = WaveSurfer.util.extend({}, this.defaultParams, params);

        // Marker objects
        this.markers = {};
        this.once('marked', this.bindMarks.bind(this));

        // Used to save the current volume when muting so we can
        // restore once unmuted
        this.savedVolume = 0;
        // The current muted state
        this.isMuted = false;

        this.createBackend();
        this.createDrawer();
    },

    createDrawer: function () {
        var my = this;

        this.drawer = Object.create(WaveSurfer.Drawer[this.params.renderer]);
        this.drawer.init(this.params);

        this.drawer.on('redraw', function () {
            my.drawBuffer();
        });

        this.drawer.on('click', function (progress) {
            my.seekTo(progress);
        });

        this.on('progress', function (progress) {
            my.drawer.progress(progress);
        });
    },

    createBackend: function () {
        var my = this;

        this.backend = Object.create(WaveSurfer.WebAudio);

        this.backend.on('play', function () {
            my.fireEvent('play');
        });

        this.on('play', function () {
            my.restartAnimationLoop();
        });

        this.backend.init(this.params);
    },

    restartAnimationLoop: function () {
        var my = this;
        var requestFrame = window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame;
        var frame = function () {
            my.fireEvent('progress', my.backend.getPlayedPercents());
            if (!my.backend.isPaused()) {
                requestFrame(frame);
            }
        };
        frame();
    },

    playAt: function (percents) {
        this.backend.play(this.backend.getDuration() * percents);
    },

    play: function () {
        this.backend.play();
    },

    pause: function () {
        this.backend.pause();
    },

    playPause: function () {
        this.backend.isPaused() ? this.play() : this.pause();
    },

    skipBackward: function (seconds) {
        this.skip(seconds || -this.params.skipLength);
    },

    skipForward: function (seconds) {
        this.skip(seconds || this.params.skipLength);
    },

    skip: function (offset) {
        var timings = this.timings(offset);
        var progress = timings[0] / timings[1];

        this.seekTo(progress);
    },

    seekTo: function (progress) {
        var paused = this.backend.isPaused();
        this.playAt(progress);
        if (paused) {
            this.pause();
        }
        this.fireEvent('seek', progress);
    },

    stop: function () {
        this.playAt(0);
        this.pause();
        this.drawer.progress(0);
    },

    /**
     * Set the playback volume.
     *
     * @param {Number} newVolume A value between 0 and 1, 0 being no
     * volume and 1 being full volume.
     */
    setVolume: function (newVolume) {
        this.backend.setVolume(newVolume);
    },

    /**
     * Toggle the volume on and off. It not currenly muted it will
     * save the current volume value and turn the volume off.
     * If currently muted then it will restore the volume to the saved
     * value, and then rest the saved value.
     */
    toggleMute: function () {
        if (this.isMuted) {
            // If currently muted then restore to the saved volume
            // and update the mute properties
            this.backend.setVolume(this.savedVolume);
            this.isMuted = false;
        } else {
            // If currently not muted then save current volume,
            // turn off the volume and update the mute properties
            this.savedVolume = this.backend.getVolume();
            this.backend.setVolume(0);
            this.isMuted = true;
        }
    },

    mark: function (options) {
        if (options.id && options.id in this.markers) {
            return this.markers[options.id].update(options);
        }

        var my = this;

        var opts = WaveSurfer.util.extend({
            id: WaveSurfer.util.getId(),
            position: this.backend.getCurrentTime(),
            width: this.params.markerWidth
        }, options);

        var marker = Object.create(WaveSurfer.Mark);

        marker.on('update', function () {
            var duration = my.backend.getDuration() || 1;
            if (null == marker.position) {
                marker.position = marker.percentage * duration;
            }
            // validate percentage
            marker.percentage = marker.position / duration;
            my.markers[marker.id] = marker;

            // redraw marker
            my.drawer.addMark(marker);
        });

        marker.on('remove', function () {
            my.drawer.removeMark(marker);
            delete my.markers[marker.id];
        });

        this.fireEvent('marked', marker);

        return marker.init(opts);
    },

    redrawMarks: function () {
        Object.keys(this.markers).forEach(function (id) {
            var marker = this.markers[id];
            this.drawer.addMark(marker);
        }, this);
    },

    clearMarks: function () {
        Object.keys(this.markers).forEach(function (id) {
            this.markers[id].remove();
        }, this);
    },

    timings: function (offset) {
        var position = this.backend.getCurrentTime() || 0;
        var duration = this.backend.getDuration() || 1;
        position = Math.max(0, Math.min(duration, position + (offset || 0)));
        return [ position, duration ];
    },

    drawBuffer: function () {
        this.drawer.clear();
        this.drawer.progress(this.backend.getPlayedPercents());
        this.redrawMarks();

        if (this.params.fillParent && !this.params.scrollParent) {
            var length = this.drawer.getWidth();
        } else {
            length = this.backend.getDuration() * this.params.minPxPerSec;
        }

        var peaks = this.backend.getPeaks(length);
        this.drawer.drawPeaks(peaks, length);
    },

    loadBuffer: function (data) {
        var my = this;
        this.pause();
        this.backend.loadBuffer(data, function () {
            my.clearMarks();
            my.drawBuffer();
            my.fireEvent('ready');
        }, function () {
            my.fireEvent('error', 'Error decoding audio');
        });
    },

    onProgress: function (e) {
        if (e.lengthComputable) {
            var percentComplete = e.loaded / e.total;
        } else {
            // Approximate progress with an asymptotic
            // function, and assume downloads in the 1-3 MB range.
            percentComplete = e.loaded / (e.loaded + 1000000);
        }
        this.fireEvent('loading', Math.round(percentComplete * 100), e.target);
    },

    /**
     * Loads an audio file via XHR.
     */
    load: function (url) {
        var my = this;
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.send();
        xhr.responseType = 'arraybuffer';
        xhr.addEventListener('progress', function (e) {
            my.onProgress(e);
        });
        xhr.addEventListener('load', function (e) {
            if (200 == xhr.status) {
                my.loadBuffer(xhr.response);
            } else {
                my.fireEvent('error', 'Server response: ' + xhr.statusText);
            }
        });
        xhr.addEventListener('error', function (e) {
            my.fireEvent('error', 'Error loading audio');
        });
        this.empty();
    },

    /**
     * Listens to drag'n'drop.
     * @param {HTMLElement|String} dropTarget Element or selector.
     */
    bindDragNDrop: function (dropTarget) {
        var my = this;

        // Create file reader
        var reader = new FileReader();
        reader.addEventListener('progress', function (e) {
            my.onProgress(e);
        });
        reader.addEventListener('load', function (e) {
            my.loadBuffer(e.target.result);
        });
        reader.addEventListener('error', function () {
            my.fireEvent('error', 'Error reading file');
        });

        // Bind drop event
        if (typeof dropTarget == 'string') {
            dropTarget = document.querySelector(dropTarget);
        }
        var dropActiveCl = 'wavesurfer-dragover';
        dropTarget.addEventListener('drop', function (e) {
            e.stopPropagation();
            e.preventDefault();
            dropTarget.classList.remove(dropActiveCl);
            var file = e.dataTransfer.files[0];
            if (file) {
                my.empty();
                reader.readAsArrayBuffer(file);
            } else {
                my.fireEvent('error', 'Not a file');
            }
        });
        // Bind dragover & dragleave
        dropTarget.addEventListener('dragover', function (e) {
            e.stopPropagation();
            e.preventDefault();
            dropTarget.classList.add(dropActiveCl);
        });
        dropTarget.addEventListener('dragleave', function (e) {
            e.stopPropagation();
            e.preventDefault();
            dropTarget.classList.remove(dropActiveCl);
        });
    },

    bindMarks: function () {
        var my = this;
        var prevTime = 0;

        this.backend.on('play', function () {
            // Reset marker events
            Object.keys(my.markers).forEach(function (id) {
                my.markers[id].played = false;
            });
        });

        this.backend.on('audioprocess', function (time) {
            Object.keys(my.markers).forEach(function (id) {
                var marker = my.markers[id];
                if (!marker.played) {
                    if (marker.position <= time && marker.position >= prevTime) {
                        // Prevent firing the event more than once per playback
                        marker.played = true;

                        my.fireEvent('mark', marker);
                        marker.fireEvent('reached');
                    }
                }
            });
            prevTime = time;
        });
    },

    empty: function () {
        this.pause();
        this.clearMarks();
        this.backend.loadEmpty();
        this.drawer.drawPeaks({ length: this.drawer.getWidth() }, 0);
    },

    unregisterEvents: function(){
        var events = ['ready', 'loading', 'seek', 'play', 'mark', 'error' ];
        var wavesurfer = this;
        // wavesurfer event
        events.forEach( function(type){
            wavesurfer.un(type);
        });
        // drawer event
        if (wavesurfer.drawer) {
            window.removeEventListener('resize', wavesurfer.drawer.resize);
        }
    }
};

/* Mark */
WaveSurfer.Mark = {
    defaultParams: {
        id: null,
        position: 0,
        percentage: 0,
        width: 1,
        color: '#333'
    },

    init: function (options) {
        return this.update(
            WaveSurfer.util.extend({}, this.defaultParams, options)
        );
    },

    getTitle: function () {
        var d = new Date(this.position * 1000);
        return d.getMinutes() + ':' + d.getSeconds();
    },

    update: function (options) {
        Object.keys(options).forEach(function (key) {
            if (key in this.defaultParams) {
                this[key] = options[key];
            }
        }, this);

        // If percentage is specified, but position is undefined,
        // let the subscribers to recalculate the position
        if (null == options.position && null != options.percentage) {
            this.position = null;
        }

        this.fireEvent('update');
        return this;
    },

    remove: function () {
        this.fireEvent('remove');
    }
};

/* Observer */
WaveSurfer.Observer = {
    on: function (event, fn) {
        if (!this.handlers) { this.handlers = {}; }

        var handlers = this.handlers[event];
        if (!handlers) {
            handlers = this.handlers[event] = [];
        }
        handlers.push(fn);
    },

    un: function (event, fn) {
        if (!this.handlers) { return; }

        var handlers = this.handlers[event];
        if (handlers) {
            if (fn) {
                for (var i = handlers.length - 1; i >= 0; i--) {
                    if (handlers[i] == fn) {
                        handlers.splice(i, 1);
                    }
                }
            } else {
                handlers.length = 0;
            }
        }
    },

    once: function (event, handler) {
        var fn = (function () {
            handler();
            this.un(event, fn);
        }).bind(this);
        this.on(event, fn);
    },

    fireEvent: function (event) {
        if (!this.handlers) { return; }

        var handlers = this.handlers[event];
        var args = Array.prototype.slice.call(arguments, 1);
        if (handlers) {
            for (var i = 0, len = handlers.length; i < len; i += 1) {
                handlers[i].apply(null, args);
            }
        }
    }
};

/* Common utilities */
WaveSurfer.util = {
    extend: function (dest) {
        var sources = Array.prototype.slice.call(arguments, 1);
        sources.forEach(function (source) {
            if (source != null) {
                Object.keys(source).forEach(function (key) {
                    dest[key] = source[key];
                });
            }
        });
        return dest;
    },

    getId: function () {
        return 'wavesurfer_' + Math.random().toString(32).substring(2);
    },

    max: function (values) {
        var max = -Infinity;
        for (var i = 0, len = values.length; i < len; i++) {
            var val = values[i];
            if (val > max) { max = val; }
        }
        return max;
    }
};

WaveSurfer.util.extend(WaveSurfer, WaveSurfer.Observer);
WaveSurfer.util.extend(WaveSurfer.Mark, WaveSurfer.Observer);
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import Styled from 'rsg-components/Styled';

export const styles = ({ space, color, borderRadius }) => ({
	root: {
		marginBottom: space[4],
	},
	preview: {
		padding: space[2],
		border: [[1, color.border, 'solid']],
		borderRadius,
	},
	controls: {
		display: 'flex',
		alignItems: 'center',
	},
	toolbar: {
		marginLeft: 'auto',
	},
	tab: {}, // expose className to allow using it in 'styles' settings
});

export function PlaygroundRenderer({
	classes,
	name,
	preview,
	previewProps,
	tabButtons,
	tabBody,
	toolbar,
}) {
	const { className, ...props } = previewProps;
	return (

				{preview}

{tabButtons}

{toolbar}

{tabBody}

	);
}

PlaygroundRenderer.propTypes = {
	classes: PropTypes.object.isRequired,
	name: PropTypes.string.isRequired,
	preview: PropTypes.node.isRequired,
	previewProps: PropTypes.object.isRequired,
	tabButtons: PropTypes.node.isRequired,
	tabBody: PropTypes.node.isRequired,
	toolbar: PropTypes.node.isRequired,
};

export default Styled(styles)(PlaygroundRenderer);
<commit_msg>Fix: Do not overflow floated elements in examples (#773)<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import Styled from 'rsg-components/Styled';

export const styles = ({ space, color, borderRadius }) => ({
	root: {
		marginBottom: space[4],
	},
	preview: {
		padding: space[2],
		border: [[1, color.border, 'solid']],
		borderRadius,
		// the next 2 lines are required to contain floated components
		width: '100%',
		display: 'inline-block',
	},
	controls: {
		display: 'flex',
		alignItems: 'center',
	},
	toolbar: {
		marginLeft: 'auto',
	},
	tab: {}, // expose className to allow using it in 'styles' settings
});

export function PlaygroundRenderer({
	classes,
	name,
	preview,
	previewProps,
	tabButtons,
	tabBody,
	toolbar,
}) {
	const { className, ...props } = previewProps;
	return (

				{preview}

{tabButtons}

{toolbar}

{tabBody}

	);
}

PlaygroundRenderer.propTypes = {
	classes: PropTypes.object.isRequired,
	name: PropTypes.string.isRequired,
	preview: PropTypes.node.isRequired,
	previewProps: PropTypes.object.isRequired,
	tabButtons: PropTypes.node.isRequired,
	tabBody: PropTypes.node.isRequired,
	toolbar: PropTypes.node.isRequired,
};

export default Styled(styles)(PlaygroundRenderer);
<|endoftext|>


<commit_before>/*
Copyright (C) 2018-2019 de4dot@gmail.com

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

const {
	Code, CodeExt, Decoder, DecoderOptions, EncodingKind, MandatoryPrefix, OpCodeOperandKind,
	OpCodeTableKind, TupleType
} = require("iced-x86");

test("OpCodeInfo", () => {
	const bytes = new Uint8Array([0x48, 0x01, 0x18]);
	const decoder = new Decoder(64, bytes, DecoderOptions.None);
	const instr = decoder.decode();

	const info1 = instr.opCode;
	const info2 = CodeExt.opCode(instr.code);
	expect(info1.code).toBe(Code.Add_rm64_r64);
	expect(info2.code).toBe(Code.Add_rm64_r64);

	expect(info1.encoding).toBe(EncodingKind.Legacy);
	expect(info1.isInstruction).toBe(true);
	expect(info1.mode16).toBe(false);
	expect(info1.mode32).toBe(false);
	expect(info1.mode64).toBe(true);
	expect(info1.fwait).toBe(false);
	expect(info1.operandSize).toBe(64);
	expect(info1.addressSize).toBe(0);
	expect(info1.L).toBe(0);
	expect(info1.W).toBe(0);
	expect(info1.isLIG).toBe(false);
	expect(info1.isWIG).toBe(false);
	expect(info1.isWIG32).toBe(false);
	expect(info1.tupleType).toBe(TupleType.None);
	expect(info1.canBroadcast).toBe(false);
	expect(info1.canUseRoundingControl).toBe(false);
	expect(info1.canSuppressAllExceptions).toBe(false);
	expect(info1.canUseOpMaskRegister).toBe(false);
	expect(info1.requireNonZeroOpMaskRegister).toBe(false);
	expect(info1.canUseZeroingMasking).toBe(false);
	expect(info1.canUseLockPrefix).toBe(true);
	expect(info1.canUseXacquirePrefix).toBe(true);
	expect(info1.canUseXreleasePrefix).toBe(true);
	expect(info1.canUseRepPrefix).toBe(false);
	expect(info1.canUseRepnePrefix).toBe(false);
	expect(info1.canUseBndPrefix).toBe(false);
	expect(info1.canUseHintTakenPrefix).toBe(false);
	expect(info1.canUseNotrackPrefix).toBe(false);
	expect(info1.table).toBe(OpCodeTableKind.Normal);
	expect(info1.mandatoryPrefix).toBe(MandatoryPrefix.None);
	expect(info1.opCode).toBe(0x01);
	expect(info1.isGroup).toBe(false);
	expect(info1.groupIndex).toBe(-1);
	expect(info1.opCount).toBe(2);
	expect(info1.op0Kind).toBe(OpCodeOperandKind.r64_or_mem);
	expect(info1.op1Kind).toBe(OpCodeOperandKind.r64_reg);
	expect(info1.op2Kind).toBe(OpCodeOperandKind.None);
	expect(info1.op3Kind).toBe(OpCodeOperandKind.None);
	expect(info1.op4Kind).toBe(OpCodeOperandKind.None);
	expect(info1.opKind(0)).toBe(OpCodeOperandKind.r64_or_mem);
	expect(info1.opKind(1)).toBe(OpCodeOperandKind.r64_reg);
	expect(info1.opKind(2)).toBe(OpCodeOperandKind.None);
	expect(info1.opKind(3)).toBe(OpCodeOperandKind.None);
	expect(info1.opKind(4)).toBe(OpCodeOperandKind.None);
	expect(info1.isAvailableInMode(16)).toBe(false);
	expect(info1.isAvailableInMode(32)).toBe(false);
	expect(info1.isAvailableInMode(64)).toBe(true);
	expect(info1.opCodeString).toBe("REX.W 01 /r");
	expect(info1.instructionString).toBe("ADD r/m64, r64");

	decoder.free();
	instr.free();
	info1.free();
	info2.free();
});
<commit_msg>Update JS test with new rmGroupIndex property<commit_after>/*
Copyright (C) 2018-2019 de4dot@gmail.com

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

const {
	Code, CodeExt, Decoder, DecoderOptions, EncodingKind, MandatoryPrefix, OpCodeOperandKind,
	OpCodeTableKind, TupleType
} = require("iced-x86");

test("OpCodeInfo", () => {
	const bytes = new Uint8Array([0x48, 0x01, 0x18]);
	const decoder = new Decoder(64, bytes, DecoderOptions.None);
	const instr = decoder.decode();

	const info1 = instr.opCode;
	const info2 = CodeExt.opCode(instr.code);
	expect(info1.code).toBe(Code.Add_rm64_r64);
	expect(info2.code).toBe(Code.Add_rm64_r64);

	expect(info1.encoding).toBe(EncodingKind.Legacy);
	expect(info1.isInstruction).toBe(true);
	expect(info1.mode16).toBe(false);
	expect(info1.mode32).toBe(false);
	expect(info1.mode64).toBe(true);
	expect(info1.fwait).toBe(false);
	expect(info1.operandSize).toBe(64);
	expect(info1.addressSize).toBe(0);
	expect(info1.L).toBe(0);
	expect(info1.W).toBe(0);
	expect(info1.isLIG).toBe(false);
	expect(info1.isWIG).toBe(false);
	expect(info1.isWIG32).toBe(false);
	expect(info1.tupleType).toBe(TupleType.None);
	expect(info1.canBroadcast).toBe(false);
	expect(info1.canUseRoundingControl).toBe(false);
	expect(info1.canSuppressAllExceptions).toBe(false);
	expect(info1.canUseOpMaskRegister).toBe(false);
	expect(info1.requireNonZeroOpMaskRegister).toBe(false);
	expect(info1.canUseZeroingMasking).toBe(false);
	expect(info1.canUseLockPrefix).toBe(true);
	expect(info1.canUseXacquirePrefix).toBe(true);
	expect(info1.canUseXreleasePrefix).toBe(true);
	expect(info1.canUseRepPrefix).toBe(false);
	expect(info1.canUseRepnePrefix).toBe(false);
	expect(info1.canUseBndPrefix).toBe(false);
	expect(info1.canUseHintTakenPrefix).toBe(false);
	expect(info1.canUseNotrackPrefix).toBe(false);
	expect(info1.table).toBe(OpCodeTableKind.Normal);
	expect(info1.mandatoryPrefix).toBe(MandatoryPrefix.None);
	expect(info1.opCode).toBe(0x01);
	expect(info1.isGroup).toBe(false);
	expect(info1.groupIndex).toBe(-1);
	expect(info1.isRmGroup).toBe(false);
	expect(info1.rmGroupIndex).toBe(-1);
	expect(info1.opCount).toBe(2);
	expect(info1.op0Kind).toBe(OpCodeOperandKind.r64_or_mem);
	expect(info1.op1Kind).toBe(OpCodeOperandKind.r64_reg);
	expect(info1.op2Kind).toBe(OpCodeOperandKind.None);
	expect(info1.op3Kind).toBe(OpCodeOperandKind.None);
	expect(info1.op4Kind).toBe(OpCodeOperandKind.None);
	expect(info1.opKind(0)).toBe(OpCodeOperandKind.r64_or_mem);
	expect(info1.opKind(1)).toBe(OpCodeOperandKind.r64_reg);
	expect(info1.opKind(2)).toBe(OpCodeOperandKind.None);
	expect(info1.opKind(3)).toBe(OpCodeOperandKind.None);
	expect(info1.opKind(4)).toBe(OpCodeOperandKind.None);
	expect(info1.isAvailableInMode(16)).toBe(false);
	expect(info1.isAvailableInMode(32)).toBe(false);
	expect(info1.isAvailableInMode(64)).toBe(true);
	expect(info1.opCodeString).toBe("REX.W 01 /r");
	expect(info1.instructionString).toBe("ADD r/m64, r64");

	decoder.free();
	instr.free();
	info1.free();
	info2.free();
});
<|endoftext|>