<commit_before>import React, { PropTypes } from 'react';

import { withGoogleMap } from 'react-google-maps';
import GoogleMap from 'react-google-maps/lib/GoogleMap';
import Marker from 'react-google-maps/lib/Marker';

import styles from './styles.css';

const GoogleMapLoader = withGoogleMap(props => (
  <GoogleMap {...props.mapProps}>
    <Marker {...props.marker} />
  </GoogleMap>
));

export default class LocationField extends React.Component {
  static contextTypes = {
    notify: PropTypes.func
  };
  static propTypes = {
    value: PropTypes.string,
    dataValue: PropTypes.object,
    onChange: PropTypes.func,
    onDataChange: PropTypes.func,
    defaultLocation: PropTypes.object,
    className: PropTypes.string,
  }
  constructor(props) {
    super(props);
    this.state = { clean: true };
  }
  componentDidMount() {
    const { LOCALE_COUNTRY } = window;
    const options = { types: [], componentRestrictions: { country: LOCALE_COUNTRY } };
    const { input } = this.refs;
    const { maps } = window.google;
    const autocomplete = new maps.places.Autocomplete(input, options);
    maps.event.addListener(autocomplete, 'place_changed', () => {
      const place = autocomplete.getPlace();
      this.onPlaceChange(place);
      return place;
    });
  }
  onBlur = event => {
    if (!this.state.clean) {
      event.target.value = '';
    }
  }
  onFocus = event => {
    event.target.select();
  }
  onChange = event => {
    if (!(event.nativeEvent.detail && event.nativeEvent.detail === 'generated')) {
      this.setState({ clean: false });
      event.stopPropagation();
      event.preventDefault();
    }
  }
  onPlaceChange = place => {
    if (!place.geometry) {
      this.context.notify('No map data for this location; please try a different address', 'error');
      return;
    }
    this.latLngChange(place.geometry.location, { placeID: place.place_id });
    this.props.onChange(place.formatted_address);
    this.setState({ clean: true });
  }
  latLngChange = (latLng, extraData) => {
    const locationData = {
      lat: latLng.lat(),
      lng: latLng.lng(),
      ...extraData
    };
    this.changeCenter(locationData);
    this.props.onDataChange(locationData);
  }
  changeCenter = locationData => {
    if (this.refs.component) {
      this.refs.component.state.map.panTo(locationData);
    }
  }
  render() {
    const { value, dataValue, className } = this.props;
    const attrs = {
      type: 'text',
      name,
      className,
      ref: 'input',
      onFocus: this.onFocus,
      onBlur: this.onBlur,
      onChange: this.onChange,
      placeholder: value,
      defaultValue: value
    };
    let map = null;
    let mapHelp = null;
    let locationData = dataValue;
    if (locationData) {
      if (typeof locationData === 'string') locationData = JSON.parse(locationData);
      const marker = {
        position: locationData,
        icon: { url: '/images/map-pin-active.svg' },
        defaultAnimation: 2,
        draggable: true,
        cursor: '-webkit-grab, move',
        onDragEnd: drag => {
          this.latLngChange(drag.latLng);
        }
      };
      const mapProps = {
        defaultZoom: 15,
        defaultCenter: locationData,
        center: locationData,
        draggableCursor: '-webkit-grab, move',
        options: { streetViewControl: false, scrollwheel: false, mapTypeControl: false }
      };
      map = (<GoogleMapLoader
        containerElement={
}
        mapElement={
}
        mapProps={mapProps}
        marker={marker}
        ref="component"
      />);
      mapHelp =
Drag map pin to refine location
;
    }
    return (

      <input {...attrs} />
      {map}
      {mapHelp}

);
  }
}
<commit_msg>address name fix<commit_after>import React, { PropTypes } from 'react';

import { withGoogleMap } from 'react-google-maps';
import GoogleMap from 'react-google-maps/lib/GoogleMap';
import Marker from 'react-google-maps/lib/Marker';

import styles from './styles.css';

const GoogleMapLoader = withGoogleMap(props => (
  <GoogleMap {...props.mapProps}>
    <Marker {...props.marker} />
  </GoogleMap>
));

export default class LocationField extends React.Component {
  static contextTypes = {
    notify: PropTypes.func
  };
  static propTypes = {
    value: PropTypes.string,
    dataValue: PropTypes.object,
    onChange: PropTypes.func,
    onDataChange: PropTypes.func,
    defaultLocation: PropTypes.object,
    className: PropTypes.string,
  }
  constructor(props) {
    super(props);
    this.state = { clean: true };
  }
  componentDidMount() {
    const { LOCALE_COUNTRY } = window;
    const options = { types: [], componentRestrictions: { country: LOCALE_COUNTRY } };
    const { input } = this.refs;
    const { maps } = window.google;
    const autocomplete = new maps.places.Autocomplete(input, options);
    maps.event.addListener(autocomplete, 'place_changed', () => {
      const place = autocomplete.getPlace();
      this.onPlaceChange(place);
      return place;
    });
  }
  onBlur = event => {
    if (!this.state.clean) {
      event.target.value = '';
    }
  }
  onFocus = event => {
    event.target.select();
  }
  onChange = event => {
    if (!(event.nativeEvent.detail && event.nativeEvent.detail === 'generated')) {
      this.setState({ clean: false });
      event.stopPropagation();
      event.preventDefault();
    }
  }
  onPlaceChange = place => {
    if (!place.geometry) {
      this.context.notify('No map data for this location; please try a different address', 'error');
      return;
    }
    this.latLngChange(place.geometry.location, { placeID: place.place_id });
    this.props.onChange(this.placeToAddress(place));
    this.setState({ clean: true });
  }
  placeToAddress(place) {
    const { name } = place;
    const address = place.formatted_address;
    return address.indexOf(name) === -1 ? [name, address].join(', ') : address;
  }
  latLngChange = (latLng, extraData) => {
    const locationData = {
      lat: latLng.lat(),
      lng: latLng.lng(),
      ...extraData
    };
    this.changeCenter(locationData);
    this.props.onDataChange(locationData);
  }
  changeCenter = locationData => {
    if (this.refs.component) {
      this.refs.component.state.map.panTo(locationData);
    }
  }
  render() {
    const { value, dataValue, className } = this.props;
    const attrs = {
      type: 'text',
      name,
      className,
      ref: 'input',
      onFocus: this.onFocus,
      onBlur: this.onBlur,
      onChange: this.onChange,
      placeholder: value,
      defaultValue: value
    };
    let map = null;
    let mapHelp = null;
    let locationData = dataValue;
    if (locationData) {
      if (typeof locationData === 'string') locationData = JSON.parse(locationData);
      const marker = {
        position: locationData,
        icon: { url: '/images/map-pin-active.svg' },
        defaultAnimation: 2,
        draggable: true,
        cursor: '-webkit-grab, move',
        onDragEnd: drag => {
          this.latLngChange(drag.latLng);
        }
      };
      const mapProps = {
        defaultZoom: 15,
        defaultCenter: locationData,
        center: locationData,
        draggableCursor: '-webkit-grab, move',
        options: { streetViewControl: false, scrollwheel: false, mapTypeControl: false }
      };
      map = (<GoogleMapLoader
        containerElement={
}
        mapElement={
}
        mapProps={mapProps}
        marker={marker}
        ref="component"
      />);
      mapHelp =
Drag map pin to refine location
;
    }
    return (

      <input {...attrs} />
      {map}
      {mapHelp}

);
  }
}
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'

import LoadingBolt from 'components/LoadingBolt'

import FormContainer from './FormContainer'
import ConnectionType from './ConnectionType'
import ConnectionDetails from './ConnectionDetails'
import Alias from './Alias'
import Autopilot from './Autopilot'
import Login from './Login'
import Signup from './Signup'
import RecoverForm from './RecoverForm'
import NewWalletSeed from './NewWalletSeed'
import ReEnterSeed from './ReEnterSeed'
import NewWalletPassword from './NewWalletPassword'
import NewAezeedPassword from './NewAezeedPassword'
import styles from './Onboarding.scss'

const Onboarding = ({
  onboarding: {
    step,
    connectionType,
    connectionHost,
    connectionCert,
    connectionMacaroon,
    alias,
    autopilot,
    startingLnd,
    createWalletPassword,
    seed,
    aezeedPassword,
    fetchingSeed
  },
  connectionTypeProps,
  connectionDetailProps,
  changeStep,
  startLnd,
  submitNewWallet,
  aliasProps,
  initWalletProps,
  autopilotProps,
  recoverFormProps,
  newWalletSeedProps,
  newWalletPasswordProps,
  newAezeedPasswordProps,
  reEnterSeedProps
}) => {
  const renderStep = () => {
    switch (step) {
      case 0.1:
        return (
          <FormContainer
            title="How do you want to connect to the Lightning Network?"
            description="
              By default Zap will spin up a node for you and handle all the nerdy stuff
              in the background. However you can also setup a custom node connection and
              use Zap to control a remote node if you desire (for advanced users).
            "
            back={null}
            next={() => changeStep(connectionType === 'local' ? 1 : 0.2)}
          >
            <ConnectionType {...connectionTypeProps} />
          </FormContainer>
        )

      case 0.2:
        return (
          <FormContainer
            title="Connection details"
            description="Enter the connection details for your Lightning node."
            back={() => changeStep(0.1)}
            next={() =>
              startLnd({
                connectionType,
                connectionHost,
                connectionCert,
                connectionMacaroon
              })
            }
          >
            <ConnectionDetails {...connectionDetailProps} />
          </FormContainer>
        )

      case 1:
        return (
          <FormContainer
            title="What should we call you?"
            description="Set your nickname to help others connect with you on the Lightning Network"
            back={() => changeStep(0.1)}
            next={() => changeStep(2)}
          >
            <Alias {...aliasProps} />
          </FormContainer>
        )
      case 2:
        return (
          <FormContainer
            title="Autopilot"
            description="Autopilot is an automatic network manager. Instead of manually adding people to build your network to make payments, enable autopilot to automatically connect you to the Lightning Network using 60% of your balance." // eslint-disable-line max-len
            back={() => changeStep(1)}
            next={() => startLnd({ connectionType, alias, autopilot })}
          >
            <Autopilot {...autopilotProps} />
          </FormContainer>
        )
      case 3:
        return (
          <FormContainer
            title="Welcome back!"
            description="Enter your wallet password or create a new wallet"
            back={null}
            next={null}
          >
            <Login {...initWalletProps.loginProps} />
          </FormContainer>
        )
      case 4:
        return (
          <FormContainer
            title="Welcome!"
            description="Looks like you are new here. Set a password to encrypt your wallet. This password will be needed to unlock Zap in the future" // eslint-disable-line max-len
            back={null}
            next={() => {
              // dont allow the user to move on if the confirmation password doesnt match the original password
              if (newWalletPasswordProps.showCreateWalletPasswordConfirmationError) {
                return
              }
              // if the password is less than 8 characters dont allow users to proceed
              if (newWalletPasswordProps.passwordMinCharsError) {
                return
              }

              changeStep(5)
            }}
          >
            <NewWalletPassword {...newWalletPasswordProps} />
          </FormContainer>
        )
      case 5:
        return (
          <FormContainer
            title={"Alright, let's get set up"}
            description="Would you like to create a new wallet or import an existing one?"
            back={() => changeStep(4)}
            next={() => changeStep(initWalletProps.signupProps.signupForm.create ? 6 : 5.1)}
          >
            <Signup {...initWalletProps.signupProps} />
          </FormContainer>
        )
      case 5.1:
        return (
          <FormContainer
            title="Import your seed"
            description="Recovering a wallet, nice. You don't need anyone else, you got yourself :)"
            back={() => changeStep(5)}
            next={() => changeStep(5.2)}
          >
            <RecoverForm {...recoverFormProps} />
          </FormContainer>
        )
      case 5.2:
        return (
          <FormContainer
            title="Seed passphrase"
            description="Enter your cipherseed passphrase (or just submit if you don't have one)"
            back={() => changeStep(5)}
            next={() => {
              const recoverySeed = recoverFormProps.recoverSeedInput.map(input => input.word)

              submitNewWallet(createWalletPassword, recoverySeed, aezeedPassword)
            }}
          >
            <NewAezeedPassword {...newAezeedPasswordProps} />
          </FormContainer>
        )
      case 6:
        return (
          <FormContainer
            title="Save your wallet seed"
            description="Please save these 24 words securely! This will allow you to recover your wallet in the future"
            back={() => changeStep(5)}
            next={() => changeStep(7)}
          >
            <NewWalletSeed {...newWalletSeedProps} />
          </FormContainer>
        )
      case 7:
        return (
          <FormContainer
            title="Retype your seed"
            description={`Your seed is important! If you lose your seed you'll have no way to recover your wallet.
            To make sure that you have properly saved your seed, please retype words ${
              reEnterSeedProps.seedIndexesArr[0]
            }, ${reEnterSeedProps.seedIndexesArr[1]} and ${reEnterSeedProps.seedIndexesArr[2]}`}
            back={() => changeStep(6)}
            next={() => {
              // don't allow them to move on if they havent re-entered the seed correctly
              if (!reEnterSeedProps.reEnterSeedChecker) {
                return
              }

              changeStep(8)
            }}
          >
            <ReEnterSeed {...reEnterSeedProps} />
          </FormContainer>
        )
      case 8:
        return (
          <FormContainer
            title="Encrypt your seed"
            description="Totally optional, but we encourage it. Set a password that will be used to encrypt your wallet seed" // eslint-disable-line max-len
            back={() => changeStep(6)}
            next={() => {
              // dont allow the user to move on if the confirmation password doesnt match the original password
              if (newAezeedPasswordProps.showAezeedPasswordConfirmationError) {
                return
              }

              submitNewWallet(createWalletPassword, seed, aezeedPassword)
            }}
          >
            <NewAezeedPassword {...newAezeedPasswordProps} />
          </FormContainer>
        )
      default:
        return <LoadingBolt />
    }
  }

  if (startingLnd) {
    return <LoadingBolt />
  }
  if (fetchingSeed) {
    return <LoadingBolt />
  }

  return
{renderStep()}

}

Onboarding.propTypes = {
  onboarding: PropTypes.object.isRequired,
  connectionTypeProps: PropTypes.object.isRequired,
  connectionDetailProps: PropTypes.object.isRequired,
  aliasProps: PropTypes.object.isRequired,
  autopilotProps: PropTypes.object.isRequired,
  initWalletProps: PropTypes.object.isRequired,
  newWalletSeedProps: PropTypes.object.isRequired,
  newWalletPasswordProps: PropTypes.object.isRequired,
  newAezeedPasswordProps: PropTypes.object.isRequired,
  recoverFormProps: PropTypes.object.isRequired,
  reEnterSeedProps: PropTypes.object.isRequired,
  changeStep: PropTypes.func.isRequired,
  startLnd: PropTypes.func.isRequired,
  submitNewWallet: PropTypes.func.isRequired
}

export default Onboarding
<commit_msg>fix(onboarding-empty-pass): add empty password validation<commit_after>import React from 'react'
import PropTypes from 'prop-types'

import LoadingBolt from 'components/LoadingBolt'

import FormContainer from './FormContainer'
import ConnectionType from './ConnectionType'
import ConnectionDetails from './ConnectionDetails'
import Alias from './Alias'
import Autopilot from './Autopilot'
import Login from './Login'
import Signup from './Signup'
import RecoverForm from './RecoverForm'
import NewWalletSeed from './NewWalletSeed'
import ReEnterSeed from './ReEnterSeed'
import NewWalletPassword from './NewWalletPassword'
import NewAezeedPassword from './NewAezeedPassword'
import styles from './Onboarding.scss'

const Onboarding = ({
  onboarding: {
    step,
    connectionType,
    connectionHost,
    connectionCert,
    connectionMacaroon,
    alias,
    autopilot,
    startingLnd,
    createWalletPassword,
    seed,
    aezeedPassword,
    fetchingSeed
  },
  connectionTypeProps,
  connectionDetailProps,
  changeStep,
  startLnd,
  submitNewWallet,
  aliasProps,
  initWalletProps,
  autopilotProps,
  recoverFormProps,
  newWalletSeedProps,
  newWalletPasswordProps,
  newAezeedPasswordProps,
  reEnterSeedProps
}) => {
  const renderStep = () => {
    switch (step) {
      case 0.1:
        return (
          <FormContainer
            title="How do you want to connect to the Lightning Network?"
            description="
              By default Zap will spin up a node for you and handle all the nerdy stuff
              in the background. However you can also setup a custom node connection and
              use Zap to control a remote node if you desire (for advanced users).
            "
            back={null}
            next={() => changeStep(connectionType === 'local' ? 1 : 0.2)}
          >
            <ConnectionType {...connectionTypeProps} />
          </FormContainer>
        )

      case 0.2:
        return (
          <FormContainer
            title="Connection details"
            description="Enter the connection details for your Lightning node."
            back={() => changeStep(0.1)}
            next={() =>
              startLnd({
                connectionType,
                connectionHost,
                connectionCert,
                connectionMacaroon
              })
            }
          >
            <ConnectionDetails {...connectionDetailProps} />
          </FormContainer>
        )

      case 1:
        return (
          <FormContainer
            title="What should we call you?"
            description="Set your nickname to help others connect with you on the Lightning Network"
            back={() => changeStep(0.1)}
            next={() => changeStep(2)}
          >
            <Alias {...aliasProps} />
          </FormContainer>
        )
      case 2:
        return (
          <FormContainer
            title="Autopilot"
            description="Autopilot is an automatic network manager. Instead of manually adding people to build your network to make payments, enable autopilot to automatically connect you to the Lightning Network using 60% of your balance." // eslint-disable-line max-len
            back={() => changeStep(1)}
            next={() => startLnd({ connectionType, alias, autopilot })}
          >
            <Autopilot {...autopilotProps} />
          </FormContainer>
        )
      case 3:
        return (
          <FormContainer
            title="Welcome back!"
            description="Enter your wallet password or create a new wallet"
            back={null}
            next={null}
          >
            <Login {...initWalletProps.loginProps} />
          </FormContainer>
        )
      case 4:
        return (
          <FormContainer
            title="Welcome!"
            description="Looks like you are new here. Set a password to encrypt your wallet. This password will be needed to unlock Zap in the future" // eslint-disable-line max-len
            back={null}
            next={() => {
              // dont allow the user to move on if the confirmation password doesnt match the original password
              if (newWalletPasswordProps.showCreateWalletPasswordConfirmationError) {
                return
              }
              // if the password is less than 8 characters or empty dont allow users to proceed
              if (
                newWalletPasswordProps.passwordMinCharsError ||
                !newWalletPasswordProps.createWalletPassword
              ) {
                return
              }

              changeStep(5)
            }}
          >
            <NewWalletPassword {...newWalletPasswordProps} />
          </FormContainer>
        )
      case 5:
        return (
          <FormContainer
            title={"Alright, let's get set up"}
            description="Would you like to create a new wallet or import an existing one?"
            back={() => changeStep(4)}
            next={() => changeStep(initWalletProps.signupProps.signupForm.create ? 6 : 5.1)}
          >
            <Signup {...initWalletProps.signupProps} />
          </FormContainer>
        )
      case 5.1:
        return (
          <FormContainer
            title="Import your seed"
            description="Recovering a wallet, nice. You don't need anyone else, you got yourself :)"
            back={() => changeStep(5)}
            next={() => changeStep(5.2)}
          >
            <RecoverForm {...recoverFormProps} />
          </FormContainer>
        )
      case 5.2:
        return (
          <FormContainer
            title="Seed passphrase"
            description="Enter your cipherseed passphrase (or just submit if you don't have one)"
            back={() => changeStep(5)}
            next={() => {
              const recoverySeed = recoverFormProps.recoverSeedInput.map(input => input.word)

              submitNewWallet(createWalletPassword, recoverySeed, aezeedPassword)
            }}
          >
            <NewAezeedPassword {...newAezeedPasswordProps} />
          </FormContainer>
        )
      case 6:
        return (
          <FormContainer
            title="Save your wallet seed"
            description="Please save these 24 words securely! This will allow you to recover your wallet in the future"
            back={() => changeStep(5)}
            next={() => changeStep(7)}
          >
            <NewWalletSeed {...newWalletSeedProps} />
          </FormContainer>
        )
      case 7:
        return (
          <FormContainer
            title="Retype your seed"
            description={`Your seed is important! If you lose your seed you'll have no way to recover your wallet.
            To make sure that you have properly saved your seed, please retype words ${
              reEnterSeedProps.seedIndexesArr[0]
            }, ${reEnterSeedProps.seedIndexesArr[1]} and ${reEnterSeedProps.seedIndexesArr[2]}`}
            back={() => changeStep(6)}
            next={() => {
              // don't allow them to move on if they havent re-entered the seed correctly
              if (!reEnterSeedProps.reEnterSeedChecker) {
                return
              }

              changeStep(8)
            }}
          >
            <ReEnterSeed {...reEnterSeedProps} />
          </FormContainer>
        )
      case 8:
        return (
          <FormContainer
            title="Encrypt your seed"
            description="Totally optional, but we encourage it. Set a password that will be used to encrypt your wallet seed" // eslint-disable-line max-len
            back={() => changeStep(6)}
            next={() => {
              // dont allow the user to move on if the confirmation password doesnt match the original password
              if (newAezeedPasswordProps.showAezeedPasswordConfirmationError) {
                return
              }

              submitNewWallet(createWalletPassword, seed, aezeedPassword)
            }}
          >
            <NewAezeedPassword {...newAezeedPasswordProps} />
          </FormContainer>
        )
      default:
        return <LoadingBolt />
    }
  }

  if (startingLnd) {
    return <LoadingBolt />
  }
  if (fetchingSeed) {
    return <LoadingBolt />
  }

  return
{renderStep()}

}

Onboarding.propTypes = {
  onboarding: PropTypes.object.isRequired,
  connectionTypeProps: PropTypes.object.isRequired,
  connectionDetailProps: PropTypes.object.isRequired,
  aliasProps: PropTypes.object.isRequired,
  autopilotProps: PropTypes.object.isRequired,
  initWalletProps: PropTypes.object.isRequired,
  newWalletSeedProps: PropTypes.object.isRequired,
  newWalletPasswordProps: PropTypes.object.isRequired,
  newAezeedPasswordProps: PropTypes.object.isRequired,
  recoverFormProps: PropTypes.object.isRequired,
  reEnterSeedProps: PropTypes.object.isRequired,
  changeStep: PropTypes.func.isRequired,
  startLnd: PropTypes.func.isRequired,
  submitNewWallet: PropTypes.func.isRequired
}

export default Onboarding
<|endoftext|>


<commit_before>'use strict';

require('./_create-way.scss');

module.exports = {
  template: require('./create-way.html'),
  controller: ['$log', '$mdDialog', '$mdToast','wayService', CreateWayController],
  controllerAs: 'createWayCtrl'
};

function CreateWayController($log, $mdDialog, $mdToast, wayService) {
  $log.debug('CreateWayController');

  this.way = {};
  this.way.recurringDayOfWeek = [];

  this.daysOfWeek = ['M', 'T', 'W', 'R', 'F', 'Sa', 'Su'];
  this.isPM = true;
  const dayMap = { M: 0, T: 1, W: 2, R: 3, F: 4, Sa: 5, Su: 6 };

  this.isLoading = false;

  this.createWaySubmit = function() {
    this.isLoading = true;
    wayService.createWay(this.way)
    .then( () => {
      $mdToast.showSimple('Made a Way was successful');
      this.isLoading = false;
      this.way = {};
      this.way.recurringDayOfWeek = [];
    })
    .catch( err => {
      $mdToast.showSimple(err.data);
      this.isLoading = false;
    });

    $log.log(this.way);
  };

  this.closeDialog = function() {
    $mdDialog.hide();
  };

  this.exists = function (item, list) {
    return list.indexOf(dayMap[item]) > -1;
  };

  this.toggle = function (item, list) {
    var idx = list.indexOf(dayMap[item]);
    if (idx > -1) {
      list.splice(idx, 1);
    }
    else {
      list.push(dayMap[item]);
    }
  };
}
<commit_msg>updated create way time logic<commit_after>'use strict';

require('./_create-way.scss');

module.exports = {
  template: require('./create-way.html'),
  controller: ['$log', '$mdDialog', '$mdToast','wayService', CreateWayController],
  controllerAs: 'createWayCtrl'
};

function CreateWayController($log, $mdDialog, $mdToast, wayService) {
  $log.debug('CreateWayController');

  this.way = {};
  this.way.recurringDayOfWeek = [];

  this.daysOfWeek = ['M', 'T', 'W', 'R', 'F', 'Sa', 'Su'];
  this.isPM = true;
  const dayMap = { M: 0, T: 1, W: 2, R: 3, F: 4, Sa: 5, Su: 6 };

  this.isLoading = false;

  this.createWaySubmit = function() {
    this.isLoading = true;
    this.way.startTime.hour = this.hour12;

    if (this.ampm === 'pm') {
      this.way.startTime.hour += 12;
    }

    wayService.createWay(this.way)
    .then( () => {
      $mdToast.showSimple('Made a Way was successful');
      this.isLoading = false;
      // this.way = {};
      // this.way.recurringDayOfWeek = [];
      $mdDialog.hide();
    })
    .catch( err => {
      $mdToast.showSimple(err.data);
      this.isLoading = false;
    });

    $log.log(this.way);
  };

  this.closeDialog = function() {
    $mdDialog.hide();
  };

  this.exists = function (item, list) {
    return list.indexOf(dayMap[item]) > -1;
  };

  this.toggle = function (item, list) {
    var idx = list.indexOf(dayMap[item]);
    if (idx > -1) {
      list.splice(idx, 1);
    }
    else {
      list.push(dayMap[item]);
    }
  };
}
<|endoftext|>


<commit_before>import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import BaseCollection from '/imports/api/base/BaseCollection';
import { Category } from '/imports/api/category/CategoryCollection';
import { check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';

/** @module Item */

/**
 * Items provide item data for a user.
 * @extends module:Base~BaseCollection
 */
class ItemCollection extends BaseCollection {

  /**
   * Creates the Profile collection.
   */
  constructor() {
    super('Item', new SimpleSchema({
      name: { type: String },
      price: { type: String },
      category: {type: [String] },
      // Remainder are optional
      description: { type: String, optional: true },
      picture: { type: SimpleSchema.RegEx.Url, optional: true },
    }));
  }

  /**
   * Defines a new Item.
   * @example
   * Items.define({ ({ name: 'Discrete Mathematics and it's Application',
   *                   price: '49.50',
   *                   category: ['textbook', 'school supplies'});
   *                   description: 'Textbook used with ICS 141 and 241.'
   *                   picture: www.google.com
   * @param { Object } description Object with required key name, price, and category.
   * Remaining keys are optional.
   * Username must be unique for all users. It should be the UH email account.
   * Interests is an array of defined interest names.
   * @throws { Meteor.Error } If a user with the supplied username already exists, or
   * if one or more interests are not defined, or if github, facebook, and instagram are not URLs.
   * @returns The newly created docID.
   */
  define({ firstName = '', lastName = '', username, bio = '', interests, picture = '', title = '', github = '',
      facebook = '', instagram = '' }) {
    // make sure required fields are OK.
    const checkPattern = { firstName: String, lastName: String, username: String, bio: String, picture: String,
      title: String };
    check({ firstName, lastName, username, bio, picture, title }, checkPattern);

    if (this.find({ username }).count() > 0) {
      throw new Meteor.Error(`${username} is previously defined in another Profile`);
    }

    // Throw an error if any of the passed Interest names are not defined.
    Interests.assertNames(interests);
    return this._collection.insert({ firstName, lastName, username, bio, interests, picture, title, github,
      facebook, instagram });
  }

  /**
   * Returns an object representing the Profile docID in a format acceptable to define().
   * @param docID The docID of a Profile.
   * @returns { Object } An object representing the definition of docID.
   */
  dumpOne(docID) {
    const doc = this.findDoc(docID);
    const name = doc.name;
    const price = doc.price;
    const category = doc.category;
    const description = doc.description;
    const picture = doc.picture;
    return { name, price, category, description, picture };
  }
}
<commit_msg>fixed ItemCollection.js<commit_after>import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import BaseCollection from '/imports/api/base/BaseCollection';
import { Category } from '/imports/api/category/CategoryCollection';
import { check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';

/** @module Item */

/**
 * Items provide item data for a user.
 * @extends module:Base~BaseCollection
 */
class ItemCollection extends BaseCollection {

  /**
   * Creates the Profile collection.
   */
  constructor() {
    super('Item', new SimpleSchema({
      name: { type: String },
      price: { type: String },
      seller: { type: String },
      category: {type: [String] },
      // Remainder are optional
      description: { type: String, optional: true },
      picture: { type: SimpleSchema.RegEx.Url, optional: true },
    }));
  }

  /**
   * Defines a new Item.
   * @example
   * Items.define({ ({ name: 'Discrete Mathematics and it's Application',
   *                   price: '49.50',
   *                   category: ['textbook', 'school supplies'});
   *                   description: 'Textbook used with ICS 141 and 241.'
   *                   picture: www.google.com
   * @param { Object } description Object with required key name, price, and category.
   * Remaining keys are optional.
   * Username must be unique for all users. It should be the UH email account.
   * Categories is an array of defined category names.
   * @throws { Meteor.Error } if one or more interests are not defined
   * @returns The newly created docID.
   */
  define({ name = '', price = '', seller, category, description = '', picture = '' }) {
    // make sure required fields are OK.
    const checkPattern = { name: String, price: String, seller: String, description: String, picture: String };
    check({ name, price, seller, description, picture }, checkPattern);

    // Throw an error if any of the passed Category names are not defined.
    Category.assertNames(category);
    return this._collection.insert({ name, price, seller, category, picture });
  }

  /**
   * Returns an object representing the Profile docID in a format acceptable to define().
   * @param docID The docID of a Profile.
   * @returns { Object } An object representing the definition of docID.
   */
  dumpOne(docID) {
    const doc = this.findDoc(docID);
    const name = doc.name;
    const price = doc.price;
    const category = doc.category;
    const description = doc.description;
    const picture = doc.picture;
    return { name, price, category, description, picture };
  }
}
<|endoftext|>


<commit_before>'use strict';

var Crypto = require('crypto');
var semver = require('semver');

var Datasource = require('./datasource');

// Map configuration object

/// API: Create MapConfig from configuration object
//
/// @param obj js MapConfiguration object, see
///        http://github.com/CartoDB/Windshaft/wiki/MapConfig-specification
///
function MapConfig (config, datasource) {
    // TODO: inject defaults ?
    this._cfg = config;

    if (!semver.satisfies(this.version(), '>= 1.0.0 <= 1.8.0')) {
        throw new Error('Unsupported layergroup configuration version ' + this.version());
    }

    if (!Object.prototype.hasOwnProperty.call(this._cfg, 'layers')) {
        throw new Error('Missing layers array from layergroup config');
    }

    this._cfg.layers.forEach(function (layer, i) {
        if (!Object.prototype.hasOwnProperty.call(layer, 'options')) {
            throw new Error('Missing options from layer ' + i + ' of layergroup config');
        }
        // NOTE: interactivity used to be a string as of version 1.0.0
        if (Array.isArray(layer.options.interactivity)) {
            layer.options.interactivity = layer.options.interactivity.join(',');
        }
    });

    if (this._cfg.buffersize) {
        Object.keys(this._cfg.buffersize).forEach(format => {
            if (this._cfg.buffersize[format] !== undefined && !Number.isFinite(this._cfg.buffersize[format])) {
                throw new Error(`Buffer size of format "${format}" must be a number`);
            }
        });
    }

    /**
    * @type {Datasource}
    */
    this._datasource = datasource;

    this._id = null;
}

function md5Hash (s) {
    return Crypto.createHash('md5').update(s, 'binary').digest('hex');
}

/// API: Get serialized version of this MapConfig
MapConfig.prototype.serialize = function () {
    if (this._datasource.isEmpty()) {
        return JSON.stringify(this._cfg);
    }
    return JSON.stringify({
        cfg: this._cfg,
        ds: this._datasource.obj()
    });
};

/// API: Get identifier for this MapConfig
MapConfig.prototype.id = function () {
    if (this._id === null) {
        this._id = md5Hash(JSON.stringify(this._cfg));
    }
    // debug('MapConfig.id=%s', this._id);
    return this._id;
};

/// API: Get configuration object of this MapConfig
MapConfig.prototype.obj = function () {
    return this._cfg;
};

MapConfig.prototype.version = function () {
    return this._cfg.version || '1.0.0';
};

MapConfig.prototype.setDbParams = function (dbParams) {
    this._cfg.dbparams = dbParams;
    this.flush();
};

MapConfig.prototype.flush = function () {
    // flush id so it gets recalculated
    this._id = null;
};

/// API: Get type string of given layer
//
/// @param num layer index (0-based)
/// @returns a type string, as read from the layer
///
MapConfig.prototype.layerType = function (num) {
    var lyr = this.getLayer(num);
    if (!lyr) {
        return undefined;
    }
    return this.getType(lyr.type);
};

MapConfig.prototype.getType = function (type) {
    return getType(type);
};

function getType (type) {
    // TODO: check validity of other types ?
    return (!type || type === 'cartodb') ? 'mapnik' : type;
}

MapConfig.prototype.setBufferSize = function (bufferSize) {
    this._cfg.buffersize = bufferSize;
    this.flush();
    return this;
};

MapConfig.prototype.getBufferSize = function (format) {
    if (this._cfg.buffersize && isValidBufferSize(this._cfg.buffersize[format])) {
        return parseInt(this._cfg.buffersize[format], 10);
    }

    return undefined;
};

function isValidBufferSize (value) {
    return Number.isFinite(parseInt(value, 10));
}

MapConfig.prototype.hasIncompatibleLayers = function () {
    return !this.isVectorOnlyMapConfig() && this.hasVectorLayer();
};

MapConfig.prototype.isVectorOnlyMapConfig = function () {
    const layers = this.getLayers();
    let isVectorOnlyMapConfig = false;

    if (!layers.length) {
        return isVectorOnlyMapConfig;
    }

    isVectorOnlyMapConfig = true;

    for (let index = 0; index < layers.length; index++) {
        if (!this.isVectorLayer(index)) {
            isVectorOnlyMapConfig = false;
            break;
        }
    }

    return isVectorOnlyMapConfig;
};

MapConfig.prototype.hasVectorLayer = function () {
    const layers = this.getLayers();
    let hasVectorLayer = false;

    for (let index = 0; index < layers.length; index++) {
        if (this.isVectorLayer(index)) {
            hasVectorLayer = true;
            break;
        }
    }

    return hasVectorLayer;
};

MapConfig.prototype.isVectorLayer = function (index) {
    const layer = this.getLayer(index);
    const type = getType(layer.type);
    const sql = this.getLayerOption(index, 'sql');
    const cartocss = this.getLayerOption(index, 'cartocss');
    const cartocssVersion = this.getLayerOption(index, 'cartocss_version');

    return type === 'mapnik' && typeof sql === 'string' && cartocss === undefined && cartocssVersion === undefined;
};

/*****************************************************************************
 * Layers
 ****************************************************************************/

MapConfig.prototype.getLayerId = function (layerIndex) {
    return getLayerId(this._cfg, layerIndex);
};

function getLayerId (rawMapConfig, layerIndex) {
    var layer = rawMapConfig.layers[layerIndex];
    if (layer.id) {
        return layer.id;
    }

    var layerType = getType(layer.type);
    var layerId = 'layer' + getLayerIndexByType(rawMapConfig, layerType, layerIndex);
    if (layerType !== 'mapnik') {
        layerId = layerType + '-' + layerId;
    }
    return layerId;
}

MapConfig.prototype.getIndexByLayerId = function (layerId) {
    var layers = this.getLayers();

    for (var i = 0; i < layers.length; i++) {
        if (layers[i].id === layerId) {
            return i;
        }
    }

    return -1;
};

/// API: Get layer by index
//
/// @returns undefined on invalid index
///
MapConfig.prototype.getLayer = function (layerIndex) {
    return this._cfg.layers[layerIndex];
};

MapConfig.prototype.getLayers = function () {
    return this._cfg.layers.map(function (_layer, layerIndex) {
        return this.getLayer(layerIndex);
    }.bind(this));
};

MapConfig.prototype.getLayerIndexByType = function (type, mapConfigLayerIdx) {
    return getLayerIndexByType(this._cfg, type, mapConfigLayerIdx);
};

function getLayerIndexByType (rawMapConfig, type, mapConfigLayerIdx) {
    var typeLayerIndex = 0;
    var mapConfigToTypeLayers = {};

    rawMapConfig.layers.forEach(function (layer, layerIdx) {
        if (getType(layer.type) === type) {
            mapConfigToTypeLayers[layerIdx] = typeLayerIndex++;
        }
    });

    return mapConfigToTypeLayers[mapConfigLayerIdx];
}

MapConfig.prototype.getLayerOption = function (layerIndex, optionName, defaultValue) {
    var layerOption = defaultValue;
    var layer = this.getLayer(layerIndex);
    if (layer && Object.prototype.hasOwnProperty.call(layer.options, optionName)) {
        layerOption = layer.options[optionName];
    }
    return layerOption;
};

/*****************************************************************************
 * Datasource
 ****************************************************************************/

MapConfig.prototype.getLayerDatasource = function (layerIndex) {
    var datasource = this._datasource.getLayerDatasource(layerIndex) || {};

    var layerSrid = this.getLayerOption(layerIndex, 'srid');
    if (layerSrid) {
        datasource.srid = layerSrid;
    }

    return datasource;
};

/**
 * À la Factory method
 *
 * @param {Object} rawConfig
 * @param {Datasource} [datasource=Datasource.EmptyDatasource()]
 * @returns {MapConfig}
 */
function create (rawConfig, datasource) {
    if (rawConfig.ds) {
        return new MapConfig(rawConfig.cfg, new Datasource(rawConfig.ds));
    }
    datasource = datasource || Datasource.EmptyDatasource();
    return new MapConfig(rawConfig, datasource);
}

/*****************************************************************************
 * MVT
 ****************************************************************************/

const DEFAULT_EXTENT = 4096;
const DEFAULT_SIMPLIFY_EXTENT = 256;
// Accepted values between 1 and 2^31 -1 (DEFAULT_MAX_EXTENT)
const DEFAULT_MAX_EXTENT = 2147483647;
const DEFAULT_MIN_EXTENT = 1;

function checkRange (number, min, max) {
    return (!isNaN(number) && number >= min && number <= max);
}

// Checks all layers for a valid `vector_simplify_extent`
// Makes sure all layers have the same value (or using DEFAULT_EXTENT)
// Returns undefined if none of the layers have it declared
function getSimplifyExtent (layers, vectorExtent) {
    let undef = 0;
    const extents = [...new Set(layers.map(layer => {
        if (layer.options.vector_simplify_extent === undefined) {
            undef++;
            return layer.options.vector_extent || DEFAULT_SIMPLIFY_EXTENT;
        }
        return layer.options.vector_simplify_extent;
    }))];

    if (extents.length > 1) {
        throw new Error('Multiple simplify extent values in mapConfig (' + extents + ')');
    }

    if (undef === layers.length) {
        return vectorExtent;
    }

    const maxExtent = vectorExtent || DEFAULT_EXTENT;

    // Accepted values between 1 and max_extent
    const simplifyExtent = parseInt(extents[0]);
    if (!checkRange(simplifyExtent, DEFAULT_MIN_EXTENT, maxExtent)) {
        throw new Error('Invalid vector_simplify_extent (' + simplifyExtent + '). ' +
                        'Must be between 1 and vector_extent [' + maxExtent + ']');
    }

    return simplifyExtent;
}

// Checks all layers for a valid `vectorExtent`
// Makes sure all layers have the same value (or using DEFAULT_EXTENT)
// Returns undefined if none of the layers have it declared
function getTileExtent (layers) {
    let undef = 0;
    const layerExtents = [...new Set(layers.map(layer => {
        if (layer.options.vector_extent === undefined) {
            undef++;
            return DEFAULT_EXTENT;
        }
        return layer.options.vector_extent;
    }))];

    if (layerExtents.length > 1) {
        throw new Error('Multiple extent values in mapConfig (' + layerExtents + ')');
    }

    if (undef === layers.length) {
        return undefined;
    }

    const extent = parseInt(layerExtents[0]);
    if (!checkRange(extent, DEFAULT_MIN_EXTENT, DEFAULT_MAX_EXTENT)) {
        throw new Error('Invalid vector_extent. Must be between 1 and ' + DEFAULT_MAX_EXTENT);
    }

    return extent;
}

// Returns an object with the extents needed for MVTs. Throws on error
MapConfig.prototype.getMVTExtents = function () {
    const layers = this.getLayers();
    const extent = getTileExtent(layers);
    const simplifyExtent = getSimplifyExtent(layers, extent);

    return { extent: extent || DEFAULT_EXTENT, simplify_extent: simplifyExtent || DEFAULT_SIMPLIFY_EXTENT };
};

module.exports = MapConfig;
// Factory like method to create MapConfig objects when you are unsure about being
// able to provide all the MapConfig collaborators or you have to create a MapConfig
// object from a serialized version
module.exports.create = create;

module.exports.getLayerId = getLayerId;
<commit_msg>Use ES6 class syntax<commit_after>'use strict';

const crypto = require('crypto');
const semver = require('semver');
const Datasource = require('./datasource');

// see: http://github.com/CartoDB/Windshaft/wiki/MapConfig-specification
module.exports = class MapConfig {
    // Factory like method to create MapConfig objects when you are unsure about being
    // able to provide all the MapConfig collaborators or you have to create a MapConfig
    // object from a serialized version
    static create (rawConfig, datasource) {
        if (rawConfig.ds) {
            return new MapConfig(rawConfig.cfg, new Datasource(rawConfig.ds));
        }
        datasource = datasource || Datasource.EmptyDatasource();
        return new MapConfig(rawConfig, datasource);
    }

    static getLayerId (rawMapConfig, layerIndex) {
        var layer = rawMapConfig.layers[layerIndex];
        if (layer.id) {
            return layer.id;
        }

        var layerType = getType(layer.type);
        var layerId = 'layer' + getLayerIndexByType(rawMapConfig, layerType, layerIndex);
        if (layerType !== 'mapnik') {
            layerId = layerType + '-' + layerId;
        }
        return layerId;
    }

    constructor (config, datasource) {
        // TODO: inject defaults ?
        this._cfg = config;

        if (!semver.satisfies(this.version(), '>= 1.0.0 <= 1.8.0')) {
            throw new Error('Unsupported layergroup configuration version ' + this.version());
        }

        if (!Object.prototype.hasOwnProperty.call(this._cfg, 'layers')) {
            throw new Error('Missing layers array from layergroup config');
        }

        this._cfg.layers.forEach(function (layer, i) {
            if (!Object.prototype.hasOwnProperty.call(layer, 'options')) {
                throw new Error('Missing options from layer ' + i + ' of layergroup config');
            }
            // NOTE: interactivity used to be a string as of version 1.0.0
            if (Array.isArray(layer.options.interactivity)) {
                layer.options.interactivity = layer.options.interactivity.join(',');
            }
        });

        if (this._cfg.buffersize) {
            Object.keys(this._cfg.buffersize).forEach(format => {
                if (this._cfg.buffersize[format] !== undefined && !Number.isFinite(this._cfg.buffersize[format])) {
                    throw new Error(`Buffer size of format "${format}" must be a number`);
                }
            });
        }

        /**
        * @type {Datasource}
        */
        this._datasource = datasource;

        this._id = null;
    }

    serialize () {
        if (this._datasource.isEmpty()) {
            return JSON.stringify(this._cfg);
        }
        return JSON.stringify({
            cfg: this._cfg,
            ds: this._datasource.obj()
        });
    }

    id () {
        if (this._id === null) {
            this._id = md5Hash(JSON.stringify(this._cfg));
        }

        return this._id;
    }

    obj () {
        return this._cfg;
    }

    version () {
        return this._cfg.version || '1.0.0';
    }

    setDbParams (dbParams) {
        this._cfg.dbparams = dbParams;
        this.flush();
    }

    // flush id so it gets recalculated
    flush () {
        this._id = null;
    }

    layerType (layerIndex) {
        var lyr = this.getLayer(layerIndex);
        if (!lyr) {
            return undefined;
        }
        return this.getType(lyr.type);
    }

    getType (type) {
        return getType(type);
    }

    setBufferSize (bufferSize) {
        this._cfg.buffersize = bufferSize;
        this.flush();

        return this;
    }

    getBufferSize (format) {
        if (this._cfg.buffersize && isValidBufferSize(this._cfg.buffersize[format])) {
            return parseInt(this._cfg.buffersize[format], 10);
        }

        return undefined;
    }

    hasIncompatibleLayers () {
        return !this.isVectorOnlyMapConfig() && this.hasVectorLayer();
    }

    isVectorOnlyMapConfig () {
        const layers = this.getLayers();
        let isVectorOnlyMapConfig = false;

        if (!layers.length) {
            return isVectorOnlyMapConfig;
        }

        isVectorOnlyMapConfig = true;

        for (let index = 0; index < layers.length; index++) {
            if (!this.isVectorLayer(index)) {
                isVectorOnlyMapConfig = false;
                break;
            }
        }

        return isVectorOnlyMapConfig;
    }

    hasVectorLayer () {
        const layers = this.getLayers();
        let hasVectorLayer = false;

        for (let index = 0; index < layers.length; index++) {
            if (this.isVectorLayer(index)) {
                hasVectorLayer = true;
                break;
            }
        }

        return hasVectorLayer;
    }

    isVectorLayer (index) {
        const layer = this.getLayer(index);
        const type = getType(layer.type);
        const sql = this.getLayerOption(index, 'sql');
        const cartocss = this.getLayerOption(index, 'cartocss');
        const cartocssVersion = this.getLayerOption(index, 'cartocss_version');

        return type === 'mapnik' && typeof sql === 'string' && cartocss === undefined && cartocssVersion === undefined;
    }

    /*****************************************************************************
     * Layers
     ****************************************************************************/

    getLayerId (layerIndex) {
        return MapConfig.getLayerId(this._cfg, layerIndex);
    }

    getIndexByLayerId (layerId) {
        var layers = this.getLayers();

        for (var i = 0; i < layers.length; i++) {
            if (layers[i].id === layerId) {
                return i;
            }
        }

        return -1;
    }

    getLayer (layerIndex) {
        return this._cfg.layers[layerIndex];
    }

    getLayers () {
        return this._cfg.layers.map(function (_layer, layerIndex) {
            return this.getLayer(layerIndex);
        }.bind(this));
    }

    getLayerIndexByType (type, mapConfigLayerIdx) {
        return getLayerIndexByType(this._cfg, type, mapConfigLayerIdx);
    }

    getLayerOption (layerIndex, optionName, defaultValue) {
        var layerOption = defaultValue;
        var layer = this.getLayer(layerIndex);
        if (layer && Object.prototype.hasOwnProperty.call(layer.options, optionName)) {
            layerOption = layer.options[optionName];
        }
        return layerOption;
    }

    /*****************************************************************************
     * Datasource
     ****************************************************************************/

    getLayerDatasource (layerIndex) {
        var datasource = this._datasource.getLayerDatasource(layerIndex) || {};

        var layerSrid = this.getLayerOption(layerIndex, 'srid');
        if (layerSrid) {
            datasource.srid = layerSrid;
        }

        return datasource;
    }

    /*****************************************************************************
     * MVT
     ****************************************************************************/

    getMVTExtents () {
        const layers = this.getLayers();
        const extent = getTileExtent(layers);
        const simplifyExtent = getSimplifyExtent(layers, extent);

        return { extent: extent || DEFAULT_EXTENT, simplify_extent: simplifyExtent || DEFAULT_SIMPLIFY_EXTENT };
    }
};

function md5Hash (s) {
    return crypto.createHash('md5').update(s, 'binary').digest('hex');
}

function getType (type) {
    // TODO: check validity of other types ?
    return (!type || type === 'cartodb') ? 'mapnik' : type;
}

function isValidBufferSize (value) {
    return Number.isFinite(parseInt(value, 10));
}

/*****************************************************************************
 * Layers
 ****************************************************************************/

function getLayerIndexByType (rawMapConfig, type, mapConfigLayerIdx) {
    var typeLayerIndex = 0;
    var mapConfigToTypeLayers = {};

    rawMapConfig.layers.forEach(function (layer, layerIdx) {
        if (getType(layer.type) === type) {
            mapConfigToTypeLayers[layerIdx] = typeLayerIndex++;
        }
    });

    return mapConfigToTypeLayers[mapConfigLayerIdx];
}

/*****************************************************************************
 * MVT
 ****************************************************************************/

const DEFAULT_EXTENT = 4096;
const DEFAULT_SIMPLIFY_EXTENT = 256;
// Accepted values between 1 and 2^31 -1 (DEFAULT_MAX_EXTENT)
const DEFAULT_MAX_EXTENT = 2147483647;
const DEFAULT_MIN_EXTENT = 1;

function checkRange (number, min, max) {
    return (!isNaN(number) && number >= min && number <= max);
}

// Checks all layers for a valid `vector_simplify_extent`
// Makes sure all layers have the same value (or using DEFAULT_EXTENT)
// Returns undefined if none of the layers have it declared
function getSimplifyExtent (layers, vectorExtent) {
    let undef = 0;
    const extents = [...new Set(layers.map(layer => {
        if (layer.options.vector_simplify_extent === undefined) {
            undef++;
            return layer.options.vector_extent || DEFAULT_SIMPLIFY_EXTENT;
        }
        return layer.options.vector_simplify_extent;
    }))];

    if (extents.length > 1) {
        throw new Error('Multiple simplify extent values in mapConfig (' + extents + ')');
    }

    if (undef === layers.length) {
        return vectorExtent;
    }

    const maxExtent = vectorExtent || DEFAULT_EXTENT;

    // Accepted values between 1 and max_extent
    const simplifyExtent = parseInt(extents[0]);
    if (!checkRange(simplifyExtent, DEFAULT_MIN_EXTENT, maxExtent)) {
        throw new Error('Invalid vector_simplify_extent (' + simplifyExtent + '). ' +
                        'Must be between 1 and vector_extent [' + maxExtent + ']');
    }

    return simplifyExtent;
}

// Checks all layers for a valid `vectorExtent`
// Makes sure all layers have the same value (or using DEFAULT_EXTENT)
// Returns undefined if none of the layers have it declared
function getTileExtent (layers) {
    let undef = 0;
    const layerExtents = [...new Set(layers.map(layer => {
        if (layer.options.vector_extent === undefined) {
            undef++;
            return DEFAULT_EXTENT;
        }
        return layer.options.vector_extent;
    }))];

    if (layerExtents.length > 1) {
        throw new Error('Multiple extent values in mapConfig (' + layerExtents + ')');
    }

    if (undef === layers.length) {
        return undefined;
    }

    const extent = parseInt(layerExtents[0]);
    if (!checkRange(extent, DEFAULT_MIN_EXTENT, DEFAULT_MAX_EXTENT)) {
        throw new Error('Invalid vector_extent. Must be between 1 and ' + DEFAULT_MAX_EXTENT);
    }

    return extent;
}
<|endoftext|>


<commit_before>/*
 * Copyrights Loic J. Duros 2012
 * lduros@member.fsf.org
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const { Cc, Ci } = require("chrome");
const { getMostRecentBrowserWindow } = require('api-utils/window/utils');
const { Symbiont } = require('sdk/content/content');

/* I haven't found this sort of validation functions in the SDK,
except for the deprecated api-utils module. */
let isString = function (str) {
  return typeof(str) == 'string' || str instanceof String;
};

let isArray = function (obj) {
  return Object.prototype.toString.call(obj) === '[object Array]';
};

exports.NotificationBox = function (options) {
  options = options || {};
  let mainWindow = getWindow();
  let nb = mainWindow.gBrowser.getNotificationBox();
  let notification, priority, label, image, value, buttons = [];

  if (options.value && isString(options.value)) {
    notification = nb.getNotificationWithValue(options.value);
    value = options.value;
  }
  else {
    notification = nb.getNotificationWithValue('');
    value = '';
  }

  // Add label or create empty notification.
  if (options.label && isString(options.label))
    label = options.label;
  else
    label = "";

  // Set priority of the notification (from info low, to critical
  // block.
  if (options.priority && options.priority in PRIORITY)
    priority = nb[PRIORITY[options.priority]];
  else
    priority = nb[PRIORITY.INFO_LOW];

  // Set a custom icon for the notification or use the regular info
  // icon.
  if (options.image && isString(options.image))
    image = options.image;
  else
    image = 'chrome://browser/skin/Info.png';

  // Add buttons.
  if (isArray(options.buttons)) {
    for (let i = 0, length = options.buttons.length; i < length; i++) {
      buttons.push(NotificationButton(options.buttons[i]));
    }
  }
  else if (typeof(options.buttons) === 'object') {
    // If it's not an array of buttons, then it should be a single button.
    buttons.push(NotificationButton(options.buttons));
  }
  else {
    buttons = null;
  }

  // add new notification to notificationbox.
  nb.appendNotification(label, value,
                        image,
                        priority, buttons);
  return notification;
};

var NotificationButton = function (options) {

  options = options || {};
  let accessKey, onClick, label, popup;

  if (options.accessKey)
    accessKey = options.accessKey;
  else
    accessKey = '';

  if (options.onClick)
    onClick = options.onClick;
  else
    onClick = function () {};

  if (options.label)
    label = options.label;
  else
    label = "";

  // no popup for now... maybe we can use a panel later.
  popup = null;

  return {label: label,
          accessKey: accessKey,
          callback: onClick,
          popup: popup};

};

const PRIORITY = {
    'INFO_LOW': 'PRIORITY_INFO_LOW',
    'INFO_MEDIUM': 'PRIORITY_INFO_MEDIUM',
    'INFO_HIGH': 'PRIORITY_INFO_HIGH',
    'WARNING_LOW': 'PRIORITY_WARNING_LOW',
    'WARNING_MEDIUM': 'PRIORITY_WARNING_MEDIUM',
    'WARNING_HIGH': 'PRIORITY_WARNING_HIGH',
    'CRITICAL_LOW': 'PRIORITY_CRITICAL_LOW',
    'CRITICAL_MEDIUM': 'PRIORITY_CRITICAL_MEDIUM',
    'CRITICAL_HIGH': 'PRIORITY_CRITICAL_HIGH',
    'CRITICAL_BLOCK': 'PRIORITY_CRITICAL_BLOCK'
};

let getWindow = function () {
  return getMostRecentBrowserWindow();
};

exports.PRIORITY = PRIORITY;

<commit_msg>not using symbiont anymore (until/if it is really needed)<commit_after>/*
 * Copyrights Loic J. Duros 2012
 * lduros@member.fsf.org
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const { Cc, Ci } = require("chrome");
const { getMostRecentBrowserWindow } = require('api-utils/window/utils');

/* I haven't found this sort of validation functions in the SDK,
except for the deprecated api-utils module. */
let isString = function (str) {
  return typeof(str) == 'string' || str instanceof String;
};

let isArray = function (obj) {
  return Object.prototype.toString.call(obj) === '[object Array]';
};

exports.NotificationBox = function (options) {
  options = options || {};
  let mainWindow = getWindow();
  let nb = mainWindow.gBrowser.getNotificationBox();
  let notification, priority, label, image, value, buttons = [];

  if (options.value && isString(options.value)) {
    notification = nb.getNotificationWithValue(options.value);
    value = options.value;
  }
  else {
    notification = nb.getNotificationWithValue('');
    value = '';
  }

  // Add label or create empty notification.
  if (options.label && isString(options.label))
    label = options.label;
  else
    label = "";

  // Set priority of the notification (from info low, to critical
  // block.
  if (options.priority && options.priority in PRIORITY)
    priority = nb[PRIORITY[options.priority]];
  else
    priority = nb[PRIORITY.INFO_LOW];

  // Set a custom icon for the notification or use the regular info
  // icon.
  if (options.image && isString(options.image))
    image = options.image;
  else
    image = 'chrome://browser/skin/Info.png';

  // Add buttons.
  if (isArray(options.buttons)) {
    for (let i = 0, length = options.buttons.length; i < length; i++) {
      buttons.push(NotificationButton(options.buttons[i]));
    }
  }
  else if (typeof(options.buttons) === 'object') {
    // If it's not an array of buttons, then it should be a single button.
    buttons.push(NotificationButton(options.buttons));
  }
  else {
    buttons = null;
  }

  // add new notification to notificationbox.
  nb.appendNotification(label, value,
                        image,
                        priority, buttons);
  return notification;
};

var NotificationButton = function (options) {

  options = options || {};
  let accessKey, onClick, label, popup;

  if (options.accessKey)
    accessKey = options.accessKey;
  else
    accessKey = '';

  if (options.onClick)
    onClick = options.onClick;
  else
    onClick = function () {};

  if (options.label)
    label = options.label;
  else
    label = "";

  // no popup for now... maybe we can use a panel later.
  popup = null;

  return {label: label,
          accessKey: accessKey,
          callback: onClick,
          popup: popup};

};

const PRIORITY = {
    'INFO_LOW': 'PRIORITY_INFO_LOW',
    'INFO_MEDIUM': 'PRIORITY_INFO_MEDIUM',
    'INFO_HIGH': 'PRIORITY_INFO_HIGH',
    'WARNING_LOW': 'PRIORITY_WARNING_LOW',
    'WARNING_MEDIUM': 'PRIORITY_WARNING_MEDIUM',
    'WARNING_HIGH': 'PRIORITY_WARNING_HIGH',
    'CRITICAL_LOW': 'PRIORITY_CRITICAL_LOW',
    'CRITICAL_MEDIUM': 'PRIORITY_CRITICAL_MEDIUM',
    'CRITICAL_HIGH': 'PRIORITY_CRITICAL_HIGH',
    'CRITICAL_BLOCK': 'PRIORITY_CRITICAL_BLOCK'
};

let getWindow = function () {
  return getMostRecentBrowserWindow();
};

exports.PRIORITY = PRIORITY;

<|endoftext|>


<commit_before>// lib/objectmiddleware.js
//
// Useful middleware for working with routes like :type/:uuid
//
// Copyright 2011-2012, StatusNet Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

var _ = require("underscore"),
    Step = require("step"),
    HTTPError = require("../lib/httperror").HTTPError,
    ActivityObject = require("../lib/model/activityobject").ActivityObject,
    Activity = require("../lib/model/activity").Activity;

var requestObject = function(req, res, next) {

    var type = req.params.type,
        uuid = req.params.uuid,
        Cls,
        obj = null;

    if (_.contains(ActivityObject.objectTypes, type) || type == "other") {
        req.type = type;
    } else {
        next(new HTTPError("Unknown type: " + type, 404));
        return;
    }

    Cls = ActivityObject.toClass(type);

    Cls.search({"_uuid": uuid}, function(err, results) {
        if (err) {
            next(err);
        } else if (results.length === 0) {
            next(new HTTPError("Can't find a " + type + " with ID = " + uuid, 404));
        } else if (results.length > 1) {
            next(new HTTPError("Too many " + type + " objects with ID = " + req.params.uuid, 500));
        } else {
            obj = results[0];
            if (obj.hasOwnProperty("deleted")) {
                next(new HTTPError("Deleted", 410));
            } else {
                obj.expand(function(err) {
                    if (err) {
                        next(err);
                    } else {
                        req[type] = obj;
                        next();
                    }
                });
            }
        }
    });
};

var authorOnly = function(req, res, next) {

    var type = req.type,
        obj = req[type];

    if (obj && obj.author && obj.author.id == req.remoteUser.profile.id) {
        next();
    } else {
        next(new HTTPError("Only the author can modify this object.", 403));
    }
};

var authorOrRecipient = function(req, res, next) {

    var type = req.type,
        obj = req[type],
        user = req.remoteUser,
        person = (user) ? user.profile : null;

    if (obj && obj.author && person && obj.author.id == person.id) {
        next();
    } else {
        Step(
            function() {
                Activity.postOf(obj, this);
            },
            function(err, act) {
                if (err) throw err;
                if (!act) {
                    next(new HTTPError("Only the author and recipients can view this object.", 403));
                } else {
                    act.checkRecipient(person, this);
                }
            },
            function(err, isRecipient) {
                if (err) {
                    next(err);
                } else if (isRecipient) {
                    next();
                } else {
                    next(new HTTPError("Only the author and recipients can view this object.", 403));
                }
            }
        );
    }
};

exports.requestObject     = requestObject;
exports.authorOnly        = authorOnly;
exports.authorOrRecipient = authorOrRecipient;
<commit_msg>Better description of why you can't see this<commit_after>// lib/objectmiddleware.js
//
// Useful middleware for working with routes like :type/:uuid
//
// Copyright 2011-2012, StatusNet Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

var _ = require("underscore"),
    Step = require("step"),
    HTTPError = require("../lib/httperror").HTTPError,
    ActivityObject = require("../lib/model/activityobject").ActivityObject,
    Activity = require("../lib/model/activity").Activity;

var requestObject = function(req, res, next) {

    var type = req.params.type,
        uuid = req.params.uuid,
        Cls,
        obj = null;

    if (_.contains(ActivityObject.objectTypes, type) || type == "other") {
        req.type = type;
    } else {
        next(new HTTPError("Unknown type: " + type, 404));
        return;
    }

    Cls = ActivityObject.toClass(type);

    Cls.search({"_uuid": uuid}, function(err, results) {
        if (err) {
            next(err);
        } else if (results.length === 0) {
            next(new HTTPError("Can't find a " + type + " with ID = " + uuid, 404));
        } else if (results.length > 1) {
            next(new HTTPError("Too many " + type + " objects with ID = " + req.params.uuid, 500));
        } else {
            obj = results[0];
            if (obj.hasOwnProperty("deleted")) {
                next(new HTTPError("Deleted", 410));
            } else {
                obj.expand(function(err) {
                    if (err) {
                        next(err);
                    } else {
                        req[type] = obj;
                        next();
                    }
                });
            }
        }
    });
};

var authorOnly = function(req, res, next) {

    var type = req.type,
        obj = req[type];

    if (obj && obj.author && obj.author.id == req.remoteUser.profile.id) {
        next();
    } else {
        next(new HTTPError("Only the author can modify this object.", 403));
    }
};

var authorOrRecipient = function(req, res, next) {

    var type = req.type,
        obj = req[type],
        user = req.remoteUser,
        person = (user) ? user.profile : null;

    if (obj && obj.author && person && obj.author.id == person.id) {
        next();
    } else {
        Step(
            function() {
                Activity.postOf(obj, this);
            },
            function(err, act) {
                if (err) throw err;
                if (!act) {
                    next(new HTTPError("No authorization for this object.", 403));
                } else {
                    act.checkRecipient(person, this);
                }
            },
            function(err, isRecipient) {
                if (err) {
                    next(err);
                } else if (isRecipient) {
                    next();
                } else {
                    next(new HTTPError("Only the author and recipients can view this object.", 403));
                }
            }
        );
    }
};

exports.requestObject     = requestObject;
exports.authorOnly        = authorOnly;
exports.authorOrRecipient = authorOrRecipient;
<|endoftext|>


<commit_before>var _ = require("underscore"),
    utils = require("./utils"),
    models = require("./server-models"),
    logger = require("./logging").getLogger();

var ensureSuperuser = utils.ensureSuperuser

module.exports = {
    route: function(app, db, options) {
        //---------------------------------------------------------//
        //                        PERMALINKS                            //
        //---------------------------------------------------------//

        app.get("/h/", utils.ensureAuthenticated, function(req, res) {
            res.render('permalink-intro.ejs', {user: req.user});
        });

        app.get("/h/admin/:code/:key", utils.ensureAuthenticated, function(req, res) {
            var session = db.permalinkSessions.find(function(s) {
                return s.get("shortCode")===req.params.code;
            });

            if(_.isUndefined(session)) {
                logger.warn("Request for /h/admin/:code/:key with unknown session code: " + req.params.code);
                res.status(404);
                res.send();
                return;
            }

            if(req.params.key===session.get("creationKey")) {
                // now render the normal permalink view, but with the admin interface showing.
                res.render('permalink.ejs', {showAdmin: true, users:db.users, session:session });
            } else {
                logger.warn("Attempt to load /h/admin/:code/:key with invalid key for this session: " + req.params.key);
                res.status(403);
                res._errorReason = "invalid creationKey";
                res.send();
                return;
            }

        });

        app.post("/h/admin/:code", utils.ensureAuthenticated, function(req, res) {
            if(!("creationKey" in req.body)) {
                res.status(400);
                res.send();
                return;
            }

            // otherwise, if creationKey is present, check it against the specified session.
            var session = db.permalinkSessions.find(function(s) {
                return s.get("shortCode")==req.params.code;
            });

            if(_.isUndefined(session)) {
                logger.warn("sess:unknown (set title/desc)" + JSON.stringify(req.body));
                res.status(404);
                res.send();
                return;
            }

            if(req.body.creationKey===session.get("creationKey")) {
                session.set("title", req.body.title);
                session.set("description", req.body.description);
                session.save();

                res.redirect("/h/" + req.params.code);
                logger.analytics("permalinks", {
                    action: "update",
                    title: req.body.title,
                    description: req.body.description,
                    shortCode: session.get("shortCode"),
                    req: req,
                    session: session
                });
            } else {
                logger.warn("POST to /h/admin/:code with invaid creationKey.");
                res.status(403);
                res._errorReason = "invalid creationKey",
                res.send();
                return;
            }
        });

        app.get("/h/:code", utils.ensureAuthenticated, function(req, res) {
            // okay, this is the permalink part of the site. if this key exists already,
            // then render an appropriate template immediately. if we don't have a
            // session that matches this code, then create one and then render
            // the page.

            // validate shortcodes here.
            var re = /^[A-Za-z0-9-_.+]*$/;
            if(!re.test(req.params.code)) {
                logger.warn("GET /h/" + req.params.code + " is not a valid hangout permalink");
                res.send(400, "Invalid short code.");
                res._errorReason = "invalid shortCode";
                return;
            }

            var session = db.permalinkSessions.findWhere({shortCode: req.params.code});
            if(!session) {
                session = new models.ServerSession();
                session.set("isPermalinkSession", true);

                // use the specified code for the new session.
                session.set("shortCode", req.params.code);
                db.permalinkSessions.add(session);
                session.generateCreationKey();
                session.set("first-load", true);
                session.save();

                // now redirect them to the admin page for this session.
                res.redirect("/h/admin/" + req.params.code + "/" + session.get("creationKey"));
                logger.analytics("permalinks", {
                    action: "create",
                    shortCode: req.params.code,
                    session: session,
                    req: req,
                    res: res
                });
                return;
            }

            // the problem with this is that we don't actually have all users in the
            // hangout in our list of users. That only includes people who have logged
            // in here. Not sure what to do about this. We'll either have to force
            // people to google log in when they land on the page, OR we're
            // going to have to have the participant information sent from the
            // hangout app instead of just the ids involved.

            res.render('permalink.ejs', {showAdmin: false, users:db.users, session:session});

            // after rendering, drop the first-load
            if(session.get("first-load")) {
                session.set("first-load", false);
                session.save();
            }
        });

        // this endpoint manually stops a shortcode session.
        // we seem to occasionally get sessions that are broken and stay open when
        // they're supposed to be closed. this lets us fix that issue.
        // this checks global admin status, not per-shortcode admin status.
        // we could at some point add this in to the permalink admin page, but I don't
        // think people actually go back to that.
        app.post("/h/:code/stop", utils.ensureAuthenticated, ensureSuperuser, function(req, res) {
            var session = db.permalinkSessions.find(function(s) {
                return s.get("shortCode")==req.params.code;
            });
            if(!session) {
                logger.warn("sess:unknown (stop)" + JSON.stringify(req.body));
                res.send(404, "Not found");
                return;
            }
            session.onHangoutStopped()
            res.redirect("/admin");
        });
    }
}
<commit_msg>removing authentication from permalinks - not sure though if it's the right approach<commit_after>var _ = require("underscore"),
    utils = require("./utils"),
    models = require("./server-models"),
    logger = require("./logging").getLogger();

var ensureSuperuser = utils.ensureSuperuser

module.exports = {
    route: function(app, db, options) {
        //---------------------------------------------------------//
        //                        PERMALINKS                            //
        //---------------------------------------------------------//

        app.get("/h/", function(req, res) {
            res.render('permalink-intro.ejs', {user: req.user});
        });

        app.get("/h/admin/:code/:key", function(req, res) {
            var session = db.permalinkSessions.find(function(s) {
                return s.get("shortCode")===req.params.code;
            });

            if(_.isUndefined(session)) {
                logger.warn("Request for /h/admin/:code/:key with unknown session code: " + req.params.code);
                res.status(404);
                res.send();
                return;
            }

            if(req.params.key===session.get("creationKey")) {
                // now render the normal permalink view, but with the admin interface showing.
                res.render('permalink.ejs', {showAdmin: true, users:db.users, session:session });
            } else {
                logger.warn("Attempt to load /h/admin/:code/:key with invalid key for this session: " + req.params.key);
                res.status(403);
                res._errorReason = "invalid creationKey";
                res.send();
                return;
            }

        });

        app.post("/h/admin/:code", function(req, res) {
            if(!("creationKey" in req.body)) {
                res.status(400);
                res.send();
                return;
            }

            // otherwise, if creationKey is present, check it against the specified session.
            var session = db.permalinkSessions.find(function(s) {
                return s.get("shortCode")==req.params.code;
            });

            if(_.isUndefined(session)) {
                logger.warn("sess:unknown (set title/desc)" + JSON.stringify(req.body));
                res.status(404);
                res.send();
                return;
            }

            if(req.body.creationKey===session.get("creationKey")) {
                session.set("title", req.body.title);
                session.set("description", req.body.description);
                session.save();

                res.redirect("/h/" + req.params.code);
                logger.analytics("permalinks", {
                    action: "update",
                    title: req.body.title,
                    description: req.body.description,
                    shortCode: session.get("shortCode"),
                    req: req,
                    session: session
                });
            } else {
                logger.warn("POST to /h/admin/:code with invaid creationKey.");
                res.status(403);
                res._errorReason = "invalid creationKey",
                res.send();
                return;
            }
        });

        app.get("/h/:code", function(req, res) {
            // okay, this is the permalink part of the site. if this key exists already,
            // then render an appropriate template immediately. if we don't have a
            // session that matches this code, then create one and then render
            // the page.

            // validate shortcodes here.
            var re = /^[A-Za-z0-9-_.+]*$/;
            if(!re.test(req.params.code)) {
                logger.warn("GET /h/" + req.params.code + " is not a valid hangout permalink");
                res.send(400, "Invalid short code.");
                res._errorReason = "invalid shortCode";
                return;
            }

            var session = db.permalinkSessions.findWhere({shortCode: req.params.code});
            if(!session) {
                session = new models.ServerSession();
                session.set("isPermalinkSession", true);

                // use the specified code for the new session.
                session.set("shortCode", req.params.code);
                db.permalinkSessions.add(session);
                session.generateCreationKey();
                session.set("first-load", true);
                session.save();

                // now redirect them to the admin page for this session.
                res.redirect("/h/admin/" + req.params.code + "/" + session.get("creationKey"));
                logger.analytics("permalinks", {
                    action: "create",
                    shortCode: req.params.code,
                    session: session,
                    req: req,
                    res: res
                });
                return;
            }

            // the problem with this is that we don't actually have all users in the
            // hangout in our list of users. That only includes people who have logged
            // in here. Not sure what to do about this. We'll either have to force
            // people to google log in when they land on the page, OR we're
            // going to have to have the participant information sent from the
            // hangout app instead of just the ids involved.

            res.render('permalink.ejs', {showAdmin: false, users:db.users, session:session});

            // after rendering, drop the first-load
            if(session.get("first-load")) {
                session.set("first-load", false);
                session.save();
            }
        });

        // this endpoint manually stops a shortcode session.
        // we seem to occasionally get sessions that are broken and stay open when
        // they're supposed to be closed. this lets us fix that issue.
        // this checks global admin status, not per-shortcode admin status.
        // we could at some point add this in to the permalink admin page, but I don't
        // think people actually go back to that.
        app.post("/h/:code/stop", ensureSuperuser, function(req, res) {
            var session = db.permalinkSessions.find(function(s) {
                return s.get("shortCode")==req.params.code;
            });
            if(!session) {
                logger.warn("sess:unknown (stop)" + JSON.stringify(req.body));
                res.send(404, "Not found");
                return;
            }
            session.onHangoutStopped()
            res.redirect("/admin");
        });
    }
}
<|endoftext|>