<commit_before>import {addSimulation} from 'gModules/simulations/actions'
import {addSimulationToFact} from 'gModules/facts/actions'

import * as constants from './constants'
import {Simulator} from './simulator'
import {INTERNAL_ERROR, INPUT_ERROR, PARSER_ERROR, INFINITE_LOOP_ERROR} from 'lib/errors/modelErrors'

import e from 'gEngine/engine'

const {
  NODE_TYPES,
  ERROR_SUBTYPES: {GRAPH_SUBTYPES: {MISSING_INPUT_ERROR, IN_INFINITE_LOOP, INVALID_ANCESTOR_ERROR}},
} = constants

function getSpacesAndOrganization(state, graphFilters) {
  let spaces = []
  let organization = null

  if (!!graphFilters.factId) {
    const organizationFact = state.facts.organizationFacts.find(({children}) => e.collections.some(children, graphFilters.factId))
    const fact = e.collections.get(_.get(organizationFact, 'children'), graphFilters.factId)
    if (!_.isEmpty(fact.imported_to_intermediate_space_ids)) {
      const orgId = e.organization.organizationIdFromFactReadableId(organizationFact.variable_name)
      organization = e.collections.get(state.organizations, orgId)
      const organizationSpaces = e.collections.filter(state.spaces, orgId, 'organization_id')
      spaces.push(...organizationSpaces.filter(s => s.exported_facts_count > 0 && !_.isEmpty(s.imported_fact_ids)))
    }
  } else if (!!graphFilters.spaceId) {
    spaces.push(e.collections.get(state.spaces, graphFilters.spaceId))
    organization = e.collections.get(state.organizations, _.get(spaces[0], 'organization_id'))
  } else if (!!graphFilters.metricId) {
    const spaceId = e.collections.gget(state.metrics, graphFilters.metricId, 'id', 'space')
    spaces.push(e.collections.get(state.spaces, spaceId))
    organization = e.collections.get(state.organizations, _.get(spaces[0], 'organization_id'))
  }

  return {spaces: spaces.filter(s => !!s), organization}
}

// TODO(matthew): Find a way to test this through the public API.
export function getSubset(state, graphFilters) {
  const {spaces, organization} = getSpacesAndOrganization(state, graphFilters)

  if (_.isEmpty(spaces)) { return {subset: {metrics: [], guesstimates: [], simulations: []}, relevantFacts: []} }
  const spaceIds = spaces.map(s => s.id)

  let subset = e.space.subset(state, ...spaceIds)
  const organizationFacts = e.facts.getFactsForOrg(state.facts.organizationFacts, organization)

  const {organizationFactsUsed, globalFactsUsed} = e.facts.getRelevantFactsAndReformatGlobals(subset, state.facts.globalFacts, organizationFacts, spaces.map(s => s.id))

  // When should facts be simulatable?
  //
  // This logic is a bit dicey, and very tempermental, so it warrants an explanation.
  // We only want to simulate facts if the user is in editing mode on a space; you don't want to redefine their global
  // fact store if they are just arbitrarily adjusting parameters, for example. View mode or edit mode is determined by
  // one of two things: either the canvasState flags edits as being allowed or not, or the space's permissions itself
  // can forbid editing by a user. But, as our permission system right now prohibits the use of (or exporting of,
  // TODO(matthew): Add that restriction) from spaces that the user doesn't have permission to edit, this second
  // restriction is moot; if you can't edit the space you can't be simulating output facts in the first place.
  // Therefore, the only restriction that defines whether or not the user is in editing mode that is relevant when there
  // are possible output facts is the canvas state. In particular, a user is in edit mode (and thus we should simulate
  // facts) when the canvasState editsAllowed field is manually set to true.
  //
  // However, there is one additional caveat. If we are simulating facts as part of a downstream propagation from an
  // upstream fact change, then we want to simulate facts independently of canvasState. This is indicated by whether or
  // not the graphFilters object has the `factId` field set.
  //
  // Additionally, we never want to simulate input facts, or facts not exported by the space we're simulating.
  //
  // So, our final condition as to whether or not we want to simulate a given fact f is:
  //   ([can edit] OR [simulating fact descendants]) AND [fact is output]
  const {canvasState: {editsAllowed, editsAllowedManuallySet}} = state
  const allowedToSimulateOutputFact = !!graphFilters.factId || !editsAllowedManuallySet || editsAllowed

  const organizationFactsFlaggedAsSimulatable = organizationFactsUsed.map(f => ({
    ...f,
    shouldBeSimulated: allowedToSimulateOutputFact && spaceIds.includes(_.get(f, 'exported_from_id')),
  }))

  const globalFactHandleToNodeIdMap = _.transform(
    globalFactsUsed,
    (resultMap, globalFact) => { resultMap[globalFact.variable_name] = e.guesstimate.expressionSyntaxPad(globalFact.id, false) },
    {}
  )

  subset.guesstimates = subset.guesstimates.map(g => ({
    ...g,
    expression: e.utils.replaceByMap(g.expression, globalFactHandleToNodeIdMap)
  }))

  return {subset, relevantFacts: [...organizationFactsFlaggedAsSimulatable, ...globalFactsUsed]}
}

const nodeIdToMetricId = id => id.slice(e.simulation.METRIC_ID_PREFIX.length)
const nodeIdToFactId = id => id.slice(e.simulation.FACT_ID_PREFIX.length)
const nodeIdIsMetric = id => id.includes(e.simulation.METRIC_ID_PREFIX)

function guesstimateTypeToNodeType(guesstimateType) {
  switch (guesstimateType) {
    case 'FUNCTION':
      return NODE_TYPES.FUNCTION
    case 'DATA':
      return NODE_TYPES.DATA
    default:
      return NODE_TYPES.USER_INPUT
  }
}

const filterErrorsFn = e => e.type !== INPUT_ERROR && e.type !== PARSER_ERROR && e.type !== INFINITE_LOOP_ERROR
const metricIdToNodeId = id => `${e.simulation.METRIC_ID_PREFIX}${id}`
const metricToSimulationNodeFn = m => ({
  id: metricIdToNodeId(m.id),
  type: guesstimateTypeToNodeType(m.guesstimate.guesstimateType),
  guesstimateType: m.guesstimate.guesstimateType,
  expression: m.guesstimate.expression,
  samples: m.guesstimate.guesstimateType === 'DATA' ? e.utils.orArr(_.get(m, 'guesstimate.data')) : e.simulation.values(m.simulation),
  errors: e.utils.mutableCopy(e.simulation.errors(m.simulation)).filter(filterErrorsFn),
})

const factIdToNodeId = id => `${e.simulation.FACT_ID_PREFIX}${id}`
const factToSimulationNodeFn = f => ({
  id: factIdToNodeId(f.id),
  expression: f.expression,
  type: NODE_TYPES.UNSET, // Facts are currently type-less.
  guesstimateType: null, // Facts are currently type-less.
  samples: e.simulation.values(f.simulation),
  errors: e.utils.mutableCopy(e.simulation.errors(f.simulation)).filter(filterErrorsFn),
  skipSimulating: !_.get(f, 'shouldBeSimulated'),
})

function denormalize({metrics, guesstimates, simulations}) {
  return metrics.map(m => ({
    ...m,
    guesstimate: e.collections.get(guesstimates, m.id, 'metric'),
    simulation: e.collections.get(simulations, m.id, 'metric'),
  }))
}

const allPresent = (obj, ...props) => props.map(p => present(obj, p)).reduce((x,y) => x && y, true)
const present = (obj, prop) => _.has(obj, prop) && (!!_.get(obj, prop) || _.get(obj, prop) === 0)
function translateOptions(graphFilters) {
  if (allPresent(graphFilters, 'factId')) { return {simulateStrictSubsetFrom: [factIdToNodeId(graphFilters.factId)]} }
  if (allPresent(graphFilters, 'metricId', 'onlyHead')) { return {simulateIds: [metricIdToNodeId(graphFilters.metricId)]} }
  if (allPresent(graphFilters, 'metricId', 'notHead')) { return {simulateStrictSubsetFrom: [metricIdToNodeId(graphFilters.metricId)]} }
  if (allPresent(graphFilters, 'simulateSubsetFrom')) { return {simulateSubsetFrom: graphFilters.simulateSubsetFrom.map(metricIdToNodeId)} }
  if (allPresent(graphFilters, 'simulateSubset')) { return {simulateIds: graphFilters.simulateSubset.map(metricIdToNodeId)} }
  return {}
}

function translateErrorFn(denormalizedMetrics, metricID) {
  const metric = e.collections.get(denormalizedMetrics, metricID)
  const getReadableIdFn = id => e.collections.gget(denormalizedMetrics, id, 'id', 'readableId')

  return err => {
    switch (err.subType) {
      case MISSING_INPUT_ERROR:
        return {type: INPUT_ERROR, message: 'Metric depends on deleted metric'}
      case IN_INFINITE_LOOP:
        return {type: INFINITE_LOOP_ERROR, message: 'Metric references itself through dependency chain'}
      case INVALID_ANCESTOR_ERROR:
        let invalidAncestors = Object.assign([], err.ancestors).map(nodeIdToMetricId)
        const invalidDirectInputs = _.remove(invalidAncestors, a => metric.guesstimate.expression.includes(a))

        const invalidAncestorReadableIDs = invalidAncestors.map(getReadableIdFn)
        const invalidDirectInputReadableIDs = invalidDirectInputs.map(getReadableIdFn)
        const hasInvalidInputs = !_.isEmpty(invalidDirectInputReadableIDs)
        const hasInvalidAncestors = !_.isEmpty(invalidAncestorReadableIDs)
        const hasBoth = hasInvalidInputs && hasInvalidAncestors

        let message = 'Broken '
        if (hasInvalidInputs) {
          message += `input${invalidDirectInputs.length > 1 ? 's' : ''} ${invalidDirectInputReadableIDs.join(', ')}`
        }

        if (hasBoth) {
          message += ` and upstream input${invalidAncestors.length > 1 ? 's' : ''} ${invalidAncestorReadableIDs.join(', ')}`
        } else if (hasInvalidAncestors) {
          message += ` upstream input${invalidAncestors.length > 1 ? 's' : ''} ${invalidAncestorReadableIDs.join(', ')}`
        }
        message += '.'

        return {type: INPUT_ERROR, message}
      default:
        return err
    }
  }
}

const getCurrPropId = state => nodeId => {
  if (nodeIdIsMetric(nodeId)) {
    const metricId = nodeIdToMetricId(nodeId)
    return e.collections.gget(state.simulations, metricId, 'metric', 'propagationId')
  } else {
    const factId = nodeIdToFactId(nodeId)

    const organizationFact = state.facts.organizationFacts.find(({children}) => e.collections.some(children, factId))
    const fact = e.collections.get(_.get(organizationFact, 'children'), factId)
    return e.utils.orZero(_.get(fact, 'simulation.propagationId'))
  }
}

export function simulate(dispatch, getState, graphFilters) {
  const state = getState()
  const shouldTriggerDownstreamFactSimulations = !graphFilters.factId

  const {subset, relevantFacts} = getSubset(state, graphFilters)
  const denormalizedMetrics = denormalize(subset)

  const nodes = [..._.map(denormalizedMetrics, metricToSimulationNodeFn), ..._.map(relevantFacts, factToSimulationNodeFn)]

  if (_.isEmpty(nodes)) { return }

  const propagationId = (new Date()).getTime()

  const yieldMetricSims = (nodeId, {samples, errors}) => {
    const metric = nodeIdToMetricId(nodeId)
    const newSimulation = {
      metric,
      propagationId,
      sample: {
        values: _.isEmpty(errors) ? samples : [],
        errors: Object.assign([], errors.map(translateErrorFn(denormalizedMetrics, metric))),
      }
    }
    dispatch(addSimulation(newSimulation))
  }

  const yieldFactSims = (nodeId, {samples, errors}) => {
    // TODO(matthew): Proper error handling...
    if (!_.isEmpty(errors)) { return }

    const factId = nodeIdToFactId(nodeId)
    const newSimulation = {
      propagationId,
      sample: {
        values: _.isEmpty(errors) ? samples : [],
        errors: Object.assign([], errors),
      }
    }
    dispatch(addSimulationToFact(newSimulation, factId, shouldTriggerDownstreamFactSimulations))
  }

  const yieldSims = (nodeId, sim) => { nodeIdIsMetric(nodeId) ? yieldMetricSims(nodeId, sim) : yieldFactSims(nodeId, sim) }

  let simulator = new Simulator(
    nodes,
    e.simulation.NUM_SAMPLES,
    translateOptions(graphFilters),
    propagationId,
    yieldSims,
    getCurrPropId(state)
  )
  simulator.run()
}
<commit_msg>Removed old TODO<commit_after>import {addSimulation} from 'gModules/simulations/actions'
import {addSimulationToFact} from 'gModules/facts/actions'

import * as constants from './constants'
import {Simulator} from './simulator'
import {INTERNAL_ERROR, INPUT_ERROR, PARSER_ERROR, INFINITE_LOOP_ERROR} from 'lib/errors/modelErrors'

import e from 'gEngine/engine'

const {
  NODE_TYPES,
  ERROR_SUBTYPES: {GRAPH_SUBTYPES: {MISSING_INPUT_ERROR, IN_INFINITE_LOOP, INVALID_ANCESTOR_ERROR}},
} = constants

function getSpacesAndOrganization(state, graphFilters) {
  let spaces = []
  let organization = null

  if (!!graphFilters.factId) {
    const organizationFact = state.facts.organizationFacts.find(({children}) => e.collections.some(children, graphFilters.factId))
    const fact = e.collections.get(_.get(organizationFact, 'children'), graphFilters.factId)
    if (!_.isEmpty(fact.imported_to_intermediate_space_ids)) {
      const orgId = e.organization.organizationIdFromFactReadableId(organizationFact.variable_name)
      organization = e.collections.get(state.organizations, orgId)
      const organizationSpaces = e.collections.filter(state.spaces, orgId, 'organization_id')
      spaces.push(...organizationSpaces.filter(s => s.exported_facts_count > 0 && !_.isEmpty(s.imported_fact_ids)))
    }
  } else if (!!graphFilters.spaceId) {
    spaces.push(e.collections.get(state.spaces, graphFilters.spaceId))
    organization = e.collections.get(state.organizations, _.get(spaces[0], 'organization_id'))
  } else if (!!graphFilters.metricId) {
    const spaceId = e.collections.gget(state.metrics, graphFilters.metricId, 'id', 'space')
    spaces.push(e.collections.get(state.spaces, spaceId))
    organization = e.collections.get(state.organizations, _.get(spaces[0], 'organization_id'))
  }

  return {spaces: spaces.filter(s => !!s), organization}
}

// TODO(matthew): Find a way to test this through the public API.
export function getSubset(state, graphFilters) {
  const {spaces, organization} = getSpacesAndOrganization(state, graphFilters)

  if (_.isEmpty(spaces)) { return {subset: {metrics: [], guesstimates: [], simulations: []}, relevantFacts: []} }
  const spaceIds = spaces.map(s => s.id)

  let subset = e.space.subset(state, ...spaceIds)
  const organizationFacts = e.facts.getFactsForOrg(state.facts.organizationFacts, organization)

  const {organizationFactsUsed, globalFactsUsed} = e.facts.getRelevantFactsAndReformatGlobals(subset, state.facts.globalFacts, organizationFacts, spaces.map(s => s.id))

  // When should facts be simulatable?
  //
  // This logic is a bit dicey, and very tempermental, so it warrants an explanation.
  // We only want to simulate facts if the user is in editing mode on a space; you don't want to redefine their global
  // fact store if they are just arbitrarily adjusting parameters, for example. View mode or edit mode is determined by
  // one of two things: either the canvasState flags edits as being allowed or not, or the space's permissions itself
  // can forbid editing by a user. But, as our permission system right now prohibits the use of (or exporting of) facts
  // from spaces that the user doesn't have permission to edit, this second restriction is moot; if you can't edit the
  // space you can't be simulating output facts in the first place.  Therefore, the only restriction that defines
  // whether or not the user is in editing mode that is relevant when there are possible output facts is the canvas
  // state. In particular, a user is in edit mode (and thus we should simulate facts) when the canvasState editsAllowed
  // field is manually set to true.
  //
  // However, there is one additional caveat. If we are simulating facts as part of a downstream propagation from an
  // upstream fact change, then we want to simulate facts independently of canvasState. This is indicated by whether or
  // not the graphFilters object has the `factId` field set.
  //
  // Additionally, we never want to simulate input facts, or facts not exported by the space we're simulating.
  //
  // So, our final condition as to whether or not we want to simulate a given fact f is:
  //   ([can edit] OR [simulating fact descendants]) AND [fact is output]
  const {canvasState: {editsAllowed, editsAllowedManuallySet}} = state
  const allowedToSimulateOutputFact = !!graphFilters.factId || !editsAllowedManuallySet || editsAllowed

  const organizationFactsFlaggedAsSimulatable = organizationFactsUsed.map(f => ({
    ...f,
    shouldBeSimulated: allowedToSimulateOutputFact && spaceIds.includes(_.get(f, 'exported_from_id')),
  }))

  const globalFactHandleToNodeIdMap = _.transform(
    globalFactsUsed,
    (resultMap, globalFact) => { resultMap[globalFact.variable_name] = e.guesstimate.expressionSyntaxPad(globalFact.id, false) },
    {}
  )

  subset.guesstimates = subset.guesstimates.map(g => ({
    ...g,
    expression: e.utils.replaceByMap(g.expression, globalFactHandleToNodeIdMap)
  }))

  return {subset, relevantFacts: [...organizationFactsFlaggedAsSimulatable, ...globalFactsUsed]}
}

const nodeIdToMetricId = id => id.slice(e.simulation.METRIC_ID_PREFIX.length)
const nodeIdToFactId = id => id.slice(e.simulation.FACT_ID_PREFIX.length)
const nodeIdIsMetric = id => id.includes(e.simulation.METRIC_ID_PREFIX)

function guesstimateTypeToNodeType(guesstimateType) {
  switch (guesstimateType) {
    case 'FUNCTION':
      return NODE_TYPES.FUNCTION
    case 'DATA':
      return NODE_TYPES.DATA
    default:
      return NODE_TYPES.USER_INPUT
  }
}

const filterErrorsFn = e => e.type !== INPUT_ERROR && e.type !== PARSER_ERROR && e.type !== INFINITE_LOOP_ERROR
const metricIdToNodeId = id => `${e.simulation.METRIC_ID_PREFIX}${id}`
const metricToSimulationNodeFn = m => ({
  id: metricIdToNodeId(m.id),
  type: guesstimateTypeToNodeType(m.guesstimate.guesstimateType),
  guesstimateType: m.guesstimate.guesstimateType,
  expression: m.guesstimate.expression,
  samples: m.guesstimate.guesstimateType === 'DATA' ? e.utils.orArr(_.get(m, 'guesstimate.data')) : e.simulation.values(m.simulation),
  errors: e.utils.mutableCopy(e.simulation.errors(m.simulation)).filter(filterErrorsFn),
})

const factIdToNodeId = id => `${e.simulation.FACT_ID_PREFIX}${id}`
const factToSimulationNodeFn = f => ({
  id: factIdToNodeId(f.id),
  expression: f.expression,
  type: NODE_TYPES.UNSET, // Facts are currently type-less.
  guesstimateType: null, // Facts are currently type-less.
  samples: e.simulation.values(f.simulation),
  errors: e.utils.mutableCopy(e.simulation.errors(f.simulation)).filter(filterErrorsFn),
  skipSimulating: !_.get(f, 'shouldBeSimulated'),
})

function denormalize({metrics, guesstimates, simulations}) {
  return metrics.map(m => ({
    ...m,
    guesstimate: e.collections.get(guesstimates, m.id, 'metric'),
    simulation: e.collections.get(simulations, m.id, 'metric'),
  }))
}

const allPresent = (obj, ...props) => props.map(p => present(obj, p)).reduce((x,y) => x && y, true)
const present = (obj, prop) => _.has(obj, prop) && (!!_.get(obj, prop) || _.get(obj, prop) === 0)
function translateOptions(graphFilters) {
  if (allPresent(graphFilters, 'factId')) { return {simulateStrictSubsetFrom: [factIdToNodeId(graphFilters.factId)]} }
  if (allPresent(graphFilters, 'metricId', 'onlyHead')) { return {simulateIds: [metricIdToNodeId(graphFilters.metricId)]} }
  if (allPresent(graphFilters, 'metricId', 'notHead')) { return {simulateStrictSubsetFrom: [metricIdToNodeId(graphFilters.metricId)]} }
  if (allPresent(graphFilters, 'simulateSubsetFrom')) { return {simulateSubsetFrom: graphFilters.simulateSubsetFrom.map(metricIdToNodeId)} }
  if (allPresent(graphFilters, 'simulateSubset')) { return {simulateIds: graphFilters.simulateSubset.map(metricIdToNodeId)} }
  return {}
}

function translateErrorFn(denormalizedMetrics, metricID) {
  const metric = e.collections.get(denormalizedMetrics, metricID)
  const getReadableIdFn = id => e.collections.gget(denormalizedMetrics, id, 'id', 'readableId')

  return err => {
    switch (err.subType) {
      case MISSING_INPUT_ERROR:
        return {type: INPUT_ERROR, message: 'Metric depends on deleted metric'}
      case IN_INFINITE_LOOP:
        return {type: INFINITE_LOOP_ERROR, message: 'Metric references itself through dependency chain'}
      case INVALID_ANCESTOR_ERROR:
        let invalidAncestors = Object.assign([], err.ancestors).map(nodeIdToMetricId)
        const invalidDirectInputs = _.remove(invalidAncestors, a => metric.guesstimate.expression.includes(a))

        const invalidAncestorReadableIDs = invalidAncestors.map(getReadableIdFn)
        const invalidDirectInputReadableIDs = invalidDirectInputs.map(getReadableIdFn)
        const hasInvalidInputs = !_.isEmpty(invalidDirectInputReadableIDs)
        const hasInvalidAncestors = !_.isEmpty(invalidAncestorReadableIDs)
        const hasBoth = hasInvalidInputs && hasInvalidAncestors

        let message = 'Broken '
        if (hasInvalidInputs) {
          message += `input${invalidDirectInputs.length > 1 ? 's' : ''} ${invalidDirectInputReadableIDs.join(', ')}`
        }

        if (hasBoth) {
          message += ` and upstream input${invalidAncestors.length > 1 ? 's' : ''} ${invalidAncestorReadableIDs.join(', ')}`
        } else if (hasInvalidAncestors) {
          message += ` upstream input${invalidAncestors.length > 1 ? 's' : ''} ${invalidAncestorReadableIDs.join(', ')}`
        }
        message += '.'

        return {type: INPUT_ERROR, message}
      default:
        return err
    }
  }
}

const getCurrPropId = state => nodeId => {
  if (nodeIdIsMetric(nodeId)) {
    const metricId = nodeIdToMetricId(nodeId)
    return e.collections.gget(state.simulations, metricId, 'metric', 'propagationId')
  } else {
    const factId = nodeIdToFactId(nodeId)

    const organizationFact = state.facts.organizationFacts.find(({children}) => e.collections.some(children, factId))
    const fact = e.collections.get(_.get(organizationFact, 'children'), factId)
    return e.utils.orZero(_.get(fact, 'simulation.propagationId'))
  }
}

export function simulate(dispatch, getState, graphFilters) {
  const state = getState()
  const shouldTriggerDownstreamFactSimulations = !graphFilters.factId

  const {subset, relevantFacts} = getSubset(state, graphFilters)
  const denormalizedMetrics = denormalize(subset)

  const nodes = [..._.map(denormalizedMetrics, metricToSimulationNodeFn), ..._.map(relevantFacts, factToSimulationNodeFn)]

  if (_.isEmpty(nodes)) { return }

  const propagationId = (new Date()).getTime()

  const yieldMetricSims = (nodeId, {samples, errors}) => {
    const metric = nodeIdToMetricId(nodeId)
    const newSimulation = {
      metric,
      propagationId,
      sample: {
        values: _.isEmpty(errors) ? samples : [],
        errors: Object.assign([], errors.map(translateErrorFn(denormalizedMetrics, metric))),
      }
    }
    dispatch(addSimulation(newSimulation))
  }

  const yieldFactSims = (nodeId, {samples, errors}) => {
    // TODO(matthew): Proper error handling...
    if (!_.isEmpty(errors)) { return }

    const factId = nodeIdToFactId(nodeId)
    const newSimulation = {
      propagationId,
      sample: {
        values: _.isEmpty(errors) ? samples : [],
        errors: Object.assign([], errors),
      }
    }
    dispatch(addSimulationToFact(newSimulation, factId, shouldTriggerDownstreamFactSimulations))
  }

  const yieldSims = (nodeId, sim) => { nodeIdIsMetric(nodeId) ? yieldMetricSims(nodeId, sim) : yieldFactSims(nodeId, sim) }

  let simulator = new Simulator(
    nodes,
    e.simulation.NUM_SAMPLES,
    translateOptions(graphFilters),
    propagationId,
    yieldSims,
    getCurrPropId(state)
  )
  simulator.run()
}
<|endoftext|>


<commit_before>function Validator(options) {

    if (!(this instanceof Validator)) {
        return new Validator(options);
    }

    this.file = options.file ? options.file : null;

    this.log = [];
    this.line = 0;
    this.progress = 0;
    this._readBytes = 0;
    this._events = {};
    this.numLines = 0;

    this.linesToRead = 1000;
}

Validator.prototype = {
    init: function () {
        this.file = null;
        this.log = [];
        this.line = 0;
        this.numLines = 0;
        this.progress = 0;
        this._readBytes = 0;
    },
    stop: function (cb) {
        if (this._navigator != null) {
            this._navigator._stop = true;
        }
    },

    validate: function () {
        var me = this;

        /*Check if file is \r or \n , \r\n */
        this._detectCRSeparator(this.file, function (res) {
            if (res) {
                me._navigator = new FileNavigator(me.file, undefined, {
                    newLineCode: '\r'.charCodeAt(0),
                    splitPattern: /\r/
                });
            } else {
                me._navigator = new FileNavigator(me.file);
            }

            me._totalBytes = me.file.size;
            var indexToStartWith = 0;

            // me._navigator.readSomeLines(indexToStartWith, function linesReadHandler(err, index, lines, eof, progress) {
                me._navigator.readLines(indexToStartWith, me.linesToRead, function linesReadHandler(err, index, lines, eof, progress) {
                if (err) {
                    me._emit("err");
                    return;
                }
                // console.log(lines.length);
                console.log(progress);
                for (var i = 0; i < lines.length; i++) {
                    if (i % 1000 == 0) {
                        me._emit("progress", [me.progress]);
                    }
                    var line = lines[i];
                    me.line++;
                    // console.log(me.line)
                    me.numLines++;
                    me._emit("lines", [me.numLines]);
                    me._readBytes += line.length;
                    me.progress = (me._readBytes / me._totalBytes) * 100;
                    me.validateLine(line);
                }
                // me._emit("progress", [me.progress]);

                if (eof && me._totalBytes) {
                    me._emit("progress", [100]);
                    me._emit("end");
                    me._validateEnd();
                    return;
                }
                if (me._navigator._stop != true) {
                    // me._navigator.readSomeLines(index + lines.length, linesReadHandler);
                    me._navigator.readLines(index + lines.length, me.linesToRead, linesReadHandler);
                } else {
                    me._emit("stop");
                    console.log("STOP!!!!!");
                }

            })

        });

    },
    validateLine: function (line) {
        return true;
    },
    _validateEnd: function () {
        this.validateEnd();
    },
    validateEnd: function () {
        return true;
    },
    addLog: function (type, msg) {
        var log = {
            type: type,
            msg: msg,
            line: this.line
        };
        this.log.push(log);
        this._emit("log", [log]);
    },
    on: function (eventName, cb) {
        this._events[eventName] = cb;
    },
    _emit: function (event, args) {

        var boundEvents = this._events;
        if (typeof boundEvents[event] === 'function') {
            boundEvents[event].apply(this, args);
        }
    },
    _detectCRSeparator: function (file, cb) {
        var reader = new FileReader();
        reader.onload = function (e) {
            var regex = /\r(?!\n)/;
            if (regex.test(e.target.result)) {
                cb(true);
            } else {
                cb(false);
            }
        }
        reader.readAsText(file);
    }
}
<commit_msg>Updated Validator<commit_after>function Validator(options) {

    if (!(this instanceof Validator)) {
        return new Validator(options);
    }

    this.file = options.file ? options.file : null;

    this.log = [];
    this.line = 0;
    this.progress = 0;
    this._readBytes = 0;
    this._events = {};
    this.numLines = 0;

    this.linesToRead = 2000;
}

Validator.prototype = {
    init: function () {
        this.file = null;
        this.log = [];
        this.line = 0;
        this.numLines = 0;
        this.progress = 0;
        this._readBytes = 0;
    },
    stop: function (cb) {
        if (this._navigator != null) {
            this._navigator._stop = true;
        }
    },

    validate: function () {
        var me = this;

        /*Check if file is \r or \n , \r\n */
        this._detectCRSeparator(this.file, function (res) {
            var lastReadBytes = null;
            if (res) {
                me._navigator = new FileNavigator(me.file, undefined, {
                    newLineCode: '\r'.charCodeAt(0),
                    splitPattern: /\r/
                });
            } else {
                me._navigator = new FileNavigator(me.file);
            }

            me._totalBytes = me.file.size;
            var indexToStartWith = 0;

            // me._navigator.readSomeLines(indexToStartWith, function linesReadHandler(err, index, lines, eof, progress) {
            me._navigator.readLines(indexToStartWith, me.linesToRead, function linesReadHandler(err, index, lines, eof, progress) {
                if (err) {
                    me._emit("err");
                    return;
                }
                // console.log(lines.length);
                console.log(progress);
                for (var i = 0; i < lines.length; i++) {
                    var line = lines[i];
                    me.line++;

                    me.numLines++;
                    // me._emit("lines", [me.numLines]);
                    me._readBytes += line.length;
                    me.progress = (me._readBytes / me._totalBytes) * 100;
                    me.validateLine(line);
                }
                // me._emit("progress", [me.progress]);

                if (lastReadBytes == me._readBytes) {
                    me._emit("progress", 100);
                    me._emit("end");
                    me._validateEnd();
                    return;
                }

                if (me._navigator._stop != true) {
                    // me._navigator.readSomeLines(index + lines.length, linesReadHandler);
                    me._navigator.readLines(index + lines.length, me.linesToRead, linesReadHandler);
                } else {
                    me._emit("stop");
                    console.log("STOP!!!!!");
                }

            })

        });

    },
    validateLine: function (line) {
        return true;
    },
    _validateEnd: function () {
        this.validateEnd();
    },
    validateEnd: function () {
        return true;
    },
    addLog: function (type, msg) {
        var log = {
            type: type,
            msg: msg,
            line: this.line
        };
        this.log.push(log);
        this._emit("log", log);
    },
    on: function (eventName, cb) {
        this._events[eventName] = cb;
    },
    _emit: function (event, args) {
        if (typeof this._events[event] === 'function') {
            this._events[event].apply(this, Array.prototype.slice.call(arguments, 1));
        }
    },
    _detectCRSeparator: function (file, cb) {
        var reader = new FileReader();
        reader.onload = function (e) {
            var regex = /\r(?!\n)/;
            if (regex.test(e.target.result)) {
                cb(true);
            } else {
                cb(false);
            }
        }
        reader.readAsText(file);
    }
}
<|endoftext|>


<commit_before>import path from 'path';
import fs from 'fs.promised';
import ip from 'ip';
import webpack from 'webpack';
import WebpackDevServer from 'webpack-dev-server';
import chalk from 'chalk';
import getPort from 'get-port';
import clientConfig from './webpack-client-config';
import serverConfig from './webpack-server-config';
import transformConfig from './transform-config';

export default async (watch=false, env, onprogress) => {
	if (watch) {
		return await devBuild(env, onprogress);
	}

	return await prodBuild(env);
};

const devBuild = async (env, onprogress) => {
	let config = clientConfig(env);
	await transformConfig(env, config);

	let userPort = parseInt(process.env.PORT || config.devServer.port, 10) || 8080;
	let port = await getPort(userPort);

	let compiler = webpack(config);
	return await new Promise((resolve, reject) => {

		compiler.plugin('done', stats => {
			let devServer = config.devServer;

			let protocol = devServer.https ? 'https' : 'http';
			let host = process.env.HOST || devServer.host || 'localhost';

			let serverAddr = `${protocol}://${host}:${chalk.bold(port)}`;
			let localIpAddr = `${protocol}://${ip.address()}:${chalk.bold(port)}`;

			clearConsole();
			if (stats.hasErrors()) {
				process.stdout.write(chalk.red('\Build failed!\n\n'));
			} else {
				process.stdout.write(chalk.green('\nCompiled successfully!\n\n'));

				if (userPort !== port) {
					process.stdout.write(`Port ${chalk.bold(userPort)} is in use, using ${chalk.bold(port)} instead\n\n`);
				}
				process.stdout.write('You can view the application in browser.\n\n');
				process.stdout.write(`${chalk.bold('Local:')}            ${serverAddr}\n`);
				process.stdout.write(`${chalk.bold('On Your Network:')}  ${localIpAddr}\n`);
			}

			if (onprogress) onprogress(stats);
		});
		compiler.plugin('failed', reject);

		let server = new WebpackDevServer(compiler, config.devServer);
		server.listen(port);
	});
};

const prodBuild = async (env) => {
	let compiler, client = clientConfig(env);

	await transformConfig(env, client);

	if (env.prerender) {
		let ssrConfig = serverConfig(env);
		await transformConfig(env, ssrConfig, true);
		compiler = webpack([client, ssrConfig]);
	} else {
		compiler = webpack(client);
	}

	return await new Promise((resolve, reject) => {
		compiler.run((err, stats) => {
			if (err || stats.hasErrors()) {
				showStats(stats);
				reject(chalk.red('Build failed!'));
			}
			else {
				// Timeout for plugins that work on `after-emit` event of webpack
				setTimeout(()=>	resolve(stats), 20);
			}
		});
	});
};

export function showStats(stats) {
	let info = stats.toJson("errors-only");

	if (stats.hasErrors()) {
		info.errors.map(stripBabelLoaderPrefix).forEach( message => {
			process.stderr.write(chalk.red(message)+'\n');
		});
	}

	if (stats.hasWarnings()) {
		info.warnings.map(stripBabelLoaderPrefix).forEach( message => {
			process.stderr.write(chalk.yellow(message)+'\n');
		});
	}

	return stats;
}

export function writeJsonStats(stats) {
	let outputPath = path.resolve(process.cwd(), 'stats.json');
	let jsonStats = stats.toJson({
		json: true,
		chunkModules: true,
		source: false,
	});

	jsonStats = (jsonStats.children && jsonStats.children[0]) || jsonStats;

	jsonStats.modules.forEach(stripBabelLoaderFromModuleNames);
	jsonStats.chunks.forEach(c => c.modules.forEach(stripBabelLoaderFromModuleNames));

	return fs.writeFile(outputPath, JSON.stringify(jsonStats))
		.then(() => {
			process.stdout.write('\nWebpack output stats generated.\n\n');
			process.stdout.write('You can upload your stats.json to:\n');
			process.stdout.write('- https://chrisbateman.github.io/webpack-visualizer/\n');
			process.stdout.write('- https://webpack.github.io/analyse/\n');
		});
}

const clearConsole = () => {
	process.stdout.write(
		process.platform === 'win32' ? '\x1Bc' : '\x1B[2J\x1B[3J\x1B[H'
	);
};

const stripBabelLoaderFromModuleNames = m => {
	const keysToNormalize = ['identifier', 'name', 'module', 'moduleName', 'moduleIdentifier'];

	keysToNormalize.forEach(key => {
		if (key in m) {
			m[key] = stripBabelLoaderPrefix(m[key]);
		}
	});

	if (m.reasons) {
		m.reasons.forEach(stripBabelLoaderFromModuleNames);
	}

	return m;
};

const stripBabelLoaderPrefix = log => log.replace(/@?\s*(\.\/~\/babel-loader\/lib\?{[\s\S]*?}!)/g, '');
<commit_msg>rebuild application when a new package is added<commit_after>import path from 'path';
import fs from 'fs.promised';
import ip from 'ip';
import webpack from 'webpack';
import WebpackDevServer from 'webpack-dev-server';
import chalk from 'chalk';
import getPort from 'get-port';
import clientConfig from './webpack-client-config';
import serverConfig from './webpack-server-config';
import transformConfig from './transform-config';

export default async (watch=false, env, onprogress) => {
	if (watch) {
		return await devBuild(env, onprogress);
	}

	return await prodBuild(env);
};

const devBuild = async (env, onprogress) => {
	let config = clientConfig(env);
	await transformConfig(env, config);

	let userPort = parseInt(process.env.PORT || config.devServer.port, 10) || 8080;
	let port = await getPort(userPort);

	let compiler = webpack(config);
	return await new Promise((resolve, reject) => {

		compiler.plugin('emit', (compilation, callback) => {
			var missingDeps = compilation.missingDependencies;
			var nodeModulesPath = path.resolve(__dirname, '../../../node_modules');

			if (missingDeps.some(file => file.indexOf(nodeModulesPath) !== -1)) {
				// ...tell webpack to watch node_modules recursively until they appear.
				compilation.contextDependencies.push(nodeModulesPath);
			}

			callback();
		});

		compiler.plugin('done', stats => {
			let devServer = config.devServer;

			let protocol = devServer.https ? 'https' : 'http';
			let host = process.env.HOST || devServer.host || 'localhost';

			let serverAddr = `${protocol}://${host}:${chalk.bold(port)}`;
			let localIpAddr = `${protocol}://${ip.address()}:${chalk.bold(port)}`;

			clearConsole();
			if (stats.hasErrors()) {
				process.stdout.write(chalk.red('\Build failed!\n\n'));
			} else {
				process.stdout.write(chalk.green('\nCompiled successfully!\n\n'));

				if (userPort !== port) {
					process.stdout.write(`Port ${chalk.bold(userPort)} is in use, using ${chalk.bold(port)} instead\n\n`);
				}
				process.stdout.write('You can view the application in browser.\n\n');
				process.stdout.write(`${chalk.bold('Local:')}            ${serverAddr}\n`);
				process.stdout.write(`${chalk.bold('On Your Network:')}  ${localIpAddr}\n`);
			}

			if (onprogress) onprogress(stats);
		});
		compiler.plugin('failed', reject);

		let server = new WebpackDevServer(compiler, config.devServer);
		server.listen(port);
	});
};

const prodBuild = async (env) => {
	let compiler, client = clientConfig(env);

	await transformConfig(env, client);

	if (env.prerender) {
		let ssrConfig = serverConfig(env);
		await transformConfig(env, ssrConfig, true);
		compiler = webpack([client, ssrConfig]);
	} else {
		compiler = webpack(client);
	}

	return await new Promise((resolve, reject) => {
		compiler.run((err, stats) => {
			if (err || stats.hasErrors()) {
				showStats(stats);
				reject(chalk.red('Build failed!'));
			}
			else {
				// Timeout for plugins that work on `after-emit` event of webpack
				setTimeout(()=>	resolve(stats), 20);
			}
		});
	});
};

export function showStats(stats) {
	let info = stats.toJson("errors-only");

	if (stats.hasErrors()) {
		info.errors.map(stripBabelLoaderPrefix).forEach( message => {
			process.stderr.write(chalk.red(message)+'\n');
		});
	}

	if (stats.hasWarnings()) {
		info.warnings.map(stripBabelLoaderPrefix).forEach( message => {
			process.stderr.write(chalk.yellow(message)+'\n');
		});
	}

	return stats;
}

export function writeJsonStats(stats) {
	let outputPath = path.resolve(process.cwd(), 'stats.json');
	let jsonStats = stats.toJson({
		json: true,
		chunkModules: true,
		source: false,
	});

	jsonStats = (jsonStats.children && jsonStats.children[0]) || jsonStats;

	jsonStats.modules.forEach(stripBabelLoaderFromModuleNames);
	jsonStats.chunks.forEach(c => c.modules.forEach(stripBabelLoaderFromModuleNames));

	return fs.writeFile(outputPath, JSON.stringify(jsonStats))
		.then(() => {
			process.stdout.write('\nWebpack output stats generated.\n\n');
			process.stdout.write('You can upload your stats.json to:\n');
			process.stdout.write('- https://chrisbateman.github.io/webpack-visualizer/\n');
			process.stdout.write('- https://webpack.github.io/analyse/\n');
		});
}

const clearConsole = () => {
	process.stdout.write(
		process.platform === 'win32' ? '\x1Bc' : '\x1B[2J\x1B[3J\x1B[H'
	);
};

const stripBabelLoaderFromModuleNames = m => {
	const keysToNormalize = ['identifier', 'name', 'module', 'moduleName', 'moduleIdentifier'];

	keysToNormalize.forEach(key => {
		if (key in m) {
			m[key] = stripBabelLoaderPrefix(m[key]);
		}
	});

	if (m.reasons) {
		m.reasons.forEach(stripBabelLoaderFromModuleNames);
	}

	return m;
};

const stripBabelLoaderPrefix = log => log.replace(/@?\s*(\.\/~\/babel-loader\/lib\?{[\s\S]*?}!)/g, '');
<|endoftext|>


<commit_before>var curry = require('curry');
var EventEmitter = require('events').EventEmitter;
var   registeredRoute = new EventEmitter()
    , registeredRouteError = new EventEmitter();

const PUBLIC = "public"
    , SECURED = "secured"
    , ADMINISTRATION = { SYSTEM: "systemAdministration", USER: "userAdministration", STREAM: "streamAdministration"
    };

var routes = {};

var registerRoute = curry(function(securityLevel, category, name, urlPattern, handler) {
    var route = {
          "secured": securityLevel === SECURED
        , "category": category
        , "name": name
        , "pattern": urlPattern
        , "handler": handler
    };

    if(routes[urlPattern]) {
        registeredRouteError.emit('registrationError', route);
        return;
    }

    routes[urlPattern] = route;

    var eventToEmit = '';
    if(route.secured) {
        if(route.category === ADMINISTRATION.SYSTEM) {
            eventToEmit = 'registeredSystemRoute';
        }else if(route.category === ADMINISTRATION.USER) {
            eventToEmit = 'registeredUserRoute';
        }else if(route.category === ADMINISTRATION.STREAM) {
            eventToEmit = 'registeredStreamRoute';
        }else {
            eventToEmit = 'registeredSecuredRoute';
        }
    } else
    {
        eventToEmit = 'registeredPublicRoute';
    }
    registeredRoute.emit(eventToEmit, route);
});

const registerPublicRoute = registerRoute(PUBLIC, null);
const registerSystemAdminRoute = registerRoute(SECURED, ADMINISTRATION.SYSTEM);
const registerUserAdminRoute = registerRoute(SECURED, ADMINISTRATION.USER);
const registerStreamAdminRoute = registerRoute(SECURED, ADMINISTRATION.STREAM);

//Methods
exports.registerPublicRoute                 = registerPublicRoute;
exports.registerSystemAdministrationRoute   = registerSystemAdminRoute;
exports.registerUserAdministrationRoute     = registerUserAdminRoute;
exports.registerStreamAdministrationRoute   = registerStreamAdminRoute;

//Signals
exports.routeRegistered = registeredRoute;
exports.routeRegisteredError = registeredRouteError;

//State
exports.routes = routes;
<commit_msg>Implement pattern enforcement in ApiModel<commit_after>var curry = require('curry');
var EventEmitter = require('events').EventEmitter;
var config = require('../config.json');
var   registeredRoute = new EventEmitter()
    , registeredRouteError = new EventEmitter();

const PUBLIC = "public"
    , SECURED = "secured"
    , ADMINISTRATION = { SYSTEM: "systemAdministration", USER: "userAdministration", STREAM: "streamAdministration"
    };

var routes = {};

var registerRoute = curry(function(securityLevel, category, name, urlPattern, handler) {
function applyPatternSettings(urlPattern)
{
    var prePattern = (config.enforceLeadingSlash && !urlPattern.match(/^\//)) ? '/' : '';
    var postPattern = (config.enforceTrailingSlash && !urlPattern.match(/\[\/\]$/)) ? '[/]?' : '';
    return prePattern + (urlPattern ? urlPattern.replace(/\/$/, '') + postPattern : '');
}

    var route = {
          "secured": securityLevel === SECURED
        , "category": category
        , "name": name
        , "pattern": urlPattern
        , "handler": handler
    };

    if(routes[urlPattern]) {
        registeredRouteError.emit('registrationError', route);
        return;
    }

    routes[urlPattern] = route;

    var eventToEmit = '';
    if(route.secured) {
        if(route.category === ADMINISTRATION.SYSTEM) {
            eventToEmit = 'registeredSystemRoute';
        }else if(route.category === ADMINISTRATION.USER) {
            eventToEmit = 'registeredUserRoute';
        }else if(route.category === ADMINISTRATION.STREAM) {
            eventToEmit = 'registeredStreamRoute';
        }else {
            eventToEmit = 'registeredSecuredRoute';
        }
    } else
    {
        eventToEmit = 'registeredPublicRoute';
    }
    registeredRoute.emit(eventToEmit, route);
});

const registerPublicRoute = registerRoute(PUBLIC, null);
const registerSystemAdminRoute = registerRoute(SECURED, ADMINISTRATION.SYSTEM);
const registerUserAdminRoute = registerRoute(SECURED, ADMINISTRATION.USER);
const registerStreamAdminRoute = registerRoute(SECURED, ADMINISTRATION.STREAM);

//Methods
exports.registerPublicRoute                 = registerPublicRoute;
exports.registerSystemAdministrationRoute   = registerSystemAdminRoute;
exports.registerUserAdministrationRoute     = registerUserAdminRoute;
exports.registerStreamAdministrationRoute   = registerStreamAdminRoute;

//Signals
exports.routeRegistered = registeredRoute;
exports.routeRegisteredError = registeredRouteError;

//State
exports.routes = routes;
<|endoftext|>


<commit_before>/*
 Copyright 2012 Ilya Lakhin (Илья Александрович Лахин)

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

//////////////////////////////
//         Console          //
//////////////////////////////

    var console = context.console;

    kira.console = {
        watch: function(message) {
            console.log(message);
            return message;
        },

        profile: function(block) {
            var start = new Date().getTime();
            block();
            return new Date().getTime() - start;
        }
    };<commit_msg>Console module deployment feature was implemented<commit_after>/*
 Copyright 2012 Ilya Lakhin (Илья Александрович Лахин)

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

//////////////////////////////
//         Console          //
//////////////////////////////

    kira.console = (function() {
        var nativeLog = context.console.log;

        var console = {
            watch: function(message) {
                nativeLog(message);
                return message;
            },

            profile: function(block) {
                var start = new Date().getTime();
                block();
                return new Date().getTime() - start;
            }
        };

        kira.installer.install("kira.console", [
            {
                source: console,
                destination: context.console
            },
            {
                source: {
                    watch: console.watch,
                    profile: console.profile
                },
                destination: context,
                safe: true
            }
        ]);

        return console;
    })();<|endoftext|>


<commit_before>(function(root, library) {
    if (typeof define === 'function' && define.amd) {
        define([], library);
    } else {
        root.matrix = library();
    }
})(this, function() {
    /**
     *  Custom Error "class" to be thrown on matrix.js
     *  related errors.
     */
    function MatrixError(message) {
        this.name = 'MatrixError';
        this.message = message;
    }

    /**
     *  Performs matrix addition on given matrices.
     */
    function _matrixAddition(a, b) {
        var result = [];
        for (var i = 0; i < a.length; i++) {
            result.push([]);
            for (var j = 0; j < b.length; j++) {
                result[i].push(a[i][j] + b[i][j]);
            }
        }
        return result;
    }

    /**
     *  Performs scalar addition on the given matrix and scalar value.
     */
    function _scalarAddition(matrix, scalar) {
        var result = [];
        for (var i = 0; i < matrix.length; i++) {
            result.push([]);
            for (var j = 0; j < matrix[i].length; j++) {
                result[i].push(matrix[i][j] + scalar);
            }
        }
        return result;
    }

    /**
     *  Performs matrix when given two matrices, or scalar addition when given
     *  a matrix and a scalar value.
     */
    function add(a, b) {
        if (a instanceof Array && b instanceof Array) {
            if (!valid(a) || !valid(b)) {
                throw new MatrixError('A given matrix is invalid.');
            } else if (a.length !== b.length || a[0].length !== b[0].length) {
                throw new MatrixError('Matrices are not of the same '
                    + 'dimensions.');
            }
            return _matrixAddition(a, b);
        } else if ((typeof a === 'number' && b instanceof Array)
                || (typeof b === 'number' && a instanceof Array)) {
            var matrix = a instanceof Array ? a : b;
            var scalar = a instanceof Array ? b : a;
            return _scalarAddition(matrix, scalar);
        }
        throw new MatrixError('No matrices given.');
    }

    /**
     *  Creates an identity matrix with the given size.
     */
    function identity(size) {
        if (size !== undefined && size >= 0) {
            var matrix = [];
            for (var i = 0; i < size; i++) {
                matrix.push([]);
                for (var j = 0; j < size; j++) {
                    matrix[i][j] = i === j ? 1 : 0;
                }
            }
            return matrix;
        }
        throw new MatrixError('Invalid matrix dimensions given.');
    }

    /**
     *  Accepts a matrix and returns the transpose of the
     *  given matrix.
     */
    function transpose(matrix) {
        if (valid(matrix)) {
            var result = [];
            for (var i = 0; matrix.length && i < matrix[0].length; i++) {
                result[i] = [];
                for (var j = 0; j < matrix.length; j++) {
                    result[i].push(matrix[j][i]);
                }
            }
            return result;
        }
        throw new MatrixError('Given matrix is invalid.');
    }

    /**
     *  Validates a given matrix, returning true if it is
     *  valid or false otherwise.
     */
    function valid(matrix) {
        if (matrix instanceof Array) {
            for (var i = 0; i < matrix.length - 1; i++) {
                if (matrix[i].length !== matrix[i + 1].length) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    /**
     *  Creates a ones matrix with the given dimensions.
     */
    function ones(rows, columns) {
        columns = columns || rows;
        if (typeof rows === 'number' && typeof columns === 'number') {
            var matrix = [];
            for (var i = 0; i < rows; i++) {
                matrix.push([]);
                for (var j = 0; j < columns; j++) {
                    matrix[i].push(1);
                }
            }
            return matrix;
        }
        throw new TypeError('Matrix dimensions should be integers.');
    }

    /**
     *  Creates a zeros matrix with the given dimensions.
     */
    function zeros(rows, columns) {
        columns = columns || rows;
        if (typeof rows === 'number' && typeof columns === 'number') {
            var matrix = [];
            for (var i = 0; i < rows; i++) {
                matrix.push([]);
                for (var j = 0; j < columns; j++) {
                    matrix[i].push(0);
                }
            }
            return matrix;
        }
        throw new TypeError('Matrix dimensions should be integers.');
    }

    // Attach matrix methods to Array.prototype
    Array.prototype.add = function(value) {
        return add(this, value);
    };

    Array.prototype.valid = function() {
        return valid(this);
    };

    Array.prototype.transpose = function() {
        return transpose(this);
    };

    return {
        add: add,
        multiply: null,
        transpose: transpose,
        inverse: null,
        determinant: null,
        identity: identity,
        valid: valid,
        ones: ones,
        zeros: zeros,
        MatrixError: MatrixError
    };
});
<commit_msg>integrated matrix.identity into array prototype<commit_after>(function(root, library) {
    if (typeof define === 'function' && define.amd) {
        define([], library);
    } else {
        root.matrix = library();
    }
})(this, function() {
    /**
     *  Custom Error "class" to be thrown on matrix.js
     *  related errors.
     */
    function MatrixError(message) {
        this.name = 'MatrixError';
        this.message = message;
    }

    /**
     *  Performs matrix addition on given matrices.
     */
    function _matrixAddition(a, b) {
        var result = [];
        for (var i = 0; i < a.length; i++) {
            result.push([]);
            for (var j = 0; j < b.length; j++) {
                result[i].push(a[i][j] + b[i][j]);
            }
        }
        return result;
    }

    /**
     *  Performs scalar addition on the given matrix and scalar value.
     */
    function _scalarAddition(matrix, scalar) {
        var result = [];
        for (var i = 0; i < matrix.length; i++) {
            result.push([]);
            for (var j = 0; j < matrix[i].length; j++) {
                result[i].push(matrix[i][j] + scalar);
            }
        }
        return result;
    }

    /**
     *  Performs matrix when given two matrices, or scalar addition when given
     *  a matrix and a scalar value.
     */
    function add(a, b) {
        if (a instanceof Array && b instanceof Array) {
            if (!valid(a) || !valid(b)) {
                throw new MatrixError('A given matrix is invalid.');
            } else if (a.length !== b.length || a[0].length !== b[0].length) {
                throw new MatrixError('Matrices are not of the same '
                    + 'dimensions.');
            }
            return _matrixAddition(a, b);
        } else if ((typeof a === 'number' && b instanceof Array)
                || (typeof b === 'number' && a instanceof Array)) {
            var matrix = a instanceof Array ? a : b;
            var scalar = a instanceof Array ? b : a;
            return _scalarAddition(matrix, scalar);
        }
        throw new MatrixError('No matrices given.');
    }

    /**
     *  Creates an identity matrix with the given size.
     */
    function identity(size) {
        if (size !== undefined && size >= 0) {
            var matrix = [];
            for (var i = 0; i < size; i++) {
                matrix.push([]);
                for (var j = 0; j < size; j++) {
                    matrix[i][j] = i === j ? 1 : 0;
                }
            }
            return matrix;
        }
        throw new MatrixError('Invalid matrix dimensions given.');
    }

    /**
     *  Accepts a matrix and returns the transpose of the
     *  given matrix.
     */
    function transpose(matrix) {
        if (valid(matrix)) {
            var result = [];
            for (var i = 0; matrix.length && i < matrix[0].length; i++) {
                result[i] = [];
                for (var j = 0; j < matrix.length; j++) {
                    result[i].push(matrix[j][i]);
                }
            }
            return result;
        }
        throw new MatrixError('Given matrix is invalid.');
    }

    /**
     *  Validates a given matrix, returning true if it is
     *  valid or false otherwise.
     */
    function valid(matrix) {
        if (matrix instanceof Array) {
            for (var i = 0; i < matrix.length - 1; i++) {
                if (matrix[i].length !== matrix[i + 1].length) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    /**
     *  Creates a ones matrix with the given dimensions.
     */
    function ones(rows, columns) {
        columns = columns || rows;
        if (typeof rows === 'number' && typeof columns === 'number') {
            var matrix = [];
            for (var i = 0; i < rows; i++) {
                matrix.push([]);
                for (var j = 0; j < columns; j++) {
                    matrix[i].push(1);
                }
            }
            return matrix;
        }
        throw new TypeError('Matrix dimensions should be integers.');
    }

    /**
     *  Creates a zeros matrix with the given dimensions.
     */
    function zeros(rows, columns) {
        columns = columns || rows;
        if (typeof rows === 'number' && typeof columns === 'number') {
            var matrix = [];
            for (var i = 0; i < rows; i++) {
                matrix.push([]);
                for (var j = 0; j < columns; j++) {
                    matrix[i].push(0);
                }
            }
            return matrix;
        }
        throw new TypeError('Matrix dimensions should be integers.');
    }

    // Attach matrix methods to Array.prototype
    Array.prototype.add = function(value) {
        return add(this, value);
    };

    Array.prototype.identity = function() {
        return identity(this);
    };

    Array.prototype.valid = function() {
        return valid(this);
    };

    Array.prototype.transpose = function() {
        return transpose(this);
    };

    return {
        add: add,
        multiply: null,
        transpose: transpose,
        inverse: null,
        determinant: null,
        identity: identity,
        valid: valid,
        ones: ones,
        zeros: zeros,
        MatrixError: MatrixError
    };
});
<|endoftext|>


<commit_before>var _isReady = false,
    _registration = [];

var _bind = function(fn) {
    if (document.readyState === 'complete') {
        return fn();
    }

    if (document.addEventListener) {
        return document.addEventListener('DOMContentLoaded', fn);
    }

    document.attachEvent('onreadystatechange', function() {
        if (document.readyState === 'interactive') { fn(); }
    });
};

var _makeCalls = function() {
    var idx = 0,
        length = _registration.length;
    for (; idx < length; idx++) {
        _registration[idx]();
    }
    _registration.length = 0;
};

_bind(function() {
    if (_isReady) { return; }

    _isReady = true;
    _makeCalls();
});

module.exports = function(callback) {
    if (_isReady) {
        callback();
        return this;
    }

    _registration.push(callback);
    return this;
};
<commit_msg>Fixed onready in IE 8<commit_after>var _isReady = false,
    _registration = [];

var _bind = function(fn) {
    if (document.readyState === 'complete') {
        return fn();
    }

    if (document.addEventListener) {
        return document.addEventListener('DOMContentLoaded', fn);
    }

    document.attachEvent('onreadystatechange', function() {
        if (document.readyState === 'interactive') { fn(); }
    });
    window.attachEvent('onload', fn);
};

var _makeCalls = function() {
    var idx = 0,
        length = _registration.length;
    for (; idx < length; idx++) {
        _registration[idx]();
    }
    _registration.length = 0;
};

_bind(function() {
    if (_isReady) { return; }

    _isReady = true;
    _makeCalls();
});

module.exports = function(callback) {
    if (_isReady) {
        callback();
        return this;
    }

    _registration.push(callback);
    return this;
};
<|endoftext|>


<commit_before>
var largest_dimension = function(matrix) {
  var i, j, column_len = matrix[0].length, row_len = matrix.length, max=0, val, prev;
  matrix.forEach(function(row) {
    var i=0, len=row.length, prev;
    for (; i<len; i+=1) {
      prev = row[i-1] || 0;
      row[i] = row[i]==1 ? row[i]+prev : row[i];
    }
  });
  for (i=0; i<row_len; i+=1) {
    for (j=0; j<column_len; j+=1) {
      val = matrix[i][j];
      prev = (matrix[i-1]&&matrix[i-1][j]) || 0;
      if (val != 0) {
	matrix[i][j] += prev;
      }
      if (matrix[i][j]>=max) max = matrix[i][j];
    }
  }
  return max;
};

console.log(largest_dimension([
  [0,0,0,1,0],
  [1,1,1,0,0],
  [1,1,1,1,0],
  [1,1,0,0,0],
  [1,1,1,1,0]
]));

var rotate = function(matrix) {
  var temp, head, tail, offset, outer, offset, len = matrix.length;
  for (outer=0; outer<len/2; outer+=1) {
    for (offset=0; offset<len-outer*2-1; offset+=1) {
      temp = matrix[outer+offset][outer];
      matrix[outer+offset][outer] = matrix[outer][len-outer-offset-1];
      matrix[outer][len-outer-offset-1] = matrix[len-outer-offset-1][len-outer-1];
      matrix[len-outer-offset-1][len-outer-1] = matrix[len-outer-1][outer+offset];
      matrix[len-outer-1][outer+offset] = temp;
    }
  }
  return matrix;
};

console.log(rotate([
  [1,2,3,4,5],
  [11,12,13,14,15],
  [21,22,23,24,25],
  [31,32,33,34,35],
  [41,42,43,44,45]
]));<commit_msg>Implemented region fill in a matrix<commit_after>
var largest_dimension = function(matrix) {
  var i, j, column_len = matrix[0].length, row_len = matrix.length, max=0, val, prev;
  matrix.forEach(function(row) {
    var i=0, len=row.length, prev;
    for (; i<len; i+=1) {
      prev = row[i-1] || 0;
      row[i] = row[i]==1 ? row[i]+prev : row[i];
    }
  });
  for (i=0; i<row_len; i+=1) {
    for (j=0; j<column_len; j+=1) {
      val = matrix[i][j];
      prev = (matrix[i-1]&&matrix[i-1][j]) || 0;
      if (val != 0) {
	matrix[i][j] += prev;
      }
      if (matrix[i][j]>=max) max = matrix[i][j];
    }
  }
  return max;
};

console.log(largest_dimension([
  [0,0,0,1,0],
  [1,1,1,0,0],
  [1,1,1,1,0],
  [1,1,0,0,0],
  [1,1,1,1,0]
]));

var rotate = function(matrix) {
  var temp, head, tail, offset, outer, offset, len = matrix.length;
  for (outer=0; outer<len/2; outer+=1) {
    for (offset=0; offset<len-outer*2-1; offset+=1) {
      temp = matrix[outer+offset][outer];
      matrix[outer+offset][outer] = matrix[outer][len-outer-offset-1];
      matrix[outer][len-outer-offset-1] = matrix[len-outer-offset-1][len-outer-1];
      matrix[len-outer-offset-1][len-outer-1] = matrix[len-outer-1][outer+offset];
      matrix[len-outer-1][outer+offset] = temp;
    }
  }
  return matrix;
};

console.log(rotate([
  [1,2,3,4,5],
  [11,12,13,14,15],
  [21,22,23,24,25],
  [31,32,33,34,35],
  [41,42,43,44,45]
]));

var region_fill = function(matrix, x, y, color) {
  var chk = function(_x,_y,_c) {
    return matrix[_y]!=null && matrix[_y][_x]!=null && matrix[_y][_x]!=_c;
  };
  matrix[y][x] = color;
  chk(x-1,y,color) && region_fill(matrix, x-1,y, color);
  chk(x,y+1,color) && region_fill(matrix, x,y+1, color);
  chk(x+1,y,color) && region_fill(matrix, x+1,y, color);
  chk(x,y-1,color) && region_fill(matrix, x,y-1, color);
};

var matrix = [
  [1,1,0,1,1],
  [0,1,0,0,1],
  [1,0,0,0,1],
  [1,1,0,1,1],
  [0,0,1,0,0]
];
region_fill(matrix, 2, 2, 1);
console.log(matrix);<|endoftext|>


<commit_before>"use strict";

/**
 * @constructor
 */
function Memory(buffer, memory_size)
{
    var int8array = new Uint8Array(buffer),
        int16array = new Uint16Array(buffer),
        int8sarray = new Int8Array(buffer),
        int32sarray = new Int32Array(buffer);

    this.mem8 = int8array;
    this.mem8s = int8sarray;
    this.mem32s = int32sarray;

    this.buffer = buffer;

    // debug function called by all memory reads and writes

    function debug_write(addr, size, value)
    {
        if(!DEBUG)
        {
            return;
        }

        //dbg_assert(typeof value === "number" && !isNaN(value));
        debug_read(addr, size, true);
    }

    /** @param {boolean=} is_write */
    function debug_read(addr, size, is_write)
    {
        if(!DEBUG)
        {
            return;
        }

        dbg_assert(typeof addr === "number");
        dbg_assert(!isNaN(addr));
    };

    this.dump_all = function(start, end)
    {
        start = start || 0;
        end = end || 0x100000;

        // textarea method: (slow)
        //var result_string = "";

        //for(var i = start; i < start + end; i++)
        //{
        //    result_string += String.fromCharCode(int8array[i]);
        //}

        //dump_text(btoa(result_string));

        // save as method:
        dump_file(buffer.slice(start, end), "memory.bin");

    };

    this.dump = function(addr, length)
    {
        length = length || 4 * 0x10;
        var line, byt;

        for(var i = 0; i < length >> 4; i++)
        {
            line = h(addr + (i << 4), 5) + "   ";

            for(var j = 0; j < 0x10; j++)
            {
                byt = this.read8(addr + (i << 4) + j);
                line += h(byt, 2) + " ";
            }

            line += "  ";

            for(j = 0; j < 0x10; j++)
            {
                byt = this.read8(addr + (i << 4) + j);
                line += (byt < 33 || byt > 126) ? "." : String.fromCharCode(byt);
            }

            dbg_log(line);
        }
    };

    this.print_memory_map = function()
    {
        var width = 0x80,
            height = 0x10,
            block_size = memory_size / width / height | 0,
            row;

        for(var i = 0; i < height; i++)
        {
            row = "0x" + h(i * width * block_size, 8) + " | ";

            for(var j = 0; j < width; j++)
            {
                var used = this.mem32s[(i * width + j) * block_size] > 0;

                row += used ? "X" : " ";
            }

            dbg_log(row);
        }
    };

    var
        /**
         * Arbritary value, the minimum number of bytes that can be mapped
         * by one device. This might be spec'd somewhere ...
         *
         * @const
         */
        MMAP_BLOCK_BITS = 14,
        /** @const */
        MMAP_BLOCK_SIZE = 1 << MMAP_BLOCK_BITS,

        // this only supports a 32 bit address space
        memory_map_registered = new Int8Array(1 << (32 - MMAP_BLOCK_BITS)),

        memory_map_read = [],
        memory_map_write = [];

    dbg_assert((memory_size & MMAP_BLOCK_SIZE - 1) === 0);

    /**
     * @param addr {number}
     * @param size {number}
     *
     */
    this.mmap_register = function(addr, size, read_func, write_func)
    {
        dbg_log("mmap_register addr=" + h(addr, 8) + ": size=" + h(size, 8), LOG_IO);

        dbg_assert((addr & MMAP_BLOCK_SIZE - 1) === 0);
        dbg_assert(size && (size & MMAP_BLOCK_SIZE - 1) === 0);

        var aligned_addr = addr >>> MMAP_BLOCK_BITS;

        for(; size > 0; aligned_addr++)
        {
            memory_map_registered[aligned_addr] = 1;

            memory_map_read[aligned_addr] = do_read;
            memory_map_write[aligned_addr] = do_write;

            size -= MMAP_BLOCK_SIZE;
        }

        function do_read(read_addr)
        {
            return read_func(read_addr - addr | 0);
        }

        function do_write(write_addr, value)
        {
            write_func(write_addr - addr | 0, value);
        }
    };

    for(var i = 0; (i << MMAP_BLOCK_BITS) < memory_size; i++)
    {
        // avoid sparse arrays
        memory_map_read[i] = memory_map_write[i] = undefined;
    }

    this.mmap_register(memory_size, 0x100000000 - memory_size,
        function(addr) {
            // read outside of the memory size
            addr += memory_size;
            dbg_log("Read from unmapped memory space, addr=" + h(addr, 8), LOG_IO);
            return 0;
        },
        function(addr, value) {
            // write outside of the memory size
            addr += memory_size;
            dbg_log("Write to unmapped memory space, addr=" + h(addr, 8) + " value=" + h(value, 2), LOG_IO);
        });

    function mmap_read8(addr)
    {
        return memory_map_read[addr >>> MMAP_BLOCK_BITS](addr);
    };

    function mmap_write8(addr, value)
    {
        memory_map_write[addr >>> MMAP_BLOCK_BITS](addr, value);
    };

    function mmap_read32(addr)
    {
        return mmap_read8(addr) | mmap_read8(addr + 1) << 8 |
            mmap_read8(addr + 2) << 16 | mmap_read8(addr + 3) << 24;
    };

    function mmap_write32(addr, value)
    {
        mmap_write8(addr, value & 0xFF);
        mmap_write8(addr + 1, value >> 8 & 0xFF);
        mmap_write8(addr + 2, value >> 16 & 0xFF);
        mmap_write8(addr + 3, value >>> 24);
    };

    /**
     * @param addr {number}
     */
    this.read8s = function(addr)
    {
        debug_read(addr, 1);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            return mmap_read8(addr) << 24 >> 24;
        }
        else
        {
            return int8sarray[addr];
        }
    };

    /**
     * @param addr {number}
     */
    this.read8 = function(addr)
    {
        debug_read(addr, 1);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            return mmap_read8(addr);
        }
        else
        {
            return int8array[addr];
        }
    };

    /**
     * @param addr {number}
     */
    this.read16 = function(addr)
    {
        debug_read(addr, 2);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            return mmap_read8(addr) | mmap_read8(addr + 1) << 8;
        }
        else
        {
            return int8array[addr] | int8array[addr + 1] << 8;
        }
    };

    /**
     * @param addr {number}
     */
    this.read_aligned16 = function(addr)
    {
        debug_read(addr, 2);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            return mmap_read8(addr) | mmap_read8(addr + 1) << 8;
        }
        else
        {
            return int16array[addr >> 1];
        }
    };

    /**
     * @param addr {number}
     */
    this.read32s = function(addr)
    {
        debug_read(addr, 4);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            return mmap_read32(addr) | 0;
        }
        else
        {
            return int8array[addr] | int8array[addr + 1] << 8 |
                int8array[addr + 2] << 16 | int8array[addr + 3] << 24;
        }
    };

    /**
     * @param addr {number}
     */
    this.read_aligned32 = function(addr)
    {
        debug_read(addr, 4);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            return mmap_read32(addr) | 0;
        }
        else
        {
            return int32sarray[addr >> 2];
        }
    };

    /**
     * @param addr {number}
     * @param value {number}
     */
    this.write8 = function(addr, value)
    {
        debug_write(addr, 1, value);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            mmap_write8(addr, value);
        }
        else
        {
            int8array[addr] = value;
        }
    };

    /**
     * @param addr {number}
     * @param value {number}
     */
    this.write16 = function(addr, value)
    {
        debug_write(addr, 2, value);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            mmap_write8(addr, value & 0xff);
            mmap_write8(addr + 1, value >> 8 & 0xff);
        }
        else
        {
            int8array[addr] = value;
            int8array[addr + 1] = value >> 8;
        }
    };

    /**
     * @param addr {number}
     * @param value {number}
     */
    this.write_aligned16 = function(addr, value)
    {
        debug_write(addr, 2, value);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            mmap_write8(addr, value & 0xff);
            mmap_write8(addr + 1, value >> 8 & 0xff);
        }
        else
        {
            int16array[addr >> 1] = value;
        }
    };

    /**
     * @param addr {number}
     * @param value {number}
     */
    this.write32 = function(addr, value)
    {
        debug_write(addr, 4, value);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            mmap_write32(addr, value);
        }
        else
        {
            int8array[addr] = value;
            int8array[addr + 1] = value >> 8;
            int8array[addr + 2] = value >> 16;
            int8array[addr + 3] = value >> 24;
        }
    };

    this.write_aligned32 = function(addr, value)
    {
        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            mmap_write32(addr, value);
        }
        else
        {
            int32sarray[addr >> 2] = value;
        }
    };

    /**
     * @param offset {number}
     * @param blob {Array.<number>}
     */
    this.write_blob = function(blob, offset)
    {
        dbg_assert(blob && blob.length);
        int8array.set(blob, offset);
    };

    /**
     * zero byte terminated string
     */
    this.read_string = function(addr)
    {
        var str = "",
            data_byte;

        while(data_byte = this.read8(addr))
        {
            str += String.fromCharCode(data_byte);
            addr++;
        }

        return str;
    };

    this.write_string = function(str, addr)
    {
        for(var i = 0; i < str.length; i++)
        {
            this.write8(addr + i, str.charCodeAt(i));
        }
    };
}
<commit_msg>Change in aligned read/write, add size parameter to mmap_register<commit_after>"use strict";

/**
 * @constructor
 */
function Memory(buffer, memory_size)
{
    var int8array = new Uint8Array(buffer),
        int16array = new Uint16Array(buffer),
        int8sarray = new Int8Array(buffer),
        int32sarray = new Int32Array(buffer);

    this.mem8 = int8array;
    this.mem8s = int8sarray;
    this.mem32s = int32sarray;

    this.buffer = buffer;

    // debug function called by all memory reads and writes

    function debug_write(addr, size, value)
    {
        if(!DEBUG)
        {
            return;
        }

        //dbg_assert(typeof value === "number" && !isNaN(value));
        debug_read(addr, size, true);
    }

    /** @param {boolean=} is_write */
    function debug_read(addr, size, is_write)
    {
        if(!DEBUG)
        {
            return;
        }

        dbg_assert(typeof addr === "number");
        dbg_assert(!isNaN(addr));
    };

    this.dump_all = function(start, end)
    {
        start = start || 0;
        end = end || 0x100000;

        // textarea method: (slow)
        //var result_string = "";

        //for(var i = start; i < start + end; i++)
        //{
        //    result_string += String.fromCharCode(int8array[i]);
        //}

        //dump_text(btoa(result_string));

        // save as method:
        dump_file(buffer.slice(start, end), "memory.bin");

    };

    this.dump = function(addr, length)
    {
        length = length || 4 * 0x10;
        var line, byt;

        for(var i = 0; i < length >> 4; i++)
        {
            line = h(addr + (i << 4), 5) + "   ";

            for(var j = 0; j < 0x10; j++)
            {
                byt = this.read8(addr + (i << 4) + j);
                line += h(byt, 2) + " ";
            }

            line += "  ";

            for(j = 0; j < 0x10; j++)
            {
                byt = this.read8(addr + (i << 4) + j);
                line += (byt < 33 || byt > 126) ? "." : String.fromCharCode(byt);
            }

            dbg_log(line);
        }
    };

    this.print_memory_map = function()
    {
        var width = 0x80,
            height = 0x10,
            block_size = memory_size / width / height | 0,
            row;

        for(var i = 0; i < height; i++)
        {
            row = "0x" + h(i * width * block_size, 8) + " | ";

            for(var j = 0; j < width; j++)
            {
                var used = this.mem32s[(i * width + j) * block_size] > 0;

                row += used ? "X" : " ";
            }

            dbg_log(row);
        }
    };

    var
        /**
         * Arbritary value, the minimum number of bytes that can be mapped
         * by one device. This might be spec'd somewhere ...
         *
         * @const
         */
        MMAP_BLOCK_BITS = 14,
        /** @const */
        MMAP_BLOCK_SIZE = 1 << MMAP_BLOCK_BITS,

        // this only supports a 32 bit address space
        memory_map_registered = new Int8Array(1 << (32 - MMAP_BLOCK_BITS)),

        memory_map_read = [],
        memory_map_write = [];

    dbg_assert((memory_size & MMAP_BLOCK_SIZE - 1) === 0);

    /**
     * @param addr {number}
     * @param size {number}
     *
     */
    this.mmap_register = function(addr, size, fn_size, read_func, write_func)
    {
        dbg_log("mmap_register addr=" + h(addr >>> 0, 8) + " size=" + h(size, 8) + " fn_size=" + fn_size, LOG_IO);

        dbg_assert((addr & MMAP_BLOCK_SIZE - 1) === 0);
        dbg_assert(size && (size & MMAP_BLOCK_SIZE - 1) === 0);
        dbg_assert(fn_size === 1 || fn_size === 4);

        var aligned_addr = addr >>> MMAP_BLOCK_BITS;

        for(; size > 0; aligned_addr++)
        {
            memory_map_registered[aligned_addr] = fn_size;

            memory_map_read[aligned_addr] = do_read;
            memory_map_write[aligned_addr] = do_write;

            size -= MMAP_BLOCK_SIZE;
        }

        function do_read(read_addr)
        {
            return read_func(read_addr - addr | 0);
        }

        function do_write(write_addr, value)
        {
            write_func(write_addr - addr | 0, value);
        }
    };

    for(var i = 0; (i << MMAP_BLOCK_BITS) < memory_size; i++)
    {
        // avoid sparse arrays
        memory_map_read[i] = memory_map_write[i] = undefined;
    }

    this.mmap_register(memory_size, 0x100000000 - memory_size, 1,
        function(addr) {
            // read outside of the memory size
            addr += memory_size;
            dbg_log("Read from unmapped memory space, addr=" + h(addr >>> 0, 8), LOG_IO);
            return 0xFF;
        },
        function(addr, value) {
            // write outside of the memory size
            addr += memory_size;
            dbg_log("Write to unmapped memory space, addr=" + h(addr >>> 0, 8) + " value=" + h(value, 2), LOG_IO);
        });

    function mmap_read8(addr)
    {
        return memory_map_read[addr >>> MMAP_BLOCK_BITS](addr);
    }

    function mmap_write8(addr, value)
    {
        memory_map_write[addr >>> MMAP_BLOCK_BITS](addr, value);
    }

    function mmap_read32(addr)
    {
        var aligned_addr = addr >>> MMAP_BLOCK_BITS,
            fn = memory_map_read[aligned_addr];

        if(memory_map_registered[aligned_addr] === 4)
        {
            return fn(addr);
        }
        else
        {
            return fn(addr) | fn(addr + 1) << 8 | fn(addr + 2) << 16 | fn(addr + 3) << 24;
        }
    }

    function mmap_write32(addr, value)
    {
        var aligned_addr = addr >>> MMAP_BLOCK_BITS,
            fn = memory_map_write[aligned_addr];

        if(memory_map_registered[aligned_addr] === 4)
        {
            fn(addr, value);
        }
        else
        {
            fn(addr, value & 0xFF);
            fn(addr + 1, value >> 8 & 0xFF);
            fn(addr + 2, value >> 16 & 0xFF);
            fn(addr + 3, value >>> 24);
        }
    }

    /**
     * @param addr {number}
     */
    this.read8 = function(addr)
    {
        debug_read(addr, 1);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            return mmap_read8(addr);
        }
        else
        {
            return int8array[addr];
        }
    };

    /**
     * @param addr {number}
     */
    this.read16 = function(addr)
    {
        debug_read(addr, 2);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            return mmap_read8(addr) | mmap_read8(addr + 1) << 8;
        }
        else
        {
            return int8array[addr] | int8array[addr + 1] << 8;
        }
    };

    /**
     * @param addr {number}
     */
    this.read_aligned16 = function(addr)
    {
        debug_read(addr, 2);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS - 1])
        {
            addr <<= 1;
            return mmap_read8(addr) | mmap_read8(addr + 1) << 8;
        }
        else
        {
            return int16array[addr >> 1];
        }
    };

    /**
     * @param addr {number}
     */
    this.read32s = function(addr)
    {
        debug_read(addr, 4);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            return mmap_read32(addr);
        }
        else
        {
            return int8array[addr] | int8array[addr + 1] << 8 |
                int8array[addr + 2] << 16 | int8array[addr + 3] << 24;
        }
    };

    /**
     * @param addr {number}
     */
    this.read_aligned32 = function(addr)
    {
        debug_read(addr, 4);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS - 2])
        {
            return mmap_read32(addr << 2);
        }
        else
        {
            return int32sarray[addr];
        }
    };

    /**
     * @param addr {number}
     * @param value {number}
     */
    this.write8 = function(addr, value)
    {
        debug_write(addr, 1, value);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            mmap_write8(addr, value);
        }
        else
        {
            int8array[addr] = value;
        }
    };

    /**
     * @param addr {number}
     * @param value {number}
     */
    this.write16 = function(addr, value)
    {
        debug_write(addr, 2, value);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            mmap_write8(addr, value & 0xff);
            mmap_write8(addr + 1, value >> 8 & 0xff);
        }
        else
        {
            int8array[addr] = value;
            int8array[addr + 1] = value >> 8;
        }
    };

    /**
     * @param addr {number}
     * @param value {number}
     */
    this.write_aligned16 = function(addr, value)
    {
        debug_write(addr, 2, value);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS - 1])
        {
            addr <<= 1;
            mmap_write8(addr, value & 0xff);
            mmap_write8(addr + 1, value >> 8 & 0xff);
        }
        else
        {
            int16array[addr] = value;
        }
    };

    /**
     * @param addr {number}
     * @param value {number}
     */
    this.write32 = function(addr, value)
    {
        debug_write(addr, 4, value);

        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS])
        {
            mmap_write32(addr, value);
        }
        else
        {
            int8array[addr] = value;
            int8array[addr + 1] = value >> 8;
            int8array[addr + 2] = value >> 16;
            int8array[addr + 3] = value >> 24;
        }
    };

    this.write_aligned32 = function(addr, value)
    {
        if(memory_map_registered[addr >>> MMAP_BLOCK_BITS - 2])
        {
            mmap_write32(addr << 2, value);
        }
        else
        {
            int32sarray[addr] = value;
        }
    };

    /**
     * @param offset {number}
     * @param blob {Array.<number>}
     */
    this.write_blob = function(blob, offset)
    {
        dbg_assert(blob && blob.length);
        int8array.set(blob, offset);
    };

    /**
     * zero byte terminated string
     */
    this.read_string = function(addr)
    {
        var str = "",
            data_byte;

        while(data_byte = this.read8(addr))
        {
            str += String.fromCharCode(data_byte);
            addr++;
        }

        return str;
    };

    this.write_string = function(str, addr)
    {
        for(var i = 0; i < str.length; i++)
        {
            this.write8(addr + i, str.charCodeAt(i));
        }
    };
}
<|endoftext|>


<commit_before>import 'document-register-element'

import Node from '../motor/Node'

import jss from '../jss'

const nodeList = []
let stylesheet = null

const style = {
    motorNodeElement: {
        display:         'block',
        position:        'absolute',
        top:             '0',
        left:            '0',

        // TODO: set via JavaScript. Defaults to [0.5,0.5,0.5] (the Z axis
        // doesn't apply for DOM elements, but will for 3D objects in WebGL.)
        transformOrigin: '50% 50% 0', // default

        transformStyle:  'preserve-3d',
    },
}

class MotorHTMLNode extends HTMLElement {
    createdCallback() {
        //console.log('<motor-node> createdCallback()', this.id)
        this._attached = false
        this._cleanedUp = true
        this.node = null // to hold the imperative API Node instance.

        // XXX: "this.mountPromise" vs "this.ready":
        // "ready" seems to be more intuitive on the HTML side because
        // if the user has a reference to a motor-node or a motor-scene
        // and it exists in DOM, then it is already "mounted" from the
        // HTML API perspective. Maybe we can use "mountPromise" for
        // the imperative API, and "ready" for the HTML API. For example:
        //
        // await $('motor-scene')[0].ready // When using the HTML API
        // await node.mountPromise // When using the imperative API
        //
        // Or, maybe we can just use ".ready" in both APIs?...
        this._resolveReadyPromise = null
        this.ready = new Promise(r => this._resolveReadyPromise = r)

        nodeList.push(this)
        if (!stylesheet) {
            //console.log('Creating Node style.')
            // XXX create stylesheet inside animation frame?
            stylesheet = jss.createStyleSheet(style).attach()
        }
        this.classList.add(stylesheet.classes.motorNodeElement)
    }

    makeImperativeNode() {
        return new Node({}, this)
    }

    /**
     * Either this gets called by the imperative API when the imperative API
     * makes one of these elements, or it gets called when this element gets
     * appended to another motor-node.
     * @private
     */
    _init(imperativeMotorNode) {
        if (imperativeMotorNode && imperativeMotorNode instanceof Node)
            this.node = imperativeMotorNode
        else
            this.node = this.makeImperativeNode()

        this.signalWhenReady()
    }

    async signalWhenReady() {
        await this.node.mountPromise
        this._resolveReadyPromise()
    }

    attachedCallback() {
        //console.log('<motor-node> attachedCallback()', this.id)

        // Check that motor-nodes are mounted to motor-scenes or motor-nodes.
        // Scene can be mounted to any element. In the future we could inspect
        // the scene mount point, and advise about posisble styling issues
        // (f.e. making the scene container have a height).
        // TODO: different check needed when using is="" attributes.
        if (this.nodeName == 'MOTOR-NODE')
            if (! (this.parentNode.nodeName == 'MOTOR-NODE' || this.parentNode.nodeName == 'MOTOR-SCENE') )
                throw new Error('A <motor-node> element must be appended only to <motor-scene> or other <motor-node> elements.')

        if (!this.node)
            this._init()

        this._attached = true

        if (this._cleanedUp) {
            this._cleanedUp = false

            // make stuff here if needed.
        }

        // Attach this motor-node's Node to the parent motor-node's
        // Node (doesn't apply to motor-scene, which doesn't have a
        // parent to attach to).
        // TODO: prevent this call if attachedCallback happened to to call to
        // addChild on the imperative side.
        if (this.nodeName != 'MOTOR-SCENE')
            this.parentNode.node.addChild(this.node, true)
    }

    // TODO XXX: remove corresponding imperative Node from it's parent.
    async detachedCallback() {
        //console.log('<motor-node> detachedCallback()')
        this._attached = false

        // XXX Deferr to the next tick before cleaning up in case the element
        // is actually being re-attached somewhere else within this same tick
        // (detaching and attaching is synchronous, so by deferring to the next
        // tick we'll be able to know if the element was re-attached or not in
        // order to clean up or not). If the element gets re-attached before
        // the next tick, then we want to preserve the style sheet, preserve
        // the animation frame, and keep the scene in the sceneList by not
        // running the following this.cleanUp() call. {{
        await Promise.resolve() // deferr to the next tick.

        // If the scene wasn't re-attached in the last tick, clean up.
        // TODO (performance): Should we coordinate this.cleanUp() with
        // animation loop to prevent jank? MotorHTMLScene.cleanUp may remove a
        // JSS stylesheet. Is that something we want to do in a frame?
        if (!this._attached && !this._cleanedUp) {
            this.cleanUp()
        }

        // }}
    }

    cleanUp() {
        nodeList.pop(this)
        if (nodeList.length == 0) {
            stylesheet.detach()
            stylesheet = null
        }

        this._cleanedUp = true
    }

    attributeChangedCallback(attribute, oldValue, newValue) {
        //console.log('<motor-node> attributeChangedCallback', this.id, attribute, this.node)
        this.updateNodeProperty(attribute, oldValue, newValue)
    }

    async updateNodeProperty(attribute, oldValue, newValue) {
        // TODO: Handle actual values (not just string property values as
        // follows) for performance; especially when DOMMatrix is supported
        // by browsers.

        // if not initialized yet, wait.
        if (!this.node) await this.ready

        // attributes on our HTML elements are the same name as those on
        // the Node class (the setters).
        if (newValue !== oldValue) {
            if (attribute.match(/opacity/i))
                this.node[attribute] = parseFloat(newValue)
            else if (attribute.match(/sizemode/i))
                this.node[attribute] = parseStringArray(newValue)
            else if (
                attribute.match(/rotation/i)
                || attribute.match(/scale/i)
                || attribute.match(/position/i)
                || attribute.match(/absoluteSize/i)
                || attribute.match(/proportionalSize/i)
                || attribute.match(/align/i)
                || attribute.match(/mountPoint/i)
                || attribute.match(/origin/i) // origin is TODO on imperative side.
            ) {
                this.node[attribute] = parseNumberArray(newValue)
            }
            else {
                /* nothing, ignore other attributes */
            }
        }
    }
}
MotorHTMLNode = document.registerElement('motor-node', MotorHTMLNode)

export default MotorHTMLNode

function parseNumberArray(str) {
    checkIsNumberArrayString(str)

    let numbers = str.split(',')

    numbers = numbers.map(num => window.parseFloat(num))
    return numbers
}

function parseStringArray(str) {
    let strings = str.split(',')
    strings = strings.map(str => str.trim())
    return strings
}

function checkIsNumberArrayString(str) {
    if (!str.match(/^\s*(-?((\d+\.\d+)|(\d+))(\s*,\s*)?){3}\s*$/g))
        throw new Error(`Invalid array. Must be an array of numbers of length 3, for example "1, 2.5,3" without brackets. Yours was ${str}.`)
}
<commit_msg>A hack to that extending HTMLElement in Safari works.<commit_after>import 'document-register-element'

import Node from '../motor/Node'

import jss from '../jss'

const nodeList = []
let stylesheet = null

const style = {
    motorNodeElement: {
        display:         'block',
        position:        'absolute',
        top:             '0',
        left:            '0',

        // TODO: set via JavaScript. Defaults to [0.5,0.5,0.5] (the Z axis
        // doesn't apply for DOM elements, but will for 3D objects in WebGL.)
        transformOrigin: '50% 50% 0', // default

        transformStyle:  'preserve-3d',
    },
}

// Very very stupid hack needed for Safari. See
// https://github.com/google/traceur-compiler/issues/1709
if (typeof window.HTMLElement != 'function') {
    const _HTMLElement = function HTMLElement(){}
    _HTMLElement.prototype = window.HTMLElement.prototype
    window.HTMLElement = _HTMLElement
}

class MotorHTMLNode extends window.HTMLElement {
    createdCallback() {
        //console.log('<motor-node> createdCallback()', this.id)
        this._attached = false
        this._cleanedUp = true
        this.node = null // to hold the imperative API Node instance.

        // XXX: "this.mountPromise" vs "this.ready":
        // "ready" seems to be more intuitive on the HTML side because
        // if the user has a reference to a motor-node or a motor-scene
        // and it exists in DOM, then it is already "mounted" from the
        // HTML API perspective. Maybe we can use "mountPromise" for
        // the imperative API, and "ready" for the HTML API. For example:
        //
        // await $('motor-scene')[0].ready // When using the HTML API
        // await node.mountPromise // When using the imperative API
        //
        // Or, maybe we can just use ".ready" in both APIs?...
        this._resolveReadyPromise = null
        this.ready = new Promise(r => this._resolveReadyPromise = r)

        nodeList.push(this)
        if (!stylesheet) {
            //console.log('Creating Node style.')
            // XXX create stylesheet inside animation frame?
            stylesheet = jss.createStyleSheet(style).attach()
        }
        this.classList.add(stylesheet.classes.motorNodeElement)
    }

    makeImperativeNode() {
        return new Node({}, this)
    }

    /**
     * Either this gets called by the imperative API when the imperative API
     * makes one of these elements, or it gets called when this element gets
     * appended to another motor-node.
     * @private
     */
    _init(imperativeMotorNode) {
        if (imperativeMotorNode && imperativeMotorNode instanceof Node)
            this.node = imperativeMotorNode
        else
            this.node = this.makeImperativeNode()

        this.signalWhenReady()
    }

    async signalWhenReady() {
        await this.node.mountPromise
        this._resolveReadyPromise()
    }

    attachedCallback() {
        //console.log('<motor-node> attachedCallback()', this.id)

        // Check that motor-nodes are mounted to motor-scenes or motor-nodes.
        // Scene can be mounted to any element. In the future we could inspect
        // the scene mount point, and advise about posisble styling issues
        // (f.e. making the scene container have a height).
        // TODO: different check needed when using is="" attributes.
        if (this.nodeName == 'MOTOR-NODE')
            if (! (this.parentNode.nodeName == 'MOTOR-NODE' || this.parentNode.nodeName == 'MOTOR-SCENE') )
                throw new Error('A <motor-node> element must be appended only to <motor-scene> or other <motor-node> elements.')

        if (!this.node)
            this._init()

        this._attached = true

        if (this._cleanedUp) {
            this._cleanedUp = false

            // make stuff here if needed.
        }

        // Attach this motor-node's Node to the parent motor-node's
        // Node (doesn't apply to motor-scene, which doesn't have a
        // parent to attach to).
        // TODO: prevent this call if attachedCallback happened to to call to
        // addChild on the imperative side.
        if (this.nodeName != 'MOTOR-SCENE')
            this.parentNode.node.addChild(this.node, true)
    }

    // TODO XXX: remove corresponding imperative Node from it's parent.
    async detachedCallback() {
        //console.log('<motor-node> detachedCallback()')
        this._attached = false

        // XXX Deferr to the next tick before cleaning up in case the element
        // is actually being re-attached somewhere else within this same tick
        // (detaching and attaching is synchronous, so by deferring to the next
        // tick we'll be able to know if the element was re-attached or not in
        // order to clean up or not). If the element gets re-attached before
        // the next tick, then we want to preserve the style sheet, preserve
        // the animation frame, and keep the scene in the sceneList by not
        // running the following this.cleanUp() call. {{
        await Promise.resolve() // deferr to the next tick.

        // If the scene wasn't re-attached in the last tick, clean up.
        // TODO (performance): Should we coordinate this.cleanUp() with
        // animation loop to prevent jank? MotorHTMLScene.cleanUp may remove a
        // JSS stylesheet. Is that something we want to do in a frame?
        if (!this._attached && !this._cleanedUp) {
            this.cleanUp()
        }

        // }}
    }

    cleanUp() {
        nodeList.pop(this)
        if (nodeList.length == 0) {
            stylesheet.detach()
            stylesheet = null
        }

        this._cleanedUp = true
    }

    attributeChangedCallback(attribute, oldValue, newValue) {
        //console.log('<motor-node> attributeChangedCallback', this.id, attribute, this.node)
        this.updateNodeProperty(attribute, oldValue, newValue)
    }

    async updateNodeProperty(attribute, oldValue, newValue) {
        // TODO: Handle actual values (not just string property values as
        // follows) for performance; especially when DOMMatrix is supported
        // by browsers.

        // if not initialized yet, wait.
        if (!this.node) await this.ready

        // attributes on our HTML elements are the same name as those on
        // the Node class (the setters).
        if (newValue !== oldValue) {
            if (attribute.match(/opacity/i))
                this.node[attribute] = parseFloat(newValue)
            else if (attribute.match(/sizemode/i))
                this.node[attribute] = parseStringArray(newValue)
            else if (
                attribute.match(/rotation/i)
                || attribute.match(/scale/i)
                || attribute.match(/position/i)
                || attribute.match(/absoluteSize/i)
                || attribute.match(/proportionalSize/i)
                || attribute.match(/align/i)
                || attribute.match(/mountPoint/i)
                || attribute.match(/origin/i) // origin is TODO on imperative side.
            ) {
                this.node[attribute] = parseNumberArray(newValue)
            }
            else {
                /* nothing, ignore other attributes */
            }
        }
    }
}
MotorHTMLNode = document.registerElement('motor-node', MotorHTMLNode)

export default MotorHTMLNode

function parseNumberArray(str) {
    checkIsNumberArrayString(str)

    let numbers = str.split(',')

    numbers = numbers.map(num => window.parseFloat(num))
    return numbers
}

function parseStringArray(str) {
    let strings = str.split(',')
    strings = strings.map(str => str.trim())
    return strings
}

function checkIsNumberArrayString(str) {
    if (!str.match(/^\s*(-?((\d+\.\d+)|(\d+))(\s*,\s*)?){3}\s*$/g))
        throw new Error(`Invalid array. Must be an array of numbers of length 3, for example "1, 2.5,3" without brackets. Yours was ${str}.`)
}
<|endoftext|>