<commit_before>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.comics.v2',
  name: 'DAOSummaryView',
  extends: 'foam.u2.View',

  documentation: `
    A configurable summary view for a specific instance
  `,

  topics: [
    'finished',
    'throwError'
  ],

  axioms: [
    foam.pattern.Faceted.create()
  ],

  css:`
    ^ {
      padding: 32px
    }

    ^ .foam-u2-ActionView-back {
      display: flex;
      align-items: center;
      width: 30%;
    }

    ^account-name {
      font-size: 36px;
      font-weight: 600;
    }

    ^actions-header .foam-u2-ActionView {
      margin-right: 24px;
      line-height: 1.5
    }

    ^view-container {
      margin: auto;
    }
  `,

  requires: [
    'foam.u2.layout.Cols',
    'foam.u2.layout.Rows',
    'foam.u2.ControllerMode',
    'foam.u2.dialog.NotificationMessage',
    'foam.u2.dialog.Popup',
  ],

  imports: [
    'stack'
  ],

  exports: [
    'controllerMode'
  ],

  properties: [
    {
      class: 'FObjectProperty',
      name: 'data'
    },
    {
      class: 'FObjectProperty',
      of: 'foam.comics.v2.DAOControllerConfig',
      name: 'config'
    },
    {
      name: 'controllerMode',
      factory: function() {
        return this.ControllerMode.VIEW;
      }
    },
    {
      name: 'primary',
      expression: function(config$of) {
        var allActions = config$of.getAxiomsByClass(foam.core.Action);
        var defaultAction = allActions.filter((a) => a.isDefault);
        return defaultAction.length >= 1 ? defaultAction[0] : allActions[0];
      }
    },
    {
      class: 'foam.u2.ViewSpecWithJava',
      name: 'viewView',
      expression: function() {
        return foam.u2.detail.SectionedDetailView;
      }
    },
    {
      class: 'String',
      name: 'backLabel'
    }
  ],

  actions: [
    {
      name: 'edit',
      isAvailable: function(config$editEnabled) {
        return config$editEnabled;
      },
      code: function() {
        if ( ! this.stack ) return;
        this.stack.push({
          class: 'foam.comics.v2.DAOUpdateView',
          data: this.data,
          config: this.config,
          of: this.config.of
        });
      }
    },
    {
      name: 'delete',
      isAvailable: function(config$deleteEnabled) {
        return config$deleteEnabled;
      },
      code: function() {
        this.add(this.Popup.create({ backgroundColor: 'transparent' }).tag({
          class: 'foam.u2.DeleteModal',
          dao: this.config.dao,
          onDelete: () => {
            this.finished.pub();
            this.stack.back();
          },
          data: this.data
        }));
      }
    }
  ],

  methods: [
    function initE() {
      var self = this;
      this.SUPER();
      this
        .addClass(this.myClass())
        .add(self.slot(function(data, data$id, config$CRUDActionsAuth$update, config$CRUDActionsAuth$delete,config$browseTitle, config$viewBorder, viewView) {

          // iterate through permissions and replace % with data$id
          var editAction = self.EDIT;
          var deleteAction = self.DELETE;

          if ( config$CRUDActionsAuth$update ) {
            var editArray = config$CRUDActionsAuth$update;

            editArray = editArray.map(permission => {
              return permission.replace("%", data$id);
            });

            editAction = self.EDIT.clone().copyFrom({
              availablePermissions: self.EDIT.availablePermissions.concat(editArray)
            });
          }

          if ( config$CRUDActionsAuth$delete ) {
            var deleteArray = config$CRUDActionsAuth$delete;

            deleteArray = deleteArray.map(permission => {
              return permission.replace("%", data$id);
            });

            deleteAction = self.DELETE.clone().copyFrom({
              availablePermissions: self.DELETE.availablePermissions.concat(deleteArray)
            });
          }

          var label = self.backLabel || `All ${config$browseTitle}`;

          return self.E()
            .start(self.Rows)
              .start(self.Rows)
                // we will handle this in the StackView instead
                .startContext({ data: self.stack })
                  .tag(self.stack.BACK, {
                    buttonStyle: foam.u2.ButtonStyle.TERTIARY,
                    icon: 'images/back-icon.svg',
                    label: label
                  })
                .endContext()
                .start(self.Cols).style({ 'align-items': 'center' })
                  .start()
                    .add(data.toSummary())
                    .addClass(this.myClass('account-name'))
                  .end()
                  .startContext({ data }).add(self.primary).endContext()
                .end()
              .end()

              .start(self.Cols)
                .start(self.Cols).addClass(this.myClass('actions-header'))
                  .startContext({ data: self })
                    .tag(editAction, {
                      buttonStyle: foam.u2.ButtonStyle.TERTIARY,
                      icon: 'images/edit-icon.svg'
                    })
                    .tag(deleteAction, {
                      buttonStyle: foam.u2.ButtonStyle.TERTIARY,
                      icon: 'images/delete-icon.svg'
                    })
                  .endContext()
                .end()
              .end()

              .start(config$viewBorder)
                .start(viewView, { data }).addClass(this.myClass('view-container')).end()
              .end()
            .end();
        }));
    }
  ]
});
<commit_msg>make backlabel foamy<commit_after>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.comics.v2',
  name: 'DAOSummaryView',
  extends: 'foam.u2.View',

  documentation: `
    A configurable summary view for a specific instance
  `,

  topics: [
    'finished',
    'throwError'
  ],

  axioms: [
    foam.pattern.Faceted.create()
  ],

  css:`
    ^ {
      padding: 32px
    }

    ^ .foam-u2-ActionView-back {
      display: flex;
      align-items: center;
      width: 30%;
    }

    ^account-name {
      font-size: 36px;
      font-weight: 600;
    }

    ^actions-header .foam-u2-ActionView {
      margin-right: 24px;
      line-height: 1.5
    }

    ^view-container {
      margin: auto;
    }
  `,

  requires: [
    'foam.u2.layout.Cols',
    'foam.u2.layout.Rows',
    'foam.u2.ControllerMode',
    'foam.u2.dialog.NotificationMessage',
    'foam.u2.dialog.Popup',
  ],

  imports: [
    'stack'
  ],

  exports: [
    'controllerMode'
  ],

  properties: [
    {
      class: 'FObjectProperty',
      name: 'data'
    },
    {
      class: 'FObjectProperty',
      of: 'foam.comics.v2.DAOControllerConfig',
      name: 'config'
    },
    {
      name: 'controllerMode',
      factory: function() {
        return this.ControllerMode.VIEW;
      }
    },
    {
      name: 'primary',
      expression: function(config$of) {
        var allActions = config$of.getAxiomsByClass(foam.core.Action);
        var defaultAction = allActions.filter((a) => a.isDefault);
        return defaultAction.length >= 1 ? defaultAction[0] : allActions[0];
      }
    },
    {
      class: 'foam.u2.ViewSpecWithJava',
      name: 'viewView',
      expression: function() {
        return foam.u2.detail.SectionedDetailView;
      }
    },
    {
      class: 'String',
      name: 'backLabel',
      expression: function(config$browseTitle) {
        return 'All ' + config$browseTitle;
      }
    }
  ],

  actions: [
    {
      name: 'edit',
      isAvailable: function(config$editEnabled) {
        return config$editEnabled;
      },
      code: function() {
        if ( ! this.stack ) return;
        this.stack.push({
          class: 'foam.comics.v2.DAOUpdateView',
          data: this.data,
          config: this.config,
          of: this.config.of
        });
      }
    },
    {
      name: 'delete',
      isAvailable: function(config$deleteEnabled) {
        return config$deleteEnabled;
      },
      code: function() {
        this.add(this.Popup.create({ backgroundColor: 'transparent' }).tag({
          class: 'foam.u2.DeleteModal',
          dao: this.config.dao,
          onDelete: () => {
            this.finished.pub();
            this.stack.back();
          },
          data: this.data
        }));
      }
    }
  ],

  methods: [
    function initE() {
      var self = this;
      this.SUPER();
      this
        .addClass(this.myClass())
        .add(self.slot(function(data, data$id, config$CRUDActionsAuth$update, config$CRUDActionsAuth$delete,config$browseTitle, config$viewBorder, viewView) {

          // iterate through permissions and replace % with data$id
          var editAction = self.EDIT;
          var deleteAction = self.DELETE;

          if ( config$CRUDActionsAuth$update ) {
            var editArray = config$CRUDActionsAuth$update;

            editArray = editArray.map(permission => {
              return permission.replace("%", data$id);
            });

            editAction = self.EDIT.clone().copyFrom({
              availablePermissions: self.EDIT.availablePermissions.concat(editArray)
            });
          }

          if ( config$CRUDActionsAuth$delete ) {
            var deleteArray = config$CRUDActionsAuth$delete;

            deleteArray = deleteArray.map(permission => {
              return permission.replace("%", data$id);
            });

            deleteAction = self.DELETE.clone().copyFrom({
              availablePermissions: self.DELETE.availablePermissions.concat(deleteArray)
            });
          }

          return self.E()
            .start(self.Rows)
              .start(self.Rows)
                // we will handle this in the StackView instead
                .startContext({ data: self.stack })
                  .tag(self.stack.BACK, {
                    buttonStyle: foam.u2.ButtonStyle.TERTIARY,
                    icon: 'images/back-icon.svg',
                    label: self.backLabel
                  })
                .endContext()
                .start(self.Cols).style({ 'align-items': 'center' })
                  .start()
                    .add(data.toSummary())
                    .addClass(this.myClass('account-name'))
                  .end()
                  .startContext({ data }).add(self.primary).endContext()
                .end()
              .end()

              .start(self.Cols)
                .start(self.Cols).addClass(this.myClass('actions-header'))
                  .startContext({ data: self })
                    .tag(editAction, {
                      buttonStyle: foam.u2.ButtonStyle.TERTIARY,
                      icon: 'images/edit-icon.svg'
                    })
                    .tag(deleteAction, {
                      buttonStyle: foam.u2.ButtonStyle.TERTIARY,
                      icon: 'images/delete-icon.svg'
                    })
                  .endContext()
                .end()
              .end()

              .start(config$viewBorder)
                .start(viewView, { data }).addClass(this.myClass('view-container')).end()
              .end()
            .end();
        }));
    }
  ]
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { Box, Row, Rule, Text } from '@tlon/indigo-react';
import index from '../lib/omnibox';
import Mousetrap from 'mousetrap';
import OmniboxInput from './OmniboxInput';
import OmniboxResult from './OmniboxResult';

import { cite } from '../lib/util';

export class Omnibox extends Component {
  constructor(props) {
    super(props);
    this.state = {
      index: new Map([]),
      query: '',
      results: this.initialResults(),
      selected: ''
    };
    this.handleClickOutside = this.handleClickOutside.bind(this);
    this.search = this.search.bind(this);
    this.navigate = this.navigate.bind(this);
    this.control - this.control.bind(this);
    this.setPreviousSelected = this.setPreviousSelected.bind(this);
    this.setNextSelected = this.setNextSelected.bind(this);
  }

  componentDidUpdate(prevProps) {
    if (prevProps !== this.props) {
      this.setState({ index: index(this.props.associations, this.props.apps.tiles) });
    }

    if (prevProps && this.props.show && prevProps.show !== this.props.show) {
      Mousetrap.bind('escape', () => this.props.api.local.setOmnibox());
      document.addEventListener('mousedown', this.handleClickOutside);
      const touchstart = new Event('touchstart');
      this.omniInput.input.dispatchEvent(touchstart);
      this.omniInput.input.focus();
    }
  }

  componentWillUpdate(prevProps) {
    if (this.props.show && prevProps.show !== this.props.show) {
      Mousetrap.unbind('escape');
      document.removeEventListener('mousedown', this.handleClickOutside);
    }
  }

    control(evt) {
    if (evt.key === 'Escape') {
      if (this.state.query.length > 0) {
        this.setState({ query: '', results: this.initialResults() });
      } else if (this.props.show) {
        this.props.api.local.setOmnibox();
      }
    };

    if (
      evt.key === 'ArrowUp' ||
      (evt.shiftKey && evt.key === 'Tab')) {
        evt.preventDefault();
      return this.setPreviousSelected();
    }

    if (evt.key === 'ArrowDown' || evt.key === 'Tab') {
      evt.preventDefault();
      this.setNextSelected();
    }

    if (evt.key === 'Enter') {
      if (this.state.selected !== '') {
        this.navigate(this.state.selected);
      } else {
        this.navigate(Array.from(this.state.results.values()).flat()[0].link);
      }
    }
  }

  handleClickOutside(evt) {
    if (this.props.show && !this.omniBox.contains(evt.target)) {
      this.setState({ results: this.initialResults(), query: '' }, () => {
        this.props.api.local.setOmnibox();
      });
    }
  }

  initialResults() {
    return new Map([
      ['commands', []],
      ['subscriptions', []],
      ['groups', []],
      ['apps', []]
    ]);
  }

  navigate(link) {
    const { props } = this;
    this.setState({ results: this.initialResults(), query: '' }, () => {
      props.api.local.setOmnibox();
      props.history.push(link);
    });
  }

  search(event) {
    const { state } = this;
    const query = event.target.value;
    const results = this.initialResults();

    this.setState({ query: query });

    // wipe results if backspacing
    if (query.length === 0) {
      this.setState({ results: results, selected: '' });
      return;
    }

    // don't search for single characters
    if (query.length === 1) {
      return;
    }

    ['commands', 'subscriptions', 'groups', 'apps'].map((category) => {
      const categoryIndex = state.index.get(category);
      results.set(category,
        categoryIndex.filter((result) => {
          return (
            result.title.toLowerCase().includes(query) ||
            result.link.toLowerCase().includes(query) ||
            result.app.toLowerCase().includes(query) ||
            (result.host !== null ? result.host.includes(query) : false)
          );
        })
      );
    });

    this.setState({ results: results });
  }

    setPreviousSelected() {
      const current = this.state.selected;
      const flattenedResults = Array.from(this.state.results.values()).flat();
      const totalLength = flattenedResults.length;
      if (current !== '') {
        const currentIndex = flattenedResults.indexOf(
          ...flattenedResults.filter((e) => {
            return e.link === current;
          })
        );
        if (currentIndex > 0) {
        const nextLink = flattenedResults[currentIndex - 1].link;
        this.setState({ selected: nextLink });
        } else {
        const nextLink = flattenedResults[totalLength - 1].link;
        this.setState({ selected: nextLink });
        }
      } else {
        const nextLink = flattenedResults[totalLength - 1].link;
        this.setState({ selected: nextLink });
      }
  }

  setNextSelected() {
    const current = this.state.selected;
    const flattenedResults = Array.from(this.state.results.values()).flat();
    if (current !== '') {
      const currentIndex = flattenedResults.indexOf(
        ...flattenedResults.filter((e) => {
          return e.link === current;
        })
      );
      if (currentIndex < flattenedResults.length - 1) {
      const nextLink = flattenedResults[currentIndex + 1].link;
      this.setState({ selected: nextLink });
      } else {
      const nextLink = flattenedResults[0].link;
      this.setState({ selected: nextLink });
      }
    } else {
      const nextLink = flattenedResults[0].link;
      this.setState({ selected: nextLink });
    }
  }

  render() {
    const { props, state } = this;
    const categoryResult = [];

    const renderResults = <Box maxHeight="400px" overflowY="scroll" overflowX="hidden">
      {categoryResult}
    </Box>;

      ['commands', 'subscriptions', 'groups', 'apps'].map((category, i) => {
      const categoryResults = state.results.get(category);
      if (categoryResults.length > 0) {
        const each = categoryResults.map((result, i) => {
          return <OmniboxResult
            key={i}
            icon={result.app}
            text={result.title}
            subtext={cite(result.host)}
            link={result.link}
            navigate={() => this.navigate(result.link)}
            selected={this.state.selected}
            dark={props.dark}
                 />;
        });
         categoryResult.push(<Box key={i} width='max(50vw, 300px)' maxWidth='600px'>
        <Rule borderTopWidth="0.5px" color="washedGray" />
        <Text gray ml={2}>{category.charAt(0).toUpperCase() + category.slice(1)}</Text>
          {each}
        </Box>);
      }
    });

    return (
        <Box
          backgroundColor='lightGray'
          width='100vw'
          height='100vh'
          position='absolute'
          top='0'
          right='0'
          zIndex='9'
          display={props.show ? 'block' : 'none'}>
          <Row justifyContent='center'>
            <Box
              mt='20vh'
              width='max(50vw, 300px)'
              maxWidth='600px'
              borderRadius='2'
              backgroundColor='white'
              ref={(el) => {
                this.omniBox = el;
              }}>
              <OmniboxInput
                ref={(el) => { this.omniInput = el; }}
                control={e => this.control(e)}
                search={this.search}
                query={state.query}
              />
              {renderResults}
            </Box>
          </Row>
        </Box>
    );
  }
}

export default withRouter(Omnibox);
<commit_msg>omnibox: stop enter from propagation<commit_after>import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { Box, Row, Rule, Text } from '@tlon/indigo-react';
import index from '../lib/omnibox';
import Mousetrap from 'mousetrap';
import OmniboxInput from './OmniboxInput';
import OmniboxResult from './OmniboxResult';

import { cite } from '../lib/util';

export class Omnibox extends Component {
  constructor(props) {
    super(props);
    this.state = {
      index: new Map([]),
      query: '',
      results: this.initialResults(),
      selected: ''
    };
    this.handleClickOutside = this.handleClickOutside.bind(this);
    this.search = this.search.bind(this);
    this.navigate = this.navigate.bind(this);
    this.control - this.control.bind(this);
    this.setPreviousSelected = this.setPreviousSelected.bind(this);
    this.setNextSelected = this.setNextSelected.bind(this);
  }

  componentDidUpdate(prevProps) {
    if (prevProps !== this.props) {
      this.setState({ index: index(this.props.associations, this.props.apps.tiles) });
    }

    if (prevProps && this.props.show && prevProps.show !== this.props.show) {
      Mousetrap.bind('escape', () => this.props.api.local.setOmnibox());
      document.addEventListener('mousedown', this.handleClickOutside);
      const touchstart = new Event('touchstart');
      this.omniInput.input.dispatchEvent(touchstart);
      this.omniInput.input.focus();
    }
  }

  componentWillUpdate(prevProps) {
    if (this.props.show && prevProps.show !== this.props.show) {
      Mousetrap.unbind('escape');
      document.removeEventListener('mousedown', this.handleClickOutside);
    }
  }

    control(evt) {
    if (evt.key === 'Escape') {
      if (this.state.query.length > 0) {
        this.setState({ query: '', results: this.initialResults() });
      } else if (this.props.show) {
        this.props.api.local.setOmnibox();
      }
    };

    if (
      evt.key === 'ArrowUp' ||
      (evt.shiftKey && evt.key === 'Tab')) {
        evt.preventDefault();
      return this.setPreviousSelected();
    }

    if (evt.key === 'ArrowDown' || evt.key === 'Tab') {
      evt.preventDefault();
      this.setNextSelected();
    }

    if (evt.key === 'Enter') {
      evt.preventDefault();
      if (this.state.selected !== '') {
        this.navigate(this.state.selected);
      } else {
        this.navigate(Array.from(this.state.results.values()).flat()[0].link);
      }
    }
  }

  handleClickOutside(evt) {
    if (this.props.show && !this.omniBox.contains(evt.target)) {
      this.setState({ results: this.initialResults(), query: '' }, () => {
        this.props.api.local.setOmnibox();
      });
    }
  }

  initialResults() {
    return new Map([
      ['commands', []],
      ['subscriptions', []],
      ['groups', []],
      ['apps', []]
    ]);
  }

  navigate(link) {
    const { props } = this;
    this.setState({ results: this.initialResults(), query: '' }, () => {
      props.api.local.setOmnibox();
      props.history.push(link);
    });
  }

  search(event) {
    const { state } = this;
    const query = event.target.value;
    const results = this.initialResults();

    this.setState({ query: query });

    // wipe results if backspacing
    if (query.length === 0) {
      this.setState({ results: results, selected: '' });
      return;
    }

    // don't search for single characters
    if (query.length === 1) {
      return;
    }

    ['commands', 'subscriptions', 'groups', 'apps'].map((category) => {
      const categoryIndex = state.index.get(category);
      results.set(category,
        categoryIndex.filter((result) => {
          return (
            result.title.toLowerCase().includes(query) ||
            result.link.toLowerCase().includes(query) ||
            result.app.toLowerCase().includes(query) ||
            (result.host !== null ? result.host.includes(query) : false)
          );
        })
      );
    });

    this.setState({ results: results });
  }

    setPreviousSelected() {
      const current = this.state.selected;
      const flattenedResults = Array.from(this.state.results.values()).flat();
      const totalLength = flattenedResults.length;
      if (current !== '') {
        const currentIndex = flattenedResults.indexOf(
          ...flattenedResults.filter((e) => {
            return e.link === current;
          })
        );
        if (currentIndex > 0) {
        const nextLink = flattenedResults[currentIndex - 1].link;
        this.setState({ selected: nextLink });
        } else {
        const nextLink = flattenedResults[totalLength - 1].link;
        this.setState({ selected: nextLink });
        }
      } else {
        const nextLink = flattenedResults[totalLength - 1].link;
        this.setState({ selected: nextLink });
      }
  }

  setNextSelected() {
    const current = this.state.selected;
    const flattenedResults = Array.from(this.state.results.values()).flat();
    if (current !== '') {
      const currentIndex = flattenedResults.indexOf(
        ...flattenedResults.filter((e) => {
          return e.link === current;
        })
      );
      if (currentIndex < flattenedResults.length - 1) {
      const nextLink = flattenedResults[currentIndex + 1].link;
      this.setState({ selected: nextLink });
      } else {
      const nextLink = flattenedResults[0].link;
      this.setState({ selected: nextLink });
      }
    } else {
      const nextLink = flattenedResults[0].link;
      this.setState({ selected: nextLink });
    }
  }

  render() {
    const { props, state } = this;
    const categoryResult = [];

    const renderResults = <Box maxHeight="400px" overflowY="scroll" overflowX="hidden">
      {categoryResult}
    </Box>;

      ['commands', 'subscriptions', 'groups', 'apps'].map((category, i) => {
      const categoryResults = state.results.get(category);
      if (categoryResults.length > 0) {
        const each = categoryResults.map((result, i) => {
          return <OmniboxResult
            key={i}
            icon={result.app}
            text={result.title}
            subtext={cite(result.host)}
            link={result.link}
            navigate={() => this.navigate(result.link)}
            selected={this.state.selected}
            dark={props.dark}
                 />;
        });
         categoryResult.push(<Box key={i} width='max(50vw, 300px)' maxWidth='600px'>
        <Rule borderTopWidth="0.5px" color="washedGray" />
        <Text gray ml={2}>{category.charAt(0).toUpperCase() + category.slice(1)}</Text>
          {each}
        </Box>);
      }
    });

    return (
        <Box
          backgroundColor='lightGray'
          width='100vw'
          height='100vh'
          position='absolute'
          top='0'
          right='0'
          zIndex='9'
          display={props.show ? 'block' : 'none'}>
          <Row justifyContent='center'>
            <Box
              mt='20vh'
              width='max(50vw, 300px)'
              maxWidth='600px'
              borderRadius='2'
              backgroundColor='white'
              ref={(el) => {
                this.omniBox = el;
              }}>
              <OmniboxInput
                ref={(el) => { this.omniInput = el; }}
                control={e => this.control(e)}
                search={this.search}
                query={state.query}
              />
              {renderResults}
            </Box>
          </Row>
        </Box>
    );
  }
}

export default withRouter(Omnibox);
<|endoftext|>


<commit_before>import { Button, Divider, Text } from '@ui-kitten/components';
import { Formik } from 'formik';
import ky from 'ky';
import propTypes from 'prop-types';
import React from 'react';
import { Alert, StyleSheet } from 'react-native';
import * as Sentry from 'sentry-expo';
import useAuth from '../../auth/context';
import config from '../../config';
import { ACCURACY, getLocation } from '../../location';
import useStyles, { PADDING } from '../../styles';
import { coordinatesToString } from '../../utilities';
import PhotoCapture from './PhotoCapture';
import RadioPills from './RadioPills';
import Species from './Species';

const GENDERS = ['female', 'male'];
const AGES = ['adult', 'juvenile'];

export default function Form({
  formikRef,
  initialValues,
  validationSchema,
  carcassCoordinates,
  reportType,
  onClose,
  children = () => null,
  isLoading,
  setIsLoading,
  style,
}) {
  const {
    authInfo: { user },
    getBearerToken,
  } = useAuth();
  const commonStyles = useStyles();

  const submitReport = async (values) => {
    console.log('submitReport');

    setIsLoading(true);

    const formData = new FormData();
    for (let valueName in values) {
      if (values[valueName] !== null) {
        formData.append(valueName, values[valueName]);
      }
    }

    // add data gathered from outside of the form
    formData.append('animal_location', coordinatesToString(carcassCoordinates));
    formData.append('user_id', user.id);
    formData.append('submit_date', new Date().toISOString());
    const currentLocation = await getLocation(ACCURACY.Highest);
    formData.append('submit_location', coordinatesToString(currentLocation.coords));

    console.log('formData', formData);

    let responseJson;
    try {
      responseJson = await ky
        .post(`${config.API}/reports/${reportType}`, {
          body: formData,
          headers: {
            Authorization: await getBearerToken(),
          },
        })
        .json();
    } catch (error) {
      Sentry.Native.captureException(error);
      Alert.alert('Error', error.message);
      // TODO: allow them to cache the report for submission at a later time.

      return;
    }

    if (responseJson.success) {
      console.log('responseJson.report_id', responseJson.report_id);

      Alert.alert('Success!', 'Your report has been submitted.', [
        {
          text: 'OK',
          onPress: () => onClose(true),
        },
      ]);
    } else {
      Alert.alert('Error', responseJson.error);
    }
  };

  const onPhotoChange = (newPhotoProps) => {
    if (!newPhotoProps) {
      formikRef.current.setFieldValue('photo', null);
      formikRef.current.setFieldValue('photo_location', null);
      formikRef.current.setFieldValue('photo_date', null);
    } else {
      const { uri, type, name, coordinates, date } = newPhotoProps;
      formikRef.current.setFieldValue('photo', {
        uri,
        type,
        name,
      });
      formikRef.current.setFieldValue('photo_location', coordinates);
      formikRef.current.setFieldValue('photo_date', date);
    }
  };

  return (
    <Formik
      innerRef={formikRef}
      initialValues={initialValues}
      validationSchema={validationSchema}
      onSubmit={(values) => submitReport(values).then(() => setIsLoading(false))}
      style={style}
    >
      {({ values, setFieldValue, errors, dirty, isValid, handleSubmit }) => (
        <>
          {children({ values, setFieldValue, errors })}
          <PhotoCapture
            isRequired={validationSchema.fields.photo.spec.presence === 'required'}
            onChange={onPhotoChange}
            uri={values.photo?.uri}
          />
          <Species
            onChange={(newValue) => {
              setFieldValue('species', newValue.species);
              setFieldValue('species_confidence_level', newValue.species_confidence_level);
            }}
            values={{
              species: values.species,
              species_confidence_level: values.species_confidence_level,
            }}
            style={styles.bottomBump}
          />
          <Text category="h6">Animal age?</Text>
          <RadioPills
            value={values.age_class}
            onChange={(value) => setFieldValue('age_class', value)}
            options={AGES.concat([config.UNKNOWN])}
            style={styles.bottomBump}
          />
          <Text category="h6">Animal sex?</Text>
          <RadioPills
            value={values.sex}
            onChange={(value) => setFieldValue('sex', value)}
            options={GENDERS.concat([config.UNKNOWN])}
            style={styles.bottomBump}
          />
          <Divider style={commonStyles.margin} />
          <Button
            status="info"
            style={commonStyles.margin}
            onPress={handleSubmit}
            disabled={!dirty || !isValid || isLoading}
          >
            Submit Report
          </Button>
          {__DEV__ ? (
            <>
              <Text>errors: {JSON.stringify(errors, null, '  ')}</Text>
              <Text>values: {JSON.stringify(values, null, '  ')}</Text>
            </>
          ) : null}
        </>
      )}
    </Formik>
  );
}

Form.propTypes = {
  formikRef: propTypes.object.isRequired,
  initialValues: propTypes.object.isRequired,
  validationSchema: propTypes.object.isRequired,
  children: propTypes.func,
  carcassCoordinates: propTypes.object,
  reportType: propTypes.string.isRequired,
  onClose: propTypes.func.isRequired,
  isLoading: propTypes.bool.isRequired,
  setIsLoading: propTypes.func.isRequired,
  style: propTypes.object,
};

const styles = StyleSheet.create({
  bottomBump: {
    marginBottom: PADDING,
  },
});
<commit_msg>fix: increase post report timeout<commit_after>import { Button, Divider, Text } from '@ui-kitten/components';
import { Formik } from 'formik';
import ky from 'ky';
import propTypes from 'prop-types';
import React from 'react';
import { Alert, StyleSheet } from 'react-native';
import * as Sentry from 'sentry-expo';
import useAuth from '../../auth/context';
import config from '../../config';
import { ACCURACY, getLocation } from '../../location';
import useStyles, { PADDING } from '../../styles';
import { coordinatesToString } from '../../utilities';
import PhotoCapture from './PhotoCapture';
import RadioPills from './RadioPills';
import Species from './Species';

const GENDERS = ['female', 'male'];
const AGES = ['adult', 'juvenile'];

export default function Form({
  formikRef,
  initialValues,
  validationSchema,
  carcassCoordinates,
  reportType,
  onClose,
  children = () => null,
  isLoading,
  setIsLoading,
  style,
}) {
  const {
    authInfo: { user },
    getBearerToken,
  } = useAuth();
  const commonStyles = useStyles();

  const submitReport = async (values) => {
    console.log('submitReport');

    setIsLoading(true);

    const formData = new FormData();
    for (let valueName in values) {
      if (values[valueName] !== null) {
        formData.append(valueName, values[valueName]);
      }
    }

    // add data gathered from outside of the form
    formData.append('animal_location', coordinatesToString(carcassCoordinates));
    formData.append('user_id', user.id);
    formData.append('submit_date', new Date().toISOString());
    const currentLocation = await getLocation(ACCURACY.Highest);
    formData.append('submit_location', coordinatesToString(currentLocation.coords));

    console.log('formData', formData);

    let responseJson;
    try {
      responseJson = await ky
        .post(`${config.API}/reports/${reportType}`, {
          body: formData,
          headers: {
            Authorization: await getBearerToken(),
          },
          timeout: 20000, // give cloud run time to spin up especially in dev project
        })
        .json();
    } catch (error) {
      Sentry.Native.captureException(error);
      Alert.alert('Error', error.message);
      // TODO: allow them to cache the report for submission at a later time.

      return;
    }

    if (responseJson.success) {
      console.log('responseJson.report_id', responseJson.report_id);

      Alert.alert('Success!', 'Your report has been submitted.', [
        {
          text: 'OK',
          onPress: () => onClose(true),
        },
      ]);
    } else {
      Alert.alert('Error', responseJson.error);
    }
  };

  const onPhotoChange = (newPhotoProps) => {
    if (!newPhotoProps) {
      formikRef.current.setFieldValue('photo', null);
      formikRef.current.setFieldValue('photo_location', null);
      formikRef.current.setFieldValue('photo_date', null);
    } else {
      const { uri, type, name, coordinates, date } = newPhotoProps;
      formikRef.current.setFieldValue('photo', {
        uri,
        type,
        name,
      });
      formikRef.current.setFieldValue('photo_location', coordinates);
      formikRef.current.setFieldValue('photo_date', date);
    }
  };

  return (
    <Formik
      innerRef={formikRef}
      initialValues={initialValues}
      validationSchema={validationSchema}
      onSubmit={(values) => submitReport(values).then(() => setIsLoading(false))}
      style={style}
    >
      {({ values, setFieldValue, errors, dirty, isValid, handleSubmit }) => (
        <>
          {children({ values, setFieldValue, errors })}
          <PhotoCapture
            isRequired={validationSchema.fields.photo.spec.presence === 'required'}
            onChange={onPhotoChange}
            uri={values.photo?.uri}
          />
          <Species
            onChange={(newValue) => {
              setFieldValue('species', newValue.species);
              setFieldValue('species_confidence_level', newValue.species_confidence_level);
            }}
            values={{
              species: values.species,
              species_confidence_level: values.species_confidence_level,
            }}
            style={styles.bottomBump}
          />
          <Text category="h6">Animal age?</Text>
          <RadioPills
            value={values.age_class}
            onChange={(value) => setFieldValue('age_class', value)}
            options={AGES.concat([config.UNKNOWN])}
            style={styles.bottomBump}
          />
          <Text category="h6">Animal sex?</Text>
          <RadioPills
            value={values.sex}
            onChange={(value) => setFieldValue('sex', value)}
            options={GENDERS.concat([config.UNKNOWN])}
            style={styles.bottomBump}
          />
          <Divider style={commonStyles.margin} />
          <Button
            status="info"
            style={commonStyles.margin}
            onPress={handleSubmit}
            disabled={!dirty || !isValid || isLoading}
          >
            Submit Report
          </Button>
          {__DEV__ ? (
            <>
              <Text>errors: {JSON.stringify(errors, null, '  ')}</Text>
              <Text>values: {JSON.stringify(values, null, '  ')}</Text>
            </>
          ) : null}
        </>
      )}
    </Formik>
  );
}

Form.propTypes = {
  formikRef: propTypes.object.isRequired,
  initialValues: propTypes.object.isRequired,
  validationSchema: propTypes.object.isRequired,
  children: propTypes.func,
  carcassCoordinates: propTypes.object,
  reportType: propTypes.string.isRequired,
  onClose: propTypes.func.isRequired,
  isLoading: propTypes.bool.isRequired,
  setIsLoading: propTypes.func.isRequired,
  style: propTypes.object,
};

const styles = StyleSheet.create({
  bottomBump: {
    marginBottom: PADDING,
  },
});
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

// An Algorithm for Automatically Fitting Digitized Curves
// by Philip J. Schneider
// from "Graphics Gems", Academic Press, 1990
var PathFitter = Base.extend({
	initialize: function(path, error) {
		this.points = [];
		var segments = path._segments,
			prev;
		for (var i = 0, l = segments.length; i < l; i++) {
			var point = segments[i].point.clone();
			if (!prev || !prev.equals(point)) {
				this.points[i] = point;
				prev = point;
			}
		}
		this.error = error;
		this.iterationError = error * error;
	},

	fit: function() {
		this.segments = [new Segment(this.points[0])];
		this.fitCubic(0, this.points.length - 1,
				// Left Tangent
				this.points[1].subtract(this.points[0]).normalize(),
				// Right Tangent
				this.points[this.points.length - 2].subtract(
					this.points[this.points.length - 1]).normalize());
		return this.segments;
	},

	// Fit a Bezier curve to a (sub)set of digitized points
	fitCubic: function(first, last, tan1, tan2) {
		//	Use heuristic if region only has two points in it
		if (last - first == 1) {
			var pt1 = this.points[first],
				pt2 = this.points[last],
				dist = pt1.getDistance(pt2) / 3;
			this.addCurve([pt1, pt1.add(tan1.normalize(dist)),
					pt2.add(tan2.normalize(dist)), pt2]);
			return;
		}
		// Parameterize points, and attempt to fit curve
		var uPrime = this.chordLengthParameterize(first, last),
			prevMaxError = this.iterationError,
			error,
			split;
		// Try 4 iterations
		for (var i = 0; i < 4; i++) {
			var curve = this.generateBezier(first, last, uPrime, tan1, tan2);
			//	Find max deviation of points to fitted curve
			var max = this.findMaxError(first, last, curve, uPrime);
			if (max.error < this.error) {
				this.addCurve(curve);
				return;
			}
			split = max.index;
			// If error not too large, try some reparameterization and iteration
			if (max.error >= this.iterationError || max.error >= prevMaxError)
				break;
			uPrime = this.reparameterize(first, last, uPrime, curve);
			prevMaxError = max.error;
		}
		// Fitting failed -- split at max error point and fit recursively
		var V1 = this.points[split - 1].subtract(this.points[split]),
			V2 = this.points[split].subtract(this.points[split + 1]),
			tanCenter = V1.add(V2).divide(2).normalize();
		this.fitCubic(first, split, tan1, tanCenter);
		this.fitCubic(split, last, tanCenter.negate(), tan2);
	},

	addCurve: function(curve) {
		var prev = this.segments[this.segments.length - 1];
		prev.setHandleOut(curve[1].subtract(curve[0]));
		this.segments.push(
				new Segment(curve[3], curve[2].subtract(curve[3])));
	},

	// Use least-squares method to find Bezier control points for region.
	generateBezier: function(first, last, uPrime, tan1, tan2) {
		var epsilon = Numerical.TOLERANCE,
			pt1 = this.points[first],
			pt2 = this.points[last],
			// Create the C and X matrices
		 	C = [[0, 0], [0, 0]],
			X = [0, 0];

		for (var i = 0, l = last - first + 1; i < l; i++) {
			var u = uPrime[i],
				t = 1 - u,
				b = 3 * u * t,
				b0 = t * t * t,
				b1 = b * t,
				b2 = b * u,
				b3 = u * u * u,
				a1 = tan1.normalize(b1),
				a2 = tan2.normalize(b2),
				tmp = this.points[first + i]
					.subtract(pt1.multiply(b0 + b1))
					.subtract(pt2.multiply(b2 + b3));
			C[0][0] += a1.dot(a1);
			C[0][1] += a1.dot(a2);
			// C[1][0] += a1.dot(a2);
			C[1][0] = C[0][1];
			C[1][1] += a2.dot(a2);
			X[0] += a1.dot(tmp);
			X[1] += a2.dot(tmp);
		}

		// Compute the determinants of C and X
		var detC0C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1],
			alpha1, alpha2;
		if (Math.abs(detC0C1) > epsilon) {
			// Kramer's rule
			var detC0X  = C[0][0] * X[1]    - C[1][0] * X[0],
				detXC1  = X[0]    * C[1][1] - X[1]    * C[0][1];
			// Derive alpha values
			alpha1 = detXC1 / detC0C1;
			alpha2 = detC0X / detC0C1;
		} else {
			// Matrix is under-determined, try assuming alpha1 == alpha2
			var c0 = C[0][0] + C[0][1],
				c1 = C[1][0] + C[1][1];
			if (Math.abs(c0) > epsilon) {
				alpha1 = alpha2 = X[0] / c0;
			} else if (Math.abs(c0) > epsilon) {
				alpha1 = alpha2 = X[1] / c1;
			} else {
				// Handle below
				alpha1 = alpha2 = 0.;
			}
		}

		// If alpha negative, use the Wu/Barsky heuristic (see text)
		// (if alpha is 0, you get coincident control points that lead to
		// divide by zero in any subsequent NewtonRaphsonRootFind() call.
		var segLength = pt2.getDistance(pt1);
		epsilon *= segLength;
		if (alpha1 < epsilon || alpha2 < epsilon) {
			// fall back on standard (probably inaccurate) formula,
			// and subdivide further if needed.
			alpha1 = alpha2 = segLength / 3;
		}

		// First and last control points of the Bezier curve are
		// positioned exactly at the first and last data points
		// Control points 1 and 2 are positioned an alpha distance out
		// on the tangent vectors, left and right, respectively
		return [pt1, pt1.add(tan1.normalize(alpha1)),
				pt2.add(tan2.normalize(alpha2)), pt2];
	},

	// Given set of points and their parameterization, try to find
	// a better parameterization.
	reparameterize: function(first, last, u, curve) {
		var uPrime = [];
		for (var i = first; i <= last; i++) {
			uPrime[i - first] = this.findRoot(curve, this.points[i],
					u[i - first]);
		}
		return uPrime;
	},

	// Use Newton-Raphson iteration to find better root.
	findRoot: function(curve, point, u) {
		var curve1 = [],
			curve2 = [];
		// Generate control vertices for Q'
		for (var i = 0; i <= 2; i++) {
			curve1[i] = curve[i + 1].subtract(curve[i]).multiply(3);
		}
		// Generate control vertices for Q''
		for (var i = 0; i <= 1; i++) {
			curve2[i] = curve1[i + 1].subtract(curve1[i]).multiply(2);
		}
		// Compute Q(u), Q'(u) and Q''(u)
		var pt = this.evaluate(3, curve, u),
		 	pt1 = this.evaluate(2, curve1, u),
		 	pt2 = this.evaluate(1, curve2, u),
		 	diff = pt.subtract(point),
			df = pt1.dot(pt1) + diff.dot(pt2);
		// Compute f(u) / f'(u)
		if (Math.abs(df) < Numerical.TOLERANCE)
			return u;
		// u = u - f(u) / f'(u)
		return u - V.dot(Q1_u) / df;
	},

	// Evaluate a Bezier curve at a particular parameter value
	evaluate: function(degree, curve, t) {
		// Copy array
		var tmp = curve.slice();
		// Triangle computation
		for (var i = 1; i <= degree; i++) {
			for (var j = 0; j <= degree - i; j++) {
				tmp[j] = tmp[j].multiply(1 - t).add(tmp[j + 1].multiply(t));
			}
		}
		return tmp[0];
	},

	// Assign parameter values to digitized points
	// using relative distances between points.
	chordLengthParameterize: function(first, last) {
		var u = [0];
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first - 1]
					+ this.points[i].getDistance(this.points[i - 1]);
		}
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first] / u[last - first];
		}
		return u;
	},

	// Find the maximum squared distance of digitized points to fitted curve.
	findMaxError: function(first, last, curve, u) {
		var index = Math.floor((last - first + 1) / 2),
			maxDist = 0;
		for (var i = first + 1; i < last; i++) {
			var P = this.evaluate(3, curve, u[i - first]);
			var v = P.subtract(this.points[i]);
			var dist = v.x * v.x + v.y * v.y; // squared
			if (dist >= maxDist) {
				maxDist = dist;
				index = i;
			}
		}
		return {
			error: maxDist,
			index: index
		};
	}
});
<commit_msg>Simplify code.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

// An Algorithm for Automatically Fitting Digitized Curves
// by Philip J. Schneider
// from "Graphics Gems", Academic Press, 1990
var PathFitter = Base.extend({
	initialize: function(path, error) {
		this.points = [];
		var segments = path._segments,
			prev;
		for (var i = 0, l = segments.length; i < l; i++) {
			var point = segments[i].point.clone();
			if (!prev || !prev.equals(point)) {
				this.points[i] = point;
				prev = point;
			}
		}
		this.error = error;
		this.iterationError = error * error;
	},

	fit: function() {
		this.segments = [new Segment(this.points[0])];
		this.fitCubic(0, this.points.length - 1,
				// Left Tangent
				this.points[1].subtract(this.points[0]).normalize(),
				// Right Tangent
				this.points[this.points.length - 2].subtract(
					this.points[this.points.length - 1]).normalize());
		return this.segments;
	},

	// Fit a Bezier curve to a (sub)set of digitized points
	fitCubic: function(first, last, tan1, tan2) {
		//	Use heuristic if region only has two points in it
		if (last - first == 1) {
			var pt1 = this.points[first],
				pt2 = this.points[last],
				dist = pt1.getDistance(pt2) / 3;
			this.addCurve([pt1, pt1.add(tan1.normalize(dist)),
					pt2.add(tan2.normalize(dist)), pt2]);
			return;
		}
		// Parameterize points, and attempt to fit curve
		var uPrime = this.chordLengthParameterize(first, last),
			prevMaxError = this.iterationError,
			error,
			split;
		// Try 4 iterations
		for (var i = 0; i < 4; i++) {
			var curve = this.generateBezier(first, last, uPrime, tan1, tan2);
			//	Find max deviation of points to fitted curve
			var max = this.findMaxError(first, last, curve, uPrime);
			if (max.error < this.error) {
				this.addCurve(curve);
				return;
			}
			split = max.index;
			// If error not too large, try some reparameterization and iteration
			if (max.error >= this.iterationError || max.error >= prevMaxError)
				break;
			uPrime = this.reparameterize(first, last, uPrime, curve);
			prevMaxError = max.error;
		}
		// Fitting failed -- split at max error point and fit recursively
		var V1 = this.points[split - 1].subtract(this.points[split]),
			V2 = this.points[split].subtract(this.points[split + 1]),
			tanCenter = V1.add(V2).divide(2).normalize();
		this.fitCubic(first, split, tan1, tanCenter);
		this.fitCubic(split, last, tanCenter.negate(), tan2);
	},

	addCurve: function(curve) {
		var prev = this.segments[this.segments.length - 1];
		prev.setHandleOut(curve[1].subtract(curve[0]));
		this.segments.push(
				new Segment(curve[3], curve[2].subtract(curve[3])));
	},

	// Use least-squares method to find Bezier control points for region.
	generateBezier: function(first, last, uPrime, tan1, tan2) {
		var epsilon = Numerical.TOLERANCE,
			pt1 = this.points[first],
			pt2 = this.points[last],
			// Create the C and X matrices
		 	C = [[0, 0], [0, 0]],
			X = [0, 0];

		for (var i = 0, l = last - first + 1; i < l; i++) {
			var u = uPrime[i],
				t = 1 - u,
				b = 3 * u * t,
				b0 = t * t * t,
				b1 = b * t,
				b2 = b * u,
				b3 = u * u * u,
				a1 = tan1.normalize(b1),
				a2 = tan2.normalize(b2),
				tmp = this.points[first + i]
					.subtract(pt1.multiply(b0 + b1))
					.subtract(pt2.multiply(b2 + b3));
			C[0][0] += a1.dot(a1);
			C[0][1] += a1.dot(a2);
			// C[1][0] += a1.dot(a2);
			C[1][0] = C[0][1];
			C[1][1] += a2.dot(a2);
			X[0] += a1.dot(tmp);
			X[1] += a2.dot(tmp);
		}

		// Compute the determinants of C and X
		var detC0C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1],
			alpha1, alpha2;
		if (Math.abs(detC0C1) > epsilon) {
			// Kramer's rule
			var detC0X  = C[0][0] * X[1]    - C[1][0] * X[0],
				detXC1  = X[0]    * C[1][1] - X[1]    * C[0][1];
			// Derive alpha values
			alpha1 = detXC1 / detC0C1;
			alpha2 = detC0X / detC0C1;
		} else {
			// Matrix is under-determined, try assuming alpha1 == alpha2
			var c0 = C[0][0] + C[0][1],
				c1 = C[1][0] + C[1][1];
			if (Math.abs(c0) > epsilon) {
				alpha1 = alpha2 = X[0] / c0;
			} else if (Math.abs(c0) > epsilon) {
				alpha1 = alpha2 = X[1] / c1;
			} else {
				// Handle below
				alpha1 = alpha2 = 0.;
			}
		}

		// If alpha negative, use the Wu/Barsky heuristic (see text)
		// (if alpha is 0, you get coincident control points that lead to
		// divide by zero in any subsequent NewtonRaphsonRootFind() call.
		var segLength = pt2.getDistance(pt1);
		epsilon *= segLength;
		if (alpha1 < epsilon || alpha2 < epsilon) {
			// fall back on standard (probably inaccurate) formula,
			// and subdivide further if needed.
			alpha1 = alpha2 = segLength / 3;
		}

		// First and last control points of the Bezier curve are
		// positioned exactly at the first and last data points
		// Control points 1 and 2 are positioned an alpha distance out
		// on the tangent vectors, left and right, respectively
		return [pt1, pt1.add(tan1.normalize(alpha1)),
				pt2.add(tan2.normalize(alpha2)), pt2];
	},

	// Given set of points and their parameterization, try to find
	// a better parameterization.
	reparameterize: function(first, last, u, curve) {
		var uPrime = [];
		for (var i = first; i <= last; i++) {
			uPrime[i - first] = this.findRoot(curve, this.points[i],
					u[i - first]);
		}
		return uPrime;
	},

	// Use Newton-Raphson iteration to find better root.
	findRoot: function(curve, point, u) {
		var curve1 = [],
			curve2 = [];
		// Generate control vertices for Q'
		for (var i = 0; i <= 2; i++) {
			curve1[i] = curve[i + 1].subtract(curve[i]).multiply(3);
		}
		// Generate control vertices for Q''
		for (var i = 0; i <= 1; i++) {
			curve2[i] = curve1[i + 1].subtract(curve1[i]).multiply(2);
		}
		// Compute Q(u), Q'(u) and Q''(u)
		var pt = this.evaluate(3, curve, u),
		 	pt1 = this.evaluate(2, curve1, u),
		 	pt2 = this.evaluate(1, curve2, u),
		 	diff = pt.subtract(point),
			df = pt1.dot(pt1) + diff.dot(pt2);
		// Compute f(u) / f'(u)
		if (Math.abs(df) < Numerical.TOLERANCE)
			return u;
		// u = u - f(u) / f'(u)
		return u - V.dot(Q1_u) / df;
	},

	// Evaluate a Bezier curve at a particular parameter value
	evaluate: function(degree, curve, t) {
		// Copy array
		var tmp = curve.slice();
		// Triangle computation
		for (var i = 1; i <= degree; i++) {
			for (var j = 0; j <= degree - i; j++) {
				tmp[j] = tmp[j].multiply(1 - t).add(tmp[j + 1].multiply(t));
			}
		}
		return tmp[0];
	},

	// Assign parameter values to digitized points
	// using relative distances between points.
	chordLengthParameterize: function(first, last) {
		var u = [0];
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first - 1]
					+ this.points[i].getDistance(this.points[i - 1]);
		}
		for (var i = 1, m = last - first; i <= m; i++) {
			u[i] /= u[m];
		}
		return u;
	},

	// Find the maximum squared distance of digitized points to fitted curve.
	findMaxError: function(first, last, curve, u) {
		var index = Math.floor((last - first + 1) / 2),
			maxDist = 0;
		for (var i = first + 1; i < last; i++) {
			var P = this.evaluate(3, curve, u[i - first]);
			var v = P.subtract(this.points[i]);
			var dist = v.x * v.x + v.y * v.y; // squared
			if (dist >= maxDist) {
				maxDist = dist;
				index = i;
			}
		}
		return {
			error: maxDist,
			index: index
		};
	}
});
<|endoftext|>


<commit_before>import React from 'react';
import Relay from 'react-relay';
import {AppBar, Styles, FlatButton, Tabs, Tab, AppCanvas} from 'material-ui';
import BernieLogo from './BernieLogo';
import {BernieColors} from './bernie-styles'

export default class Dashboard extends React.Component {

  render() {
    return (

        {this.props.children}

    );
  }
}<commit_msg>Remove unused dashboard<commit_after><|endoftext|>


<commit_before>/**
 * @fileoverview layout group. group include item.
 * @author NHN Ent. FE dev Lab <dl_javascript@nhnent.com>
 */

'use strict';

var $ = require('jquery');
var snippet = require('tui-code-snippet');

var statics = require('./statics');
var Item = require('./item');

/**
 * The group class make list of item and group element(jQueryObject).
 * @class Group
 * @param {object} options - option
 *     @param {string} options.id
 *     @param {array} options.items array of items
 *     @param {string} [options.html] html of group element
 *     @param {(number|string)} [options.ratio] ratio
 * @ignore
 */
var Group = snippet.defineClass(/** @lends Group.prototype */ {
    /**
     * Element pool
     */
    $pool: $('

'),

    init: function(options) {
        if (!options) {
            throw new Error(statics.ERROR.OPTIONS_NOT_DEFINED);
        }

        this.size = options.ratio + '%';
        this.id = options.id;

        this._makeElement(options.html || statics.HTML.GROUP);
        this._makeItems(options.items);
        this._appendDimmed();

        this.render();
    },

    /**
     * Make group element(JqueryObject)
     * @param {string} html The html string to create the html element
     * @private
     */
    _makeElement: function(html) {
        html = this._getHtml(html, {
            'group-id': this.id
        });

        this.$element = $(html);
        this.$element.css({
            'position': 'relative',
            'width': this.size
        });
    },

    /* eslint-disable no-useless-escape */
    /**
     * Make markup with template
     * @param {string} html A item element html
     * @param {object} map The map to change html string
     * @returns {string}
     * @private
     */
    _getHtml: function(html, map) {
        html = html.replace(/\{\{([^\}]+)\}\}/g, function(mstr, name) {
            return map[name];
        });

        return html;
    },
    /* eslint-enable no-useless-escape */

    /**
     * Make list of item by items
     * @param {array} list The list of item's IDs
     * @private
     */
    _makeItems: function(list) {
        var options = {
            groupInfo: this.id
        };
        this.list = snippet.map(list, function(item) {
            snippet.extend(item, options);

            return new Item(item);
        }, this);
    },

    /**
     * Make dimmed element
     * @private
     */
    _makeDimmed: function() {
        this.$dimmed = $('

');
        this.$dimmed.css({
            position: 'absolute',
            left: 0,
            top: 0,
            bottom: 0,
            right: 0,
            display: 'none'
        });
    },
    /**
     * Append dimmed element
     * @private
     */
    _appendDimmed: function() {
        if (!this.$dimmed) {
            this._makeDimmed();
        }
        this.$element.append(this.$dimmed);
    },

    /**
     * Remove item by index
     * @param {number} index The index of the item to remove
     **/
    remove: function(index) {
        this.storePool(this.list[index]);
        this.list.splice(index, 1);
    },

    /**
     * Add item to item list
     * @param {object} item item object
     * @param {number} [index] add The index of the item to add
     */
    add: function(item, index) {
        if (arguments.length > 1) {
            this.list.splice(index, 0, item);
        } else {
            this.list.push(item);
        }
        item.groupInfo = this.id;
    },

    /**
     * Rearrange group items
     */
    render: function() {
        snippet.forEach(this.list, function(item, index) {
            this.$dimmed.before(item.$element);
            item.index = index;
            item.$element.attr({
                'data-index': index,
                'data-groupinfo': this.id
            });
        }, this);
        this.$dimmed.hide();
    },

    /**
     * Store items to pool
     * @param {object} $element A JQuery element to store in the pool
     */
    storePool: function($element) {
        if ($element) {
            this.$pool.append($element);
        } else {
            snippet.forEach(this.list, function(item) {
                this.$pool.append(item.$element);
            }, this);
        }
    }
});

module.exports = Group;
<commit_msg>fixed line<commit_after>/**
 * @fileoverview layout group. group include item.
 * @author NHN Ent. FE dev Lab <dl_javascript@nhnent.com>
 */

'use strict';

var $ = require('jquery');
var snippet = require('tui-code-snippet');

var statics = require('./statics');
var Item = require('./item');

/**
 * The group class make list of item and group element(jQueryObject).
 * @class Group
 * @param {object} options - option
 *     @param {string} options.id
 *     @param {array} options.items array of items
 *     @param {string} [options.html] html of group element
 *     @param {(number|string)} [options.ratio] ratio
 * @ignore
 */
var Group = snippet.defineClass(/** @lends Group.prototype */ {
    /**
     * Element pool
     */
    $pool: $('

'),

    init: function(options) {
        if (!options) {
            throw new Error(statics.ERROR.OPTIONS_NOT_DEFINED);
        }

        this.size = options.ratio + '%';
        this.id = options.id;

        this._makeElement(options.html || statics.HTML.GROUP);
        this._makeItems(options.items);
        this._appendDimmed();

        this.render();
    },

    /**
     * Make group element(JqueryObject)
     * @param {string} html The html string to create the html element
     * @private
     */
    _makeElement: function(html) {
        html = this._getHtml(html, {
            'group-id': this.id
        });

        this.$element = $(html);
        this.$element.css({
            'position': 'relative',
            'width': this.size
        });
    },

    /* eslint-disable no-useless-escape */
    /**
     * Make markup with template
     * @param {string} html A item element html
     * @param {object} map The map to change html string
     * @returns {string}
     * @private
     */
    _getHtml: function(html, map) {
        html = html.replace(/\{\{([^\}]+)\}\}/g, function(mstr, name) {
            return map[name];
        });

        return html;
    },
    /* eslint-enable no-useless-escape */

    /**
     * Make list of item by items
     * @param {array} list The list of item's IDs
     * @private
     */
    _makeItems: function(list) {
        var options = {
            groupInfo: this.id
        };
        this.list = snippet.map(list, function(item) {
            snippet.extend(item, options);

            return new Item(item);
        }, this);
    },

    /**
     * Make dimmed element
     * @private
     */
    _makeDimmed: function() {
        this.$dimmed = $('

');
        this.$dimmed.css({
            position: 'absolute',
            left: 0,
            top: 0,
            bottom: 0,
            right: 0,
            display: 'none'
        });
    },

    /**
     * Append dimmed element
     * @private
     */
    _appendDimmed: function() {
        if (!this.$dimmed) {
            this._makeDimmed();
        }
        this.$element.append(this.$dimmed);
    },

    /**
     * Remove item by index
     * @param {number} index The index of the item to remove
     **/
    remove: function(index) {
        this.storePool(this.list[index]);
        this.list.splice(index, 1);
    },

    /**
     * Add item to item list
     * @param {object} item item object
     * @param {number} [index] add The index of the item to add
     */
    add: function(item, index) {
        if (arguments.length > 1) {
            this.list.splice(index, 0, item);
        } else {
            this.list.push(item);
        }
        item.groupInfo = this.id;
    },

    /**
     * Rearrange group items
     */
    render: function() {
        snippet.forEach(this.list, function(item, index) {
            this.$dimmed.before(item.$element);
            item.index = index;
            item.$element.attr({
                'data-index': index,
                'data-groupinfo': this.id
            });
        }, this);
        this.$dimmed.hide();
    },

    /**
     * Store items to pool
     * @param {object} $element A JQuery element to store in the pool
     */
    storePool: function($element) {
        if ($element) {
            this.$pool.append($element);
        } else {
            snippet.forEach(this.list, function(item) {
                this.$pool.append(item.$element);
            }, this);
        }
    }
});

module.exports = Group;
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

// An Algorithm for Automatically Fitting Digitized Curves
// by Philip J. Schneider
// from "Graphics Gems", Academic Press, 1990
var PathFitter = Base.extend({
	initialize: function(path, error) {
		this.points = [];
		var segments = path._segments,
			prev;
		for (var i = 0, l = segments.length; i < l; i++) {
			var point = segments[i].point.clone();
			if (!prev || !prev.equals(point)) {
				this.points[i] = point;
				prev = point;
			}
		}
		this.error = error;
		this.iterationError = error * error;
	},

	fit: function() {
		this.segments = [new Segment(this.points[0])];
		this.fitCubic(0, this.points.length - 1,
				// Left Tangent
				this.points[1].subtract(this.points[0]).normalize(),
				// Right Tangent
				this.points[this.points.length - 2].subtract(
					this.points[this.points.length - 1]).normalize());
		return this.segments;
	},

	// Fit a Bezier curve to a (sub)set of digitized points
	fitCubic: function(first, last, tHat1, tHat2) {
		//	Use heuristic if region only has two points in it
		if (last - first == 1) {
			var pt1 = this.points[first],
				pt2 = this.points[last],
				dist = pt1.getDistance(pt2) / 3;
			this.addCurve([pt1, pt1.add(tHat1.normalize(dist)),
					pt2.add(tHat2.normalize(dist)), pt2]);
			return;
		}
		// Parameterize points, and attempt to fit curve
		var uPrime = this.chordLengthParameterize(first, last),
			prevMaxError = this.iterationError,
			error,
			split;
		// Try 4 iterations
		for (var i = 0; i < 4; i++) {
			var bezCurve = this.generateBezier(first, last, uPrime, tHat1, tHat2);
			//	Find max deviation of points to fitted curve
			var max = this.findMaxError(first, last, bezCurve, uPrime);
			if (max.error < this.error) {
				this.addCurve(bezCurve);
				return;
			}
			split = max.index;
			// If error not too large, try some reparameterization and iteration
			if (max.error >= this.iterationError || max.error >= prevMaxError)
				break;
			uPrime = this.reparameterize(first, last, uPrime, bezCurve);
			prevMaxError = max.error;
		}
		// Fitting failed -- split at max error point and fit recursively
		var V1 = this.points[split - 1].subtract(this.points[split]),
			V2 = this.points[split].subtract(this.points[split + 1]),
			tHatCenter = V1.add(V2).divide(2).normalize();
		this.fitCubic(first, split, tHat1, tHatCenter);
		this.fitCubic(split, last, tHatCenter.negate(), tHat2);
	},

	addCurve: function(bezCurve) {
		var prev = this.segments[this.segments.length - 1];
		prev.setHandleOut(bezCurve[1].subtract(bezCurve[0]));
		this.segments.push(
				new Segment(bezCurve[3], bezCurve[2].subtract(bezCurve[3])));
	},

	// Use least-squares method to find Bezier control points for region.
	generateBezier: function(first, last, uPrime, tHat1, tHat2) {
		var nPts = last - first + 1,
			pt1 = this.points[first],
			pt2 = this.points[last];

		// Create the C and X matrices
		var C = [[0, 0], [0, 0]],
			X = [0, 0];

		for (var i = 0; i < nPts; i++) {
			var u = uPrime[i],
				t = 1 - u,
				b = 3 * u * t,
				b0 = t * t * t,
				b1 = b * t,
				b2 = b * u,
				b3 = u * u * u,
				a1 = tHat1.normalize(b1),
				a2 = tHat2.normalize(b2),
				tmp = this.points[first + i]
					.subtract(pt1.multiply(b0 + b1))
					.subtract(pt2.multiply(b2 + b3));
			C[0][0] += a1.dot(a1);
			C[0][1] += a1.dot(a2);
			// C[1][0] += a1.dot(a2);
			C[1][0] = C[0][1];
			C[1][1] += a2.dot(a2);
			X[0] += A[i][0].dot(tmp);
			X[1] += A[i][1].dot(tmp);
		}

		// Compute the determinants of C and X
		var det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1],
			det_C0_X  = C[0][0] * X[1]    - C[1][0] * X[0],
			det_X_C1  = X[0]    * C[1][1] - X[1]    * C[0][1],
			singularity = det_C0_C1 < Numerical.TOLERANCE;

		// Finally, derive alpha values
		var alpha_l = singularity ? 0 : det_X_C1 / det_C0_C1,
			alpha_r = singularity ? 0 : det_C0_X / det_C0_C1;

		// If alpha negative, use the Wu/Barsky heuristic (see text)
		// (if alpha is 0, you get coincident control points that lead to
		// divide by zero in any subsequent NewtonRaphsonRootFind() call.
		var segLength = pt2.getDistance(pt1),
			epsilon = Numerical.TOLERANCE * segLength;
		if (alpha_l < epsilon || alpha_r < epsilon) {
			// fall back on standard (probably inaccurate) formula,
			// and subdivide further if needed.
			alpha_l = alpha_r = segLength / 3;
		}

		// First and last control points of the Bezier curve are
		// positioned exactly at the first and last data points
		// Control points 1 and 2 are positioned an alpha distance out
		// on the tangent vectors, left and right, respectively
		return [pt1, pt1.add(tHat1.normalize(alpha_l)),
				pt2.add(tHat2.normalize(alpha_r)), pt2];
	},

	// Given set of points and their parameterization, try to find
	// a better parameterization.
	reparameterize: function(first, last, u, bezCurve) {
		var uPrime = [];
		for (var i = first; i <= last; i++) {
			uPrime[i - first] = this.findRoot(bezCurve, this.points[i],
					u[i - first]);
		}
		return uPrime;
	},

	// Use Newton-Raphson iteration to find better root.
	findRoot: function(Q, P, u) {
		var Q1 = [],
			Q2 = [];
		// Generate control vertices for Q'
		for (var i = 0; i <= 2; i++) {
			Q1[i] = Q[i + 1].subtract(Q[i]).multiply(3);
		}
		// Generate control vertices for Q''
		for (var i = 0; i <= 1; i++) {
			Q2[i] = Q1[i + 1].subtract(Q1[i]).multiply(2);
		}
		// Compute Q(u), Q'(u) and Q''(u)
		Q_u = this.evaluate(3, Q, u);
		Q1_u = this.evaluate(2, Q1, u);
		Q2_u = this.evaluate(1, Q2, u);
		// Compute f(u)/f'(u)
		var V = Q_u.subtract(P),
			df = Q1_u.dot(Q1_u) + V.dot(Q2_u);
		if (df == 0)
			return u;
		// u = u - f(u) / f'(u)
		return u - V.dot(Q1_u) / df;
	},

	// Evaluate a Bezier curve at a particular parameter value
	evaluate: function(degree, V, t) {
		// Copy array
		var Vtemp = V.slice();
		// Triangle computation
		for (var i = 1; i <= degree; i++) {
			for (var j = 0; j <= degree - i; j++) {
				Vtemp[j] = Vtemp[j].multiply(1 - t).add(Vtemp[j + 1].multiply(t));
			}
		}
		return Vtemp[0];
	},

	// Assign parameter values to digitized points
	// using relative distances between points.
	chordLengthParameterize: function(first, last) {
		var u = [0];
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first - 1]
					+ this.points[i].getDistance(this.points[i - 1]);
		}
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first] / u[last - first];
		}
		return u;
	},

	// Find the maximum squared distance of digitized points to fitted curve.
	findMaxError: function(first, last, bezCurve, u) {
		var index = Math.floor((last - first + 1) / 2),
			maxDist = 0;
		for (var i = first + 1; i < last; i++) {
			var P = this.evaluate(3, bezCurve, u[i - first]);
			var v = P.subtract(this.points[i]);
			var dist = v.x * v.x + v.y * v.y; // squared
			if (dist >= maxDist) {
				maxDist = dist;
				index = i;
			}
		}
		return {
			error: maxDist,
			index: index
		};
	}
});
<commit_msg>Handle case of nearly singular matrix separately.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

// An Algorithm for Automatically Fitting Digitized Curves
// by Philip J. Schneider
// from "Graphics Gems", Academic Press, 1990
var PathFitter = Base.extend({
	initialize: function(path, error) {
		this.points = [];
		var segments = path._segments,
			prev;
		for (var i = 0, l = segments.length; i < l; i++) {
			var point = segments[i].point.clone();
			if (!prev || !prev.equals(point)) {
				this.points[i] = point;
				prev = point;
			}
		}
		this.error = error;
		this.iterationError = error * error;
	},

	fit: function() {
		this.segments = [new Segment(this.points[0])];
		this.fitCubic(0, this.points.length - 1,
				// Left Tangent
				this.points[1].subtract(this.points[0]).normalize(),
				// Right Tangent
				this.points[this.points.length - 2].subtract(
					this.points[this.points.length - 1]).normalize());
		return this.segments;
	},

	// Fit a Bezier curve to a (sub)set of digitized points
	fitCubic: function(first, last, tHat1, tHat2) {
		//	Use heuristic if region only has two points in it
		if (last - first == 1) {
			var pt1 = this.points[first],
				pt2 = this.points[last],
				dist = pt1.getDistance(pt2) / 3;
			this.addCurve([pt1, pt1.add(tHat1.normalize(dist)),
					pt2.add(tHat2.normalize(dist)), pt2]);
			return;
		}
		// Parameterize points, and attempt to fit curve
		var uPrime = this.chordLengthParameterize(first, last),
			prevMaxError = this.iterationError,
			error,
			split;
		// Try 4 iterations
		for (var i = 0; i < 4; i++) {
			var bezCurve = this.generateBezier(first, last, uPrime, tHat1, tHat2);
			//	Find max deviation of points to fitted curve
			var max = this.findMaxError(first, last, bezCurve, uPrime);
			if (max.error < this.error) {
				this.addCurve(bezCurve);
				return;
			}
			split = max.index;
			// If error not too large, try some reparameterization and iteration
			if (max.error >= this.iterationError || max.error >= prevMaxError)
				break;
			uPrime = this.reparameterize(first, last, uPrime, bezCurve);
			prevMaxError = max.error;
		}
		// Fitting failed -- split at max error point and fit recursively
		var V1 = this.points[split - 1].subtract(this.points[split]),
			V2 = this.points[split].subtract(this.points[split + 1]),
			tHatCenter = V1.add(V2).divide(2).normalize();
		this.fitCubic(first, split, tHat1, tHatCenter);
		this.fitCubic(split, last, tHatCenter.negate(), tHat2);
	},

	addCurve: function(bezCurve) {
		var prev = this.segments[this.segments.length - 1];
		prev.setHandleOut(bezCurve[1].subtract(bezCurve[0]));
		this.segments.push(
				new Segment(bezCurve[3], bezCurve[2].subtract(bezCurve[3])));
	},

	// Use least-squares method to find Bezier control points for region.
	generateBezier: function(first, last, uPrime, tHat1, tHat2) {
		var nPts = last - first + 1,
			pt1 = this.points[first],
			pt2 = this.points[last];

		// Create the C and X matrices
		var C = [[0, 0], [0, 0]],
			X = [0, 0];

		for (var i = 0; i < nPts; i++) {
			var u = uPrime[i],
				t = 1 - u,
				b = 3 * u * t,
				b0 = t * t * t,
				b1 = b * t,
				b2 = b * u,
				b3 = u * u * u,
				a1 = tHat1.normalize(b1),
				a2 = tHat2.normalize(b2),
				tmp = this.points[first + i]
					.subtract(pt1.multiply(b0 + b1))
					.subtract(pt2.multiply(b2 + b3));
			C[0][0] += a1.dot(a1);
			C[0][1] += a1.dot(a2);
			// C[1][0] += a1.dot(a2);
			C[1][0] = C[0][1];
			C[1][1] += a2.dot(a2);
			X[0] += A[i][0].dot(tmp);
			X[1] += A[i][1].dot(tmp);
		}

		// Compute the determinants of C and X
		var det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1],
			alpha_l, alpha_r;
		if (Math.abs(det_C0_C1) < Numerical.TOLERANCE) {
			// Kramer's rule
			var det_C0_X  = C[0][0] * X[1]    - C[1][0] * X[0],
				det_X_C1  = X[0]    * C[1][1] - X[1]    * C[0][1];
			// Derive alpha values
			alpha_l = det_X_C1 / det_C0_C1;
			alpha_r = det_C0_X / det_C0_C1;
		} else {
			// Matrix is under-determined, try assuming alpha_l == alpha_r
			var c0 = C[0][0] + C[0][1],
				c1 = C[1][0] + C[1][1];
			if (Math.abs(c0) > Numerical.TOLERANCE) {
				alpha_l = alpha_r = X[0] / c0;
			} else if (Math.abs(c0) > Numerical.TOLERANCE) {
				alpha_l = alpha_r = X[1] / c1;
			} else {
				// Handle below
				alpha_l = alpha_r = 0.;
			}
		}

		// If alpha negative, use the Wu/Barsky heuristic (see text)
		// (if alpha is 0, you get coincident control points that lead to
		// divide by zero in any subsequent NewtonRaphsonRootFind() call.
		var segLength = pt2.getDistance(pt1),
			epsilon = Numerical.TOLERANCE * segLength;
		if (alpha_l < epsilon || alpha_r < epsilon) {
			// fall back on standard (probably inaccurate) formula,
			// and subdivide further if needed.
			alpha_l = alpha_r = segLength / 3;
		}

		// First and last control points of the Bezier curve are
		// positioned exactly at the first and last data points
		// Control points 1 and 2 are positioned an alpha distance out
		// on the tangent vectors, left and right, respectively
		return [pt1, pt1.add(tHat1.normalize(alpha_l)),
				pt2.add(tHat2.normalize(alpha_r)), pt2];
	},

	// Given set of points and their parameterization, try to find
	// a better parameterization.
	reparameterize: function(first, last, u, bezCurve) {
		var uPrime = [];
		for (var i = first; i <= last; i++) {
			uPrime[i - first] = this.findRoot(bezCurve, this.points[i],
					u[i - first]);
		}
		return uPrime;
	},

	// Use Newton-Raphson iteration to find better root.
	findRoot: function(Q, P, u) {
		var Q1 = [],
			Q2 = [];
		// Generate control vertices for Q'
		for (var i = 0; i <= 2; i++) {
			Q1[i] = Q[i + 1].subtract(Q[i]).multiply(3);
		}
		// Generate control vertices for Q''
		for (var i = 0; i <= 1; i++) {
			Q2[i] = Q1[i + 1].subtract(Q1[i]).multiply(2);
		}
		// Compute Q(u), Q'(u) and Q''(u)
		Q_u = this.evaluate(3, Q, u);
		Q1_u = this.evaluate(2, Q1, u);
		Q2_u = this.evaluate(1, Q2, u);
		// Compute f(u)/f'(u)
		var V = Q_u.subtract(P),
			df = Q1_u.dot(Q1_u) + V.dot(Q2_u);
		if (df == 0)
			return u;
		// u = u - f(u) / f'(u)
		return u - V.dot(Q1_u) / df;
	},

	// Evaluate a Bezier curve at a particular parameter value
	evaluate: function(degree, V, t) {
		// Copy array
		var Vtemp = V.slice();
		// Triangle computation
		for (var i = 1; i <= degree; i++) {
			for (var j = 0; j <= degree - i; j++) {
				Vtemp[j] = Vtemp[j].multiply(1 - t).add(Vtemp[j + 1].multiply(t));
			}
		}
		return Vtemp[0];
	},

	// Assign parameter values to digitized points
	// using relative distances between points.
	chordLengthParameterize: function(first, last) {
		var u = [0];
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first - 1]
					+ this.points[i].getDistance(this.points[i - 1]);
		}
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first] / u[last - first];
		}
		return u;
	},

	// Find the maximum squared distance of digitized points to fitted curve.
	findMaxError: function(first, last, bezCurve, u) {
		var index = Math.floor((last - first + 1) / 2),
			maxDist = 0;
		for (var i = first + 1; i < last; i++) {
			var P = this.evaluate(3, bezCurve, u[i - first]);
			var v = P.subtract(this.points[i]);
			var dist = v.x * v.x + v.y * v.y; // squared
			if (dist >= maxDist) {
				maxDist = dist;
				index = i;
			}
		}
		return {
			error: maxDist,
			index: index
		};
	}
});
<|endoftext|>


<commit_before>import Editor from './editor/editor';
import * as UI from './editor/ui';
import ImageCard from './cards/image';
import Range from './utils/cursor/range';
import Position from './utils/cursor/position';
import Error from './utils/mobiledoc-error';
import VERSION from './version';
import { MOBILEDOC_VERSION } from './renderers/mobiledoc';

const Mobiledoc = {
  Editor,
  UI,
  ImageCard,
  Range,
  Position,
  Error,
  VERSION,
  MOBILEDOC_VERSION
};

export function registerGlobal(global) {
  global.Mobiledoc = Mobiledoc;
}

export { Editor, UI, Range, Position, MOBILEDOC_VERSION };
export default Mobiledoc;
<commit_msg>Remove global 🦺<commit_after>import Editor from './editor/editor';
import ImageCard from './cards/image';
import Range from './utils/cursor/range';
import Position from './utils/cursor/position';
import Error from './utils/mobiledoc-error';
import VERSION from './version';
import { MOBILEDOC_VERSION } from './renderers/mobiledoc';

export { Editor, ImageCard, Range, Position, Error, VERSION, MOBILEDOC_VERSION };
<|endoftext|>


<commit_before>application = function() {

    var clientPaths = {
        "darwin": {
            "x64": "./client/mac/BTClient-x64",
            "ia32": "./client/mac/BTClient"
        },
        "win32": {
            "x64": "./client/win/BTClient-x64.exe",
            "ia32": "./client/win/BTClient.exe"
        },
        "linux": {
            "x64": "./client/linux/BTClient-x64",
            "ia32": "./client/linux/BTClient"
        }
    };

    var loadingOpts = false;
    var waitingOnBoards = false;

    var handleOverlay = function() {
        if (!loadingOpts && !waitingOnBoards) {
            document.getElementById("loadingBackdrop").close();
        }
    }

    var opts = null;
    var optPanels = {};
    var loadOptions = function(options) {
        opts = options;
        loadingOpts = false;
        var pushPages = document.getElementsByTagName("push-pages")[0]
        //setup option pages
        optPanels = createOptionPanels(options);
        //insert each panel
        for (p in optPanels) {
            Polymer.dom(pushPages).appendChild(optPanels[p].wrapper);
            if (optPanels[p].hasOwnProperty("dependants")) {
                Polymer.dom.flush();
                optPanels[p].setup();
            }
        }
        //add the installer panel
        var ip = document.createElement('install-panel');
        var na = document.createElement('neon-animatable');
        na.appendChild(ip);
        ip.addEventListener("beginFirmwareUpload", installHandler);
        Polymer.dom(pushPages).appendChild(na);
        //handle overlay
        handleOverlay();
    }

    var installHandler = function() {
        //iterate over option panels and get user selcted values
        var options = {};

        //TODO: Rebuild this logic to use cleaner option format
        /*for (prop in optPanels) {
            var curr = optPanels[prop];
            if (curr.panel.tagName.toLowerCase() == "radio-option-panel") {
                options[prop] = curr.panel.selected.ugly();
            }
            else if (curr.panel.tagName.toLowerCase() == "slider-option-panel") {
                options[prop] = curr.panel.value;
            }
            else if (curr.panel.tagName.toLowerCase() == "switch-option-panel") {
                var switches = curr.panel.options;
                for (sw in switches) {
                    var optName = switches[sw].name.ugly();
                    options[optName] = switches[sw].on;
                }
            }
        }*/
        //Get build from server
        var installPanel = document.getElementsByTagName('install-panel')[0];
        installPanel.requestingBuild = true;
        //Get build from server
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "http://build.brewtroller.com:8080/build", true);
        xhr.responseType = "json";
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                if (xhr.status == 200) {
                    if (xhr.response.hasOwnProperty('binary')) {
                        installPanel.uploadingToBoard = true;
                        installPanel.requestingBuild = false;
                        app.socket.send(JSON.stringify({"type": "2", "device": device, "payload": xhr.response.binary}));
                        return;
                    }
                }
                handleServerError(xhr.response, xhr.status);
            }
        };
        xhr.send(JSON.stringify(options));
    };

    var handleServerError = function(resp, code) {
        //clear spinner in backdrop and set error message
        var overlay = document.getElementById("loadingBackdrop");
        var spinner = document.getElementById("loadingSpinner");
        overlay.removeChild(spinner);
        overlay.querySelector("span").innerHTML = "Error contacting BrewTroller Build Server.
Check your network connection or try again later."
        //reset the overlay sizing
        overlay.close();
        overlay.open();
    }

    var handleClientError = function(err) {
        var overlay = document.getElementById("loadingBackdrop");
        var spinner = document.getElementById("loadingSpinner");
        if (spinner != null) {
            overlay.removeChild(spinner);
        }
        overlay.querySelector("span").innerHTML = err
        //reset the overlay sizing
        overlay.close();
        overlay.open();
    }

    var device = null;
    var handleClientMessage = function(m) {
        //Handle boards return
        if (m instanceof Array) {
            if (m.length == 0) {
                //Got no boards, show error
                var overlay = document.getElementById("loadingBackdrop");
                var spinner = document.getElementById("loadingSpinner");
                if (spinner != null) {
                    overlay.removeChild(spinner);
                }
                overlay.querySelector("span").innerHTML = "No BrewTrollers Dectected.
Check connections and try again."
                //reset the overlay sizing
                overlay.close();
                overlay.open();
            }
            else {
                //use first board
                waitingOnBoards = false;
                var info = document.getElementsByTagName('info-panel')[0];
                var statusParts = m[0].Status.split("\t");
                info.port = m[0].Port;
                info.board = "Unable to detect board version";
                info.firmware = statusParts[3] + "." + statusParts[4];
                handleOverlay();
                device = m[0].Port;
            }
        } else {
            if (m.hasOwnProperty("flash")) {
                var installPanel = document.getElementsByTagName('install-panel')[0];
                installPanel.uploadingToBoard = false;
                if (m.flash != "complete"){
                    var overlay = document.getElementById('loadingBackdrop');
                    //remove spinner if necessary
                    var loadingSpinner = document.getElementById("loadingSpinner");
                    if (loadingSpinner != null) {
                        overlay.removeChild(loadingSpinner);
                    }
                    overlay.querySelector("span").innerHTML = "Error flashing Board!:
" + m.flash;
                    overlay.open();
                }
            }
        }
    }

    var scanForBoards = function() {
        var message = {"type": "1"};
        this.socket.send(JSON.stringify(message));
    }

    this.socket = null;
    var handleClientSpawn = function(port) {
        app.socket = new WebSocket("ws://127.0.0.1:" + port);
        app.socket.onmessage = function(e) {
            handleClientMessage(JSON.parse(e.data));
        }
        app.socket.onopen = function(){
            //Scan for boards
            scanForBoards.bind(app)();
        }
    }

    var clientPort = null;

    //kickoff options pull from server
    var xhr = new XMLHttpRequest();
    //xhr.open("GET", "http://build.brewtroller.com:8080/options", true);
    xhr.open("GET", "../../options.json.example", true);
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                loadOptions(JSON.parse(xhr.responseText));
            }
            else {
                handleServerError(JSON.parse(xhr.responseText), xhr.status);
            }
        }
    }
    xhr.send();

    this.client = null;
    waitingOnBoards = true;

    //If we are running in the Node.js environment
    if (typeof process != "undefined") {
        var spawn = require('child_process').spawn;
        //spawn a client instance
        this.client = spawn(clientPaths[process.platform][process.arch])
        this.client.stdout.on('data', function(data){
            if (clientPort == null) {
                handleClientSpawn(Number(data));
            }
        });
        this.client.stderr.on('data', function(data) {
            console.log("err: " + data);
            handleClientError(data);
        });
        this.client.on('close', function(code){
            console.log("client closed: " + code);
            this.client = null;
        });

        var onClose = function(e) {
            if (app.socket != null) {
                app.socket.close();
                app.socket = null;
            }
            if (app.client != null) {
                app.client.kill();
                app.client = null;
            }
            this.close(true);
        }
        var nw = require('nw.gui');
        var win = nw.Window.get();
        win.on('close', onClose);
    }
    else {
        waitingOnBoards = false;
    }
};

var app = null;
window.onload = function() {
    document.getElementById("loadingBackdrop").open();
    app = new application();
}<commit_msg>Ensure we timeout if the server is down, and display an appropriate message.<commit_after>application = function() {

    var clientPaths = {
        "darwin": {
            "x64": "./client/mac/BTClient-x64",
            "ia32": "./client/mac/BTClient"
        },
        "win32": {
            "x64": "./client/win/BTClient-x64.exe",
            "ia32": "./client/win/BTClient.exe"
        },
        "linux": {
            "x64": "./client/linux/BTClient-x64",
            "ia32": "./client/linux/BTClient"
        }
    };

    var loadingOpts = false;
    var waitingOnBoards = false;

    var handleOverlay = function() {
        if (!loadingOpts && !waitingOnBoards) {
            document.getElementById("loadingBackdrop").close();
        }
    }

    var opts = null;
    var optPanels = {};
    var loadOptions = function(options) {
        opts = options;
        loadingOpts = false;
        var pushPages = document.getElementsByTagName("push-pages")[0]
        //setup option pages
        optPanels = createOptionPanels(options);
        //insert each panel
        for (p in optPanels) {
            Polymer.dom(pushPages).appendChild(optPanels[p].wrapper);
            if (optPanels[p].hasOwnProperty("dependants")) {
                Polymer.dom.flush();
                optPanels[p].setup();
            }
        }
        //add the installer panel
        var ip = document.createElement('install-panel');
        var na = document.createElement('neon-animatable');
        na.appendChild(ip);
        ip.addEventListener("beginFirmwareUpload", installHandler);
        Polymer.dom(pushPages).appendChild(na);
        //handle overlay
        handleOverlay();
    }

    var installHandler = function() {
        //iterate over option panels and get user selcted values
        var options = {};

        //TODO: Rebuild this logic to use cleaner option format
        /*for (prop in optPanels) {
            var curr = optPanels[prop];
            if (curr.panel.tagName.toLowerCase() == "radio-option-panel") {
                options[prop] = curr.panel.selected.ugly();
            }
            else if (curr.panel.tagName.toLowerCase() == "slider-option-panel") {
                options[prop] = curr.panel.value;
            }
            else if (curr.panel.tagName.toLowerCase() == "switch-option-panel") {
                var switches = curr.panel.options;
                for (sw in switches) {
                    var optName = switches[sw].name.ugly();
                    options[optName] = switches[sw].on;
                }
            }
        }*/
        //Get build from server
        var installPanel = document.getElementsByTagName('install-panel')[0];
        installPanel.requestingBuild = true;
        //Get build from server
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "http://build.brewtroller.com:8080/build", true);
        xhr.responseType = "json";
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                if (xhr.status == 200) {
                    if (xhr.response.hasOwnProperty('binary')) {
                        installPanel.uploadingToBoard = true;
                        installPanel.requestingBuild = false;
                        app.socket.send(JSON.stringify({"type": "2", "device": device, "payload": xhr.response.binary}));
                        return;
                    }
                }
                handleServerError(xhr.response, xhr.status);
            }
        };
        xhr.send(JSON.stringify(options));
    };

    var handleServerError = function(resp, code) {
        //clear spinner in backdrop and set error message
        var overlay = document.getElementById("loadingBackdrop");
        var spinner = document.getElementById("loadingSpinner");
        overlay.removeChild(spinner);
        overlay.querySelector("span").innerHTML = "Error contacting BrewTroller Build Server.
Check your network connection or try again later."
        //reset the overlay sizing
        overlay.close();
        overlay.open();
    }

    var handleClientError = function(err) {
        var overlay = document.getElementById("loadingBackdrop");
        var spinner = document.getElementById("loadingSpinner");
        if (spinner != null) {
            overlay.removeChild(spinner);
        }
        overlay.querySelector("span").innerHTML = err
        //reset the overlay sizing
        overlay.close();
        overlay.open();
    }

    var device = null;
    var handleClientMessage = function(m) {
        //Handle boards return
        if (m instanceof Array) {
            if (m.length == 0) {
                //Got no boards, show error
                var overlay = document.getElementById("loadingBackdrop");
                var spinner = document.getElementById("loadingSpinner");
                if (spinner != null) {
                    overlay.removeChild(spinner);
                }
                overlay.querySelector("span").innerHTML = "No BrewTrollers Dectected.
Check connections and try again."
                //reset the overlay sizing
                overlay.close();
                overlay.open();
            }
            else {
                //use first board
                waitingOnBoards = false;
                var info = document.getElementsByTagName('info-panel')[0];
                var statusParts = m[0].Status.split("\t");
                info.port = m[0].Port;
                info.board = "Unable to detect board version";
                info.firmware = statusParts[3] + "." + statusParts[4];
                handleOverlay();
                device = m[0].Port;
            }
        } else {
            if (m.hasOwnProperty("flash")) {
                var installPanel = document.getElementsByTagName('install-panel')[0];
                installPanel.uploadingToBoard = false;
                if (m.flash != "complete"){
                    var overlay = document.getElementById('loadingBackdrop');
                    //remove spinner if necessary
                    var loadingSpinner = document.getElementById("loadingSpinner");
                    if (loadingSpinner != null) {
                        overlay.removeChild(loadingSpinner);
                    }
                    overlay.querySelector("span").innerHTML = "Error flashing Board!:
" + m.flash;
                    overlay.open();
                }
            }
        }
    }

    var scanForBoards = function() {
        var message = {"type": "1"};
        this.socket.send(JSON.stringify(message));
    }

    this.socket = null;
    var handleClientSpawn = function(port) {
        app.socket = new WebSocket("ws://127.0.0.1:" + port);
        app.socket.onmessage = function(e) {
            handleClientMessage(JSON.parse(e.data));
        }
        app.socket.onopen = function(){
            //Scan for boards
            scanForBoards.bind(app)();
        }
    }

    var clientPort = null;

    //kickoff options pull from server
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "http://build.brewtroller.com:8080/options", true);

    //Use this file for testing!
    //xhr.open("GET", "../../options.json.example", true);
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                loadOptions(JSON.parse(xhr.responseText));
            }
            else {
                handleServerError(JSON.parse(xhr.responseText), xhr.status);
            }
        }
    }
    //Timeout the request after 10s, as the server maybe down
    xhr.timeout = 10000;
    xhr.ontimeout = function() {
        handleServerError();
    }
    xhr.send();
    loadingOpts = true;

    this.client = null;
    waitingOnBoards = true;

    //If we are running in the Node.js environment
    if (typeof process != "undefined") {
        var spawn = require('child_process').spawn;
        //spawn a client instance
        this.client = spawn(clientPaths[process.platform][process.arch])
        this.client.stdout.on('data', function(data){
            if (clientPort == null) {
                handleClientSpawn(Number(data));
            }
        });
        this.client.stderr.on('data', function(data) {
            console.log("err: " + data);
            handleClientError(data);
        });
        this.client.on('close', function(code){
            console.log("client closed: " + code);
            this.client = null;
        });

        var onClose = function(e) {
            if (app.socket != null) {
                app.socket.close();
                app.socket = null;
            }
            if (app.client != null) {
                app.client.kill();
                app.client = null;
            }
            this.close(true);
        }
        var nw = require('nw.gui');
        var win = nw.Window.get();
        win.on('close', onClose);
    }
    else {
        waitingOnBoards = false;
    }
};

var app = null;
window.onload = function() {
    document.getElementById("loadingBackdrop").open();
    app = new application();
}<|endoftext|>