<commit_before>import React from 'react';
import Reflux from 'reflux';
import Dropzone from 'react-dropzone';
import Map from 'es6-map';
import _ from 'underscore';
import { Link } from 'react-router';
import actions from '../actions';
import bem from '../bem';
import stores from '../stores';
import Select from 'react-select';
import ui from '../ui';
import mixins from '../mixins';
import DocumentTitle from 'react-document-title';
import CopyToClipboard from 'react-copy-to-clipboard';
import icons from '../../xlform/src/view.icons';
import $ from 'jquery';

import {
  formatTime,
  currentLang,
  assign,
  t,
  log,
  notify,
  validFileTypes
} from '../utils';

var FormLanding = React.createClass({
  mixins: [
    mixins.droppable,
    mixins.dmix,
    Reflux.ListenerMixin
  ],
  getInitialState () {
    return {
      questionLanguageIndex: 0,
      selectedCollectMethod: 'offline_url'
    };
  },
  componentWillReceiveProps() {
    this.setState({
        questionLanguageIndex: 0
      }
    );
  },
  enketoPreviewModal (evt) {
    evt.preventDefault();
    stores.pageState.showModal({
      type: 'enketo-preview',
      assetid: this.state.uid
    });
  },
  renderFormInfo () {
    var dvcount = this.state.deployed_versions.length;
    return (
        <bem.FormView__cell m={['columns', 'padding']}>
          <bem.FormView__cell>
            <bem.FormView__cell m='version'>
              {dvcount > 0 ? `v${dvcount}` : ''}
            </bem.FormView__cell>
            <bem.FormView__cell m='date'>
              {t('Last Modified')} :
              {formatTime(this.state.date_modified)} -

                {this.state.summary.row_count || '0'}
                {t('questions')}

            </bem.FormView__cell>
          </bem.FormView__cell>
          <bem.FormView__cell m='buttons'>
            {this.state.userCanEdit &&

                  {this.state.has_deployment ? t('redeploy') : t('deploy')}

            }
          </bem.FormView__cell>
        </bem.FormView__cell>
      );
  },
  renderFormLanguages () {
    return (
      <bem.FormView__cell m={['padding', 'bordertop', 'languages']}>
        {t('Languages')}
        {this.state.summary.languages.map((l, i)=>{
          return (
              <bem.FormView__cell key={`lang-${i}`} m='langButton'
                className={this.state.questionLanguageIndex == i ? 'active' : ''}
                onClick={this.updateQuestionListLanguage}
                data-index={i}>
                {l}
              </bem.FormView__cell>
            );
        })}

      </bem.FormView__cell>
    );
  },
  updateQuestionListLanguage (evt) {
    let i = evt.currentTarget.dataset.index;
    this.setState({
        questionLanguageIndex: i
      }
    );
  },
  sharingModal (evt) {
    evt.preventDefault();
    stores.pageState.showModal({
      type: 'sharing',
      assetid: this.state.uid
    });
  },
  renderHistory () {
    var dvcount = this.state.deployed_versions.length;
    return (
      <bem.FormView__row className={this.state.historyExpanded ? 'historyExpanded' : 'historyHidden'}>
        <bem.FormView__cell m={['columns', 'history-label']}>
          <bem.FormView__cell m='label'>
            {t('Form history')}
          </bem.FormView__cell>
        </bem.FormView__cell>
        <bem.FormView__cell m={['box', 'history-table']}>
          <bem.FormView__group m="deployments">
            <bem.FormView__group m={['items', 'headings']}>
              <bem.FormView__label m='version'>{t('Version')}</bem.FormView__label>
              <bem.FormView__label m='date'>{t('Last Modified')}</bem.FormView__label>
              <bem.FormView__label m='clone'>{t('Clone')}</bem.FormView__label>
            </bem.FormView__group>
            {this.state.deployed_versions.map((item, n) => {
              return (
                <bem.FormView__group m="items" key={n} >
                  <bem.FormView__label m='version'>
                    {`v${dvcount-n}`}
                    {item.uid === this.state.deployed_version_id && this.state.deployment__active &&
                      <bem.FormView__cell m='deployed'>
                        {t('Deployed')}
                      </bem.FormView__cell>
                    }
                  </bem.FormView__label>
                  <bem.FormView__label m='date'>
                    {formatTime(item.date_deployed)}
                  </bem.FormView__label>
                  <bem.FormView__label m='clone' className="right-tooltip">
                      <bem.FormView__link m='clone'
                          data-version-id={item.uid}
                          data-tip={t('Clone this version as a new project')}
                          onClick={this.saveCloneAs}>

                      </bem.FormView__link>
                  </bem.FormView__label>
                </bem.FormView__group>
              );
            })}
          </bem.FormView__group>
        </bem.FormView__cell>
        {this.state.deployed_versions.length > 1 &&
          <bem.FormView__cell m={['centered']}>
            <button className="mdl-button mdl-button--colored" onClick={this.toggleDeploymentHistory}>
              {this.state.historyExpanded ? t('Hide full history') : t('Show full history')}
            </button>
          </bem.FormView__cell>
        }
      </bem.FormView__row>
      );
  },
  renderCollectData () {
    var deployment__links = this.state.deployment__links;

    var available_links = new Map([
        ['offline_url', {
          label: t('Online-Offline (multiple submission)'),
          desc: t('This allows online and offline submissions and is the best option for collecting data in the field. ')
        }],
        ['url', {
          label: t('Online-Only (multiple submissions)'),
          desc: t('This is the best option when entering many records at once on a computer, e.g. for transcribing paper records')
        }],
        ['iframe_url', {
          label: t('Embeddable web form code'),
          desc: t('Use this html5 code snippet to integrate your form on your own website using smaller margins. ')
        }],
        ['preview_url', {
          label: t('View only'),
          desc: t('Use this version for testing, getting feedback. Does not allow submitting data. ')
        }],
        ['android', {
          label: t('Android application'),
          desc: t('Use this option to collect data in the field with your Android device.')
        }],
    ]);

    var deployment__links_list = [];
    available_links.forEach(function (value, key) {
      deployment__links_list.push(
        {
          key: key,
          label: value.label,
          desc: value.desc,
        }
      );
    });

    var chosenMethod = this.state.selectedCollectMethod;

    var kc_server = document.createElement('a');
    kc_server.href = this.state.deployment__identifier;
    var kobocollect_url = kc_server.origin + '/' + this.state.owner__username;

    return (
      <bem.FormView__row>
        <bem.FormView__cell m='columns'>
          <bem.FormView__cell m='label'>
              {t('Collect data')}
          </bem.FormView__cell>
        </bem.FormView__cell>
        <bem.FormView__cell m='box'>
          <bem.FormView__cell m={['columns', 'padding']}>
            <bem.FormView__cell>
              <ui.PopoverMenu type='collectData-menu' triggerLabel={available_links[chosenMethod].label}>
                {deployment__links_list.map((c)=>{
                  return (
                      <bem.PopoverMenu__link m={['collect-row']}
                                             key={`c-${c.key}`}
                                             data-method={c.key}
                                             onClick={this.setCollectMethod}>

{c.label}

{c.desc}

{c.value}

                      </bem.PopoverMenu__link>
                    );
                })}
              </ui.PopoverMenu>
            </bem.FormView__cell>
            <bem.FormView__cell>
              {chosenMethod != 'iframe_url' && chosenMethod != 'android' &&
                <CopyToClipboard text={this.state.deployment__links[chosenMethod]} onCopy={() => notify('copied to clipboard')}>
                  <button className="copy mdl-button mdl-button--colored">{t('Copy')}</button>
                </CopyToClipboard>
              }
              {chosenMethod != 'iframe_url' && chosenMethod != 'android' &&

                  {t('Open')}

              }
              { chosenMethod == 'android' &&

                   {t('Download KoboCollect')}

              }
              {chosenMethod == 'iframe_url' &&
                <CopyToClipboard text={`<iframe src=${this.state.deployment__links[chosenMethod]} width="800" height="600"></iframe>`}
                                 onCopy={() => notify('copied to clipboard')}>
                  <button className="copy mdl-button mdl-button--colored">{t('Copy')}</button>
                </CopyToClipboard>
              }
            </bem.FormView__cell>
          </bem.FormView__cell>
          <bem.FormView__cell m={['padding', 'bordertop', 'collect-meta']}>
            {chosenMethod != 'android' &&
              available_links[chosenMethod].desc
            }

            {chosenMethod == 'iframe_url' &&

                {`<iframe src=${this.state.deployment__links[chosenMethod]} width="800" height="600"></iframe>`}

            }

            {chosenMethod == 'android' &&

                  {t('Install')}

                  KoboCollect

                  {t('on your Android device.')}

{t('Click on')}  {t('to open settings.')}

                  {t('Enter the server URL')}
                  {kobocollect_url}
                  {t('and your username and password')}

{t('Open "Get Blank Form" and select this project. ')}

{t('Open "Enter Data."')}

            }

          </bem.FormView__cell>
        </bem.FormView__cell>
      </bem.FormView__row>
    );
  },
  setCollectMethod(evt) {
    var method = $(evt.target).parents('.popover-menu__link').data('method');
    this.setState({
        selectedCollectMethod: method
      }
    );
  },
  renderButtons () {
    var downloadable = false;
    var downloads = [];
    if (this.state.downloads) {
      downloadable = !!this.state.downloads[0];
      downloads = this.state.downloads;
    }

    return (
        <bem.FormView__group m='buttons'>
          {this.state.userCanEdit ?
            <Link to={`/forms/${this.state.uid}/edit`}
                  className="form-view__link form-view__link--edit"
                  data-tip={t('edit')}>

            </Link>
          :
            <bem.FormView__link m={'edit'}
              data-tip={t('Editing capabilities not granted, you can only view this form')}>

            </bem.FormView__link>
          }
          <bem.FormView__link m='preview'
            onClick={this.enketoPreviewModal}
            data-tip={t('Preview')}>

          </bem.FormView__link>
          {this.state.userCanEdit &&
            <Dropzone onDrop={this.dropFiles}
                          multiple={false}
                          className='dropzone'
                          accept={validFileTypes()}>
              <bem.FormView__link m='upload' data-tip={t('Replace with XLS')}>

              </bem.FormView__link>
            </Dropzone>
          }

          <ui.PopoverMenu type='formLanding-menu'
                      triggerLabel={}
                      triggerTip={t('More Actions')}>
              {downloads.map((dl)=>{
                return (
                    <bem.PopoverMenu__link m={`dl-${dl.format}`} href={dl.url}
                        key={`dl-${dl.format}`}>
                      <i className={`k-icon-${dl.format}-file`}/>
                      {t('Download')}
                      {dl.format.toString().toUpperCase()}
                    </bem.PopoverMenu__link>
                  );
              })}
              {this.state.userCanEdit &&
                <bem.PopoverMenu__link onClick={this.sharingModal}>

                  {t('Share this project')}
                </bem.PopoverMenu__link>
              }
              <bem.PopoverMenu__link onClick={this.saveCloneAs}>

                {t('Clone this project')}
              </bem.PopoverMenu__link>
          </ui.PopoverMenu>
        </bem.FormView__group>
      );
  },
  render () {
    var docTitle = this.state.name || t('Untitled');

    if (this.state.uid == undefined) {
      return (
        <ui.Panel>
          <bem.Loading>
            <bem.Loading__inner>

              {t('loading...')}
            </bem.Loading__inner>
          </bem.Loading>
        </ui.Panel>
      );
    }

    return (
      <DocumentTitle title={`${docTitle} | KoboToolbox`}>
        <bem.FormView m='form'>
          <bem.FormView__row>
            <bem.FormView__cell m={['columns', 'first']}>
              <bem.FormView__cell m='label'>
                {this.state.deployment__active ? t('Current version') :
                  this.state.has_deployment ? t('Archived version') :
                    t('Draft version')}
              </bem.FormView__cell>
              <bem.FormView__cell>
                {this.renderButtons()}
              </bem.FormView__cell>
            </bem.FormView__cell>
            <bem.FormView__cell m='box'>
              {this.state.deployed_versions.length > 0 &&
                this.state.deployed_version_id != this.state.version_id && this.state.deployment__active &&
                <bem.FormView__cell m='warning'>

                  {t('If you want to make these changes public, you must deploy this form.')}
                </bem.FormView__cell>
              }
              {this.renderFormInfo()}
              {this.state.summary && this.state.summary.languages && this.state.summary.languages[0] != null &&
                this.renderFormLanguages()
              }
            </bem.FormView__cell>
          </bem.FormView__row>
          {this.state.deployed_versions.length > 0 &&
            this.renderHistory()
          }
          {this.state.deployed_versions.length > 0 && this.state.deployment__active &&
            this.renderCollectData()
          }
        </bem.FormView>
      </DocumentTitle>
      );
  }

})

export default FormLanding;
<commit_msg>use ES6 map method to get values from mapped array<commit_after>import React from 'react';
import Reflux from 'reflux';
import Dropzone from 'react-dropzone';
import Map from 'es6-map';
import _ from 'underscore';
import { Link } from 'react-router';
import actions from '../actions';
import bem from '../bem';
import stores from '../stores';
import Select from 'react-select';
import ui from '../ui';
import mixins from '../mixins';
import DocumentTitle from 'react-document-title';
import CopyToClipboard from 'react-copy-to-clipboard';
import icons from '../../xlform/src/view.icons';
import $ from 'jquery';

import {
  formatTime,
  currentLang,
  assign,
  t,
  log,
  notify,
  validFileTypes
} from '../utils';

var FormLanding = React.createClass({
  mixins: [
    mixins.droppable,
    mixins.dmix,
    Reflux.ListenerMixin
  ],
  getInitialState () {
    return {
      questionLanguageIndex: 0,
      selectedCollectMethod: 'offline_url'
    };
  },
  componentWillReceiveProps() {
    this.setState({
        questionLanguageIndex: 0
      }
    );
  },
  enketoPreviewModal (evt) {
    evt.preventDefault();
    stores.pageState.showModal({
      type: 'enketo-preview',
      assetid: this.state.uid
    });
  },
  renderFormInfo () {
    var dvcount = this.state.deployed_versions.length;
    return (
        <bem.FormView__cell m={['columns', 'padding']}>
          <bem.FormView__cell>
            <bem.FormView__cell m='version'>
              {dvcount > 0 ? `v${dvcount}` : ''}
            </bem.FormView__cell>
            <bem.FormView__cell m='date'>
              {t('Last Modified')} :
              {formatTime(this.state.date_modified)} -

                {this.state.summary.row_count || '0'}
                {t('questions')}

            </bem.FormView__cell>
          </bem.FormView__cell>
          <bem.FormView__cell m='buttons'>
            {this.state.userCanEdit &&

                  {this.state.has_deployment ? t('redeploy') : t('deploy')}

            }
          </bem.FormView__cell>
        </bem.FormView__cell>
      );
  },
  renderFormLanguages () {
    return (
      <bem.FormView__cell m={['padding', 'bordertop', 'languages']}>
        {t('Languages')}
        {this.state.summary.languages.map((l, i)=>{
          return (
              <bem.FormView__cell key={`lang-${i}`} m='langButton'
                className={this.state.questionLanguageIndex == i ? 'active' : ''}
                onClick={this.updateQuestionListLanguage}
                data-index={i}>
                {l}
              </bem.FormView__cell>
            );
        })}

      </bem.FormView__cell>
    );
  },
  updateQuestionListLanguage (evt) {
    let i = evt.currentTarget.dataset.index;
    this.setState({
        questionLanguageIndex: i
      }
    );
  },
  sharingModal (evt) {
    evt.preventDefault();
    stores.pageState.showModal({
      type: 'sharing',
      assetid: this.state.uid
    });
  },
  renderHistory () {
    var dvcount = this.state.deployed_versions.length;
    return (
      <bem.FormView__row className={this.state.historyExpanded ? 'historyExpanded' : 'historyHidden'}>
        <bem.FormView__cell m={['columns', 'history-label']}>
          <bem.FormView__cell m='label'>
            {t('Form history')}
          </bem.FormView__cell>
        </bem.FormView__cell>
        <bem.FormView__cell m={['box', 'history-table']}>
          <bem.FormView__group m="deployments">
            <bem.FormView__group m={['items', 'headings']}>
              <bem.FormView__label m='version'>{t('Version')}</bem.FormView__label>
              <bem.FormView__label m='date'>{t('Last Modified')}</bem.FormView__label>
              <bem.FormView__label m='clone'>{t('Clone')}</bem.FormView__label>
            </bem.FormView__group>
            {this.state.deployed_versions.map((item, n) => {
              return (
                <bem.FormView__group m="items" key={n} >
                  <bem.FormView__label m='version'>
                    {`v${dvcount-n}`}
                    {item.uid === this.state.deployed_version_id && this.state.deployment__active &&
                      <bem.FormView__cell m='deployed'>
                        {t('Deployed')}
                      </bem.FormView__cell>
                    }
                  </bem.FormView__label>
                  <bem.FormView__label m='date'>
                    {formatTime(item.date_deployed)}
                  </bem.FormView__label>
                  <bem.FormView__label m='clone' className="right-tooltip">
                      <bem.FormView__link m='clone'
                          data-version-id={item.uid}
                          data-tip={t('Clone this version as a new project')}
                          onClick={this.saveCloneAs}>

                      </bem.FormView__link>
                  </bem.FormView__label>
                </bem.FormView__group>
              );
            })}
          </bem.FormView__group>
        </bem.FormView__cell>
        {this.state.deployed_versions.length > 1 &&
          <bem.FormView__cell m={['centered']}>
            <button className="mdl-button mdl-button--colored" onClick={this.toggleDeploymentHistory}>
              {this.state.historyExpanded ? t('Hide full history') : t('Show full history')}
            </button>
          </bem.FormView__cell>
        }
      </bem.FormView__row>
      );
  },
  renderCollectData () {
    var deployment__links = this.state.deployment__links;

    var available_links = new Map([
        ['offline_url', {
          label: t('Online-Offline (multiple submission)'),
          desc: t('This allows online and offline submissions and is the best option for collecting data in the field. ')
        }],
        ['url', {
          label: t('Online-Only (multiple submissions)'),
          desc: t('This is the best option when entering many records at once on a computer, e.g. for transcribing paper records')
        }],
        ['iframe_url', {
          label: t('Embeddable web form code'),
          desc: t('Use this html5 code snippet to integrate your form on your own website using smaller margins. ')
        }],
        ['preview_url', {
          label: t('View only'),
          desc: t('Use this version for testing, getting feedback. Does not allow submitting data. ')
        }],
        ['android', {
          label: t('Android application'),
          desc: t('Use this option to collect data in the field with your Android device.')
        }],
    ]);

    var deployment__links_list = [];
    available_links.forEach(function (value, key) {
      deployment__links_list.push(
        {
          key: key,
          label: value.label,
          desc: value.desc,
        }
      );
    });

    var chosenMethod = this.state.selectedCollectMethod;

    var kc_server = document.createElement('a');
    kc_server.href = this.state.deployment__identifier;
    var kobocollect_url = kc_server.origin + '/' + this.state.owner__username;

    return (
      <bem.FormView__row>
        <bem.FormView__cell m='columns'>
          <bem.FormView__cell m='label'>
              {t('Collect data')}
          </bem.FormView__cell>
        </bem.FormView__cell>
        <bem.FormView__cell m='box'>
          <bem.FormView__cell m={['columns', 'padding']}>
            <bem.FormView__cell>
              <ui.PopoverMenu type='collectData-menu' triggerLabel={available_links.get(chosenMethod).label}>
                {deployment__links_list.map((c)=>{
                  return (
                      <bem.PopoverMenu__link m={['collect-row']}
                                             key={`c-${c.key}`}
                                             data-method={c.key}
                                             onClick={this.setCollectMethod}>

{c.label}

{c.desc}

{c.value}

                      </bem.PopoverMenu__link>
                    );
                })}
              </ui.PopoverMenu>
            </bem.FormView__cell>
            <bem.FormView__cell>
              {chosenMethod != 'iframe_url' && chosenMethod != 'android' &&
                <CopyToClipboard text={this.state.deployment__links[chosenMethod]} onCopy={() => notify('copied to clipboard')}>
                  <button className="copy mdl-button mdl-button--colored">{t('Copy')}</button>
                </CopyToClipboard>
              }
              {chosenMethod != 'iframe_url' && chosenMethod != 'android' &&

                  {t('Open')}

              }
              { chosenMethod == 'android' &&

                   {t('Download KoboCollect')}

              }
              {chosenMethod == 'iframe_url' &&
                <CopyToClipboard text={`<iframe src=${this.state.deployment__links[chosenMethod]} width="800" height="600"></iframe>`}
                                 onCopy={() => notify('copied to clipboard')}>
                  <button className="copy mdl-button mdl-button--colored">{t('Copy')}</button>
                </CopyToClipboard>
              }
            </bem.FormView__cell>
          </bem.FormView__cell>
          <bem.FormView__cell m={['padding', 'bordertop', 'collect-meta']}>
            {chosenMethod != 'android' &&
              available_links.get(chosenMethod).desc
            }

            {chosenMethod == 'iframe_url' &&

                {`<iframe src=${this.state.deployment__links[chosenMethod]} width="800" height="600"></iframe>`}

            }

            {chosenMethod == 'android' &&

                  {t('Install')}

                  KoboCollect

                  {t('on your Android device.')}

{t('Click on')}  {t('to open settings.')}

                  {t('Enter the server URL')}
                  {kobocollect_url}
                  {t('and your username and password')}

{t('Open "Get Blank Form" and select this project. ')}

{t('Open "Enter Data."')}

            }

          </bem.FormView__cell>
        </bem.FormView__cell>
      </bem.FormView__row>
    );
  },
  setCollectMethod(evt) {
    var method = $(evt.target).parents('.popover-menu__link').data('method');
    this.setState({
        selectedCollectMethod: method
      }
    );
  },
  renderButtons () {
    var downloadable = false;
    var downloads = [];
    if (this.state.downloads) {
      downloadable = !!this.state.downloads[0];
      downloads = this.state.downloads;
    }

    return (
        <bem.FormView__group m='buttons'>
          {this.state.userCanEdit ?
            <Link to={`/forms/${this.state.uid}/edit`}
                  className="form-view__link form-view__link--edit"
                  data-tip={t('edit')}>

            </Link>
          :
            <bem.FormView__link m={'edit'}
              data-tip={t('Editing capabilities not granted, you can only view this form')}>

            </bem.FormView__link>
          }
          <bem.FormView__link m='preview'
            onClick={this.enketoPreviewModal}
            data-tip={t('Preview')}>

          </bem.FormView__link>
          {this.state.userCanEdit &&
            <Dropzone onDrop={this.dropFiles}
                          multiple={false}
                          className='dropzone'
                          accept={validFileTypes()}>
              <bem.FormView__link m='upload' data-tip={t('Replace with XLS')}>

              </bem.FormView__link>
            </Dropzone>
          }

          <ui.PopoverMenu type='formLanding-menu'
                      triggerLabel={}
                      triggerTip={t('More Actions')}>
              {downloads.map((dl)=>{
                return (
                    <bem.PopoverMenu__link m={`dl-${dl.format}`} href={dl.url}
                        key={`dl-${dl.format}`}>
                      <i className={`k-icon-${dl.format}-file`}/>
                      {t('Download')}
                      {dl.format.toString().toUpperCase()}
                    </bem.PopoverMenu__link>
                  );
              })}
              {this.state.userCanEdit &&
                <bem.PopoverMenu__link onClick={this.sharingModal}>

                  {t('Share this project')}
                </bem.PopoverMenu__link>
              }
              <bem.PopoverMenu__link onClick={this.saveCloneAs}>

                {t('Clone this project')}
              </bem.PopoverMenu__link>
          </ui.PopoverMenu>
        </bem.FormView__group>
      );
  },
  render () {
    var docTitle = this.state.name || t('Untitled');

    if (this.state.uid == undefined) {
      return (
        <ui.Panel>
          <bem.Loading>
            <bem.Loading__inner>

              {t('loading...')}
            </bem.Loading__inner>
          </bem.Loading>
        </ui.Panel>
      );
    }

    return (
      <DocumentTitle title={`${docTitle} | KoboToolbox`}>
        <bem.FormView m='form'>
          <bem.FormView__row>
            <bem.FormView__cell m={['columns', 'first']}>
              <bem.FormView__cell m='label'>
                {this.state.deployment__active ? t('Current version') :
                  this.state.has_deployment ? t('Archived version') :
                    t('Draft version')}
              </bem.FormView__cell>
              <bem.FormView__cell>
                {this.renderButtons()}
              </bem.FormView__cell>
            </bem.FormView__cell>
            <bem.FormView__cell m='box'>
              {this.state.deployed_versions.length > 0 &&
                this.state.deployed_version_id != this.state.version_id && this.state.deployment__active &&
                <bem.FormView__cell m='warning'>

                  {t('If you want to make these changes public, you must deploy this form.')}
                </bem.FormView__cell>
              }
              {this.renderFormInfo()}
              {this.state.summary && this.state.summary.languages && this.state.summary.languages[0] != null &&
                this.renderFormLanguages()
              }
            </bem.FormView__cell>
          </bem.FormView__row>
          {this.state.deployed_versions.length > 0 &&
            this.renderHistory()
          }
          {this.state.deployed_versions.length > 0 && this.state.deployment__active &&
            this.renderCollectData()
          }
        </bem.FormView>
      </DocumentTitle>
      );
  }

})

export default FormLanding;
<|endoftext|>


<commit_before>'use babel'

import Update from '../src/update'
import remote from 'remote'
import ipc from 'ipc'

fdescribe('Update', () => {
  let update

  afterEach(() => {
    update.dispose()
  })

  describe('::initialize', () => {
    it('subscribes to appropriate applicationDelegate events', () => {
      update = new Update()

      const downloadingSpy = jasmine.createSpy('downloadingSpy')
      const checkingSpy = jasmine.createSpy('checkingSpy')
      const noUpdateSpy = jasmine.createSpy('noUpdateSpy')
      const completedDownloadSpy = jasmine.createSpy('completedDownloadSpy')

      update.emitter.on('did-begin-checking-for-update', checkingSpy)
      update.emitter.on('did-begin-downloading-update', downloadingSpy)
      update.emitter.on('did-complete-downloading-update', completedDownloadSpy)
      update.emitter.on('update-not-available', noUpdateSpy)

      update.initialize()

      const webContents = remote.getCurrentWebContents()
      webContents.send('message', 'checking-for-update')
      webContents.send('message', 'did-begin-downloading-update')
      webContents.send('message', 'update-available', {releaseVersion: '1.2.3'})
      webContents.send('message', 'update-not-available')

      waitsFor(() => {
        return noUpdateSpy.callCount > 0
      })

      runs(() => {
        expect(downloadingSpy.callCount).toBe(1)
        expect(checkingSpy.callCount).toBe(1)
        expect(noUpdateSpy.callCount).toBe(1)
        expect(completedDownloadSpy.callCount).toBe(1)
      })
    })
  })

  beforeEach(() => {
    update = new Update()
    update.initialize()
  })

  describe('::onDidBeginCheckingForUpdate', () => {
    it('subscribes to "did-begin-checking-for-update" event', () => {
      const spy = jasmine.createSpy('spy')
      update.onDidBeginCheckingForUpdate(spy)
      update.emitter.emit('did-begin-checking-for-update')
      expect(spy.callCount).toBe(1)
    })
  })

  describe('::onDidBeginDownload', () => {
    it('subscribes to "did-begin-downloading-update" event', () => {
      const spy = jasmine.createSpy('spy')
      update.onDidBeginDownload(spy)
      update.emitter.emit('did-begin-downloading-update')
      expect(spy.callCount).toBe(1)
    })
  })

  describe('::onDidCompleteDownload', () => {
    it('subscribes to "did-complete-downloading-update" event', () => {
      const spy = jasmine.createSpy('spy')
      update.onDidCompleteDownload(spy)
      update.emitter.emit('did-complete-downloading-update')
      expect(spy.callCount).toBe(1)
    })
  })

  describe('::onUpdateNotAvailable', () => {
    it('subscribes to "update-not-available" event', () => {
      const spy = jasmine.createSpy('spy')
      update.onUpdateNotAvailable(spy)
      update.emitter.emit('update-not-available')
      expect(spy.callCount).toBe(1)
    })
  })

  describe('::onUpdateAvailable', () => {
    it('subscribes to "update-available" event', () => {
      const spy = jasmine.createSpy('spy')
      update.onUpdateAvailable(spy)
      update.emitter.emit('update-available')
      expect(spy.callCount).toBe(1)
    })
  })

  // TODO: spec is timing out. spy is not called
  // describe('::check', () => {
  //   it('sends "check-for-update" event', () => {
  //     const spy = jasmine.createSpy('spy')
  //     ipc.on('check-for-update', () => {
  //       spy()
  //     })
  //     update.check()
  //     waitsFor(() => {
  //       return spy.callCount > 0
  //     })
  //   })
  // })

  describe('::dispose', () => {
    it('disposes of subscriptions', () => {
      expect(update.subscriptions.disposables).not.toBeNull()
      update.dispose()
      expect(update.subscriptions.disposables).toBeNull()
    })
  })

})
<commit_msg>Improve specs for `Update` class<commit_after>'use babel'

import Update from '../src/update'
import {remote} from 'electron'
const electronAutoUpdater = remote.require('electron').autoUpdater

describe('Update', () => {
  let update

  beforeEach(() => {
    update = new Update()
    update.initialize()
  })

  afterEach(() => {
    update.dispose()
  })

  describe('::onDidBeginCheckingForUpdate', () => {
    it('subscribes to "did-begin-checking-for-update" event', () => {
      const spy = jasmine.createSpy('spy')
      update.onDidBeginCheckingForUpdate(spy)
      electronAutoUpdater.emit('checking-for-update')
      waitsFor(() => {
        return spy.callCount === 1
      })
    })
  })

  describe('::onDidBeginDownload', () => {
    it('subscribes to "did-begin-downloading-update" event', () => {
      const spy = jasmine.createSpy('spy')
      update.onDidBeginDownload(spy)
      electronAutoUpdater.emit('update-available')
      waitsFor(() => {
        return spy.callCount === 1
      })
    })
  })

  describe('::onDidCompleteDownload', () => {
    it('subscribes to "did-complete-downloading-update" event', () => {
      const spy = jasmine.createSpy('spy')
      update.onDidCompleteDownload(spy)
      electronAutoUpdater.emit('update-downloaded', null, null, {releaseVersion: '1.2.3'})
      waitsFor(() => {
        return spy.callCount === 1
      })
    })
  })

  describe('::onUpdateNotAvailable', () => {
    it('subscribes to "update-not-available" event', () => {
      const spy = jasmine.createSpy('spy')
      update.onUpdateNotAvailable(spy)
      electronAutoUpdater.emit('update-not-available')
      waitsFor(() => {
        return spy.callCount === 1
      })
    })
  })

})
<|endoftext|>


<commit_before>describe("tools", function () {
	//dummy function example, called by .andCallFake() when using Spies
	function writeList() {
		return true;
	}
	var tools = require("../js/tools.js");

	//These are globally set before each single test.
	//You may make local beforeEach within each describe block for specifics for your describe.
	beforeEach(function (){
		//You don't need to ".andCallFake(function) here, just did it as an example.
		spyOn(tools.squeak, "writeListToFrontend").andCallFake(writeList);

		//See warning below in AddAction for as how to use this.  You'll need it a lot
		this.startActionCount = tools.squeak.getListOfActionsCount();
	});

	//All tests for addAction go in here
	describe("addAction", function() {
		//Test the base case
		it("should add an action", function() {
			tools.squeak.addAction(1, 1, 1, 2, "focus");
			var actionCount = tools.squeak.getListOfActionsCount();
			expect(actionCount).toEqual(1);
		});

		//Test an internal action gets done.
		it("should call writeListToFrontend", function() {
			tools.squeak.addAction(1, 1, 1, 2, "focus");
			expect(tools.squeak.writeListToFrontend).toHaveBeenCalled();
		});

		//Test error handling.
		it("should not throw an error unless an improper action is given", function() {
			expect(function(){tools.squeak.addAction(1, 1, 1, 2, "focus");}).not.toThrow()
			expect(function(){tools.squeak.addAction(1, 1, 1, 2, "flip-desk");}).toThrow()
		});

		//Check logic structures (where possible)
		it("should return false if start time is after end time", function() {
			var goodCall = tools.squeak.addAction(1, 1, 2, 2, "focus");
			var badCall = tools.squeak.addAction(1, 1, 3, 2, "focus");
			expect(goodCall).toEqual(true);
			expect(badCall).toEqual(false);
		});

		//WARNING: 	This is an example that shows a 'gotcha.'  Normally we want each of our
		//			tests to be atomic (aka, nothing bleeds over from one to the next), but
		//			as you can see the listOfActions value is accumulating over all the tests.
		it("should add several valid actions to the list of actions", function() {
			var actionCount = tools.squeak.getListOfActionsCount();
			expect(actionCount).toEqual(this.startActionCount); //From prior tests.  A better solution is below.
			tools.squeak.addAction(1, 1, 2, 2, "focus");
			tools.squeak.addAction(1, 1, 1, 2, "autoScroll");
			tools.squeak.addAction(1, 1, 2, 2, "strike");
			actionCount = tools.squeak.getListOfActionsCount() - this.startActionCount;
			expect(actionCount).toEqual(3); //Actual test done here.
		});

		it("should add multiple actions given multiple lines", function() {
			tools.squeak.addAction(1, 3, 1, 3, "focus");
			var actionCount = tools.squeak.getListOfActionsCount() - this.startActionCount;
			expect(actionCount).toEqual(3);
		});
	});

	//Delete Action
	describe("deleteAction", function() {
		it("should delete an action", function() {
			tools.squeak.deleteAction(1);
			var actionCount = tools.squeak.getListOfActionsCount();
			expect(actionCount).toEqual(actionCount - 1);
		});

		it("should call writeListToFrontend", function() {
			tools.squeak.deleteAction(1);
			expect(tools.squeak.writeListToFrontend).toHaveBeenCalled();
		});

		it("should not throw an error unless an improper action is given", function() {
			expect(function(){tools.squeak.deleteAction(1);}).not.toThrow()
			expect(function(){tools.squeak.deleteAction("freak-out");}).toThrow()
		});

		it("should return false if id was not found", function() {
			var goodCall = tools.squeak.deleteAction(1);
			var badCall = tools.squeak.deleteAction(0);
			expect(goodCall).toEqual(true);
			expect(badCall).toEqual(false);
		});
	});

	//Undo
	describe("undo", function() {

	});

	//Publish
	describe("publish", function() {

	});
});<commit_msg>fixed logic error in tools spec<commit_after>describe("tools", function () {
	//dummy function example, called by .andCallFake() when using Spies
	function writeList() {
		return true;
	}
	var tools = require("../js/tools.js");

	//These are globally set before each single test.
	//You may make local beforeEach within each describe block for specifics for your describe.
	beforeEach(function (){
		//You don't need to ".andCallFake(function) here, just did it as an example.
		spyOn(tools.squeak, "writeListToFrontend").andCallFake(writeList);

		//See warning below in AddAction for as how to use this.  You'll need it a lot
		this.startActionCount = tools.squeak.getListOfActionsCount();
	});

	//All tests for addAction go in here
	describe("addAction", function() {
		//Test the base case
		it("should add an action", function() {
			tools.squeak.addAction(1, 1, 1, 2, "focus");
			var actionCount = tools.squeak.getListOfActionsCount();
			expect(actionCount).toEqual(1);
		});

		//Test an internal action gets done.
		it("should call writeListToFrontend", function() {
			tools.squeak.addAction(1, 1, 1, 2, "focus");
			expect(tools.squeak.writeListToFrontend).toHaveBeenCalled();
		});

		//Test error handling.
		it("should not throw an error unless an improper action is given", function() {
			expect(function(){tools.squeak.addAction(1, 1, 1, 2, "focus");}).not.toThrow()
			expect(function(){tools.squeak.addAction(1, 1, 1, 2, "flip-desk");}).toThrow()
		});

		//Check logic structures (where possible)
		it("should return false if start time is after end time", function() {
			var goodCall = tools.squeak.addAction(1, 1, 2, 2, "focus");
			var badCall = tools.squeak.addAction(1, 1, 3, 2, "focus");
			expect(goodCall).toEqual(true);
			expect(badCall).toEqual(false);
		});

		//WARNING: 	This is an example that shows a 'gotcha.'  Normally we want each of our
		//			tests to be atomic (aka, nothing bleeds over from one to the next), but
		//			as you can see the listOfActions value is accumulating over all the tests.
		it("should add several valid actions to the list of actions", function() {
			var actionCount = tools.squeak.getListOfActionsCount();
			expect(actionCount).toEqual(this.startActionCount); //From prior tests.  A better solution is below.
			tools.squeak.addAction(1, 1, 2, 2, "focus");
			tools.squeak.addAction(1, 1, 1, 2, "autoScroll");
			tools.squeak.addAction(1, 1, 2, 2, "strike");
			actionCount = tools.squeak.getListOfActionsCount() - this.startActionCount;
			expect(actionCount).toEqual(3); //Actual test done here.
		});

		it("should add multiple actions given multiple lines", function() {
			tools.squeak.addAction(1, 3, 1, 3, "focus");
			var actionCount = tools.squeak.getListOfActionsCount() - this.startActionCount;
			expect(actionCount).toEqual(3);
		});
	});

	//Delete Action
	describe("deleteAction", function() {
		it("should delete an action", function() {
			var tmpActionCount = tools.squeak.getListOfActionsCount();
			tools.squeak.deleteAction(1);
			var actionCount = tools.squeak.getListOfActionsCount();
			expect(actionCount).toEqual(tmpActionCount - 1);
		});

		it("should call writeListToFrontend", function() {
			tools.squeak.deleteAction(1);
			expect(tools.squeak.writeListToFrontend).toHaveBeenCalled();
		});

		it("should not throw an error unless an improper action is given", function() {
			expect(function(){tools.squeak.deleteAction(1);}).not.toThrow()
			expect(function(){tools.squeak.deleteAction("freak-out");}).toThrow()
		});

		it("should return false if id was not found", function() {
			var goodCall = tools.squeak.deleteAction(1);
			var badCall = tools.squeak.deleteAction(0);
			expect(goodCall).toEqual(true);
			expect(badCall).toEqual(false);
		});
	});

	//Undo
	describe("undo", function() {

	});

	//Publish
	describe("publish", function() {

	});
});<|endoftext|>


<commit_before>/**
 * This is the Socket.IO Router. It routes the Messages between the
 * components of the Server. The components are at the moment: pad and timeslider
 */

/*
 * 2011 Peter 'Pita' Martischka
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Saves all components
 * key is the component name
 * value is the component module
 */
var components = {};

var socket;

/**
 * adds a component
 */
exports.addComponent = function(moduleName, module)
{
  //save the component
  components[moduleName] = module;

  //give the module the socket
  module.setSocketIO(socket);
}

/**
 * sets the socket.io and adds event functions for routing
 */
exports.setSocketIO = function(_socket)
{
  //save this socket internaly
  socket = _socket;

  socket.on('connection', function(client)
  {
    //tell all components about this connect
    for(var i in components)
    {
      components[i].handleConnect(client);
    }

    client.on('message', function(message)
    {
      if(!message.protocolVersion|| message.protocolVersion != 2)
      {
        console.error("Protocolversion header is not correct:" + JSON.stringify(message));
        return;
      }

      //route this message to the correct component, if possible
      if(message.component && components[message.component])
      {
        console.error(message);

        //check if component is registered in the components array
        if(components[message.component])
        {
          components[message.component].handleMessage(client, message);
        }
      }
      else
      {
        console.error("Can't route the message:" + JSON.stringify(message));
      }
    });

    client.on('disconnect', function()
    {
       //tell all components about this disconnect
      for(var i in components)
      {
        components[i].handleDisconnect(client);
      }
    });
  });
}
<commit_msg>Check only Protocolversion of messages that have one<commit_after>/**
 * This is the Socket.IO Router. It routes the Messages between the
 * components of the Server. The components are at the moment: pad and timeslider
 */

/*
 * 2011 Peter 'Pita' Martischka
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Saves all components
 * key is the component name
 * value is the component module
 */
var components = {};

var socket;

/**
 * adds a component
 */
exports.addComponent = function(moduleName, module)
{
  //save the component
  components[moduleName] = module;

  //give the module the socket
  module.setSocketIO(socket);
}

/**
 * sets the socket.io and adds event functions for routing
 */
exports.setSocketIO = function(_socket)
{
  //save this socket internaly
  socket = _socket;

  socket.on('connection', function(client)
  {
    //tell all components about this connect
    for(var i in components)
    {
      components[i].handleConnect(client);
    }

    client.on('message', function(message)
    {
      if(message.protocolVersion && message.protocolVersion != 2)
      {
        console.error("Protocolversion header is not correct:" + JSON.stringify(message));
        return;
      }

      //route this message to the correct component, if possible
      if(message.component && components[message.component])
      {
        console.error(message);

        //check if component is registered in the components array
        if(components[message.component])
        {
          components[message.component].handleMessage(client, message);
        }
      }
      else
      {
        console.error("Can't route the message:" + JSON.stringify(message));
      }
    });

    client.on('disconnect', function()
    {
       //tell all components about this disconnect
      for(var i in components)
      {
        components[i].handleDisconnect(client);
      }
    });
  });
}
<|endoftext|>


<commit_before>(function (root, factory) {
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = factory(
      require('react/addons'),
      require('swipe-js-iso')
    );
  } else {
    root.ReactSwipe = factory(
      root.React,
      root.Swipe
    );
  }
})(this, function (React, Swipe) {
  var styles = {
    container: {
      overflow: 'hidden',
      visibility: 'hidden',
      position: 'relative'
    },

    wrapper: {
      overflow: 'hidden',
      position: 'relative'
    },

    child: {
      float: 'left',
      width: '100%',
      position: 'relative'
    }
  };

  var ReactSwipe = React.createClass({
    // https://github.com/thebird/Swipe#config-options
    propTypes: {
      startSlide      : React.PropTypes.number,
      slideToIndex    : React.PropTypes.number,
      shouldUpdate    : React.PropTypes.func,
      speed           : React.PropTypes.number,
      auto            : React.PropTypes.number,
      continuous      : React.PropTypes.bool,
      disableScroll   : React.PropTypes.bool,
      stopPropagation : React.PropTypes.bool,
      callback        : React.PropTypes.func,
      transitionEnd   : React.PropTypes.func
    },

    componentDidMount: function () {
      if (this.isMounted()) {
        this.swipe = Swipe(React.findDOMNode(this), this.props);
      }
    },

    componentDidUpdate: function () {
      if (this.props.slideToIndex || this.props.slideToIndex === 0) {
        this.swipe.slide(this.props.slideToIndex);
      }
    },

    componentWillUnmount: function () {
      this.swipe.kill();
      delete this.swipe;
    },

    shouldComponentUpdate: function (nextProps) {
      return (
        (this.props.slideToIndex !== nextProps.slideToIndex) ||
        (typeof this.props.shouldUpdate !== 'undefined') && this.props.shouldUpdate(nextProps)
      );
    },

    render: function() {
      return React.createElement('div', React.__spread({}, this.props, {style: styles.container}),
        React.createElement('div', {style: styles.wrapper},
          React.Children.map(this.props.children, function (child) {
            return React.addons.cloneWithProps(child, {style: styles.child});
          })
        )
      );
    }
  });

  return ReactSwipe;
});
<commit_msg>change for 0.12.x<commit_after>(function (root, factory) {
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = factory(
      require('react/addons'),
      require('swipe-js-iso')
    );
  } else {
    root.ReactSwipe = factory(
      root.React,
      root.Swipe
    );
  }
})(this, function (React, Swipe) {
  var styles = {
    container: {
      overflow: 'hidden',
      visibility: 'hidden',
      position: 'relative'
    },

    wrapper: {
      overflow: 'hidden',
      position: 'relative'
    },

    child: {
      float: 'left',
      width: '100%',
      position: 'relative'
    }
  };

  var ReactSwipe = React.createClass({
    // https://github.com/thebird/Swipe#config-options
    propTypes: {
      startSlide      : React.PropTypes.number,
      slideToIndex    : React.PropTypes.number,
      shouldUpdate    : React.PropTypes.func,
      speed           : React.PropTypes.number,
      auto            : React.PropTypes.number,
      continuous      : React.PropTypes.bool,
      disableScroll   : React.PropTypes.bool,
      stopPropagation : React.PropTypes.bool,
      callback        : React.PropTypes.func,
      transitionEnd   : React.PropTypes.func
    },

    componentDidMount: function () {
      if (this.isMounted()) {
        this.swipe = Swipe(this.getDOMNode(), this.props);
      }
    },

    componentDidUpdate: function () {
      if (this.props.slideToIndex || this.props.slideToIndex === 0) {
        this.swipe.slide(this.props.slideToIndex);
      }
    },

    componentWillUnmount: function () {
      this.swipe.kill();
      delete this.swipe;
    },

    shouldComponentUpdate: function (nextProps) {
      return (
        (this.props.slideToIndex !== nextProps.slideToIndex) ||
        (typeof this.props.shouldUpdate !== 'undefined') && this.props.shouldUpdate(nextProps)
      );
    },

    render: function() {
      return React.createElement('div', React.__spread({}, this.props, {style: styles.container}),
        React.createElement('div', {style: styles.wrapper},
          React.Children.map(this.props.children, function (child) {
            return React.addons.cloneWithProps(child, {style: styles.child});
          })
        )
      );
    }
  });

  return ReactSwipe;
});
<|endoftext|>


<commit_before>var request = require('request'),
    styles = require('./');

request(process.argv[2])
.pipe(styles({baseurl: process.argv[2]}))
.pipe(process.stdout);
<commit_msg>remove stray file<commit_after><|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var url = require('url');
var extend = require('extend');
var debug = require('debug')('cgi');
var spawn = require('child_process').spawn;
var CGIParser = require('./parser');

/**
 * Module exports.
 */

module.exports = cgi;

/**
 * Constants.
 */

var SERVER_SOFTWARE = 'Node/' + process.version;
var SERVER_PROTOCOL = 'HTTP/1.1';
var GATEWAY_INTERFACE = 'CGI/1.1';

function cgi(cgiBin, options) {
  options = extend({}, cgi.DEFAULTS, options);

  return function layer(req, res, next) {
    if (!next) {
      // define a default "next" handler if none was passed
      next = function(err) {
        debug('"next" called:', err);
        res.writeHead(404, { "Content-Type": "text/plain" });
        res.end("Not Found\n");
      };
    }
    if (!req.hasOwnProperty("uri")) { req.uri = url.parse(req.url); }
    if (req.uri.pathname.substring(0, options.mountPoint.length) !== options.mountPoint) return next();
    debug('handling HTTP request: %j', req.url);

    var host = (req.headers.host || '').split(':');
    var address = host[0];
    var port = host[1];
    if ((!address || !port) && typeof this.address == 'function') {
      debug('determining server address and port via address()');
      var serverAddress = this.address();
      if (!address) address = serverAddress.address;
      if (!port) port = serverAddress.port;
    }

    // Take environment variables from the current server process
    var env = extend({}, process.env);

    // Determine the correct PATH_INFO variable.
    // It must be prepended with a "/" char as per:
    //   https://tools.ietf.org/html/rfc3875#section-4.1.5
    var pathInfo = req.uri.pathname.substring(options.mountPoint.length);
    if ('/' !== pathInfo[0]) pathInfo = '/' + pathInfo;
    debug('calculated PATH_INFO variable: %s', pathInfo);

    // These meta-variables below can be overwritten by a
    // user's 'env' object in options
    extend(env, {
      GATEWAY_INTERFACE:  GATEWAY_INTERFACE,
      SCRIPT_NAME:        options.mountPoint,
      PATH_INFO:          pathInfo,
      SERVER_NAME:        address || 'unknown',
      SERVER_PORT:        port || 80,
      SERVER_PROTOCOL:    SERVER_PROTOCOL,
      SERVER_SOFTWARE:    SERVER_SOFTWARE
    });

    // The client HTTP request headers are attached to the env as well,
    // in the format: "User-Agent" -> "HTTP_USER_AGENT"
    for (var header in req.headers) {
      var name = 'HTTP_' + header.toUpperCase().replace(/-/g, '_');
      env[name] = req.headers[header];
    }

    // Now add the user-specified env variables
    if (options.env) extend(env, options.env);

    // These final environment variables take precedence over user-specified ones.
    env.REQUEST_METHOD = req.method;
    env.QUERY_STRING = req.uri.query || '';
    env.REMOTE_ADDR = req.connection.remoteAddress;
    env.REMOTE_PORT = req.connection.remotePort;
    if ('content-length' in req.headers) {
      env.CONTENT_LENGTH = req.headers['content-length'];
    }
    if ('content-type' in req.headers) {
      env.CONTENT_TYPE = req.headers['content-type'];
    }
    if ('authorization' in req.headers) {
      var auth = req.headers.authorization.split(' ');
      env.AUTH_TYPE = auth[0];
      //var unbase = new Buffer(auth[1], 'base64').toString().split(':');
    }

    // Now we can spawn the CGI executable
    debug('env: %j', env);
    var envDoc = {env: env};
    if (options.cwd !== undefined) envDoc.cwd = options.cwd;
    var cgiSpawn = spawn(cgiBin, options.args, envDoc);
    debug('cgi spawn (pid: %d)', cgiSpawn.pid);

    // The request body is piped to 'stdin' of the CGI spawn
    req.pipe(cgiSpawn.stdin);

    // If `options.stderr` is set to a Stream instance, then re-emit the
    // 'data' events onto the stream.
    var onData;
    if (options.stderr) {
      onData = function (chunk) {
        options.stderr.write(chunk);
      };
      cgiSpawn.stderr.on('data', onData);
    }

    // A proper CGI script is supposed to print headers to 'stdout'
    // followed by a blank line, then a response body.
    var cgiResult;
    if (!options.nph) {
      cgiResult = new CGIParser(cgiSpawn.stdout);

      // When the blank line after the headers has been parsed, then
      // the 'headers' event is emitted with a Headers instance.
      cgiResult.on('headers', function(headers) {
        headers.forEach(function(header) {
          // Don't set the 'Status' header. It's special, and should be
          // used to set the HTTP response code below.
          if (header.key === 'Status') return;
          res.setHeader(header.key, header.value);
        });

        // set the response status code
        res.statusCode = parseInt(headers.status, 10) || 200;

        // The response body is piped to the response body of the HTTP request
        cgiResult.pipe(res);
      });
    } else {
      // If it's an NPH script, then responsibility of the HTTP response is
      // completely passed off to the child process.
      cgiSpawn.stdout.pipe(res.connection);
    }

    cgiSpawn.on('exit', function(code, signal) {
      debug('cgi spawn %d "exit" event (code %s) (signal %s)', cgiSpawn.pid, code, signal);
      // TODO: react on a failure status code (dump stderr to the response?)
    });

    cgiSpawn.stdout.on('end', function () {
      // clean up event listeners upon the "end" event
      debug('cgi spawn %d stdout "end" event', cgiSpawn.pid);
      if (cgiResult) {
        cgiResult.cleanup();
      }
      if (onData) {
        options.stderr.removeListener('data', onData);
      }
    });
  };
}

// The default config options to use for each `cgi()` call.
cgi.DEFAULTS = {
  // The 'cgi' process working directory. If undefined current path is used
  cwd: undefined,
  // The 'cgi' handler will take effect when the req.url begins with "mountPoint"
  mountPoint: '/',
  // Any additional variables to insert into the CGI script's Environment
  env: {},
  // Set to 'true' if the CGI script is an NPH script
  nph: false,
  // Set to a `Stream` instance if you want to log stderr of the CGI script somewhere
  stderr: null,
  // A list of arguments for the cgi bin to be used by spawn
  args: []
};
<commit_msg>cgi: pass the `options` object directly to spawn()<commit_after>
/**
 * Module dependencies.
 */

var url = require('url');
var extend = require('extend');
var debug = require('debug')('cgi');
var spawn = require('child_process').spawn;
var CGIParser = require('./parser');

/**
 * Module exports.
 */

module.exports = cgi;

/**
 * Constants.
 */

var SERVER_SOFTWARE = 'Node/' + process.version;
var SERVER_PROTOCOL = 'HTTP/1.1';
var GATEWAY_INTERFACE = 'CGI/1.1';

function cgi(cgiBin, options) {
  options = extend({}, cgi.DEFAULTS, options);

  return function layer(req, res, next) {
    if (!next) {
      // define a default "next" handler if none was passed
      next = function(err) {
        debug('"next" called:', err);
        res.writeHead(404, { "Content-Type": "text/plain" });
        res.end("Not Found\n");
      };
    }
    if (!req.hasOwnProperty("uri")) { req.uri = url.parse(req.url); }
    if (req.uri.pathname.substring(0, options.mountPoint.length) !== options.mountPoint) return next();
    debug('handling HTTP request: %j', req.url);

    var host = (req.headers.host || '').split(':');
    var address = host[0];
    var port = host[1];
    if ((!address || !port) && typeof this.address == 'function') {
      debug('determining server address and port via address()');
      var serverAddress = this.address();
      if (!address) address = serverAddress.address;
      if (!port) port = serverAddress.port;
    }

    // Take environment variables from the current server process
    var env = extend({}, process.env);

    // Determine the correct PATH_INFO variable.
    // It must be prepended with a "/" char as per:
    //   https://tools.ietf.org/html/rfc3875#section-4.1.5
    var pathInfo = req.uri.pathname.substring(options.mountPoint.length);
    if ('/' !== pathInfo[0]) pathInfo = '/' + pathInfo;
    debug('calculated PATH_INFO variable: %s', pathInfo);

    // These meta-variables below can be overwritten by a
    // user's 'env' object in options
    extend(env, {
      GATEWAY_INTERFACE:  GATEWAY_INTERFACE,
      SCRIPT_NAME:        options.mountPoint,
      PATH_INFO:          pathInfo,
      SERVER_NAME:        address || 'unknown',
      SERVER_PORT:        port || 80,
      SERVER_PROTOCOL:    SERVER_PROTOCOL,
      SERVER_SOFTWARE:    SERVER_SOFTWARE
    });

    // The client HTTP request headers are attached to the env as well,
    // in the format: "User-Agent" -> "HTTP_USER_AGENT"
    for (var header in req.headers) {
      var name = 'HTTP_' + header.toUpperCase().replace(/-/g, '_');
      env[name] = req.headers[header];
    }

    // Now add the user-specified env variables
    if (options.env) extend(env, options.env);

    // These final environment variables take precedence over user-specified ones.
    env.REQUEST_METHOD = req.method;
    env.QUERY_STRING = req.uri.query || '';
    env.REMOTE_ADDR = req.connection.remoteAddress;
    env.REMOTE_PORT = req.connection.remotePort;
    if ('content-length' in req.headers) {
      env.CONTENT_LENGTH = req.headers['content-length'];
    }
    if ('content-type' in req.headers) {
      env.CONTENT_TYPE = req.headers['content-type'];
    }
    if ('authorization' in req.headers) {
      var auth = req.headers.authorization.split(' ');
      env.AUTH_TYPE = auth[0];
      //var unbase = new Buffer(auth[1], 'base64').toString().split(':');
    }

    // Now we can spawn the CGI executable
    debug('env: %j', env);
    options.env = env;

    var cgiSpawn = spawn(cgiBin, options.args, options);
    debug('cgi spawn (pid: %d)', cgiSpawn.pid);

    // The request body is piped to 'stdin' of the CGI spawn
    req.pipe(cgiSpawn.stdin);

    // If `options.stderr` is set to a Stream instance, then re-emit the
    // 'data' events onto the stream.
    var onData;
    if (options.stderr) {
      onData = function (chunk) {
        options.stderr.write(chunk);
      };
      cgiSpawn.stderr.on('data', onData);
    }

    // A proper CGI script is supposed to print headers to 'stdout'
    // followed by a blank line, then a response body.
    var cgiResult;
    if (!options.nph) {
      cgiResult = new CGIParser(cgiSpawn.stdout);

      // When the blank line after the headers has been parsed, then
      // the 'headers' event is emitted with a Headers instance.
      cgiResult.on('headers', function(headers) {
        headers.forEach(function(header) {
          // Don't set the 'Status' header. It's special, and should be
          // used to set the HTTP response code below.
          if (header.key === 'Status') return;
          res.setHeader(header.key, header.value);
        });

        // set the response status code
        res.statusCode = parseInt(headers.status, 10) || 200;

        // The response body is piped to the response body of the HTTP request
        cgiResult.pipe(res);
      });
    } else {
      // If it's an NPH script, then responsibility of the HTTP response is
      // completely passed off to the child process.
      cgiSpawn.stdout.pipe(res.connection);
    }

    cgiSpawn.on('exit', function(code, signal) {
      debug('cgi spawn %d "exit" event (code %s) (signal %s)', cgiSpawn.pid, code, signal);
      // TODO: react on a failure status code (dump stderr to the response?)
    });

    cgiSpawn.stdout.on('end', function () {
      // clean up event listeners upon the "end" event
      debug('cgi spawn %d stdout "end" event', cgiSpawn.pid);
      if (cgiResult) {
        cgiResult.cleanup();
      }
      if (onData) {
        options.stderr.removeListener('data', onData);
      }
    });
  };
}

// The default config options to use for each `cgi()` call.
cgi.DEFAULTS = {
  // The 'cgi' handler will take effect when the req.url begins with "mountPoint"
  mountPoint: '/',
  // Any additional variables to insert into the CGI script's Environment
  env: {},
  // Set to 'true' if the CGI script is an NPH script
  nph: false,
  // Set to a `Stream` instance if you want to log stderr of the CGI script somewhere
  stderr: null,
  // A list of arguments for the cgi bin to be used by spawn
  args: []
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

var FILE_NOT_FOUND = 'ENOENT'

var fs = require('fs')
var ldjson = require('ldjson-stream')
var through = require('through2')
var browserslist = require('browserslist')
var path = require('path')
var _ = require('lodash')

var formatBrowserName = require('./lib/util').formatBrowserName
var defaultBrowsers = require('./').default
var doiuse = require('./stream')

var yargs = require('yargs')
  .usage('Lint your CSS for browser support.')
  .example('cat FILE | $0 -b "ios >= 6"', '')
  .example('$0 --browsers "ie >= 9, > 1%, last 3 versions" [FILE] [FILE] ...', '')
  .example('$0 -b "ie >= 8" -b "> 1%" -b "last 3 versions" [FILE] [FILE] ...', '')
  .options('b', {
    alias: 'browsers',
    description: 'Autoprefixer-like browser criteria.',
    default: defaultBrowsers.join(', ')
  })
  .string('b')
  .options('i', {
    alias: 'ignore',
    description: 'List of features to ignore.',
    default: ''
  })
  .string('i')
  .options('l', {
    alias: 'list-only',
    description: 'Just show the browsers and features that would be tested by' +
      'the specified browser criteria, without actually processing any CSS.'
  })
  .options('c', {
    alias: 'config',
    description: 'Provide options through config file'
  })
  .string('verbose')
  .options('v', {
    alias: 'verbose',
    description: 'Verbose output. Multiple levels available.'
  })
  .count('verbose')
  .options('j', {
    alias: 'json',
    description: 'Output JSON instead of string linter-like messages.'
  })
  .boolean('j')
  .help('h', 'Show help message.')
  .alias('h', 'help')

var argv = yargs.argv

//Config file reading
if (argv.config) {
  try {
    var fileData = fs.readFileSync(path.resolve(argv.config), "utf8")
    var config = JSON.parse(fileData)
    _.forEach(_.keys(config), function(key) {
      var value = config[key]
      if (key == 'browsers') {
        if (_.isArray(value)) value = value.join(',')
      }

      argv[key] = value
    })
  } catch (err) {
    if (err.code === FILE_NOT_FOUND) console.error('Config file not found', err)
    else console.error(err)
  }
}

argv.browsers = argv.browsers.split(',').map(function (s) {return s.trim()})
argv.ignore = argv.ignore.split(',').map(function (s) {return s.trim()})
// Informational output
if (argv.l) { argv.v = ++argv.verbose }
if (argv.verbose >= 1) {
  var browsers = browserslist(argv.browsers)
    .map(function (b) {
      b = b.split(' ')
      b[0] = formatBrowserName(b[0])
      b[1] = parseInt(b[1], 10)
      return b
    })
    .sort(function (a, b) { return (a[0] !== b[0]) ? a[0] > b[0] : a[1] > b[1] })
    .map(function (b) { return b.join(' ') })
    .join(', ')
  console.log('[doiuse] Browsers: ' + browsers)
}

var out
if (argv.verbose >= 2) {
  var features = require('./')(argv.browsers).info().features
  console.log('\n[doiuse] Unsupported features:')
  for (var feat in features) {
    out = [features[feat].caniuseData.title]
    if (argv.verbose >= 3) {
      out.push('\n', features[feat].missing.join(', '), '\n')
    }
    console.log(out.join(''))
  }
}
if (argv.l) { process.exit() }

// Process the CSS
if (argv.help || (argv._.length === 0 && process.stdin.isTTY)) {
  yargs.showHelp()
  process.exit()
}

if (argv.json) {
  out = ldjson.serialize()
}
if (!argv.json) {
  out = through.obj(function (usage, enc, next) {
    next(null, usage.message + '\n')
  })
}
out.pipe(process.stdout)

if (argv._.length > 0) {
  argv._.forEach(function (file) {
    fs.createReadStream(file)
    .pipe(doiuse({ browsers: argv.browsers, ignore: argv.ignore }, file))
    .on('error', function (err) { console.error(err) })
    .pipe(out)
  })
} else {
  process.stdin
    .pipe(doiuse({ browsers: argv.browsers, ignore: argv.ignore }))
    .on('error', function (err) { console.error(err) })
    .pipe(out)
}
<commit_msg>another minor standart fix<commit_after>#!/usr/bin/env node

var FILE_NOT_FOUND = 'ENOENT'

var fs = require('fs')
var ldjson = require('ldjson-stream')
var through = require('through2')
var browserslist = require('browserslist')
var path = require('path')
var _ = require('lodash')

var formatBrowserName = require('./lib/util').formatBrowserName
var defaultBrowsers = require('./').default
var doiuse = require('./stream')

var yargs = require('yargs')
  .usage('Lint your CSS for browser support.')
  .example('cat FILE | $0 -b "ios >= 6"', '')
  .example('$0 --browsers "ie >= 9, > 1%, last 3 versions" [FILE] [FILE] ...', '')
  .example('$0 -b "ie >= 8" -b "> 1%" -b "last 3 versions" [FILE] [FILE] ...', '')
  .options('b', {
    alias: 'browsers',
    description: 'Autoprefixer-like browser criteria.',
    default: defaultBrowsers.join(', ')
  })
  .string('b')
  .options('i', {
    alias: 'ignore',
    description: 'List of features to ignore.',
    default: ''
  })
  .string('i')
  .options('l', {
    alias: 'list-only',
    description: 'Just show the browsers and features that would be tested by' +
      'the specified browser criteria, without actually processing any CSS.'
  })
  .options('c', {
    alias: 'config',
    description: 'Provide options through config file'
  })
  .string('verbose')
  .options('v', {
    alias: 'verbose',
    description: 'Verbose output. Multiple levels available.'
  })
  .count('verbose')
  .options('j', {
    alias: 'json',
    description: 'Output JSON instead of string linter-like messages.'
  })
  .boolean('j')
  .help('h', 'Show help message.')
  .alias('h', 'help')

var argv = yargs.argv

//  Config file reading
if (argv.config) {
  try {
    var fileData = fs.readFileSync(path.resolve(argv.config), 'utf8')
    var config = JSON.parse(fileData)
    _.forEach(_.keys(config), function (key) {
      var value = config[key]
      if (key === 'browsers') {
        if (_.isArray(value)) value = value.join(',')
      }

      argv[key] = value
    })
  } catch (err) {
    if (err.code === FILE_NOT_FOUND) console.error('Config file not found', err)
    else console.error(err)
  }
}

argv.browsers = argv.browsers.split(',').map(function (s) {return s.trim()})
argv.ignore = argv.ignore.split(',').map(function (s) {return s.trim()})
// Informational output
if (argv.l) { argv.v = ++argv.verbose }
if (argv.verbose >= 1) {
  var browsers = browserslist(argv.browsers)
    .map(function (b) {
      b = b.split(' ')
      b[0] = formatBrowserName(b[0])
      b[1] = parseInt(b[1], 10)
      return b
    })
    .sort(function (a, b) { return (a[0] !== b[0]) ? a[0] > b[0] : a[1] > b[1] })
    .map(function (b) { return b.join(' ') })
    .join(', ')
  console.log('[doiuse] Browsers: ' + browsers)
}

var out
if (argv.verbose >= 2) {
  var features = require('./')(argv.browsers).info().features
  console.log('\n[doiuse] Unsupported features:')
  for (var feat in features) {
    out = [features[feat].caniuseData.title]
    if (argv.verbose >= 3) {
      out.push('\n', features[feat].missing.join(', '), '\n')
    }
    console.log(out.join(''))
  }
}
if (argv.l) { process.exit() }

// Process the CSS
if (argv.help || (argv._.length === 0 && process.stdin.isTTY)) {
  yargs.showHelp()
  process.exit()
}

if (argv.json) {
  out = ldjson.serialize()
}
if (!argv.json) {
  out = through.obj(function (usage, enc, next) {
    next(null, usage.message + '\n')
  })
}
out.pipe(process.stdout)

if (argv._.length > 0) {
  argv._.forEach(function (file) {
    fs.createReadStream(file)
    .pipe(doiuse({ browsers: argv.browsers, ignore: argv.ignore }, file))
    .on('error', function (err) { console.error(err) })
    .pipe(out)
  })
} else {
  process.stdin
    .pipe(doiuse({ browsers: argv.browsers, ignore: argv.ignore }))
    .on('error', function (err) { console.error(err) })
    .pipe(out)
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
/**
 * Kotatsu CLI
 * ============
 *
 * The CLI tool that will call the lib's function.
 */
var kotatsu = require('./kotatsu.js'),
    red = require('chalk').red,
    yargs = require('yargs'),
    path = require('path'),
    pkg = require('./package.json');

// Handling ES6 configuration
require('babel-core/register')({
  only: /\.babel\.js/,
  presets: ['es2015']
});

var CWD = process.cwd();

var COMMANDS = [
  'start',
  'serve',
  'monitor',
  'run',
  'build'
];

var EXPECTED_PARTS = 2;

var USAGE = 'Usage: kotatsu <command> {options} [entry]',
    AVAILABLE_COMMANDS = 'Available commands: ' + COMMANDS.join(', ');

function error(message, details) {
  throw Error('\n' + red('Error: ' + message) + (details ? '\n' + details : ''));
}

var webpackConfig = {},
    entry = null,
    command,
    side;

// Building the CLI
var argv = yargs
  .locale('en')
  .wrap(100)
  .usage(USAGE)
  .check(function(argv) {
    command = argv._[0];

    if (!argv._.length)
      error('Not enough arguments.', [
        USAGE,
        AVAILABLE_COMMANDS
      ].join('\n'));

    if (!Number.isInteger(argv.port))
      error('Invalid port: ' + argv.port);

    if (!~COMMANDS.indexOf(command))
      error(
        'Invalid command: ' + command,
        AVAILABLE_COMMANDS
      );

    // Should we load a config file?
    if (argv.config) {
      try {
        var configPath = require.resolve(path.join(process.cwd(), argv.config));
        webpackConfig = require(configPath);

        // Handling ES6 export
        if ('default' in webpackConfig)
          webpackConfig = webpackConfig.default;
      }
      catch (e) {
        error(
          'Error while loading your config file: "' + argv.config + '".',
          e.stack || ''
        );
      }

      if (webpackConfig.entry)
        EXPECTED_PARTS--;
    }

    // Build specifics
    if (command === 'build') {
      EXPECTED_PARTS++;

      if (argv._.length < EXPECTED_PARTS)
        error('The "build" command takes 2 arguments: client or server, and the entry.');

      if (!~['client', 'server'].indexOf(argv._[1]))
        error('Do you want to build for client or server? You gave: "' + argv._[1] + '".');

      side = argv._[1] === 'client' ? 'front' : 'back';
      entry = argv._[2];
    }
    else {
      if (argv._.length < EXPECTED_PARTS)
        error('Expecting two arguments: the command and the path to your entry.');

      entry = argv._[1];
    }

    // Attempting to resolve our entry
    if (entry) {
      entry = path.resolve(CWD, entry);

      try {
        require.resolve(entry);
      }
      catch (e) {
        error('Could not resolve your entry: "' + argv._[1] + '".', e.stack);
      }
    }

    return true;
  })

  // Commands
  .command('start', 'Start a node.js script.')
  .command('serve', 'Serve a client-side application.')
  .command('', '---')
  .command('monitor', 'Monitor a terminating node.js script.')
  .command('run', 'Run the given node.js script.')
  .command('build', 'Build your code for client or server.')

  // Generic options
  .option('c', {
    alias: 'config',
    describe: 'Optional webpack config that will be merged with kotatsu\'s one (useful if you need specific loaders).'
  })
  .option('d', {
    alias: 'devtool',
    describe: 'Webpack devtool spec to use to compute source maps.',
    type: 'string'
  })
  .option('m', {
    alias: 'mount-node',
    describe: 'Id of the mount node in the generated HMTL index.',
    type: 'string'
  })
  .option('o', {
    alias: 'output',
    describe: 'Output path (either directory or filename).',
    type: 'string'
  })
  .option('p', {
    alias: 'port',
    describe: 'Port that the server should listen to.',
    default: 3000
  })
  .option('s', {
    alias: 'source-maps',
    describe: 'Should source maps be computed for easier debugging?',
    type: 'boolean',
    default: false
  })
  .option('babel', {
    describe: 'Use Babel to compile the files.',
    type: 'boolean',
    default: false
  })
  .option('es2015', {
    describe: 'Is your code written in ES2015?',
    type: 'boolean',
    default: false
  })
  .option('index', {
    describe: 'Path to a custom HMTL index file.',
    type: 'string'
  })
  .option('jsx', {
    describe: 'Does your code uses JSX syntax?',
    type: 'boolean',
    default: false
  })
  .option('minify', {
    describe: 'Minify the bundle.',
    type: 'boolean',
    default: false
  })
  .option('pragma', {
    describe: 'JSX pragma.',
    type: 'string'
  })
  .option('presets', {
    describe: 'Babel 6 presets separated by a comma (example: es2015,react).',
    type: 'string'
  })
  .option('progress', {
    describe: 'Should it display the compilation\'s progress?',
    type: 'boolean',
    default: false
  })
  .option('proxy', {
    describe: 'Proxy information (example: /api http://localhost:4000)',
    type: 'string',
    nargs: 2
  })
  .option('public', {
    describe: 'Path to a public folder (can be used multiple times).',
    type: 'string'
  })
  .option('quiet', {
    describe: 'Disable logs.',
    type: 'boolean',
    default: false
  })

  // Examples
  .example('kotatsu start script.js', 'Launching the given script with HMR.')
  .example('kotatsu start --es2015 scripts.js', 'Launching a ES2015 script.')
  .example('kotatsu start -c webpack.config.js script.js', 'Using a specific webpack config.')
  .example('kotatsu start --source-maps script.js', 'Computing source maps.')
  .example('kotatsu start script.js -- --path test.js', 'Passing arguments to the script.')
  .example('')
  .example('kotatsu serve entry.js', 'Serving the given app.')
  .example('kotatsu serve --es2015 --jsx entry.jsx', 'Serving the given ES2015 & JSX app.')
  .example('kotatsu serve --port 8000 entry.jsx', 'Serving the app on a different port.')
  .example('kotatsu serve --babel entry.js', 'Enable Babel to use .babelrc files.')
  .example('kotatsu serve --proxy /api http://localhost:4000', 'Proxying an API.')
  .example('')
  .example('kotatsu build server --es2015 entry.js -o ./', 'Build the given script.')
  .example('kotatsu build client entry.js -o build', 'Build the given client app.')

  // Help & Version
  .version(pkg.version)
  .help('h')
  .alias('h', 'help')
  .showHelpOnFail(false, 'Use the --help option to get the list of available options.')
  .epilogue('Repository: ' + pkg.repository.url)
  .argv;

var publicPaths = argv.public ?
  [].concat(argv.public).map(function(p) {
    return path.resolve(CWD, p);
  }) :
  null;

var opts = {
  args: argv._.slice(EXPECTED_PARTS),
  babel: argv.babel,
  cwd: CWD,
  config: webpackConfig,
  devtool: argv.devtool,
  entry: entry ? path.resolve(CWD, entry) : null,
  es2015: argv.es2015,
  index: argv.index ? path.resolve(CWD, argv.index) : null,
  public: publicPaths,
  jsx: argv.jsx,
  minify: argv.minify,
  mountNode: argv.mountNode,
  output: argv.output ? path.resolve(CWD, argv.output) : null,
  port: argv.port,
  pragma: argv.pragma,
  presets: argv.presets ? argv.presets.split(',') : null,
  progress: argv.progress,
  proxy: argv.proxy,
  quiet: argv.quiet,
  sourceMaps: argv.sourceMaps
};

// Cleaning null values
for (var k in opts)
  if (opts[k] === null || opts[k] === undefined)
    delete opts[k];

// Applying the correct method.
if (command === 'build')
  kotatsu.build(side, opts);
else
  kotatsu[command](opts);
<commit_msg>Fixing lint<commit_after>#!/usr/bin/env node
/* eslint no-shadow: 0 */
/**
 * Kotatsu CLI
 * ============
 *
 * The CLI tool that will call the lib's function.
 */
var kotatsu = require('./kotatsu.js'),
    red = require('chalk').red,
    yargs = require('yargs'),
    path = require('path'),
    pkg = require('./package.json');

// Handling ES6 configuration
require('babel-core/register')({
  only: /\.babel\.js/,
  presets: ['es2015']
});

var CWD = process.cwd();

var COMMANDS = [
  'start',
  'serve',
  'monitor',
  'run',
  'build'
];

var EXPECTED_PARTS = 2;

var USAGE = 'Usage: kotatsu <command> {options} [entry]',
    AVAILABLE_COMMANDS = 'Available commands: ' + COMMANDS.join(', ');

function error(message, details) {
  throw Error('\n' + red('Error: ' + message) + (details ? '\n' + details : ''));
}

var webpackConfig = {},
    entry = null,
    command,
    side;

// Building the CLI
var argv = yargs
  .locale('en')
  .wrap(100)
  .usage(USAGE)
  .check(function(argv) {
    command = argv._[0];

    if (!argv._.length)
      error('Not enough arguments.', [
        USAGE,
        AVAILABLE_COMMANDS
      ].join('\n'));

    if (!Number.isInteger(argv.port))
      error('Invalid port: ' + argv.port);

    if (!~COMMANDS.indexOf(command))
      error(
        'Invalid command: ' + command,
        AVAILABLE_COMMANDS
      );

    // Should we load a config file?
    if (argv.config) {
      try {
        var configPath = require.resolve(path.join(process.cwd(), argv.config));
        webpackConfig = require(configPath);

        // Handling ES6 export
        if ('default' in webpackConfig)
          webpackConfig = webpackConfig.default;
      }
      catch (e) {
        error(
          'Error while loading your config file: "' + argv.config + '".',
          e.stack || ''
        );
      }

      if (webpackConfig.entry)
        EXPECTED_PARTS--;
    }

    // Build specifics
    if (command === 'build') {
      EXPECTED_PARTS++;

      if (argv._.length < EXPECTED_PARTS)
        error('The "build" command takes 2 arguments: client or server, and the entry.');

      if (!~['client', 'server'].indexOf(argv._[1]))
        error('Do you want to build for client or server? You gave: "' + argv._[1] + '".');

      side = argv._[1] === 'client' ? 'front' : 'back';
      entry = argv._[2];
    }
    else {
      if (argv._.length < EXPECTED_PARTS)
        error('Expecting two arguments: the command and the path to your entry.');

      entry = argv._[1];
    }

    // Attempting to resolve our entry
    if (entry) {
      entry = path.resolve(CWD, entry);

      try {
        require.resolve(entry);
      }
      catch (e) {
        error('Could not resolve your entry: "' + argv._[1] + '".', e.stack);
      }
    }

    return true;
  })

  // Commands
  .command('start', 'Start a node.js script.')
  .command('serve', 'Serve a client-side application.')
  .command('', '---')
  .command('monitor', 'Monitor a terminating node.js script.')
  .command('run', 'Run the given node.js script.')
  .command('build', 'Build your code for client or server.')

  // Generic options
  .option('c', {
    alias: 'config',
    describe: 'Optional webpack config that will be merged with kotatsu\'s one (useful if you need specific loaders).'
  })
  .option('d', {
    alias: 'devtool',
    describe: 'Webpack devtool spec to use to compute source maps.',
    type: 'string'
  })
  .option('m', {
    alias: 'mount-node',
    describe: 'Id of the mount node in the generated HMTL index.',
    type: 'string'
  })
  .option('o', {
    alias: 'output',
    describe: 'Output path (either directory or filename).',
    type: 'string'
  })
  .option('p', {
    alias: 'port',
    describe: 'Port that the server should listen to.',
    default: 3000
  })
  .option('s', {
    alias: 'source-maps',
    describe: 'Should source maps be computed for easier debugging?',
    type: 'boolean',
    default: false
  })
  .option('babel', {
    describe: 'Use Babel to compile the files.',
    type: 'boolean',
    default: false
  })
  .option('es2015', {
    describe: 'Is your code written in ES2015?',
    type: 'boolean',
    default: false
  })
  .option('index', {
    describe: 'Path to a custom HMTL index file.',
    type: 'string'
  })
  .option('jsx', {
    describe: 'Does your code uses JSX syntax?',
    type: 'boolean',
    default: false
  })
  .option('minify', {
    describe: 'Minify the bundle.',
    type: 'boolean',
    default: false
  })
  .option('pragma', {
    describe: 'JSX pragma.',
    type: 'string'
  })
  .option('presets', {
    describe: 'Babel 6 presets separated by a comma (example: es2015,react).',
    type: 'string'
  })
  .option('progress', {
    describe: 'Should it display the compilation\'s progress?',
    type: 'boolean',
    default: false
  })
  .option('proxy', {
    describe: 'Proxy information (example: /api http://localhost:4000)',
    type: 'string',
    nargs: 2
  })
  .option('public', {
    describe: 'Path to a public folder (can be used multiple times).',
    type: 'string'
  })
  .option('quiet', {
    describe: 'Disable logs.',
    type: 'boolean',
    default: false
  })

  // Examples
  .example('kotatsu start script.js', 'Launching the given script with HMR.')
  .example('kotatsu start --es2015 scripts.js', 'Launching a ES2015 script.')
  .example('kotatsu start -c webpack.config.js script.js', 'Using a specific webpack config.')
  .example('kotatsu start --source-maps script.js', 'Computing source maps.')
  .example('kotatsu start script.js -- --path test.js', 'Passing arguments to the script.')
  .example('')
  .example('kotatsu serve entry.js', 'Serving the given app.')
  .example('kotatsu serve --es2015 --jsx entry.jsx', 'Serving the given ES2015 & JSX app.')
  .example('kotatsu serve --port 8000 entry.jsx', 'Serving the app on a different port.')
  .example('kotatsu serve --babel entry.js', 'Enable Babel to use .babelrc files.')
  .example('kotatsu serve --proxy /api http://localhost:4000', 'Proxying an API.')
  .example('')
  .example('kotatsu build server --es2015 entry.js -o ./', 'Build the given script.')
  .example('kotatsu build client entry.js -o build', 'Build the given client app.')

  // Help & Version
  .version(pkg.version)
  .help('h')
  .alias('h', 'help')
  .showHelpOnFail(false, 'Use the --help option to get the list of available options.')
  .epilogue('Repository: ' + pkg.repository.url)
  .argv;

var publicPaths = argv.public ?
  [].concat(argv.public).map(function(p) {
    return path.resolve(CWD, p);
  }) :
  null;

var opts = {
  args: argv._.slice(EXPECTED_PARTS),
  babel: argv.babel,
  cwd: CWD,
  config: webpackConfig,
  devtool: argv.devtool,
  entry: entry ? path.resolve(CWD, entry) : null,
  es2015: argv.es2015,
  index: argv.index ? path.resolve(CWD, argv.index) : null,
  public: publicPaths,
  jsx: argv.jsx,
  minify: argv.minify,
  mountNode: argv.mountNode,
  output: argv.output ? path.resolve(CWD, argv.output) : null,
  port: argv.port,
  pragma: argv.pragma,
  presets: argv.presets ? argv.presets.split(',') : null,
  progress: argv.progress,
  proxy: argv.proxy,
  quiet: argv.quiet,
  sourceMaps: argv.sourceMaps
};

// Cleaning null values
for (var k in opts)
  if (opts[k] === null || opts[k] === undefined)
    delete opts[k];

// Applying the correct method.
if (command === 'build')
  kotatsu.build(side, opts);
else
  kotatsu[command](opts);
<|endoftext|>


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

var pkg = require('./package')
var db = require('./lib/db')

var argv = require('minimist')(process.argv.slice(2))

if (argv.update || argv.u) {
  require('./lib/update')(argv)
} else if (argv.version || argv.v) {
  version()
} else if (argv.help || argv.h) {
  usage()
} else if (!db.existsSync()) {
  noCache()
} else if (argv._.length > 0) {
  require('./lib/query').apply(null, argv._)
} else {
  usage(1)
}

function version () {
  console.log(pkg.version)
  process.exit()
}

function usage (code) {
  console.log('Usage:')
  console.log('  %s <options> | <name> [range]', pkg.name)
  console.log()
  console.log('Options:')
  console.log('  --version, -v  output version')
  console.log('  --help, -h     output this help')
  console.log('  --update, -u   update the local cache')
  console.log()
  console.log('Examples:')
  console.log('  %s --update', pkg.name)
  console.log('  %s bluebird ^2.0.0', pkg.name)
  process.exit(Number.isFinite(code) ? code : 0)
}

function noCache () {
  console.log('ERROR: Could not find a local cache at', db.path)
  console.log()
  console.log('Ensure that you update the local cache at least once via:')
  console.log('  %s --update', pkg.name)
  console.log()
  console.log('This will take a while!')
  process.exit(1)
}
<commit_msg>Code cleanup<commit_after>#!/usr/bin/env node
'use strict'

var pkg = require('./package')
var db = require('./lib/db')

var argv = require('minimist')(process.argv.slice(2))

if (argv.update || argv.u) {
  require('./lib/update')(argv)
} else if (argv.version || argv.v) {
  version()
} else if (argv.help || argv.h) {
  usage()
} else if (!db.existsSync()) {
  noCache()
} else if (argv._.length > 0) {
  require('./lib/query').apply(null, argv._)
} else {
  usage(1)
}

function version () {
  console.log(pkg.version)
  process.exit()
}

function usage (code) {
  console.log('Usage:')
  console.log('  %s <options> | <name> [range]', pkg.name)
  console.log()
  console.log('Options:')
  console.log('  --version, -v  output version')
  console.log('  --help, -h     output this help')
  console.log('  --update, -u   update the local cache')
  console.log()
  console.log('Examples:')
  console.log('  %s --update', pkg.name)
  console.log('  %s bluebird ^2.0.0', pkg.name)
  process.exit(code || 0)
}

function noCache () {
  console.log('ERROR: Could not find a local cache at', db.path)
  console.log()
  console.log('Ensure that you update the local cache at least once via:')
  console.log('  %s --update', pkg.name)
  console.log()
  console.log('This will take a while!')
  process.exit(1)
}
<|endoftext|>


<commit_before>var   fs = require('fs'),
commands = require('./lib/commands')

function usage() {
    return "Usage: pig COMMAND SERVICE [& args]\n\n" +
           "Commands:\n" +
           "  start   Start named service. \n" +
           "  stop    Stop named service\n" +
           "  up      Start all daemons from pig.json\n" +
           "  down    Stop all daemons in pig.json\n" +
           "  bash    Attach /bin/bash to named service (for debug)\n"
}

function main(args) {
    var containers = JSON.parse(fs.readFileSync('pig.json'))

    var command = args[0]
    var name = args[1]

    var dockerCommandArgs = args.slice(2)

    function container() {
        if (!name) {
            throw new Error(usage())
        }

        var container = containers[name]
        if (!container) {
            throw new Error('Service \'' + name + '\' is not configured in pig.json')
        }

        return container
    }

    switch (command) {
        case "start":
            commands.start(container(), containers, dockerCommandArgs)
            break

        case "stop":
            commands.stop(container(), containers)
            break

        case "bash":
            commands.bash(container(), containers)
            break

        case "up":
            commands.startDaemons(containers)
            break

        case "down":
            commands.stopDaemons(containers)
            break

        case undefined:
            throw new Error(usage())

        default:
            throw new Error('Unknown command \'' + command + '\'\n' + usage())
    }
}

module.exports.main = function() {
    try {
        var cmdArgs = process.argv.slice(2)
        main(cmdArgs)
    } catch (e) {
        process.stderr.write('error: ' + e.message + '\n')
    }
}
<commit_msg>Handle errors from pig start in cli<commit_after>var   fs = require('fs'),
commands = require('./lib/commands')

function usage() {
    return "Usage: pig COMMAND SERVICE [& args]\n\n" +
           "Commands:\n" +
           "  start   Start named service. \n" +
           "  stop    Stop named service\n" +
           "  up      Start all daemons from pig.json\n" +
           "  down    Stop all daemons in pig.json\n" +
           "  bash    Attach /bin/bash to named service (for debug)\n"
}

function main(args) {
    var containers = JSON.parse(fs.readFileSync('pig.json'))

    var command = args[0]
    var name = args[1]

    var dockerCommandArgs = args.slice(2)

    function container() {
        if (!name) {
            throw new Error(usage())
        }

        var container = containers[name]
        if (!container) {
            throw new Error('Service \'' + name + '\' is not configured in pig.json')
        }

        return container
    }

    switch (command) {
        case "start":
            commands.start(container(), containers, dockerCommandArgs, {}, handleError)
            break

        case "stop":
            commands.stop(container(), containers)
            break

        case "bash":
            commands.bash(container(), containers)
            break

        case "up":
            commands.startDaemons(containers)
            break

        case "down":
            commands.stopDaemons(containers)
            break

        case undefined:
            throw new Error(usage())

        default:
            throw new Error('Unknown command \'' + command + '\'\n' + usage())
    }
}

function handleError(err) {
    if (err) {
        process.stderr.write('error: ' + e.message + '\n')
    }
}

module.exports.main = function() {
    try {
        var cmdArgs = process.argv.slice(2)
        main(cmdArgs)
    } catch (e) {
        handleError(err)
    }
}
<|endoftext|>