<commit_before>import ReactDOMServer from 'react-dom/server'
import React from 'react'
import raf from 'raf'
import Radium from 'radium'

import phash from './lib/phash'
import log from './lib/log'
import hotCache from './mixins/hotCache'
import reportError from './lib/reportError'
import runEvents from './lib/runEvents'
import createElement from './tag/createElement'
import viewOn from './lib/viewOn'

const capitalize = str =>
  str[0].toUpperCase() + str.substring(1)

const pathWithoutProps = path =>
  path.replace(/\.[a-z0-9\-]+$/, '')

let views = {}
let viewErrorDebouncers = {}

export default function createComponent(Flint, Internal, name, view, options = {}) {
  const el = createElement(name)
  let isChanged = options.changed

  if (process.env.production)
    return createViewComponent()

  if (options.changed) {
    views[name] = createViewComponent()
  }

  // once rendered, isChanged is used to prevent
  // unnecessary props hashing, for faster hot reloads
  Flint.on('render:done', () => {
    isChanged = false
  })

  return createProxyComponent()

  // proxy components handle hot reloads
  function createProxyComponent() {
    return React.createClass({

      childContextTypes: {
        path: React.PropTypes.string,
        displayName: React.PropTypes.string
      },

      contextTypes: {
        path: React.PropTypes.string
      },

      getChildContext() {
        return {
          path: this.getPath()
        }
      },

      getPath() {
        if (!this.path) this.setPath()
        return this.path
      },

      getSep() {
        return name == 'Main' ? '' : ','
      },

      setPathKey() {
        const flint = this.props.__flint
        const key = flint && flint.key || '00'
        const index = flint && flint.index || '00'
        const parentPath = this.context.path || ''
        this.pathKey = `${parentPath}${this.getSep()}${name}-${key}/${index}`
      },

      setPath() {
        this.setPathKey()

        if (!isChanged) {
          const prevPath = Internal.paths[this.pathKey]
          if (prevPath) {
            this.path = prevPath
            return
          }
        }

        const propsHash = phash(this.props)
        this.path = `${this.pathKey}.${propsHash}`

        // for faster retrieval hot reloading
        Internal.paths[this.pathKey] = this.path
      },

      onMount(component) {
        const path = this.getPath()
        const lastRendered = component.lastRendered

        Internal.mountedViews[name] = Internal.mountedViews[name] || []
        Internal.mountedViews[name].push(this)
        Internal.viewsAtPath[path] = component

        if (lastRendered)
          Internal.lastWorkingRenders[pathWithoutProps(path)] = lastRendered

        Internal.lastWorkingViews[name] = { component }
      },

      render() {
        const View = views[name]

        let viewProps = Object.assign({}, this.props)

        viewProps.__flint = viewProps.__flint || {}
        viewProps.__flint.onMount = this.onMount
        viewProps.__flint.path = this.getPath()

        return React.createElement(View, viewProps)
      }
    })
  }

  // create view
  function createViewComponent() {
    const component = React.createClass({
      displayName: name,
      name,
      Flint,
      el,

      mixins: [hotCache({ Internal, options, name })],

      // TODO: shouldComponentUpdate based on hot load for perf
      shouldComponentUpdate() {
        return !this.isPaused
      },

      shouldReRender() {
        return (
          this._isMounted && !this.isUpdating &&
          !this.isPaused && !this.firstRender &&
          !this.isRendering
        )
      },

      // LIFECYCLES

      getInitialState() {
        const fprops = this.props.__flint

        Internal.getInitialStates[fprops ? fprops.path : 'Main'] = () => this.getInitialState()

        let u = null

        this.successfulRender = null
        this.firstRender = true
        this.isUpdating = true
        this.styles = { _static: {} }
        this.events = { mount: u, unmount: u, change: u, props: u }
        this.path = null

        // scope on() to view
        this.viewOn = viewOn(this)

        // cache Flint view render() (defined below)
        const flintRender = this.render

        this.renders = []

        // setter to capture view render
        this.render = renderFn => {
          this.renders.push(renderFn)
        }

        // call view
        if (process.env.production)
          view.call(this, this, this.viewOn, this.styles)
        else {
          try {
            view.call(this, this, this.viewOn, this.styles)
            this.recoveryRender = false
          }
          catch(e) {
            Internal.caughtRuntimeErrors++
            reportError(e)
            console.error(e.stack)
            this.recoveryRender = true
          }
        }

        // reset original render
        this.render = flintRender

        return null
      },

      runEvents(name) {
        runEvents(this.events, name)
      },

      componentWillReceiveProps(nextProps) {
        this.props = nextProps
        this.runEvents('props')
      },

      componentDidMount() {
        this.isRendering = false
        this._isMounted = true
        this.isUpdating = false

        this.runEvents('mount')

        if (this.queuedUpdate)
          this.update()

        if (!process.env.production) {
          this.props.__flint.onMount(this)
          this.setID()
        }
      },

      componentWillUnmount() {
        // fixes unmount errors github.com/flintjs/flint/issues/60
        if (!process.env.production) {
          this.render()
        }

        this._isMounted = false
        this.runEvents('unmount')
      },

      componentWillMount() {
        // componentWillUpdate only run after first render
        this.runEvents('change')
        this.runEvents('props')
      },

      componentWillUpdate() {
        this.isUpdating = true
        this.runEvents('change')
      },

      setID() {
        // set flintID for state inspect
        const node = ReactDOM.findDOMNode(this)
        if (node) node.__flintID = this.props.__flint.path
      },

      componentDidUpdate() {
        this.isRendering = false
        this.isUpdating = false
        this.queuedUpdate = false

        if (this.queuedUpdate)
          this.update()

        if (!process.env.production) {
          this.setID()
        }
      },

      // FLINT HELPERS

      // helpers for controlling re-renders
      pause() { this.isPaused = true },
      resume() { this.isPaused = false },

      // for looping while waiting
      delayUpdate() {
        if (this.queuedUpdate) return

        this.queuedUpdate = true

        setTimeout(() => {
          this.update()
        })
      },

      update() {
        if (!Internal.firstRender && !this.isRendering && !this.isUpdating && this._isMounted) {
          this.isUpdating = true
          setTimeout(() => this.forceUpdate())
        }
        else {
          if (!this.queuedUpdate)
            this.delayUpdate()
        }
      },

      // helpers for context
      childContext(obj) {
        if (!obj) return

        Object.keys(obj).forEach(key => {
          this.constructor.childContextTypes[key] =
            React.PropTypes[typeof obj[key]]
        })

        this.getChildContext = () => obj
      },

      getWrapper(tags, props, numRenders) {
        const wrapperName = name.toLowerCase()

        let tagProps = Object.assign({
          isWrapper: true
        }, props)

        return this.el(`view.${name}`, tagProps, ...tags)
      },

      getRender() {
        if (this.recoveryRender)
          return this.getLastGoodRender()

        let tags, props
        let addWrapper = true
        const numRenders = this.renders && this.renders.length

        if (!numRenders) {
          tags = []
          props = { yield: true }
        }

        else if (numRenders == 1) {
          tags = this.renders[0].call(this)

          addWrapper = (
            Array.isArray(tags) ||
            !tags.props
          )

          if (!Array.isArray(tags) && tags.props && tags.props.__flint && tags.props.__flint.tagName != name.toLowerCase()) {
            addWrapper = true
            tags = [tags]
          }
        }

        else if (numRenders > 1) {
          tags = this.renders.map(r => r.call(this))
        }

        // if $ = false, unwrap if possible
        // if (this.styles._static && this.styles._static.$ == false && tags.length == 1) {
        //   addWrapper = false
        //   tags = tags[0]
        // }

        // top level tag returned false
        if (!tags)
          addWrapper = true

        const wrappedTags = addWrapper ?
          this.getWrapper(tags, props, numRenders) :
          tags

        const cleanName = name.replace('.', '-')
        const viewClassName = `View${cleanName}`
        const parentClassName = wrappedTags.props.className
        const className = parentClassName
          ? `${viewClassName} ${parentClassName}`
          : viewClassName

        const withClass = React.cloneElement(wrappedTags, { className })

        return withClass
      },

      getLastGoodRender() {
        return Internal.lastWorkingRenders[pathWithoutProps(this.props.__flint.path)]
      },

      render() {
        const self = this

        self.isRendering = true
        self.firstRender = false

        if (process.env.production)
          return self.getRender()
        else {
          clearTimeout(viewErrorDebouncers[self.props.__flint.path])
        }

        // try render
        try {
          const els = self.getRender()
          self.lastRendered = els
          return els
        }
        catch(e) {
          Internal.caughtRuntimeErrors++

          // console warn, with debounce
          viewErrorDebouncers[self.props.__flint.path] = setTimeout(() => {
            console.groupCollapsed(`Render error in view ${name} (${e.message})`)
            console.warn(e.message)

            if (e.stack && Array.isArray(e.stack))
              console.error(...e.stack.split("\n"))
            else
              console.error(e)

            console.groupEnd()
          }, 500)

          reportError(e)

          const lastRender = self.getLastGoodRender()

          try {
            let inner = Error in view {name}

            if (Internal.isDevTools)
              return inner

            if (lastRender) {
              let __html = ReactDOMServer.renderToString(lastRender)
              __html = __html.replace(/\s*data\-react[a-z-]*\=\"[^"]*\"/g, '')
              inner =
            }

            // highlight in red and return last working render
            return (

                {inner}

            )
          }
          catch(e) {
            log("Error rendering last version of view after error")
          }
        }
      }
    })

    return Radium(component)
  }
}
<commit_msg>update logic error<commit_after>import ReactDOMServer from 'react-dom/server'
import React from 'react'
import raf from 'raf'
import Radium from 'radium'

import phash from './lib/phash'
import log from './lib/log'
import hotCache from './mixins/hotCache'
import reportError from './lib/reportError'
import runEvents from './lib/runEvents'
import createElement from './tag/createElement'
import viewOn from './lib/viewOn'

const capitalize = str =>
  str[0].toUpperCase() + str.substring(1)

const pathWithoutProps = path =>
  path.replace(/\.[a-z0-9\-]+$/, '')

let views = {}
let viewErrorDebouncers = {}

export default function createComponent(Flint, Internal, name, view, options = {}) {
  const el = createElement(name)
  let isChanged = options.changed

  if (process.env.production)
    return createViewComponent()

  if (options.changed) {
    views[name] = createViewComponent()
  }

  // once rendered, isChanged is used to prevent
  // unnecessary props hashing, for faster hot reloads
  Flint.on('render:done', () => {
    isChanged = false
  })

  return createProxyComponent()

  // proxy components handle hot reloads
  function createProxyComponent() {
    return React.createClass({

      childContextTypes: {
        path: React.PropTypes.string,
        displayName: React.PropTypes.string
      },

      contextTypes: {
        path: React.PropTypes.string
      },

      getChildContext() {
        return {
          path: this.getPath()
        }
      },

      getPath() {
        if (!this.path) this.setPath()
        return this.path
      },

      getSep() {
        return name == 'Main' ? '' : ','
      },

      setPathKey() {
        const flint = this.props.__flint
        const key = flint && flint.key || '00'
        const index = flint && flint.index || '00'
        const parentPath = this.context.path || ''
        this.pathKey = `${parentPath}${this.getSep()}${name}-${key}/${index}`
      },

      setPath() {
        this.setPathKey()

        if (!isChanged) {
          const prevPath = Internal.paths[this.pathKey]
          if (prevPath) {
            this.path = prevPath
            return
          }
        }

        const propsHash = phash(this.props)
        this.path = `${this.pathKey}.${propsHash}`

        // for faster retrieval hot reloading
        Internal.paths[this.pathKey] = this.path
      },

      onMount(component) {
        const path = this.getPath()
        const lastRendered = component.lastRendered

        Internal.mountedViews[name] = Internal.mountedViews[name] || []
        Internal.mountedViews[name].push(this)
        Internal.viewsAtPath[path] = component

        if (lastRendered)
          Internal.lastWorkingRenders[pathWithoutProps(path)] = lastRendered

        Internal.lastWorkingViews[name] = { component }
      },

      render() {
        const View = views[name]

        let viewProps = Object.assign({}, this.props)

        viewProps.__flint = viewProps.__flint || {}
        viewProps.__flint.onMount = this.onMount
        viewProps.__flint.path = this.getPath()

        return React.createElement(View, viewProps)
      }
    })
  }

  // create view
  function createViewComponent() {
    const component = React.createClass({
      displayName: name,
      name,
      Flint,
      el,

      mixins: [hotCache({ Internal, options, name })],

      // TODO: shouldComponentUpdate based on hot load for perf
      shouldComponentUpdate() {
        return !this.isPaused
      },

      shouldReRender() {
        return (
          this._isMounted && !this.isUpdating &&
          !this.isPaused && !this.firstRender &&
          !this.isRendering
        )
      },

      // LIFECYCLES

      getInitialState() {
        const fprops = this.props.__flint

        Internal.getInitialStates[fprops ? fprops.path : 'Main'] = () => this.getInitialState()

        let u = null

        this.firstRender = true
        this.isUpdating = true
        this.styles = { _static: {} }
        this.events = { mount: u, unmount: u, change: u, props: u }
        this.path = null

        // scope on() to view
        this.viewOn = viewOn(this)

        // cache Flint view render() (defined below)
        const flintRender = this.render

        this.renders = []

        // setter to capture view render
        this.render = renderFn => {
          this.renders.push(renderFn)
        }

        // call view
        if (process.env.production)
          view.call(this, this, this.viewOn, this.styles)
        else {
          try {
            view.call(this, this, this.viewOn, this.styles)
            this.recoveryRender = false
          }
          catch(e) {
            Internal.caughtRuntimeErrors++
            reportError(e)
            console.error(e.stack)
            this.recoveryRender = true
          }
        }

        // reset original render
        this.render = flintRender

        return null
      },

      runEvents(name) {
        runEvents(this.events, name)
      },

      componentWillReceiveProps(nextProps) {
        this.props = nextProps
        this.runEvents('props')
      },

      componentDidMount() {
        this.isRendering = false
        this._isMounted = true
        this.isUpdating = false

        this.runEvents('mount')

        if (this.queuedUpdate)
          this.update()

        if (!process.env.production) {
          this.props.__flint.onMount(this)
          this.setID()
        }
      },

      componentWillUnmount() {
        // fixes unmount errors github.com/flintjs/flint/issues/60
        if (!process.env.production) {
          this.render()
        }

        this._isMounted = false
        this.runEvents('unmount')
      },

      componentWillMount() {
        // componentWillUpdate only run after first render
        this.runEvents('change')
        this.runEvents('props')
      },

      componentWillUpdate() {
        this.isUpdating = true
        this.runEvents('change')
      },

      setID() {
        // set flintID for state inspect
        const node = ReactDOM.findDOMNode(this)
        if (node) node.__flintID = this.props.__flint.path
      },

      componentDidUpdate() {
        this.isRendering = false
        this.isUpdating = false

        if (this.queuedUpdate) {
          this.queuedUpdate = false
          this.update()
        }

        if (!process.env.production) {
          this.setID()
        }
      },

      // FLINT HELPERS

      // helpers for controlling re-renders
      pause() { this.isPaused = true },
      resume() { this.isPaused = false },

      // for looping while waiting
      delayUpdate() {
        if (this.queuedUpdate) return

        this.queuedUpdate = true

        setTimeout(() => {
          this.update()
        })
      },

      update() {
        if (!Internal.firstRender && !this.isRendering && !this.isUpdating && this._isMounted) {
          this.isUpdating = true
          setTimeout(() => this.forceUpdate())
        }
        else {
          if (!this.queuedUpdate)
            this.delayUpdate()
        }
      },

      // helpers for context
      childContext(obj) {
        if (!obj) return

        Object.keys(obj).forEach(key => {
          this.constructor.childContextTypes[key] =
            React.PropTypes[typeof obj[key]]
        })

        this.getChildContext = () => obj
      },

      getWrapper(tags, props, numRenders) {
        const wrapperName = name.toLowerCase()

        let tagProps = Object.assign({
          isWrapper: true
        }, props)

        return this.el(`view.${name}`, tagProps, ...tags)
      },

      getRender() {
        if (this.recoveryRender)
          return this.getLastGoodRender()

        let tags, props
        let addWrapper = true
        const numRenders = this.renders && this.renders.length

        if (!numRenders) {
          tags = []
          props = { yield: true }
        }

        else if (numRenders == 1) {
          tags = this.renders[0].call(this)

          addWrapper = (
            Array.isArray(tags) ||
            !tags.props
          )

          if (!Array.isArray(tags) && tags.props && tags.props.__flint && tags.props.__flint.tagName != name.toLowerCase()) {
            addWrapper = true
            tags = [tags]
          }
        }

        else if (numRenders > 1) {
          tags = this.renders.map(r => r.call(this))
        }

        // if $ = false, unwrap if possible
        // if (this.styles._static && this.styles._static.$ == false && tags.length == 1) {
        //   addWrapper = false
        //   tags = tags[0]
        // }

        // top level tag returned false
        if (!tags)
          addWrapper = true

        const wrappedTags = addWrapper ?
          this.getWrapper(tags, props, numRenders) :
          tags

        const cleanName = name.replace('.', '-')
        const viewClassName = `View${cleanName}`
        const parentClassName = wrappedTags.props.className
        const className = parentClassName
          ? `${viewClassName} ${parentClassName}`
          : viewClassName

        const withClass = React.cloneElement(wrappedTags, { className })

        return withClass
      },

      getLastGoodRender() {
        return Internal.lastWorkingRenders[pathWithoutProps(this.props.__flint.path)]
      },

      render() {
        const self = this

        self.isRendering = true
        self.firstRender = false

        if (process.env.production)
          return self.getRender()
        else {
          clearTimeout(viewErrorDebouncers[self.props.__flint.path])
        }

        // try render
        try {
          const els = self.getRender()
          self.lastRendered = els
          return els
        }
        catch(e) {
          Internal.caughtRuntimeErrors++

          // console warn, with debounce
          viewErrorDebouncers[self.props.__flint.path] = setTimeout(() => {
            console.groupCollapsed(`Render error in view ${name} (${e.message})`)
            console.warn(e.message)

            if (e.stack && Array.isArray(e.stack))
              console.error(...e.stack.split("\n"))
            else
              console.error(e)

            console.groupEnd()
          }, 500)

          reportError(e)

          const lastRender = self.getLastGoodRender()

          try {
            let inner = Error in view {name}

            if (Internal.isDevTools)
              return inner

            if (lastRender) {
              let __html = ReactDOMServer.renderToString(lastRender)
              __html = __html.replace(/\s*data\-react[a-z-]*\=\"[^"]*\"/g, '')
              inner =
            }

            // highlight in red and return last working render
            return (

                {inner}

            )
          }
          catch(e) {
            log("Error rendering last version of view after error")
          }
        }
      }
    })

    return Radium(component)
  }
}
<|endoftext|>


<commit_before>import React from 'react';
const Format = require('d3-format');

class Display extends React.PureComponent {
  constructor(props) {
    super(props);
    this.format = Format.format(props.format || '0.2f');
  }

  formatValue(v) {
    const t = typeof v;
    switch (t) {
      case 'object':
        return JSON.stringify(v);
      case 'number':
        return this.format(v);
      case 'string':
      default:
        return v;
    }
  }

  render() {
    const { value } = this.props;
    const v = value !== undefined ? value : this.props.var;
    return <span>{this.formatValue(v)}</span>;
  }
}

Display._idyll = {
  name: 'Display',
  tagType: 'closed',
  displayType: 'inline',
  props: [
    {
      name: 'value',
      type: 'any',
      example: 'x',
      description: 'The value to be displayed.'
    },
    {
      name: 'format',
      type: 'string',
      example: '"0.2f"',
      description:
        'The format to use, powered by [d3-format](https://github.com/d3/d3-format).'
    }
  ]
};

export default Display;
<commit_msg>add classname to display component<commit_after>import React from 'react';
const Format = require('d3-format');

class Display extends React.PureComponent {
  constructor(props) {
    super(props);
    this.format = Format.format(props.format || '0.2f');
  }

  formatValue(v) {
    const t = typeof v;
    switch (t) {
      case 'object':
        return JSON.stringify(v);
      case 'number':
        return this.format(v);
      case 'string':
      default:
        return v;
    }
  }

  render() {
    const { value } = this.props;
    const v = value !== undefined ? value : this.props.var;
    return (
      <span
        className={`idyll-display ${
          this.props.className ? this.props.className : ''
        }`.trim()}
      >
        {this.formatValue(v)}
      </span>
    );
  }
}

Display._idyll = {
  name: 'Display',
  tagType: 'closed',
  displayType: 'inline',
  props: [
    {
      name: 'value',
      type: 'any',
      example: 'x',
      description: 'The value to be displayed.'
    },
    {
      name: 'format',
      type: 'string',
      example: '"0.2f"',
      description:
        'The format to use, powered by [d3-format](https://github.com/d3/d3-format).'
    }
  ]
};

export default Display;
<|endoftext|>


<commit_before>import path from "path";

export function getCodeAndDependencies(bundle, name) {
  const chunk = findChunkWithName(bundle, name);
  const output = [chunk.code];

  for (const dep of chunk.imports) {
    output.push(bundle[dep].code);
  }

  return output.join("\n");
}

export function findChunkWithName(bundle, name) {
  return Object.values(bundle).find(desc =>
    (desc.facadeModuleId || "").endsWith(name)
  );
}

export function findAssetWithName(bundle, name) {
  const parsedName = path.parse(name);

  return Object.values(bundle).find(desc => {
    if (!desc.isAsset) return false;
    const parsedGraphName = path.parse(desc.fileName);
    if (parsedGraphName.ext !== parsedName.ext) return false;
    if (!parsedGraphName.name.startsWith(parsedName.name)) return false;
    const expectedHash = parsedGraphName.name.slice(parsedName.name.length);
    return /^-[0-9a-f]+$/.test(expectedHash);
  });
}
<commit_msg>Also crawl dependencies of dependencies<commit_after>import path from "path";

export function getCodeAndDependencies(bundle, name) {
  const crawlDependencies = new Set();
  const chunk = findChunkWithName(bundle, name);
  const output = [];
  crawlDependencies.add(chunk.fileName);

  for (const fileName of crawlDependencies) {
    const chunk = bundle[fileName];
    output.push(chunk.code);
    for (const dep of chunk.imports) {
      crawlDependencies.add(dep);
    }
  }

  return output.join("\n");
}

export function findChunkWithName(bundle, name) {
  return Object.values(bundle).find(desc =>
    (desc.facadeModuleId || "").endsWith(name)
  );
}

export function findAssetWithName(bundle, name) {
  const parsedName = path.parse(name);

  return Object.values(bundle).find(desc => {
    if (!desc.isAsset) return false;
    const parsedGraphName = path.parse(desc.fileName);
    if (parsedGraphName.ext !== parsedName.ext) return false;
    if (!parsedGraphName.name.startsWith(parsedName.name)) return false;
    const expectedHash = parsedGraphName.name.slice(parsedName.name.length);
    return /^-[0-9a-f]+$/.test(expectedHash);
  });
}
<|endoftext|>


<commit_before>import path from "path";

export function getCodeAndDependencies(bundle, name) {
  const chunk = findChunkWithName(bundle, name);
  const output = [chunk.code];

  for (const dep of chunk.imports) {
    output.push(bundle[dep].code);
  }

  return output.join("\n");
}

export function findChunkWithName(bundle, name) {
  return Object.values(bundle).find(desc =>
    (desc.facadeModuleId || "").endsWith(name)
  );
}

export function findAssetWithName(bundle, name) {
  const parsedName = path.parse(name);

  return Object.values(bundle).find(desc => {
    if (!desc.isAsset) return false;
    const parsedGraphName = path.parse(desc.fileName);
    if (parsedGraphName.ext !== parsedName.ext) return false;
    if (!parsedGraphName.name.startsWith(parsedName.name)) return false;
    const expectedHash = parsedGraphName.name.slice(parsedName.name.length);
    return /^-[0-9a-f]+$/.test(expectedHash);
  });
}
<commit_msg>Also crawl dependencies of dependencies (#488)<commit_after>import path from "path";

export function getCodeAndDependencies(bundle, name) {
  const chunk = findChunkWithName(bundle, name);
  const output = [];
  const crawlDependencies = new Set([chunk.fileName]);

  for (const fileName of crawlDependencies) {
    const chunk = bundle[fileName];
    output.push(chunk.code);
    for (const dep of chunk.imports) {
      crawlDependencies.add(dep);
    }
  }

  return output.join("\n");
}

export function findChunkWithName(bundle, name) {
  return Object.values(bundle).find(desc =>
    (desc.facadeModuleId || "").endsWith(name)
  );
}

export function findAssetWithName(bundle, name) {
  const parsedName = path.parse(name);

  return Object.values(bundle).find(desc => {
    if (!desc.isAsset) return false;
    const parsedGraphName = path.parse(desc.fileName);
    if (parsedGraphName.ext !== parsedName.ext) return false;
    if (!parsedGraphName.name.startsWith(parsedName.name)) return false;
    const expectedHash = parsedGraphName.name.slice(parsedName.name.length);
    return /^-[0-9a-f]+$/.test(expectedHash);
  });
}
<|endoftext|>


<commit_before>const MWS = require('mws-simple');
const { MWS_ENDPOINTS } = require('./constants');
const sleep = require('./util/sleep');
const fs = require('fs');

const errors = require('./errors.js');

/*
 * TODO: split the "init" function out of the "callEndpoint" file, difficulty: callEndpoint
 * depends on having init modify the mws value, which doesn't carry between module pieces in that
 * case -- exporting 'mws' to callEndpoint just results in null every time it's accessed, even
 * when requiring it inline in code, rather than at the top of the file. Ugh.  Big design
 * problem, that is a holdover from when the entire module was all located in a single file.
 */

/** holds the mws-simple reference after init() is called */
let mws = null;

/**
 * Initialize mws-advanced with your MWS access keys, merchantId, optionally authtoken, host, port
 * If accessKeyId, secretAccessKey, and/or merchantId are not provided, they will be read from
 * the environment variables MWS_ACESS_KEY, MWS_SECRET_ACCESS_KEY, and MWS_MERCHANT_ID respectively
 *
 * @public
 * @example
 * const mws = MWS.init({ region: 'NA', accessKeyId: '1234', secretAccessKey: '2345', merchantId: '1234567890' });
 * const mws = MWS.init({ region: 'EU', accessKeyId, ... });
 * const mws = MWS.init({ authToken: 'qwerty', accessKeyId, ...});
 * const mws = MWS.init({ host: 'alternate-mws-server.com', accessKeyId, ... });
 * @param {object} config Contains your MWS Access Keys/Tokens and options to configure the API
 * @param {string} [config.accessKeyId=process.env.MWS_ACCESS_KEY] Your MWS Access Key
 * @param {string} [config.secretAccessKey=process.env.MWS_SECRET_ACCESS_KEY] Your MWS Secret Access Key
 * @param {string} [config.merchantId=process.env.MWS_MERCHANT_ID] Your MWS Merchant ID
 * @param {string} [config.authToken] If making a call for a third party account, the Auth Token provided
 *                           for the third party account
 * @param {string} [config.region='NA'] One of the Amazon regions as specified in https://docs.developer.amazonservices.com/en_US/dev_guide/DG_Endpoints.html
 * @param {string} [config.host='mws.amazonservices.com'] Set MWS host server name, see https://docs.developer.amazonservices.com/en_US/dev_guide/DG_Endpoints.html
 * @param {number} [config.port=443] Set MWS host port
 * @returns {mws-simple} - The mws-simple instance used to communicate with the API
 */

const init = ({
    region = 'NA',
    // marketplace = 'US', // TODO: maybe someday we will want to keep track of a 'default' marketplace.
    accessKeyId = process.env.MWS_ACCESS_KEY,
    secretAccessKey = process.env.MWS_SECRET_ACCESS_KEY,
    merchantId = process.env.MWS_MERCHANT_ID,
    authToken,
    host = MWS_ENDPOINTS[region] || 'mws.amazonservices.com',
    port,
} = {}) => {
    mws = new MWS({
        accessKeyId,
        secretAccessKey,
        merchantId,
        authToken,
        host,
        port,
    });
    return mws;
};

const { flattenResult } = require('./flatten-result');

const { validateAndTransformParameters } = require('./validation');
const { digResponseResult } = require('./dig-response-result.js');

// TODO: add Subscriptions and Recommendations categories
const {
    feeds, finances, inbound, inventory, outbound,
    merchFulfillment, orders, products, sellers, reports,
} = require('./endpoints');

// TODO: THIS MAY BE A BAD IDEA CONSIDERING THAT SOME CATEGORIES SHARE SOME ENDPOINT NAMES
// TODO: WE MAY NEED TO COME UP WITH A WAY TO DEAL WITH THAT.

/** simple flat list of all the endpoints required from individual modules above */
const endpoints = {
    ...feeds,
    ...finances,
    ...inbound,
    ...inventory,
    ...merchFulfillment,
    ...orders,
    ...outbound,
    ...products,
    ...sellers,
    ...reports,
};

/**
 * Return a promise for making the desired request, flattening the response out to something
 * that will hopefully make a little more sense.
 *
 * @async
 * @private
 * @param {any} requestData
 * @param {object} [opt] - options
 * @param {boolean} [opt.noFlatten] - do not run flattenResult on the output
 */
const requestPromise = (requestData, opt = {}) =>
    new Promise((resolve, reject) => {
        mws.request(requestData, (err, result) => {
            if (err) {
                reject(err);
            } else {
                resolve(opt.noFlatten ? result : flattenResult(result));
            }
        });
    });

/**
 * Call a known endpoint at MWS, returning the raw data from the function. Parameters are
 * transformed and validated according to the rules defined in lib/endpoints
 *
 * @async
 * @public
 * @param {string} name - name of MWS API function to call
 * @param {object} [callOptions] - named hash object of the parameters to pass to the API
 * @param {object} [opt] - options for callEndpoint
 * @param {boolean} [opt.noFlatten] - do not flatten results
 * @param {boolean} [opt.returnRaw] - return only the raw data (may or may not be flattened)
 * @param {string} [opt.saveRaw] - filename to save raw data to (may or may not be flattened)
 * @param {string} [opt.saveParsed] - filename to save final parsed data to (not compatible with returnRaw, since parsing won't happen)
 * @returns {any} - Results of the call to MWS
 */
const callEndpoint = async (
    name,
    callOptions = {},
    opt = {
        maxThrottleRetries: 2,
    },
) => {
    const endpoint = endpoints[name];
    if (!endpoint) {
        throw new errors.InvalidUsage(`Unknown endpoint name supplied to callEndpoint, ${name}`);
    }

    const newOptions = endpoint.params ?
        validateAndTransformParameters(endpoint.params, callOptions) : callOptions;

    const { feedContent } = newOptions;
    delete newOptions.feedContent;

    const queryOptions = {
        ...newOptions,
        Action: endpoint.action,
        Version: endpoint.version,
    };

    const params = {
        path: `/${endpoint.category}/${endpoint.version}`,
        query: queryOptions,
        feedContent,
    };

    let throttleRetries = 0;
    try {
        const result = await requestPromise(params, { noFlatten: opt.noFlatten });
        if (opt.saveRaw) {
            fs.writeFileSync(opt.saveRaw, JSON.stringify(result));
        }
        if (opt.returnRaw) {
            return result;
        }
        const digResult = digResponseResult(name, result);
        if (opt.saveParsed) {
            fs.writeFileSync(opt.saveParsed, JSON.stringify(digResult));
        }
        return digResult;
    } catch (err) {
        if (err instanceof mws.ServerError) {
            if (err.code === 503 && opt.maxThrottleRetries > 0 && throttleRetries <= opt.maxThrottleRetries) {
                throttleRetries += 1;
                console.warn('***** Error 503 .. throttling?', name);
                let ms = 2000;
                if (!endpoint.throttle) {
                    console.warn(`***** throttle information missing for API ${name}`);
                    console.warn('***** ', JSON.stringify(endpoint));
                } else {
                    // restoreRate = how many you get back in a minute of time. there's an assumption here
                    // that you're spamming a lot of requests if you're hitting throttling, and this
                    // throttle management system is first version, here -- so we're going to throttle it
                    // not to the minimum possible time frame, but to the length of time that it will take
                    // to restore your entire maxInFlight -- assuming you're probably going to hit the max
                    // again as soon as we start letting more requests in.

                    // ultimately, an upgraded version of this throttling handler would keep track of how
                    // many of every request are in flight, and try to throttle it to the minimum amount
                    // of time that you can go, automatically throttling future calls without having to
                    // even encounter the 503 from the server.

                    // that day is not today.  it might be tomorrow. maybe next weekend. i don't know. :-)
                    const restoreMaxInFlightMin = (endpoint.throttle.maxInFlight / endpoint.throttle.restoreRate) * (callOptions.IdList ? callOptions.IdList.length : 1);
                    ms = (restoreMaxInFlightMin * 60 * 1000) + 100;
                }
                console.warn(`***** trying again in ${ms}ms`);
                await sleep(ms + 100);
                return callEndpoint(name, callOptions, opt);
            }
        }
        throw err;
    }
};

const parseEndpoint = (name, callOptions, opt) => async (parser) => {
    try {
        const res = await callEndpoint(name, callOptions, opt);
        return parser(res);
    } catch (err) {
        console.warn('**** caught parseEndpoint error');
        throw err;
    }
};

module.exports = {
    init,
    callEndpoint,
    parseEndpoint,
};
<commit_msg>minor doc update<commit_after>const MWS = require('mws-simple');
const { MWS_ENDPOINTS } = require('./constants');
const sleep = require('./util/sleep');
const fs = require('fs');

const errors = require('./errors.js');

/*
 * TODO: split the "init" function out of the "callEndpoint" file, difficulty: callEndpoint
 * depends on having init modify the mws value, which doesn't carry between module pieces in that
 * case -- exporting 'mws' to callEndpoint just results in null every time it's accessed, even
 * when requiring it inline in code, rather than at the top of the file. Ugh.  Big design
 * problem, that is a holdover from when the entire module was all located in a single file.
 */

/** holds the mws-simple reference after init() is called */
let mws = null;

/**
 * Initialize mws-advanced with your MWS access keys, merchantId, optionally authtoken, host, port
 * If accessKeyId, secretAccessKey, and/or merchantId are not provided, they will be read from
 * the environment variables MWS_ACESS_KEY, MWS_SECRET_ACCESS_KEY, and MWS_MERCHANT_ID respectively
 *
 * @public
 * @example
 * const mws = MWS.init({ region: 'NA', accessKeyId: '1234', secretAccessKey: '2345', merchantId: '1234567890' });
 * const mws = MWS.init({ region: 'EU', accessKeyId, ... });
 * const mws = MWS.init({ authToken: 'qwerty', accessKeyId, ...});
 * const mws = MWS.init({ host: 'alternate-mws-server.com', accessKeyId, ... });
 * @param {object} config Contains your MWS Access Keys/Tokens and options to configure the API
 * @param {string} [config.accessKeyId=process.env.MWS_ACCESS_KEY] Your MWS Access Key
 * @param {string} [config.secretAccessKey=process.env.MWS_SECRET_ACCESS_KEY] Your MWS Secret Access Key
 * @param {string} [config.merchantId=process.env.MWS_MERCHANT_ID] Your MWS Merchant ID
 * @param {string} [config.authToken] If making a call for a third party account, the Auth Token provided
 *                           for the third party account
 * @param {string} [config.region='NA'] One of the Amazon regions as specified in https://docs.developer.amazonservices.com/en_US/dev_guide/DG_Endpoints.html
 * @param {string} [config.host='mws.amazonservices.com'] Set MWS host server name, see https://docs.developer.amazonservices.com/en_US/dev_guide/DG_Endpoints.html
 * @param {number} [config.port=443] Set MWS host port
 * @returns {mws-simple} - The mws-simple instance used to communicate with the API
 */

const init = ({
    region = 'NA',
    // marketplace = 'US', // TODO: maybe someday we will want to keep track of a 'default' marketplace.
    accessKeyId = process.env.MWS_ACCESS_KEY,
    secretAccessKey = process.env.MWS_SECRET_ACCESS_KEY,
    merchantId = process.env.MWS_MERCHANT_ID,
    authToken,
    host = MWS_ENDPOINTS[region] || 'mws.amazonservices.com',
    port,
} = {}) => {
    mws = new MWS({
        accessKeyId,
        secretAccessKey,
        merchantId,
        authToken,
        host,
        port,
    });
    return mws;
};

const { flattenResult } = require('./flatten-result');

const { validateAndTransformParameters } = require('./validation');
const { digResponseResult } = require('./dig-response-result.js');

// TODO: add Subscriptions and Recommendations categories
const {
    feeds, finances, inbound, inventory, outbound,
    merchFulfillment, orders, products, sellers, reports,
} = require('./endpoints');

// TODO: THIS MAY BE A BAD IDEA CONSIDERING THAT SOME CATEGORIES SHARE SOME ENDPOINT NAMES
// TODO: WE MAY NEED TO COME UP WITH A WAY TO DEAL WITH THAT.

/** simple flat list of all the endpoints required from individual modules above */
const endpoints = {
    ...feeds,
    ...finances,
    ...inbound,
    ...inventory,
    ...merchFulfillment,
    ...orders,
    ...outbound,
    ...products,
    ...sellers,
    ...reports,
};

/**
 * Return a promise for making the desired request, flattening the response out to something
 * that will hopefully make a little more sense.
 *
 * @async
 * @private
 * @param {any} requestData
 * @param {object} [opt] - options
 * @param {boolean} [opt.noFlatten] - do not run flattenResult on the output
 */
const requestPromise = (requestData, opt = {}) =>
    new Promise((resolve, reject) => {
        mws.request(requestData, (err, result) => {
            if (err) {
                reject(err);
            } else {
                resolve(opt.noFlatten ? result : flattenResult(result));
            }
        });
    });

/**
 * Call a known endpoint at MWS, returning the raw data from the function. Parameters are
 * transformed and validated according to the rules defined in lib/endpoints
 *
 * @async
 * @public
 * @param {string} name - name of MWS API function to call
 * @param {object} [callOptions] - named hash object of the parameters to pass to the API
 * @param {string} [callOptions.feedContent] - if calling a function that submits a feed, supply the feed data here
 * @param {any} [callOptions....rest] - other parameters will be passed through validation and into the API
 * @param {object} [opt] - options for callEndpoint
 * @param {boolean} [opt.noFlatten] - do not flatten results
 * @param {boolean} [opt.returnRaw] - return only the raw data (may or may not be flattened)
 * @param {string} [opt.saveRaw] - filename to save raw data to (may or may not be flattened)
 * @param {string} [opt.saveParsed] - filename to save final parsed data to (not compatible with returnRaw, since parsing won't happen)
 * @returns {any} - Results of the call to MWS
 */
const callEndpoint = async (
    name,
    callOptions = {},
    opt = {
        maxThrottleRetries: 2,
    },
) => {
    const endpoint = endpoints[name];
    if (!endpoint) {
        throw new errors.InvalidUsage(`Unknown endpoint name supplied to callEndpoint, ${name}`);
    }

    const newOptions = endpoint.params ?
        validateAndTransformParameters(endpoint.params, callOptions) : callOptions;

    const { feedContent } = newOptions;
    delete newOptions.feedContent;

    const queryOptions = {
        ...newOptions,
        Action: endpoint.action,
        Version: endpoint.version,
    };

    const params = {
        path: `/${endpoint.category}/${endpoint.version}`,
        query: queryOptions,
        feedContent,
    };

    let throttleRetries = 0;
    try {
        const result = await requestPromise(params, { noFlatten: opt.noFlatten });
        if (opt.saveRaw) {
            fs.writeFileSync(opt.saveRaw, JSON.stringify(result));
        }
        if (opt.returnRaw) {
            return result;
        }
        const digResult = digResponseResult(name, result);
        if (opt.saveParsed) {
            fs.writeFileSync(opt.saveParsed, JSON.stringify(digResult));
        }
        return digResult;
    } catch (err) {
        if (err instanceof mws.ServerError) {
            if (err.code === 503 && opt.maxThrottleRetries > 0 && throttleRetries <= opt.maxThrottleRetries) {
                throttleRetries += 1;
                console.warn('***** Error 503 .. throttling?', name);
                let ms = 2000;
                if (!endpoint.throttle) {
                    console.warn(`***** throttle information missing for API ${name}`);
                    console.warn('***** ', JSON.stringify(endpoint));
                } else {
                    // restoreRate = how many you get back in a minute of time. there's an assumption here
                    // that you're spamming a lot of requests if you're hitting throttling, and this
                    // throttle management system is first version, here -- so we're going to throttle it
                    // not to the minimum possible time frame, but to the length of time that it will take
                    // to restore your entire maxInFlight -- assuming you're probably going to hit the max
                    // again as soon as we start letting more requests in.

                    // ultimately, an upgraded version of this throttling handler would keep track of how
                    // many of every request are in flight, and try to throttle it to the minimum amount
                    // of time that you can go, automatically throttling future calls without having to
                    // even encounter the 503 from the server.

                    // that day is not today.  it might be tomorrow. maybe next weekend. i don't know. :-)
                    const restoreMaxInFlightMin = (endpoint.throttle.maxInFlight / endpoint.throttle.restoreRate) * (callOptions.IdList ? callOptions.IdList.length : 1);
                    ms = (restoreMaxInFlightMin * 60 * 1000) + 100;
                }
                console.warn(`***** trying again in ${ms}ms`);
                await sleep(ms + 100);
                return callEndpoint(name, callOptions, opt);
            }
        }
        throw err;
    }
};

const parseEndpoint = (name, callOptions, opt) => async (parser) => {
    try {
        const res = await callEndpoint(name, callOptions, opt);
        return parser(res);
    } catch (err) {
        console.warn('**** caught parseEndpoint error');
        throw err;
    }
};

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


<commit_before>import React from "react"
import { toT } from "../../utils/converter"
import BLOCKCHAIN_INFO from "../../../../env"
import { CSSTransitionGroup } from 'react-transition-group'

const TransactionListView = (props) => {

  function hashDetailLink(hash) {
    const url = BLOCKCHAIN_INFO.ethScanUrl + 'tx/'
    return url + hash
  }

  function gotoLink(hash) {
    const url = BLOCKCHAIN_INFO.ethScanUrl + 'tx/' + hash
    window.open(url)
  }

  function getTokenSymbol(address) {
    for (let key in props.tokens) {
      if (address === props.tokens[key].address) {
        return { key, decimal: props.tokens[key].decimal }
      }
    }
  }

  // function createRecap(log) {
  //   const sourceToken = getTokenSymbol(log.source)
  //   const destToken = getTokenSymbol(log.dest)
  //   const sender = log.sender.slice(0, 8) + " ... " + log.sender.slice(-6)
  //   const sourceAmount = toT(log.actualSrcAmount, sourceToken.decimal).slice(0, 7)
  //   const destAmount = toT(log.actualDestAmount, destToken.decimal).slice(0, 7)
  //   return (
  //

  //       {sourceAmount + ' ' + sourceToken.key} to
  //        {destAmount + ' ' + destToken.key}
  //

  //   )
  // }

  function getIcon(tokenAddress) {
    let token = getTokenSymbol(tokenAddress)
    return props.tokens[token.key].icon
  }

  // function calculateTimeStamp(currentBlock) {
  //   var lastBlock = props.lastBlock
  //   var averageTime = props.averageTime
  //   var seconds = (lastBlock - currentBlock) * averageTime / 1000
  //   var interval = Math.floor(seconds / 31536000);
  //   if (interval > 0) {
  //     return interval + " years ago"
  //   }
  //   interval = Math.floor(seconds / 2592000);
  //   if (interval > 0) {
  //     return interval + " months ago"
  //   }
  //   interval = Math.floor(seconds / 86400);
  //   if (interval > 0) {
  //     return interval + " days ago"
  //   }
  //   interval = Math.floor(seconds / 3600);
  //   if (interval > 0) {
  //     return interval + " hours ago"
  //   }
  //   interval = Math.floor(seconds / 60);
  //   if (interval > 0) {
  //     return interval + " minutes ago"
  //   }
  //   return Math.floor(seconds) + " seconds ago"
  // }

  function calculateTimeStamp(timeStamp) {
    var msPerMinute = 60 * 1000;
    var msPerHour = msPerMinute * 60;
    var msPerDay = msPerHour * 24;
    var msPerMonth = msPerDay * 30;
    var msPerYear = msPerDay * 365;

    var elapsed = Date.now() - timeStamp * 1000;

    if (elapsed < msPerMinute) {
      return Math.round(elapsed / 1000) + ' ' + (props.translate('history.second_ago') || 'seconds ago');
    }

    else if (elapsed < msPerHour) {
      return Math.round(elapsed / msPerMinute) + ' ' + (props.translate('history.minutes_ago') || 'minutes ago');
    }

    else if (elapsed < msPerDay) {
      return Math.round(elapsed / msPerHour) + ' ' + (props.translate('history.hours_ago') || 'hours ago');
    }

    else if (elapsed < msPerMonth) {
      return Math.round(elapsed / msPerDay) + ' ' + (props.translate('history.days_ago') || 'days ago');
    }

    else if (elapsed < msPerYear) {
      return Math.round(elapsed / msPerMonth) + ' ' + (props.translate('history.months_ago') || 'months ago');
    }

    else {
      return Math.round(elapsed / msPerYear) + ' ' + (props.translate('history.years_ago') || 'years ago');
    }
  }
  //return timestamp

  function content(list) {
    var content = list.map(function (item, i) {
      var sourceToken = getTokenSymbol(item.source)
      var destToken = getTokenSymbol(item.dest)
      var sourceIcon = getIcon(item.source)
      var destIcon = getIcon(item.dest)
      var sourceAmount = toT(item.actualSrcAmount, sourceToken.decimal, 3)
      var sourceAmountFull = toT(item.actualSrcAmount, sourceToken.decimal, 7)
      return (

 gotoLink(item.txHash)}>

                {sourceAmount}
                {sourceToken.key.toUpperCase()} to {destToken.key.toUpperCase()}

                {calculateTimeStamp(item.timestamp)}

      )
    })
    return content
  }

  return (

{props.translate("transaction_list.transaction_history") || "TRANSACTION HISTORY"}

                ETH / TOKEN

                  <CSSTransitionGroup
                    transitionName="example"
                    transitionEnterTimeout={1000}
                    transitionLeaveTimeout={1000}>
                    {content(props.logsEth)}
                  </CSSTransitionGroup>

                TOKEN / ETH

                  <CSSTransitionGroup
                    transitionName="example"
                    transitionEnterTimeout={1000}
                    transitionLeaveTimeout={1000}>
                    {content(props.logsToken)}
                  </CSSTransitionGroup>

  )
}

export default TransactionListView;<commit_msg>update url img history<commit_after>import React from "react"
import { toT } from "../../utils/converter"
import BLOCKCHAIN_INFO from "../../../../env"
import { CSSTransitionGroup } from 'react-transition-group'

const TransactionListView = (props) => {

  function hashDetailLink(hash) {
    const url = BLOCKCHAIN_INFO.ethScanUrl + 'tx/'
    return url + hash
  }

  function gotoLink(hash) {
    const url = BLOCKCHAIN_INFO.ethScanUrl + 'tx/' + hash
    window.open(url)
  }

  function getTokenSymbol(address) {
    for (let key in props.tokens) {
      if (address === props.tokens[key].address) {
        return { key, decimal: props.tokens[key].decimal }
      }
    }
  }

  // function createRecap(log) {
  //   const sourceToken = getTokenSymbol(log.source)
  //   const destToken = getTokenSymbol(log.dest)
  //   const sender = log.sender.slice(0, 8) + " ... " + log.sender.slice(-6)
  //   const sourceAmount = toT(log.actualSrcAmount, sourceToken.decimal).slice(0, 7)
  //   const destAmount = toT(log.actualDestAmount, destToken.decimal).slice(0, 7)
  //   return (
  //

  //       {sourceAmount + ' ' + sourceToken.key} to
  //        {destAmount + ' ' + destToken.key}
  //

  //   )
  // }

  function getIcon(tokenAddress) {
    let token = getTokenSymbol(tokenAddress)
    return props.tokens[token.key].icon
  }

  // function calculateTimeStamp(currentBlock) {
  //   var lastBlock = props.lastBlock
  //   var averageTime = props.averageTime
  //   var seconds = (lastBlock - currentBlock) * averageTime / 1000
  //   var interval = Math.floor(seconds / 31536000);
  //   if (interval > 0) {
  //     return interval + " years ago"
  //   }
  //   interval = Math.floor(seconds / 2592000);
  //   if (interval > 0) {
  //     return interval + " months ago"
  //   }
  //   interval = Math.floor(seconds / 86400);
  //   if (interval > 0) {
  //     return interval + " days ago"
  //   }
  //   interval = Math.floor(seconds / 3600);
  //   if (interval > 0) {
  //     return interval + " hours ago"
  //   }
  //   interval = Math.floor(seconds / 60);
  //   if (interval > 0) {
  //     return interval + " minutes ago"
  //   }
  //   return Math.floor(seconds) + " seconds ago"
  // }

  function calculateTimeStamp(timeStamp) {
    var msPerMinute = 60 * 1000;
    var msPerHour = msPerMinute * 60;
    var msPerDay = msPerHour * 24;
    var msPerMonth = msPerDay * 30;
    var msPerYear = msPerDay * 365;

    var elapsed = Date.now() - timeStamp * 1000;

    if (elapsed < msPerMinute) {
      return Math.round(elapsed / 1000) + ' ' + (props.translate('history.second_ago') || 'seconds ago');
    }

    else if (elapsed < msPerHour) {
      return Math.round(elapsed / msPerMinute) + ' ' + (props.translate('history.minutes_ago') || 'minutes ago');
    }

    else if (elapsed < msPerDay) {
      return Math.round(elapsed / msPerHour) + ' ' + (props.translate('history.hours_ago') || 'hours ago');
    }

    else if (elapsed < msPerMonth) {
      return Math.round(elapsed / msPerDay) + ' ' + (props.translate('history.days_ago') || 'days ago');
    }

    else if (elapsed < msPerYear) {
      return Math.round(elapsed / msPerMonth) + ' ' + (props.translate('history.months_ago') || 'months ago');
    }

    else {
      return Math.round(elapsed / msPerYear) + ' ' + (props.translate('history.years_ago') || 'years ago');
    }
  }
  //return timestamp

  function content(list) {
    var content = list.map(function (item, i) {
      var sourceToken = getTokenSymbol(item.source)
      var destToken = getTokenSymbol(item.dest)
      var sourceIcon = getIcon(item.source)
      var destIcon = getIcon(item.dest)
      var sourceAmount = toT(item.actualSrcAmount, sourceToken.decimal, 3)
      var sourceAmountFull = toT(item.actualSrcAmount, sourceToken.decimal, 7)
      return (

 gotoLink(item.txHash)}>

                {sourceAmount}
                {sourceToken.key.toUpperCase()} to {destToken.key.toUpperCase()}

                {calculateTimeStamp(item.timestamp)}

      )
    })
    return content
  }

  return (

{props.translate("transaction_list.transaction_history") || "TRANSACTION HISTORY"}

                ETH / TOKEN

                  <CSSTransitionGroup
                    transitionName="example"
                    transitionEnterTimeout={1000}
                    transitionLeaveTimeout={1000}>
                    {content(props.logsEth)}
                  </CSSTransitionGroup>

                TOKEN / ETH

                  <CSSTransitionGroup
                    transitionName="example"
                    transitionEnterTimeout={1000}
                    transitionLeaveTimeout={1000}>
                    {content(props.logsToken)}
                  </CSSTransitionGroup>

  )
}

export default TransactionListView;<|endoftext|>


<commit_before>'use strict';

var fs     = require('fs');
var os     = require('os');
var path   = require('path');
var semver = require('semver');

var StreamInsert = require('./common/stream-insert.js');

var chlgShow  = require('./chlg-show');
var dates     = require('./common/dates');
var formatter = require('./format/raw');

var search = /## \[Unreleased\]\[unreleased\]/;

module.exports = function chlgRelease(release, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = {};
  }

  if (semver.valid(release) === null) {
    return callback(new Error('‘' + release + '’ is not valid semver version'));
  }

  var file = options.file || 'CHANGELOG.md';
  var tmp  = path.join(os.tmpdir(), 'chlg-' + Date.now() + '.md');

  try {
    var date = options.date ? dates.parse(options.date) : new Date();

    if (isNaN(date.getTime())) {
      return callback(new Error('Invalid date: ' + options.date));
    }

    chlgShow({file: file, releases: ['all']}, function (error, logs) {
      if (error) {
        return callback(error);
      }

      var releases = Object.keys(logs);

      if (releases.length > 1) {
        var latest = releases[1];

        if (!semver.gt(release, latest)) {
          return callback(new Error('Last release (' + latest + ') is greater than ' + release));
        } else if (logs[latest].date.getTime() >= date.getTime()) {
          return callback(new Error('The release date is prior to the last (' + dates.format(logs[latest].date) + ')'));
        }
      }

      var insert = '\n' + formatter.release(release, date);

      var stream = fs.createReadStream(file, {encoding: 'utf8'})
        .on('error', callback)
        .pipe(new StreamInsert(insert, search))
        .on('error', callback)
        .pipe(fs.createWriteStream(tmp))
        .on('error', callback);

      stream.on('finish', function () {
        fs.createReadStream(tmp, {encoding: 'utf8'}).pipe(fs.createWriteStream(file)).on('finish', function () {
          fs.unlink(tmp, callback);
        }).on('error', callback);
      });
    });
  } catch (error) {
    return callback(error);
  }
};
<commit_msg>Add JSDoc in chlg-release<commit_after>'use strict';

/**
 * @module chlg-release
 */

var fs     = require('fs');
var os     = require('os');
var path   = require('path');
var semver = require('semver');

var StreamInsert = require('./common/stream-insert.js');

var chlgShow  = require('./chlg-show');
var dates     = require('./common/dates');
var formatter = require('./format/raw');

var search = /## \[Unreleased\]\[unreleased\]/;

/**
 * @typedef  {object} Options
 * @property {string} [file=CHANGELOG.md] - The change log file name/path.
 * @property {string} [date=now]          - Force a specific release date, default to the current date.
 */

/**
 * Add a new release to the change log containing all current messages.
 *
 * @param  {string}   release   - Release number (semver version)
 * @param  {Options}  [options] - Options
 * @param  {Function} callback  - Callback invoked with an optional error when the release has been added in change log
 */
module.exports = function chlgRelease(release, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = {};
  }

  if (semver.valid(release) === null) {
    return callback(new Error('‘' + release + '’ is not valid semver version'));
  }

  var file = options.file || 'CHANGELOG.md';
  var tmp  = path.join(os.tmpdir(), 'chlg-' + Date.now() + '.md');

  try {
    var date = options.date ? dates.parse(options.date) : new Date();

    if (isNaN(date.getTime())) {
      return callback(new Error('Invalid date: ' + options.date));
    }

    chlgShow({file: file, releases: ['all']}, function (error, logs) {
      if (error) {
        return callback(error);
      }

      var releases = Object.keys(logs);

      if (releases.length > 1) {
        var latest = releases[1];

        if (!semver.gt(release, latest)) {
          return callback(new Error('Last release (' + latest + ') is greater than ' + release));
        } else if (logs[latest].date.getTime() >= date.getTime()) {
          return callback(new Error('The release date is prior to the last (' + dates.format(logs[latest].date) + ')'));
        }
      }

      var insert = '\n' + formatter.release(release, date);

      var stream = fs.createReadStream(file, {encoding: 'utf8'})
        .on('error', callback)
        .pipe(new StreamInsert(insert, search))
        .on('error', callback)
        .pipe(fs.createWriteStream(tmp))
        .on('error', callback);

      stream.on('finish', function () {
        fs.createReadStream(tmp, {encoding: 'utf8'}).pipe(fs.createWriteStream(file)).on('finish', function () {
          fs.unlink(tmp, callback);
        }).on('error', callback);
      });
    });
  } catch (error) {
    return callback(error);
  }
};
<|endoftext|>


<commit_before>/*jshint esversion: 6 */

export const API_SERVER_URL = api_server_url;
export const LOGIN_SERVER_URL = login_server_url;
export const LOGOUT_SERVER_URL = logout_server_url;

// TODO: also cache login in local cookie so we don't have to do so many round trips
let cached_me = null;
let logged_in = null;

export function me_cached() {
    if (cached_me) {
        return {
            user_id: cached_me["user_id"],
            username: cached_me["username"],
        };
    }
    else if (window.localStorage["cache"]) {
        return {
            user_id: window.localStorage["user_id"],
            username: window.localStorage["username"],
        };
    }
    else {
        return null;
    }
}

export function me() {
    if (cached_me !== null) return Promise.resolve(cached_me);
    else if (logged_in === false) return Promise.resolve(null);

    return $.get({
        url: `${LOGIN_SERVER_URL}/me`,
        xhrFields: {
            withCredentials: true,
        },
    }).then((me) => {
        if (me === null) {
            logged_in = false;
            return null;
        }
        logged_in = true;
        return get_user(me.user_id).then((user) => {
            cached_me = user;
            // TODO: invalidate this cache every so often
            window.localStorage["cache"] = Date.now();
            window.localStorage["user_id"] = user.user_id;
            window.localStorage["username"] = user.username;
            return user;
        });
    });
}

export function get_user(user_id) {
    return $.get({
        url: `${API_SERVER_URL}/user/${user_id}`,
        xhrFields: {
            withCredentials: true,
        },
    });
}

export function logout() {
    return $.post({
        url: `${LOGOUT_SERVER_URL}`,
        xhrFields: {
            withCredentials: true,
        },
    }).then((res) => {
        logged_in = false;
        window.localStorage.removeItem("cache");
        window.localStorage.removeItem("user_id");
        window.localStorage.removeItem("username");
    });
}

export function make_profile_image_url(username) {
    return `https://github.com/${username}.png`;
}

export function list_bots(user_id) {
    return $.get({
        url: `${API_SERVER_URL}/user/${user_id}/bot`,
    });
}

export function makeRequest() {
    const xhr = new XMLHttpRequest();
    return xhr;
}

export function update_bot(user_id, bot_id, file, progress_callback) {
    const method = bot_id === null ? "POST" : "PUT";
    const endpoint = bot_id === null ? "bot" : `bot/${bot_id}`;

    const xhr = makeRequest();
    xhr.upload.addEventListener("progress", function (e) {
        if (e.lengthComputable) {
            progress_callback(e.loaded / e.total);
        }
    }, false);
    xhr.upload.addEventListener("load", function (e) {
        progress_callback(1);
    }, false);
    xhr.withCredentials = true;
    xhr.open(method, `${API_SERVER_URL}/user/${user_id}/${endpoint}`);

    const form_data = new FormData();
    form_data.append("name", "botFile");
    form_data.append("botFile", file);

    xhr.send(form_data);

    return new Promise((resolve, reject) => {
        xhr.onload = function (e) {
            if (this.status === 200) {
                resolve();
            }
            else {
                const response = JSON.parse(e.target.responseText);
                reject(response);
            }
        };
    });
}

export function list_organizations() {
    return $.get({
        url: `${API_SERVER_URL}/organization`,
    });
}

export function register_me(data) {
    return $.post({
        url: `${API_SERVER_URL}/user`,
        data: JSON.stringify(data),
        contentType: "application/json",
        xhrFields: {
            withCredentials: true,
        },
    });
}

export function update_me(user_id, data) {
    return $.ajax({
        url: `${API_SERVER_URL}/user/${user_id}`,
        method: "PUT",
        data: JSON.stringify(data),
        contentType: "application/json",
        xhrFields: {
            withCredentials: true,
        },
    });
}

export function get_replay(game_id, progress_callback) {
    let game_data_promise = Promise.resolve($.get(`${API_SERVER_URL}/user/0/match/${game_id}`));
    let replay_promise = new Promise((resolve, reject) => {
        const xhr = makeRequest();
        xhr.withCredentials = true;
        xhr.open("GET", `${API_SERVER_URL}/user/0/match/${game_id}/replay`, true);
        xhr.responseType = "arraybuffer";

        if (progress_callback) {
            xhr.onprogress = function (e) {
                progress_callback(e.loaded, e.total);
            };
        }

        xhr.onload = function (e) {
            if (this.status === 200) {
                const blob = this.response;
                resolve(blob);
            }
            else {
                reject();
            }
        };

        xhr.onerror = function () {
            reject();
        };

        xhr.onreadystatechange = function (e) {
            if (xhr.readyState === 4) {
                if (xhr.status !== 200) {
                    reject();
                }
            }
        };

        xhr.send();
    });
    return Promise.all([game_data_promise, replay_promise]).then(([game, replay]) => {
        return {
            game: game,
            replay: replay,
        };
    });
}

export function get_expired_replay(replay_class, replay_name) {
    return new Promise((resolve, reject) => {
        const xhr = makeRequest();
        xhr.withCredentials = true;
        xhr.open("GET", `${API_SERVER_URL}/replay/class/${replay_class}/name/${replay_name}`, true);
        xhr.responseType = "arraybuffer";

        xhr.onload = function (e) {
            if (this.status === 200) {
                const blob = this.response;
                resolve(blob);
            }
            else {
                reject();
            }
        };

        xhr.onerror = function () {
            reject();
        };

        xhr.onreadystatechange = function (e) {
            if (xhr.readyState === 4) {
                if (xhr.status !== 200) {
                    reject();
                }
            }
        };

        xhr.send();
    });
}

export function leaderboard(filters, hackathon = null, offset = null, limit = null) {
    let url = `${API_SERVER_URL}/leaderboard`;
    let fields = {};
    if (hackathon) {
        url = `${API_SERVER_URL}/hackathon/${hackathon}/leaderboard`;
        fields.withCredentials = true;
    }

    const querystring = [];
    if (offset !== null && limit !== null) {
        querystring.push(`offset=${offset}&limit=${limit}`);
    }
    if (filters && filters.length > 0) {
        querystring.push(`filter=${filters.join('&filter=')}`);
    }
    if (querystring.length > 0) {
        url += `?${querystring.join("&")}`;
    }
    return $.get({
        url: url,
        xhrFields: fields,
    });
}

export function reset_api_key() {
    return $.post({
        url: `${API_SERVER_URL}/api_key`,
        xhrFields: {
            withCredentials: true,
        },
    });
}

export function registerHackathon(code) {
    const me = me_cached();
    if (!me) {
        return Promise.reject({
            message: "You must be logged in to register for a hackathon.",
        });
    }
    return $.post({
        url: `${API_SERVER_URL}/user/${me.user_id}/hackathon`,
        data: {
            verification_code: code,
        },
        xhrFields: {
            withCredentials: true,
        },
    });
}

export function getHackathon(id) {
    return $.get({
        url: `${API_SERVER_URL}/hackathon/${id}`,
        xhrFields: {
            withCredentials: true,
        },
    });
}

export function getUserHackathons(userId) {
    return $.get({
        url: `${API_SERVER_URL}/user/${userId}/hackathon`,
        xhrFields: {
            withCredentials: true,
        }
    });
}

export function getUserHistory(userId) {
    return $.get({
        url: `${API_SERVER_URL}/user/${userId}/history`,
        xhrFields: {
            withCredentials: true,
        }
    });
}

export function invitefriend(email) {
    return $.post({
        url: `${API_SERVER_URL}/invitation/user/` + email
    });
}

export function subscribe(email) {
    return $.post({
        url: `${API_SERVER_URL}/user/addsubscriber/` + email
    });
}
<commit_msg>Fixed bot submission error on first upload<commit_after>/*jshint esversion: 6 */

export const API_SERVER_URL = api_server_url;
export const LOGIN_SERVER_URL = login_server_url;
export const LOGOUT_SERVER_URL = logout_server_url;

// TODO: also cache login in local cookie so we don't have to do so many round trips
let cached_me = null;
let logged_in = null;

export function me_cached() {
    if (cached_me) {
        return {
            user_id: cached_me["user_id"],
            username: cached_me["username"],
        };
    }
    else if (window.localStorage["cache"]) {
        return {
            user_id: window.localStorage["user_id"],
            username: window.localStorage["username"],
        };
    }
    else {
        return null;
    }
}

export function me() {
    if (cached_me !== null) return Promise.resolve(cached_me);
    else if (logged_in === false) return Promise.resolve(null);

    return $.get({
        url: `${LOGIN_SERVER_URL}/me`,
        xhrFields: {
            withCredentials: true,
        },
    }).then((me) => {
        if (me === null) {
            logged_in = false;
            return null;
        }
        logged_in = true;
        return get_user(me.user_id).then((user) => {
            cached_me = user;
            // TODO: invalidate this cache every so often
            window.localStorage["cache"] = Date.now();
            window.localStorage["user_id"] = user.user_id;
            window.localStorage["username"] = user.username;
            return user;
        });
    });
}

export function get_user(user_id) {
    return $.get({
        url: `${API_SERVER_URL}/user/${user_id}`,
        xhrFields: {
            withCredentials: true,
        },
    });
}

export function logout() {
    return $.post({
        url: `${LOGOUT_SERVER_URL}`,
        xhrFields: {
            withCredentials: true,
        },
    }).then((res) => {
        logged_in = false;
        window.localStorage.removeItem("cache");
        window.localStorage.removeItem("user_id");
        window.localStorage.removeItem("username");
    });
}

export function make_profile_image_url(username) {
    return `https://github.com/${username}.png`;
}

export function list_bots(user_id) {
    return $.get({
        url: `${API_SERVER_URL}/user/${user_id}/bot`,
    });
}

export function makeRequest() {
    const xhr = new XMLHttpRequest();
    return xhr;
}

export function update_bot(user_id, bot_id, file, progress_callback) {
    const method = bot_id === null ? "POST" : "PUT";
    const endpoint = bot_id === null ? "bot" : `bot/${bot_id}`;

    const xhr = makeRequest();
    xhr.upload.addEventListener("progress", function (e) {
        if (e.lengthComputable) {
            progress_callback(e.loaded / e.total);
        }
    }, false);
    xhr.upload.addEventListener("load", function (e) {
        progress_callback(1);
    }, false);
    xhr.withCredentials = true;
    xhr.open(method, `${API_SERVER_URL}/user/${user_id}/${endpoint}`);

    const form_data = new FormData();
    form_data.append("name", "botFile");
    form_data.append("botFile", file);

    xhr.send(form_data);

    return new Promise((resolve, reject) => {
        xhr.onload = function (e) {
            if (this.status === 200 || this.status == 201) {
                resolve();
            }
            else {
                const response = JSON.parse(e.target.responseText);
                reject(response);
            }
        };
    });
}

export function list_organizations() {
    return $.get({
        url: `${API_SERVER_URL}/organization`,
    });
}

export function register_me(data) {
    return $.post({
        url: `${API_SERVER_URL}/user`,
        data: JSON.stringify(data),
        contentType: "application/json",
        xhrFields: {
            withCredentials: true,
        },
    });
}

export function update_me(user_id, data) {
    return $.ajax({
        url: `${API_SERVER_URL}/user/${user_id}`,
        method: "PUT",
        data: JSON.stringify(data),
        contentType: "application/json",
        xhrFields: {
            withCredentials: true,
        },
    });
}

export function get_replay(game_id, progress_callback) {
    let game_data_promise = Promise.resolve($.get(`${API_SERVER_URL}/user/0/match/${game_id}`));
    let replay_promise = new Promise((resolve, reject) => {
        const xhr = makeRequest();
        xhr.withCredentials = true;
        xhr.open("GET", `${API_SERVER_URL}/user/0/match/${game_id}/replay`, true);
        xhr.responseType = "arraybuffer";

        if (progress_callback) {
            xhr.onprogress = function (e) {
                progress_callback(e.loaded, e.total);
            };
        }

        xhr.onload = function (e) {
            if (this.status === 200) {
                const blob = this.response;
                resolve(blob);
            }
            else {
                reject();
            }
        };

        xhr.onerror = function () {
            reject();
        };

        xhr.onreadystatechange = function (e) {
            if (xhr.readyState === 4) {
                if (xhr.status !== 200) {
                    reject();
                }
            }
        };

        xhr.send();
    });
    return Promise.all([game_data_promise, replay_promise]).then(([game, replay]) => {
        return {
            game: game,
            replay: replay,
        };
    });
}

export function get_expired_replay(replay_class, replay_name) {
    return new Promise((resolve, reject) => {
        const xhr = makeRequest();
        xhr.withCredentials = true;
        xhr.open("GET", `${API_SERVER_URL}/replay/class/${replay_class}/name/${replay_name}`, true);
        xhr.responseType = "arraybuffer";

        xhr.onload = function (e) {
            if (this.status === 200) {
                const blob = this.response;
                resolve(blob);
            }
            else {
                reject();
            }
        };

        xhr.onerror = function () {
            reject();
        };

        xhr.onreadystatechange = function (e) {
            if (xhr.readyState === 4) {
                if (xhr.status !== 200) {
                    reject();
                }
            }
        };

        xhr.send();
    });
}

export function leaderboard(filters, hackathon = null, offset = null, limit = null) {
    let url = `${API_SERVER_URL}/leaderboard`;
    let fields = {};
    if (hackathon) {
        url = `${API_SERVER_URL}/hackathon/${hackathon}/leaderboard`;
        fields.withCredentials = true;
    }

    const querystring = [];
    if (offset !== null && limit !== null) {
        querystring.push(`offset=${offset}&limit=${limit}`);
    }
    if (filters && filters.length > 0) {
        querystring.push(`filter=${filters.join('&filter=')}`);
    }
    if (querystring.length > 0) {
        url += `?${querystring.join("&")}`;
    }
    return $.get({
        url: url,
        xhrFields: fields,
    });
}

export function reset_api_key() {
    return $.post({
        url: `${API_SERVER_URL}/api_key`,
        xhrFields: {
            withCredentials: true,
        },
    });
}

export function registerHackathon(code) {
    const me = me_cached();
    if (!me) {
        return Promise.reject({
            message: "You must be logged in to register for a hackathon.",
        });
    }
    return $.post({
        url: `${API_SERVER_URL}/user/${me.user_id}/hackathon`,
        data: {
            verification_code: code,
        },
        xhrFields: {
            withCredentials: true,
        },
    });
}

export function getHackathon(id) {
    return $.get({
        url: `${API_SERVER_URL}/hackathon/${id}`,
        xhrFields: {
            withCredentials: true,
        },
    });
}

export function getUserHackathons(userId) {
    return $.get({
        url: `${API_SERVER_URL}/user/${userId}/hackathon`,
        xhrFields: {
            withCredentials: true,
        }
    });
}

export function getUserHistory(userId) {
    return $.get({
        url: `${API_SERVER_URL}/user/${userId}/history`,
        xhrFields: {
            withCredentials: true,
        }
    });
}

export function invitefriend(email) {
    return $.post({
        url: `${API_SERVER_URL}/invitation/user/` + email
    });
}

export function subscribe(email) {
    return $.post({
        url: `${API_SERVER_URL}/user/addsubscriber/` + email
    });
}
<|endoftext|>


<commit_before>// --- JS Error Logger --------------------------------------------------------

window.onerror = function (msg, location, lineNo, columnNo, error) {
  $.post('/debug/jserrorlog', {
    message: msg,
    line: lineNo,
    column: columnNo,
    url: location,
    useragent: navigator.userAgent,
    stack: error,
  }, 'multipart/form-data');
  alert(msg + '\nFile: ' + location + '\nLine: ' + lineNo + '\nColumn: ' + columnNo);
};

// --- Common Functions -------------------------------------------------------

function uuid() {
  var random;
  var i;

  var result = '';
  var seed = Date.now();

  for (i = 0; i < 32; i++) {
    random = (seed + Math.random() * 16) % 16 | 0;
    seed = Math.floor(seed / 16);

    if (i === 8 || i === 12 || i === 16 || i === 20) {
      result += '-';
    }

    if (i === 12) {
      result += (4).toString(16);
    } else if (i === 16) {
      result += (random & (3 | 8)).toString(16);
    } else {
      result += random.toString(16);
    }
  }
  return result;
}

function sleep(time) {
  var start = new Date().getTime();

  if (typeof Promise !== 'undefined' && Promise.toString().indexOf('[native code]') !== -1) {
    // The statement below should be this function "return new Promise((resolve) => setTimeout(resolve, time));" without the arrow
    return new Promise(function (resolve) { return setTimeout(resolve, time); }, this);
  }
  // Burn motherfucker burn.... I'm sorry Mr. APU, it won't be for long
  while (new Date().getTime() < start + time);
  return undefined;
}

function getServerIP() {
  return $.ajax({
    dataType: 'text',
    url: '/api/serverip',
    async: false,
  }).responseText;
}

function getJson(url) {
  return $.ajax({
    dataType: 'json',
    url: url,
    async: false,
  }).responseJSON;
}

function sendJson(url, data) {
  return $.ajax({
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    url: url,
    data: data,
    async: false,
  }).responseJSON;
}

function getCategories() {
  var url = '/api/categories';
  var result = getJson(url);

  if (result !== undefined && result.length > 0) {
    return result;
  }
  return undefined;
}

function getEntries(category) {
  var url = '/api/entries/' + category;
  var result = getJson(url);

  if (result !== undefined && result.length > 0) {
    return result;
  }
  return undefined;
}

function loadFrame(url) {
  var ifrObj = $('#ifr').get(0);

  if (ifrObj !== undefined) {
    ifrObj.contentWindow.location.replace(url);
  }
}

function cacheRedirect(country) {
  loadFrame('/cache/redirect/' + country + '/index.html');
}

function cacheTheme() {
  loadFrame('/cache/theme/index.html');
}

function cacheCategory(category) {
  loadFrame('/cache/category/' + category + '/index.html');
}

function cacheEntry(category, entry) {
  loadFrame('/cache/entry/' + category + '/' + entry + '/index.html');
}

function cacheAll() {
  loadFrame('/cache/all/index.html');
}

function getCategoryMeta(category) {
  return getJson('/exploits/' + category + '/meta.json');
}

function getEntryMeta(category, entry) {
  return getJson('/exploits/' + category + '/' + entry + '/meta.json');
}

function isCategoryCacheable(category) {
  var result = getCategoryMeta(category);

  if (result === undefined || result.Cacheable === undefined || typeof (result.Cacheable) !== typeof (true)) {
    return false;
  }
  return result.Cacheable;
}

function isEntryAvailableOffline(category, entry) {
  var result = getEntryMeta(category, entry);

  if (result === undefined || result.Offline === undefined || typeof (result.Offline) !== typeof (true)) {
    return false;
  }
  return result.Offline;
}

function checkUAMatch(validUAs) {
  var result;

  var currentUA = navigator.userAgent;

  if ($.inArray(currentUA, validUAs) !== -1) {
    return true;
  }

  $.each(validUAs, function (i, field) {
    var pattern = new RegExp(field);
    if (pattern.test(currentUA)) {
      result = true;
    }
  });
  return result;
}

function loadEntry(category, entry) {
  loadFrame('/exploits/' + category + '/' + entry + '/index.html');
}

function clearFrame() {
  loadFrame('/blank.html');
}

function safeRedirect(url) {
  clearFrame();
  $('#ifr').on('load', function () {
    window.location.href = url;
  });
}

function getStorage(key) {
  if (localStorage.getItem(key) !== null) {
    return localStorage.getItem(key);
  }
  return undefined;
}

function setStorage(key, value, datatype) {
  if (typeof (value) === datatype) {
    localStorage.setItem(key, value);
  }
}

function getLanguage() {
  return getStorage('language');
}

function setLanguage(lang) {
  setStorage('language', lang, 'string');
}

function setAutoload(category, entry) {
  document.cookie = 'autoload=' + category + '/' + entry + '; expires=Tue, 19 Jan 2038 03:14:07 UTC;';
}

function clearAutoload() {
  document.cookie = 'autoload=; expires=Mon, 01 Jan 2001 00:00:00 UTC;';
}

function getCookie(cname) {
  var result;

  var name = cname + '=';
  var decodedCookie = decodeURIComponent(document.cookie);
  var cookies = decodedCookie.split(';');

  $.each(cookies, function (i, field) {
    while (field.charAt(0) === ' ') {
      field = field.substring(1);
    }
    if (field.indexOf(name) === 0) {
      result = field.substring(name.length, field.length);
    }
  });
  return result;
}

function autoloadCookie() {
  var category;
  var entry;

  var autoload = getCookie('autoload');

  if (autoload) {
    try {
      category = autoload.split('/')[0];
      entry = autoload.split('/')[1];
      if ($.inArray(category, getCategories()) === -1 || $.inArray(entry, getEntries(category)) === -1) {
        clearAutoload();
      } else {
        return autoload;
      }
    } catch (e) {
      clearAutoload();
    }
  }
  return undefined;
}
/*
Copyright (c) 2017-2018 Al Azif, https://github.com/Al-Azif/ps4-exploit-host

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

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

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

window.onerror = function (msg, errorLocation, lineNo, columnNo, error) {
  $.post('/debug/jserrorlog', {
    message: msg,
    line: lineNo,
    column: columnNo,
    url: errorLocation,
    useragent: navigator.userAgent,
    stack: error,
  }, 'multipart/form-data');
  alert(msg + '\nFile: ' + errorLocation + '\nLine: ' + lineNo + '\nColumn: ' + columnNo);
};

// --- Common Functions -------------------------------------------------------

function uuid() {
  var random;
  var i;

  var result = '';
  var seed = Date.now();

  for (i = 0; i < 32; i++) {
    random = (seed + Math.random() * 16) % 16 | 0;
    seed = Math.floor(seed / 16);

    if (i === 8 || i === 12 || i === 16 || i === 20) {
      result += '-';
    }

    if (i === 12) {
      result += (4).toString(16);
    } else if (i === 16) {
      result += (random & (3 | 8)).toString(16);
    } else {
      result += random.toString(16);
    }
  }
  return result;
}

function sleep(time) {
  var start = new Date().getTime();

  if (typeof Promise !== 'undefined' && Promise.toString().indexOf('[native code]') !== -1) {
    // The statement below should be this function "return new Promise((resolve) => setTimeout(resolve, time));" without the arrow
    return new Promise(function (resolve) { return setTimeout(resolve, time); }, this);
  }
  // Burn motherfucker burn.... I'm sorry Mr. APU, it won't be for long
  while (new Date().getTime() < start + time);
  return undefined;
}

function getServerIP() {
  return $.ajax({
    dataType: 'text',
    url: '/api/serverip',
    async: false,
  }).responseText;
}

function getJson(inputURL) {
  return $.ajax({
    dataType: 'json',
    url: inputURL,
    async: false,
  }).responseJSON;
}

function sendJson(inputURL, message) {
  return $.ajax({
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    url: inputURL,
    data: message,
    async: false,
  }).responseJSON;
}

function getCategories() {
  var url = '/api/categories';
  var result = getJson(url);

  if (result !== undefined && result.length > 0) {
    return result;
  }
  return undefined;
}

function getEntries(category) {
  var url = '/api/entries/' + category;
  var result = getJson(url);

  if (result !== undefined && result.length > 0) {
    return result;
  }
  return undefined;
}

function loadFrame(url) {
  var ifrObj = $('#ifr').get(0);

  if (ifrObj !== undefined) {
    ifrObj.contentWindow.location.replace(url);
  }
}

function cacheRedirect(country) {
  loadFrame('/cache/redirect/' + country + '/index.html');
}

function cacheTheme() {
  loadFrame('/cache/theme/index.html');
}

function cacheCategory(category) {
  loadFrame('/cache/category/' + category + '/index.html');
}

function cacheEntry(category, entry) {
  loadFrame('/cache/entry/' + category + '/' + entry + '/index.html');
}

function cacheAll() {
  loadFrame('/cache/all/index.html');
}

function getCategoryMeta(category) {
  return getJson('/exploits/' + category + '/meta.json');
}

function getEntryMeta(category, entry) {
  return getJson('/exploits/' + category + '/' + entry + '/meta.json');
}

function isCategoryCacheable(category) {
  var result = getCategoryMeta(category);

  if (result === undefined || result.Cacheable === undefined || typeof (result.Cacheable) !== typeof (true)) {
    return false;
  }
  return result.Cacheable;
}

function isEntryAvailableOffline(category, entry) {
  var result = getEntryMeta(category, entry);

  if (result === undefined || result.Offline === undefined || typeof (result.Offline) !== typeof (true)) {
    return false;
  }
  return result.Offline;
}

function checkUAMatch(validUAs) {
  var result;

  var currentUA = navigator.userAgent;

  if ($.inArray(currentUA, validUAs) !== -1) {
    return true;
  }

  $.each(validUAs, function (i, field) {
    var pattern = new RegExp(field);
    if (pattern.test(currentUA)) {
      result = true;
    }
  });
  return result;
}

function loadEntry(category, entry) {
  loadFrame('/exploits/' + category + '/' + entry + '/index.html');
}

function clearFrame() {
  loadFrame('/blank.html');
}

function safeRedirect(url) {
  clearFrame();
  $('#ifr').on('load', function () {
    window.location.href = url;
  });
}

function getStorage(key) {
  if (localStorage.getItem(key) !== null) {
    return localStorage.getItem(key);
  }
  return undefined;
}

function setStorage(key, value, datatype) {
  if (typeof (value) === datatype) {
    localStorage.setItem(key, value);
  }
}

function getLanguage() {
  return getStorage('language');
}

function setLanguage(lang) {
  setStorage('language', lang, 'string');
}

function setAutoload(category, entry) {
  document.cookie = 'autoload=' + category + '/' + entry + '; expires=Tue, 19 Jan 2038 03:14:07 UTC;';
}

function clearAutoload() {
  document.cookie = 'autoload=; expires=Mon, 01 Jan 2001 00:00:00 UTC;';
}

function getCookie(cname) {
  var result;

  var name = cname + '=';
  var decodedCookie = decodeURIComponent(document.cookie);
  var cookies = decodedCookie.split(';');

  $.each(cookies, function (i, field) {
    while (field.charAt(0) === ' ') {
      field = field.substring(1);
    }
    if (field.indexOf(name) === 0) {
      result = field.substring(name.length, field.length);
    }
  });
  return result;
}

function autoloadCookie() {
  var category;
  var entry;

  var autoload = getCookie('autoload');

  if (autoload) {
    try {
      category = autoload.split('/')[0];
      entry = autoload.split('/')[1];
      if ($.inArray(category, getCategories()) === -1 || $.inArray(entry, getEntries(category)) === -1) {
        clearAutoload();
      } else {
        return autoload;
      }
    } catch (e) {
      clearAutoload();
    }
  }
  return undefined;
}
/*
Copyright (c) 2017-2018 Al Azif, https://github.com/Al-Azif/ps4-exploit-host

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

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

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