<commit_before>#!/usr/bin/env node
'use strict'
const execSync = require('child_process').execSync
const fs = require('fs')
const path = require('path')
const util = require('util')

const ghauth = require('ghauth')
const ghissues = require('ghissues')
const pkgToId = require('pkg-to-id')
const Command = require('commander').Command
const semverRegex = require('semver-regex')
const winston = require('winston')

const pkg = require('./package')

const logger = new winston.Logger({
  transports: [new winston.transports.Console()]
})
logger.cli()

function exec (command) {
  logger.debug('Command: %s', command)
  try {
    return execSync(command)
  } catch (error) {
    logger.error(error)
    process.exit(1)
  }
}

function parseArguments (defaults, argv) {
  const program = new Command()
    .version(defaults.version)
    .description(defaults.description)
    .option('-u, --user [user]', 'GitHub user', defaults.user)
    .option('-p, --project [project]', 'GitHub project', defaults.project)
    .option('-t, --tag [tag]', 'Git tag', defaults.tag)
    .option('-l, --log-level [logLevel]',
            'Log level',
            /^(error|warn|info|verbose|debug|silly)$/i,
            defaults.logLevel)
    .option('-n --dry-run',
            'Log actions, but skip adding comments to GitHub PRs')
    .parse(argv)

  return program
}

function getMergeCommits (revRange) {
  const gitLogCmd = `git log ${revRange} --format='%s' --grep='^Merge pull request #[0-9]\\+ from '`
  const commits = exec(gitLogCmd).toString().trimRight()
  logger.debug('Commits: %s', commits)
  return commits
}

function getPRs (commits) {
  const prs = commits.split('\n').map(function (line) {
    const match = /Merge pull request #(\d+) from /.exec(line)
    if (match) {
      return parseInt(match[1], 10)
    }
    return false
  }).filter(Boolean)
  logger.debug('PRs: %s', prs)
  return prs
}

function writeComments (authOptions, program, prs, comment) {
  ghauth(authOptions, function (error, authData) {
    if (error) {
      logger.error('GitHub Authorization failure: %s', error)
      process.exit(1)
    }
    logger.debug('GitHub Authorization success for user: %s', authData.user)
    prs.forEach(function (pr) {
      logger.info('Adding comment to PR#%d', pr)
      if (!program.dryRun) {
        ghissues.createComment(
          authData, program.user, program.project, pr, comment, function (error, comment) {
            if (error) {
              logger.error('Error adding comment to PR#%d: %s', pr, error)
            } else {
              logger.debug('Comment: %s', comment)
            }
          })
      }
    })

    logger.info('Done!')
  })
}

function main () {
  logger.info('%s v%s', pkg.name, pkg.version)

  const pkgFile = path.join(process.cwd(), 'package.json')
  let pkgId
  if (fs.existsSync(pkgFile)) {
    const pkgData = require(pkgFile)
    pkgId = pkgToId(pkgData)
  } else {
    logger.warn('File not found: %s', pkgFile)
    pkgId = {}
  }
  const tags = exec("git tag --sort='-version:refname'")
    .toString().split('\n').filter(tag => semverRegex().test(tag))

  const defaults = {
    version: pkg.version,
    description: pkg.description,
    user: pkgId.user,
    project: pkgId.name,
    tag: tags[0],
    logLevel: 'info'
  }
  const program = parseArguments(defaults, process.argv)

  logger.level = program.logLevel
  logger.debug('pkgId:', pkgId)
  logger.debug('Tags: %s', tags)
  logger.debug('program:', {
    user: program.user,
    project: program.project,
    tag: program.tag,
    logLevel: program.logLevel,
    dryRun: program.dryRun
  })

  if (tags.length === 0) {
    logger.error('No tags found in repository')
    process.exit(1)
  }
  if (!semverRegex().test(program.tag)) {
    logger.error('Tag not semver compliant: %s', program.tag)
    process.exit(1)
  }

  const toTagIndex = tags.indexOf(program.tag)
  if (toTagIndex === -1) {
    logger.error('Tag not found in repository: %s', program.tag)
    process.exit(1)
  }
  const toTag = program.tag
  const fromTag = tags[toTagIndex + 1]

  const revRange = (typeof fromTag !== 'undefined') ? `${fromTag}..${toTag}` : toTag
  const commits = getMergeCommits(revRange)
  const prs = getPRs(commits)

  const authOptions = {
    configName: pkg.name,
    note: util.format('%s: %s', pkg.name, pkg.description)
  }
  writeComments(authOptions, program, prs, toTag)
}

if (require.main === module) {
  main()
}
<commit_msg>Update authorization note<commit_after>#!/usr/bin/env node
'use strict'
const execSync = require('child_process').execSync
const fs = require('fs')
const path = require('path')

const ghauth = require('ghauth')
const ghissues = require('ghissues')
const pkgToId = require('pkg-to-id')
const Command = require('commander').Command
const semverRegex = require('semver-regex')
const winston = require('winston')

const pkg = require('./package')

const logger = new winston.Logger({
  transports: [new winston.transports.Console()]
})
logger.cli()

function exec (command) {
  logger.debug('Command: %s', command)
  try {
    return execSync(command)
  } catch (error) {
    logger.error(error)
    process.exit(1)
  }
}

function parseArguments (defaults, argv) {
  const program = new Command()
    .version(defaults.version)
    .description(defaults.description)
    .option('-u, --user [user]', 'GitHub user', defaults.user)
    .option('-p, --project [project]', 'GitHub project', defaults.project)
    .option('-t, --tag [tag]', 'Git tag', defaults.tag)
    .option('-l, --log-level [logLevel]',
            'Log level',
            /^(error|warn|info|verbose|debug|silly)$/i,
            defaults.logLevel)
    .option('-n --dry-run',
            'Log actions, but skip adding comments to GitHub PRs')
    .parse(argv)

  return program
}

function getMergeCommits (revRange) {
  const gitLogCmd = `git log ${revRange} --format='%s' --grep='^Merge pull request #[0-9]\\+ from '`
  const commits = exec(gitLogCmd).toString().trimRight()
  logger.debug('Commits: %s', commits)
  return commits
}

function getPRs (commits) {
  const prs = commits.split('\n').map(function (line) {
    const match = /Merge pull request #(\d+) from /.exec(line)
    if (match) {
      return parseInt(match[1], 10)
    }
    return false
  }).filter(Boolean)
  logger.debug('PRs: %s', prs)
  return prs
}

function writeComments (authOptions, program, prs, comment) {
  ghauth(authOptions, function (error, authData) {
    if (error) {
      logger.error('GitHub Authorization failure: %s', error)
      process.exit(1)
    }
    logger.debug('GitHub Authorization success for user: %s', authData.user)
    prs.forEach(function (pr) {
      logger.info('Adding comment to PR#%d', pr)
      if (!program.dryRun) {
        ghissues.createComment(
          authData, program.user, program.project, pr, comment, function (error, comment) {
            if (error) {
              logger.error('Error adding comment to PR#%d: %s', pr, error)
            } else {
              logger.debug('Comment: %s', comment)
            }
          })
      }
    })

    logger.info('Done!')
  })
}

function main () {
  logger.info('%s v%s', pkg.name, pkg.version)

  const pkgFile = path.join(process.cwd(), 'package.json')
  let pkgId
  if (fs.existsSync(pkgFile)) {
    const pkgData = require(pkgFile)
    pkgId = pkgToId(pkgData)
  } else {
    logger.warn('File not found: %s', pkgFile)
    pkgId = {}
  }
  const tags = exec("git tag --sort='-version:refname'")
    .toString().split('\n').filter(tag => semverRegex().test(tag))

  const defaults = {
    version: pkg.version,
    description: pkg.description,
    user: pkgId.user,
    project: pkgId.name,
    tag: tags[0],
    logLevel: 'info'
  }
  const program = parseArguments(defaults, process.argv)

  logger.level = program.logLevel
  logger.debug('pkgId:', pkgId)
  logger.debug('Tags: %s', tags)
  logger.debug('program:', {
    user: program.user,
    project: program.project,
    tag: program.tag,
    logLevel: program.logLevel,
    dryRun: program.dryRun
  })

  if (tags.length === 0) {
    logger.error('No tags found in repository')
    process.exit(1)
  }
  if (!semverRegex().test(program.tag)) {
    logger.error('Tag not semver compliant: %s', program.tag)
    process.exit(1)
  }

  const toTagIndex = tags.indexOf(program.tag)
  if (toTagIndex === -1) {
    logger.error('Tag not found in repository: %s', program.tag)
    process.exit(1)
  }
  const toTag = program.tag
  const fromTag = tags[toTagIndex + 1]

  const revRange = (typeof fromTag !== 'undefined') ? `${fromTag}..${toTag}` : toTag
  const commits = getMergeCommits(revRange)
  const prs = getPRs(commits)

  const authOptions = {
    configName: pkg.name,
    note: pkg.name
  }
  writeComments(authOptions, program, prs, toTag)
}

if (require.main === module) {
  main()
}
<|endoftext|>


<commit_before>'use strict'

import BaseTransport from './rpc'

class DesktopTransport extends BaseTransport {
  constructor (incomingRPCCallback) {
    const paths = [
      // Hardcoded for now!
      process.env.HOME + '/Library/Caches/KeybaseDevel/keybased.sock',
      process.env.XDG_RUNTIME_DIR + '/keybase.devel/keybased.sock'
    ]
    let sockfile = null
    paths.map(path => {
      // Can't use ES2015 import because it'll hoist and crash mobile.
      let fs = require('fs')
      let exists = fs.existsSync(path)
      if (exists) {
        console.log('Found keybased socket file at ' + path)
        sockfile = path
      }
    })
    if (!sockfile) {
      console.error('No keybased socket file found!')
    }
    super(
      { path: sockfile, robust: true },
      null,
      incomingRPCCallback
    )
    this.needsConnect = true
    this.needsBase64 = false
  }
}

export default DesktopTransport
<commit_msg>We can use the fs module now<commit_after>'use strict'

import BaseTransport from './rpc'
import fs from 'fs'

class DesktopTransport extends BaseTransport {
  constructor (incomingRPCCallback) {
    const paths = [
      // Hardcoded for now!
      process.env.HOME + '/Library/Caches/KeybaseDevel/keybased.sock',
      process.env.XDG_RUNTIME_DIR + '/keybase.devel/keybased.sock'
    ]
    let sockfile = null
    paths.map(path => {
      let exists = fs.existsSync(path)
      if (exists) {
        console.log('Found keybased socket file at ' + path)
        sockfile = path
      }
    })
    if (!sockfile) {
      console.error('No keybased socket file found!')
    }
    super(
      { path: sockfile, robust: true },
      null,
      incomingRPCCallback
    )
    this.needsConnect = true
    this.needsBase64 = false
  }
}

export default DesktopTransport
<|endoftext|>


<commit_before>/**
 * menu bar carto module
 * this module allows to edit Carto style
 */

cdb.admin.mod = cdb.admin.mod || {};

(function() {

  /**
   * module to change cartoCSS
   * is rendered on the right panel of map
   */
  cdb.admin.mod.Carto = cdb.core.View.extend({

    buttonClass: 'style_mod',
    type: 'tool',

    events: {
      'click nav a.wizard': 'enableWizard',
      'click nav a.editor': 'enableEditor',
      'click .doc_info':    '_showDoc'
    },

    initialize: function() {
      this.panels = new cdb.ui.common.TabPane();
      this.active = 'wizard';
      this.template = this.getTemplate('table/menu_modules/views/carto');
    },

    render: function() {
      var self = this;
      this.$el.append(this.template({}));
      this.panels.setElement(this.$('.panels'));

      // panels
      var editorPanel = new cdb.admin.mod.CartoEditor({
        model: this.model, // dataLayer
        table: this.options.table,
        className: "editor"
      });
      this.panels.addTab('editor', editorPanel.render());
      this.retrigger('hasErrors', editorPanel);
      this.retrigger('clearError', editorPanel);

      this.panels.addTab('wizard', new cdb.admin.mod.CartoWizard({
        model: this.model, // datalayer
        table: this.options.table,
        className: "wizard"
      }).render());

      return this;
    },

    enableWizard: function(ev) {
      ev.preventDefault();

      // Add - Remove selected class
      this.active = 'wizard';
      this._setSelected('wizard');

      this.panels.active('wizard');
      this.trigger('enable', 'wizard');

      return false;
    },

    enableEditor: function(ev) {
      ev.preventDefault();

      // Add - Remove selected class
      this.active = 'carto';
      this._setSelected('editor');

      this.panels.active('editor');
      this.trigger('enable', 'carto');

      return false;
    },

    _setSelected: function(name) {
      // Add - Remove selected class
      this.$el.find("nav > a").removeClass("selected");
      this.$("nav > a." + name).addClass("selected");
    },

    active: function(name) {
      if(name == 'carto') {
        this.enableEditor();
      } else {
        this.enableWizard()
      }
    },

    _showDoc: function(ev) {
      ev.preventDefault();
      var dialog = new cdb.admin.CartoCSSInfo();
      $("body").append(dialog.render().el);
      dialog.open();
    }

  });

}());
<commit_msg>check if the table has data, and if not, disables wizard<commit_after>/**
 * menu bar carto module
 * this module allows to edit Carto style
 */

cdb.admin.mod = cdb.admin.mod || {};

(function() {

  /**
   * module to change cartoCSS
   * is rendered on the right panel of map
   */
  cdb.admin.mod.Carto = cdb.core.View.extend({

    buttonClass: 'style_mod',
    type: 'tool',

    events: {
      'click nav a.wizard': 'enableWizard',
      'click nav a.editor': 'enableEditor',
      'click .doc_info':    '_showDoc'
    },

    initialize: function() {
      this.panels = new cdb.ui.common.TabPane();
      this.active = 'wizard';
      this.template = this.getTemplate('table/menu_modules/views/carto');
    },

    tableHasData: function() {
      if(this.options &&
        this.options.table &&
        this.options.table.data &&
        this.options.table.data().models
        ) {
        return this.options.table.data().models.length > 0;
      }
      return false;

    },

    render: function() {
      var self = this;
      this.$el.append(this.template({}));
      this.panels.setElement(this.$('.panels'));

      // panels
      var editorPanel = new cdb.admin.mod.CartoEditor({
        model: this.model, // dataLayer
        table: this.options.table,
        className: "editor"
      });
      this.panels.addTab('editor', editorPanel.render());
      this.retrigger('hasErrors', editorPanel);
      this.retrigger('clearError', editorPanel);
      this.options.table.bind('dataLoaded', this.addWizard.bind(this));
      return this;

    },

    addWizard: function(ev) {
      if(this.tableHasData()) {
        this.panels.addTab('wizard', new cdb.admin.mod.CartoWizard({
          model: this.model, // datalayer
          table: this.options.table,
          className: "wizard"
        }).render());
      } else {
        this.$('a.wizard').remove();
      }
    },
    enableWizard: function(ev) {
      ev.preventDefault();

      // Add - Remove selected class
      this.active = 'wizard';
      this._setSelected('wizard');

      this.panels.active('wizard');
      this.trigger('enable', 'wizard');

      return false;
    },

    enableEditor: function(ev) {
      ev.preventDefault();

      // Add - Remove selected class
      this.active = 'carto';
      this._setSelected('editor');

      this.panels.active('editor');
      this.trigger('enable', 'carto');

      return false;
    },

    _setSelected: function(name) {
      // Add - Remove selected class
      this.$el.find("nav > a").removeClass("selected");
      this.$("nav > a." + name).addClass("selected");
    },

    active: function(name) {
      if(name == 'carto') {
        this.enableEditor();
      } else {
        this.enableWizard()
      }
    },

    _showDoc: function(ev) {
      ev.preventDefault();
      var dialog = new cdb.admin.CartoCSSInfo();
      $("body").append(dialog.render().el);
      dialog.open();
    }

  });

}());
<|endoftext|>


<commit_before>// @flow
import React, { Component } from 'react'
import Drawer from 'material-ui/Drawer'
import { connect } from 'react-redux'
import { isInsertMode } from 'ory-editor-core/lib/selector/display'
import { createStructuredSelector } from 'reselect'
import { Editor } from 'ory-editor-core/lib'
import List from 'material-ui/List/List'
import ListItem from 'material-ui/List/ListItem'
import Subheader from 'material-ui/Subheader'
import Toggle from 'material-ui/Toggle'
import Divider from 'material-ui/Divider'
import TextField from 'material-ui/TextField'
import { LayoutPlugin, ContentPlugin } from 'ory-editor-core/lib/service/plugin/classes'
import Item from './Item'
import Provider from '../Provider'

type Props = {
  isInsertMode: boolean,
  editor: Editor
}

class Raw extends Component {
  constructor(props: Props) {
    super(props)
    this.state = {
      searchFilter: (a: any) => (a),
      isSearching: false
    }

    this.onSearch = this.onSearch.bind(this)
  }

  state: {
    searchFilter: Function,
    isSearching: boolean
  }

  componentDidUpdate() {
    const input = this.input
    if (input && this.props.isInsertMode && input instanceof HTMLElement) {
      setTimeout(() => {
        const e = input.querySelector('input')
        if (e) {
          e.focus()
        }
      }, 100)
    }
  }

  input: Component<*, *, *>

  onRef = (component: Component<*, *, *>) => {
    this.input = component
  }

  onSearch = (e: Event) => {
    const target = e.target
    if (target instanceof HTMLInputElement) {
      this.setState({
        searchFilter: ((v: any) => ({ text = '' }: Object) => text.toLowerCase().indexOf(v) > -1)(target.value.toLowerCase()),
        isSearching: target.value.length > 0
      })
    }
  }

  render() {
    const { isInsertMode, editor: { plugins } } = this.props
    const { isSearching, searchFilter } = this.state
    const content = plugins.plugins.content.filter(searchFilter)
    const layout = plugins.plugins.layout.filter(searchFilter)

    return (
      <Drawer open={isInsertMode}>
        <Subheader>Content</Subheader>

          <TextField
            hintText="Search anything"
            fullWidth
            onChange={this.onSearch}
          />

        <List>
          {content.length ? <Subheader>Content</Subheader> : null}
          {content.map((plugin: ContentPlugin, k: Number) => {
            const initialState = plugin.createInitialState()

            return (
              <Item
                plugin={plugin}
                key={k}
                insert={{
                  content: {
                    plugin,
                    state: initialState
                  }
                }}
              />
            )
          })}
        </List>
        <List>
          {layout.length ? <Subheader>Layout</Subheader> : null}
          {layout.map((plugin: LayoutPlugin, k: Number) => {
            const initialState = plugin.createInitialState()
            const children = plugin.createInitialChildren()

            return (
              <Item
                plugin={plugin}
                key={k}
                insert={{
                  ...children,
                  layout: {
                    plugin,
                    state: initialState
                  }
                }}
              />
            )
          })}
        </List>
      </Drawer>
    )
  }
}

const mapStateToProps = createStructuredSelector({ isInsertMode })

const Decorated = connect(mapStateToProps)(Raw)

const Toolbar = (props: any) => (
  <Provider {...props}>
    <Decorated {...props} />
  </Provider>
)

export default Toolbar
<commit_msg>ui: remove unused imports<commit_after>// @flow
import React, { Component } from 'react'
import Drawer from 'material-ui/Drawer'
import { connect } from 'react-redux'
import { isInsertMode } from 'ory-editor-core/lib/selector/display'
import { createStructuredSelector } from 'reselect'
import { Editor } from 'ory-editor-core/lib'
import List from 'material-ui/List/List'
import Subheader from 'material-ui/Subheader'
import TextField from 'material-ui/TextField'
import { LayoutPlugin, ContentPlugin } from 'ory-editor-core/lib/service/plugin/classes'
import Item from './Item'
import Provider from '../Provider'

type Props = {
  isInsertMode: boolean,
  editor: Editor
}

class Raw extends Component {
  constructor(props: Props) {
    super(props)
    this.state = {
      searchFilter: (a: any) => (a),
      isSearching: false
    }

    this.onSearch = this.onSearch.bind(this)
  }

  state: {
    searchFilter: Function,
    isSearching: boolean
  }

  componentDidUpdate() {
    const input = this.input
    if (input && this.props.isInsertMode && input instanceof HTMLElement) {
      setTimeout(() => {
        const e = input.querySelector('input')
        if (e) {
          e.focus()
        }
      }, 100)
    }
  }

  input: Component<*, *, *>

  onRef = (component: Component<*, *, *>) => {
    this.input = component
  }

  onSearch = (e: Event) => {
    const target = e.target
    if (target instanceof HTMLInputElement) {
      this.setState({
        searchFilter: ((v: any) => ({ text = '' }: Object) => text.toLowerCase().indexOf(v) > -1)(target.value.toLowerCase()),
        isSearching: target.value.length > 0
      })
    }
  }

  render() {
    const { isInsertMode, editor: { plugins } } = this.props
    const { isSearching, searchFilter } = this.state
    const content = plugins.plugins.content.filter(searchFilter)
    const layout = plugins.plugins.layout.filter(searchFilter)

    return (
      <Drawer open={isInsertMode}>
        <Subheader>Content</Subheader>

          <TextField
            hintText="Search anything"
            fullWidth
            onChange={this.onSearch}
          />

        <List>
          {content.length ? <Subheader>Content</Subheader> : null}
          {content.map((plugin: ContentPlugin, k: Number) => {
            const initialState = plugin.createInitialState()

            return (
              <Item
                plugin={plugin}
                key={k}
                insert={{
                  content: {
                    plugin,
                    state: initialState
                  }
                }}
              />
            )
          })}
        </List>
        <List>
          {layout.length ? <Subheader>Layout</Subheader> : null}
          {layout.map((plugin: LayoutPlugin, k: Number) => {
            const initialState = plugin.createInitialState()
            const children = plugin.createInitialChildren()

            return (
              <Item
                plugin={plugin}
                key={k}
                insert={{
                  ...children,
                  layout: {
                    plugin,
                    state: initialState
                  }
                }}
              />
            )
          })}
        </List>
      </Drawer>
    )
  }
}

const mapStateToProps = createStructuredSelector({ isInsertMode })

const Decorated = connect(mapStateToProps)(Raw)

const Toolbar = (props: any) => (
  <Provider {...props}>
    <Decorated {...props} />
  </Provider>
)

export default Toolbar
<|endoftext|>


<commit_before>/**
 * logdown - Debug utility with markdown support that runs on browser and server
 *
 * @version v1.5.0
 * @link https://github.com/caiogondim/logdown
 * @author Caio Gondim <me@caiogondim.com> (http://caiogondim.com)
 * @license MIT
 */
!function(){"use strict";function e(o){if(!(this instanceof e))return new e(o);o=o||{};var n=void 0===o.prefix?"":o.prefix;return n=p(n),n&&s(n,g)?u(n,g):(this.alignOutput=Boolean(o.alignOutput),this.markdown=void 0===o.markdown||o.markdown,this.prefix=n,g.push(this),r(g),d()?(this.prefixColor=x[h%x.length],h+=1):f()&&(this.prefixColor=v()),this)}function r(e){var r=e.sort(function(e,r){return r.prefix.length-e.prefix.length})[0];e.forEach(function(e){if(e.alignOutput){var o=new Array(Math.max(r.prefix.length-e.prefix.length+1,0)).join(" ");e.prefix=e.prefix+o}})}function o(e){for(var r=[],o=n(e);o;)e=e.replace(o.rule.regexp,o.rule.replacer),d()&&(r.push(o.rule.style),r.push("")),o=n(e);return{text:e,styles:r}}function n(e){var r=[],o=[];return d()?o=[{regexp:/\*([^\*]+)\*/,replacer:function(e,r){return"%c"+r+"%c"},style:"font-weight:bold;"},{regexp:/_([^_]+)_/,replacer:function(e,r){return"%c"+r+"%c"},style:"font-style:italic;"},{regexp:/`([^`]+)`/,replacer:function(e,r){return"%c"+r+"%c"},style:"background:#FDF6E3; color:#586E75; padding:1px 5px; border-radius:4px;"}]:f()&&(o=[{regexp:/\*([^\*]+)\*/,replacer:function(e,r){return"["+m.modifiers.bold[0]+"m"+r+"["+m.modifiers.bold[1]+"m"}},{regexp:/_([^_]+)_/,replacer:function(e,r){return"["+m.modifiers.italic[0]+"m"+r+"["+m.modifiers.italic[1]+"m"}},{regexp:/`([^`]+)`/,replacer:function(e,r){return"["+m.bgColors.bgYellow[0]+"m["+m.colors.black[0]+"m "+r+" ["+m.colors.black[1]+"m["+m.bgColors.bgYellow[1]+"m"}}]),o.forEach(function(o){var n=e.match(o.regexp);n&&r.push({rule:o,match:n})}),0===r.length?null:(r.sort(function(e,r){return e.match.index-r.match.index}),r[0])}function t(e,r){var n,t=[];return r.prefix?a()?(t.push("%c"+r.prefix+"%c "),t.push("color:"+r.prefixColor+"; font-weight:bold;","")):t.push("["+r.prefix+"] "):t.push(""),"string"==typeof e[0]?r.markdown&&a()?(n=o(e[0]),t[0]=t[0]+n.text,t=t.concat(n.styles)):t[0]=t[0]+e[0]:t[0]=e[0],e.length>1&&(t=t.concat(e.splice(1))),t}function i(e,r,n){var t=[];return n.prefix&&(a()?t[0]="["+n.prefixColor[0]+"m["+m.modifiers.bold[0]+"m"+n.prefix+"["+m.modifiers.bold[1]+"m["+n.prefixColor[1]+"m":t[0]="["+n.prefix+"]"),"warn"===r?t[0]="["+m.colors.yellow[0]+"m⚠["+m.colors.yellow[1]+"m "+(t[0]||""):"error"===r?t[0]="["+m.colors.red[0]+"m✖["+m.colors.red[1]+"m "+(t[0]||""):"info"===r?t[0]="["+m.colors.blue[0]+"mℹ["+m.colors.blue[1]+"m "+(t[0]||""):"debug"===r&&(t[0]="["+m.colors.gray[0]+"m🐛["+m.colors.gray[1]+"m "+(t[0]||"")),e.forEach(function(e){"string"==typeof e&&n.markdown?t.push(o(e).text):t.push(e)}),t}function c(r){var o=null;"undefined"!=typeof process&&void 0!==process.env&&0===b.length&&(void 0!==process.env.NODE_DEBUG&&""!==process.env.NODE_DEBUG?o="NODE_DEBUG":void 0!==process.env.DEBUG&&""!==process.env.DEBUG&&(o="DEBUG"),o&&(e.disable("*"),process.env[o].split(",").forEach(function(r){e.enable(r)})));var n=!1;return b.forEach(function(e){"enable"===e.type&&e.regExp.test(r.prefix)?n=!1:"disable"===e.type&&e.regExp.test(r.prefix)&&(n=!0)}),n}function l(e){return new RegExp("^"+e.replace(/\*/g,".*?")+"$")}function s(e,r){var o=!1;return r.forEach(function(r){if(r.prefix===e)return void(o=!0)}),o}function u(e,r){var o;return r.forEach(function(r){if(r.prefix===e)return void(o=r)}),o}function p(e){return"string"==typeof e?e.replace(/%c/g,""):e}function a(){if(d()){var e="WebkitAppearance"in document.documentElement.style,r=window.console&&(console.firebug||console.exception&&console.table),o=navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31;return e||r||o}if(f())return!(process.stdout&&!process.stdout.isTTY)&&("win32"===process.platform||("COLORTERM"in process.env||"dumb"!==process.env.TERM&&!!/^screen|^xterm|^vt100|color|ansi|cygwin|linux/i.test(process.env.TERM)))}function f(){return"undefined"!=typeof module&&"undefined"!=typeof module.exports}function d(){return"undefined"!=typeof window}var g=[],h=0,x=["#B58900","#CB4B16","#DC322F","#D33682","#6C71C4","#268BD2","#2AA198","#859900"],m={modifiers:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},colors:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],gray:[90,39]},bgColors:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49]}},b=[];e.enable=function(){Array.prototype.forEach.call(arguments,function(r){"-"===r[0]&&e.disable(r.substr(1));var o=l(r);"*"===r?b=[]:b.push({type:"enable",regExp:o})})},e.disable=function(){Array.prototype.forEach.call(arguments,function(r){"-"===r[0]&&e.enable(r.substr(1));var o=l(r);"*"===r?b=[{type:"disable",regExp:o}]:b.push({type:"disable",regExp:o})})};var y=["debug","log","info","warn","error"];y.forEach(function(r){e.prototype[r]=function(){if(!c(this)){var e,o=Array.prototype.slice.call(arguments,0);d()?(e=t(o,this),Function.prototype.apply.call(console[r]||console.log,console,e)):f()&&(e=i(o,r,this),(console[r]||console.log).apply(console,e))}}});var v=function(){var e=0,r=[[31,39],[32,39],[33,39],[34,39],[35,39],[36,39]];return function(){return r[(e+=1)%r.length]}}();f()?module.exports=e:d()&&(window.Logdown=e)}();<commit_msg>Removed old dist file<commit_after><|endoftext|>


<commit_before>import Vue from 'vue'
import App from './App'
import router from './router'

import Buefy from '../src'
import VueResource from 'vue-resource'
import VueProgressBar from 'vue-progressbar'
import VueAnalytics from 'vue-analytics'
import Bluebird from 'bluebird'
import hljs from 'highlight.js'

Vue.config.productionTip = false

global.Promise = Bluebird

Vue.use(Buefy)
Vue.use(VueResource)
Vue.use(VueProgressBar, {
    color: '#7957d5',
    failedColor: '#ff3860',
    transition: {
        speed: '0.2s',
        opacity: '0.1s'
    }
})
Vue.use(VueAnalytics, {
    id: 'UA-75199408-3',
    router
})

Vue.directive('highlight', {
    deep: true,
    bind(el, binding) {
        // on first bind, highlight all targets
        const targets = el.querySelectorAll('code')
        for (const target of Array.from(targets)) {
            // if a value is directly assigned to the directive, use this
            // instead of the element content.
            if (binding.value) {
                target.innerHTML = binding.value
            }
            hljs.highlightBlock(target)
        }
    },
    componentUpdated(el, binding) {
        // after an update, re-fill the content and then highlight
        const targets = el.querySelectorAll('code')
        for (const target of Array.from(targets)) {
            if (binding.value) {
                target.innerHTML = binding.value
                hljs.highlightBlock(target)
            }
        }
    }
})

Vue.filter('pre', (text) => {
    if (!text) return

    // Remove first blank line
    text = text.replace(/^\s*[\r\n]/g, '')

    // Find how many whitespaces before the first character of the first line
    const whitespaces = /^[ \t]*./.exec(text).toString().slice(0, -1)

    // Replace first occurrance of whitespace on each line
    let newText = []
    text.split(/\r\n|\r|\n/).forEach((line) => {
        newText.push(line.replace(whitespaces, ''))
    })
    newText = newText.join('\r\n')

    return newText
})

new Vue({
    el: '#app',
    router,
    template: '<App/>',
    components: { App }
})
<commit_msg>Fix issue with highlight.js after update<commit_after>import Vue from 'vue'
import App from './App'
import router from './router'

import Buefy from '../src'
import VueResource from 'vue-resource'
import VueProgressBar from 'vue-progressbar'
import VueAnalytics from 'vue-analytics'
import Bluebird from 'bluebird'
import hljs from 'highlight.js'

Vue.config.productionTip = false

global.Promise = Bluebird

Vue.use(Buefy)
Vue.use(VueResource)
Vue.use(VueProgressBar, {
    color: '#7957d5',
    failedColor: '#ff3860',
    transition: {
        speed: '0.2s',
        opacity: '0.1s'
    }
})
Vue.use(VueAnalytics, {
    id: 'UA-75199408-3',
    router
})

Vue.directive('highlight', {
    deep: true,
    bind(el, binding) {
        // On first bind, highlight all targets
        const targets = el.querySelectorAll('code')
        for (const target of targets) {
            // if a value is directly assigned to the directive, use this
            // instead of the element content.
            if (binding.value) {
                target.innerHTML = binding.value
            }
            hljs.highlightBlock(target)
        }
    },
    componentUpdated(el, binding) {
        // After an update, re-fill the content and then highlight
        const targets = el.querySelectorAll('code')
        for (const target of targets) {
            if (binding.value) {
                target.innerHTML = binding.value
                hljs.highlightBlock(target)
            }
        }
    }
})

Vue.filter('pre', (text) => {
    if (!text) return

    // Remove first blank line
    text = text.replace(/^\s*[\r\n]/g, '')

    // Find how many whitespaces before the first character of the first line
    const whitespaces = /^[ \t]*./.exec(text).toString().slice(0, -1)

    // Replace first occurrance of whitespace on each line
    let newText = []
    text.split(/\r\n|\r|\n/).forEach((line) => {
        newText.push(line.replace(whitespaces, ''))
    })
    newText = newText.join('\r\n')

    return newText
})

new Vue({
    el: '#app',
    router,
    template: '<App/>',
    components: { App }
})
<|endoftext|>


<commit_before>const wd = require('wd');
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const logging = require('./logging');
const capsConfig = require('./caps');
const serverConfig = require('./server');
const testDefinitions = require('../e2e-specs');

chai.use(chaiAsPromised);
chaiAsPromised.transferPromiseness = wd.transferPromiseness;
global.should = chai.should();

describe('Advanced HTTP e2e test suite', function () {
  const isSauceLabs = !!process.env.SAUCE_USERNAME;
  const isVerbose = process.argv.includes('--verbose');
  const isDevice = process.argv.includes('--device');
  const isAndroid = process.argv.includes('--android');

  const targetInfo = { isSauceLabs, isDevice, isAndroid };
  const environment = isSauceLabs ? 'saucelabs' : 'local';

  let driver;
  let allPassed = true;

  this.timeout(15000);
  this.slow(4000);

  before(async function () {
    driver = await wd.promiseChainRemote(serverConfig.getServer(environment));

    if (isVerbose) {
      logging.setupLogging(driver);
    }

    await driver.init(
      capsConfig.getCaps(
        environment,
        isAndroid ? 'android' : 'ios',
        isDevice ? 'device' : 'emulator'
      )
    );
  });

  after(async function () {
    await driver.quit().finally(
      () => isSauceLabs && driver.sauceJobStatus(allPassed)
    );
  });

  const defineTestForMocha = (test, index) => {
    it(index + ': ' + test.description, async () => {
      await clickNext(driver);
      await validateTestIndex(driver, index);
      await validateTestTitle(driver, test.description);
      await waitToBeFinished(driver, test.timeout || 10000);
      await validateResult(driver, test.validationFunc, targetInfo);
    });
  };

  const onlyFlaggedTests = [];
  const enabledTests = [];

  testDefinitions.tests.forEach(test => {
    if (test.only) {
      onlyFlaggedTests.push(test);
    }

    if (!test.disabled) {
      enabledTests.push(test);
    }
  });

  if (onlyFlaggedTests.length) {
    onlyFlaggedTests.forEach(defineTestForMocha);
  } else {
    enabledTests.forEach(defineTestForMocha);
  }
});

async function clickNext(driver) {
  await driver.elementById('nextBtn').click().sleep(1000);
}

async function validateTestIndex(driver, testIndex) {
  const description = await driver.elementById('descriptionLbl').text();
  const index = parseInt(description.match(/(\d+):/)[1], 10);

  index.should.be.equal(testIndex, 'Test index is not matching!');
}

async function validateTestTitle(driver, testTitle) {
  const description = await driver.elementById('descriptionLbl').text();
  const title = description.match(/\d+:\ (.*)/)[1];

  title.should.be.equal(testTitle, 'Test description is not matching!');
}

async function waitToBeFinished(driver, timeout) {
  const timeoutTimestamp = Date.now() + timeout;

  while (true) {
    if (await driver.elementById('statusInput').getValue() === 'finished') {
      return true;
    }

    if (Date.now() > timeoutTimestamp) {
      throw new Error('Test function timed out!');
    }

    await sleep(500);
  }
}

async function validateResult(driver, validationFunc, targetInfo) {
  const result = await driver.safeExecute('app.lastResult');
  validationFunc(driver, result, targetInfo);
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
<commit_msg>chore: update mocha timeout values<commit_after>const wd = require('wd');
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const logging = require('./logging');
const capsConfig = require('./caps');
const serverConfig = require('./server');
const testDefinitions = require('../e2e-specs');

chai.use(chaiAsPromised);
chaiAsPromised.transferPromiseness = wd.transferPromiseness;
global.should = chai.should();

describe('Advanced HTTP e2e test suite', function () {
  const isSauceLabs = !!process.env.SAUCE_USERNAME;
  const isVerbose = process.argv.includes('--verbose');
  const isDevice = process.argv.includes('--device');
  const isAndroid = process.argv.includes('--android');

  const targetInfo = { isSauceLabs, isDevice, isAndroid };
  const environment = isSauceLabs ? 'saucelabs' : 'local';

  let driver;
  let allPassed = true;

  this.timeout(15000);
  this.slow(4000);

  before(async function () {
    // connecting to saucelabs can take some time
    this.timeout(300000);

    driver = await wd.promiseChainRemote(serverConfig.getServer(environment));

    if (isVerbose) {
      logging.setupLogging(driver);
    }

    await driver.init(
      capsConfig.getCaps(
        environment,
        isAndroid ? 'android' : 'ios',
        isDevice ? 'device' : 'emulator'
      )
    );
  });

  after(async function () {
    await driver.quit().finally(
      () => isSauceLabs && driver.sauceJobStatus(allPassed)
    );
  });

  const defineTestForMocha = (test, index) => {
    it(index + ': ' + test.description, async () => {
      await clickNext(driver);
      await validateTestIndex(driver, index);
      await validateTestTitle(driver, test.description);
      await waitToBeFinished(driver, test.timeout || 10000);
      await validateResult(driver, test.validationFunc, targetInfo);
    });
  };

  const onlyFlaggedTests = [];
  const enabledTests = [];

  testDefinitions.tests.forEach(test => {
    if (test.only) {
      onlyFlaggedTests.push(test);
    }

    if (!test.disabled) {
      enabledTests.push(test);
    }
  });

  if (onlyFlaggedTests.length) {
    onlyFlaggedTests.forEach(defineTestForMocha);
  } else {
    enabledTests.forEach(defineTestForMocha);
  }
});

async function clickNext(driver) {
  await driver.elementById('nextBtn').click().sleep(1000);
}

async function validateTestIndex(driver, testIndex) {
  const description = await driver.elementById('descriptionLbl').text();
  const index = parseInt(description.match(/(\d+):/)[1], 10);

  index.should.be.equal(testIndex, 'Test index is not matching!');
}

async function validateTestTitle(driver, testTitle) {
  const description = await driver.elementById('descriptionLbl').text();
  const title = description.match(/\d+:\ (.*)/)[1];

  title.should.be.equal(testTitle, 'Test description is not matching!');
}

async function waitToBeFinished(driver, timeout) {
  const timeoutTimestamp = Date.now() + timeout;

  while (true) {
    if (await driver.elementById('statusInput').getValue() === 'finished') {
      return true;
    }

    if (Date.now() > timeoutTimestamp) {
      throw new Error('Test function timed out!');
    }

    await sleep(500);
  }
}

async function validateResult(driver, validationFunc, targetInfo) {
  const result = await driver.safeExecute('app.lastResult');
  validationFunc(driver, result, targetInfo);
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
<|endoftext|>


<commit_before>import '/imports/startup/client';
import '/imports/startup/both';
import '/imports/api/items/beach';
import '/imports/ui/layouts';
import '/imports/ui/layouts/items';
import '/imports/ui/pages';
import '/imports/ui/stylesheets/style.css';

import '/imports/ui/pages/admin';
import '/imports/ui/pages/items';
import '/imports/ui/pages/landing';
import '/imports/ui/pages/user';
import '/imports/ui/pages/misc';

<<<<<<< HEAD
<<<<<<< HEAD
import '/imports/ui/components/items';
import '/imports/ui/components/form-controls';
<<<<<<< HEAD
=======
=======
>>>>>>> origin/master
import '/imports/api/profiles';

import '/imports/ui/components/items';
/* import the CAS landing authentication */
import '/imports/ui/components/landing';
<<<<<<< HEAD
>>>>>>> origin/master
=======
>>>>>>> origin/master
=======
>>>>>>> issue-17-redo
<commit_msg>Fixed client/main.js again<commit_after>import '/imports/startup/client';
import '/imports/startup/both';
import '/imports/api/items/beach';
import '/imports/ui/layouts';
import '/imports/ui/layouts/items';
import '/imports/ui/pages';
import '/imports/ui/stylesheets/style.css';

import '/imports/ui/pages/admin';
import '/imports/ui/pages/items';
import '/imports/ui/pages/landing';
import '/imports/ui/pages/user';
import '/imports/ui/pages/misc';
import '/imports/ui/components/items';
import '/imports/ui/components/form-controls';
import '/imports/api/profiles';
/* import the CAS landing authentication */
import '/imports/ui/components/landing';
<|endoftext|>


<commit_before>"use strict";

var httpProxy  = require("http-proxy");
var utils      = require("./utils");
var proxyUtils = require("./proxy-utils");
var Immutable  = require("immutable");
var Map        = require("immutable").Map;
var List       = require("immutable").List;

/**
 * Default options that are passed along to http-proxy
 */
var defaultHttpProxyOptions = Map({
    /**
     * This ensures targets are more likely to
     * accept each request
     */
    changeOrigin: true,
    /**
     * This handles redirects
     */
    autoRewrite: true,
    /**
     * This allows our self-signed certs to be used for development
     */
    secure: false,
    ws: true
});

var defaultCookieOptions = Map({
    stripDomain: true
});

var ProxyOption = Immutable.Record({
    route: "",
    target: "",
    rewriteRules: true,
    /**
     * Functions to be called on proxy request
     * with args [proxyReq, req, res, options]
     */
    proxyReq:     List([]),
    /**
     * Functions to be called on proxy response
     * with args [proxyRes, req, res]
     */
    proxyRes:     List([]),
    /**
     * Functions to be called on proxy response
     * with args [proxyReq, req, socket, options, head]
     */
    proxyReqWs:   List([]),
    errHandler:   undefined,
    url:          Map({}),
    proxyOptions: Map(defaultHttpProxyOptions),
    cookies:      Map(defaultCookieOptions),
    ws:           false,
    middleware:   List([]),
    reqHeaders:   undefined
});

/**
 * @param {BrowserSync} bs
 * @param {String} scripts
 * @returns {*}
 */
module.exports = function createProxyServer (bs, scripts) {

    var opt         = new ProxyOption().mergeDeep(bs.options.get("proxy"));
    var proxy       = httpProxy.createProxyServer(opt.get("proxyOptions").set("target", opt.get("target")).toJS());
    var target      = opt.get("target");
    var proxyReq    = getProxyReqFunctions(opt.get("proxyReq"), opt, bs);
    var proxyRes    = getProxyResFunctions(opt.get("proxyRes"), opt);

    /**
     * Add the proxy middleware to any given by the user
     */
    var middlewareAdded = bs.options
        .update("middleware", function (mw) {
            return mw.concat({
                id: "Browsersync Proxy",
                route: opt.get("route"),
                handle: function (req, res) {
                    proxy.web(req, res, {
                        target: target
                    });
                }
            })
        });

    var app  = utils.getBaseApp(bs, middlewareAdded, scripts);

    /**
     * @type {*|{server, app}}
     */
    var browserSyncServer = utils.getServer(app, bs.options);
    browserSyncServer.proxy = proxy;

    if (opt.get("ws")) {
        // debug(`+ ws upgrade for: ${x.get("target")}`);
        browserSyncServer.server.on("upgrade", function (req, socket, head) {
            proxy.ws(req, socket, head);
        });
    }

    /**
     * Add any user provided functions for proxyReq, proxyReqWs and proxyRes
     */
    applyFns("proxyReq", proxyReq);
    applyFns("proxyRes", proxyRes);
    applyFns("proxyReqWs", opt.get("proxyReqWs"))

    /**
     * Handle Proxy errors
     */
    proxy.on("error", function (err) {
        if (typeof opt.get("errHandler") === "function") {
            opt.get("errHandler").call(null, err);
        }
    });

    /**
     * Apply functions to proxy events
     * @param {string} name - the name of the http-proxy event
     * @param {Array} fns - functions to call on each event
     */
    function applyFns (name, fns) {
        if (!List.isList(fns)) fns = [fns];
        proxy.on(name, function () {
            var args = arguments;
            fns.forEach(function(fn) {
                if (typeof fn === "function") {
                    fn.apply(null, args);
                }
            });
        });
    }

    return browserSyncServer;
};

/**
 * @param resFns
 * @returns {*}
 */
function getProxyResFunctions (resFns, opt) {
    if (opt.getIn(["cookies", "stripDomain"])) {
        return resFns.push(proxyUtils.checkCookies);
    }
    return resFns;
}

/**
 * @param reqFns
 * @returns {*}
 */
function getProxyReqFunctions (reqFns, opt, bs) {

    var reqHeaders = opt.getIn(["reqHeaders"]);

    if (!reqHeaders) {
        return reqFns;
    }

    /**
     * Back-compat for old `reqHeaders` option here a
     * function was given that returned an object
     * where key:value was header-name:header-value
     * This didn't really work as it clobbered all other headers,
     * but it remains for the unlucky few who used it.
     */
    if (typeof reqHeaders === "function") {
        var output = reqHeaders.call(bs, opt.toJS());
        if (Object.keys(output).length) {
            return reqFns.concat(function (proxyReq) {
                Object.keys(output).forEach(function (key) {
                    proxyReq.setHeader(key, output[key]);
                });
            });
        }
    }

    /**
     * Now, if {key:value} given, set the each header
     *
     * eg: reqHeaders: {
     *     'is-dev': 'true'
     * }
     */
    if (Map.isMap(reqHeaders)) {
        return reqFns.concat(function (proxyReq) {
            reqHeaders.forEach(function (value, key) {
                proxyReq.setHeader(key, value);
            });
        });
    }

    return reqFns;
}
<commit_msg>chore: code style<commit_after>"use strict";

var httpProxy  = require("http-proxy");
var utils      = require("./utils");
var proxyUtils = require("./proxy-utils");
var Immutable  = require("immutable");
var Map        = require("immutable").Map;
var List       = require("immutable").List;

/**
 * Default options that are passed along to http-proxy
 */
var defaultHttpProxyOptions = Map({
    /**
     * This ensures targets are more likely to
     * accept each request
     */
    changeOrigin: true,
    /**
     * This handles redirects
     */
    autoRewrite: true,
    /**
     * This allows our self-signed certs to be used for development
     */
    secure: false,
    ws: true
});

var defaultCookieOptions = Map({
    stripDomain: true
});

var ProxyOption = Immutable.Record({
    route: "",
    target: "",
    rewriteRules: true,
    /**
     * Functions to be called on proxy request
     * with args [proxyReq, req, res, options]
     */
    proxyReq:     List([]),
    /**
     * Functions to be called on proxy response
     * with args [proxyRes, req, res]
     */
    proxyRes:     List([]),
    /**
     * Functions to be called on proxy response
     * with args [proxyReq, req, socket, options, head]
     */
    proxyReqWs:   List([]),
    errHandler:   undefined,
    url:          Map({}),
    proxyOptions: Map(defaultHttpProxyOptions),
    cookies:      Map(defaultCookieOptions),
    ws:           false,
    middleware:   List([]),
    reqHeaders:   undefined
});

/**
 * @param {BrowserSync} bs
 * @param {String} scripts
 * @returns {*}
 */
module.exports = function createProxyServer (bs, scripts) {

    var opt         = new ProxyOption().mergeDeep(bs.options.get("proxy"));
    var proxy       = httpProxy.createProxyServer(opt.get("proxyOptions").set("target", opt.get("target")).toJS());
    var target      = opt.get("target");
    var proxyReq    = getProxyReqFunctions(opt.get("proxyReq"), opt, bs);
    var proxyRes    = getProxyResFunctions(opt.get("proxyRes"), opt);
    var proxyResWs  = opt.get("proxyReqWs");

    /**
     * Add the proxy middleware to any given by the user
     */
    var middlewareAdded = bs.options
        .update("middleware", function (mw) {
            return mw.concat({
                id: "Browsersync Proxy",
                route: opt.get("route"),
                handle: function (req, res) {
                    proxy.web(req, res, {
                        target: target
                    });
                }
            })
        });

    var app  = utils.getBaseApp(bs, middlewareAdded, scripts);

    /**
     * @type {*|{server, app}}
     */
    var browserSyncServer = utils.getServer(app, bs.options);
    browserSyncServer.proxy = proxy;

    if (opt.get("ws")) {
        // debug(`+ ws upgrade for: ${x.get("target")}`);
        browserSyncServer.server.on("upgrade", function (req, socket, head) {
            proxy.ws(req, socket, head);
        });
    }

    /**
     * Add any user provided functions for proxyReq, proxyReqWs and proxyRes
     */
    applyFns("proxyReq",   proxyReq);
    applyFns("proxyRes",   proxyRes);
    applyFns("proxyReqWs", proxyResWs);

    /**
     * Handle Proxy errors
     */
    proxy.on("error", function (err) {
        if (typeof opt.get("errHandler") === "function") {
            opt.get("errHandler").call(null, err);
        }
    });

    /**
     * Apply functions to proxy events
     * @param {string} name - the name of the http-proxy event
     * @param {Array} fns - functions to call on each event
     */
    function applyFns (name, fns) {
        if (!List.isList(fns)) fns = [fns];
        proxy.on(name, function () {
            var args = arguments;
            fns.forEach(function(fn) {
                if (typeof fn === "function") {
                    fn.apply(null, args);
                }
            });
        });
    }

    return browserSyncServer;
};

/**
 * @param resFns
 * @returns {*}
 */
function getProxyResFunctions (resFns, opt) {
    if (opt.getIn(["cookies", "stripDomain"])) {
        return resFns.push(proxyUtils.checkCookies);
    }
    return resFns;
}

/**
 * @param reqFns
 * @returns {*}
 */
function getProxyReqFunctions (reqFns, opt, bs) {

    var reqHeaders = opt.getIn(["reqHeaders"]);

    if (!reqHeaders) {
        return reqFns;
    }

    /**
     * Back-compat for old `reqHeaders` option here a
     * function was given that returned an object
     * where key:value was header-name:header-value
     * This didn't really work as it clobbered all other headers,
     * but it remains for the unlucky few who used it.
     */
    if (typeof reqHeaders === "function") {
        var output = reqHeaders.call(bs, opt.toJS());
        if (Object.keys(output).length) {
            return reqFns.concat(function (proxyReq) {
                Object.keys(output).forEach(function (key) {
                    proxyReq.setHeader(key, output[key]);
                });
            });
        }
    }

    /**
     * Now, if {key:value} given, set the each header
     *
     * eg: reqHeaders: {
     *     'is-dev': 'true'
     * }
     */
    if (Map.isMap(reqHeaders)) {
        return reqFns.concat(function (proxyReq) {
            reqHeaders.forEach(function (value, key) {
                proxyReq.setHeader(key, value);
            });
        });
    }

    return reqFns;
}
<|endoftext|>


<commit_before>(function() {
    "use strict";

    angular.module("blocktrail.wallet")
        .controller("SendCtrl", SendCtrl);

    function SendCtrl($scope, $state, $rootScope, $translate, $log, $modal, bitcoinJS, CurrencyConverter, Currencies, activeWallet,
                      $timeout, dialogService, $q, launchService, CONFIG, settingsService, $stateParams, walletsManagerService,
                      NotificationsService) {

        var walletData = activeWallet.getReadOnlyWalletData();
        var settingsData = settingsService.getReadOnlySettingsData();
        // get current active wallets native currency
        var nativeCurrency = CONFIG.NETWORKS[walletData.networkType].TICKER;

        var maxSpendable = null;
        var maxSpendablePromise = null;

        $rootScope.pageTitle = "SEND";

        $scope.isLoading = true;

        $scope.settings = settingsData;

        //$scope.fiatFirst = false;
        $scope.OPTIMAL_FEE = "optimal";
        $scope.LOW_PRIORITY_FEE = "low_priority";
        $scope.PRIOBOOST = "prioboost";

        $scope.PRIOBOOST_MAX_SIZE = 1300;
        $scope.prioboost = {
            discountP: null,
            credits: 2,
            possible: null,
            estSize: null,
            tooLarge: false,
            zeroConf: false
        };

        $scope.sendInput = {
            recipientAddress: "",
            referenceMessage: "",
            pin: null,
            amount: "",
            feeChoice: $scope.OPTIMAL_FEE
        };

        $scope.fees = {
            optimal: null,
            lowPriority: null,
            minRelayFee: null
        };

        $scope.errors = {
            amount: false,
            recipient: false
        };

        $scope.complete = false;
        $scope.displayFee = false;
        $scope.useZeroConf = true;

        $scope.requires2FA = null;

        $scope.currencies = null;
        $scope.currencyType = null;
        $scope.altCurrency = {};

        $scope.$on("enabled_currency", function() {
            updateCurrentType($scope.currencyType);
        });

        // Methods
        $scope.updateCurrentType = updateCurrentType;
        $scope.setAltCurrency = setAltCurrency;
        $scope.fetchFee = fetchFee;
        $scope.resetError = resetError;
        $scope.onSubmitFormSend = onSubmitFormSend;

        initData();

        /**
         * Init data
         */
        function initData() {
            // set default BTC
            updateCurrentType(nativeCurrency);

            return launchService.getAccountInfo().then(function (accountInfo) {
                $scope.requires2FA = accountInfo.requires2FA;
                return getMaxSpendable().then(function (data) {
                    var maxSpendable = data[1][blocktrailSDK.Wallet.FEE_STRATEGY_MIN_RELAY_FEE];

                    $scope.prioboost.credits = maxSpendable.prioboost_remaining;
                    $scope.prioboost.discountP = (1 - (maxSpendable.fees.min_relay_fee / maxSpendable.fees.optimal)) * 100;

                    $scope.isLoading = false;
                });
            }).catch(function () {
                $scope.isLoading = false;
            });
        }

        // Fetch state parameters if provided
        handleBitcoinPaymentScheme();
        /**
         * Handle state parameters about bitcoin payment information, if present
         */
        function handleBitcoinPaymentScheme() {

            // Protocol sanity check
            if ($stateParams.protocol === "bitcoin" || $stateParams.protocol === "bitcoincash") {
                $timeout(function () {
                    // Correct wallet for protocol check
                    if ($stateParams.protocol === "bitcoin" && walletData.networkType === "BCC") {
                        return switchWalletByNetworkTypeAndIdentifier('BTC', walletData.identifier);
                    } else if ($stateParams.protocol === "bitcoincash" && walletData.networkType === "BTC") {
                        /*
                         * This is only added here for completions sake - there is no way to register 'bitcoincash:'
                         * URI handlers yet in the majority of browsers
                         */
                        return switchWalletByNetworkTypeAndIdentifier('BCC', walletData.identifier);
                    } else {
                        applyBitcoinURIParams($stateParams.address, $stateParams.amount);
                    }
                });
            } else if ($stateParams.protocol === null) {
                // If it is not set, do not need to complain
            } else {
                throw new Error("Unknown protocol type for payment URL");
            }
        }

        /**
         * Switches the wallet interface based on the network type and identifier
         * @param networkType Network type
         * @param identifier Wallet identifier
         */
        function switchWalletByNetworkTypeAndIdentifier(networkType, identifier) {
            $scope.isLoading = true;
            return walletsManagerService.setActiveWalletByNetworkTypeAndIdentifier(networkType, identifier)
                .then(function () {
                    $state.reload();
                    $scope.isLoading = false;
                });
        }

        /**
         * Applies the amount and address to the input fields for sending coins
         * @param address
         * @param amount
         */
        function applyBitcoinURIParams(address, amount) {
            if (address) {
                activeWallet.validateAddress(address)
                    .then(function (address) {
                        if (address) {
                            $scope.sendInput.recipientAddress = address;
                        }
                    });
            }

            if (amount) {
                amount = parseFloat($stateParams.amount);

                if (amount) {
                    $scope.sendInput.amount = amount;
                }
                // Update fiat price
                setAltCurrency();
            }
        }

        NotificationsService.checkAndPromptBitcoinURIHandler();

        /**
         * Update currency type
         * @param currencyType
         */
        function updateCurrentType(currencyType) {
            $scope.currencies = Currencies.getCurrencies();

            // filter out crypto currencies that are not current
            $scope.currencies = $scope.currencies.filter(function(currency) {
                return currency.isFiat || currency.code === nativeCurrency;
            });

            // filter out selected currency
            $scope.currencies = $scope.currencies.filter(function(currency) {
                return currency.code !== currencyType;
            });

            $scope.currencyType = currencyType;

            setAltCurrency();
        }

        /**
         * Set alt currency
         */
        function setAltCurrency() {
            if ($scope.currencyType === nativeCurrency) {
                $scope.altCurrency.code = $scope.settings.localCurrency;
                $scope.altCurrency.amount = parseFloat(CurrencyConverter.fromBTC($scope.sendInput.amount, $scope.settings.localCurrency, 2)) || 0;
            } else {
                $scope.altCurrency.code = nativeCurrency;
                $scope.altCurrency.amount = parseFloat(CurrencyConverter.toBTC($scope.sendInput.amount, $scope.currencyType, 6)) || 0;
            }
        }

        /**
         * Get max spendable
         * @return {*}
         */
        function getMaxSpendable() {
            if (maxSpendable !== null) {
                return $q.when(maxSpendable);
            } else if (maxSpendablePromise !== null) {
                return maxSpendablePromise;
            } else {
                maxSpendablePromise = $q.all([
                    activeWallet.getSdkWallet().maxSpendable($scope.useZeroConf, blocktrailSDK.Wallet.FEE_STRATEGY_OPTIMAL),
                    activeWallet.getSdkWallet().maxSpendable($scope.useZeroConf, blocktrailSDK.Wallet.FEE_STRATEGY_LOW_PRIORITY),
                    activeWallet.getSdkWallet().maxSpendable($scope.useZeroConf, blocktrailSDK.Wallet.FEE_STRATEGY_MIN_RELAY_FEE)
                ]).then(function(results) {
                    // set the local stored value
                    maxSpendable = {};
                    maxSpendable[blocktrailSDK.Wallet.FEE_STRATEGY_OPTIMAL] = results[0];
                    maxSpendable[blocktrailSDK.Wallet.FEE_STRATEGY_LOW_PRIORITY] = results[1];
                    maxSpendable[blocktrailSDK.Wallet.FEE_STRATEGY_MIN_RELAY_FEE] = results[2];

                    maxSpendablePromise = null; // unset promise, it's done
                    return maxSpendable;
                });

                return maxSpendablePromise;
            }
        }

        /**
         * Fetch fee
         */
        function fetchFee() {
            // reset state
            $scope.fees.lowPriority = null;
            $scope.fees.optimal = null;
            $scope.fees.minRelayFee = null;
            $scope.displayFee = false;
            $scope.prioboost.possible = null;
            $scope.prioboost.estSize = null;
            $scope.prioboost.zeroConf = null;

            var localPay = {};
            var amount = 0;

            if ($scope.currencyType === nativeCurrency) {
                amount = $scope.sendInput.amount;
            } else {
                amount = $scope.altCurrency.amount;
            }

            amount = parseInt(CurrencyConverter.toSatoshi(amount, "BTC"));

            // halt if input is 0
            if (amount <= 0) {
                return $q.reject(new Error("Amount needs to be > 0"));
            }

            // either use the real destination address or otherwise use a fake address
            if ($scope.sendInput.recipientAddress) {
                localPay[$scope.sendInput.recipientAddress] = amount;
            } else {
                var fakeP2SHScript = bitcoinJS.script.scriptHash.output.encode(new blocktrailSDK.Buffer("0000000000000000000000000000000000000000", "hex"));
                var fakeAddress = bitcoinJS.address.fromOutputScript(fakeP2SHScript, activeWallet.getSdkWallet().sdk.network);
                localPay[fakeAddress.toString()] = amount;
            }

            return $q.all([
                activeWallet
                    .getSdkWallet()
                    .coinSelection(localPay, false, $scope.useZeroConf, blocktrailSDK.Wallet.FEE_STRATEGY_LOW_PRIORITY)
                    .spread(function(utxos, fee, change, res) {
                        $log.debug("lowPriority fee: " + fee);

                        return fee;
                    })
                    .catch(function(e) {
                        // when we get a fee error we use maxspendable fee
                        if (e instanceof blocktrail.WalletFeeError || (e instanceof Error && e.message === "Wallet balance too low")) {
                            return getMaxSpendable().then(function(maxSpendable) {
                                var fee = maxSpendable[blocktrailSDK.Wallet.FEE_STRATEGY_LOW_PRIORITY].fee;
                                $log.debug("lowPriority fee MAXSPENDABLE: " + fee);
                                return fee;
                            });
                        } else {
                            throw e;
                        }
                    }),
                activeWallet
                    .getSdkWallet()
                    .coinSelection(localPay, false, $scope.useZeroConf, blocktrailSDK.Wallet.FEE_STRATEGY_OPTIMAL)
                    .spread(function(utxos, fee, change, res) {
                        $log.debug("optimal fee: " + fee);

                        return fee;
                    })
                    .catch(function(e) {
                        // when we get a fee error we use maxspendable fee
                        if (e instanceof blocktrail.WalletFeeError || (e instanceof Error && e.message === "Wallet balance too low")) {
                            return getMaxSpendable()
                                .then(function(maxSpendable) {
                                    var fee = maxSpendable[blocktrailSDK.Wallet.FEE_STRATEGY_OPTIMAL].fee;
                                    $log.debug("optiomal fee MAXSPENDABLE: " + fee);
                                    return fee;
                                });
                        } else {
                            throw e;
                        }
                    }),
                activeWallet
                    .getSdkWallet()
                    .coinSelection(localPay, false, $scope.useZeroConf, blocktrailSDK.Wallet.FEE_STRATEGY_MIN_RELAY_FEE)
                    .spread(function(utxos, fee, change, res) {
                        $log.debug("minRelayFee fee: " + fee);

                        $scope.prioboost.estSize = res.size;
                        $scope.prioboost.credits = res.prioboost_remaining;
                        $scope.prioboost.zeroConf = res.zeroconf;
                        $scope.prioboost.tooLarge = $scope.prioboost.estSize > $scope.PRIOBOOST_MAX_SIZE;
                        $scope.prioboost.possible = !$scope.prioboost.zeroConf && !$scope.prioboost.tooLarge && $scope.prioboost.credits > 0;

                        return fee;
                    })
                    .catch(function(e) {
                        // when we get a fee error we use maxspendable fee
                        if (e instanceof blocktrail.WalletFeeError || (e instanceof Error && e.message === "Wallet balance too low")) {
                            return getMaxSpendable()
                                .then(function(maxSpendable) {
                                    var fee = maxSpendable[blocktrailSDK.Wallet.FEE_STRATEGY_MIN_RELAY_FEE].fee;
                                    $log.debug("minRelayFee fee MAXSPENDABLE: " + fee);
                                    return fee;
                                });
                        } else {
                            throw e;
                        }
                    })
            ])
                .then(function(res) {
                    var lowPriorityFee = res[0];
                    var optimalFee = res[1];
                    var minRelayFee = res[2];

                    $scope.fees.lowPriority = lowPriorityFee;
                    $scope.fees.optimal = optimalFee;
                    $scope.fees.minRelayFee = minRelayFee;
                    $scope.displayFee = true;

                    return updateFee();
                }, function(e) {
                    $log.debug("fetchFee ERR " + e);
                });
        }

        /**
         * Update fee
         */
        function updateFee() {
            if ($scope.sendInput.feeChoice === $scope.OPTIMAL_FEE) {
                $scope.fee = $scope.fees.optimal;
            } else if ($scope.sendInput.feeChoice === $scope.LOW_PRIORITY_FEE) {
                $scope.fee = $scope.fees.lowPriority;
            } else if ($scope.sendInput.feeChoice === $scope.PRIOBOOST) {
                $scope.fee = $scope.fees.minRelayFee;
            } else {
                throw new Error("Invalid");
            }
        }

        /**
         * On submit form send
         */
        function onSubmitFormSend() {
            $scope.isLoading = true;

            return $scope
                .fetchFee()
                .then(validateData)
                .then(
                    function(sendAmount) {
                        $scope.isLoading = false;

                        $modal.open({
                            controller: "SendConfirmModalCtrl",
                            templateUrl: "js/modules/wallet/controllers/send-confirm-modal/send-confirm-modal.tpl.html",
                            size: "md",
                            backdrop: "static",
                            resolve: {
                                activeWallet: function() {
                                    return activeWallet;
                                },
                                sendData: function() {
                                    return {
                                        feeChoice: $scope.sendInput.feeChoice,
                                        recipientAddress: $scope.sendInput.recipientAddress,
                                        amount: sendAmount,
                                        requires2FA: $scope.requires2FA
                                    };
                                }
                            }
                        });
                    },
                    function() {
                        $scope.isLoading = false;
                    });
        }

        /**
         * Validate data
         */
        function validateData() {
            var sendAmount = 0;
            var isValid = true;

            clearErrors();

            if ($scope.sendInput.feeChoice === $scope.PRIOBOOST && $scope.prioboost.possible === false) {
                var body = $scope.prioboost.credits <= 0 ? $translate.instant("PRIOBOOST_NO_CREDITS") : ($scope.prioboost.tooLarge ? $translate.instant("PRIOBOOST_TOO_LARGE") : $translate.instant("PRIOBOOST_ZERO_CONF"));
                var title = $translate.instant("PRIOBOOST_NOT_POSSIBLE");

                dialogService
                    .alert({
                        body: body,
                        title: title
                    });

                isValid = false;
            }

            // input amount
            // https://stackoverflow.com/questions/7810446/regex-validation-of-numeric-with-up-to-4-decimal-places
            if (!$scope.sendInput.amount || !$scope.sendInput.amount.toString().match("^[0-9]*(?:\.[0-9]{0,8})?$")) {
                $scope.errors.amount = "MSG_INVALID_AMOUNT";
                isValid = false;
            }

            if (parseFloat($scope.sendInput.amount).toFixed(8) === "0.00000000") {
                $scope.errors.amount = "MSG_INVALID_AMOUNT";
                isValid = false;
            }

            if ($scope.currencyType === nativeCurrency) {
                sendAmount = $scope.sendInput.amount;
            } else {
                sendAmount = $scope.altCurrency.amount;
            }

            if (parseInt(CurrencyConverter.toSatoshi(sendAmount, "BTC")) >= ($scope.walletData.balance + $scope.walletData.uncBalance)) {
                $scope.errors.amount = "MSG_INSUFFICIENT_FUNDS";
                isValid = false;
            }

            // no send address
            if (!$scope.sendInput.recipientAddress) {
                $scope.errors.recipient = "MSG_MISSING_RECIPIENT";
                isValid = false;
            }

            if (isValid) {
                return activeWallet
                    .validateAddress($scope.sendInput.recipientAddress)
                    .then(function() {
                        return sendAmount;
                    })
                    .catch(function() {
                        $scope.errors.recipient = "MSG_INVALID_RECIPIENT";
                        return $q.reject();
                    });
            } else {
                return $q.reject();
            }
        }

        /**
         * Clear errors
         */
        function clearErrors() {
            $scope.errors.amount = false;
            $scope.errors.recipient = false;
        }

        /**
         * Clear error
         * @param type
         */
        function resetError(type) {
            $scope.errors[type] = false;
        };
    }
})();
<commit_msg>fix array index<commit_after>(function() {
    "use strict";

    angular.module("blocktrail.wallet")
        .controller("SendCtrl", SendCtrl);

    function SendCtrl($scope, $state, $rootScope, $translate, $log, $modal, bitcoinJS, CurrencyConverter, Currencies, activeWallet,
                      $timeout, dialogService, $q, launchService, CONFIG, settingsService, $stateParams, walletsManagerService,
                      NotificationsService) {

        var walletData = activeWallet.getReadOnlyWalletData();
        var settingsData = settingsService.getReadOnlySettingsData();
        // get current active wallets native currency
        var nativeCurrency = CONFIG.NETWORKS[walletData.networkType].TICKER;

        var maxSpendable = null;
        var maxSpendablePromise = null;

        $rootScope.pageTitle = "SEND";

        $scope.isLoading = true;

        $scope.settings = settingsData;

        //$scope.fiatFirst = false;
        $scope.OPTIMAL_FEE = "optimal";
        $scope.LOW_PRIORITY_FEE = "low_priority";
        $scope.PRIOBOOST = "prioboost";

        $scope.PRIOBOOST_MAX_SIZE = 1300;
        $scope.prioboost = {
            discountP: null,
            credits: 2,
            possible: null,
            estSize: null,
            tooLarge: false,
            zeroConf: false
        };

        $scope.sendInput = {
            recipientAddress: "",
            referenceMessage: "",
            pin: null,
            amount: "",
            feeChoice: $scope.OPTIMAL_FEE
        };

        $scope.fees = {
            optimal: null,
            lowPriority: null,
            minRelayFee: null
        };

        $scope.errors = {
            amount: false,
            recipient: false
        };

        $scope.complete = false;
        $scope.displayFee = false;
        $scope.useZeroConf = true;

        $scope.requires2FA = null;

        $scope.currencies = null;
        $scope.currencyType = null;
        $scope.altCurrency = {};

        $scope.$on("enabled_currency", function() {
            updateCurrentType($scope.currencyType);
        });

        // Methods
        $scope.updateCurrentType = updateCurrentType;
        $scope.setAltCurrency = setAltCurrency;
        $scope.fetchFee = fetchFee;
        $scope.resetError = resetError;
        $scope.onSubmitFormSend = onSubmitFormSend;

        initData();

        /**
         * Init data
         */
        function initData() {
            // set default BTC
            updateCurrentType(nativeCurrency);

            return launchService.getAccountInfo().then(function (accountInfo) {
                $scope.requires2FA = accountInfo.requires2FA;
                return getMaxSpendable().then(function (data) {
                    var maxSpendable = data[blocktrailSDK.Wallet.FEE_STRATEGY_MIN_RELAY_FEE];

                    $scope.prioboost.credits = maxSpendable.prioboost_remaining;
                    $scope.prioboost.discountP = (1 - (maxSpendable.fees.min_relay_fee / maxSpendable.fees.optimal)) * 100;

                    $scope.isLoading = false;
                });
            }).catch(function () {
                $scope.isLoading = false;
            });
        }

        // Fetch state parameters if provided
        handleBitcoinPaymentScheme();
        /**
         * Handle state parameters about bitcoin payment information, if present
         */
        function handleBitcoinPaymentScheme() {

            // Protocol sanity check
            if ($stateParams.protocol === "bitcoin" || $stateParams.protocol === "bitcoincash") {
                $timeout(function () {
                    // Correct wallet for protocol check
                    if ($stateParams.protocol === "bitcoin" && walletData.networkType === "BCC") {
                        return switchWalletByNetworkTypeAndIdentifier('BTC', walletData.identifier);
                    } else if ($stateParams.protocol === "bitcoincash" && walletData.networkType === "BTC") {
                        /*
                         * This is only added here for completions sake - there is no way to register 'bitcoincash:'
                         * URI handlers yet in the majority of browsers
                         */
                        return switchWalletByNetworkTypeAndIdentifier('BCC', walletData.identifier);
                    } else {
                        applyBitcoinURIParams($stateParams.address, $stateParams.amount);
                    }
                });
            } else if ($stateParams.protocol === null) {
                // If it is not set, do not need to complain
            } else {
                throw new Error("Unknown protocol type for payment URL");
            }
        }

        /**
         * Switches the wallet interface based on the network type and identifier
         * @param networkType Network type
         * @param identifier Wallet identifier
         */
        function switchWalletByNetworkTypeAndIdentifier(networkType, identifier) {
            $scope.isLoading = true;
            return walletsManagerService.setActiveWalletByNetworkTypeAndIdentifier(networkType, identifier)
                .then(function () {
                    $state.reload();
                    $scope.isLoading = false;
                });
        }

        /**
         * Applies the amount and address to the input fields for sending coins
         * @param address
         * @param amount
         */
        function applyBitcoinURIParams(address, amount) {
            if (address) {
                activeWallet.validateAddress(address)
                    .then(function (address) {
                        if (address) {
                            $scope.sendInput.recipientAddress = address;
                        }
                    });
            }

            if (amount) {
                amount = parseFloat($stateParams.amount);

                if (amount) {
                    $scope.sendInput.amount = amount;
                }
                // Update fiat price
                setAltCurrency();
            }
        }

        NotificationsService.checkAndPromptBitcoinURIHandler();

        /**
         * Update currency type
         * @param currencyType
         */
        function updateCurrentType(currencyType) {
            $scope.currencies = Currencies.getCurrencies();

            // filter out crypto currencies that are not current
            $scope.currencies = $scope.currencies.filter(function(currency) {
                return currency.isFiat || currency.code === nativeCurrency;
            });

            // filter out selected currency
            $scope.currencies = $scope.currencies.filter(function(currency) {
                return currency.code !== currencyType;
            });

            $scope.currencyType = currencyType;

            setAltCurrency();
        }

        /**
         * Set alt currency
         */
        function setAltCurrency() {
            if ($scope.currencyType === nativeCurrency) {
                $scope.altCurrency.code = $scope.settings.localCurrency;
                $scope.altCurrency.amount = parseFloat(CurrencyConverter.fromBTC($scope.sendInput.amount, $scope.settings.localCurrency, 2)) || 0;
            } else {
                $scope.altCurrency.code = nativeCurrency;
                $scope.altCurrency.amount = parseFloat(CurrencyConverter.toBTC($scope.sendInput.amount, $scope.currencyType, 6)) || 0;
            }
        }

        /**
         * Get max spendable
         * @return {*}
         */
        function getMaxSpendable() {
            if (maxSpendable !== null) {
                return $q.when(maxSpendable);
            } else if (maxSpendablePromise !== null) {
                return maxSpendablePromise;
            } else {
                maxSpendablePromise = $q.all([
                    activeWallet.getSdkWallet().maxSpendable($scope.useZeroConf, blocktrailSDK.Wallet.FEE_STRATEGY_OPTIMAL),
                    activeWallet.getSdkWallet().maxSpendable($scope.useZeroConf, blocktrailSDK.Wallet.FEE_STRATEGY_LOW_PRIORITY),
                    activeWallet.getSdkWallet().maxSpendable($scope.useZeroConf, blocktrailSDK.Wallet.FEE_STRATEGY_MIN_RELAY_FEE)
                ]).then(function(results) {
                    // set the local stored value
                    maxSpendable = {};
                    maxSpendable[blocktrailSDK.Wallet.FEE_STRATEGY_OPTIMAL] = results[0];
                    maxSpendable[blocktrailSDK.Wallet.FEE_STRATEGY_LOW_PRIORITY] = results[1];
                    maxSpendable[blocktrailSDK.Wallet.FEE_STRATEGY_MIN_RELAY_FEE] = results[2];

                    maxSpendablePromise = null; // unset promise, it's done
                    return maxSpendable;
                });

                return maxSpendablePromise;
            }
        }

        /**
         * Fetch fee
         */
        function fetchFee() {
            // reset state
            $scope.fees.lowPriority = null;
            $scope.fees.optimal = null;
            $scope.fees.minRelayFee = null;
            $scope.displayFee = false;
            $scope.prioboost.possible = null;
            $scope.prioboost.estSize = null;
            $scope.prioboost.zeroConf = null;

            var localPay = {};
            var amount = 0;

            if ($scope.currencyType === nativeCurrency) {
                amount = $scope.sendInput.amount;
            } else {
                amount = $scope.altCurrency.amount;
            }

            amount = parseInt(CurrencyConverter.toSatoshi(amount, "BTC"));

            // halt if input is 0
            if (amount <= 0) {
                return $q.reject(new Error("Amount needs to be > 0"));
            }

            // either use the real destination address or otherwise use a fake address
            if ($scope.sendInput.recipientAddress) {
                localPay[$scope.sendInput.recipientAddress] = amount;
            } else {
                var fakeP2SHScript = bitcoinJS.script.scriptHash.output.encode(new blocktrailSDK.Buffer("0000000000000000000000000000000000000000", "hex"));
                var fakeAddress = bitcoinJS.address.fromOutputScript(fakeP2SHScript, activeWallet.getSdkWallet().sdk.network);
                localPay[fakeAddress.toString()] = amount;
            }

            return $q.all([
                activeWallet
                    .getSdkWallet()
                    .coinSelection(localPay, false, $scope.useZeroConf, blocktrailSDK.Wallet.FEE_STRATEGY_LOW_PRIORITY)
                    .spread(function(utxos, fee, change, res) {
                        $log.debug("lowPriority fee: " + fee);

                        return fee;
                    })
                    .catch(function(e) {
                        // when we get a fee error we use maxspendable fee
                        if (e instanceof blocktrail.WalletFeeError || (e instanceof Error && e.message === "Wallet balance too low")) {
                            return getMaxSpendable().then(function(maxSpendable) {
                                var fee = maxSpendable[blocktrailSDK.Wallet.FEE_STRATEGY_LOW_PRIORITY].fee;
                                $log.debug("lowPriority fee MAXSPENDABLE: " + fee);
                                return fee;
                            });
                        } else {
                            throw e;
                        }
                    }),
                activeWallet
                    .getSdkWallet()
                    .coinSelection(localPay, false, $scope.useZeroConf, blocktrailSDK.Wallet.FEE_STRATEGY_OPTIMAL)
                    .spread(function(utxos, fee, change, res) {
                        $log.debug("optimal fee: " + fee);

                        return fee;
                    })
                    .catch(function(e) {
                        // when we get a fee error we use maxspendable fee
                        if (e instanceof blocktrail.WalletFeeError || (e instanceof Error && e.message === "Wallet balance too low")) {
                            return getMaxSpendable()
                                .then(function(maxSpendable) {
                                    var fee = maxSpendable[blocktrailSDK.Wallet.FEE_STRATEGY_OPTIMAL].fee;
                                    $log.debug("optiomal fee MAXSPENDABLE: " + fee);
                                    return fee;
                                });
                        } else {
                            throw e;
                        }
                    }),
                activeWallet
                    .getSdkWallet()
                    .coinSelection(localPay, false, $scope.useZeroConf, blocktrailSDK.Wallet.FEE_STRATEGY_MIN_RELAY_FEE)
                    .spread(function(utxos, fee, change, res) {
                        $log.debug("minRelayFee fee: " + fee);

                        $scope.prioboost.estSize = res.size;
                        $scope.prioboost.credits = res.prioboost_remaining;
                        $scope.prioboost.zeroConf = res.zeroconf;
                        $scope.prioboost.tooLarge = $scope.prioboost.estSize > $scope.PRIOBOOST_MAX_SIZE;
                        $scope.prioboost.possible = !$scope.prioboost.zeroConf && !$scope.prioboost.tooLarge && $scope.prioboost.credits > 0;

                        return fee;
                    })
                    .catch(function(e) {
                        // when we get a fee error we use maxspendable fee
                        if (e instanceof blocktrail.WalletFeeError || (e instanceof Error && e.message === "Wallet balance too low")) {
                            return getMaxSpendable()
                                .then(function(maxSpendable) {
                                    var fee = maxSpendable[blocktrailSDK.Wallet.FEE_STRATEGY_MIN_RELAY_FEE].fee;
                                    $log.debug("minRelayFee fee MAXSPENDABLE: " + fee);
                                    return fee;
                                });
                        } else {
                            throw e;
                        }
                    })
            ])
                .then(function(res) {
                    var lowPriorityFee = res[0];
                    var optimalFee = res[1];
                    var minRelayFee = res[2];

                    $scope.fees.lowPriority = lowPriorityFee;
                    $scope.fees.optimal = optimalFee;
                    $scope.fees.minRelayFee = minRelayFee;
                    $scope.displayFee = true;

                    return updateFee();
                }, function(e) {
                    $log.debug("fetchFee ERR " + e);
                });
        }

        /**
         * Update fee
         */
        function updateFee() {
            if ($scope.sendInput.feeChoice === $scope.OPTIMAL_FEE) {
                $scope.fee = $scope.fees.optimal;
            } else if ($scope.sendInput.feeChoice === $scope.LOW_PRIORITY_FEE) {
                $scope.fee = $scope.fees.lowPriority;
            } else if ($scope.sendInput.feeChoice === $scope.PRIOBOOST) {
                $scope.fee = $scope.fees.minRelayFee;
            } else {
                throw new Error("Invalid");
            }
        }

        /**
         * On submit form send
         */
        function onSubmitFormSend() {
            $scope.isLoading = true;

            return $scope
                .fetchFee()
                .then(validateData)
                .then(
                    function(sendAmount) {
                        $scope.isLoading = false;

                        $modal.open({
                            controller: "SendConfirmModalCtrl",
                            templateUrl: "js/modules/wallet/controllers/send-confirm-modal/send-confirm-modal.tpl.html",
                            size: "md",
                            backdrop: "static",
                            resolve: {
                                activeWallet: function() {
                                    return activeWallet;
                                },
                                sendData: function() {
                                    return {
                                        feeChoice: $scope.sendInput.feeChoice,
                                        recipientAddress: $scope.sendInput.recipientAddress,
                                        amount: sendAmount,
                                        requires2FA: $scope.requires2FA
                                    };
                                }
                            }
                        });
                    },
                    function() {
                        $scope.isLoading = false;
                    });
        }

        /**
         * Validate data
         */
        function validateData() {
            var sendAmount = 0;
            var isValid = true;

            clearErrors();

            if ($scope.sendInput.feeChoice === $scope.PRIOBOOST && $scope.prioboost.possible === false) {
                var body = $scope.prioboost.credits <= 0 ? $translate.instant("PRIOBOOST_NO_CREDITS") : ($scope.prioboost.tooLarge ? $translate.instant("PRIOBOOST_TOO_LARGE") : $translate.instant("PRIOBOOST_ZERO_CONF"));
                var title = $translate.instant("PRIOBOOST_NOT_POSSIBLE");

                dialogService
                    .alert({
                        body: body,
                        title: title
                    });

                isValid = false;
            }

            // input amount
            // https://stackoverflow.com/questions/7810446/regex-validation-of-numeric-with-up-to-4-decimal-places
            if (!$scope.sendInput.amount || !$scope.sendInput.amount.toString().match("^[0-9]*(?:\.[0-9]{0,8})?$")) {
                $scope.errors.amount = "MSG_INVALID_AMOUNT";
                isValid = false;
            }

            if (parseFloat($scope.sendInput.amount).toFixed(8) === "0.00000000") {
                $scope.errors.amount = "MSG_INVALID_AMOUNT";
                isValid = false;
            }

            if ($scope.currencyType === nativeCurrency) {
                sendAmount = $scope.sendInput.amount;
            } else {
                sendAmount = $scope.altCurrency.amount;
            }

            if (parseInt(CurrencyConverter.toSatoshi(sendAmount, "BTC")) >= ($scope.walletData.balance + $scope.walletData.uncBalance)) {
                $scope.errors.amount = "MSG_INSUFFICIENT_FUNDS";
                isValid = false;
            }

            // no send address
            if (!$scope.sendInput.recipientAddress) {
                $scope.errors.recipient = "MSG_MISSING_RECIPIENT";
                isValid = false;
            }

            if (isValid) {
                return activeWallet
                    .validateAddress($scope.sendInput.recipientAddress)
                    .then(function() {
                        return sendAmount;
                    })
                    .catch(function() {
                        $scope.errors.recipient = "MSG_INVALID_RECIPIENT";
                        return $q.reject();
                    });
            } else {
                return $q.reject();
            }
        }

        /**
         * Clear errors
         */
        function clearErrors() {
            $scope.errors.amount = false;
            $scope.errors.recipient = false;
        }

        /**
         * Clear error
         * @param type
         */
        function resetError(type) {
            $scope.errors[type] = false;
        };
    }
})();
<|endoftext|>