<commit_before>import axios from '../lib/axios'
import React from 'react'
import PropTypes from 'prop-types'
import 'react-stepzilla/src/css/main.css'
import qs from 'querystring'
import { hot } from 'react-hot-loader'

import MultiStepForm from './MultiStepForm'
import FormStep from './steps/FormStep'
import ContactStep from './steps/ContactStep'
import LocationStep from './steps/LocationStep'
import ScheduleStep from './steps/ScheduleStep'

import './style.css'

// defined by webpack
const apiEndpoint = API_ENDPOINT // eslint-disable-line no-undef

const groupTypes = [
  {
    id: 'G',
    label: 'Une réunion de groupe',
    description: 'Une réunion qui concerne principalement les membres du groupes, et non le public de façon générale. ' +
      'Par exemple, la réunion hebdomadaire du groupe, une réunion de travail, ou l\'audition d\'une association'
  },
  {
    id: 'M',
    label: 'Une réunion publique',
    description: 'Une réunion ouverts à tous les publics, au-delà des membres du groupe d\'action, mais qui aura lieu ' +
      'dans un lieu privé. Par exemple, une réunion publique avec un orateur, une projection ou un concert.'
  },
  {
    id: 'A',
    label: 'Une action publique',
    description: 'Une action qui se déroulera dans un lieu public et qui aura comme objectif principal d\'aller à la' +
      'rencontre ou d\'atteindre des personnes extérieures à la FI'
  },
  {
    id: 'O',
    label: 'Un autre type d\'événement',
    description: 'Tout autre type d\'événement qui ne rentre pas dans les catégories ci-dessus.'
  }
]

class CreateEventForm extends React.Component {
  constructor (props) {
    super(props)
    this.state = { fields: props.initial || {} }
    this.setFields = this.setFields.bind(this)
  }

  async componentDidMount () {
    let subtypes = (await axios.get(apiEndpoint + '/events_subtypes/')).data
    this.setState({ subtypes })
  }

  setFields (fields) {
    this.setState({ fields: Object.assign({}, this.state.fields, fields) })
  }

  render () {
    if (!this.state.subtypes) {
      return null
    }

    let steps = [
      {
        name: 'Quel type ?',
        component: <EventTypeStep setFields={this.setFields} fields={this.state.fields} subtypes={this.state.subtypes} />
      },
      {
        name: 'Qui contacter ?',
        component: <ContactStep setFields={this.setFields} fields={this.state.fields} />
      },
      { name: 'Quand ?', component: <ScheduleStep setFields={this.setFields} fields={this.state.fields} /> },
      { name: 'Où ?', component: <LocationStep setFields={this.setFields} fields={this.state.fields} /> },
      { name: 'Validation et nom', component: <ValidateStep fields={this.state.fields} /> }
    ]

    if (this.props.groups && this.props.groups.length > 0) {
      steps.splice(1, 0, {
        name: 'Qui organise ?',
        component: <OrganizerStep setFields={this.setFields} fields={this.state.fields} groups={this.props.groups} />
      })
    }

    return <MultiStepForm steps={steps} />
  }
}

CreateEventForm.propTypes = {
  'groups': PropTypes.array,
  'initial': PropTypes.object
}

function CheckBoxList ({ children }) {
  return

    {children}

}

CheckBoxList.propTypes = {
  children: PropTypes.node
}

function CheckBox ({ label, active, onClick }) {
  return

     {
      e.preventDefault()
      onClick()
    }}>  {label}

}

CheckBox.propTypes = {
  label: PropTypes.string,
  active: PropTypes.bool,
  onClick: PropTypes.func
}

class EventTypeStep extends FormStep {
  constructor (props) {
    super(props)
    this.rankedSubtypes = props.subtypes.reduce((acc, s) => {
      (acc[s.type] = acc[s.type] || []).push(s)
      return acc
    }, {})
  }

  setSubtype (subtype) {
    this.props.setFields({
      subtype: subtype.label
    })
  }

  isCurrentSubtype (subtype) {
    return subtype.label === this.props.fields.subtype
  }

  isValidated () {
    return !!this.props.fields.subtype
  }

  getRightColumn () {
    if (this.state.isNotCampaign) {
      return (

Je veux créer...
{
            groupTypes.map(type => (

{type.label}

                <CheckBoxList>
                  {
                    this.rankedSubtypes[type.id].map(subtype => (
                      <CheckBox key={subtype.description} active={this.isCurrentSubtype(subtype)}
                        label={subtype.description} onClick={() => this.setSubtype(subtype)} />
                    ))
                  }
                </CheckBoxList>

            ))
          }

      )
    }

    return (

          Attention ! De manière générale, vous ne pouvez pas engager de frais sans la validation du mandataire
          financier de la campagne européenne ou de la France insoumise. Pour vous guider dans la création de votre
          événement, merci d'indiquer les éléments suivants :

Mon événement...

...est en lien avec la campagne des européennes

S'agit-il d'un événement de campagne ?

         <input type='radio' onClick={() => this.setState({ campaign: true })}
            checked={this.state.campaign} /> Oui
         <input type='radio' onClick={() => this.setState({ campaign: false })}
            checked={!this.state.campaign} /> Non

         Je remplis le formulaire d'accord préalable

...un autre événement

Ce n'est pas un événement de campagne, ou c'est un événement de campagne qui ne nécessite pas de moyens
          payants. S'il y a un concours gratuit en nature (prêt de salle, de matériel...), vous devez néanmoins
          remplir  le
            formulaire dédié à l'issue de l'événement.

        <button className='btn btn-default' onClick={() => this.setState({ isNotCampaign: true })}>Je crée directement
          mon événement
        </button>

    )
  }

  render () {
    return (

Quel type d'événement voulez-vous créer ?

            Chaque insoumis·e peut créer un événement sur la plateforme dès lors qu’il respecte le cadre et la démarche
            de la France insoumise dans un esprit d’ouverture, de bienveillance et de volonté de se projeter dans
            l’action.

            Afin de mieux identifier les événements que vous créez, et de pouvoir mieux les recommander aux autres
            insoumis⋅es, indiquez le type d'événement que vous organisez.

            Vous souhaitez inviter un⋅e député⋅e, candidat⋅e, ou animateur⋅ice de livret ? {' '} Suivez le mode d'emploi.

        {this.getRightColumn()}

    )
  }
}

class OrganizerStep extends FormStep {
  constructor (props) {
    super(props)
    this.setIndividual = this.setIndividual.bind(this)
  }

  setIndividual () {
    this.props.setFields({ organizerGroup: null })
  }

  setGroup (group) {
    this.props.setFields({ organizerGroup: group.id })
  }

  render () {
    const { organizerGroup } = this.props.fields

    return

Qui organise l'événement ?

          Un événement peut être organisé à titre individuel par une personne. Mais comme vous êtes aussi gestionnaire
          d'un groupe d'action, il est aussi possible d'indiquer que cet événement est organisé par votre groupe.

L'événement est organisé...

...à titre individuel

          <CheckBoxList> <CheckBox active={!organizerGroup} label="J'en suis l'organisateur"
            onClick={this.setIndividual} /> </CheckBoxList>

...par un groupe d'action

          <CheckBoxList>
            {this.props.groups.map((group) => (
              <CheckBox key={group.id} active={group.id === organizerGroup} label={group.name}
                onClick={() => this.setGroup(group)} />
            ))}
          </CheckBoxList>

  }
}

class ValidateStep extends FormStep {
  constructor (props) {
    super(props)
    this.post = this.post.bind(this)
    this.state = { processing: false }
    this.eventNameRef = React.createRef()
  }

  async post (e) {
    e.preventDefault()
    this.setState({ processing: true })

    const { fields } = this.props
    let data = qs.stringify({
      name: this.eventNameRef.current.value,
      contact_email: fields.email,
      contact_name: fields.name || null,
      contact_phone: fields.phone,
      contact_hide_phone: fields.hidePhone,
      start_time: fields.startTime.format('YYYY-MM-DD HH:mm:SS'),
      end_time: fields.endTime.format('YYYY-MM-DD HH:mm:SS'),
      location_name: fields.locationName,
      location_address1: fields.locationAddress1,
      location_address2: fields.locationAddress2 || null,
      location_zip: fields.locationZip,
      location_city: fields.locationCity,
      location_country: fields.locationCountryCode,
      subtype: fields.subtype,
      as_group: fields.organizerGroup
    })

    try {
      let res = await axios.post('form/', data)
      window.location.href = res.data.url
    } catch (e) {
      this.setState({ error: e, processing: false })
    }
  }

  render () {
    const { fields } = this.props
    return (

Voici les informations que vous avez entrées.

              Type d'événement : {fields.subtype.label}

              Numéro de téléphone : {fields.phone} ({fields.hidePhone ? 'caché' : 'public'})

            {fields.name &&

              Nom du contact pour l'événement : {fields.name}

            }

              Adresse email de contact pour l'événement : {fields.email}

              Horaires : Du {fields.startTime.format('LLL')} au {fields.endTime.format('LLL')}.

              Lieu :
 {fields.locationAddress1}
 {fields.locationAddress2
                ? {fields.locationAddress2}
 : ''} {fields.locationZip}, {fields.locationCity}

Pour finir, il vous reste juste à choisir un nom pour votre événement ! Choisissez un nom simple et
            descriptif (par exemple : « Porte à porte près du café de la gare »).

          <form onSubmit={this.post}>

              <input className='form-control' ref={this.eventNameRef} type='text' placeholder="Nom de l'événement"
                required />

            <button className='btn btn-primary' type='submit' disabled={this.state.processing}>Créer mon événement
            </button>
          </form>
          {this.state.error && (

              Une erreur s'est produite. Merci de réessayer plus tard.

          )}

    )
  }
}

export default hot(module)(CreateEventForm)
<commit_msg>Revert une modif comittée par erreur<commit_after>import axios from '../lib/axios';
import React from 'react';
import PropTypes from 'prop-types';
import 'react-stepzilla/src/css/main.css';
import qs from 'querystring';
import {hot} from 'react-hot-loader';

import MultiStepForm from './MultiStepForm';
import FormStep from './steps/FormStep';
import ContactStep from './steps/ContactStep';
import LocationStep from './steps/LocationStep';
import ScheduleStep from './steps/ScheduleStep';

import './style.css';

// defined by webpack
const apiEndpoint = API_ENDPOINT; // eslint-disable-line no-undef

const groupTypes = [
  {
    id: 'G',
    label: 'Une réunion de groupe',
    description: 'Une réunion qui concerne principalement les membres du groupes, et non le public de façon générale. ' +
    'Par exemple, la réunion hebdomadaire du groupe, une réunion de travail, ou l\'audition d\'une association'
  },
  {
    id: 'M',
    label: 'Une réunion publique',
    description: 'Une réunion ouverts à tous les publics, au-delà des membres du groupe d\'action, mais qui aura lieu ' +
    'dans un lieu privé. Par exemple, une réunion publique avec un orateur, une projection ou un concert.'
  },
  {
    id: 'A',
    label: 'Une action publique',
    description: 'Une action qui se déroulera dans un lieu public et qui aura comme objectif principal d\'aller à la' +
    'rencontre ou d\'atteindre des personnes extérieures à la FI'
  },
  {
    id: 'O',
    label: 'Un autre type d\'événement',
    description: 'Tout autre type d\'événement qui ne rentre pas dans les catégories ci-dessus.'
  }
];

class CreateEventForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {fields: props.initial || {}};
    this.setFields = this.setFields.bind(this);
  }

  async componentDidMount() {
    let subtypes = (await axios.get(apiEndpoint + '/events_subtypes/')).data;
    this.setState({subtypes});
  }

  setFields(fields) {
    this.setState({fields: Object.assign({}, this.state.fields, fields)});
  }

  render() {
    if (!this.state.subtypes) {
      return null;
    }

    let steps = [
      {
        name: 'Quel type ?',
        component: <EventTypeStep setFields={this.setFields} fields={this.state.fields} subtypes={this.state.subtypes}/>
      },
      {
        name: 'Qui contacter ?',
        component: <ContactStep setFields={this.setFields} fields={this.state.fields}/>
      },
      {name: 'Quand ?', component: <ScheduleStep setFields={this.setFields} fields={this.state.fields}/>},
      {name: 'Où ?', component: <LocationStep setFields={this.setFields} fields={this.state.fields}/>},
      {name: 'Validation et nom', component: <ValidateStep fields={this.state.fields}/>},
    ];

    if (this.props.groups && this.props.groups.length > 0) {
      steps.splice(1, 0, {
        name: 'Qui organise ?',
        component: <OrganizerStep setFields={this.setFields} fields={this.state.fields} groups={this.props.groups} />
      });
    }

    return <MultiStepForm steps={steps}/>;
  }
}

CreateEventForm.propTypes = {
  'groups': PropTypes.array,
  'initial': PropTypes.object
};

function CheckBoxList({children}) {
  return

    {children}

;
}

CheckBoxList.propTypes = {
  children: PropTypes.node
};

function CheckBox({label, active, onClick}) {
  return

     {
      e.preventDefault();
      onClick();
    }}
    >

      {label}

;
}

CheckBox.propTypes = {
  label: PropTypes.string,
  active: PropTypes.bool,
  onClick: PropTypes.func
};

class EventTypeStep extends FormStep {
  constructor(props) {
    super(props);
    this.rankedSubtypes = props.subtypes.reduce((acc, s) => {
      (acc[s.type] = acc[s.type] || []).push(s);
      return acc;
    }, {});
  }

  setSubtype(subtype) {
    this.props.setFields({
      subtype: subtype.label,
    });
  }

  isCurrentSubtype(subtype) {
    return subtype.label === this.props.fields.subtype;
  }

  isValidated() {
    return !!this.props.fields.subtype;
  }

  getRightColumn() {
    if (this.state.isNotCampaign) {
      return (

Je veux créer...

          {
            groupTypes.map(type => (

{type.label}

                <CheckBoxList>
                  {
                    this.rankedSubtypes[type.id].map(subtype => (
                      <CheckBox
                        key={subtype.description} active={this.isCurrentSubtype(subtype)}
                        label={subtype.description} onClick={() => this.setSubtype(subtype)}
                      />
                    ))
                  }
                </CheckBoxList>

            ))
          }

      );
    }

    return (

          Attention ! Nous sommes désormais officiellement en campagne
          électorale. Cela signifie que vous ne pouvez engager de frais sans
          la validation du mandataire financier de la campagne.

Je veux créer...

...un événement de campagne avec frais

Un événement de campagne qui implique des moyens financiers. S'il remplit certains critères, il peut
        être financé. Sinon, il doit être financé par des dons. Dans tous les cas, les factures doivent être réglées par
          le mandataire financier de la campagne.

          Je remplis le formulaire d'accord préalable

...un autre événement

Ce n'est pas un événement de campagne, ou c'est un événement de campagne qui ne nécessite pas de moyens
        payants. S'il y a un concours gratuit en nature (prêt de salle, de matériel...), vous devez néanmoins
        remplir
            le formulaire dédié à l'issue de l'événement.

        <button className="btn btn-default" onClick={() => this.setState({isNotCampaign: true})}>Je crée directement mon événement</button>

    )
  }

  render() {
    return (

Quel type d'événement voulez-vous créer ?

            Chaque insoumis·e peut créer un événement sur la plateforme dès lors
            qu’il respecte le cadre et la démarche de la France insoumise dans un esprit
            d’ouverture, de bienveillance et de volonté de se projeter dans l’action.

            Afin de mieux identifier les événements que vous créez, et de pouvoir mieux les recommander aux autres
            insoumis⋅es, indiquez le type d'événement que vous organisez.

            Vous souhaitez inviter un⋅e député⋅e, candidat⋅e, ou animateur⋅ice de livret ?
            {' '}
            Suivez le mode d'emploi.

        {this.getRightColumn()}

    );
  }
}

class OrganizerStep extends FormStep {
  constructor(props) {
    super(props);
    this.setIndividual = this.setIndividual.bind(this);
  }

  setIndividual() {
    this.props.setFields({organizerGroup: null});
  }

  setGroup(group) {
    this.props.setFields({organizerGroup: group.id});
  }

  render() {
    const {organizerGroup} = this.props.fields;

    return

Qui organise l'événement ?

          Un événement peut être organisé à titre individuel par une personne. Mais comme vous êtes aussi gestionnaire
          d'un groupe d'action, il est aussi possible d'indiquer que cet événement est organisé par votre groupe.

L'événement est organisé...

...à titre individuel

          <CheckBoxList>
            <CheckBox
              active={!organizerGroup} label="J'en suis l'organisateur"
              onClick={this.setIndividual}
            />
          </CheckBoxList>

...par un groupe d'action

          <CheckBoxList>
            {this.props.groups.map((group) => (
              <CheckBox
                key={group.id}
                active={group.id === organizerGroup}
                label={group.name}
                onClick={() => this.setGroup(group)}
              />
            ))}
          </CheckBoxList>

;
  }
}

class ValidateStep extends FormStep {
  constructor(props) {
    super(props);
    this.post = this.post.bind(this);
    this.state = {processing: false};
  }

  async post(e) {
    e.preventDefault();
    this.setState({processing: true});

    const {fields} = this.props;
    let data = qs.stringify({
      name: this.eventName.value,
      contact_email: fields.email,
      contact_name: fields.name || null,
      contact_phone: fields.phone,
      contact_hide_phone: fields.hidePhone,
      start_time: fields.startTime.format('YYYY-MM-DD HH:mm:SS'),
      end_time: fields.endTime.format('YYYY-MM-DD HH:mm:SS'),
      location_name: fields.locationName,
      location_address1: fields.locationAddress1,
      location_address2: fields.locationAddress2 || null,
      location_zip: fields.locationZip,
      location_city: fields.locationCity,
      location_country: fields.locationCountryCode,
      subtype: fields.subtype,
      as_group: fields.organizerGroup
    });

    try {
      let res = await axios.post('form/', data);
      location.href = res.data.url;
    } catch (e) {
      this.setState({error: e, processing: false});
    }
  }

  render() {
    const {fields} = this.props;
    return (

Voici les informations que vous avez entrées.

              Type d'événement : {fields.subtype.label}

              Numéro de
                téléphone : {fields.phone} ({fields.hidePhone ? 'caché' : 'public'})

            {fields.name &&

              Nom du contact pour l'événement : {fields.name}

            }

              Adresse email de contact pour l'événement : {fields.email}

              Horaires : Du {fields.startTime.format('LLL')} au {fields.endTime.format('LLL')}.

              Lieu :

              {fields.locationAddress1}

              {fields.locationAddress2 ? {fields.locationAddress2}
 : ''}
              {fields.locationZip}, {fields.locationCity}

Pour finir, il vous reste juste à choisir un nom pour votre événement ! Choisissez un nom simple
            et descriptif (par exemple : « Porte à porte près du café de la gare »).

          <form onSubmit={this.post}>

              <input
                className="form-control" ref={i => this.eventName = i} type="text" placeholder="Nom de l'événement"
                required
              />

            <button className="btn btn-primary" type="submit" disabled={this.state.processing}>Créer mon événement
            </button>
          </form>
          {this.state.error && (

              Une erreur s'est produite. Merci de réessayer plus tard.

          )}

    );
  }
}

export default hot(module)(CreateEventForm);
<|endoftext|>


<commit_before>
'use strict';

/**
 * UI.Layout
 */
angular.module('ui.layout', [])
  .controller('uiLayoutCtrl', ['$scope', '$attrs', '$element', function uiLayoutCtrl($scope, $attrs, $element) {
    // Gives to the children directives the access to the parent layout.
    return {
      opts: angular.extend({}, $scope.$eval($attrs.uiLayout), $scope.$eval($attrs.options)),
      element: $element
    };
  }])

  .directive('uiLayout', ['$parse', function ($parse) {

    var splitBarElem_htmlTemplate = '

';

    function convertNumericDataTypesToPencents(numberVairousTypeArray, minSizes, maxSizes, parentSize){
      var _i, _n;
      var _res = []; _res.length = numberVairousTypeArray.length;
      var _commonSizeIndex = [];
      var _minSizes = [];
      var _maxSizes = [];
      var _remainingSpace = 100;

      for (_i = 0, _n = numberVairousTypeArray.length; _i < _n; ++_i) {
        var minSize = parseInt(minSizes[_i], 10);
        if(minSize) {
          var minType = minSizes[_i].match(/\d+\s*(px|%)\s*$/i);
          if(!isNaN(minSize) && minType) {
            if(minType.length > 1 && 'px' === minType[1]) {
               minSize = + (minSize / parentSize * 100).toFixed(5);
            }
          }
        }
        _minSizes.push(minSize);

        var maxSize = parseInt(maxSizes[_i], 10);
        if(maxSize) {
          var maxType = maxSizes[_i].match(/\d+\s*(px|%)\s*$/i);
          if(!isNaN(maxSize) && maxType) {
            if(maxType.length > 1 && 'px' === maxType[1]) {
               maxSize = + (maxSize / parentSize * 100).toFixed(5);
            }
          }
        }
        _maxSizes.push(maxSize);

        var rawSize = numberVairousTypeArray[_i];
        var value = parseInt(rawSize, 10);
        // should only support pixels and pencent data type
        var type = rawSize.match(/\d+\s*(px|%)\s*$/i);
        if (!isNaN(value) && type){
          if (type.length > 1 && 'px' === type[1]){
            value = + (value / parentSize * 100).toFixed(5);
          }

          if(minSize) value = Math.max(value, minSize);
          if(maxSize) value = Math.min(value, maxSize);

          _res[_i] = value;
          _remainingSpace -= value;
        }  else {
          rawSize = 'auto';
        }

        if (/^\s*auto\s*$/.test(rawSize)){
          _commonSizeIndex.push(_i); continue;
        }
      }

      if (_commonSizeIndex.length > 0){
        var _commonSize = _remainingSpace / _commonSizeIndex.length;
        var _modifiedSizeIndex = [];
        // Check to make sure the common size isn't outside the bounds of min/max-size
        for (_i = 0, _n = _commonSizeIndex.length; _i < _n; ++_i) {
          var _cid = _commonSizeIndex[_i];
          var _minSize = _minSizes[_cid];
          var _maxSize = _maxSizes[_cid];
          if(_commonSize <= _minSize) {
            _remainingSpace -= _minSize;
            _res[_cid] = _minSize;
          } else if(_commonSize >= _maxSize) {
            _remainingSpace -= _maxSize;
            _res[_cid] = _maxSize;
          } else {
            _modifiedSizeIndex.push(_cid);
          }
        }
        _commonSize = _remainingSpace / _modifiedSizeIndex.length;
        for (_i = 0, _n = _modifiedSizeIndex.length; _i < _n; ++_i) {
          var cid = _modifiedSizeIndex[_i];
          if(cid !== null) {
            _res[cid] = _commonSize;
          }
        }
      }

      parentSize;

      return _res;
    }

    return {
      restrict: 'AE',
      compile: function compile(tElement, tAttrs) {

        var _i, _childens = tElement.children(), _child_len = _childens.length;
        var _sizes, _position;

        // Parse `ui-layout` or `options` attributes (with no scope...)
        var opts = angular.extend({}, $parse(tAttrs.uiLayout)(), $parse(tAttrs.options)());
        var isUsingColumnFlow = opts.flow === 'column';

        tElement
          // Force the layout to fill the parent space
          // fix no height layout...
          .addClass('stretch')
          // set the layout css class
          .addClass('ui-layout-' + (opts.flow || 'row'));

        // Initial global size definition
        opts.sizes = opts.sizes || [];
        opts.maxSizes = opts.maxSizes || [];
        opts.minSizes = opts.minSizes || [];
        opts.dividerSize = opts.dividerSize || '10px';

        // Preallocate the array size
        opts.sizes.length = _child_len;

        for (_i = 0; _i < _child_len; ++_i) {
          // Stretch all the children by default
          angular.element(_childens[_i]).addClass('stretch');
          // Size initialization priority
          // - the size attr on the child element
          // - the global size on the layout option
          // - 'auto' Fair separation of the remaining space
          opts.sizes[_i] = angular.element(_childens[_i]).attr('size') || opts.sizes[_i]  || 'auto';
          opts.maxSizes[_i] = angular.element(_childens[_i]).attr('max-size') || opts.maxSizes[_i] || null;
          opts.minSizes[_i] = angular.element(_childens[_i]).attr('min-size') || opts.minSizes[_i] || null;
        }

        // get the final percent sizes
        _sizes = convertNumericDataTypesToPencents(opts.sizes, opts.minSizes, opts.maxSizes, tElement[0]['offset' + (isUsingColumnFlow ? 'Width' : 'Height')]);

        if (_child_len > 1) {
          // Initialise the layout with equal sizes.
          var flowProperty = ( isUsingColumnFlow ? 'left' : 'top');
          var oppositeFlowProperty = ( isUsingColumnFlow ? 'right' : 'bottom');
          var sizeProperty = ( isUsingColumnFlow ? 'width' : 'height');
          _position = 0;
          for (_i = 0; _i < _child_len; ++_i) {
            var area = angular.element(_childens[_i])
              .css(flowProperty, _position + '%');

            _position += _sizes[_i];
            area.css(oppositeFlowProperty, (100 - _position) + '%');

            if (_i < _child_len - 1) {
              // Add a split bar
              var bar = angular.element(splitBarElem_htmlTemplate).css(flowProperty, _position + '%');
              bar.css(sizeProperty, opts.dividerSize);
              area.after(bar);
            }
          }
        }
      },
      controller: 'uiLayoutCtrl'
    };

  }])

  .directive('uiSplitbar', function () {

    // Get all the page.
    var htmlElement = angular.element(document.body.parentElement);

    return {
      require: '^uiLayout',
      restrict: 'EAC',
      link: function (scope, iElement, iAttrs, parentLayout) {

        var animationFrameRequested, lastX;
        var _cache = {};

        // Use relative mouse position
        var isUsingColumnFlow = parentLayout.opts.flow === 'column';
        var mouseProperty = ( isUsingColumnFlow ? 'clientX' : 'clientY');

        // Use bounding box / css property names
        var flowProperty = ( isUsingColumnFlow ? 'left' : 'top');
        var oppositeFlowProperty = ( isUsingColumnFlow ? 'right' : 'bottom');
        var sizeProperty = ( isUsingColumnFlow ? 'width' : 'height');

        // Use bounding box properties
        var barElm = iElement[0];
        var previousElement = barElm.previousElementSibling;
        var nextElement = barElm.nextElementSibling;

        // Stores the layout values for some seconds to not recalculate it during the animation
        function _cached_layout_values() {
          // layout bounding box
          var layout_bb = parentLayout.element[0].getBoundingClientRect();

          // split bar bounding box
          var bar_bb = barElm.getBoundingClientRect();

          _cache.time = +new Date();
          _cache.barSize = bar_bb[sizeProperty];
          _cache.layoutSize = layout_bb[sizeProperty];
          _cache.layoutOrigine = layout_bb[flowProperty];
          _cache.previousElement = previousElement.getBoundingClientRect();
          _cache.previousElement.min = parseInt(previousElement.getAttribute('min-size'),10);
          _cache.previousElement.max = parseInt(previousElement.getAttribute('max-size'),10);
          _cache.nextElement = nextElement.getBoundingClientRect();
          _cache.nextElement.min = parseInt(nextElement.getAttribute('min-size'),10);
          _cache.nextElement.max = parseInt(nextElement.getAttribute('max-size'),10);

          var dividerSize = isNaN(bar_bb[sizeProperty]) ? bar_bb[sizeProperty] : bar_bb[sizeProperty] + 'px';
          var _dividerSize = parseInt(dividerSize, 10);
          var _dividerType = dividerSize.match(/\d+\s*(px|%)\s*$/i);
          if(!isNaN(_dividerSize) && _dividerType) {
            if(_dividerType.length > 1 && 'px' === _dividerType[1]) {
              _dividerSize = + (_dividerSize / _cache.layoutSize * 100).toFixed(5);
            }
          }

          if(_cache.previousElement.min) {
            var minType = previousElement.getAttribute('min-size').match(/\d+\s*(px|%)\s*$/i);
            if(!isNaN(_cache.previousElement.min) && minType) {
              if(minType.length > 1 && 'px' === minType[1]) {
                 _cache.previousElement.min = + (_cache.previousElement.min / _cache.layoutSize * 100).toFixed(5);
              }
            }
            // ensure the min size isn't smaller than the divider size
            if(_dividerSize && _cache.previousElement.min < _dividerSize) _cache.previousElement.min = _dividerSize;
          } else {
            _cache.previousElement.min = _dividerSize;
          }

          if( _cache.previousElement.max) {
            var maxType = previousElement.getAttribute('max-size').match(/\d+\s*(px|%)\s*$/i);
            if(!isNaN( _cache.previousElement.max) && maxType) {
              if(maxType.length > 1 && 'px' === maxType[1]) {
                  _cache.previousElement.max = + ( _cache.previousElement.max / _cache.layoutSize * 100).toFixed(5);
              }
            }
          }

          if(_cache.nextElement.min) {
            var _minType = nextElement.getAttribute('min-size').match(/\d+\s*(px|%)\s*$/i);
            if(!isNaN(_cache.nextElement.min) && _minType) {
              if(_minType.length > 1 && 'px' === _minType[1]) {
                 _cache.nextElement.min = + (_cache.nextElement.min / _cache.layoutSize * 100).toFixed(5);
              }
            }
            // ensure the min size isn't smaller than the divider size
            if(_dividerSize && _cache.nextElement.min < _dividerSize) _cache.nextElement.min = _dividerSize;
          } else {
            _cache.nextElement.min = _dividerSize;
          }

          if(_cache.nextElement.max) {
            var _maxType = nextElement.getAttribute('max-size').match(/\d+\s*(px|%)\s*$/i);
            if(!isNaN(_cache.nextElement.max) && _maxType) {
              if(_maxType.length > 1 && 'px' === _maxType[1]) {
                 _cache.nextElement.max = + (_cache.nextElement.max / _cache.layoutSize * 100).toFixed(5);
              }
            }
          }
        }

        function _draw() {
          var the_pos = (lastX - _cache.layoutOrigine) / _cache.layoutSize * 100;

          // Keep the bar in the window (no left/top 100%)
          the_pos = Math.min(the_pos, 100 - _cache.barSize / _cache.layoutSize * 100);

          // Keep the bar from going past the previous elements max/min sizes
          var previousElementValue = _cache.previousElement[flowProperty] / _cache.layoutSize * 100;
          if(!isNaN(_cache.previousElement.min) && the_pos < (previousElementValue + _cache.previousElement.min)) the_pos = (previousElementValue + _cache.previousElement.min);
          if(!isNaN(_cache.previousElement.max) && the_pos > (previousElementValue + _cache.previousElement.max)) the_pos = (previousElementValue + _cache.previousElement.max);

          // Keep the bar from going past the next elements max/min sizes
          var nextElementValue = (_cache.nextElement[flowProperty] + _cache.nextElement[sizeProperty]) / _cache.layoutSize * 100;
          var nextElementMinValue = nextElementValue - _cache.nextElement.min;
          var nextElementMaxValue = nextElementValue - _cache.nextElement.max;
          if(!isNaN(_cache.nextElement.max) && the_pos < nextElementMaxValue) the_pos = nextElementMaxValue;
          if(!isNaN(_cache.nextElement.min) && the_pos > nextElementMinValue) the_pos = nextElementMinValue;

          // The the bar in the near beetween the near by area
          the_pos = Math.max(the_pos, parseInt(barElm.previousElementSibling.style[flowProperty], 10));
          if (barElm.nextElementSibling.nextElementSibling) {
            the_pos = Math.min(the_pos, parseInt(barElm.nextElementSibling.nextElementSibling.style[flowProperty], 10));
          }

          // change the position of the bar and the next area
          barElm.style[flowProperty] = barElm.nextElementSibling.style[flowProperty] = the_pos + '%';
          // change the size of the previous area
          barElm.previousElementSibling.style[oppositeFlowProperty] = (100 - the_pos) + '%';

          // Enable a new animation frame
          animationFrameRequested = null;
        }

        function _resize(mouseEvent) {
          // Store the mouse position for later

          // FIX :
          // - with touch events, when using jQuery, the mouseEvent is in fact a jQueryEvent. So we use originalEvent here.
          // - real touch events comes in the _targetTouches_ array
          lastX = mouseEvent[mouseProperty] ||
            (mouseEvent.originalEvent && mouseEvent.originalEvent[mouseProperty]) ||
            (mouseEvent.targetTouches ? mouseEvent.targetTouches[0][mouseProperty] : 0);

          // Cancel previous rAF call
          if (animationFrameRequested) {
            window.cancelAnimationFrame(animationFrameRequested);
          }

          if (!_cache.time || +new Date() > _cache.time + 1000) { // after ~60 frames
            _cached_layout_values();
          }

          // Animate the page outside the event
          animationFrameRequested = window.requestAnimationFrame(_draw);
        }

        // Bind the click on the bar then you can move it all over the page.
        iElement.on('mousedown touchstart', function (e) {
          e.preventDefault();
          e.stopPropagation();
          htmlElement.on('mousemove touchmove', _resize);
          return false;
        });
        htmlElement.on('mouseup touchend', function () {
          htmlElement.off('mousemove touchmove');
        });
      }
    };
  });
<commit_msg>fix misspelled words<commit_after>
'use strict';

/**
 * UI.Layout
 */
angular.module('ui.layout', [])
  .controller('uiLayoutCtrl', ['$scope', '$attrs', '$element', function uiLayoutCtrl($scope, $attrs, $element) {
    // Gives to the children directives the access to the parent layout.
    return {
      opts: angular.extend({}, $scope.$eval($attrs.uiLayout), $scope.$eval($attrs.options)),
      element: $element
    };
  }])

  .directive('uiLayout', ['$parse', function ($parse) {

    var splitBarElem_htmlTemplate = '

';

    function convertNumericDataTypesToPercents(numberVariousTypeArray, minSizes, maxSizes, parentSize){
      var _i, _n;
      var _res = []; _res.length = numberVariousTypeArray.length;
      var _commonSizeIndex = [];
      var _minSizes = [];
      var _maxSizes = [];
      var _remainingSpace = 100;

      for (_i = 0, _n = numberVariousTypeArray.length; _i < _n; ++_i) {
        var minSize = parseInt(minSizes[_i], 10);
        if(minSize) {
          var minType = minSizes[_i].match(/\d+\s*(px|%)\s*$/i);
          if(!isNaN(minSize) && minType) {
            if(minType.length > 1 && 'px' === minType[1]) {
               minSize = + (minSize / parentSize * 100).toFixed(5);
            }
          }
        }
        _minSizes.push(minSize);

        var maxSize = parseInt(maxSizes[_i], 10);
        if(maxSize) {
          var maxType = maxSizes[_i].match(/\d+\s*(px|%)\s*$/i);
          if(!isNaN(maxSize) && maxType) {
            if(maxType.length > 1 && 'px' === maxType[1]) {
               maxSize = + (maxSize / parentSize * 100).toFixed(5);
            }
          }
        }
        _maxSizes.push(maxSize);

        var rawSize = numberVariousTypeArray[_i];
        var value = parseInt(rawSize, 10);
        // should only support pixels and percent data type
        var type = rawSize.match(/\d+\s*(px|%)\s*$/i);
        if (!isNaN(value) && type){
          if (type.length > 1 && 'px' === type[1]){
            value = + (value / parentSize * 100).toFixed(5);
          }

          if(minSize) value = Math.max(value, minSize);
          if(maxSize) value = Math.min(value, maxSize);

          _res[_i] = value;
          _remainingSpace -= value;
        }  else {
          rawSize = 'auto';
        }

        if (/^\s*auto\s*$/.test(rawSize)){
          _commonSizeIndex.push(_i); continue;
        }
      }

      if (_commonSizeIndex.length > 0){
        var _commonSize = _remainingSpace / _commonSizeIndex.length;
        var _modifiedSizeIndex = [];
        // Check to make sure the common size isn't outside the bounds of min/max-size
        for (_i = 0, _n = _commonSizeIndex.length; _i < _n; ++_i) {
          var _cid = _commonSizeIndex[_i];
          var _minSize = _minSizes[_cid];
          var _maxSize = _maxSizes[_cid];
          if(_commonSize <= _minSize) {
            _remainingSpace -= _minSize;
            _res[_cid] = _minSize;
          } else if(_commonSize >= _maxSize) {
            _remainingSpace -= _maxSize;
            _res[_cid] = _maxSize;
          } else {
            _modifiedSizeIndex.push(_cid);
          }
        }
        _commonSize = _remainingSpace / _modifiedSizeIndex.length;
        for (_i = 0, _n = _modifiedSizeIndex.length; _i < _n; ++_i) {
          var cid = _modifiedSizeIndex[_i];
          if(cid !== null) {
            _res[cid] = _commonSize;
          }
        }
      }

      parentSize;

      return _res;
    }

    return {
      restrict: 'AE',
      compile: function compile(tElement, tAttrs) {

        var _i, _children = tElement.children(), _child_len = _children.length;
        var _sizes, _position;

        // Parse `ui-layout` or `options` attributes (with no scope...)
        var opts = angular.extend({}, $parse(tAttrs.uiLayout)(), $parse(tAttrs.options)());
        var isUsingColumnFlow = opts.flow === 'column';

        tElement
          // Force the layout to fill the parent space
          // fix no height layout...
          .addClass('stretch')
          // set the layout css class
          .addClass('ui-layout-' + (opts.flow || 'row'));

        // Initial global size definition
        opts.sizes = opts.sizes || [];
        opts.maxSizes = opts.maxSizes || [];
        opts.minSizes = opts.minSizes || [];
        opts.dividerSize = opts.dividerSize || '10px';

        // Preallocate the array size
        opts.sizes.length = _child_len;

        for (_i = 0; _i < _child_len; ++_i) {
          // Stretch all the children by default
          angular.element(_children[_i]).addClass('stretch');
          // Size initialization priority
          // - the size attr on the child element
          // - the global size on the layout option
          // - 'auto' Fair separation of the remaining space
          opts.sizes[_i] = angular.element(_children[_i]).attr('size') || opts.sizes[_i]  || 'auto';
          opts.maxSizes[_i] = angular.element(_children[_i]).attr('max-size') || opts.maxSizes[_i] || null;
          opts.minSizes[_i] = angular.element(_children[_i]).attr('min-size') || opts.minSizes[_i] || null;
        }

        // get the final percent sizes
        _sizes = convertNumericDataTypesToPercents(opts.sizes, opts.minSizes, opts.maxSizes, tElement[0]['offset' + (isUsingColumnFlow ? 'Width' : 'Height')]);

        if (_child_len > 1) {
          // Initialise the layout with equal sizes.
          var flowProperty = ( isUsingColumnFlow ? 'left' : 'top');
          var oppositeFlowProperty = ( isUsingColumnFlow ? 'right' : 'bottom');
          var sizeProperty = ( isUsingColumnFlow ? 'width' : 'height');
          _position = 0;
          for (_i = 0; _i < _child_len; ++_i) {
            var area = angular.element(_children[_i])
              .css(flowProperty, _position + '%');

            _position += _sizes[_i];
            area.css(oppositeFlowProperty, (100 - _position) + '%');

            if (_i < _child_len - 1) {
              // Add a split bar
              var bar = angular.element(splitBarElem_htmlTemplate).css(flowProperty, _position + '%');
              bar.css(sizeProperty, opts.dividerSize);
              area.after(bar);
            }
          }
        }
      },
      controller: 'uiLayoutCtrl'
    };

  }])

  .directive('uiSplitbar', function () {

    // Get all the page.
    var htmlElement = angular.element(document.body.parentElement);

    return {
      require: '^uiLayout',
      restrict: 'EAC',
      link: function (scope, iElement, iAttrs, parentLayout) {

        var animationFrameRequested, lastX;
        var _cache = {};

        // Use relative mouse position
        var isUsingColumnFlow = parentLayout.opts.flow === 'column';
        var mouseProperty = ( isUsingColumnFlow ? 'clientX' : 'clientY');

        // Use bounding box / css property names
        var flowProperty = ( isUsingColumnFlow ? 'left' : 'top');
        var oppositeFlowProperty = ( isUsingColumnFlow ? 'right' : 'bottom');
        var sizeProperty = ( isUsingColumnFlow ? 'width' : 'height');

        // Use bounding box properties
        var barElm = iElement[0];
        var previousElement = barElm.previousElementSibling;
        var nextElement = barElm.nextElementSibling;

        // Stores the layout values for some seconds to not recalculate it during the animation
        function _cached_layout_values() {
          // layout bounding box
          var layout_bb = parentLayout.element[0].getBoundingClientRect();

          // split bar bounding box
          var bar_bb = barElm.getBoundingClientRect();

          _cache.time = +new Date();
          _cache.barSize = bar_bb[sizeProperty];
          _cache.layoutSize = layout_bb[sizeProperty];
          _cache.layoutOrigine = layout_bb[flowProperty];
          _cache.previousElement = previousElement.getBoundingClientRect();
          _cache.previousElement.min = parseInt(previousElement.getAttribute('min-size'),10);
          _cache.previousElement.max = parseInt(previousElement.getAttribute('max-size'),10);
          _cache.nextElement = nextElement.getBoundingClientRect();
          _cache.nextElement.min = parseInt(nextElement.getAttribute('min-size'),10);
          _cache.nextElement.max = parseInt(nextElement.getAttribute('max-size'),10);

          var dividerSize = isNaN(bar_bb[sizeProperty]) ? bar_bb[sizeProperty] : bar_bb[sizeProperty] + 'px';
          var _dividerSize = parseInt(dividerSize, 10);
          var _dividerType = dividerSize.match(/\d+\s*(px|%)\s*$/i);
          if(!isNaN(_dividerSize) && _dividerType) {
            if(_dividerType.length > 1 && 'px' === _dividerType[1]) {
              _dividerSize = + (_dividerSize / _cache.layoutSize * 100).toFixed(5);
            }
          }

          if(_cache.previousElement.min) {
            var minType = previousElement.getAttribute('min-size').match(/\d+\s*(px|%)\s*$/i);
            if(!isNaN(_cache.previousElement.min) && minType) {
              if(minType.length > 1 && 'px' === minType[1]) {
                 _cache.previousElement.min = + (_cache.previousElement.min / _cache.layoutSize * 100).toFixed(5);
              }
            }
            // ensure the min size isn't smaller than the divider size
            if(_dividerSize && _cache.previousElement.min < _dividerSize) _cache.previousElement.min = _dividerSize;
          } else {
            _cache.previousElement.min = _dividerSize;
          }

          if( _cache.previousElement.max) {
            var maxType = previousElement.getAttribute('max-size').match(/\d+\s*(px|%)\s*$/i);
            if(!isNaN( _cache.previousElement.max) && maxType) {
              if(maxType.length > 1 && 'px' === maxType[1]) {
                  _cache.previousElement.max = + ( _cache.previousElement.max / _cache.layoutSize * 100).toFixed(5);
              }
            }
          }

          if(_cache.nextElement.min) {
            var _minType = nextElement.getAttribute('min-size').match(/\d+\s*(px|%)\s*$/i);
            if(!isNaN(_cache.nextElement.min) && _minType) {
              if(_minType.length > 1 && 'px' === _minType[1]) {
                 _cache.nextElement.min = + (_cache.nextElement.min / _cache.layoutSize * 100).toFixed(5);
              }
            }
            // ensure the min size isn't smaller than the divider size
            if(_dividerSize && _cache.nextElement.min < _dividerSize) _cache.nextElement.min = _dividerSize;
          } else {
            _cache.nextElement.min = _dividerSize;
          }

          if(_cache.nextElement.max) {
            var _maxType = nextElement.getAttribute('max-size').match(/\d+\s*(px|%)\s*$/i);
            if(!isNaN(_cache.nextElement.max) && _maxType) {
              if(_maxType.length > 1 && 'px' === _maxType[1]) {
                 _cache.nextElement.max = + (_cache.nextElement.max / _cache.layoutSize * 100).toFixed(5);
              }
            }
          }
        }

        function _draw() {
          var the_pos = (lastX - _cache.layoutOrigine) / _cache.layoutSize * 100;

          // Keep the bar in the window (no left/top 100%)
          the_pos = Math.min(the_pos, 100 - _cache.barSize / _cache.layoutSize * 100);

          // Keep the bar from going past the previous elements max/min sizes
          var previousElementValue = _cache.previousElement[flowProperty] / _cache.layoutSize * 100;
          if(!isNaN(_cache.previousElement.min) && the_pos < (previousElementValue + _cache.previousElement.min)) the_pos = (previousElementValue + _cache.previousElement.min);
          if(!isNaN(_cache.previousElement.max) && the_pos > (previousElementValue + _cache.previousElement.max)) the_pos = (previousElementValue + _cache.previousElement.max);

          // Keep the bar from going past the next elements max/min sizes
          var nextElementValue = (_cache.nextElement[flowProperty] + _cache.nextElement[sizeProperty]) / _cache.layoutSize * 100;
          var nextElementMinValue = nextElementValue - _cache.nextElement.min;
          var nextElementMaxValue = nextElementValue - _cache.nextElement.max;
          if(!isNaN(_cache.nextElement.max) && the_pos < nextElementMaxValue) the_pos = nextElementMaxValue;
          if(!isNaN(_cache.nextElement.min) && the_pos > nextElementMinValue) the_pos = nextElementMinValue;

          // The the bar in the near beetween the near by area
          the_pos = Math.max(the_pos, parseInt(barElm.previousElementSibling.style[flowProperty], 10));
          if (barElm.nextElementSibling.nextElementSibling) {
            the_pos = Math.min(the_pos, parseInt(barElm.nextElementSibling.nextElementSibling.style[flowProperty], 10));
          }

          // change the position of the bar and the next area
          barElm.style[flowProperty] = barElm.nextElementSibling.style[flowProperty] = the_pos + '%';
          // change the size of the previous area
          barElm.previousElementSibling.style[oppositeFlowProperty] = (100 - the_pos) + '%';

          // Enable a new animation frame
          animationFrameRequested = null;
        }

        function _resize(mouseEvent) {
          // Store the mouse position for later

          // FIX :
          // - with touch events, when using jQuery, the mouseEvent is in fact a jQueryEvent. So we use originalEvent here.
          // - real touch events comes in the _targetTouches_ array
          lastX = mouseEvent[mouseProperty] ||
            (mouseEvent.originalEvent && mouseEvent.originalEvent[mouseProperty]) ||
            (mouseEvent.targetTouches ? mouseEvent.targetTouches[0][mouseProperty] : 0);

          // Cancel previous rAF call
          if (animationFrameRequested) {
            window.cancelAnimationFrame(animationFrameRequested);
          }

          if (!_cache.time || +new Date() > _cache.time + 1000) { // after ~60 frames
            _cached_layout_values();
          }

          // Animate the page outside the event
          animationFrameRequested = window.requestAnimationFrame(_draw);
        }

        // Bind the click on the bar then you can move it all over the page.
        iElement.on('mousedown touchstart', function (e) {
          e.preventDefault();
          e.stopPropagation();
          htmlElement.on('mousemove touchmove', _resize);
          return false;
        });
        htmlElement.on('mouseup touchend', function () {
          htmlElement.off('mousemove touchmove');
        });
      }
    };
  });
<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const path = require('path');

const APP_DECLARATIONS = `import Ember from 'ember';

declare global {
  interface Array<T> extends Ember.ArrayPrototypeExtensions<T> {}
  // interface Function extends Ember.FunctionPrototypeExtensions {}
}

export {};`;

/**
 * @param {string} projectName
 * @param {'classic' | 'pods'} layout
 */
function buildTemplateDeclarations(projectName, layout) {
  const comment = '// Types for compiled templates';
  const moduleBody = `
  import { TemplateFactory } from 'htmlbars-inline-precompile';
  const tmpl: TemplateFactory;
  export default tmpl;
`;
  switch (layout) {
    case 'classic':
      return `${comment}
declare module '${projectName}/templates/*' {${moduleBody}}`;
    case 'pods':
      return `${comment}
declare module '${projectName}/*/template' {${moduleBody}}`;
    default:
      throw new Error(`Unexpected project layout type: "${layout}"`);
  }
}

const { ADDON_NAME } = require('../../addon');

module.exports = {
  APP_DECLARATIONS,

  description: 'Initialize files needed for typescript compilation',

  install(options) {
    if (options.project.isEmberCLIAddon()) {
      options.dummy = true;
    }

    return this._super.install.apply(this, arguments);
  },

  locals() {
    let inRepoAddons = (this.project.pkg['ember-addon'] || {}).paths || [];
    let hasMirage = 'ember-cli-mirage' in (this.project.pkg.devDependencies || {});
    let isAddon = this.project.isEmberCLIAddon();
    let includes = ['app', isAddon && 'addon'].filter(Boolean);
    const isPods = this.pod;

    includes = includes.concat(['tests', 'types']).concat(inRepoAddons);

    if (isAddon) {
      includes.push('test-support', 'addon-test-support');
    }
    // Mirage is already covered for addons because it's under `tests/`
    if (hasMirage && !isAddon) {
      includes.push('mirage');
    }

    return {
      includes: JSON.stringify(
        includes.map((include) => `${include}/**/*`),
        null,
        2
      ).replace(/\n/g, '\n  '),
      pathsFor: (dasherizedName) => {
        // We need to wait to use this module until `ember-cli-typescript-blueprints` has been installed
        let updatePathsForAddon = require('ember-cli-typescript-blueprints/lib/utilities/update-paths-for-addon');
        let appName = isAddon ? 'dummy' : dasherizedName;
        let paths = {
          [`${appName}/tests/*`]: ['tests/*'],
        };

        if (hasMirage) {
          paths[`${appName}/mirage/*`] = [`${isAddon ? 'tests/dummy/' : ''}mirage/*`];
        }

        if (isAddon) {
          paths[`${appName}/*`] = ['tests/dummy/app/*', 'app/*'];
        } else {
          paths[`${appName}/*`] = ['app/*'];
        }

        if (isAddon) {
          paths[dasherizedName] = ['addon'];
          paths[`${dasherizedName}/*`] = ['addon/*'];
          paths[`${dasherizedName}/test-support`] = ['addon-test-support'];
          paths[`${dasherizedName}/test-support/*`] = ['addon-test-support/*'];
        }

        for (let addon of inRepoAddons) {
          updatePathsForAddon(paths, path.basename(addon), appName);
        }

        paths['*'] = ['types/*'];

        return JSON.stringify(paths, null, 2).replace(/\n/g, '\n    ');
      },
      indexDeclarations: (dasherizedName) => {
        const isDummyApp = dasherizedName === 'dummy';
        const useAppDeclarations = !(isAddon || isDummyApp);
        return useAppDeclarations ? APP_DECLARATIONS : '';
      },
      globalDeclarations: (dasherizedName) => {
        /** @type {'classic' | 'pods'} */
        let projectLayout;
        if (isPods) projectLayout = 'pods';
        else projectLayout = 'classic';
        return buildTemplateDeclarations(dasherizedName, projectLayout);
      },
    };
  },

  fileMapTokens(/*options*/) {
    // Return custom tokens to be replaced in your files.
    return {
      __app_name__(options) {
        return options.inAddon ? 'dummy' : options.dasherizedModuleName;
      },

      __config_root__(options) {
        return options.inAddon ? 'tests/dummy/app' : 'app';
      },
    };
  },

  normalizeEntityName() {
    // Entity name is optional right now, creating this hook avoids an error.
  },

  beforeInstall() {
    if (this.project.isEmberCLIAddon()) {
      this._transformAddonPackage();
    }

    let packages = [
      { name: 'ember-cli-typescript-blueprints', target: 'latest' },
      { name: 'typescript', target: 'latest' },
      { name: '@types/ember', target: 'latest' },
      { name: '@types/ember__test-helpers', target: 'latest' },
      { name: '@types/ember-resolver', target: 'latest' },
    ];

    if (this._has('ember-data')) {
      packages.push({ name: '@types/ember-data', target: 'latest' });
    }

    if (this._has('ember-cli-qunit') || this._has('ember-qunit')) {
      packages = packages.concat([
        { name: '@types/ember-qunit', target: 'latest' },
        { name: '@types/qunit', target: 'latest' },
      ]);
    }

    if (this._has('ember-cli-mocha') || this._has('ember-mocha')) {
      packages = packages.concat([
        { name: '@types/ember-mocha', target: 'latest' },
        { name: '@types/mocha', target: 'latest' },
      ]);
    }

    return this.addPackagesToProject(packages);
  },

  filesPath() {
    return `${__dirname}/../../../blueprint-files/ember-cli-typescript`;
  },

  files() {
    let files = this._super.files.apply(this, arguments);

    if (!this._has('ember-data')) {
      files = files.filter((file) => file !== 'types/ember-data/types/registries/model.d.ts');
    }

    return files;
  },

  _transformAddonPackage() {
    const pkgPath = `${this.project.root}/package.json`;

    let pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));

    // As of https://github.com/yarnpkg/yarn/pull/5712 yarn runs `prepack` and `postpack` when publishing
    this._addScript(pkg.scripts, 'prepack', 'ember ts:precompile');
    this._addScript(pkg.scripts, 'postpack', 'ember ts:clean');

    // avoid being placed in devDependencies
    if (pkg.devDependencies[ADDON_NAME]) {
      pkg.dependencies[ADDON_NAME] = pkg.devDependencies[ADDON_NAME];
      delete pkg.devDependencies[ADDON_NAME];
    }

    fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
  },

  _addScript(scripts, type, script) {
    if (scripts[type] && scripts[type] !== script) {
      this.ui.writeWarnLine(
        `Found a pre-existing \`${type}\` script in your package.json. ` +
          `By default, ember-cli-typescript expects to run \`${script}\` in this hook.`
      );
      return;
    }

    scripts[type] = script;
  },

  _has(pkg) {
    if (this.project) {
      return pkg in this.project.dependencies();
    }
  },
};
<commit_msg>feat: install @types/ember packages separately via blueprint<commit_after>'use strict';

const fs = require('fs');
const path = require('path');

const APP_DECLARATIONS = `import Ember from 'ember';

declare global {
  interface Array<T> extends Ember.ArrayPrototypeExtensions<T> {}
  // interface Function extends Ember.FunctionPrototypeExtensions {}
}

export {};`;

/**
 * @param {string} projectName
 * @param {'classic' | 'pods'} layout
 */
function buildTemplateDeclarations(projectName, layout) {
  const comment = '// Types for compiled templates';
  const moduleBody = `
  import { TemplateFactory } from 'htmlbars-inline-precompile';
  const tmpl: TemplateFactory;
  export default tmpl;
`;
  switch (layout) {
    case 'classic':
      return `${comment}
declare module '${projectName}/templates/*' {${moduleBody}}`;
    case 'pods':
      return `${comment}
declare module '${projectName}/*/template' {${moduleBody}}`;
    default:
      throw new Error(`Unexpected project layout type: "${layout}"`);
  }
}

const { ADDON_NAME } = require('../../addon');

module.exports = {
  APP_DECLARATIONS,

  description: 'Initialize files needed for typescript compilation',

  install(options) {
    if (options.project.isEmberCLIAddon()) {
      options.dummy = true;
    }

    return this._super.install.apply(this, arguments);
  },

  locals() {
    let inRepoAddons = (this.project.pkg['ember-addon'] || {}).paths || [];
    let hasMirage = 'ember-cli-mirage' in (this.project.pkg.devDependencies || {});
    let isAddon = this.project.isEmberCLIAddon();
    let includes = ['app', isAddon && 'addon'].filter(Boolean);
    const isPods = this.pod;

    includes = includes.concat(['tests', 'types']).concat(inRepoAddons);

    if (isAddon) {
      includes.push('test-support', 'addon-test-support');
    }
    // Mirage is already covered for addons because it's under `tests/`
    if (hasMirage && !isAddon) {
      includes.push('mirage');
    }

    return {
      includes: JSON.stringify(
        includes.map((include) => `${include}/**/*`),
        null,
        2
      ).replace(/\n/g, '\n  '),
      pathsFor: (dasherizedName) => {
        // We need to wait to use this module until `ember-cli-typescript-blueprints` has been installed
        let updatePathsForAddon = require('ember-cli-typescript-blueprints/lib/utilities/update-paths-for-addon');
        let appName = isAddon ? 'dummy' : dasherizedName;
        let paths = {
          [`${appName}/tests/*`]: ['tests/*'],
        };

        if (hasMirage) {
          paths[`${appName}/mirage/*`] = [`${isAddon ? 'tests/dummy/' : ''}mirage/*`];
        }

        if (isAddon) {
          paths[`${appName}/*`] = ['tests/dummy/app/*', 'app/*'];
        } else {
          paths[`${appName}/*`] = ['app/*'];
        }

        if (isAddon) {
          paths[dasherizedName] = ['addon'];
          paths[`${dasherizedName}/*`] = ['addon/*'];
          paths[`${dasherizedName}/test-support`] = ['addon-test-support'];
          paths[`${dasherizedName}/test-support/*`] = ['addon-test-support/*'];
        }

        for (let addon of inRepoAddons) {
          updatePathsForAddon(paths, path.basename(addon), appName);
        }

        paths['*'] = ['types/*'];

        return JSON.stringify(paths, null, 2).replace(/\n/g, '\n    ');
      },
      indexDeclarations: (dasherizedName) => {
        const isDummyApp = dasherizedName === 'dummy';
        const useAppDeclarations = !(isAddon || isDummyApp);
        return useAppDeclarations ? APP_DECLARATIONS : '';
      },
      globalDeclarations: (dasherizedName) => {
        /** @type {'classic' | 'pods'} */
        let projectLayout;
        if (isPods) projectLayout = 'pods';
        else projectLayout = 'classic';
        return buildTemplateDeclarations(dasherizedName, projectLayout);
      },
    };
  },

  fileMapTokens(/*options*/) {
    // Return custom tokens to be replaced in your files.
    return {
      __app_name__(options) {
        return options.inAddon ? 'dummy' : options.dasherizedModuleName;
      },

      __config_root__(options) {
        return options.inAddon ? 'tests/dummy/app' : 'app';
      },
    };
  },

  normalizeEntityName() {
    // Entity name is optional right now, creating this hook avoids an error.
  },

  beforeInstall() {
    if (this.project.isEmberCLIAddon()) {
      this._transformAddonPackage();
    }

    let packages = [
      'typescript',
      'ember-cli-typescript-blueprints',
      '@types/ember-resolver',
      '@types/ember__test-helpers',
      '@types/ember__object',
      '@types/ember__service',
      '@types/ember__controller',
      '@types/ember__string',
      '@types/ember__template',
      '@types/ember__polyfills',
      '@types/ember__utils',
      '@types/ember__runloop',
      '@types/ember__debug',
      '@types/ember__engine',
      '@types/ember__application',
      '@types/ember__test',
      '@types/ember__array',
      '@types/ember__error',
      '@types/ember__component',
      '@types/ember__routing',
      '@types/rsvp',
      '@types/htmlbars-inline-precompile',
    ];

    if (this._has('@ember/jquery')) {
      packages.push('@types/jquery');
    }

    if (this._has('ember-data')) {
      packages.push('@types/ember-data');
    }

    if (this._has('ember-cli-qunit') || this._has('ember-qunit')) {
      packages.push('@types/ember-qunit');
      packages.push('@types/qunit');
    }

    if (this._has('ember-cli-mocha') || this._has('ember-mocha')) {
      packages.push('@types/ember-mocha');
      packages.push('@types/mocha');
    }

    return this.addPackagesToProject(
      packages.map((name) => {
        return { name, target: 'latest' };
      })
    );
  },

  filesPath() {
    return `${__dirname}/../../../blueprint-files/ember-cli-typescript`;
  },

  files() {
    let files = this._super.files.apply(this, arguments);

    if (!this._has('ember-data')) {
      files = files.filter((file) => file !== 'types/ember-data/types/registries/model.d.ts');
    }

    return files;
  },

  _transformAddonPackage() {
    const pkgPath = `${this.project.root}/package.json`;

    let pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));

    // As of https://github.com/yarnpkg/yarn/pull/5712 yarn runs `prepack` and `postpack` when publishing
    this._addScript(pkg.scripts, 'prepack', 'ember ts:precompile');
    this._addScript(pkg.scripts, 'postpack', 'ember ts:clean');

    // avoid being placed in devDependencies
    if (pkg.devDependencies[ADDON_NAME]) {
      pkg.dependencies[ADDON_NAME] = pkg.devDependencies[ADDON_NAME];
      delete pkg.devDependencies[ADDON_NAME];
    }

    fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
  },

  _addScript(scripts, type, script) {
    if (scripts[type] && scripts[type] !== script) {
      this.ui.writeWarnLine(
        `Found a pre-existing \`${type}\` script in your package.json. ` +
          `By default, ember-cli-typescript expects to run \`${script}\` in this hook.`
      );
      return;
    }

    scripts[type] = script;
  },

  _has(pkg) {
    if (this.project) {
      return pkg in this.project.dependencies();
    }
  },
};
<|endoftext|>


<commit_before>/**
 * @module DL
 * @class DL.Channel.WEBSOCKETS
 *
 * @param {Client} client
 * @param {String} namespace
 * @param {Object} options optional
 * @constructor
 *
 * @example Connecting through websockets.
 *
 *     var channel = client.channel('messages', { transport: "websockets" });
 *
 * @example Force socket server endpoint.
 *
 *     var channel = client.channel('messages', {
 *       transport: "websockets",
 *       url: "ws://localhost:8080"
 *     });
 */
DL.Channel.WEBSOCKETS = function(client, collection, options) {
  var that = this;

  this.client = client;
  this.collection = collection;
  this.client_id = null;

  if (!options.url) {
    var scheme = window.location.protocol === 'https:' ? 'wss://' : 'ws://',
        url = client.url.replace(/(?:https?:)?\/\//, scheme)

    if (url.match(/index\.php/)) {
      url = url.replace("index.php", "ws/");
    } else {
      url += "ws/";
    }

    options.url = url;
  }

  options.url += this.collection.name + "?X-App-Id=" + this.client.appId + "&X-App-Key=" + this.client.key;
  var auth_token = this.client.auth.getToken();
  if (auth_token) {
    options.url += '&X-Auth-Token=' + auth_token;
  }

  // WAMP message debugging
  ab.debug(options.debug === true, options.verbose === true);

  ab.connect(options.url, function(session) {
    that.ws = session;
    that.client_id = session.sessionid();
    that.trigger('connected');
  });
};

// Inherits from Events

DL.Channel.WEBSOCKETS.prototype = new DL.Events();
DL.Channel.WEBSOCKETS.prototype.constructor = DL.Channel.WEBSOCKETS;

/**
 * Subscribe to channel. Publishes a 'connected' message on the first time.
 * @method subscribe
 * @param {String} event (optional)
 * @param {Function} callback
 * @return {DL.Channel}
 *
 * @example Registering for a single custom event
 *
 *     channel.subscribe('some-event', function(data) {
 *       console.log("Custom event triggered: ", data);
 *     })
 *
 * @example Registering for client connected/disconnected events
 *
 *     channel.subscribe('connected', function(data) {
 *       console.log("New client connected: ", data.client_id);
 *     });
 *     channel.subscribe('disconnected', function(data) {
 *       console.log("Client disconnected: ", data.client_id);
 *     });
 *
 */
DL.Channel.WEBSOCKETS.prototype.subscribe = function(event, callback) {
  this.ws.subscribe(this.collection.name + '.' + event, function(topic, data) {
    callback(data);
  });
  return this;
};

/**
 * Is EventSource listenning to messages?
 * @method isConnected
 * @return {Boolean}
 */
DL.Channel.WEBSOCKETS.prototype.isConnected = function() {
  return this.ws && this.ws._websocket_connected;
};

/**
 * Unsubscribe to a event listener
 * @method unsubscribe
 * @param {String} event
 * @return {DL.Channel}
 */
DL.Channel.WEBSOCKETS.prototype.unsubscribe = function(event) {
  this.ws.unsubscribe(this.collection.name + '.' + event);
  return this;
};

/**
 * Publish event message
 * @method publish
 * @param {String} event
 * @param {Object} message
 * @param {Object} options 'exclude' and 'elegible' are optional options.
 * @return {DL.Channel}
 */
DL.Channel.WEBSOCKETS.prototype.publish = function(event, message, options) {
  var exclude = [], eligible = [];

  if (typeof(options)==="undefined") {
    options = {};
  }

  if (options.exclude && options.exclude instanceof Array) {
    exclude = options.exclude;
  }

  if (options.eligible && options.eligible instanceof Array) {
    eligible = options.eligible;
  }

  this.ws.publish(this.collection.name + '.' + event, message, exclude, eligible);
  return this;
};

/**
 * Disconnect from channel, publishing a 'disconnected' message.
 * @method disconnect
 * @return {DL.Channel} this
 */
DL.Channel.WEBSOCKETS.prototype.disconnect = function() {
  this.ws.close();
  return this;
};

/**
 * @method call
 * @param {String} procedure
 * @return {Promise}
 */
DL.Channel.WEBSOCKETS.prototype.call = function(procedure, callbacks) {
  this.ws.call(procedure, callbacks);
  return this;
};
DL.Channel.WEBSOCKETS.prototype.connect = function() {
  this.ws.connect();
  return this;
};
<commit_msg>only unsubscribe from already-subscribed websockets events<commit_after>/**
 * @module DL
 * @class DL.Channel.WEBSOCKETS
 *
 * @param {Client} client
 * @param {String} namespace
 * @param {Object} options optional
 * @constructor
 *
 * @example Connecting through websockets.
 *
 *     var channel = client.channel('messages', { transport: "websockets" });
 *
 * @example Force socket server endpoint.
 *
 *     var channel = client.channel('messages', {
 *       transport: "websockets",
 *       url: "ws://localhost:8080"
 *     });
 */
DL.Channel.WEBSOCKETS = function(client, collection, options) {
  var that = this;

  this.client = client;
  this.collection = collection;
  this.client_id = null;

  if (!options.url) {
    var scheme = window.location.protocol === 'https:' ? 'wss://' : 'ws://',
        url = client.url.replace(/(?:https?:)?\/\//, scheme)

    if (url.match(/index\.php/)) {
      url = url.replace("index.php", "ws/");
    } else {
      url += "ws/";
    }

    options.url = url;
  }

  options.url += this.collection.name + "?X-App-Id=" + this.client.appId + "&X-App-Key=" + this.client.key;
  var auth_token = this.client.auth.getToken();
  if (auth_token) {
    options.url += '&X-Auth-Token=' + auth_token;
  }

  // WAMP message debugging
  ab.debug(options.debug === true, options.verbose === true);

  ab.connect(options.url, function(session) {
    that.ws = session;
    that.client_id = session.sessionid();
    that.trigger('connected');
  });
};

// Inherits from Events

DL.Channel.WEBSOCKETS.prototype = new DL.Events();
DL.Channel.WEBSOCKETS.prototype.constructor = DL.Channel.WEBSOCKETS;

/**
 * Subscribe to channel. Publishes a 'connected' message on the first time.
 * @method subscribe
 * @param {String} event (optional)
 * @param {Function} callback
 * @return {DL.Channel}
 *
 * @example Registering for a single custom event
 *
 *     channel.subscribe('some-event', function(data) {
 *       console.log("Custom event triggered: ", data);
 *     })
 *
 * @example Registering for client connected/disconnected events
 *
 *     channel.subscribe('connected', function(data) {
 *       console.log("New client connected: ", data.client_id);
 *     });
 *     channel.subscribe('disconnected', function(data) {
 *       console.log("Client disconnected: ", data.client_id);
 *     });
 *
 */
DL.Channel.WEBSOCKETS.prototype.subscribe = function(event, callback) {
  this.ws.subscribe(this.collection.name + '.' + event, function(topic, data) {
    callback(data);
  });
  return this;
};

/**
 * Is EventSource listenning to messages?
 * @method isConnected
 * @return {Boolean}
 */
DL.Channel.WEBSOCKETS.prototype.isConnected = function() {
  return this.ws && this.ws._websocket_connected;
};

/**
 * Unsubscribe to a event listener
 * @method unsubscribe
 * @param {String} event
 * @return {DL.Channel}
 */
DL.Channel.WEBSOCKETS.prototype.unsubscribe = function(event) {
  if (this.ws._subscriptions[this.collection.name + '.' + event]) {
    this.ws.unsubscribe(this.collection.name + '.' + event);
  }
  return this;
};

/**
 * Publish event message
 * @method publish
 * @param {String} event
 * @param {Object} message
 * @param {Object} options 'exclude' and 'elegible' are optional options.
 * @return {DL.Channel}
 */
DL.Channel.WEBSOCKETS.prototype.publish = function(event, message, options) {
  var exclude = [], eligible = [];

  if (typeof(options)==="undefined") {
    options = {};
  }

  if (options.exclude && options.exclude instanceof Array) {
    exclude = options.exclude;
  }

  if (options.eligible && options.eligible instanceof Array) {
    eligible = options.eligible;
  }

  this.ws.publish(this.collection.name + '.' + event, message, exclude, eligible);
  return this;
};

/**
 * Disconnect from channel, publishing a 'disconnected' message.
 * @method disconnect
 * @return {DL.Channel} this
 */
DL.Channel.WEBSOCKETS.prototype.disconnect = function() {
  this.ws.close();
  return this;
};

/**
 * @method call
 * @param {String} procedure
 * @return {Promise}
 */
DL.Channel.WEBSOCKETS.prototype.call = function(procedure, callbacks) {
  this.ws.call(procedure, callbacks);
  return this;
};
DL.Channel.WEBSOCKETS.prototype.connect = function() {
  this.ws.connect();
  return this;
};
<|endoftext|>


<commit_before>import { observable } from 'mobx';
import Map from 'shared/model/map';
import TaskPlan from './plan';

export
class PastTaskPlans extends Map {

  @observable course;

  constructor(attrs) {
    super();
    this.course = attrs.course;
  }

  // called from api
  fetch() {
    if (!this.course.isCloned) { return 'ABORT'; }
    return { id: this.course.cloned_from_id };
  }
  onLoaded({ data: { items } }) {
    items.forEach(plan => {
      const tp = this.get(plan.id);
      tp ? tp.update(plan) : this.set(plan.id, new TaskPlan(plan));
    });
  }

}
<commit_msg>set course on past task plan<commit_after>import { observable } from 'mobx';
import Map from 'shared/model/map';
import TaskPlan from './plan';

export
class PastTaskPlans extends Map {

  @observable course;

  constructor(attrs) {
    super();
    this.course = attrs.course;
  }

  // called from api
  fetch() {
    if (!this.course.isCloned) { return 'ABORT'; }
    return { id: this.course.cloned_from_id };
  }
  onLoaded({ data: { items } }) {
    items.forEach(plan => {
      const tp = this.get(plan.id);
      tp ? tp.update(plan) : this.set(plan.id, new TaskPlan({ ...plan, course: this.course }));
    });
  }

}
<|endoftext|>


<commit_before>/*jlint node: true */
/*global require, console, module, process, __dirname */
/*
 * application.js
 *
 * Copyright (C) 2014 by James Jenner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

var path = require('path');
var opt = require('opt').create();
var fs = require('fs');

var MeltingPot = require('meltingpot');

var PanelHandler = require('./lib/server/panelHandler.js');
var DataSourceHandler = require('./lib/server/dataSourceHandler.js');
var WidgetHandler = require('./lib/server/widgetHandler.js');
var DataSourceManager = require('./lib/server/dataSourceManager.js');
var LocalPreferenceHandler = require('./lib/server/localPreferenceHandler.js');
var PreferenceHandler = require('./lib/server/preferenceHandler.js');

//var VEHICLES_FILE = 'vehicles.json';

//// setup log4js component with a logger
//log4js.configure({
//  appenders: [
//    {
//      type: "file",
//      filename: "meltingpot.log",
//      category: ['videre', 'file']
// },
//    {
//      type: "file",
//      filename: "meltingpot_clientcomms_in.log",
//      category: ['clientIn', 'file']
// },
//    {
//      type: "file",
//      filename: "meltingpot_clientcomms_out.log",
//      category: ['clientOut', 'file']
// }
// /*
//	{
//	    type: "console"
//	}
//	*/
//    ],
//  replaceConsole: false
//});

// load the vehicle configs from the file
//var vehicles = loadVehicles(VEHICLES_FILE);

/* options handling */
// TODO: look at replacing or extending opt, would like error on invalid arg, exclusivity of args, better formatting of help, etc

var config = {
  debug: false,
  debugLevel: 0,
  clientAddress: 'localhost',
  port: 9007,
  securePort: 9008,
  uuidV1: false,
  communicationType: MeltingPot.Message.COMMS_TYPE_UNSECURE_ONLY,
  sslKey: 'keys' + path.sep + 'privatekey.pem',
  sslCert: 'keys' + path.sep + 'certificate.pem',
  autoDiscover: false,
  dataDirectory: '.' + path.sep + 'data' + path.sep,
};

var search_paths = [
  "meltingpot.conf",
  path.join(process.env.HOME, ".meltingpot-rc"),
  "/usr/local/etc/meltingpot.conf",
  "/usr/etc/meltingpot.conf",
  "/etc/meltingpot.conf"
];

var listingProtocols = false;

opt.configSync(config, search_paths);

opt.optionHelp("USAGE node " + path.basename(process.argv[1]),
  "SYNOPSIS: The application is the back end for the meltingpot front end .\n\n\t\t node " + path.basename(process.argv[1]) + " --help",
  "OPTIONS:",
  "Copyright (c) 2014 James G Jenner, all rights reserved\n" +
  " Released under MIT License\n" +
  " See: http://opensource.org/licenses/MIT\n");

opt.option(["-d", "--debug"], function (param) {
  config.debug = true;
  if (Number(param).toFixed(0) > 0) {
    config.debugLevel = Number(param).toFixed(0);
    opt.consume(param);
  } else {
    config.debugLevel = 0;
  }
}, "Generate debugging messages, level is optional. 0 - informational, 1 - detailed");

opt.option(["-so", "--secure-only"], function (param) {
  config.communicationType = MeltingPot.Message.COMMS_TYPE_SECURE_ONLY;
}, "Set communications to only accept secure connections");

opt.option(["-uo", "--unsecure-only"], function (param) {
  config.communicationType = MeltingPot.Message.COMMS_TYPE_UNSECURE_ONLY;
}, "Set communications to only accept unsecure connections, this is the default type");

opt.option(["-m", "--mixed"], function (param) {
  config.communicationType = MeltingPot.Message.COMMS_TYPE_MIXED;
}, "Set communications to accept secure and unsecure connections");

opt.option(["-u1", "--uuid-v1"], function (param) {
  config.uuidV1 = true;
}, "Set uuid generation for session keys to uuid v1, default is v4");

opt.option(["-ad", "--auto-discover"], function (param) {
  config.autoDiscover = true;
}, "comms auto discovery");

opt.option(["-dd", "--data-directory"], function (param) {
  if (param !== undefined && param.trim()) {
    config.dataDirectory = param.trim();
    if(config.dataDirectory.charAt(config.dataDirectory.length - 1) !== path.sep) {
      config.dataDirectory += path.sep;
    }
    opt.consume(param);
  } else {
    opt.usage("The directory must be provided with the option for data directory.", 1);
  }
}, "Set the directory for data files");

// server comms settings
opt.option(["-p", "--port"], function (param) {
  if (Number(param).toFixed(0) > 0) {
    config.port = Number(param).toFixed(0);
    opt.consume(param);
  } else {
    opt.usage("Port must be a number greater then 0.", 1);
  }
}, "Set the port parameter for remote connections");

opt.option(["-s", "--ssl-port"], function (param) {
  if (Number(param).toFixed(0) > 0) {
    config.securePort = Number(param).toFixed(0);
    opt.consume(param);
  } else {
    opt.usage("SLL Port must be a number greater then 0.", 1);
  }
}, "Set the ssl port parameter for remote secure connections");

opt.option(["-sk", "--ssl-key"], function (param) {
  if (param !== undefined && param.trim()) {
    config.sslKey = param.trim();
    opt.consume(param);
  }
}, "Set the ssl private key file parameter for remote secure connections");

opt.option(["-sc", "--ssl-cert"], function (param) {
  if (param !== undefined && param.trim()) {
    config.sslCert = param.trim();
    opt.consume(param);
  }
}, "Set the ssl certificate parameter for remote secure connections");

opt.option(["-g", "--generate"], function (param) {
  var config_filename = "";

  if (param !== undefined && param.trim() !== "") {
    config_filename = param.trim();
  }
  opt.consume(param);

  if (config_filename === "") {
    console.log(JSON.stringify(config, null, '\t'));
    process.exit(0);
  } else {
    fs.writeFile(config_filename, JSON.stringify(config, null, '\t'), function (err) {
      if (err) {
        console.error("ERROR: can't write", config_filename);
        process.exit(1);
      }
      console.log("Wrote configuration to", config_filename);
      process.exit(0);
    });
  }

}, "Generate a configuration file");

opt.option(["-h", "--help"], function () {
  opt.usage();
}, "This help document.");

opt.optionWith(process.argv);

// load existing definitions

// setup the client communications
var clientComms = new MeltingPot.Comms({
  port: config.port,
  securePort: config.securePort,
  uuidV1: config.uuidV1,
  communicationType: config.communicationType,
  sslKey: config.sslKey,
  sslCert: config.sslCert,
  debug: config.debug,
  debugLevel: config.debugLevel,
  messageHandlers: [
    PanelHandler.messageHandler,
    PreferenceHandler.messageHandler,
    LocalPreferenceHandler.messageHandler,
    DataSourceHandler.messageHandler,
    WidgetHandler.messageHandler,
    BannerHandler.messageHandler,
  ]
});

// setup data directory
if(!validateDataDirectory(config.dataDirectory)) {
 return -1;
}

var localPreferenceHandler = new LocalPreferenceHandler({dataDirectory: config.dataDirectory});
localPreferenceHandler.setupCommsListeners(clientComms);

var preferenceHandler = new PreferenceHandler({dataDirectory: config.dataDirectory, localPreferenceHandler: localPreferenceHandler});
preferenceHandler.setupCommsListeners(clientComms);

var panelHandler = new PanelHandler({dataDirectory: config.dataDirectory, preferenceHandler: preferenceHandler});
panelHandler.setupCommsListeners(clientComms);

var widgetHandler = new WidgetHandler({dataDirectory: config.dataDirectory});
widgetHandler.setupCommsListeners(clientComms);

var bannerHandler = new BannerHandler({dataDirectory: config.dataDirectory});
bannerHandler.setupCommsListeners(clientComms);

var dataSourceHandler = new DataSourceHandler({dataDirectory: config.dataDirectory});
dataSourceHandler.setupCommsListeners(clientComms);

var dataSourceManager = new DataSourceManager({clientComms: clientComms, dataSourceHandler: dataSourceHandler, widgetHandler: widgetHandler});
dataSourceManager.setupCommsListeners(clientComms);

// start up the server for clients
if (config.debug) {
  console.log((new Date()) + " application.js: starting client server");
}

dataSourceManager.start();
clientComms.startClientServer();

/*
 * returns false if the directory cannot be created
 */
function validateDataDirectory(dataDirectory) {
  var stats = null;

  // check if file exists
  try {
    stats = fs.statSync(dataDirectory);
  } catch (e) {
  }

  if(stats !== null) {
    if(!stats.isDirectory()) {
      console.log("ERROR: " + dataDirectory + " is not a directory");
      return false;
    }
  } else {
    // doesn't exist, create it
    try {
      fs.mkdirSync(dataDirectory);
    } catch (e) {
      console.log("ERROR: couldn't create data directory " + e);
      return false;
    }
  }

  return true;
}<commit_msg>Added bannerHandler.js<commit_after>/*jlint node: true */
/*global require, console, module, process, __dirname */
/*
 * application.js
 *
 * Copyright (C) 2014 by James Jenner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

var path = require('path');
var opt = require('opt').create();
var fs = require('fs');

var MeltingPot = require('meltingpot');

var PanelHandler = require('./lib/server/panelHandler.js');
var DataSourceHandler = require('./lib/server/dataSourceHandler.js');
var WidgetHandler = require('./lib/server/widgetHandler.js');
var DataSourceManager = require('./lib/server/dataSourceManager.js');
var LocalPreferenceHandler = require('./lib/server/localPreferenceHandler.js');
var PreferenceHandler = require('./lib/server/preferenceHandler.js');
var BannerHandler = require('./lib/server/bannerHandler.js');

//var VEHICLES_FILE = 'vehicles.json';

//// setup log4js component with a logger
//log4js.configure({
//  appenders: [
//    {
//      type: "file",
//      filename: "meltingpot.log",
//      category: ['videre', 'file']
// },
//    {
//      type: "file",
//      filename: "meltingpot_clientcomms_in.log",
//      category: ['clientIn', 'file']
// },
//    {
//      type: "file",
//      filename: "meltingpot_clientcomms_out.log",
//      category: ['clientOut', 'file']
// }
// /*
//	{
//	    type: "console"
//	}
//	*/
//    ],
//  replaceConsole: false
//});

// load the vehicle configs from the file
//var vehicles = loadVehicles(VEHICLES_FILE);

/* options handling */
// TODO: look at replacing or extending opt, would like error on invalid arg, exclusivity of args, better formatting of help, etc

var config = {
  debug: false,
  debugLevel: 0,
  clientAddress: 'localhost',
  port: 9007,
  securePort: 9008,
  uuidV1: false,
  communicationType: MeltingPot.Message.COMMS_TYPE_UNSECURE_ONLY,
  sslKey: 'keys' + path.sep + 'privatekey.pem',
  sslCert: 'keys' + path.sep + 'certificate.pem',
  autoDiscover: false,
  dataDirectory: '.' + path.sep + 'data' + path.sep,
};

var search_paths = [
  "meltingpot.conf",
  path.join(process.env.HOME, ".meltingpot-rc"),
  "/usr/local/etc/meltingpot.conf",
  "/usr/etc/meltingpot.conf",
  "/etc/meltingpot.conf"
];

var listingProtocols = false;

opt.configSync(config, search_paths);

opt.optionHelp("USAGE node " + path.basename(process.argv[1]),
  "SYNOPSIS: The application is the back end for the meltingpot front end .\n\n\t\t node " + path.basename(process.argv[1]) + " --help",
  "OPTIONS:",
  "Copyright (c) 2014 James G Jenner, all rights reserved\n" +
  " Released under MIT License\n" +
  " See: http://opensource.org/licenses/MIT\n");

opt.option(["-d", "--debug"], function (param) {
  config.debug = true;
  if (Number(param).toFixed(0) > 0) {
    config.debugLevel = Number(param).toFixed(0);
    opt.consume(param);
  } else {
    config.debugLevel = 0;
  }
}, "Generate debugging messages, level is optional. 0 - informational, 1 - detailed");

opt.option(["-so", "--secure-only"], function (param) {
  config.communicationType = MeltingPot.Message.COMMS_TYPE_SECURE_ONLY;
}, "Set communications to only accept secure connections");

opt.option(["-uo", "--unsecure-only"], function (param) {
  config.communicationType = MeltingPot.Message.COMMS_TYPE_UNSECURE_ONLY;
}, "Set communications to only accept unsecure connections, this is the default type");

opt.option(["-m", "--mixed"], function (param) {
  config.communicationType = MeltingPot.Message.COMMS_TYPE_MIXED;
}, "Set communications to accept secure and unsecure connections");

opt.option(["-u1", "--uuid-v1"], function (param) {
  config.uuidV1 = true;
}, "Set uuid generation for session keys to uuid v1, default is v4");

opt.option(["-ad", "--auto-discover"], function (param) {
  config.autoDiscover = true;
}, "comms auto discovery");

opt.option(["-dd", "--data-directory"], function (param) {
  if (param !== undefined && param.trim()) {
    config.dataDirectory = param.trim();
    if(config.dataDirectory.charAt(config.dataDirectory.length - 1) !== path.sep) {
      config.dataDirectory += path.sep;
    }
    opt.consume(param);
  } else {
    opt.usage("The directory must be provided with the option for data directory.", 1);
  }
}, "Set the directory for data files");

// server comms settings
opt.option(["-p", "--port"], function (param) {
  if (Number(param).toFixed(0) > 0) {
    config.port = Number(param).toFixed(0);
    opt.consume(param);
  } else {
    opt.usage("Port must be a number greater then 0.", 1);
  }
}, "Set the port parameter for remote connections");

opt.option(["-s", "--ssl-port"], function (param) {
  if (Number(param).toFixed(0) > 0) {
    config.securePort = Number(param).toFixed(0);
    opt.consume(param);
  } else {
    opt.usage("SLL Port must be a number greater then 0.", 1);
  }
}, "Set the ssl port parameter for remote secure connections");

opt.option(["-sk", "--ssl-key"], function (param) {
  if (param !== undefined && param.trim()) {
    config.sslKey = param.trim();
    opt.consume(param);
  }
}, "Set the ssl private key file parameter for remote secure connections");

opt.option(["-sc", "--ssl-cert"], function (param) {
  if (param !== undefined && param.trim()) {
    config.sslCert = param.trim();
    opt.consume(param);
  }
}, "Set the ssl certificate parameter for remote secure connections");

opt.option(["-g", "--generate"], function (param) {
  var config_filename = "";

  if (param !== undefined && param.trim() !== "") {
    config_filename = param.trim();
  }
  opt.consume(param);

  if (config_filename === "") {
    console.log(JSON.stringify(config, null, '\t'));
    process.exit(0);
  } else {
    fs.writeFile(config_filename, JSON.stringify(config, null, '\t'), function (err) {
      if (err) {
        console.error("ERROR: can't write", config_filename);
        process.exit(1);
      }
      console.log("Wrote configuration to", config_filename);
      process.exit(0);
    });
  }

}, "Generate a configuration file");

opt.option(["-h", "--help"], function () {
  opt.usage();
}, "This help document.");

opt.optionWith(process.argv);

// load existing definitions

// setup the client communications
var clientComms = new MeltingPot.Comms({
  port: config.port,
  securePort: config.securePort,
  uuidV1: config.uuidV1,
  communicationType: config.communicationType,
  sslKey: config.sslKey,
  sslCert: config.sslCert,
  debug: config.debug,
  debugLevel: config.debugLevel,
  messageHandlers: [
    PanelHandler.messageHandler,
    PreferenceHandler.messageHandler,
    LocalPreferenceHandler.messageHandler,
    DataSourceHandler.messageHandler,
    WidgetHandler.messageHandler,
    BannerHandler.messageHandler,
  ]
});

// setup data directory
if(!validateDataDirectory(config.dataDirectory)) {
 return -1;
}

var localPreferenceHandler = new LocalPreferenceHandler({dataDirectory: config.dataDirectory});
localPreferenceHandler.setupCommsListeners(clientComms);

var preferenceHandler = new PreferenceHandler({dataDirectory: config.dataDirectory, localPreferenceHandler: localPreferenceHandler});
preferenceHandler.setupCommsListeners(clientComms);

var panelHandler = new PanelHandler({dataDirectory: config.dataDirectory, preferenceHandler: preferenceHandler});
panelHandler.setupCommsListeners(clientComms);

var widgetHandler = new WidgetHandler({dataDirectory: config.dataDirectory});
widgetHandler.setupCommsListeners(clientComms);

var bannerHandler = new BannerHandler({dataDirectory: config.dataDirectory});
bannerHandler.setupCommsListeners(clientComms);

var dataSourceHandler = new DataSourceHandler({dataDirectory: config.dataDirectory});
dataSourceHandler.setupCommsListeners(clientComms);

var dataSourceManager = new DataSourceManager({clientComms: clientComms, dataSourceHandler: dataSourceHandler, widgetHandler: widgetHandler});
dataSourceManager.setupCommsListeners(clientComms);

// start up the server for clients
if (config.debug) {
  console.log((new Date()) + " application.js: starting client server");
}

dataSourceManager.start();
clientComms.startClientServer();

/*
 * returns false if the directory cannot be created
 */
function validateDataDirectory(dataDirectory) {
  var stats = null;

  // check if file exists
  try {
    stats = fs.statSync(dataDirectory);
  } catch (e) {
  }

  if(stats !== null) {
    if(!stats.isDirectory()) {
      console.log("ERROR: " + dataDirectory + " is not a directory");
      return false;
    }
  } else {
    // doesn't exist, create it
    try {
      fs.mkdirSync(dataDirectory);
    } catch (e) {
      console.log("ERROR: couldn't create data directory " + e);
      return false;
    }
  }

  return true;
}<|endoftext|>