<commit_before>#!/usr/bin/env node
'use strict';

const program = require('commander');
const chalk = require('chalk');
const miteApi = require('mite-api');

const pkg = require('./../package.json');
const config = require('./config');
const formater = require('./lib/formater');
const DataOutput = require('./lib/data-output');
const listCommand = require('./lib/commands/list');
const columnOptions = require('./lib/options/columns');
const commandOptions = require('./lib/options');
const { handleError } = require('./lib/errors');
const { guessRequestParamsFromPeriod } = require('./lib/period');
const { FORMAT } = require('./lib/data-output');

// no other options or comamnd line arguments used, default "period" to "today"
if (process.argv.length === 2) {
  process.argv.splice(2, 0, 'today');
}

program
  .version(pkg.version)
  .arguments('[period]')
  .description('list time entries', {
    period:
      `name of the period for which the time entries should be shown. \
Can be single dates, duraions and weekday names: \n\
- "today" shows todays time entries (default)\n\
- "last_week" or "last-week" shows entries from the whole last week\n\
- "7days", "2days", "3m" shows time entries since 7 days, 2days or 3 months\n\
- "cw2" for the calendar week 2, MO-SO\n\
- "2021 cw3" for 2021 calendar week 3, Mo-So\n\
- "2019-10-12" shows all entries from that exact date\n\
- "2021-01" entries for january 2021, or even shorter "211"\n\
- "2020" all entries from 2020\n\
- "friday", "fr" or other weekday names or abbreviations show all entries since \
  this last weekday`
  })
  .option.apply(program, commandOptions.toArgs(commandOptions.billable),
    'show entries which are billable or not billable'
  )
  .option(
    '--columns <columns>',
    columnOptions.description(listCommand.columns.options),
    columnOptions.parse
  )
  .option(
    '--customer-id <id>',
    'customer id, can be either a single ID, or multiple comma-separated IDs.'
  )
  .option.apply(program, commandOptions.toArgs(commandOptions.json))
  .option.apply(program, commandOptions.toArgs(commandOptions.plain))
  .option.apply(program, commandOptions.toArgs(commandOptions.pretty))
  .option(
    '--from <period|YYYY-MM-DD>',
    'in combination with "to" used for selecting a specific time frame of ' +
    'time entries to return, same as "period" argument or a specific date in ' +
    'the format "YYYY-MM-DD". The period argument is ignored.'
  )
  .option(
    '--group-by <column>',
    'optional grouping parameter which should be used. Valid values are ' +
    listCommand.groupBy.options.join(', ')
  )
  .option(
    '-l, --limit <limit>',
    'optional number of items to show, default is infinite',
    undefined,
    ((val) => parseInt(val, 10))
  )
  .option(
    '--locked <true|false>',
    'filter entries by their locked status',
    (val => ['true', 'yes', 'ja', 'ok', '1'].indexOf(val.toLowerCase()) > -1),
    null
  )
  .option(
    '--min-duration <minDuration>',
    'filter out entries which have a duration below the given value (client side)',
  )
  .option(
    '--max-duration <maxDuration>',
    'filter out entries which have a duration above the given value (client side)',
  )
  .option(
    '--project-id <id>',
    'project id, can be either a single ID, or multiple comma-separated IDs.'
  )
  .option(
    '--to <period|YYYY-MM-DD>',
    'in combination with "from" used for selecting a specific time frame of ' +
    'time entries to return, same as "period" argument or a specific date in ' +
    'the format "YYYY-MM-DD". The period argument is ignored.'
  )
  .option.apply(program, commandOptions.toArgs(commandOptions.tracking))
  .option(
    '--reversed',
    'reverse the sorting direction',
  )
  .option(
    '-s --search <query>',
    'search within the notes, to filter by multiple criteria connected with OR use comma-separated query values',
    ((val) => {
      if (typeof val === 'string') {
        return val.split(/\s*,\s*/);
      }
      return val;
    })
  )
  .option(
    '--service-id <id>',
    'service id, can be either a single ID, or multiple comma-separated IDs.'
  )
  .option.apply(program, commandOptions.toArgs(
    commandOptions.sort,
    commandOptions.sort.description(listCommand.sort.options),
    listCommand.sort.default
  ))
  .option(
    '--user-id <id>',
    'optional single user id who’s time entries should be returned or ' +
    'multiple values comma-separated. Note that the current user may not ' +
    'have the permission ot read other user’s time entries which will result ' +
    'in an empty response',
    ((val) => {
      if (typeof val === 'string') {
        return val.split(/\s*,\s*/);
      }
      return val;
    })
  )
  .addHelpText('after', `

Examples:

  list all entries from the current month:
    mite list this_month

  list all entries which note contains the given search query:
    mite list this_year --search JIRA-123

  show all entries from two services 123 and 38171
    mite list last_month --service-id 123,38171

  show all time entries from a specific date
    mite list 2019-10-21

  show time entries from last thursday
    mite list thursday

  show all users who tracked billable entries ordered by the amount of time
  they have tracked:
    mite list this_year --billable true --columns user,duration --group-by user --sort duration

  export all time-entries from the current month as csv:
    mite list last_week --json --columns user,id | jq -rM '.[] | @csv'

  create a report of all customer and their generated profits:
    mite list this_year --group-by customer --sort revenue

  The output of mite list can be forwarded to other commands using xargs. The
  following example will delete all matchin entries:
    mite list this_month --search="query" --columns id --plain | xargs -n1 mite delete

  Get the notes for one specific service, project for the last month to put
  them on a bill or similar
    mite list last_month --project-id 2681601 --service-id 325329 --columns note --plain | sort -u

  Show a seperate report for all users showing the revenues and times per
  service for all users matching a query:
    mite users --search marc --columns id --plain | xargs mite list last_month --group-by service --user-id

  Create PDF with time entries from a specific project for the last month
    NO_COLOR=1 mite list last-month --project-id 1234 --columns date,service,note,duration --json | jq -rM '.[] | @csv' | npx csv2md
`)
  .parse();

/**
 * Returns the request options for requesting the time entries or grouped
 * time entries for the given time entries and filtering options.
 *
 * @param {string} period
 * @param {object} opts
 * @return {Object<String, any>} time entries or grouped time entries
 */
function getRequestOptions(period, opts) {
  return {
    ...guessRequestParamsFromPeriod(period),
    ...(typeof opts.billable === 'boolean' && { billable: opts.billable }),
    ...(opts.customerId && { customer_id: opts.customerId }),
    ...(opts.from && { from: opts.from }),
    ...(opts.groupBy && { group_by: opts.groupBy }),
    ...(opts.limit && { limit: opts.limit }),
    ...(typeof opts.locked === 'boolean' && { locked: opts.locked }),
    ...(opts.projectId && { project_id: opts.projectId }),
    ...(opts.reversed && { direction: 'asc' }),
    ...(opts.search && { note: opts.search }),
    ...(opts.serviceId && { service_id: opts.serviceId }),
    ...(opts.sort && { sort: opts.sort }),
    ...(typeof opts.tracking === 'boolean' && { tracking: opts.tracking }),
    ...(opts.to && { to: opts.to }),
    ...(opts.userId && { user_id: opts.userId}),
  };
}

/**
 * Callback function to filter time entries which are shown depending on the
 * command line options
 *
 * @param {object} opts
 * @param {MiteTimeEntry} entry
 * @return {boolean}
 */
function filterData(opts, row) {
  let valid = true;
  if (opts.minDuration) {
    const minDuration = formater.durationToMinutes(opts.minDuration, 10);
    valid &= row.minutes >= minDuration;
  }
  if (opts.maxDuration) {
    const maxDuration = formater.durationToMinutes(opts.maxDuration, 10);
    valid &= row.minutes <= maxDuration;
  }
  return valid;
}

/**
 * @param {array<object>} items
 * @param {import('./lib/data-output').ColumnDefinition[]} columns
 * @param {import('./lib/data-output').FORMAT} format
 * @param {boolean} [includeSums=true]
 * @returns {array<object>}
 */
function getReport(items, columns, format, includeSums = true) {
  const tableData = DataOutput.compileTableData(items, columns, format);

  // Table footer
  // add table footer if any of the table columns has a reducer
  if (includeSums && columnOptions.hasReducer(columns)) {
    let footerColumns = DataOutput.getTableFooterColumns(items, columns);
    footerColumns = footerColumns.map(v => v ? chalk.bold(v) : v); // make footer bold
    tableData.push(footerColumns);
  }

  return DataOutput.formatData(tableData, format, columns);
}

function main(period) {
  const mite = miteApi(config.get());
  const opts = program.opts();

  const requestOpts = getRequestOptions(period, opts);
  console.log(requestOpts);
  // "columns" default option is different
  if (!opts.columns) {
    // when groupBy is used, make sure that revenue and duration are used
    if (opts.groupBy) {
      opts.columns = opts.groupBy + ',revenue,duration';
    } else {
      opts.columns = config.get().listColumns;
    }
  }
  const columns = columnOptions.resolve(opts.columns, listCommand.columns.options);
  mite.getTimeEntries(requestOpts, (err, results) => {
    if (err) return handleError(err);

    // decide wheter to output grouped report or single entry report
    let items = results
      .map(data => data[opts.groupBy ? 'time_entry_group' : 'time_entry'])
      .filter(v => v)
      .filter(filterData.bind(this, opts))
      ;
    const format = DataOutput.getFormatFromOptions(opts, config);
    const report = getReport(items, columns, format, format === FORMAT.TABLE);
    process.stdout.write(report);
  });
} // main

const period = program.args[0];
main(period);
<commit_msg>fix: removes console.log<commit_after>#!/usr/bin/env node
'use strict';

const program = require('commander');
const chalk = require('chalk');
const miteApi = require('mite-api');

const pkg = require('./../package.json');
const config = require('./config');
const formater = require('./lib/formater');
const DataOutput = require('./lib/data-output');
const listCommand = require('./lib/commands/list');
const columnOptions = require('./lib/options/columns');
const commandOptions = require('./lib/options');
const { handleError } = require('./lib/errors');
const { guessRequestParamsFromPeriod } = require('./lib/period');
const { FORMAT } = require('./lib/data-output');

// no other options or comamnd line arguments used, default "period" to "today"
if (process.argv.length === 2) {
  process.argv.splice(2, 0, 'today');
}

program
  .version(pkg.version)
  .arguments('[period]')
  .description('list time entries', {
    period:
      `name of the period for which the time entries should be shown. \
Can be single dates, duraions and weekday names: \n\
- "today" shows todays time entries (default)\n\
- "last_week" or "last-week" shows entries from the whole last week\n\
- "7days", "2days", "3m" shows time entries since 7 days, 2days or 3 months\n\
- "cw2" for the calendar week 2, MO-SO\n\
- "2021 cw3" for 2021 calendar week 3, Mo-So\n\
- "2019-10-12" shows all entries from that exact date\n\
- "2021-01" entries for january 2021, or even shorter "211"\n\
- "2020" all entries from 2020\n\
- "friday", "fr" or other weekday names or abbreviations show all entries since \
  this last weekday`
  })
  .option.apply(program, commandOptions.toArgs(commandOptions.billable),
    'show entries which are billable or not billable'
  )
  .option(
    '--columns <columns>',
    columnOptions.description(listCommand.columns.options),
    columnOptions.parse
  )
  .option(
    '--customer-id <id>',
    'customer id, can be either a single ID, or multiple comma-separated IDs.'
  )
  .option.apply(program, commandOptions.toArgs(commandOptions.json))
  .option.apply(program, commandOptions.toArgs(commandOptions.plain))
  .option.apply(program, commandOptions.toArgs(commandOptions.pretty))
  .option(
    '--from <period|YYYY-MM-DD>',
    'in combination with "to" used for selecting a specific time frame of ' +
    'time entries to return, same as "period" argument or a specific date in ' +
    'the format "YYYY-MM-DD". The period argument is ignored.'
  )
  .option(
    '--group-by <column>',
    'optional grouping parameter which should be used. Valid values are ' +
    listCommand.groupBy.options.join(', ')
  )
  .option(
    '-l, --limit <limit>',
    'optional number of items to show, default is infinite',
    undefined,
    ((val) => parseInt(val, 10))
  )
  .option(
    '--locked <true|false>',
    'filter entries by their locked status',
    (val => ['true', 'yes', 'ja', 'ok', '1'].indexOf(val.toLowerCase()) > -1),
    null
  )
  .option(
    '--min-duration <minDuration>',
    'filter out entries which have a duration below the given value (client side)',
  )
  .option(
    '--max-duration <maxDuration>',
    'filter out entries which have a duration above the given value (client side)',
  )
  .option(
    '--project-id <id>',
    'project id, can be either a single ID, or multiple comma-separated IDs.'
  )
  .option(
    '--to <period|YYYY-MM-DD>',
    'in combination with "from" used for selecting a specific time frame of ' +
    'time entries to return, same as "period" argument or a specific date in ' +
    'the format "YYYY-MM-DD". The period argument is ignored.'
  )
  .option.apply(program, commandOptions.toArgs(commandOptions.tracking))
  .option(
    '--reversed',
    'reverse the sorting direction',
  )
  .option(
    '-s --search <query>',
    'search within the notes, to filter by multiple criteria connected with OR use comma-separated query values',
    ((val) => {
      if (typeof val === 'string') {
        return val.split(/\s*,\s*/);
      }
      return val;
    })
  )
  .option(
    '--service-id <id>',
    'service id, can be either a single ID, or multiple comma-separated IDs.'
  )
  .option.apply(program, commandOptions.toArgs(
    commandOptions.sort,
    commandOptions.sort.description(listCommand.sort.options),
    listCommand.sort.default
  ))
  .option(
    '--user-id <id>',
    'optional single user id who’s time entries should be returned or ' +
    'multiple values comma-separated. Note that the current user may not ' +
    'have the permission ot read other user’s time entries which will result ' +
    'in an empty response',
    ((val) => {
      if (typeof val === 'string') {
        return val.split(/\s*,\s*/);
      }
      return val;
    })
  )
  .addHelpText('after', `

Examples:

  list all entries from the current month:
    mite list this_month

  list all entries which note contains the given search query:
    mite list this_year --search JIRA-123

  show all entries from two services 123 and 38171
    mite list last_month --service-id 123,38171

  show all time entries from a specific date
    mite list 2019-10-21

  show time entries from last thursday
    mite list thursday

  show all users who tracked billable entries ordered by the amount of time
  they have tracked:
    mite list this_year --billable true --columns user,duration --group-by user --sort duration

  export all time-entries from the current month as csv:
    mite list last_week --json --columns user,id | jq -rM '.[] | @csv'

  create a report of all customer and their generated profits:
    mite list this_year --group-by customer --sort revenue

  The output of mite list can be forwarded to other commands using xargs. The
  following example will delete all matchin entries:
    mite list this_month --search="query" --columns id --plain | xargs -n1 mite delete

  Get the notes for one specific service, project for the last month to put
  them on a bill or similar
    mite list last_month --project-id 2681601 --service-id 325329 --columns note --plain | sort -u

  Show a seperate report for all users showing the revenues and times per
  service for all users matching a query:
    mite users --search marc --columns id --plain | xargs mite list last_month --group-by service --user-id

  Create PDF with time entries from a specific project for the last month
    NO_COLOR=1 mite list last-month --project-id 1234 --columns date,service,note,duration --json | jq -rM '.[] | @csv' | npx csv2md
`)
  .parse();

/**
 * Returns the request options for requesting the time entries or grouped
 * time entries for the given time entries and filtering options.
 *
 * @param {string} period
 * @param {object} opts
 * @return {Object<String, any>} time entries or grouped time entries
 */
function getRequestOptions(period, opts) {
  return {
    ...guessRequestParamsFromPeriod(period),
    ...(typeof opts.billable === 'boolean' && { billable: opts.billable }),
    ...(opts.customerId && { customer_id: opts.customerId }),
    ...(opts.from && { from: opts.from }),
    ...(opts.groupBy && { group_by: opts.groupBy }),
    ...(opts.limit && { limit: opts.limit }),
    ...(typeof opts.locked === 'boolean' && { locked: opts.locked }),
    ...(opts.projectId && { project_id: opts.projectId }),
    ...(opts.reversed && { direction: 'asc' }),
    ...(opts.search && { note: opts.search }),
    ...(opts.serviceId && { service_id: opts.serviceId }),
    ...(opts.sort && { sort: opts.sort }),
    ...(typeof opts.tracking === 'boolean' && { tracking: opts.tracking }),
    ...(opts.to && { to: opts.to }),
    ...(opts.userId && { user_id: opts.userId}),
  };
}

/**
 * Callback function to filter time entries which are shown depending on the
 * command line options
 *
 * @param {object} opts
 * @param {MiteTimeEntry} entry
 * @return {boolean}
 */
function filterData(opts, row) {
  let valid = true;
  if (opts.minDuration) {
    const minDuration = formater.durationToMinutes(opts.minDuration, 10);
    valid &= row.minutes >= minDuration;
  }
  if (opts.maxDuration) {
    const maxDuration = formater.durationToMinutes(opts.maxDuration, 10);
    valid &= row.minutes <= maxDuration;
  }
  return valid;
}

/**
 * @param {array<object>} items
 * @param {import('./lib/data-output').ColumnDefinition[]} columns
 * @param {import('./lib/data-output').FORMAT} format
 * @param {boolean} [includeSums=true]
 * @returns {array<object>}
 */
function getReport(items, columns, format, includeSums = true) {
  const tableData = DataOutput.compileTableData(items, columns, format);

  // Table footer
  // add table footer if any of the table columns has a reducer
  if (includeSums && columnOptions.hasReducer(columns)) {
    let footerColumns = DataOutput.getTableFooterColumns(items, columns);
    footerColumns = footerColumns.map(v => v ? chalk.bold(v) : v); // make footer bold
    tableData.push(footerColumns);
  }

  return DataOutput.formatData(tableData, format, columns);
}

function main(period) {
  const mite = miteApi(config.get());
  const opts = program.opts();

  const requestOpts = getRequestOptions(period, opts);
  // "columns" default option is different
  if (!opts.columns) {
    // when groupBy is used, make sure that revenue and duration are used
    if (opts.groupBy) {
      opts.columns = opts.groupBy + ',revenue,duration';
    } else {
      opts.columns = config.get().listColumns;
    }
  }
  const columns = columnOptions.resolve(opts.columns, listCommand.columns.options);
  mite.getTimeEntries(requestOpts, (err, results) => {
    if (err) return handleError(err);

    // decide wheter to output grouped report or single entry report
    let items = results
      .map(data => data[opts.groupBy ? 'time_entry_group' : 'time_entry'])
      .filter(v => v)
      .filter(filterData.bind(this, opts))
      ;
    const format = DataOutput.getFormatFromOptions(opts, config);
    const report = getReport(items, columns, format, format === FORMAT.TABLE);
    process.stdout.write(report);
  });
} // main

const period = program.args[0];
main(period);
<|endoftext|>


<commit_before>import Rx from 'rx'
const merge = Rx.Observable.merge
import {exists,getExtension,getNameAndExtension, isValidFile, isEmpty} from './utils'
import assign from 'fast.js/object/assign'//faster object.assign

function dataSource(data){
  if(isValidFile(data)){
    return {
      src:'desktop'
      ,uri: data.name
    }
  }
  else{
    return {
      src:'http'
      ,uri:data
    }
  }
}

export default function assetRequests(inputs, drivers){
  //const {meshSources$,srcSources$} = inputs

  //FIXME: caching should be done at a higher level , to prevent useless requests
  const resourceCache$ = undefined
  const cache = {}
  function getCached(inputs){
    //this one needs to be store independant too
  }

  const baseRequest$ = inputs
    .flatMap(Rx.Observable.fromArray)
    .filter(exists)
    .filter(data=>!isEmpty(data))
    .map(function(data){
      const source     = dataSource(data)
      const uri        = source.uri
      const {name,ext} = getNameAndExtension(uri)
      return {src:source.src, uri, data, ext, name}
    })

  //baseRequest$
  //  .forEach(e=>console.log("sort of requests",e))

  const requests$ = baseRequest$
    .filter(function(req){
      const cached = cache[req.uri]
      return cached ===undefined
    })

  /*const results$ = merge(
      fetch(drivers)
      //TODO: merge with cached results
    )*/
  /*const request  = of( e.request )
      const response = e.pluck("response")
      const progress = e.pluck("progress")
      return combineLatestObj({response,request,progress})*/

  /*var sources = {
    'desktop': of("desktop"),
    'http': of("bar")
  }
  var source = Rx.Observable.case(
    function(){
      return 'http'
    }
    ,sources)
    .forEach(e=>console.log("testing",e))*/

  // request from http driver
  const httpRequests$ = requests$
    .filter(r=>r.src==="http")
    .map(function(req){
      return assign({
        url:req.uri
        ,method:'get'
        ,type:'resource'},req)
    })

  //request from desktop store (source only)
  const desktopRequests$ = requests$
    .filter(r=>r.src==="desktop")
    .map(function(req){
      return assign({
        url:req.uri
        ,method:'get'
        ,type:'resource'},req)
    })

  const requests = {
    http$:httpRequests$
    ,desktop$:desktopRequests$
  }

  return requests

}
<commit_msg>chore():added url validation before sending requests<commit_after>import Rx from 'rx'
const merge = Rx.Observable.merge
import {exists,getExtension,getNameAndExtension, isValidFile, isValidUrl, isEmpty} from './utils'
import assign from 'fast.js/object/assign'//faster object.assign

function isValidDataSource(data){

  const foo =  isValidFile(data) || isValidUrl(data)
  console.log("foo",data, foo, isValidFile(data), isValidUrl(data))
  return foo
}

function dataSource(data){
  if(isValidFile(data)){
    return {
      src:'desktop'
      ,uri: data.name
    }
  }
  else if(isValidUrl(data)){
    return {
      src:'http'
      ,uri:data
    }
  }
}

export default function assetRequests(inputs, sources){
  //const {meshSources$,srcSources$} = inputs

  //FIXME: caching should be done at a higher level , to prevent useless requests
  const resourceCache$ = undefined
  const cache = {}
  function getCached(inputs){
    //this one needs to be store independant too
  }

  const baseRequest$ = inputs
    .flatMap(Rx.Observable.fromArray)
    .filter(exists)
    .filter(data=>!isEmpty(data))
    .filter(isValidDataSource)
    .map(function(data){
      const source     = dataSource(data)
      const uri        = source.uri
      const {name,ext} = getNameAndExtension(uri)
      return {src:source.src, uri, data, ext, name}
    })

  //baseRequest$
  //  .forEach(e=>console.log("sort of requests",e))

  const requests$ = baseRequest$
    .filter(function(req){
      const cached = cache[req.uri]
      return cached ===undefined
    })

  /*const results$ = merge(
      fetch(sources)
      //TODO: merge with cached results
    )*/
  /*const request  = of( e.request )
      const response = e.pluck("response")
      const progress = e.pluck("progress")
      return combineLatestObj({response,request,progress})*/

  /*var sources = {
    'desktop': of("desktop"),
    'http': of("bar")
  }
  var source = Rx.Observable.case(
    function(){
      return 'http'
    }
    ,sources)
    .forEach(e=>console.log("testing",e))*/

  // request from http driver
  const httpRequests$ = requests$
    .filter(r=>r.src==="http")
    .map(function(req){
      return assign({
        url:req.uri
        ,method:'get'
        ,type:'resource'},req)
    })

  //request from desktop store (source only)
  const desktopRequests$ = requests$
    .filter(r=>r.src==="desktop")
    .map(function(req){
      return assign({
        url:req.uri
        ,method:'get'
        ,type:'resource'},req)
    })

  const requests = {
    http$:httpRequests$
    ,desktop$:desktopRequests$
  }

  return requests

}
<|endoftext|>


<commit_before>/*

    ___ usage ___ en_US ___
    compassion colleague child <child options>

    options:

        -c, --conduit <address:port>
            address of the conduit to use for network communication

        -m, --module
            use a Node.js module instead of an executable for the child

        -I, --island <string>
            name of the island

        -i, --id <string>
            colleague id

        -p, --ping <integer>
            milliseconds between keep alive pings (defualt 250)

        -t, --timeout <integer>
            milliseconds before a participant is considered unreachable
                (defualt 1000)

        -r, --replay <string>
            replay a log

        --ipc
            communicate with child using Node IPC instead of socket

        --help
            display help message

    ___ $ ___ en_US ___

        conduit is required:
            the `--conduit` argument is a required argument
    ___ . ___

 */
require('arguable')(module, require('cadence')(function (async, program) {
    var http = require('http')

    var children = require('child_process')
    var Shuttle = require('prolific.shuttle')
    var abend = require('abend')
    var Delta = require('delta')

    var Colleague = require('./http.js')

    var logger = require('prolific.logger').createLogger('bigeasy.compassion.colleague.bin')

    Shuttle.shuttle(program, 1000, logger)

    program.helpIf(program.command.param.help)
    program.command.required('conduit')

    var stdio = [ 'inherit', 'inherit', 'inherit' ]
    var exec = true
    if (program.command.param.ipc) {
        module = './ipc'
        stdio.push('ipc')
    } else if (program.command.param.module) {
        module = program.argv.shift()
        exec = false
    } else {
        module = './child'
        stdio.push('pipe')
    }

    try {
        var Delegate = require(module)
    } catch (e) {
        throw e
    }

    var UserAgent = require('./ua')
    var Vizsla = require('vizsla')
    if (exec) {
        var child = children.spawn(program.argv.shift(), program.argv, { stdio: stdio })
        async(function () {
            new Delta(async()).ee(child).on('close')
        }, function (exit, signal) {
            console.log(exit, signal)
            colleague.stop()
// TODO Want.
            // return program.exitCode(exit, signal)
            return exit
        })
    }

    var colleague = new Colleague({
        islandName: program.command.param.island,
        colleagueId: program.command.param.id,
        Delegate: Delegate,
        argv: child,
// TODO Assert that these are integers.
        timeout: +(program.command.param.timeout || 60000),
        ping: +(program.command.param.ping || 10000),
        ua: new UserAgent(new Vizsla)
    })
    program.on('SIGINT', colleague.stop.bind(colleague))
    var fs = require('fs')
    var byline = require('byline')
    var player = colleague
    if (program.command.param.replay) {
        colleague.replay()
        async(function () {
            colleague.delegate.initialize(program, async())
        }, function () {
            var stream = fs.createReadStream(program.command.param.replay)
            byline(stream).on('data', function (line) {
                colleague.play(JSON.parse(line))
            })
            stream.on('end', function () { program.emit('SIGINT') })
        })
    } else {
        colleague.listen(program.command.param.conduit, program.argv, abend)
    }
}))
<commit_msg>Fix using `program` instead of `argv`.<commit_after>/*

    ___ usage ___ en_US ___
    compassion colleague child <child options>

    options:

        -c, --conduit <address:port>
            address of the conduit to use for network communication

        -m, --module
            use a Node.js module instead of an executable for the child

        -I, --island <string>
            name of the island

        -i, --id <string>
            colleague id

        -p, --ping <integer>
            milliseconds between keep alive pings (defualt 250)

        -t, --timeout <integer>
            milliseconds before a participant is considered unreachable
                (defualt 1000)

        -r, --replay <string>
            replay a log

        --ipc
            communicate with child using Node IPC instead of socket

        --help
            display help message

    ___ $ ___ en_US ___

        conduit is required:
            the `--conduit` argument is a required argument
    ___ . ___

 */
require('arguable')(module, require('cadence')(function (async, program) {
    var http = require('http')

    var children = require('child_process')
    var Shuttle = require('prolific.shuttle')
    var abend = require('abend')
    var Delta = require('delta')

    var Colleague = require('./http.js')

    var logger = require('prolific.logger').createLogger('bigeasy.compassion.colleague.bin')

    Shuttle.shuttle(program, 1000, logger)

    program.helpIf(program.command.param.help)
    program.command.required('conduit')

    var stdio = [ 'inherit', 'inherit', 'inherit' ]
    var exec = true
    if (program.command.param.ipc) {
        module = './ipc'
        stdio.push('ipc')
    } else if (program.command.param.module) {
        module = program.argv.shift()
        exec = false
    } else {
        module = './child'
        stdio.push('pipe')
    }

    try {
        var Delegate = require(module)
    } catch (e) {
        throw e
    }

    var UserAgent = require('./ua')
    var Vizsla = require('vizsla')
    if (exec) {
        var child = children.spawn(program.argv.shift(), program.argv, { stdio: stdio })
        async(function () {
            new Delta(async()).ee(child).on('close')
        }, function (exit, signal) {
            console.log(exit, signal)
            colleague.stop()
// TODO Want.
            // return program.exitCode(exit, signal)
            return exit
        })
    }

    var colleague = new Colleague({
        islandName: program.command.param.island,
        colleagueId: program.command.param.id,
        Delegate: Delegate,
        argv: child,
// TODO Assert that these are integers.
        timeout: +(program.command.param.timeout || 60000),
        ping: +(program.command.param.ping || 10000),
        ua: new UserAgent(new Vizsla)
    })
    program.on('SIGINT', colleague.stop.bind(colleague))
    var fs = require('fs')
    var byline = require('byline')
    var player = colleague
    if (program.command.param.replay) {
        colleague.replay()
        async(function () {
            colleague.delegate.initialize(program, async())
        }, function () {
            var stream = fs.createReadStream(program.command.param.replay)
            byline(stream).on('data', function (line) {
                colleague.play(JSON.parse(line))
            })
            stream.on('end', function () { program.emit('SIGINT') })
        })
    } else {
        colleague.listen(program.command.param.conduit, program, abend)
    }
}))
<|endoftext|>


<commit_before>const defaultConfig = require('./default-config')
const generateLabel = require('./generate-label')

/**
 * Returns the regex, labels and config object used in every handler
 * @param {object} context - Probot context object
 * @returns {object}
 */
module.exports = async context => {
  const config = await context.config('config.yml')
  const cfg = config && config.todo ? Object.assign({}, defaultConfig, config.todo) : defaultConfig
  const labels = await generateLabel(context, cfg)
  const keywords = Array.isArray(cfg.keyword) ? cfg.keyword : [cfg.keyword]
  const reg = new RegExp(`^diff --git a\\/.+ b\\/(.+)[\\s\\S]+?^@{2}.+\\+(\\d+).+@{2}([\\s\\S]+?(^(\\+).*(${keywords.join('|')})(?:[:-\\s]+)?\\s(.*))[\\s\\S]+)`, 'gm')

  return {
    config: cfg,
    regex: reg,
    labels
  }
}
<commit_msg>Include title regex in handler setup<commit_after>const defaultConfig = require('./default-config')
const generateLabel = require('./generate-label')

/**
 * Returns the regex, labels and config object used in every handler
 * @param {object} context - Probot context object
 * @returns {object}
 */
module.exports = async context => {
  const config = await context.config('config.yml')
  const cfg = config && config.todo ? Object.assign({}, defaultConfig, config.todo) : defaultConfig
  const labels = await generateLabel(context, cfg)
  const keywords = Array.isArray(config.keyword) ? config.keyword : [config.keyword]

  return {
    config: cfg,
    regex: new RegExp(`.+()\\s(?<keyword>${keywords.join('|')})\\s(?<title>.*)`),
    labels
  }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import {
  Dimensions,
  PanResponder,
  Platform,
  StyleSheet,
  View
 } from 'react-native'
import { throttle } from 'lodash'

const GREY_LIGHT = '#eeeeee'
const {width: screenWidth, height: screenHeight} = Dimensions.get('window')

export class Dial extends Component {
  constructor (props) {
    super(props)
    this.state = {
      startingAngle: this.props.initialAngle,
      startingRadius: this.props.initialRadius,
      releaseAngle: this.props.initialAngle,
      releaseRadius: this.props.initialRadius,
      angle: this.props.initialAngle,
      radius: this.props.initialRadius
    }
    this.offset = {x: 0, y: 0}
    this.updateState = throttle(this._updateState.bind(this), 16)
  }

  static defaultProps = {
    initialRadius: 1,
    initialAngle: 0,
    precision: 0
  }

  componentWillMount () {
    this._panResponder = PanResponder.create({
      onStartShouldSetPanResponder: (e, gestureState) => true,
      onStartShouldSetPanResponderCapture: (e, gestureState) => {
        const { deg, radius } = this.calcAngle(e.nativeEvent)
        this.setState({startingAngle: deg, startingRadius: radius})
        return true
      },
      onMoveShouldSetPanResponder: (e, g) => true,
      onMoveShouldSetPanResponderCapture: (e, gestureState) => true,
      onPanResponderGrant: (e, gestureState) => true,
      onPanResponderMove: (e, gestureState) => {
        this.updateAngle(gestureState)
      },
      onPanResponderRelease: (e, gestureState) => {
        this.setState({
          releaseAngle: this.state.angle,
          releaseRadius: this.state.radius
        })
      }
    })
  }

  updateAngle (gestureState) {
    let {deg, radius} = this.calcAngle(gestureState)
    if (deg < 0) deg = deg + 360
    if (Math.abs(this.state.angle - deg) > this.props.precision) {
      this.updateState({deg, radius})
    }
  }

  calcAngle (gestureState) {
    const {pageX, pageY, moveX, moveY} = gestureState
    const [x, y] = [pageX || moveX, pageY || moveY]
    const [dx, dy] = [x - this.offset.x, y - this.offset.y]
    return {
      deg: Math.atan2(dy, dx) * 180 / Math.PI + 120,
      radius: Math.sqrt(dy * dy + dx * dx) / this.radius // pitagoras r^2 = x^2 + y^2 normalizado
    }
  }

  _updateState ({deg, radius = this.state.radius}) {
    radius = this.state.releaseRadius + radius - this.state.startingRadius
    if (radius < this.props.radiusMin) radius = this.props.radiusMin
    else if (radius > this.props.radiusMax) radius = this.props.radiusMax

    deg = deg + this.state.releaseAngle - this.state.startingAngle
    if (deg < 0) deg = deg + 360

    this.setState({angle: deg, radius})
    this.props.onValueChange(deg, radius)
  }

  componentDidMount () {
    setTimeout(() => {
      this.self.measureInWindow((x, y, width, height) => {
        this.offset = {
          x: x + width / 2 - (Platform.OS === 'ios' ? screenWidth : 0),
          y: y + height / 2
        }
        this.radius = width / 2
      })
    })
  }

  render () {
    const rotate = this.props.fixed ? '0deg' : this.state.angle + 'deg'
    const scale = this.props.elastic ? this.state.radius : 1

    return (
      <View ref={(node) => { this.self = node}}
        // onLayout={(e) => this.onLayout(e)}
        style={[styles.coverResponder, this.props.responderStyle]}
        {...this._panResponder.panHandlers}
      >
        {this.props.children
          ? <View style={[this.props.wrapperStyle, {transform: [{rotate}, {scale}]}]}>
            {this.props.children}
          </View>
          : <DefaultDial style={this.props.style} rotate={rotate} scale={scale} />
        }
      </View>
    )
  }
}

export const DefaultDial = ({style = {}, rotate = '0rad', scale = 1}) => (
  <View style={[styles.dial, style, {transform: [
    {rotate}, {scale}
  ]}]} >
    <View style={styles.innerDialDecorator}>
      <View style={styles.pointer}/>
    </View>
  </View>
)

const styles = StyleSheet.create({
  coverResponder: {
    padding: 20, // needs a minimum
  },
  dial: {
    width: 120, height: 120,
    backgroundColor: 'white',
    borderRadius: 60,
    elevation: 5,
    shadowColor: GREY_LIGHT,
    shadowOffset: {width: 1, height: 2},
    shadowOpacity: 0.8,
    shadowRadius: 1,
  },
  innerDialDecorator: {
    top: 10, left: 10,
    width: 100, height: 100,
    borderRadius: 50,
    backgroundColor: 'white',
    elevation: 3,
  },
  pointer: {
    top: 20, left: 20,
    position: 'absolute',
    width: 10, height: 10,
    backgroundColor: 'rgb(221,223,226)',
    borderRadius: 5,
  },
})

Dial.propTypes = {
  angle: React.PropTypes.number,
  precision: React.PropTypes.number,
  onValueChange: React.PropTypes.func.isRequired,
}
<commit_msg>Fix iOS offset problem (#2)<commit_after>import React, { Component } from 'react'
import {
  Dimensions,
  PanResponder,
  Platform,
  StyleSheet,
  View
 } from 'react-native'
import { throttle } from 'lodash'

const GREY_LIGHT = '#eeeeee'
const {width: screenWidth, height: screenHeight} = Dimensions.get('window')

export class Dial extends Component {
  constructor (props) {
    super(props)
    this.state = {
      startingAngle: this.props.initialAngle,
      startingRadius: this.props.initialRadius,
      releaseAngle: this.props.initialAngle,
      releaseRadius: this.props.initialRadius,
      angle: this.props.initialAngle,
      radius: this.props.initialRadius
    }
    this.offset = {x: 0, y: 0}
    this.updateState = throttle(this._updateState.bind(this), 16)
  }

  static defaultProps = {
    initialRadius: 1,
    initialAngle: 0,
    precision: 0
  }

  componentWillMount () {
    this._panResponder = PanResponder.create({
      onStartShouldSetPanResponder: (e, gestureState) => true,
      onStartShouldSetPanResponderCapture: (e, gestureState) => {
        const { deg, radius } = this.calcAngle(e.nativeEvent)
        this.setState({startingAngle: deg, startingRadius: radius})
        return true
      },
      onMoveShouldSetPanResponder: (e, g) => true,
      onMoveShouldSetPanResponderCapture: (e, gestureState) => true,
      onPanResponderGrant: (e, gestureState) => true,
      onPanResponderMove: (e, gestureState) => {
        this.updateAngle(gestureState)
      },
      onPanResponderRelease: (e, gestureState) => {
        this.setState({
          releaseAngle: this.state.angle,
          releaseRadius: this.state.radius
        })
      }
    })
  }

  updateAngle (gestureState) {
    let {deg, radius} = this.calcAngle(gestureState)
    if (deg < 0) deg = deg + 360
    if (Math.abs(this.state.angle - deg) > this.props.precision) {
      this.updateState({deg, radius})
    }
  }

  calcAngle (gestureState) {
    const {pageX, pageY, moveX, moveY} = gestureState
    const [x, y] = [pageX || moveX, pageY || moveY]
    const [dx, dy] = [x - this.offset.x, y - this.offset.y]
    return {
      deg: Math.atan2(dy, dx) * 180 / Math.PI + 120,
      radius: Math.sqrt(dy * dy + dx * dx) / this.radius // pitagoras r^2 = x^2 + y^2 normalizado
    }
  }

  _updateState ({deg, radius = this.state.radius}) {
    radius = this.state.releaseRadius + radius - this.state.startingRadius
    if (radius < this.props.radiusMin) radius = this.props.radiusMin
    else if (radius > this.props.radiusMax) radius = this.props.radiusMax

    deg = deg + this.state.releaseAngle - this.state.startingAngle
    if (deg < 0) deg = deg + 360

    this.setState({angle: deg, radius})
    this.props.onValueChange(deg, radius)
  }

  componentDidMount () {
    setTimeout(() => {
      this.self.measureInWindow((x, y, width, height) => {
        this.offset = {
          x: x + width / 2,
          y: y + height / 2
        }
        this.radius = width / 2
      })
    })
  }

  render () {
    const rotate = this.props.fixed ? '0deg' : this.state.angle + 'deg'
    const scale = this.props.elastic ? this.state.radius : 1

    return (
      <View ref={(node) => { this.self = node}}
        // onLayout={(e) => this.onLayout(e)}
        style={[styles.coverResponder, this.props.responderStyle]}
        {...this._panResponder.panHandlers}
      >
        {this.props.children
          ? <View style={[this.props.wrapperStyle, {transform: [{rotate}, {scale}]}]}>
            {this.props.children}
          </View>
          : <DefaultDial style={this.props.style} rotate={rotate} scale={scale} />
        }
      </View>
    )
  }
}

export const DefaultDial = ({style = {}, rotate = '0rad', scale = 1}) => (
  <View style={[styles.dial, style, {transform: [
    {rotate}, {scale}
  ]}]} >
    <View style={styles.innerDialDecorator}>
      <View style={styles.pointer}/>
    </View>
  </View>
)

const styles = StyleSheet.create({
  coverResponder: {
    padding: 20, // needs a minimum
  },
  dial: {
    width: 120, height: 120,
    backgroundColor: 'white',
    borderRadius: 60,
    elevation: 5,
    shadowColor: GREY_LIGHT,
    shadowOffset: {width: 1, height: 2},
    shadowOpacity: 0.8,
    shadowRadius: 1,
  },
  innerDialDecorator: {
    top: 10, left: 10,
    width: 100, height: 100,
    borderRadius: 50,
    backgroundColor: 'white',
    elevation: 3,
  },
  pointer: {
    top: 20, left: 20,
    position: 'absolute',
    width: 10, height: 10,
    backgroundColor: 'rgb(221,223,226)',
    borderRadius: 5,
  },
})

Dial.propTypes = {
  angle: React.PropTypes.number,
  precision: React.PropTypes.number,
  onValueChange: React.PropTypes.func.isRequired,
}
<|endoftext|>


<commit_before>const config = {};

//**********************************************************************
//*******************************CORE***********************************
//**********************************************************************

//Root Directory
const baseDir                   = process.cwd(); //IMPORTANT! DO NOT OVERRIDE!

//**********************************************************************
//******************************CUSTOM**********************************
//**********************************************************************
//IMPORTANT! All paths/directories should be relative to 'baseDir' unless specified otherwise.
// eg: baseDir+'/path'

config.moduleName               = 'riko';
config.destDir                  = baseDir+"/dist";
config.srcDir                   = baseDir+"/src";
config.tempDir                  = baseDir+"/temp";

config.EXPRESS_PORT             = 3000;
config.EXPRESS_ROOT             = config.destDir;

config.eslintConfig             = config.srcDir+'/__linters/.eslintrc';
config.stylelintConfig          = config.srcDir+'/__linters/.stylelintrc.yaml';
config.packageJson              = baseDir+'/package.json';

config.srcFiles                 = [
    config.srcDir+'/**/*.js?(x)',
    '!'+config.srcDir+'/custom-config.js',
    '!'+config.srcDir+'/vendor/**/*.js',
    '!'+config.srcDir+'/__tests__utils/**/*.js'
];

//**********************************************************************
//*******************************PACKAGER*******************************
//**********************************************************************
//for Electron Applications Only
config.electronPackagingOptions             = {};

//Source directory for your electron source code
config.electronPackagingOptions.dir         = config.tempDir;

//target system architecture(s)
config.electronPackagingOptions.arch        = 'x64';

//applications icon  //OS X: .icns  //Windows: .ico
config.electronPackagingOptions.icon        = config.srcDir+'/riko-logo.icns';

//The application name
config.electronPackagingOptions.name        = 'Riko';

//target platform(s) to build for
config.electronPackagingOptions.platform    = ['darwin','win32'];

//disable pruning
config.electronPackagingOptions.prune       = false; //THIS MUST BE FALSE!!!

//Enable or disable asar archiving
config.electronPackagingOptions.asar        = true;

//directory where the finished package(s) are created
config.electronPackagingOptions.out         = config.destDir;

//**********************************************************************
//********************************JS************************************
//**********************************************************************

config.js_main_file_name        = config.moduleName+'.js';
config.js_main_entry_path       = config.srcDir+'/js/'+config.js_main_file_name;
config.js_output_path           = 'assets/js';

config.js_external_scripts      = [
    {
        src: 'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js',
        async: false,
        defer: false
    },
    {
        src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js',
        async: false,
        defer: false
    },
    {
        src: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.js',
        async: true,
        defer: false
    }
];

//IMPORTANT!!! ALL VALUES OF THE FOLLOWING 'value' key *MUST BE JSON STRINGIFIED*
config.js_runtime_configs      = [
    {
        key: 'process.env',
        value: {
            'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
        }
    }
];

//**********************************************************************
//*******************************STYLES*********************************
//**********************************************************************
config.styles_main_file_name    = 'styles.min.css';

config.styles_external_stylesheets  = [
    'https://cdnjs.cloudflare.com/ajax/libs/normalize/4.2.0/normalize.min.css'
];

//**********************************************************************
//******************************TEMPLATE********************************
//**********************************************************************
config.template_main_file_name  = 'index.html';
config.template_stats_file_name = '';
config.template_src_path        = config.srcDir+'/templates/index.pug';

//if you're using a custom template engine 'OTHER THAN' pug or html
//add as string below.
//https://www.npmjs.com/package/template-html-loader
//https://github.com/tj/consolidate.js
config.template_engine          = ''; //eg: hbs, handlebars, ejs, mustache

//Google Analytics
config.gaEnable                 = true;
config.gaTrackingId             = 'UA-XXXXX-Y';
config.gaPageViewOnLoad         = true;

//**********************************************************************
//********************************MEDIA*********************************
//**********************************************************************

// IMPORTANT!!! (THESE ARE ALREADY RELATIVE TO OUTPUT OR DESTINATION)
// ALSO DO NOT ADD TRAILING SLASH '/' eg: assets/audio/

config.media_audio_output_path  = 'assets/audio';
config.media_files_output_path  = 'assets/files'; //pdfs, docs, etc
config.media_fonts_output_path  = 'assets/fonts';
config.media_images_output_path = 'assets/images';
config.media_video_output_path  = 'assets/video';

// IMPORTANT!!! Use absolute path here.
config.media_favicon_path       = config.srcDir+'/media/images/riko-favicon.png';

//Image optimization options
//See: https://github.com/Klathmon/imagemin-webpack-plugin
config.imageminConfig = {
    // progressive: true,
    pngquant:{
        quality: '65-90',
        speed: 4
    },
    svgo:{
        plugins: [
            {
                removeViewBox: false
            },
            {
                removeEmptyAttrs: false
            }
        ]
    }
};

//**********************************************************************
//*******************************VENDOR*********************************
//**********************************************************************

// add vendor dependencies here
config.externalModules = {
    //eg: $ : 'jquery'
};

//**********************************************************************
//*******************************TESTS**********************************
//**********************************************************************

// See Readme

//**********************************************************************
//*******************************EXTRAS*********************************
//**********************************************************************

//https://webpack.github.io/docs/configuration.html#devtool
config.sourcemapType = 'source-map';

//Enable of disable sourcemaps
config.sourcemapDev = true;
config.sourcemapProd = true;

//Enable remote debugging via vorlon.js very useful for debugging on mobile devices.
//Simply visit localhost:1337 or browsersync's [externalIp]:1337 in dev mode (npm run dev)
//See: http://vorlonjs.com/
//WARNING: js sourcemap info will not be able in browser console if enabled in dev mode
//IMPORTANT! this is only recommend if you're debugging a specific device or not using sourcemaps.
config.enableRemoteDebugging   = false;

config.autoprefixerOptions     = { browsers: ['> 0%'] }; //prefix all

config.hotReloadingOptions     = {
    overlay: true,
    reload: true,
    noInfo: false,
    quiet: false
};

//Override hot module replacement and simply have the page refresh on file change
config.BrowserSyncReloadOnChange = false;

// IMPORTANT! must be and array
config.onBuildStartShellCommands = [];
config.onBuildEndShellCommands = [];
config.onBuildExitShellCommands = [];

config.failOnProdBuildJsError = true;
config.failOnProdBuildStyleError = false;
config.eslintQuietMode = false; //set false to display warnings based on your eslint config

module.exports = config;<commit_msg>add comment to custom config<commit_after>const config = {};

//**********************************************************************
//*******************************CORE***********************************
//**********************************************************************

//Root Directory
const baseDir                   = process.cwd(); //IMPORTANT! DO NOT OVERRIDE!

//**********************************************************************
//******************************CUSTOM**********************************
//**********************************************************************
//IMPORTANT! All paths/directories should be relative to 'baseDir' unless specified otherwise.
// eg: baseDir+'/path'

config.moduleName               = 'riko';
config.destDir                  = baseDir+"/dist";
config.srcDir                   = baseDir+"/src";
config.tempDir                  = baseDir+"/temp";

config.EXPRESS_PORT             = 3000;
config.EXPRESS_ROOT             = config.destDir;

config.eslintConfig             = config.srcDir+'/__linters/.eslintrc';
config.stylelintConfig          = config.srcDir+'/__linters/.stylelintrc.yaml';
config.packageJson              = baseDir+'/package.json';

config.srcFiles                 = [
    config.srcDir+'/**/*.js?(x)',
    '!'+config.srcDir+'/custom-config.js',
    '!'+config.srcDir+'/vendor/**/*.js',
    '!'+config.srcDir+'/__tests__utils/**/*.js'
];

//**********************************************************************
//*******************************PACKAGER*******************************
//**********************************************************************
//for Electron Applications Only
config.electronPackagingOptions             = {};

//Source directory for your electron source code
config.electronPackagingOptions.dir         = config.tempDir;

//target system architecture(s)
config.electronPackagingOptions.arch        = 'x64';

//applications icon  //OS X: .icns  //Windows: .ico
//get free conversions herehttps://iconverticons.com/online/
config.electronPackagingOptions.icon        = config.srcDir+'/riko-logo.icns';

//The application name
config.electronPackagingOptions.name        = 'Riko';

//target platform(s) to build for
config.electronPackagingOptions.platform    = ['darwin','win32'];

//disable pruning
config.electronPackagingOptions.prune       = false; //THIS MUST BE FALSE!!!

//Enable or disable asar archiving
config.electronPackagingOptions.asar        = true;

//directory where the finished package(s) are created
config.electronPackagingOptions.out         = config.destDir;

//**********************************************************************
//********************************JS************************************
//**********************************************************************

config.js_main_file_name        = config.moduleName+'.js';
config.js_main_entry_path       = config.srcDir+'/js/'+config.js_main_file_name;
config.js_output_path           = 'assets/js';

config.js_external_scripts      = [
    {
        src: 'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js',
        async: false,
        defer: false
    },
    {
        src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js',
        async: false,
        defer: false
    },
    {
        src: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.js',
        async: true,
        defer: false
    }
];

//IMPORTANT!!! ALL VALUES OF THE FOLLOWING 'value' key *MUST BE JSON STRINGIFIED*
config.js_runtime_configs      = [
    {
        key: 'process.env',
        value: {
            'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
        }
    }
];

//**********************************************************************
//*******************************STYLES*********************************
//**********************************************************************
config.styles_main_file_name    = 'styles.min.css';

config.styles_external_stylesheets  = [
    'https://cdnjs.cloudflare.com/ajax/libs/normalize/4.2.0/normalize.min.css'
];

//**********************************************************************
//******************************TEMPLATE********************************
//**********************************************************************
config.template_main_file_name  = 'index.html';
config.template_stats_file_name = '';
config.template_src_path        = config.srcDir+'/templates/index.pug';

//if you're using a custom template engine 'OTHER THAN' pug or html
//add as string below.
//https://www.npmjs.com/package/template-html-loader
//https://github.com/tj/consolidate.js
config.template_engine          = ''; //eg: hbs, handlebars, ejs, mustache

//Google Analytics
config.gaEnable                 = true;
config.gaTrackingId             = 'UA-XXXXX-Y';
config.gaPageViewOnLoad         = true;

//**********************************************************************
//********************************MEDIA*********************************
//**********************************************************************

// IMPORTANT!!! (THESE ARE ALREADY RELATIVE TO OUTPUT OR DESTINATION)
// ALSO DO NOT ADD TRAILING SLASH '/' eg: assets/audio/

config.media_audio_output_path  = 'assets/audio';
config.media_files_output_path  = 'assets/files'; //pdfs, docs, etc
config.media_fonts_output_path  = 'assets/fonts';
config.media_images_output_path = 'assets/images';
config.media_video_output_path  = 'assets/video';

// IMPORTANT!!! Use absolute path here.
config.media_favicon_path       = config.srcDir+'/media/images/riko-favicon.png';

//Image optimization options
//See: https://github.com/Klathmon/imagemin-webpack-plugin
config.imageminConfig = {
    // progressive: true,
    pngquant:{
        quality: '65-90',
        speed: 4
    },
    svgo:{
        plugins: [
            {
                removeViewBox: false
            },
            {
                removeEmptyAttrs: false
            }
        ]
    }
};

//**********************************************************************
//*******************************VENDOR*********************************
//**********************************************************************

// add vendor dependencies here
config.externalModules = {
    //eg: $ : 'jquery'
};

//**********************************************************************
//*******************************TESTS**********************************
//**********************************************************************

// See Readme

//**********************************************************************
//*******************************EXTRAS*********************************
//**********************************************************************

//https://webpack.github.io/docs/configuration.html#devtool
config.sourcemapType = 'source-map';

//Enable of disable sourcemaps
config.sourcemapDev = true;
config.sourcemapProd = true;

//Enable remote debugging via vorlon.js very useful for debugging on mobile devices.
//Simply visit localhost:1337 or browsersync's [externalIp]:1337 in dev mode (npm run dev)
//See: http://vorlonjs.com/
//WARNING: js sourcemap info will not be able in browser console if enabled in dev mode
//IMPORTANT! this is only recommend if you're debugging a specific device or not using sourcemaps.
config.enableRemoteDebugging   = false;

config.autoprefixerOptions     = { browsers: ['> 0%'] }; //prefix all

config.hotReloadingOptions     = {
    overlay: true,
    reload: true,
    noInfo: false,
    quiet: false
};

//Override hot module replacement and simply have the page refresh on file change
config.BrowserSyncReloadOnChange = false;

// IMPORTANT! must be and array
config.onBuildStartShellCommands = [];
config.onBuildEndShellCommands = [];
config.onBuildExitShellCommands = [];

config.failOnProdBuildJsError = true;
config.failOnProdBuildStyleError = false;
config.eslintQuietMode = false; //set false to display warnings based on your eslint config

module.exports = config;<|endoftext|>


<commit_before>'use strict'
const MiniPass = require('minipass')
const Pax = require('./pax.js')
const Header = require('./header.js')
const fs = require('fs')
const path = require('path')

const types = require('./types.js')
const maxReadSize = 1024 * 1024
const PROCESS = Symbol('process')
const FILE = Symbol('file')
const DIRECTORY = Symbol('directory')
const SYMLINK = Symbol('symlink')
const HARDLINK = Symbol('hardlink')
const HEADER = Symbol('header')
const READ = Symbol('read')
const LSTAT = Symbol('lstat')
const ONLSTAT = Symbol('onlstat')
const ONREAD = Symbol('onread')
const ONREADLINK = Symbol('onreadlink')
const OPENFILE = Symbol('openfile')
const ONOPENFILE = Symbol('onopenfile')
const CLOSE = Symbol('close')

class WriteEntry extends MiniPass {
  constructor (p, opt) {
    opt = opt || {}
    super(opt)
    if (typeof p !== 'string')
      throw new TypeError('path is required')
    this.path = p
    // suppress atime, ctime, uid, gid, uname, gname
    this.portable = !!opt.portable
    // until node has builtin pwnam functions, this'll have to do
    this.myuid = process.getuid && process.getuid()
    this.myuser = process.env.USER || ''
    this.maxReadSize = opt.maxReadSize || maxReadSize
    this.linkCache = opt.linkCache || new Map()
    this.statCache = opt.statCache || new Map()
    this.preservePaths = !!opt.preservePaths
    this.cwd = opt.cwd || process.cwd()
    this.strict = !!opt.strict
    if (typeof opt.onwarn === 'function')
      this.on('warn', opt.onwarn)

    if (path.isAbsolute(p) && !this.preservePaths) {
      const parsed = path.parse(p)
      this.warn('stripping ' + parsed.root + ' from absolute path', p)
      this.path = p.substr(parsed.root.length)
    }

    this.win32 = !!opt.win32 || process.platform === 'win32'
    if (this.win32) {
      this.path = this.path.replace(/\\/g, '/')
      p = p.replace(/\\/g, '/')
    }

    this.absolute = opt.absolute || path.resolve(this.cwd, p)

    if (this.path === '')
      this.path = './'

    if (this.statCache.has(this.absolute))
      this[ONLSTAT](this.statCache.get(this.absolute))
    else
      this[LSTAT]()
  }

  warn (msg, data) {
    if (!this.strict)
      return this.emit('warn', msg, data)

    const er = new Error(msg)
    er.data = data
    this.emit('error', er)
  }

  [LSTAT] () {
    fs.lstat(this.absolute, (er, stat) => {
      if (er)
        return this.emit('error', er)
      this[ONLSTAT](stat)
    })
  }

  [ONLSTAT] (stat) {
    this.statCache.set(this.absolute, stat)
    this.stat = stat
    if (!stat.isFile())
      stat.size = 0
    this.type = getType(stat)
    this.emit('stat', stat)
    this[PROCESS]()
  }

  [PROCESS] () {
    switch (this.type) {
      case 'File': return this[FILE]()
      case 'Directory': return this[DIRECTORY]()
      case 'SymbolicLink': return this[SYMLINK]()
      // unsupported types are ignored.
      default: return this.end()
    }
  }

  [HEADER] () {
    this.header = new Header({
      path: this.path,
      linkpath: this.linkpath,
      // only the permissions and setuid/setgid/sticky bitflags
      // not the higher-order bits that specify file type
      mode: this.stat.mode & 0o7777,
      uid: this.portable ? null : this.stat.uid,
      gid: this.portable ? null : this.stat.gid,
      size: this.stat.size,
      mtime: this.stat.mtime,
      type: this.type,
      uname: this.portable ? null :
        this.stat.uid === this.myuid ? this.myuser : '',
      atime: this.portable ? null : this.stat.atime,
      ctime: this.portable ? null : this.stat.ctime
    })
    this.header.encode()
    if (this.header.needPax)
      this.write(new Pax({
        atime: this.portable ? null : this.header.atime,
        ctime: this.portable ? null : this.header.ctime,
        gid: this.portable ? null : this.header.gid,
        mtime: this.header.mtime,
        path: this.path,
        linkpath: this.linkpath,
        size: this.size,
        uid: this.portable ? null : this.header.uid,
        uname: this.portable ? null : this.header.uname,
        dev: this.portable ? null : this.stat.dev,
        ino: this.portable ? null : this.stat.ino,
        nlink: this.portable ? null : this.stat.nlink
      }).encode())
    this.write(this.header.block)
  }

  [DIRECTORY] () {
    if (this.path.substr(-1) !== '/')
      this.path += '/'
    this.stat.size = 0
    this[HEADER]()
    this.end()
  }

  [SYMLINK] () {
    fs.readlink(this.absolute, (er, linkpath) => {
      if (er)
        return this.emit('error', er)
      this[ONREADLINK](linkpath)
    })
  }

  [ONREADLINK] (linkpath) {
    this.linkpath = linkpath
    this[HEADER]()
    this.end()
  }

  [HARDLINK] (linkpath) {
    this.type = 'Link'
    this.linkpath = path.relative(this.cwd, linkpath)
    this.stat.size = 0
    this[HEADER]()
    this.end()
  }

  [FILE] () {
    if (this.stat.nlink > 1) {
      const linkKey = this.stat.dev + ':' + this.stat.ino
      if (this.linkCache.has(linkKey)) {
        const linkpath = this.linkCache.get(linkKey)
        if (linkpath.indexOf(this.cwd) === 0)
          return this[HARDLINK](linkpath)
      }
      this.linkCache.set(linkKey, this.absolute)
    }

    this[HEADER]()
    if (this.stat.size === 0)
      return this.end()

    this[OPENFILE]()
  }

  [OPENFILE] () {
    fs.open(this.absolute, 'r', (er, fd) => {
      if (er)
        return this.emit('error', er)
      this[ONOPENFILE](fd)
    })
  }

  [ONOPENFILE] (fd) {
    const blockLen = 512 * Math.ceil(this.stat.size / 512)
    const bufLen = Math.min(blockLen, this.maxReadSize)
    const buf = Buffer.allocUnsafe(bufLen)
    this[READ](fd, buf, 0, buf.length, 0, this.stat.size, blockLen)
  }

  [READ] (fd, buf, offset, length, pos, remain, blockRemain) {
    fs.read(fd, buf, offset, length, pos, (er, bytesRead) => {
      if (er)
        return this[CLOSE](fd, _ => this.emit('error', er))
      this[ONREAD](fd, buf, offset, length, pos, remain, blockRemain, bytesRead)
    })
  }

  [CLOSE] (fd, cb) {
    fs.close(fd, cb)
  }

  [ONREAD] (fd, buf, offset, length, pos, remain, blockRemain, bytesRead) {
    if (bytesRead <= 0 && remain > 0) {
      const er = new Error('unexpected EOF')
      er.path = this.absolute
      er.syscall = 'read'
      er.code = 'EOF'
      this.emit('error', er)
    }

    // null out the rest of the buffer, if we could fit the block padding
    if (bytesRead === remain) {
      for (let i = bytesRead; i < length && bytesRead < blockRemain; i++) {
        buf[i + offset] = 0
        bytesRead ++
        remain ++
      }
    }

    const writeBuf = offset === 0 && bytesRead === buf.length ?
      buf : buf.slice(offset, offset + bytesRead)
    remain -= bytesRead
    blockRemain -= bytesRead
    pos += bytesRead
    offset += bytesRead

    this.write(writeBuf)

    if (!remain) {
      if (blockRemain)
        this.write(Buffer.alloc(blockRemain))
      this.end()
      this[CLOSE](fd, _ => _)
      return
    }

    if (offset >= length) {
      buf = Buffer.allocUnsafe(length)
      offset = 0
    }
    length = buf.length - offset
    this[READ](fd, buf, offset, length, pos, remain, blockRemain)
  }
}

class WriteEntrySync extends WriteEntry {
  constructor (path, opt) {
    super(path, opt)
  }

  [LSTAT] () {
    this[ONLSTAT](fs.lstatSync(this.absolute))
  }

  [SYMLINK] () {
    this[ONREADLINK](fs.readlinkSync(this.absolute))
  }

  [OPENFILE] () {
    this[ONOPENFILE](fs.openSync(this.absolute, 'r'))
  }

  [READ] (fd, buf, offset, length, pos, remain, blockRemain) {
    let threw = true
    try {
      const bytesRead = fs.readSync(fd, buf, offset, length, pos)
      this[ONREAD](fd, buf, offset, length, pos, remain, blockRemain, bytesRead)
      threw = false
    } finally {
      if (threw)
        try { this[CLOSE](fd) } catch (er) {}
    }
  }

  [CLOSE] (fd) {
    fs.closeSync(fd)
  }
}

WriteEntry.Sync = WriteEntrySync

const getType = stat =>
  stat.isFile() ? 'File'
  : stat.isDirectory() ? 'Directory'
  : stat.isSymbolicLink() ? 'SymbolicLink'
  : 'Unsupported'

module.exports = WriteEntry
<commit_msg>maxReadSize is 16mb everywhere else, no point being different<commit_after>'use strict'
const MiniPass = require('minipass')
const Pax = require('./pax.js')
const Header = require('./header.js')
const fs = require('fs')
const path = require('path')

const types = require('./types.js')
const maxReadSize = 16 * 1024 * 1024
const PROCESS = Symbol('process')
const FILE = Symbol('file')
const DIRECTORY = Symbol('directory')
const SYMLINK = Symbol('symlink')
const HARDLINK = Symbol('hardlink')
const HEADER = Symbol('header')
const READ = Symbol('read')
const LSTAT = Symbol('lstat')
const ONLSTAT = Symbol('onlstat')
const ONREAD = Symbol('onread')
const ONREADLINK = Symbol('onreadlink')
const OPENFILE = Symbol('openfile')
const ONOPENFILE = Symbol('onopenfile')
const CLOSE = Symbol('close')

class WriteEntry extends MiniPass {
  constructor (p, opt) {
    opt = opt || {}
    super(opt)
    if (typeof p !== 'string')
      throw new TypeError('path is required')
    this.path = p
    // suppress atime, ctime, uid, gid, uname, gname
    this.portable = !!opt.portable
    // until node has builtin pwnam functions, this'll have to do
    this.myuid = process.getuid && process.getuid()
    this.myuser = process.env.USER || ''
    this.maxReadSize = opt.maxReadSize || maxReadSize
    this.linkCache = opt.linkCache || new Map()
    this.statCache = opt.statCache || new Map()
    this.preservePaths = !!opt.preservePaths
    this.cwd = opt.cwd || process.cwd()
    this.strict = !!opt.strict
    if (typeof opt.onwarn === 'function')
      this.on('warn', opt.onwarn)

    if (path.isAbsolute(p) && !this.preservePaths) {
      const parsed = path.parse(p)
      this.warn('stripping ' + parsed.root + ' from absolute path', p)
      this.path = p.substr(parsed.root.length)
    }

    this.win32 = !!opt.win32 || process.platform === 'win32'
    if (this.win32) {
      this.path = this.path.replace(/\\/g, '/')
      p = p.replace(/\\/g, '/')
    }

    this.absolute = opt.absolute || path.resolve(this.cwd, p)

    if (this.path === '')
      this.path = './'

    if (this.statCache.has(this.absolute))
      this[ONLSTAT](this.statCache.get(this.absolute))
    else
      this[LSTAT]()
  }

  warn (msg, data) {
    if (!this.strict)
      return this.emit('warn', msg, data)

    const er = new Error(msg)
    er.data = data
    this.emit('error', er)
  }

  [LSTAT] () {
    fs.lstat(this.absolute, (er, stat) => {
      if (er)
        return this.emit('error', er)
      this[ONLSTAT](stat)
    })
  }

  [ONLSTAT] (stat) {
    this.statCache.set(this.absolute, stat)
    this.stat = stat
    if (!stat.isFile())
      stat.size = 0
    this.type = getType(stat)
    this.emit('stat', stat)
    this[PROCESS]()
  }

  [PROCESS] () {
    switch (this.type) {
      case 'File': return this[FILE]()
      case 'Directory': return this[DIRECTORY]()
      case 'SymbolicLink': return this[SYMLINK]()
      // unsupported types are ignored.
      default: return this.end()
    }
  }

  [HEADER] () {
    this.header = new Header({
      path: this.path,
      linkpath: this.linkpath,
      // only the permissions and setuid/setgid/sticky bitflags
      // not the higher-order bits that specify file type
      mode: this.stat.mode & 0o7777,
      uid: this.portable ? null : this.stat.uid,
      gid: this.portable ? null : this.stat.gid,
      size: this.stat.size,
      mtime: this.stat.mtime,
      type: this.type,
      uname: this.portable ? null :
        this.stat.uid === this.myuid ? this.myuser : '',
      atime: this.portable ? null : this.stat.atime,
      ctime: this.portable ? null : this.stat.ctime
    })
    this.header.encode()
    if (this.header.needPax)
      this.write(new Pax({
        atime: this.portable ? null : this.header.atime,
        ctime: this.portable ? null : this.header.ctime,
        gid: this.portable ? null : this.header.gid,
        mtime: this.header.mtime,
        path: this.path,
        linkpath: this.linkpath,
        size: this.size,
        uid: this.portable ? null : this.header.uid,
        uname: this.portable ? null : this.header.uname,
        dev: this.portable ? null : this.stat.dev,
        ino: this.portable ? null : this.stat.ino,
        nlink: this.portable ? null : this.stat.nlink
      }).encode())
    this.write(this.header.block)
  }

  [DIRECTORY] () {
    if (this.path.substr(-1) !== '/')
      this.path += '/'
    this.stat.size = 0
    this[HEADER]()
    this.end()
  }

  [SYMLINK] () {
    fs.readlink(this.absolute, (er, linkpath) => {
      if (er)
        return this.emit('error', er)
      this[ONREADLINK](linkpath)
    })
  }

  [ONREADLINK] (linkpath) {
    this.linkpath = linkpath
    this[HEADER]()
    this.end()
  }

  [HARDLINK] (linkpath) {
    this.type = 'Link'
    this.linkpath = path.relative(this.cwd, linkpath)
    this.stat.size = 0
    this[HEADER]()
    this.end()
  }

  [FILE] () {
    if (this.stat.nlink > 1) {
      const linkKey = this.stat.dev + ':' + this.stat.ino
      if (this.linkCache.has(linkKey)) {
        const linkpath = this.linkCache.get(linkKey)
        if (linkpath.indexOf(this.cwd) === 0)
          return this[HARDLINK](linkpath)
      }
      this.linkCache.set(linkKey, this.absolute)
    }

    this[HEADER]()
    if (this.stat.size === 0)
      return this.end()

    this[OPENFILE]()
  }

  [OPENFILE] () {
    fs.open(this.absolute, 'r', (er, fd) => {
      if (er)
        return this.emit('error', er)
      this[ONOPENFILE](fd)
    })
  }

  [ONOPENFILE] (fd) {
    const blockLen = 512 * Math.ceil(this.stat.size / 512)
    const bufLen = Math.min(blockLen, this.maxReadSize)
    const buf = Buffer.allocUnsafe(bufLen)
    this[READ](fd, buf, 0, buf.length, 0, this.stat.size, blockLen)
  }

  [READ] (fd, buf, offset, length, pos, remain, blockRemain) {
    fs.read(fd, buf, offset, length, pos, (er, bytesRead) => {
      if (er)
        return this[CLOSE](fd, _ => this.emit('error', er))
      this[ONREAD](fd, buf, offset, length, pos, remain, blockRemain, bytesRead)
    })
  }

  [CLOSE] (fd, cb) {
    fs.close(fd, cb)
  }

  [ONREAD] (fd, buf, offset, length, pos, remain, blockRemain, bytesRead) {
    if (bytesRead <= 0 && remain > 0) {
      const er = new Error('unexpected EOF')
      er.path = this.absolute
      er.syscall = 'read'
      er.code = 'EOF'
      this.emit('error', er)
    }

    // null out the rest of the buffer, if we could fit the block padding
    if (bytesRead === remain) {
      for (let i = bytesRead; i < length && bytesRead < blockRemain; i++) {
        buf[i + offset] = 0
        bytesRead ++
        remain ++
      }
    }

    const writeBuf = offset === 0 && bytesRead === buf.length ?
      buf : buf.slice(offset, offset + bytesRead)
    remain -= bytesRead
    blockRemain -= bytesRead
    pos += bytesRead
    offset += bytesRead

    this.write(writeBuf)

    if (!remain) {
      if (blockRemain)
        this.write(Buffer.alloc(blockRemain))
      this.end()
      this[CLOSE](fd, _ => _)
      return
    }

    if (offset >= length) {
      buf = Buffer.allocUnsafe(length)
      offset = 0
    }
    length = buf.length - offset
    this[READ](fd, buf, offset, length, pos, remain, blockRemain)
  }
}

class WriteEntrySync extends WriteEntry {
  constructor (path, opt) {
    super(path, opt)
  }

  [LSTAT] () {
    this[ONLSTAT](fs.lstatSync(this.absolute))
  }

  [SYMLINK] () {
    this[ONREADLINK](fs.readlinkSync(this.absolute))
  }

  [OPENFILE] () {
    this[ONOPENFILE](fs.openSync(this.absolute, 'r'))
  }

  [READ] (fd, buf, offset, length, pos, remain, blockRemain) {
    let threw = true
    try {
      const bytesRead = fs.readSync(fd, buf, offset, length, pos)
      this[ONREAD](fd, buf, offset, length, pos, remain, blockRemain, bytesRead)
      threw = false
    } finally {
      if (threw)
        try { this[CLOSE](fd) } catch (er) {}
    }
  }

  [CLOSE] (fd) {
    fs.closeSync(fd)
  }
}

WriteEntry.Sync = WriteEntrySync

const getType = stat =>
  stat.isFile() ? 'File'
  : stat.isDirectory() ? 'Directory'
  : stat.isSymbolicLink() ? 'SymbolicLink'
  : 'Unsupported'

module.exports = WriteEntry
<|endoftext|>


<commit_before>import { loadState } from '../../../localStorage';
import defaults from '../../../API_config';
import asyncFetch from './asyncFetch';

function getAuthToken() {
  // We load it from the local storage.
  const loadedState = loadState();
  return loadedState.app.authentication.authToken
    ? loadedState.app.authentication.authToken
    : null;

}

/**
 * Represents an API request.
 * @returns {{}}
 * @constructor
 */
function ApiRequest() {
  const that = {};

  that.headers = {
    'Content-Type': 'application/vnd.api+json',
  };

  // try to get the auth token from the store:
  const tryToken = getAuthToken();
  if (tryToken) {
    that.headers.Authorization = `Bearer ${tryToken}`;
  }
  that.parameters = {};

  that.port = defaults.port ? parseInt(defaults.port, 10) : undefined;
  that.host = defaults.host ? defaults.host : undefined;

  /**
   * Set the last part of the url to which to make the request
   * @param endpoint
   * @returns {{}}
   */
  that.setEndpoint = endpoint => {
    that.endPoint = endpoint;
    return that;
  };

  /**
   * Set the port to which to send the request. Set to whatever is in the API_config file by default.
   * @param port
   * @returns {{}}
   */
  that.setPort = port => {
    if (isNaN(port)) {
      throw new Error(`Port must be an integer (received ${port} instead).`);
    }
    that.port = port;
    return that;
  };

  /**
   * Set the host to which to send the request. Set to whatever is in the API_config file by default.
   * @param host
   * @returns {{}}
   */
  that.setHost = host => {
    that.host = host;
    return that;
  };

  /**
   * Set the type of http request to make.
   * @param type Type of the request. Must be one of ('GET', 'POST', 'PUT', 'PATCH', 'DELETE')
   * @returns {{}}
   */
  that.setMethod = type => {
    // Check it's a valid type:
    if (['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].indexOf(type) === -1) {
      throw new Error(
        `Invalid request method: '${type}'. Must be one of ('GET', 'POST', 'PUT', 'PATCH', 'DELETE')`,
      );
    }

    // If attempting to set 'GET': check it doesn't have a body
    if (type === 'GET' && that.body) {
      throw new Error(
        `Error: Attempting to use a 'GET' request but there is a body.`,
      );
    }

    // If attempting to set 'GET': check it doesn't have a body
    if (type in ['POST', 'PUT', 'PATCH', 'DELETE'] && that.parameters) {
      throw new Error(
        `Error: Attempting to use a '${type}' request but there are url parameters.`,
      );
    }

    that.method = type;
    return that;
  };

  /**
   * Add a header to the http request
   * @param headerName
   * @param headerValue
   * @returns {{}}
   */
  that.addHeader = (headerName, headerValue) => {
    // Check it's not an authentication header. that one is included by default.
    if (headerName === 'Authentication') {
      throw new Error(
        `Invalid header 'Authentication': No need to specify an authentication header, it's included by default.`,
      );
    } else {
      that.headers[headerName] = headerValue;
      return that;
    }
  };

  /**
   * Set the body of the http request. Only works if it's not a 'GET' request.
   * @param body
   * @returns {{}}
   */
  that.setBody = body => {
    // Check we're not trying to add a body to a GET request
    if (that.method === 'GET') {
      throw new Error(`Can't add a body to a GET request.`);
    }
    that.body = JSON.stringify(body);
    return that;
  };

  /**
   * Add a parameter to the request. Only works for GET requests.
   * @param paramName
   * @param paramVal
   * @returns {{}}
   */
  that.addParameter = (paramName, paramVal) => {
    // Check we're not adding parameters to something else than a GET:
    if (that.method !== 'GET') {
      throw new Error(`Can't add url parameters to a ${that.method} request!`);
    }

    that.parameters[paramName] = paramVal;
    return that;
  };

  /**
   * Execute the request and return a promise which will resolve with the response.
   * @returns {Promise}
   */
  that.executeRequest = async function executeRequest() {
    let url = `http://${that.host}`;
    if (that.port) {
      url += `:${that.port}`;
    }
    if (that.endPoint) {
      url += `/${that.endPoint}`;
    } else {
      throw new Error('Cannot execute request: no endpoint is set!');
    }
    if (that.parameters) {
      const keys = Object.keys(that.parameters);
      keys.forEach((key, index) => {
        const beginChar = index === 0 ? '?' : '&';
        url += `${beginChar}${key}=${that.parameters[key]}`;
      });
    }
    const config = {
      method: that.method,
      headers: that.headers,
      body: that.body,
    };

    return asyncFetch(url, config);
  };
  return that;
}

export default ApiRequest;
<commit_msg>made access to localstorage more safe<commit_after>import { loadState } from '../../../localStorage';
import defaults from '../../../API_config';
import asyncFetch from './asyncFetch';

function getAuthToken() {
  // We load it from the local storage.
  const loadedState = loadState();
  if (loadedState) {
    return loadedState.app.authentication.authToken
      ? loadedState.app.authentication.authToken
      : null;
  }

  return null;
}

/**
 * Represents an API request.
 * @returns {{}}
 * @constructor
 */
function ApiRequest() {
  const that = {};

  that.headers = {
    'Content-Type': 'application/vnd.api+json',
  };

  // try to get the auth token from the store:
  const tryToken = getAuthToken();
  if (tryToken) {
    that.headers.Authorization = `Bearer ${tryToken}`;
  }
  that.parameters = {};

  that.port = defaults.port ? parseInt(defaults.port, 10) : undefined;
  that.host = defaults.host ? defaults.host : undefined;

  /**
   * Set the last part of the url to which to make the request
   * @param endpoint
   * @returns {{}}
   */
  that.setEndpoint = endpoint => {
    that.endPoint = endpoint;
    return that;
  };

  /**
   * Set the port to which to send the request. Set to whatever is in the API_config file by default.
   * @param port
   * @returns {{}}
   */
  that.setPort = port => {
    if (isNaN(port)) {
      throw new Error(`Port must be an integer (received ${port} instead).`);
    }
    that.port = port;
    return that;
  };

  /**
   * Set the host to which to send the request. Set to whatever is in the API_config file by default.
   * @param host
   * @returns {{}}
   */
  that.setHost = host => {
    that.host = host;
    return that;
  };

  /**
   * Set the type of http request to make.
   * @param type Type of the request. Must be one of ('GET', 'POST', 'PUT', 'PATCH', 'DELETE')
   * @returns {{}}
   */
  that.setMethod = type => {
    // Check it's a valid type:
    if (['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].indexOf(type) === -1) {
      throw new Error(
        `Invalid request method: '${type}'. Must be one of ('GET', 'POST', 'PUT', 'PATCH', 'DELETE')`,
      );
    }

    // If attempting to set 'GET': check it doesn't have a body
    if (type === 'GET' && that.body) {
      throw new Error(
        `Error: Attempting to use a 'GET' request but there is a body.`,
      );
    }

    // If attempting to set 'GET': check it doesn't have a body
    if (type in ['POST', 'PUT', 'PATCH', 'DELETE'] && that.parameters) {
      throw new Error(
        `Error: Attempting to use a '${type}' request but there are url parameters.`,
      );
    }

    that.method = type;
    return that;
  };

  /**
   * Add a header to the http request
   * @param headerName
   * @param headerValue
   * @returns {{}}
   */
  that.addHeader = (headerName, headerValue) => {
    // Check it's not an authentication header. that one is included by default.
    if (headerName === 'Authentication') {
      throw new Error(
        `Invalid header 'Authentication': No need to specify an authentication header, it's included by default.`,
      );
    } else {
      that.headers[headerName] = headerValue;
      return that;
    }
  };

  /**
   * Set the body of the http request. Only works if it's not a 'GET' request.
   * @param body
   * @returns {{}}
   */
  that.setBody = body => {
    // Check we're not trying to add a body to a GET request
    if (that.method === 'GET') {
      throw new Error(`Can't add a body to a GET request.`);
    }
    that.body = JSON.stringify(body);
    return that;
  };

  /**
   * Add a parameter to the request. Only works for GET requests.
   * @param paramName
   * @param paramVal
   * @returns {{}}
   */
  that.addParameter = (paramName, paramVal) => {
    // Check we're not adding parameters to something else than a GET:
    if (that.method !== 'GET') {
      throw new Error(`Can't add url parameters to a ${that.method} request!`);
    }

    that.parameters[paramName] = paramVal;
    return that;
  };

  /**
   * Execute the request and return a promise which will resolve with the response.
   * @returns {Promise}
   */
  that.executeRequest = async function executeRequest() {
    let url = `http://${that.host}`;
    if (that.port) {
      url += `:${that.port}`;
    }
    if (that.endPoint) {
      url += `/${that.endPoint}`;
    } else {
      throw new Error('Cannot execute request: no endpoint is set!');
    }
    if (that.parameters) {
      const keys = Object.keys(that.parameters);
      keys.forEach((key, index) => {
        const beginChar = index === 0 ? '?' : '&';
        url += `${beginChar}${key}=${that.parameters[key]}`;
      });
    }
    const config = {
      method: that.method,
      headers: that.headers,
      body: that.body,
    };

    return asyncFetch(url, config);
  };
  return that;
}

export default ApiRequest;
<|endoftext|>


<commit_before>import { findConstructor, getconstructorParams, toFixed } from '../utils/utils'

export function getEncodedABIClientSide(web3, abi, state, vals, crowdsaleNum, cb) {
	//console.log(web3, abi, state, vals, crowdsaleNum);
	const abiConstructor = findConstructor(abi, state)
    let params = getconstructorParams(abiConstructor, state, vals, crowdsaleNum);

    getABIencoded(web3, params.types, params.vals, function(encoded) {
		cb(encoded);
	});
}

function getABIencoded(web3, types, vals, cb) {
	if (vals) {
		for (let i = 0; i < vals.length; i++) {
			let val = vals[i];
			if( Object.prototype.toString.call( val ) === '[object Array]' ) {
				for (let j = 0; j < val.length; j++) {
			    	if (val[j]) {
			    		vals[i][j] = toFixed(val[j]);
			    	}
			    }
			}
		}
	}

	console.log(types);
	console.log(vals);

	let encoded = web3.eth.abi.encodeParameters(types, vals);
	cb(encoded.toString("hex"));
}<commit_msg>ABI encoded parameters without 0x<commit_after>import { findConstructor, getconstructorParams, toFixed } from '../utils/utils'

export function getEncodedABIClientSide(web3, abi, state, vals, crowdsaleNum, cb) {
	//console.log(web3, abi, state, vals, crowdsaleNum);
	const abiConstructor = findConstructor(abi, state)
    let params = getconstructorParams(abiConstructor, state, vals, crowdsaleNum);

    getABIencoded(web3, params.types, params.vals, function(encoded) {
		cb(encoded);
	});
}

function getABIencoded(web3, types, vals, cb) {
	if (vals) {
		for (let i = 0; i < vals.length; i++) {
			let val = vals[i];
			if( Object.prototype.toString.call( val ) === '[object Array]' ) {
				for (let j = 0; j < val.length; j++) {
			    	if (val[j]) {
			    		vals[i][j] = toFixed(val[j]);
			    	}
			    }
			}
		}
	}

	console.log(types);
	console.log(vals);

	let encoded = web3.eth.abi.encodeParameters(types, vals);
	let outputRaw = encoded.toString("hex")
	let output = outputRaw.indexOf("0x") > -1?outputRaw.substr(2):outputRaw
	cb(output);
}<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import CSSTransitionGroup from 'react-addons-css-transition-group';
import uniqueId from 'lodash/fp/uniqueId';
import cx from 'classnames';

import noop from '../../../utils/noop';
import css from './FormSelect.css';

import Select from './Select';

export default class FormSelect extends Component {
  static propTypes = {
    name: PropTypes.string.isRequired,
    onChange: PropTypes.func,
    label: PropTypes.string,
    error: PropTypes.string,
    optional: PropTypes.bool,
    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    optionalLabel: PropTypes.string,
    description: PropTypes.node,
    className: PropTypes.string,
    value: PropTypes.string,
    children: PropTypes.node.isRequired,
  };

  static defaultProps = {
    onChange: noop,
    onFocus: noop,
    onBlur: noop,
    value: '',
    error: '',
  };

  constructor(props) {
    super(props);

    this.id = uniqueId('formselect');
  }

  state = {
    hasFocus: false,
  };

  focus = () => {
    this.select.focus();
    this.handleFocus();
  };

  blur = () => {
    this.select.blur();
    this.handleBlur();
  };

  handleFocus = () => {
    const { onFocus } = this.props;
    this.setState({
      hasFocus: true,
    }, onFocus);
  };

  handleBlur = () => {
    const { onBlur } = this.props;
    this.setState({
      hasFocus: false,
    }, onBlur);
  };

  render() {
    const { hasFocus } = this.state;
    const {
      label,
      value,
      description,
      optional,
      optionalLabel,
      error,
      name,
      className,
      onChange,
      children,
      ...rest,
    } = this.props;

    const labelClasses = cx(
      css.label,
      hasFocus || (value && value.length) > 0 ? css.labelFocused : null,
      error ? css.labelErrored : null,
    );

    const inputClasses = cx(
      css.input,
      hasFocus ? css.inputFocused : null,
      error ? css.inputErrored : null,
    );

    const describedBy = `${this.id}-description`;

    return (

          { label } { optional && (

              { optionalLabel }

          ) }

          <Select
            { ...rest }
            id={ this.id }
            ref={ (c) => { this.select = c; } }
            className={ inputClasses }
            onFocus={ this.handleFocus }
            onBlur={ this.handleBlur }
            onChange={ onChange }
            value={ value }
            aria-describedby={ describedBy }
            required={ !optional }
            name={ name }
            hasError={ !!error }
          >
            { children }
          </Select>

          { description && (

              { description }

          ) }
          <CSSTransitionGroup
            transitionName={ css }
            transitionEnterTimeout={ 500 }
            transitionLeaveTimeout={ 300 }
            transitionAppearTimeout={ 500 }
            transitionAppear
          >
            { error && error.length > 0 && (

                { error }

            ) }
          </CSSTransitionGroup>

    );
  }
}
<commit_msg>Allow `FormSelect` value prop to be an array<commit_after>import React, { Component, PropTypes } from 'react';
import CSSTransitionGroup from 'react-addons-css-transition-group';
import uniqueId from 'lodash/fp/uniqueId';
import cx from 'classnames';

import noop from '../../../utils/noop';
import css from './FormSelect.css';

import Select from './Select';

export default class FormSelect extends Component {
  static propTypes = {
    name: PropTypes.string.isRequired,
    onChange: PropTypes.func,
    label: PropTypes.string,
    error: PropTypes.string,
    optional: PropTypes.bool,
    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    optionalLabel: PropTypes.string,
    description: PropTypes.node,
    className: PropTypes.string,
    value: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.array,
    ]),
    children: PropTypes.node.isRequired,
  };

  static defaultProps = {
    onChange: noop,
    onFocus: noop,
    onBlur: noop,
    value: '',
    error: '',
  };

  constructor(props) {
    super(props);

    this.id = uniqueId('formselect');
  }

  state = {
    hasFocus: false,
  };

  focus = () => {
    this.select.focus();
    this.handleFocus();
  };

  blur = () => {
    this.select.blur();
    this.handleBlur();
  };

  handleFocus = () => {
    const { onFocus } = this.props;
    this.setState({
      hasFocus: true,
    }, onFocus);
  };

  handleBlur = () => {
    const { onBlur } = this.props;
    this.setState({
      hasFocus: false,
    }, onBlur);
  };

  render() {
    const { hasFocus } = this.state;
    const {
      label,
      value,
      description,
      optional,
      optionalLabel,
      error,
      name,
      className,
      onChange,
      children,
      ...rest,
    } = this.props;

    const labelClasses = cx(
      css.label,
      hasFocus || (value && value.length) > 0 ? css.labelFocused : null,
      error ? css.labelErrored : null,
    );

    const inputClasses = cx(
      css.input,
      hasFocus ? css.inputFocused : null,
      error ? css.inputErrored : null,
    );

    const describedBy = `${this.id}-description`;

    return (

          { label } { optional && (

              { optionalLabel }

          ) }

          <Select
            { ...rest }
            id={ this.id }
            ref={ (c) => { this.select = c; } }
            className={ inputClasses }
            onFocus={ this.handleFocus }
            onBlur={ this.handleBlur }
            onChange={ onChange }
            value={ value }
            aria-describedby={ describedBy }
            required={ !optional }
            name={ name }
            hasError={ !!error }
          >
            { children }
          </Select>

          { description && (

              { description }

          ) }
          <CSSTransitionGroup
            transitionName={ css }
            transitionEnterTimeout={ 500 }
            transitionLeaveTimeout={ 300 }
            transitionAppearTimeout={ 500 }
            transitionAppear
          >
            { error && error.length > 0 && (

                { error }

            ) }
          </CSSTransitionGroup>

    );
  }
}
<|endoftext|>