<commit_before>'use strict';

/**
 * @ngdoc service
 * @name vega-lite-ui.logger
 * @description
 * # logger
 * Service in the vega-lite-ui.
 */
angular.module('vlui')
  .service('Logger', function ($location, $window, $webSql, consts, Papa, Blob, URL) {

    var service = {};

    // get user id once in the beginning
    var user = $location.search().user;

    service.db = $webSql.openDatabase('logs', '1.0', 'Logs', 2 * 1024 * 1024);

    service.tableName = 'log_' + consts.appId;

    service.actions = {
      INITIALIZE: 'INITIALIZE',
      UNDO: 'UNDO',
      REDO: 'REDO',
      DATASET_CHANGE: 'DATASET_CHANGE',
      CHART_MOUSEOVER: 'CHART_MOUSEOVER',
      CHART_MOUSEOUT: 'CHART_MOUSEOUT',
      CHART_RENDER: 'CHART_RENDER',
      CHART_EXPOSE: 'CHART_EXPOSE',
      CHART_TOOLTIP: 'CHART_TOOLTIP',
      CHART_TOOLTIP_END: 'CHART_TOOLTIP_END',
      BOOKMARK_ADD: 'BOOKMARK_ADD',
      BOOKMARK_REMOVE: 'BOOKMARK_REMOVE',
      BOOKMARKS_CLEAR: 'BOOKMARKS_CLEAR',

      NULL_FILTER_TOGGLE: 'NULL_FILTER_TOGGLE',
      TRANSPOSE_TOGGLE: 'TRANSPOSE_TOGGLE',
      SORT_TOGGLE: 'SORT_TOGGLE',
      MARKTYPE_TOGGLE: 'MARKTYPE_TOGGLE',
      LOG_TOGGLE: 'LOG_TOGGLE',

      FUNC_CHANGE: 'FUNC_CHANGE',
      // Polestar only
      SPEC_CHANGE: 'SPEC_CHANGE',
      FIELD_DROP: 'FIELD_DROP',
      MARK_CHANGE: 'MARK_CHANGE',
      // Voyager only
      FIELDS_CHANGE: 'FIELDS_CHANGE',
      FIELDS_RESET: 'FIELDS_RESET',
      DRILL_DOWN_OPEN: 'DRILL_DOWN_OPEN',
      DRILL_DOWN_CLOSE: 'DRILL_DOWN_CLOSE',
      CLUSTER_SELECT: 'CLUSTER_SELECT',
      LOAD_MORE: 'LOAD_MORE'
    };

    service.createTableIfNotExists = function() {
      service.db.createTable(service.tableName, {
        'userid':{
          'type': 'INTEGER',
          'null': 'NOT NULL'
        },
        'time':{
          'type': 'TIMESTAMP',
          'null': 'NOT NULL',
          'default': 'CURRENT_TIMESTAMP'
        },
        'action':{
          'type': 'TEXT',
          'null': 'NOT NULL'
        },
        'data': {
          'type': 'TEXT'
        },
        'diff': {
          'type': 'TEXT'
        }
      });
    };

    service.clear = function() {
      var r = $window.confirm('Really clear the logs?');
      if (r === true) {
        service.db.dropTable(service.tableName);
        service.createTableIfNotExists();
      }
    };

    service.export = function() {
      service.db.selectAll(service.tableName).then(function(results) {
        if (results.rows.length === 0) {
          console.warn('No logs');
          return;
        }

        var rows = [];

        for(var i=0; i < results.rows.length; i++) {
          rows.push(results.rows.item(i));
        }
        var csv = Papa.unparse(rows);

        var csvData = new Blob([csv], { type: 'text/csv' });
        var csvUrl = URL.createObjectURL(csvData);

        var element = angular.element('<a/>');
        element.attr({
          href: csvUrl,
          target: '_blank',
          download: service.tableName + '.csv'
        })[0].click();
      });
    };

    service.logInteraction = function(action, data, diff) {
      if (!consts.logging) {
        return;
      }

      // console.log('[Logging] ', action, data);

      var row = {userid: user, action: action};
      if (data !== undefined) {
        row.data = JSON.stringify(data);
      }

      if (diff !== undefined) {
        row.diff = JSON.stringify(diff);
      }

      service.db.insert(service.tableName, row).then(function(/*results*/) {});
    };

    service.createTableIfNotExists();
    service.logInteraction(service.actions.INITIALIZE);

    return service;
  });
<commit_msg>add init log to check for https://github.com/uwdata/vega-lite-ui/issues/14<commit_after>'use strict';

/**
 * @ngdoc service
 * @name vega-lite-ui.logger
 * @description
 * # logger
 * Service in the vega-lite-ui.
 */
angular.module('vlui')
  .service('Logger', function ($location, $window, $webSql, consts, Papa, Blob, URL) {

    var service = {};

    // get user id once in the beginning
    var user = $location.search().user;

    service.db = $webSql.openDatabase('logs', '1.0', 'Logs', 2 * 1024 * 1024);

    service.tableName = 'log_' + consts.appId;

    service.actions = {
      INITIALIZE: 'INITIALIZE',
      UNDO: 'UNDO',
      REDO: 'REDO',
      DATASET_CHANGE: 'DATASET_CHANGE',
      CHART_MOUSEOVER: 'CHART_MOUSEOVER',
      CHART_MOUSEOUT: 'CHART_MOUSEOUT',
      CHART_RENDER: 'CHART_RENDER',
      CHART_EXPOSE: 'CHART_EXPOSE',
      CHART_TOOLTIP: 'CHART_TOOLTIP',
      CHART_TOOLTIP_END: 'CHART_TOOLTIP_END',
      BOOKMARK_ADD: 'BOOKMARK_ADD',
      BOOKMARK_REMOVE: 'BOOKMARK_REMOVE',
      BOOKMARKS_CLEAR: 'BOOKMARKS_CLEAR',

      NULL_FILTER_TOGGLE: 'NULL_FILTER_TOGGLE',
      TRANSPOSE_TOGGLE: 'TRANSPOSE_TOGGLE',
      SORT_TOGGLE: 'SORT_TOGGLE',
      MARKTYPE_TOGGLE: 'MARKTYPE_TOGGLE',
      LOG_TOGGLE: 'LOG_TOGGLE',

      FUNC_CHANGE: 'FUNC_CHANGE',
      // Polestar only
      SPEC_CHANGE: 'SPEC_CHANGE',
      FIELD_DROP: 'FIELD_DROP',
      MARK_CHANGE: 'MARK_CHANGE',
      // Voyager only
      FIELDS_CHANGE: 'FIELDS_CHANGE',
      FIELDS_RESET: 'FIELDS_RESET',
      DRILL_DOWN_OPEN: 'DRILL_DOWN_OPEN',
      DRILL_DOWN_CLOSE: 'DRILL_DOWN_CLOSE',
      CLUSTER_SELECT: 'CLUSTER_SELECT',
      LOAD_MORE: 'LOAD_MORE'
    };

    service.createTableIfNotExists = function() {
      service.db.createTable(service.tableName, {
        'userid':{
          'type': 'INTEGER',
          'null': 'NOT NULL'
        },
        'time':{
          'type': 'TIMESTAMP',
          'null': 'NOT NULL',
          'default': 'CURRENT_TIMESTAMP'
        },
        'action':{
          'type': 'TEXT',
          'null': 'NOT NULL'
        },
        'data': {
          'type': 'TEXT'
        },
        'diff': {
          'type': 'TEXT'
        }
      });
    };

    service.clear = function() {
      var r = $window.confirm('Really clear the logs?');
      if (r === true) {
        service.db.dropTable(service.tableName);
        service.createTableIfNotExists();
      }
    };

    service.export = function() {
      service.db.selectAll(service.tableName).then(function(results) {
        if (results.rows.length === 0) {
          console.warn('No logs');
          return;
        }

        var rows = [];

        for(var i=0; i < results.rows.length; i++) {
          rows.push(results.rows.item(i));
        }
        var csv = Papa.unparse(rows);

        var csvData = new Blob([csv], { type: 'text/csv' });
        var csvUrl = URL.createObjectURL(csvData);

        var element = angular.element('<a/>');
        element.attr({
          href: csvUrl,
          target: '_blank',
          download: service.tableName + '.csv'
        })[0].click();
      });
    };

    service.logInteraction = function(action, data, diff) {
      if (!consts.logging) {
        return;
      }

      // console.log('[Logging] ', action, data);

      var row = {userid: user, action: action};
      if (data !== undefined) {
        row.data = JSON.stringify(data);
      }

      if (diff !== undefined) {
        row.diff = JSON.stringify(diff);
      }

      service.db.insert(service.tableName, row).then(function(/*results*/) {});
    };

    service.createTableIfNotExists();
    console.log('app:', consts.appId, 'started');
    service.logInteraction(service.actions.INITIALIZE, consts.appId);

    return service;
  });
<|endoftext|>


<commit_before>import { makeStyles, Box } from '@material-ui/core'
import classnames from 'classnames'
import { parse, isValid, format } from 'date-fns/fp'
import { Field, useFormikContext } from 'formik'
import { parsePhoneNumberFromString } from 'libphonenumber-js'
import * as R from 'ramda'
import * as uuid from 'uuid'
import * as Yup from 'yup'

import {
  RadioGroup,
  TextInput,
  Autocomplete
} from 'src/components/inputs/formik'
import { H4 } from 'src/components/typography'
import { errorColor } from 'src/styling/variables'
import { MANUAL } from 'src/utils/constants'

import { Upload } from './components'

const useStyles = makeStyles({
  radio: {
    padding: 4,
    margin: 4
  },
  radioGroup: {
    flexDirection: 'row'
  },
  error: {
    color: errorColor
  },
  specialLabel: {
    height: 40,
    padding: 0,
    width: 250
  },
  label: {
    height: 40,
    padding: 0
  },
  specialGrid: {
    display: 'grid',
    gridTemplateColumns: [[182, 162, 141]]
  },
  picker: {
    width: 150
  },
  field: {
    '& > *:last-child': {
      marginBottom: 24
    }
  }
})

const CUSTOMER_BLOCKED = 'blocked'
const CUSTOM = 'custom'
const REQUIREMENT = 'requirement'
const ID_CARD_DATA = 'idCardData'

const getAuthorizedStatus = (it, triggers, customRequests) => {
  const fields = R.concat(
    ['frontCamera', 'idCardData', 'idCardPhoto', 'usSsn', 'sanctions'],
    R.map(ite => ite.id, customRequests)
  )
  const fieldsWithPathSuffix = ['frontCamera', 'idCardPhoto']

  const isManualField = fieldName => {
    const triggerName = R.equals(fieldName, 'frontCamera')
      ? 'facephoto'
      : fieldName
    const manualOverrides = R.filter(
      ite => R.equals(R.toLower(ite.automation), MANUAL),
      triggers?.overrides ?? []
    )

    return (
      !!R.find(
        ite => R.equals(ite.requirement, triggerName),
        manualOverrides
      ) || R.equals(R.toLower(triggers.automation), MANUAL)
    )
  }

  const pendingFieldStatus = R.map(ite => {
    if (isManualField(ite)) {
      if (uuid.validate(ite)) {
        const request = R.find(
          iter => iter.infoRequestId === ite,
          it.customInfoRequests
        )
        return !R.isNil(request) && R.equals(request.override, 'automatic')
      }

      const regularFieldValue = R.includes(ite, fieldsWithPathSuffix)
        ? it[`${ite}Path`]
        : it[`${ite}`]
      if (R.isNil(regularFieldValue)) return false
      return R.equals(it[`${ite}Override`], 'automatic')
    }
    return false
  }, fields)

  const rejectedFieldStatus = R.map(ite => {
    if (isManualField(ite)) {
      if (uuid.validate(ite)) {
        const request = R.find(
          iter => iter.infoRequestId === ite,
          it.customInfoRequests
        )
        return !R.isNil(request) && R.equals(request.override, 'blocked')
      }

      const regularFieldValue = R.includes(ite, fieldsWithPathSuffix)
        ? it[`${ite}Path`]
        : it[`${ite}`]
      if (R.isNil(regularFieldValue)) return false
      return R.equals(it[`${ite}Override`], 'blocked')
    }
    return false
  }, fields)

  if (it.authorizedOverride === CUSTOMER_BLOCKED)
    return { label: 'Blocked', type: 'error' }
  if (it.isSuspended)
    return it.daysSuspended > 0
      ? { label: `${it.daysSuspended} day suspension`, type: 'warning' }
      : { label: `< 1 day suspension`, type: 'warning' }
  if (R.any(ite => ite === true, rejectedFieldStatus))
    return { label: 'Rejected', type: 'error' }
  if (R.any(ite => ite === true, pendingFieldStatus))
    return { label: 'Pending', type: 'warning' }
  return { label: 'Authorized', type: 'success' }
}

const getFormattedPhone = (phone, country) => {
  const phoneNumber =
    phone && country ? parsePhoneNumberFromString(phone, country) : null

  return phoneNumber ? phoneNumber.formatInternational() : phone
}

const getName = it => {
  const idData = R.path(['idCardData'])(it)

  return `${R.path(['firstName'])(idData) ?? ''} ${R.path(['lastName'])(
    idData
  ) ?? ''}`.trim()
}

// Manual Entry Wizard

const entryOptions = [
  { display: 'Custom entry', code: 'custom' },
  { display: 'Populate existing requirement', code: 'requirement' }
]

const dataOptions = [
  { display: 'Text', code: 'text' }
  // TODO: Requires backend modifications to support File and Image
  // { display: 'File', code: 'file' },
  // { display: 'Image', code: 'image' }
]

const requirementOptions = [
  { display: 'ID card image', code: 'idCardPhoto' },
  { display: 'ID data', code: 'idCardData' },
  { display: 'US SSN', code: 'usSsn' },
  { display: 'Customer camera', code: 'frontCamera' }
]

const customTextOptions = [
  { label: 'Data entry title', name: 'title' },
  { label: 'Data entry', name: 'data' }
]

const customUploadOptions = [{ label: 'Data entry title', name: 'title' }]

const entryTypeSchema = Yup.lazy(values => {
  if (values.entryType === 'custom') {
    return Yup.object().shape({
      entryType: Yup.string().required(),
      dataType: Yup.string().required()
    })
  } else if (values.entryType === 'requirement') {
    return Yup.object().shape({
      entryType: Yup.string().required(),
      requirement: Yup.string().required()
    })
  }
})

const customFileSchema = Yup.object().shape({
  title: Yup.string().required(),
  file: Yup.mixed().required()
})

const customImageSchema = Yup.object().shape({
  title: Yup.string().required(),
  image: Yup.mixed().required()
})

const customTextSchema = Yup.object().shape({
  title: Yup.string().required(),
  data: Yup.string().required()
})

const updateRequirementOptions = it => [
  {
    display: 'Custom information requirement',
    code: 'custom'
  },
  ...it
]

const EntryType = ({ customInfoRequirementOptions }) => {
  const classes = useStyles()
  const { values } = useFormikContext()

  const displayCustomOptions = values.entryType === CUSTOM
  const displayRequirementOptions = values.entryType === REQUIREMENT

  return (
    <>
      <Box display="flex" alignItems="center">

Type of entry

      </Box>
      <Field
        component={RadioGroup}
        name="entryType"
        options={entryOptions}
        labelClassName={classes.specialLabel}
        radioClassName={classes.radio}
        className={classnames(classes.radioGroup, classes.specialGrid)}
      />
      {displayCustomOptions && (

          <Box display="flex" alignItems="center">

Type of data

          </Box>
          <Field
            component={RadioGroup}
            name="dataType"
            options={dataOptions}
            labelClassName={classes.label}
            radioClassName={classes.radio}
            className={classnames(classes.radioGroup, classes.specialGrid)}
          />

      )}
      {displayRequirementOptions && (

          <Box display="flex" alignItems="center">

Requirements

          </Box>
          <Field
            component={RadioGroup}
            name="requirement"
            options={
              requirementOptions
              // TODO: Enable once custom info requirement manual entry is finished
              // !R.isEmpty(customInfoRequirementOptions)
              //   ? updateRequirementOptions(requirementOptions)
              //   : requirementOptions
            }
            labelClassName={classes.label}
            radioClassName={classes.radio}
            className={classnames(classes.radioGroup, classes.specialGrid)}
          />

      )}
    </>
  )
}

const ManualDataEntry = ({ selectedValues, customInfoRequirementOptions }) => {
  const classes = useStyles()

  const typeOfEntrySelected = selectedValues?.entryType
  const dataTypeSelected = selectedValues?.dataType
  const requirementSelected = selectedValues?.requirement

  const displayRequirements = typeOfEntrySelected === 'requirement'

  const isCustomInfoRequirement = requirementSelected === CUSTOM

  const updatedRequirementOptions = !R.isEmpty(customInfoRequirementOptions)
    ? updateRequirementOptions(requirementOptions)
    : requirementOptions

  const requirementName = displayRequirements
    ? R.find(R.propEq('code', requirementSelected))(updatedRequirementOptions)
        .display
    : ''

  const title = displayRequirements
    ? `Requirement ${requirementName}`
    : `Custom ${dataTypeSelected} entry`

  const elements = displayRequirements
    ? requirementElements[requirementSelected]
    : customElements[dataTypeSelected]

  const upload = displayRequirements
    ? requirementSelected === 'idCardPhoto' ||
      requirementSelected === 'frontCamera'
    : dataTypeSelected === 'file' || dataTypeSelected === 'image'

  return (
    <>
      <Box display="flex" alignItems="center">

{title}

      </Box>
      {isCustomInfoRequirement && (
        <Autocomplete
          fullWidth
          label={`Available requests`}
          className={classes.picker}
          getOptionSelected={R.eqProps('code')}
          labelProp={'display'}
          options={customInfoRequirementOptions}
          onChange={(evt, it) => {}}
        />
      )}

        {!upload &&
          !isCustomInfoRequirement &&
          elements.options.map(({ label, name }) => (
            <Field
              name={name}
              label={label}
              component={TextInput}
              width={390}
            />
          ))}

      {upload && (
        <Upload
          type={
            displayRequirements ? requirementSelected : dataTypeSelected
          }></Upload>
      )}
    </>
  )
}

const customElements = {
  text: {
    schema: customTextSchema,
    options: customTextOptions,
    Component: ManualDataEntry,
    initialValues: { data: '', title: '' },
    saveType: 'customEntry'
  },
  file: {
    schema: customFileSchema,
    options: customUploadOptions,
    Component: ManualDataEntry,
    initialValues: { file: null, title: '' },
    saveType: 'customEntryUpload'
  },
  image: {
    schema: customImageSchema,
    options: customUploadOptions,
    Component: ManualDataEntry,
    initialValues: { image: null, title: '' },
    saveType: 'customEntryUpload'
  }
}

const entryType = {
  schema: entryTypeSchema,
  options: entryOptions,
  Component: EntryType,
  initialValues: { entryType: '' }
}

// Customer data

const customerDataElements = {
  idCardData: [
    {
      name: 'firstName',
      label: 'First name',
      component: TextInput,
      editable: true
    },
    {
      name: 'documentNumber',
      label: 'ID number',
      component: TextInput,
      editable: true
    },
    {
      name: 'dateOfBirth',
      label: 'Birthdate',
      component: TextInput,
      editable: true
    },
    {
      name: 'gender',
      label: 'Gender',
      component: TextInput,
      editable: true
    },
    {
      name: 'lastName',
      label: 'Last name',
      component: TextInput,
      editable: true
    },
    {
      name: 'expirationDate',
      label: 'Expiration Date',
      component: TextInput,
      editable: true
    },
    {
      name: 'country',
      label: 'Country',
      component: TextInput,
      editable: true
    }
  ],
  usSsn: [
    {
      name: 'usSsn',
      label: 'US SSN',
      component: TextInput,
      size: 190,
      editable: true
    }
  ],
  idCardPhoto: [{ name: 'idCardPhoto' }],
  frontCamera: [{ name: 'frontCamera' }]
}

const customerDataSchemas = {
  idCardData: Yup.object().shape({
    firstName: Yup.string().required(),
    lastName: Yup.string().required(),
    documentNumber: Yup.string().required(),
    dateOfBirth: Yup.string()
      .test({
        test: val => isValid(parse(new Date(), 'yyyy-MM-dd', val))
      })
      .required(),
    gender: Yup.string().required(),
    country: Yup.string().required(),
    expirationDate: Yup.string()
      .test({
        test: val => isValid(parse(new Date(), 'yyyy-MM-dd', val))
      })
      .required()
  }),
  usSsn: Yup.object().shape({
    usSsn: Yup.string().required()
  }),
  idCardPhoto: Yup.object().shape({
    idCardPhoto: Yup.mixed().required()
  }),
  frontCamera: Yup.object().shape({
    frontCamera: Yup.mixed().required()
  })
}

const requirementElements = {
  idCardData: {
    schema: customerDataSchemas.idCardData,
    options: customerDataElements.idCardData,
    Component: ManualDataEntry,
    initialValues: {
      firstName: '',
      lastName: '',
      documentNumber: '',
      dateOfBirth: '',
      gender: '',
      country: '',
      expirationDate: ''
    },
    saveType: 'customerData'
  },
  usSsn: {
    schema: customerDataSchemas.usSsn,
    options: customerDataElements.usSsn,
    Component: ManualDataEntry,
    initialValues: { usSsn: '' },
    saveType: 'customerData'
  },
  idCardPhoto: {
    schema: customerDataSchemas.idCardPhoto,
    options: customerDataElements.idCardPhoto,
    Component: ManualDataEntry,
    initialValues: { idCardPhoto: null },
    saveType: 'customerDataUpload'
  },
  frontCamera: {
    schema: customerDataSchemas.frontCamera,
    options: customerDataElements.frontCamera,
    Component: ManualDataEntry,
    initialValues: { frontCamera: null },
    saveType: 'customerDataUpload'
  },
  custom: {
    // schema: customerDataSchemas.customInfoRequirement,
    Component: ManualDataEntry,
    initialValues: { customInfoRequirement: null },
    saveType: 'customInfoRequirement'
  }
}

const formatDates = values => {
  R.map(
    elem =>
      (values[elem] = format('yyyyMMdd')(
        parse(new Date(), 'yyyy-MM-dd', values[elem])
      ))
  )(['dateOfBirth', 'expirationDate'])
  return values
}

const mapKeys = pair => {
  const [key, value] = pair
  if (key === 'txCustomerPhotoPath' || key === 'frontCameraPath') {
    return ['path', value]
  }
  if (key === 'txCustomerPhotoAt' || key === 'frontCameraAt') {
    return ['date', value]
  }
  return pair
}

const addPhotoDir = R.map(it => {
  const hasFrontCameraData = R.has('id')(it)
  return hasFrontCameraData
    ? { ...it, photoDir: 'operator-data/customersphotos' }
    : { ...it, photoDir: 'front-camera-photo' }
})

const standardizeKeys = R.map(R.compose(R.fromPairs, R.map(mapKeys), R.toPairs))

const filterByPhotoAvailable = R.filter(
  tx => !R.isNil(tx.date) && !R.isNil(tx.path)
)

const formatPhotosData = R.compose(
  filterByPhotoAvailable,
  addPhotoDir,
  standardizeKeys
)

export {
  getAuthorizedStatus,
  getFormattedPhone,
  getName,
  entryType,
  customElements,
  requirementElements,
  formatPhotosData,
  customerDataElements,
  customerDataSchemas,
  formatDates,
  REQUIREMENT,
  CUSTOM,
  ID_CARD_DATA
}
<commit_msg>fix: add default values<commit_after>import { makeStyles, Box } from '@material-ui/core'
import classnames from 'classnames'
import { parse, isValid, format } from 'date-fns/fp'
import { Field, useFormikContext } from 'formik'
import { parsePhoneNumberFromString } from 'libphonenumber-js'
import * as R from 'ramda'
import * as uuid from 'uuid'
import * as Yup from 'yup'

import {
  RadioGroup,
  TextInput,
  Autocomplete
} from 'src/components/inputs/formik'
import { H4 } from 'src/components/typography'
import { errorColor } from 'src/styling/variables'
import { MANUAL } from 'src/utils/constants'

import { Upload } from './components'

const useStyles = makeStyles({
  radio: {
    padding: 4,
    margin: 4
  },
  radioGroup: {
    flexDirection: 'row'
  },
  error: {
    color: errorColor
  },
  specialLabel: {
    height: 40,
    padding: 0,
    width: 250
  },
  label: {
    height: 40,
    padding: 0
  },
  specialGrid: {
    display: 'grid',
    gridTemplateColumns: [[182, 162, 141]]
  },
  picker: {
    width: 150
  },
  field: {
    '& > *:last-child': {
      marginBottom: 24
    }
  }
})

const CUSTOMER_BLOCKED = 'blocked'
const CUSTOM = 'custom'
const REQUIREMENT = 'requirement'
const ID_CARD_DATA = 'idCardData'

const getAuthorizedStatus = (it, triggers, customRequests) => {
  const fields = R.concat(
    ['frontCamera', 'idCardData', 'idCardPhoto', 'usSsn', 'sanctions'],
    R.map(ite => ite.id, customRequests)
  )
  const fieldsWithPathSuffix = ['frontCamera', 'idCardPhoto']

  const isManualField = fieldName => {
    const triggerName = R.equals(fieldName, 'frontCamera')
      ? 'facephoto'
      : fieldName
    const manualOverrides = R.filter(
      ite => R.equals(R.toLower(ite.automation), MANUAL),
      triggers?.overrides ?? []
    )

    return (
      !!R.find(
        ite => R.equals(ite.requirement, triggerName),
        manualOverrides
      ) || R.equals(R.toLower(triggers.automation ?? ''), MANUAL)
    )
  }

  const pendingFieldStatus = R.map(ite => {
    if (isManualField(ite)) {
      if (uuid.validate(ite)) {
        const request = R.find(
          iter => iter.infoRequestId === ite,
          it.customInfoRequests
        )
        return !R.isNil(request) && R.equals(request.override, 'automatic')
      }

      const regularFieldValue = R.includes(ite, fieldsWithPathSuffix)
        ? it[`${ite}Path`]
        : it[`${ite}`]
      if (R.isNil(regularFieldValue)) return false
      return R.equals(it[`${ite}Override`], 'automatic')
    }
    return false
  }, fields)

  const rejectedFieldStatus = R.map(ite => {
    if (isManualField(ite)) {
      if (uuid.validate(ite)) {
        const request = R.find(
          iter => iter.infoRequestId === ite,
          it.customInfoRequests
        )
        return !R.isNil(request) && R.equals(request.override, 'blocked')
      }

      const regularFieldValue = R.includes(ite, fieldsWithPathSuffix)
        ? it[`${ite}Path`]
        : it[`${ite}`]
      if (R.isNil(regularFieldValue)) return false
      return R.equals(it[`${ite}Override`], 'blocked')
    }
    return false
  }, fields)

  if (it.authorizedOverride === CUSTOMER_BLOCKED)
    return { label: 'Blocked', type: 'error' }
  if (it.isSuspended)
    return it.daysSuspended > 0
      ? { label: `${it.daysSuspended} day suspension`, type: 'warning' }
      : { label: `< 1 day suspension`, type: 'warning' }
  if (R.any(ite => ite === true, rejectedFieldStatus))
    return { label: 'Rejected', type: 'error' }
  if (R.any(ite => ite === true, pendingFieldStatus))
    return { label: 'Pending', type: 'warning' }
  return { label: 'Authorized', type: 'success' }
}

const getFormattedPhone = (phone, country) => {
  const phoneNumber =
    phone && country ? parsePhoneNumberFromString(phone, country) : null

  return phoneNumber ? phoneNumber.formatInternational() : phone
}

const getName = it => {
  const idData = R.path(['idCardData'])(it)

  return `${R.path(['firstName'])(idData) ?? ''} ${R.path(['lastName'])(
    idData
  ) ?? ''}`.trim()
}

// Manual Entry Wizard

const entryOptions = [
  { display: 'Custom entry', code: 'custom' },
  { display: 'Populate existing requirement', code: 'requirement' }
]

const dataOptions = [
  { display: 'Text', code: 'text' }
  // TODO: Requires backend modifications to support File and Image
  // { display: 'File', code: 'file' },
  // { display: 'Image', code: 'image' }
]

const requirementOptions = [
  { display: 'ID card image', code: 'idCardPhoto' },
  { display: 'ID data', code: 'idCardData' },
  { display: 'US SSN', code: 'usSsn' },
  { display: 'Customer camera', code: 'frontCamera' }
]

const customTextOptions = [
  { label: 'Data entry title', name: 'title' },
  { label: 'Data entry', name: 'data' }
]

const customUploadOptions = [{ label: 'Data entry title', name: 'title' }]

const entryTypeSchema = Yup.lazy(values => {
  if (values.entryType === 'custom') {
    return Yup.object().shape({
      entryType: Yup.string().required(),
      dataType: Yup.string().required()
    })
  } else if (values.entryType === 'requirement') {
    return Yup.object().shape({
      entryType: Yup.string().required(),
      requirement: Yup.string().required()
    })
  }
})

const customFileSchema = Yup.object().shape({
  title: Yup.string().required(),
  file: Yup.mixed().required()
})

const customImageSchema = Yup.object().shape({
  title: Yup.string().required(),
  image: Yup.mixed().required()
})

const customTextSchema = Yup.object().shape({
  title: Yup.string().required(),
  data: Yup.string().required()
})

const updateRequirementOptions = it => [
  {
    display: 'Custom information requirement',
    code: 'custom'
  },
  ...it
]

const EntryType = ({ customInfoRequirementOptions }) => {
  const classes = useStyles()
  const { values } = useFormikContext()

  const displayCustomOptions = values.entryType === CUSTOM
  const displayRequirementOptions = values.entryType === REQUIREMENT

  return (
    <>
      <Box display="flex" alignItems="center">

Type of entry

      </Box>
      <Field
        component={RadioGroup}
        name="entryType"
        options={entryOptions}
        labelClassName={classes.specialLabel}
        radioClassName={classes.radio}
        className={classnames(classes.radioGroup, classes.specialGrid)}
      />
      {displayCustomOptions && (

          <Box display="flex" alignItems="center">

Type of data

          </Box>
          <Field
            component={RadioGroup}
            name="dataType"
            options={dataOptions}
            labelClassName={classes.label}
            radioClassName={classes.radio}
            className={classnames(classes.radioGroup, classes.specialGrid)}
          />

      )}
      {displayRequirementOptions && (

          <Box display="flex" alignItems="center">

Requirements

          </Box>
          <Field
            component={RadioGroup}
            name="requirement"
            options={
              requirementOptions
              // TODO: Enable once custom info requirement manual entry is finished
              // !R.isEmpty(customInfoRequirementOptions)
              //   ? updateRequirementOptions(requirementOptions)
              //   : requirementOptions
            }
            labelClassName={classes.label}
            radioClassName={classes.radio}
            className={classnames(classes.radioGroup, classes.specialGrid)}
          />

      )}
    </>
  )
}

const ManualDataEntry = ({ selectedValues, customInfoRequirementOptions }) => {
  const classes = useStyles()

  const typeOfEntrySelected = selectedValues?.entryType
  const dataTypeSelected = selectedValues?.dataType
  const requirementSelected = selectedValues?.requirement

  const displayRequirements = typeOfEntrySelected === 'requirement'

  const isCustomInfoRequirement = requirementSelected === CUSTOM

  const updatedRequirementOptions = !R.isEmpty(customInfoRequirementOptions)
    ? updateRequirementOptions(requirementOptions)
    : requirementOptions

  const requirementName = displayRequirements
    ? R.find(R.propEq('code', requirementSelected))(updatedRequirementOptions)
        .display
    : ''

  const title = displayRequirements
    ? `Requirement ${requirementName}`
    : `Custom ${dataTypeSelected} entry`

  const elements = displayRequirements
    ? requirementElements[requirementSelected]
    : customElements[dataTypeSelected]

  const upload = displayRequirements
    ? requirementSelected === 'idCardPhoto' ||
      requirementSelected === 'frontCamera'
    : dataTypeSelected === 'file' || dataTypeSelected === 'image'

  return (
    <>
      <Box display="flex" alignItems="center">

{title}

      </Box>
      {isCustomInfoRequirement && (
        <Autocomplete
          fullWidth
          label={`Available requests`}
          className={classes.picker}
          getOptionSelected={R.eqProps('code')}
          labelProp={'display'}
          options={customInfoRequirementOptions}
          onChange={(evt, it) => {}}
        />
      )}

        {!upload &&
          !isCustomInfoRequirement &&
          elements.options.map(({ label, name }) => (
            <Field
              name={name}
              label={label}
              component={TextInput}
              width={390}
            />
          ))}

      {upload && (
        <Upload
          type={
            displayRequirements ? requirementSelected : dataTypeSelected
          }></Upload>
      )}
    </>
  )
}

const customElements = {
  text: {
    schema: customTextSchema,
    options: customTextOptions,
    Component: ManualDataEntry,
    initialValues: { data: '', title: '' },
    saveType: 'customEntry'
  },
  file: {
    schema: customFileSchema,
    options: customUploadOptions,
    Component: ManualDataEntry,
    initialValues: { file: null, title: '' },
    saveType: 'customEntryUpload'
  },
  image: {
    schema: customImageSchema,
    options: customUploadOptions,
    Component: ManualDataEntry,
    initialValues: { image: null, title: '' },
    saveType: 'customEntryUpload'
  }
}

const entryType = {
  schema: entryTypeSchema,
  options: entryOptions,
  Component: EntryType,
  initialValues: { entryType: '' }
}

// Customer data

const customerDataElements = {
  idCardData: [
    {
      name: 'firstName',
      label: 'First name',
      component: TextInput,
      editable: true
    },
    {
      name: 'documentNumber',
      label: 'ID number',
      component: TextInput,
      editable: true
    },
    {
      name: 'dateOfBirth',
      label: 'Birthdate',
      component: TextInput,
      editable: true
    },
    {
      name: 'gender',
      label: 'Gender',
      component: TextInput,
      editable: true
    },
    {
      name: 'lastName',
      label: 'Last name',
      component: TextInput,
      editable: true
    },
    {
      name: 'expirationDate',
      label: 'Expiration Date',
      component: TextInput,
      editable: true
    },
    {
      name: 'country',
      label: 'Country',
      component: TextInput,
      editable: true
    }
  ],
  usSsn: [
    {
      name: 'usSsn',
      label: 'US SSN',
      component: TextInput,
      size: 190,
      editable: true
    }
  ],
  idCardPhoto: [{ name: 'idCardPhoto' }],
  frontCamera: [{ name: 'frontCamera' }]
}

const customerDataSchemas = {
  idCardData: Yup.object().shape({
    firstName: Yup.string().required(),
    lastName: Yup.string().required(),
    documentNumber: Yup.string().required(),
    dateOfBirth: Yup.string()
      .test({
        test: val => isValid(parse(new Date(), 'yyyy-MM-dd', val))
      })
      .required(),
    gender: Yup.string().required(),
    country: Yup.string().required(),
    expirationDate: Yup.string()
      .test({
        test: val => isValid(parse(new Date(), 'yyyy-MM-dd', val))
      })
      .required()
  }),
  usSsn: Yup.object().shape({
    usSsn: Yup.string().required()
  }),
  idCardPhoto: Yup.object().shape({
    idCardPhoto: Yup.mixed().required()
  }),
  frontCamera: Yup.object().shape({
    frontCamera: Yup.mixed().required()
  })
}

const requirementElements = {
  idCardData: {
    schema: customerDataSchemas.idCardData,
    options: customerDataElements.idCardData,
    Component: ManualDataEntry,
    initialValues: {
      firstName: '',
      lastName: '',
      documentNumber: '',
      dateOfBirth: '',
      gender: '',
      country: '',
      expirationDate: ''
    },
    saveType: 'customerData'
  },
  usSsn: {
    schema: customerDataSchemas.usSsn,
    options: customerDataElements.usSsn,
    Component: ManualDataEntry,
    initialValues: { usSsn: '' },
    saveType: 'customerData'
  },
  idCardPhoto: {
    schema: customerDataSchemas.idCardPhoto,
    options: customerDataElements.idCardPhoto,
    Component: ManualDataEntry,
    initialValues: { idCardPhoto: null },
    saveType: 'customerDataUpload'
  },
  frontCamera: {
    schema: customerDataSchemas.frontCamera,
    options: customerDataElements.frontCamera,
    Component: ManualDataEntry,
    initialValues: { frontCamera: null },
    saveType: 'customerDataUpload'
  },
  custom: {
    // schema: customerDataSchemas.customInfoRequirement,
    Component: ManualDataEntry,
    initialValues: { customInfoRequirement: null },
    saveType: 'customInfoRequirement'
  }
}

const formatDates = values => {
  R.map(
    elem =>
      (values[elem] = format('yyyyMMdd')(
        parse(new Date(), 'yyyy-MM-dd', values[elem])
      ))
  )(['dateOfBirth', 'expirationDate'])
  return values
}

const mapKeys = pair => {
  const [key, value] = pair
  if (key === 'txCustomerPhotoPath' || key === 'frontCameraPath') {
    return ['path', value]
  }
  if (key === 'txCustomerPhotoAt' || key === 'frontCameraAt') {
    return ['date', value]
  }
  return pair
}

const addPhotoDir = R.map(it => {
  const hasFrontCameraData = R.has('id')(it)
  return hasFrontCameraData
    ? { ...it, photoDir: 'operator-data/customersphotos' }
    : { ...it, photoDir: 'front-camera-photo' }
})

const standardizeKeys = R.map(R.compose(R.fromPairs, R.map(mapKeys), R.toPairs))

const filterByPhotoAvailable = R.filter(
  tx => !R.isNil(tx.date) && !R.isNil(tx.path)
)

const formatPhotosData = R.compose(
  filterByPhotoAvailable,
  addPhotoDir,
  standardizeKeys
)

export {
  getAuthorizedStatus,
  getFormattedPhone,
  getName,
  entryType,
  customElements,
  requirementElements,
  formatPhotosData,
  customerDataElements,
  customerDataSchemas,
  formatDates,
  REQUIREMENT,
  CUSTOM,
  ID_CARD_DATA
}
<|endoftext|>


<commit_before>initCanvasTextureStuff = function() {
    var self = this;
    this.go = function(onReadyCB) {
        // this kicks everything off.
        var that = this;
        _canvasWidth = canvas.width;
        _canvasHeight = canvas.height;
        self.generator = new generator(onReadyCB);
    };
    this.getCanvas = function() {
        return self.generator.canvas;
    }
};
generator = function(onReadyCB) {
    var PI = Math.PI;
    var self = this;
    this.onReadyCB = onReadyCB;
    this.canvas = document.getElementById('canvas');
    this.ctx = canvas.getContext('2d');
    this.cartesianToPolar = function(x,y,z) {
        var theta;
        var phi;
        phi = Math.atan2(y, x);
        //phi -= (PI/2.0);    // this correction lines up the UV texture nicely.
        if (phi <= 0.0) {
            phi = phi + PI*2.0;
        }
        if (phi >= (2.0 * PI)) {    // allow 2PI since we gen uv over [0,1]
            phi = phi - 2.0 * PI;
        }
        // phi = 2. * PI - phi;        // flip the texture around.
        theta = Math.acos(z);
        return [phi, theta];
    }
    this.uvToComplex = function(u,v) {
        var theta;
        var phi;
        var x;
        var y;
        var z;
        // uv.x = clamp(uv.x,0.001,.999);

        // convert from uv to polar coords
        theta = (1.0-v) * PI;
        phi = PI * 2.0 * u+PI;

        // convert polar to cartesian. Theta is polar, phi is azimuth.
        x = Math.sin(theta)*Math.cos(phi);
        y = Math.sin(theta)*Math.sin(phi);
        z = Math.cos(theta);

        // x,y,z are on the unit sphere.
        // if we pretend that sphere is a riemann sphere, then we
        // can get the corresponding complex point, a.
        // http://math.stackexchange.com/questions/1219406/how-do-i-convert-a-complex-number-to-a-point-on-the-riemann-sphere

        // we added the PI to phi above to make the Y axis correspond with
        // the positive imaginary axis and the X axis correspond with
        //  the positive real axis. So flip y and x around in this next equation.
        return new complex(x/(1.0-z), y/(1.0-z));
    }
    this.complexToUV = function(inx,iny) {
        // now c back to sphere.
        var theta;
        var phi;
        var x;
        var y;
        var z;
        var denom = 1.0 + inx * inx + iny * iny;
        x = 2.0 * inx/denom;
        y = 2.0 * iny/denom;
        z = (inx*inx + iny*iny - 1.0)/denom;
        // console.log(x,y,z);

        // convert to polar
        var polarCoords = self.cartesianToPolar(x,y,z);
        phi = polarCoords[0];
        theta = polarCoords[1];
        // console.log(phi, theta);

        // now get uv in new chart.
        var newv = 1-theta/PI;
        var newu = (phi-PI)/(2.0 * PI);
        if (newu < 0.) newu = newu + 1.0;
        return [newu, newv];
    }
    this.drawGrid = function() {
        for (i = 0; i < self.canvasHeight; i+=10) {
        self.ctx.beginPath();
        self.ctx.moveTo(0, i);
        self.ctx.lineTo(_canvasWidth,i);
        self.ctx.stroke();
        // console.log(i);
        }
    }
    this.drawCPoint = function(x,y, color) {
        var xpt = self.xform.doit(new complex(x,y));
        var pt = self.uvToCanvas( self.complexToUV(xpt.x,xpt.y));
        self.ctx.beginPath();
        // console.log(pt[0],pt[1]);
        self.ctx.arc(
        pt[0],
        pt[1],
        10,2*Math.PI, false);
        self.ctx.fillStyle = color;
        self.ctx.fill();
    }
    this.uvToCanvas = function(pt) {
        // for canvas (0,0) is on upper left
        // for texture uv (0,0) is lower left
        return [pt[0]*_canvasWidth, (1-pt[1])*_canvasHeight];
    }
    this.drawCline = function(x1,y1,x2,y2, color) {
        // self.ctx.fillStyle = 'Green';
        var m = (y2-y1)/(x2-x1);
        var iter=10
        self.ctx.strokeStyle = color;
        self.ctx.beginPath();
        var incr = (x2-x1)/iter;
        var nx = x1;
        for (var i = 0; i <= iter; i++) {
            var ny = m*(nx-x1)+y1;
            var xpt = this.xform.doit(new complex(nx,ny));
            var pt = self.uvToCanvas( self.complexToUV(xpt.x,xpt.y));
            // var pt = self.uvToCanvas( self.complexToUV(nx,ny));
            if (i == 0)
                self.ctx.moveTo(pt[0], pt[1]);
            else
                self.ctx.lineTo(pt[0], pt[1]);
            // this.drawCPoint(nx, ny);
            console.log('--->',nx,ny,color);
            nx = nx + incr;
        }
        self.ctx.stroke();
        self.ctx.strokeStyle = 'Black';
    }
    this.drawCLines = function() {
        self.xform = new xform(_one,_zero,_zero,_one);
        for (i = 0; i < 10; i++) {
        self.drawCline(-100,0.,100.,0.00);
        self.xform = new xform(
            self.xform.a.mult(_two),
            self.xform.b,
            // self.xform.b.add(_one),
            // self.xform.c.pow(_two),
            self.xform.c,
            self.xform.d
        );
        console.log(self.xform.a.x, self.xform.a.y);
        }
    }
    var img = new Image;
    img.onload = function() {
        var tmpCanvas = document.createElement("canvas");
        tmpCanvas.width = self.canvas.width;
        tmpCanvas.height = self.canvas.height;
        var tmpCtx = tmpCanvas.getContext('2d');

        tmpCtx.drawImage(img, 0, 0, img.width,    img.height,
            0, 0, self.canvas.width, self.canvas.height);

        var imgData = tmpCtx.getImageData(0,0,canvas.width,canvas.height);
        var data = imgData.data;

        var oimgData = self.ctx.createImageData(imgData);
        var odata = oimgData.data;
        var radians = -Math.PI/2.;
        var scalar = new complex(Math.cos(radians), Math.sin(radians));
        self.xform = new xform(_one,_zero,_zero,_one);
        self.xform.rotate(5);
        // self.drawCline(0,0.,5.,0.00);
        self.drawCline(1.0,0.,0.,1.0, 'blue');
        self.drawCline(0.0,1.,-1,0.0, 'green');
        self.drawCline(-1,0.0,0,-1, 'red');
        self.drawCline(0,-1,1,0, 'black');
        self.drawCPoint(0, 1, 'red');
        self.drawCPoint(1, 0, 'red');
        self.drawCPoint(0, -1, 'red');
        self.drawCPoint(-1,0, 'red');

        self.drawCPoint(0, .1, 'green');
        self.drawCPoint(.1, 0, 'green');
        self.drawCPoint(0, -.1, 'green');
        self.drawCPoint(-.1,0, 'green');

        self.drawCPoint(0, 10, 'yellow');
        self.drawCPoint(10, 0, 'yellow');
        self.drawCPoint(0, -10, 'yellow');
        self.drawCPoint(-10,0, 'yellow');

        return;
        for(var i=0; i<data.length; i+=4) {
            var red = data[i];
            var green = data[i+1];
            var blue = data[i+2];
            var alpha = data[i+3];
            var pixel = i/4;
            var row = Math.floor(pixel/canvas.width);
            var col = pixel%canvas.width;
            var u = (1.0-row/canvas.height);
            var v = col/canvas.width;
            var complexNumber = self.uvToComplex(u, v);
            var newNumber = self.xform.doit(complexNumber);
            var uv = self.complexToUV(newNumber.x, newNumber.y);
            var uvPixels = [
                Math.round((1-uv[0])*canvas.height),
                Math.round(uv[1]*canvas.width) ];
            var index = 4*(uvPixels[0]*canvas.width + uvPixels[1]);
            if (row%100 == 0 && col == 100)
                console.log(i, index, row,col, uvPixels[0], uvPixels[1]);
            odata[index] = red;
            odata[index+1] = green;
            odata[index+2] = blue;
            odata[index+3] = alpha;
        }
        self.ctx.putImageData(oimgData, 0, 0);

        // self.drawGrid();
        //self.drawCLines();
        console.log("done drawing");
        self.onReadyCB();
    }
    img.src = '../media/C.png';
    // self.ctx.fillRect(25, 25, 100, 100);
}

<commit_msg>Debugging complex math<commit_after>initCanvasTextureStuff = function() {
    var self = this;
    this.go = function(onReadyCB) {
        // this kicks everything off.
        var that = this;
        _canvasWidth = canvas.width;
        _canvasHeight = canvas.height;
        self.generator = new generator(onReadyCB);
    };
    this.getCanvas = function() {
        return self.generator.canvas;
    }
};
generator = function(onReadyCB) {
    var PI = Math.PI;
    var self = this;
    this.onReadyCB = onReadyCB;
    this.canvas = document.getElementById('canvas');
    this.ctx = canvas.getContext('2d');
    this.cartesianToPolar = function(x,y,z) {
        var theta;
        var phi;
        phi = Math.atan2(y, x);
        //phi -= (PI/2.0);    // this correction lines up the UV texture nicely.
        if (phi <= 0.0) {
            phi = phi + PI*2.0;
        }
        if (phi >= (2.0 * PI)) {    // allow 2PI since we gen uv over [0,1]
            phi = phi - 2.0 * PI;
        }
        // phi = 2. * PI - phi;        // flip the texture around.
        theta = Math.acos(z);
        return [phi, theta];
    }
    this.uvToComplex = function(u,v) {
        var theta;
        var phi;
        var x;
        var y;
        var z;
        // uv.x = clamp(uv.x,0.001,.999);

        // convert from uv to polar coords
        theta = (1.0-v) * PI;
        phi = PI * 2.0 * u+PI;

        // convert polar to cartesian. Theta is polar, phi is azimuth.
        x = Math.sin(theta)*Math.cos(phi);
        y = Math.sin(theta)*Math.sin(phi);
        z = Math.cos(theta);

        // x,y,z are on the unit sphere.
        // if we pretend that sphere is a riemann sphere, then we
        // can get the corresponding complex point, a.
        // http://math.stackexchange.com/questions/1219406/how-do-i-convert-a-complex-number-to-a-point-on-the-riemann-sphere

        // we added the PI to phi above to make the Y axis correspond with
        // the positive imaginary axis and the X axis correspond with
        //  the positive real axis. So flip y and x around in this next equation.
        return new complex(x/(1.0-z), y/(1.0-z));
    }
    this.complexToUV = function(inx,iny) {
        // now c back to sphere.
        var theta;
        var phi;
        var x;
        var y;
        var z;
        var denom = 1.0 + inx * inx + iny * iny;
        x = 2.0 * inx/denom;
        y = 2.0 * iny/denom;
        z = (inx*inx + iny*iny - 1.0)/denom;
        // console.log(x,y,z);

        // convert to polar
        var polarCoords = self.cartesianToPolar(x,y,z);
        phi = polarCoords[0];
        theta = polarCoords[1];
        // console.log(phi, theta);

        // now get uv in new chart.
        var newv = 1-theta/PI;
        var newu = (phi-PI)/(2.0 * PI);
        if (newu < 0.) newu = newu + 1.0;
        return [newu, newv];
    }
    this.drawGrid = function() {
        for (i = 0; i < self.canvasHeight; i+=10) {
        self.ctx.beginPath();
        self.ctx.moveTo(0, i);
        self.ctx.lineTo(_canvasWidth,i);
        self.ctx.stroke();
        // console.log(i);
        }
    }
    this.drawCPoint = function(x,y, color) {
        var xpt = self.xform.doit(new complex(x,y));
        var pt = self.uvToCanvas( self.complexToUV(xpt.x,xpt.y));
        self.ctx.beginPath();
        // console.log(pt[0],pt[1]);
        self.ctx.arc(
        pt[0],
        pt[1],
        10,2*Math.PI, false);
        self.ctx.fillStyle = color;
        self.ctx.fill();
    }
    this.uvToCanvas = function(pt) {
        // for canvas (0,0) is on upper left
        // for texture uv (0,0) is lower left
        return [
            Math.round(pt[0]*_canvasWidth),
            Math.round((1-pt[1])*_canvasHeight)
            ];
    }
    this.drawCline = function(x1,y1,x2,y2, color) {
        // self.ctx.fillStyle = 'Green';
        var m = (y2-y1)/(x2-x1);
        var iter=10
        self.ctx.strokeStyle = color;
        self.ctx.beginPath();
        var incr = (x2-x1)/iter;
        var nx = x1;
        for (var i = 0; i <= iter; i++) {
            var ny = m*(nx-x1)+y1;
            var xpt = this.xform.doit(new complex(nx,ny));
            var pt = self.uvToCanvas( self.complexToUV(xpt.x,xpt.y));
            // var pt = self.uvToCanvas( self.complexToUV(nx,ny));
            if (i == 0)
                self.ctx.moveTo(pt[0], pt[1]);
            else
                self.ctx.lineTo(pt[0], pt[1]);
            // this.drawCPoint(nx, ny);
            console.log('--->',nx,ny,color);
            nx = nx + incr;
        }
        self.ctx.stroke();
        self.ctx.strokeStyle = 'Black';
    }
    this.drawCLines = function() {
        self.xform = new xform(_one,_zero,_zero,_one);
        for (i = 0; i < 10; i++) {
        self.drawCline(-100,0.,100.,0.00);
        self.xform = new xform(
            self.xform.a.mult(_two),
            self.xform.b,
            // self.xform.b.add(_one),
            // self.xform.c.pow(_two),
            self.xform.c,
            self.xform.d
        );
        console.log(self.xform.a.x, self.xform.a.y);
        }
    }
    var img = new Image;
    function clamp(x) {
        if (x < 0.0001) x = 0.0001;
        if (x > 0.9999) x = 0.9999;
        return x;
    }
    img.onload = function() {
        var tmpCanvas = document.createElement("canvas");
        tmpCanvas.width = self.canvas.width;
        tmpCanvas.height = self.canvas.height;
        var tmpCtx = tmpCanvas.getContext('2d');

        tmpCtx.drawImage(img, 0, 0, img.width,    img.height,
            0, 0, self.canvas.width, self.canvas.height);

        var imgData = tmpCtx.getImageData(0,0,canvas.width,canvas.height);
        var data = imgData.data;

        var oimgData = self.ctx.createImageData(imgData);
        var odata = oimgData.data;
        var radians = -Math.PI/2.;
        var scalar = new complex(Math.cos(radians), Math.sin(radians));
        self.xform = new xform(_one,_zero,_zero,_one);
        self.xform.zoom(new complex(5,0));

        for(var i=0; i<data.length; i+=4) {
            var red = data[i];
            var green = data[i+1];
            var blue = data[i+2];
            var alpha = data[i+3];
            var pixel = i/4;
            var row = Math.floor(pixel/canvas.width);
            var col = pixel%canvas.width;
            var u = clamp(col/canvas.width);
            var v = clamp(1.0-row/canvas.height);
            var complexNumber = self.uvToComplex(u, v);
            var newNumber = self.xform.doit(complexNumber);
            var uv = self.complexToUV(newNumber.x, newNumber.y);
            var uvPixels = self.uvToCanvas(uv);
            // var uvPixels = [
            //     Math.round((1-uv[0])*canvas.height),
            //     Math.round(uv[1]*canvas.width) ];
            var index = 4*(uvPixels[0] + uvPixels[1]*canvas.width);
            if (row%100 == 0 && col == 100)
                console.log(i, index, row,col, uvPixels[0], uvPixels[1]);
            odata[index] = red;
            odata[index+1] = green;
            odata[index+2] = blue;
            odata[index+3] = alpha;
        }
        self.ctx.putImageData(oimgData, 0, 0);
        // self.drawCline(0,0.,5.,0.00);
        self.drawCline(1.0,0.,0.,1.0, 'blue');
        self.drawCline(0.0,1.,-1,0.0, 'green');
        self.drawCline(-1,0.0,0,-1, 'red');
        self.drawCline(0,-1,1,0, 'black');
        self.drawCPoint(0, 1, 'red');
        self.drawCPoint(1, 0, 'red');
        self.drawCPoint(0, -1, 'red');
        self.drawCPoint(-1,0, 'red');

        self.drawCPoint(0, .1, 'green');
        self.drawCPoint(.1, 0, 'green');
        self.drawCPoint(0, -.1, 'green');
        self.drawCPoint(-.1,0, 'green');

        self.drawCPoint(0, 10, 'blue');
        self.drawCPoint(10, 0, 'blue');
        self.drawCPoint(0, -10, 'blue');
        self.drawCPoint(-10,0, 'blue');

        // self.drawGrid();
        //self.drawCLines();
        console.log("done drawing");
        self.onReadyCB();
    }
    img.src = '../media/C.png';
    // self.ctx.fillRect(25, 25, 100, 100);
}

<|endoftext|>


<commit_before>import {inject} from 'aurelia-dependency-injection';
import {customAttribute, injectStyles, hasShadowDOM} from 'aurelia-templating';

if (hasShadowDOM) {
  injectStyles('body /deep/ .aurelia-hide { display:none !important; }');
} else {
  injectStyles('.aurelia-hide { display:none !important; }');
}

/**
* Binding to conditionally show markup in the DOM based on the value.
* - different from if in that the markup is still added to the DOM, simply not shown
*
* @class Show
* @constructor
* @param {Element} element The element that the to bind to
*/
@customAttribute('show')
@inject(Element)
export class Show {
  constructor(element) {
    this.element = element;
  }

  valueChanged(newValue) {
    if (newValue) {
      this.element.classList.remove('aurelia-hide');
    } else {
      this.element.classList.add('aurelia-hide');
    }
  }

  bind(bindingContext) {
    this.valueChanged(this.value);
  }
}
<commit_msg>fix(show): use animator for class manipulation<commit_after>import {inject} from 'aurelia-dependency-injection';
import {customAttribute, injectStyles, hasShadowDOM, Animator} from 'aurelia-templating';

if (hasShadowDOM) {
  injectStyles('body /deep/ .aurelia-hide { display:none !important; }');
} else {
  injectStyles('.aurelia-hide { display:none !important; }');
}

/**
* Binding to conditionally show markup in the DOM based on the value.
* - different from if in that the markup is still added to the DOM, simply not shown
*
* @class Show
* @constructor
* @param {Element} element The element that the to bind to
*/
@customAttribute('show')
@inject(Element, Animator)
export class Show {
  constructor(element, animator) {
    this.element = element;
    this.animator = animator;
  }

  valueChanged(newValue) {
    if (newValue) {
      this.animator.removeClass(this.element, 'aurelia-hide');
    } else {
      this.animator.addClass(this.element, 'aurelia-hide');
    }
  }

  bind(bindingContext) {
    this.valueChanged(this.value);
  }
}
<|endoftext|>


<commit_before>/*jshint browser: true*/

var makeClass = require('../makeClass');

module.exports = makeClass({

    constructor: function DOMBackend() {
        var element = document.createElement('style');
        this._sheet = element.sheet;
        document.head.appendChild(element);
    },

    add: function (id, rule) {
        var sheet = this._sheet;
        var length = sheet.cssRules.length;
        sheet.insertRule(rule, length);
        sheet.cssRules[length].__styleId = id;
    },

    remove: function (id) {
        var sheet = this._sheet;
        var i;
        for (i = sheet.cssRules.length - 1; i >= 0; i--) {
            if (sheet.cssRules[i].__styleId === id) {
                sheet.removeRule(i);
            }
        }
    },

});
<commit_msg>Fix dombackend<commit_after>/*jshint browser: true*/

var makeClass = require('../makeClass');

module.exports = makeClass({

    constructor: function DOMBackend() {
        var element = document.createElement('style');
        document.head.appendChild(element);
        this._sheet = element.sheet;
    },

    add: function (id, rule) {
        var sheet = this._sheet;
        var length = sheet.cssRules.length;
        sheet.insertRule(rule, length);
        sheet.cssRules[length].__styleId = id;
    },

    remove: function (id) {
        var sheet = this._sheet;
        var i;
        for (i = sheet.cssRules.length - 1; i >= 0; i--) {
            if (sheet.cssRules[i].__styleId === id) {
                sheet.removeRule(i);
            }
        }
    },

});
<|endoftext|>


<commit_before>import crypto from "crypto"

const { npm_config__graphene_local_secret_secret } = process.env

if( ! npm_config__graphene_local_secret_secret ) {
    const buf = crypto.randomBytes(256)
    const local_secret = buf.toString('base64')
    console.error("# WARN you need to run this command to lock-in your secret."
    console.error("# Alternatively you could add @graphene/local-secret:secret = xxxxx to ./.npmrc")
    console.error("npm config set @graphene/local-secret:secret '%s'", local_secret)
    console.error()
    process.env.npm_config__graphene_local_secret_secret = local_secret
}

export default process.env.npm_config__graphene_local_secret_secret
<commit_msg>update<commit_after>import crypto from "crypto"

const { npm_config__graphene_local_secret_secret } = process.env

if( ! npm_config__graphene_local_secret_secret ) {
    const buf = crypto.randomBytes(256)
    const local_secret = buf.toString('base64')
    console.error("# WARN you need to run this command to lock-in your secret.")
    console.error("# Alternatively you could add @graphene/local-secret:secret = xxxxx to ./.npmrc")
    console.error("npm config set @graphene/local-secret:secret '%s'", local_secret)
    console.error()
    process.env.npm_config__graphene_local_secret_secret = local_secret
}

export default process.env.npm_config__graphene_local_secret_secret
<|endoftext|>


<commit_before>
define(function (require) {
  'use strict';

  var modules = require('modules');
  var angular = require('angular');

  require('scripts/common/services/search_services'); // make sure that we have the search services loaded.

  modules.get('a4c-auth', ['a4c-search']).factory('quickSearchServices', ['$state','$resource',
    function($state, $resource ) {
      var quickSearchResource = $resource('rest/latest/quicksearch', {}, {
        'search': {
          method : 'POST',
          isArray : false,
          headers : {
            'Content-Type' : 'application/json; charset=UTF-8'
          }
        }
      });

      var openItem = {};
      openItem.indexednodetype = function(componentId){
        $state.go('components.component.detail', { id: componentId });
      };
      openItem.application = function(applicationId){
        $state.go('applications.detail.info', { id: applicationId });
      };

      function getComponentIcon(tags){
        for ( var i in tags) {
          var tag = tags[i];
          if(tag.name === 'icon'){
            return tag.value;
          }
        }
      }

      var quickSearch={};

      quickSearch.doQuickSearch= function(keyword) {
        var searchRequestObject = {
          'query': keyword,
          'from': 0,
          'size': 10
        };
        return quickSearchResource.search([], angular.toJson(searchRequestObject) ).$promise.then(function(result){
          var formatedData=result.data.data;
          for (var i = 0; i < formatedData.length; i++) {
            formatedData[i].type = result.data.types[i];
            if(formatedData[i].type ==='indexednodetype') {
              formatedData[i].icon = getComponentIcon(formatedData[i].tags);
            }
          }
          return formatedData;
        });
      };

      quickSearch.onItemSelected = function(item) {
        openItem[item.type](item.id);
      };

      return quickSearch;
    }
  ]); // factory
}); // define
<commit_msg>[ALIEN-1502] fixed broken quicksearch GOTO in component case<commit_after>
define(function (require) {
  'use strict';

  var modules = require('modules');
  var angular = require('angular');

  require('scripts/common/services/search_services'); // make sure that we have the search services loaded.

  modules.get('a4c-auth', ['a4c-search']).factory('quickSearchServices', ['$state','$resource',
    function($state, $resource ) {
      var quickSearchResource = $resource('rest/latest/quicksearch', {}, {
        'search': {
          method : 'POST',
          isArray : false,
          headers : {
            'Content-Type' : 'application/json; charset=UTF-8'
          }
        }
      });

      var openItem = {};
      openItem.indexednodetype = function(componentId){
        $state.go('components.detail', { id: componentId });
      };
      openItem.application = function(applicationId){
        $state.go('applications.detail.info', { id: applicationId });
      };

      function getComponentIcon(tags){
        for ( var i in tags) {
          var tag = tags[i];
          if(tag.name === 'icon'){
            return tag.value;
          }
        }
      }

      var quickSearch={};

      quickSearch.doQuickSearch= function(keyword) {
        var searchRequestObject = {
          'query': keyword,
          'from': 0,
          'size': 10
        };
        return quickSearchResource.search([], angular.toJson(searchRequestObject) ).$promise.then(function(result){
          var formatedData=result.data.data;
          for (var i = 0; i < formatedData.length; i++) {
            formatedData[i].type = result.data.types[i];
            if(formatedData[i].type ==='indexednodetype') {
              formatedData[i].icon = getComponentIcon(formatedData[i].tags);
            }
          }
          return formatedData;
        });
      };

      quickSearch.onItemSelected = function(item) {
        openItem[item.type](item.id);
      };

      return quickSearch;
    }
  ]); // factory
}); // define
<|endoftext|>


<commit_before>// Configure deployment-specific data here

var chaiseConfig = {
    confirmDelete: true,
    defaultAnnotationColor: 'red',
    feedbackURL: 'http://goo.gl/forms/f30sfheh4H',
    helpURL: '/help/using-the-data-browser/',
    showBadgeCounts: false,
    recordUiGridEnabled: false,
    recordUiGridExportCSVEnabled: true,
    recordUiGridExportPDFEnabled: true,
    tour: {
      pickRandom: false,
      searchInputAttribute: "Data",
      searchChosenAttribute: "Data Type",
      searchInputValue: "micro",
      extraAttribute: "Mouse Anatomic Source",
      chosenAttribute: "Data Type",
      chosenValue: "Expression microarray - gene"
    }
};
<commit_msg>Extended the chaise-config-sample.js file with some parameters.<commit_after>// Configure deployment-specific data here

var chaiseConfig = {
    layout: 'list',
    confirmDelete: true,
    headTitle: 'Chaise',
    customCSS: '/assets/css/chaise.css',
    navbarBrand: '/',
    navbarBrandImage: '/bdds/assets/images/bdds_logo_final.png',
    logoutURL: '/image-annotation',
    dataBrowser: '/',
    maxColumns: 6,
    showUnfilteredResults: false,
    defaultAnnotationColor: 'red',
    feedbackURL: 'http://goo.gl/forms/f30sfheh4H',
    helpURL: '/help/using-the-data-browser/',
    showBadgeCounts: false,
    recordUiGridEnabled: false,
    recordUiGridExportCSVEnabled: true,
    recordUiGridExportPDFEnabled: true,
    tour: {
      pickRandom: false,
      searchInputAttribute: "Data",
      searchChosenAttribute: "Data Type",
      searchInputValue: "micro",
      extraAttribute: "Mouse Anatomic Source",
      chosenAttribute: "Data Type",
      chosenValue: "Expression microarray - gene"
    }
};
<|endoftext|>


<commit_before>//Power is connected to pin4 (5V), ground is pin6, tx (output) is pin 8,
// rx (input) is pin10

var SerialPort = require('serialport').SerialPort;
var serialPort = new SerialPort('/dev/ttyAMA0', {
	baudRate: 9600
});
var EMIC = (function() {
var isOpen = false;
var isReady = false;

var emic = {};
emic.init = function () {

	console.log('Successfully loaded SerialPort module');

	console.log('Successfully initialised /dev/ttyAMA0');

	serialPort.on('open', function () {
		console.log('Port is open')
		isOpen = true;
		serialPort.on('data', function(msg) {
			msg = msg.toString('ascii');
			console.log(msg);
			if (msg == ':') {
				isReady = true
				console.log('Emic is ready for an instruction')
			}
		});
		serialPort.write(':SHello World to all\r');
	});
};
emic.speak = function (data) {
	data = data.toString('ascii');
	while (isOpen == false || isReady == false) {};
	if (data.length > 1000) {
		console.log('Error: Message exceeds the character limit');
	} else {
		//serialPort.write(':SHello World to all\r');
		serialPort.write(':S' + data + '\r');
		console.log(':S' + data + '\r');
		isReady = false
		console.log('Emic is busy')
	};
};

emic.demo = function (id) {
	id = id.toString('ascii');
	if (id == '0' || id == '1' || id == '2') {
		serialPort.write(':D' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.stopNow = function () {
	serialPort.write(':X\r');
}

emic.pause = function () {
	serialPort.write(':Z\r');
};

emic.voice = function (id) {
	var idN = id.parseInt();
	if (idN >= 0 && idN <= 8) {
		id.toString('ascii');
		serialPort.write(':N' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.volume = function (level) {
	var levelN = id.parseInt();
	if (levelN >= -48 && levelN <= 18) {
		level = level.toString('ascii');
		serialPort.write(':V' + level + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.rate = function (wpm) {
	var wpmN = wpm.parseInt();
	if (wpmN >= 75 && wpmN <= 600) {
		wpm = wpm.toString('ascii');
		serialPort.write(':W' + wpm + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.parser = function (id) {
	id = id.toString('ascii');
	if (parser == '0' || parser == '1' || parser == '2') {
		serialPort.write(':P' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.revert = function () {
	serialPort.write(':R\r');
};

emic.callCurrentSettings = function () {
	serialPort.write(':C\r');
};

emic.callVersionInfo = function () {
	serialPort.write(':I\r');
};

emic.callCommands = function () {
	serialPort.write(':I\r');
};
return emic
}());

/*function writeLog(logFile, output){
	var logf = new File(logFile);
	logf.writeln(output);
	logf.close()*/

module.exports = EMIC;

<commit_msg>update<commit_after>//Power is connected to pin4 (5V), ground is pin6, tx (output) is pin 8,
// rx (input) is pin10

var SerialPort = require('serialport').SerialPort;
var serialPort = new SerialPort('/dev/ttyAMA0', {
	baudRate: 9600
});
var EMIC = (function() {
var isOpen = false;
var isReady = true;

var emic = {};
emic.init = function () {

	console.log('Successfully loaded SerialPort module');

	console.log('Successfully initialised /dev/ttyAMA0');

	serialPort.on('open', function () {
		console.log('Port is open')
		isOpen = true;
		serialPort.on('data', function(msg) {
			msg = msg.toString('ascii');
			console.log(msg);
			if (msg == ':') {
				isReady = true
				console.log('Emic is ready for an instruction')
			}
		});
		serialPort.write(':SHello World to all\r');
	});
};
emic.speak = function (data) {
	data = data.toString('ascii');
	while (isOpen == false || isReady == false) {};
	if (data.length > 1000) {
		console.log('Error: Message exceeds the character limit');
	} else {
		//serialPort.write(':SHello World to all\r');
		serialPort.write(':S' + data + '\r');
		console.log(':S' + data + '\r');
		isReady = false
		console.log('Emic is busy')
	};
};

emic.demo = function (id) {
	id = id.toString('ascii');
	if (id == '0' || id == '1' || id == '2') {
		serialPort.write(':D' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.stopNow = function () {
	serialPort.write(':X\r');
}

emic.pause = function () {
	serialPort.write(':Z\r');
};

emic.voice = function (id) {
	var idN = id.parseInt();
	if (idN >= 0 && idN <= 8) {
		id.toString('ascii');
		serialPort.write(':N' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.volume = function (level) {
	var levelN = id.parseInt();
	if (levelN >= -48 && levelN <= 18) {
		level = level.toString('ascii');
		serialPort.write(':V' + level + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.rate = function (wpm) {
	var wpmN = wpm.parseInt();
	if (wpmN >= 75 && wpmN <= 600) {
		wpm = wpm.toString('ascii');
		serialPort.write(':W' + wpm + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.parser = function (id) {
	id = id.toString('ascii');
	if (parser == '0' || parser == '1' || parser == '2') {
		serialPort.write(':P' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.revert = function () {
	serialPort.write(':R\r');
};

emic.callCurrentSettings = function () {
	serialPort.write(':C\r');
};

emic.callVersionInfo = function () {
	serialPort.write(':I\r');
};

emic.callCommands = function () {
	serialPort.write(':I\r');
};
return emic
}());

/*function writeLog(logFile, output){
	var logf = new File(logFile);
	logf.writeln(output);
	logf.close()*/

module.exports = EMIC;

<|endoftext|>


<commit_before>'use strict';
/*eslint no-restricted-modules: [0]*/

let color = require('../config/color');
let moment = require('moment');

let BR = '
';
let SPACE = ' ';
let profileColor = '#24678d';
let trainersprites = [1, 2, 101, 102, 169, 170, 265, 266, 168];

/**
 * Profile constructor.
 *
 * @param {Boolean} isOnline
 * @param {Object|String} user - if isOnline then Object else String
 * @param {String} image
 */
function Profile(isOnline, user, image) {
	this.isOnline = isOnline || false;
	this.user = user || null;
	this.image = image;

	this.username = Tools.escapeHTML(this.isOnline ? this.user.name : this.user);
	this.url = Config.avatarurl || '';
}

/**
 * Create an bold html tag element.
 *
 * Example:
 * createFont('Hello World!');
 * => 'Hello World!'
 *
 * @param {String} color
 * @param {String} text
 * @return {String}
 */
function bold(text) {
	return '' + text + '';
}

/**
 * Create an font html tag element.
 *
 * Example:
 * createFont('Hello World!', 'blue');
 * => 'Hello World!'
 *
 * @param {String} color
 * @param {String} text
 * @return {String}
 */
function font(color, text) {
	return '' + text + '';
}

/**
 * Create an img tag element.
 *
 * Example:
 * createImg('phil.png');
 * => ''
 *
 * @param {String} link
 * @return {String}
 */
function img(link) {
	return '';
}

/**
 * Create a font html element wrap around by a bold html element.
 * Uses to `profileColor` as a color.
 * Adds a colon at the end of the text and a SPACE at the end of the element.
 *
 * Example:
 * label('Name');
 * => 'Name: '
 *
 * @param {String} text
 * @return {String}
 */
function label(text) {
	return bold(font(profileColor, text + ':')) + SPACE;
}

function currencyName(amount) {
	let name = " buck";
	return amount === 1 ? name : name + "s";
}

Profile.prototype.avatar = function () {
	if (this.isOnline) {
		if (typeof this.image === 'string') return img(this.url + ':' + Config.port + '/avatars/' + this.image);
		return img('http://play.pokemonshowdown.com/sprites/trainers/' + this.image + '.png');
	}
	for (let name in Config.customAvatars) {
		if (this.username === name) {
			return img(this.url + ':' + Config.port + '/avatars/' + Config.customAvatars[name]);
		}
	}
	let selectedSprite = trainersprites[Math.floor(Math.random() * trainersprites.length)];
	return img('http://play.pokemonshowdown.com/sprites/trainers/' + selectedSprite + '.png');
};

Profile.prototype.buttonAvatar = function () {
	let css = 'border:none;background:none;padding:0;float:left;';
	return '<button style="' + css + '" name="parseCommand" value="/user ' + this.username + '">' + this.avatar() + "</button>";
};

Profile.prototype.group = function () {
	if (this.isOnline && this.user.group === ' ') return label('Group') + 'Regular User';
	if (this.isOnline) return label('Group') + Config.groups[this.user.group].name;
	for (let name in Users.usergroups) {
		if (toId(this.username) === name) {
			return label('Group') + Config.groups[Users.usergroups[name].charAt(0)].name;
		}
	}
	return label('Group') + 'Regular User';
};

Profile.prototype.money = function (amount) {
	return label('Money') + amount + currencyName(amount);
};

Profile.prototype.name = function () {
	return label('Name') + bold(font(color(toId(this.username)), this.username));
};

Profile.prototype.seen = function (timeAgo) {
	if (this.isOnline) return label('Last Seen') + font('#2ECC40', 'Currently Online');
	if (!timeAgo) return label('Last Seen') + 'Never';
	return label('Last Seen') + moment(timeAgo).fromNow();
};

Profile.prototype.vip = function (user) {
	if (isVip(user)) return font('#6390F0', '(VIP User)');
	return '';

};

Profile.prototype.show = function (callback) {
	let userid = toId(this.username);

	return this.buttonAvatar() +
		SPACE + this.name() + BR +
		SPACE + this.group() + SPACE + this.vip(userid) + SPACE + this.con(userid) + BR +
		SPACE + this.money(Db('money').get(userid, 0)) + BR +
		SPACE + this.seen(Db('seen').get(userid)) +
		'
';
};

exports.commands = {
	profile: function (target, room, user) {
		if (!this.runBroadcast()) return;
		if (target.length >= 19) return this.sendReply("Usernames are required to be less than 19 characters long.");
		let targetUser = this.targetUserOrSelf(target);
		let profile;
		if (!targetUser) {
			profile = new Profile(false, target);
		} else {
			profile = new Profile(true, targetUser, targetUser.avatar);
		}
		this.sendReplyBox(profile.show());
	},
	profilehelp: ["/profile -	Shows information regarding user's name, group, money, and when they were last seen."],
};
<commit_msg>Update profile.js<commit_after>'use strict';
/*eslint no-restricted-modules: [0]*/

let color = require('../config/color');
let moment = require('moment');

let BR = '
';
let SPACE = ' ';
let profileColor = '#24678d';
let trainersprites = [1, 2, 101, 102, 169, 170, 265, 266, 168];

/**
 * Profile constructor.
 *
 * @param {Boolean} isOnline
 * @param {Object|String} user - if isOnline then Object else String
 * @param {String} image
 */
function Profile(isOnline, user, image) {
	this.isOnline = isOnline || false;
	this.user = user || null;
	this.image = image;

	this.username = Tools.escapeHTML(this.isOnline ? this.user.name : this.user);
	this.url = Config.avatarurl || '';
}

/**
 * Create an bold html tag element.
 *
 * Example:
 * createFont('Hello World!');
 * => 'Hello World!'
 *
 * @param {String} color
 * @param {String} text
 * @return {String}
 */
function bold(text) {
	return '' + text + '';
}

/**
 * Create an font html tag element.
 *
 * Example:
 * createFont('Hello World!', 'blue');
 * => 'Hello World!'
 *
 * @param {String} color
 * @param {String} text
 * @return {String}
 */
function font(color, text) {
	return '' + text + '';
}

/**
 * Create an img tag element.
 *
 * Example:
 * createImg('phil.png');
 * => ''
 *
 * @param {String} link
 * @return {String}
 */
function img(link) {
	return '';
}

/**
 * Create a font html element wrap around by a bold html element.
 * Uses to `profileColor` as a color.
 * Adds a colon at the end of the text and a SPACE at the end of the element.
 *
 * Example:
 * label('Name');
 * => 'Name: '
 *
 * @param {String} text
 * @return {String}
 */
function label(text) {
	return bold(font(profileColor, text + ':')) + SPACE;
}

function currencyName(amount) {
	let name = " buck";
	return amount === 1 ? name : name + "s";
}

Profile.prototype.avatar = function () {
	if (this.isOnline) {
		if (typeof this.image === 'string') return img(this.url + ':' + Config.port + '/avatars/' + this.image);
		return img('http://play.pokemonshowdown.com/sprites/trainers/' + this.image + '.png');
	}
	for (let name in Config.customAvatars) {
		if (this.username === name) {
			return img(this.url + ':' + Config.port + '/avatars/' + Config.customAvatars[name]);
		}
	}
	let selectedSprite = trainersprites[Math.floor(Math.random() * trainersprites.length)];
	return img('http://play.pokemonshowdown.com/sprites/trainers/' + selectedSprite + '.png');
};

Profile.prototype.buttonAvatar = function () {
	let css = 'border:none;background:none;padding:0;float:left;';
	return '<button style="' + css + '" name="parseCommand" value="/user ' + this.username + '">' + this.avatar() + "</button>";
};

Profile.prototype.group = function () {
	if (this.isOnline && this.user.group === ' ') return label('Group') + 'Regular User';
	if (this.isOnline) return label('Group') + Config.groups[this.user.group].name;
	for (let name in Users.usergroups) {
		if (toId(this.username) === name) {
			return label('Group') + Config.groups[Users.usergroups[name].charAt(0)].name;
		}
	}
	return label('Group') + 'Regular User';
};

Profile.prototype.money = function (amount) {
	return label('Money') + amount + currencyName(amount);
};

Profile.prototype.name = function () {
	return label('Name') + bold(font(color(toId(this.username)), this.username));
};

Profile.prototype.seen = function (timeAgo) {
	if (this.isOnline) return label('Last Seen') + font('#2ECC40', 'Currently Online');
	if (!timeAgo) return label('Last Seen') + 'Never';
	return label('Last Seen') + moment(timeAgo).fromNow();
};

Profile.prototype.vip = function (user) {
	if (isVip(user)) return font('#6390F0', '(VIP User)');
	return '';

};

Profile.prototype.show = function (callback) {
	let userid = toId(this.username);

	return this.buttonAvatar() +
		SPACE + this.name() + BR +
		SPACE + this.group() + SPACE + this.vip(userid) + BR +
		SPACE + this.money(Db('money').get(userid, 0)) + BR +
		SPACE + this.seen(Db('seen').get(userid)) +
		'
';
};

exports.commands = {
	profile: function (target, room, user) {
		if (!this.runBroadcast()) return;
		if (target.length >= 19) return this.sendReply("Usernames are required to be less than 19 characters long.");
		let targetUser = this.targetUserOrSelf(target);
		let profile;
		if (!targetUser) {
			profile = new Profile(false, target);
		} else {
			profile = new Profile(true, targetUser, targetUser.avatar);
		}
		this.sendReplyBox(profile.show());
	},
	profilehelp: ["/profile -	Shows information regarding user's name, group, money, and when they were last seen."],
};
<|endoftext|>


<commit_before>define(
	[
		"./meta"
	],
	function (meta) {
		"use strict";

		meta({
			"entity": "module",
			"description": "For type checking values. Unfortunately typeof falls short and returns 'object' for for native JavaScript types: array, date, regex, and null"
		});

		meta({
			"entity": "function",
			"name": "of",
			"description": "I get the type of the value.",
			"arguments": [{
				"name": "value",
				"type": "any"
			}, {
				"name": "custom",
				"type": "object.function",
				"description": "An object of functions. Key names map to type names. Functions will accept the value and return a string representing a custom type.",
				"required": false
			}],
			"return": {
				"type": "string",
				"description": "One of the following types: string, number, boolean, array, object, date, regexp, function, undefined, or null. Result may be a custom type if custom is passed in"
			}
		});

		var toString = Object.prototype.toString;

		function of (value, custom) {
			var type = typeof value;
			if ("object" === type) {
				type = toString.call(value).slice(8, -1).toLowerCase();
			}
			if (custom && custom[type]) {
				type = custom[type](value);
			}
			return type;
		}

		meta({
			"entity": "function",
			"name": "is",
			"description": "I test the type of value against a specified type.",
			"arguments": [{
				"name": "type",
				"type": "string",
				"description": "One of the following types: string, number, boolean, array, object, date, regexp, function, undefined, or null."
			}, {
				"name": "value",
				"type": "any"
			}, {
				"name": "custom",
				"type": "object.function",
				"description": "An object of functions. Key names map to type names. Functions will accept the value and return a string representing a custom type.",
				"required": false
			}],
			"return": {
				"type": "boolean",
				"description": "True if value is of the specified type"
			}
		});

		function is (type, value, custom) {
			return of(value, custom) === type;
		}

		return {
			of: of,
			is: is
		};
	}
);
<commit_msg>reworking api for creating custom tester<commit_after>define(
	[
		"./meta"
	],
	function (meta) {
		"use strict";

		meta({
			"entity": "module",
			"description": "For testing value types. Unfortunately typeof falls short and returns 'object' for for native JavaScript types: array, date, regexp, arguments and null. Native type names for use with type.of and type.is include: string, number, boolean, array, object, date, regexp, function, undefined, arguments or null."
		});

		meta({
			"entity": "function",
			"name": "of",
			"description": "I get the native type name of a value.",
			"arguments": [{
				"name": "value",
				"type": "any"
			}],
			"return": "string"
		});

		meta({
			"entity": "function",
			"name": "is",
			"description": "I test the type name of a value against a specified type name.",
			"arguments": [{
				"name": "type",
				"type": "string"
			}, {
				"name": "value",
				"type": "any"
			}],
			"return": "boolean"
		});

		meta({
			"entity": "function",
			"name": "custom",
			"description": "For creating a custom type tester that extends stock tester.",
			"arguments": [{
				"name": "subtypes",
				"type": "object",
				"description": "Object's keys map to native type names. Newly created tester's methods delegate to subtypes functions. Object's values must be functions that implement the type.of signature. A function for each native types is not required. Implement only as many subtypes as necessary."
			}],
			"return": {
				"type": "object",
				"description": "Custom type tester containing 'of' and 'is' methods."
			}
		});

		var toString = Object.prototype.toString;

		function of (value) {
			var type = typeof value;
			if ("object" === type) {
				type = toString.call(value).slice(8, -1).toLowerCase();
			}
			return type;
		}

		function is (type, value) {
			return of(value) === type;
		}

		function custom (subtypes) {
			function _of (value) {
				var type = of(value);
				if (hasSubtypes(type)) {
					type = getSubtype(type, value);
				}
				return type;
			}

			function _is (type, value) {
				return _of(value) === type;
			}

			function hasSubtypes (type) {
				return type in subtypes;
			}

			function getSubtype (type, value) {
				return subtypes[type](value);
			}

			return {
				of: _of,
				is: _is
			};
		}

		return {
			of: of,
			is: is,
			custom: custom
		};
	}
);
<|endoftext|>


<commit_before>import Shogi from '../src/shogi';
import * as CONST from '../constants/actionTypes';

const InitialState = {
  board: Shogi.Board,
  isHoldingPiece: undefined,
  blackPieceStand: [],
  whitePieceStand: []
};

const ShogiReducer = (state = InitialState, action) => {
  switch (action.type) {
  case CONST.HOLD_PIECE:
    if (action.piece.type == '*') {
      return state;
    } else {
      let newBoard = state.board.enhanceMovablePoint(action.piece);
      return Object.assign(
        {},
        state,
        {
          board: newBoard,
          blackPieceStand: state.blackPieceStand,
          whitePieceStand: state.whitePieceStand,
          isHoldingPiece: action.piece
        }
      );
    }
  case CONST.MOVE_PIECE:
    // if same piece click, release piece.
    if (state.isHoldingPiece) {
      let newBoard = state.board.movePiece(state.isHoldingPiece, action.piece);

      if (newBoard.takedPiece) {
        const takedPiece = newBoard.takedPiece;
        // TODO: Use constants. Refactor.
        switch (newBoard.takedPiece.team()) {
        case 'white':
          return Object.assign(
            {},
            state,
            {
              board: newBoard,
              isHoldingPiece: undefined,
              blackPieceStand: state.blackPieceStand.concat([takedPiece.toOpponentPiece()]),
              whitePieceStand: state.whitePieceStand
            }
          );
        case 'black':
          return Object.assign(
            {},
            state,
            {
              board: newBoard,
              isHoldingPiece: undefined,
              blackPieceStand: state.blackPieceStand,
              whitePieceStand: state.whitePieceStand.concat([takedPiece.toOpponentPiece()])
            }
          );
        }
      } else {
        return Object.assign(
          {},
          state,
          {
            board: newBoard,
            isHoldingPiece: undefined,
            blackPieceStand: state.blackPieceStand,
            whitePieceStand: state.whitePieceStand
          }
        );
      }
    } else {
      return Object.assign({}, state, { isHoldingPiece: action.piece });
    }
  case CONST.SHOW_PROMOTE_MODAL:
    return Object.assign({}, state, { promoteModal: true });
  default:
    return state;
  }
};

export default ShogiReducer;
<commit_msg>Add `hidePromoteModal` reducers.<commit_after>import Shogi from '../src/shogi';
import * as CONST from '../constants/actionTypes';

const InitialState = {
  board: Shogi.Board,
  isHoldingPiece: undefined,
  blackPieceStand: [],
  whitePieceStand: [],
  promoteModal: false
};

const ShogiReducer = (state = InitialState, action) => {
  switch (action.type) {
  case CONST.HOLD_PIECE:
    if (action.piece.type == '*') {
      return state;
    } else {
      let newBoard = state.board.enhanceMovablePoint(action.piece);
      return Object.assign(
        {},
        state,
        {
          board: newBoard,
          blackPieceStand: state.blackPieceStand,
          whitePieceStand: state.whitePieceStand,
          isHoldingPiece: action.piece
        }
      );
    }
  case CONST.MOVE_PIECE:
    // if same piece click, release piece.
    if (state.isHoldingPiece) {
      let newBoard = state.board.movePiece(state.isHoldingPiece, action.piece);

      if (newBoard.takedPiece) {
        const takedPiece = newBoard.takedPiece;
        // TODO: Use constants. Refactor.
        switch (newBoard.takedPiece.team()) {
        case 'white':
          return Object.assign(
            {},
            state,
            {
              board: newBoard,
              isHoldingPiece: undefined,
              blackPieceStand: state.blackPieceStand.concat([takedPiece.toOpponentPiece()]),
              whitePieceStand: state.whitePieceStand
            }
          );
        case 'black':
          return Object.assign(
            {},
            state,
            {
              board: newBoard,
              isHoldingPiece: undefined,
              blackPieceStand: state.blackPieceStand,
              whitePieceStand: state.whitePieceStand.concat([takedPiece.toOpponentPiece()])
            }
          );
        }
      } else {
        return Object.assign(
          {},
          state,
          {
            board: newBoard,
            isHoldingPiece: undefined,
            blackPieceStand: state.blackPieceStand,
            whitePieceStand: state.whitePieceStand
          }
        );
      }
    } else {
      return Object.assign({}, state, { isHoldingPiece: action.piece });
    }
  case CONST.SHOW_PROMOTE_MODAL:
    return Object.assign({}, state, { promoteModal: true });
  case CONST.HIDE_PROMOTE_MODAL:
    return Object.assign({}, state, { promoteModal: false });
  default:
    return state;
  }
};

export default ShogiReducer;
<|endoftext|>