<commit_before>import React from 'react';
import Relay from 'react-relay';

import Menu from '../shared/Menu';
import Icon from '../shared/Icon';
import permissions from '../../lib/permissions';

class SettingsMenu extends React.Component {
  static propTypes = {
    organization: React.PropTypes.shape({
      name: React.PropTypes.string.isRequired,
      slug: React.PropTypes.string.isRequired,
      members: React.PropTypes.shape({
        count: React.PropTypes.number.isRequired
      }).isRequired,
      invitations: React.PropTypes.shape({
        count: React.PropTypes.number.isRequired
      }).isRequired,
      teams: React.PropTypes.shape({
        count: React.PropTypes.number.isRequired
      }).isRequired,
      permissions: React.PropTypes.shape({
        organizationUpdate: React.PropTypes.shape({
          allowed: React.PropTypes.bool.isRequired
        }).isRequired,
        organizationInvitationCreate: React.PropTypes.shape({
          allowed: React.PropTypes.bool.isRequired
        }).isRequired,
        teamAdmin: React.PropTypes.shape({
          allowed: React.PropTypes.bool.isRequired
        }).isRequired,
        notificationServiceUpdate: React.PropTypes.shape({
          allowed: React.PropTypes.bool.isRequired
        }).isRequired,
        organizationBillingUpdate: React.PropTypes.shape({
          allowed: React.PropTypes.bool.isRequired
        }).isRequired
      })
    })
  };

  render() {
    return (

        <Menu>
          <Menu.Header>{this.props.organization.name}</Menu.Header>
          {this.renderButtons()}
        </Menu>

        <Menu>
          <Menu.Button href={`/user/settings`}>Personal Settings</Menu.Button>
        </Menu>

    );
  }

  renderButtons() {
    return permissions(this.props.organization.permissions).collect(
      {
        allowed: "organizationUpdate",
        render: (idx) => (
          <Menu.Button key={idx} href={`/organizations/${this.props.organization.slug}/settings`}>
            <Icon icon="settings" className="icon-mr"/>Settings
          </Menu.Button>
        )
      },
      {
        allowed: "organizationInvitationCreate",
        render: (idx) => (
          <Menu.Button key={idx} href={`/organizations/${this.props.organization.slug}/users`} badge={this.props.organization.members.count + this.props.organization.invitations.count}>
            <Icon icon="users" className="icon-mr"/>Users
          </Menu.Button>
        )
      },
      {
        allowed: "teamAdmin",
        render: (idx) => (
          <Menu.Button key={idx} link={`/organizations/${this.props.organization.slug}/teams`} badge={this.props.organization.teams.count}>
            <Icon icon="teams" className="icon-mr"/>Teams
          </Menu.Button>
        )
      },
      {
        allowed: "notificationServiceUpdate",
        render: (idx) => (
          <Menu.Button key={idx} href={`/organizations/${this.props.organization.slug}/services`}>
            <Icon icon="notification-services" className="icon-mr"/>Notification Services
          </Menu.Button>
        )
      },
      {
        allowed: "organizationBillingUpdate",
        render: (idx) => (
          <Menu.Button key={idx} href={`/organizations/${this.props.organization.slug}/billing`}>
            <Icon icon="billing" className="icon-mr"/>Billing
          </Menu.Button>
        )
      }
    );
  }
}

export default Relay.createContainer(SettingsMenu, {
  fragments: {
    organization: () => Relay.QL`
      fragment on Organization {
        name
        slug
        members {
          count
        }
        invitations {
          count
        }
        teams {
          count
        }
        permissions {
          organizationUpdate {
            allowed
          }
          organizationInvitationCreate {
            allowed
          }
          notificationServiceUpdate {
            allowed
          }
          organizationBillingUpdate {
            allowed
          }
          teamAdmin {
            allowed
          }
        }
      }
    `
  }
});
<commit_msg>Whoops, forgot to scope to `state: PENDING` here<commit_after>import React from 'react';
import Relay from 'react-relay';

import Menu from '../shared/Menu';
import Icon from '../shared/Icon';
import permissions from '../../lib/permissions';

class SettingsMenu extends React.Component {
  static propTypes = {
    organization: React.PropTypes.shape({
      name: React.PropTypes.string.isRequired,
      slug: React.PropTypes.string.isRequired,
      members: React.PropTypes.shape({
        count: React.PropTypes.number.isRequired
      }).isRequired,
      invitations: React.PropTypes.shape({
        count: React.PropTypes.number.isRequired
      }).isRequired,
      teams: React.PropTypes.shape({
        count: React.PropTypes.number.isRequired
      }).isRequired,
      permissions: React.PropTypes.shape({
        organizationUpdate: React.PropTypes.shape({
          allowed: React.PropTypes.bool.isRequired
        }).isRequired,
        organizationInvitationCreate: React.PropTypes.shape({
          allowed: React.PropTypes.bool.isRequired
        }).isRequired,
        teamAdmin: React.PropTypes.shape({
          allowed: React.PropTypes.bool.isRequired
        }).isRequired,
        notificationServiceUpdate: React.PropTypes.shape({
          allowed: React.PropTypes.bool.isRequired
        }).isRequired,
        organizationBillingUpdate: React.PropTypes.shape({
          allowed: React.PropTypes.bool.isRequired
        }).isRequired
      })
    })
  };

  render() {
    return (

        <Menu>
          <Menu.Header>{this.props.organization.name}</Menu.Header>
          {this.renderButtons()}
        </Menu>

        <Menu>
          <Menu.Button href={`/user/settings`}>Personal Settings</Menu.Button>
        </Menu>

    );
  }

  renderButtons() {
    return permissions(this.props.organization.permissions).collect(
      {
        allowed: "organizationUpdate",
        render: (idx) => (
          <Menu.Button key={idx} href={`/organizations/${this.props.organization.slug}/settings`}>
            <Icon icon="settings" className="icon-mr"/>Settings
          </Menu.Button>
        )
      },
      {
        allowed: "organizationInvitationCreate",
        render: (idx) => (
          <Menu.Button key={idx} href={`/organizations/${this.props.organization.slug}/users`} badge={this.props.organization.members.count + this.props.organization.invitations.count}>
            <Icon icon="users" className="icon-mr"/>Users
          </Menu.Button>
        )
      },
      {
        allowed: "teamAdmin",
        render: (idx) => (
          <Menu.Button key={idx} link={`/organizations/${this.props.organization.slug}/teams`} badge={this.props.organization.teams.count}>
            <Icon icon="teams" className="icon-mr"/>Teams
          </Menu.Button>
        )
      },
      {
        allowed: "notificationServiceUpdate",
        render: (idx) => (
          <Menu.Button key={idx} href={`/organizations/${this.props.organization.slug}/services`}>
            <Icon icon="notification-services" className="icon-mr"/>Notification Services
          </Menu.Button>
        )
      },
      {
        allowed: "organizationBillingUpdate",
        render: (idx) => (
          <Menu.Button key={idx} href={`/organizations/${this.props.organization.slug}/billing`}>
            <Icon icon="billing" className="icon-mr"/>Billing
          </Menu.Button>
        )
      }
    );
  }
}

export default Relay.createContainer(SettingsMenu, {
  fragments: {
    organization: () => Relay.QL`
      fragment on Organization {
        name
        slug
        members {
          count
        }
        invitations(state: PENDING) {
          count
        }
        teams {
          count
        }
        permissions {
          organizationUpdate {
            allowed
          }
          organizationInvitationCreate {
            allowed
          }
          notificationServiceUpdate {
            allowed
          }
          organizationBillingUpdate {
            allowed
          }
          teamAdmin {
            allowed
          }
        }
      }
    `
  }
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';

// ======================================================
// Containers
// ======================================================
import { FooterAction } from '../../Utils';
// ======================================================
// Components
// ======================================================
import { Layout, EventTitle, InputWithPad } from '../../../components';
// ======================================================
// Actions
// ======================================================
import * as ApplicationActions from '../../../actions/applicationActions';
import * as Actions from './actions';
// ======================================================
// Selectors
// ======================================================
import MasterappSelector from '../../../selectors/masterapp';
import OrderSelectors from '../../../selectors/order';
// ======================================================
// Helpers
// ======================================================
import { isEmpty } from '../../../helpers/global';

import lineId from '../../../images/line-id.png';

const mapStateToProps = state => ({
  baseURL: MasterappSelector.getBaseURL(state.masterapp),
  selectedEvent: OrderSelectors.getSelectedEvent(state.order),
  nextInput: OrderSelectors.getEventNextInput(state.order),
});

const actions = {
  ...ApplicationActions,
  ...Actions,
};

const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);

class EventPlayPage extends Component {
  static propTypes = {
    baseURL: PropTypes.string.isRequired,
    selectedEvent: PropTypes.shape({}),
    nextInput: PropTypes.string,
    submitPlayEvent: PropTypes.func.isRequired,
    updateEventInput: PropTypes.func.isRequired,
  };

  static defaultProps = {
    selectedEvent: {},
    nextInput: '',
  };

  componentWillReceiveProps = nextProps => {
    const { submitPlayEvent } = this.props;
    if (isEmpty(nextProps.nextInput)) submitPlayEvent();
  };

  handleSubmitPage = inputValue => {
    const { nextInput, updateEventInput } = this.props;
    // ======================================================
    // Update nextInput
    // ======================================================
    updateEventInput(nextInput, inputValue);
  };

  renderInputMSISDN = () => (

ใส่ เบอร์มือถือ ของคุณ

            กรุณาตรวจสอบ หมายเลขโทรศัพท์ ให้ถูกต้อง

          <InputWithPad
            type={'num'}
            rules={{
              required: 'กรุณาระบุหมายเลขโทรศัพท์',
              mobileNumber: 'รูปแบบหมายเลขโทรศัพท์ไม่ถูกต้อง',
            }}
            onConfirm={this.handleSubmitPage}
          />

  );

  renderInputEmail = () => (

ใส่ อีเมล ของคุณ

            กรุณาตรวจสอบ อีเมล ให้ถูกต้อง

          <InputWithPad
            type={'keyboard'}
            rules={{
              required: 'กรุณาระบุอีเมล',
              email: 'รูปแบบอีเมลไม่ถูกต้อง',
            }}
            isFixed
            onConfirm={this.handleSubmitPage}
          />

  );

  renderInputLineId = () => {
    const { submitPlayEvent } = this.props;
    return (

กรุณาแสกน LINE QR CODE

เมื่อได้รับรหัสส่วนลดแล้ว กดปุ่มทำรายการต่อ

ทำรายการต่อ

    );
  };

  renderInputBarcode = () => {
    const { baseURL } = this.props;
    return (

        <img alt="line" src={`${baseURL}/images/icon-barcode.png`} />

กรุณาแสกน BARCODE

    );
  };

  renderInputQrcode = () => {
    const { nextInput } = this.props;
    const { baseURL } = this.props;
    const message = nextInput === 'LINE_QR_CODE'
    ? 'กรุณาแสกน LINE QR CODE ของท่าน'
    : 'กรุณาแสกน QR CODE ที่ได้รับมา';
    return (

        <img alt="line" src={`${baseURL}/images/icon-qrcode.png`} />

{message}

    );
  };

  renderInputUI = () => {
    const { nextInput } = this.props;
    if (nextInput === 'EMAIL') {
      return this.renderInputEmail();
    } else if (nextInput === 'MSISDN') {
      return this.renderInputMSISDN();
    } else if (nextInput === 'LINE_ID') {
      return this.renderInputLineId();
    } else if (nextInput === 'BARCODE') {
      return this.renderInputBarcode();
    } else if (nextInput === 'LINE_QR_CODE' || 'QR_CODE') {
      return this.renderInputQrcode();
    }
    return '';
  };

  render() {
    console.log(this);
    const { baseURL, selectedEvent, nextInput } = this.props;
    return (

        <Layout.Title>
          <EventTitle title={'เล่นกิจกรรมรับส่วนลด'} item={selectedEvent} baseURL={baseURL} />
        </Layout.Title>
        <Layout.Content>
          {this.renderInputUI()}
          <FooterAction />
        </Layout.Content>

    );
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(EventPlayPage);
<commit_msg>Fixed กิจกรรม UI<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';

// ======================================================
// Containers
// ======================================================
import { FooterAction } from '../../Utils';
// ======================================================
// Components
// ======================================================
import { Layout, EventTitle, InputWithPad } from '../../../components';
// ======================================================
// Actions
// ======================================================
import * as ApplicationActions from '../../../actions/applicationActions';
import * as Actions from './actions';
// ======================================================
// Selectors
// ======================================================
import MasterappSelector from '../../../selectors/masterapp';
import OrderSelectors from '../../../selectors/order';
// ======================================================
// Helpers
// ======================================================
import { isEmpty } from '../../../helpers/global';

import lineId from '../../../images/line-id.png';

const mapStateToProps = state => ({
  baseURL: MasterappSelector.getBaseURL(state.masterapp),
  selectedEvent: OrderSelectors.getSelectedEvent(state.order),
  nextInput: OrderSelectors.getEventNextInput(state.order),
});

const actions = {
  ...ApplicationActions,
  ...Actions,
};

const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);

class EventPlayPage extends Component {
  static propTypes = {
    baseURL: PropTypes.string.isRequired,
    selectedEvent: PropTypes.shape({}),
    nextInput: PropTypes.string,
    submitPlayEvent: PropTypes.func.isRequired,
    updateEventInput: PropTypes.func.isRequired,
  };

  static defaultProps = {
    selectedEvent: {},
    nextInput: '',
  };

  componentWillReceiveProps = nextProps => {
    const { submitPlayEvent } = this.props;
    if (isEmpty(nextProps.nextInput)) submitPlayEvent();
  };

  handleSubmitPage = inputValue => {
    const { nextInput, updateEventInput } = this.props;
    // ======================================================
    // Update nextInput
    // ======================================================
    updateEventInput(nextInput, inputValue);
  };

  renderInputMSISDN = () => (

ใส่ เบอร์มือถือ ของคุณ

            กรุณาตรวจสอบ หมายเลขโทรศัพท์ ให้ถูกต้อง

          <InputWithPad
            type={'num'}
            rules={{
              required: 'กรุณาระบุหมายเลขโทรศัพท์',
              mobileNumber: 'รูปแบบหมายเลขโทรศัพท์ไม่ถูกต้อง',
            }}
            onConfirm={this.handleSubmitPage}
          />

  );

  renderInputEmail = () => (

ใส่ อีเมล ของคุณ

            กรุณาตรวจสอบ อีเมล ให้ถูกต้อง

          <InputWithPad
            type={'keyboard'}
            rules={{
              required: 'กรุณาระบุอีเมล',
              email: 'รูปแบบอีเมลไม่ถูกต้อง',
            }}
            isFixed
            onConfirm={this.handleSubmitPage}
          />

  );

  renderInputLineId = () => {
    const { submitPlayEvent } = this.props;
    return (

กรุณาแสกน LINE QR CODE

เมื่อได้รับรหัสส่วนลดแล้ว กดปุ่มทำรายการต่อ

ทำรายการต่อ

    );
  };

  renderInputBarcode = () => {
    const { baseURL } = this.props;
    return (

        <img alt="line" src={`${baseURL}/images/icon-barcode.png`} />

กรุณาแสกน BARCODE ที่ได้รับมา

    );
  };

  renderInputQrcode = () => {
    const { nextInput } = this.props;
    const { baseURL } = this.props;
    const message = nextInput === 'LINE_QR_CODE'
    ? 'กรุณาแสกน LINE QR CODE ของท่าน'
    : 'กรุณาแสกน QR CODE ที่ได้รับมา';
    return (

        <img alt="line" src={`${baseURL}/images/icon-qrcode.png`} />

{message}

    );
  };

  renderInputUI = () => {
    const { nextInput } = this.props;
    if (nextInput === 'EMAIL') {
      return this.renderInputEmail();
    } else if (nextInput === 'MSISDN') {
      return this.renderInputMSISDN();
    } else if (nextInput === 'LINE_ID') {
      return this.renderInputLineId();
    } else if (nextInput === 'BARCODE') {
      return this.renderInputBarcode();
    } else if (nextInput === 'LINE_QR_CODE' || 'QR_CODE') {
      return this.renderInputQrcode();
    }
    return '';
  };

  render() {
    console.log(this);
    const { baseURL, selectedEvent, nextInput } = this.props;
    return (

        <Layout.Title>
          <EventTitle title={'เล่นกิจกรรมรับส่วนลด'} item={selectedEvent} baseURL={baseURL} />
        </Layout.Title>
        <Layout.Content>
          {this.renderInputUI()}
          <FooterAction />
        </Layout.Content>

    );
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(EventPlayPage);
<|endoftext|>


<commit_before>import Controller from '@ember/controller';

import { fetch, Headers } from 'fetch';
import { service } from 'ember-decorators/service';
import config from 'travis/config/environment';
import { later } from '@ember/runloop';
import { Promise as EmberPromise } from 'rsvp';

const interval = config.intervals.githubAppsInstallationPolling;

export default Controller.extend({
  @service auth: null,
  @service raven: null,

  queryParams: ['installation_id'],

  repetitions: 0,
  maxRepetitions: 10,

  startPolling() {
    this.initialDelayPromise().then(() => this.fetchPromise().then(installation => {
      this.transitionToRoute('account', installation.owner.login);
    }));
  },

  initialDelayPromise() {
    return new Promise(((resolve) => {
      setTimeout(resolve.bind(null), interval);
    }));
  },

  fetchPromise() {
    let headers = new Headers({
      'Authorization': `token ${this.get('auth.token')}`,
      'Travis-API-Version': '3'
    });

    let url = `${config.apiEndpoint}/installation/` +
      `${this.get('installation_id')}?include=installation.owner`;

    return fetch(url, {headers}).then(response => {
      if (response.ok) {
        return response.json();
      } else {
        let repetitions = this.get('repetitions');
        let maxRepetitions = this.get('maxRepetitions');

        if (repetitions < maxRepetitions) {
          this.set('repetitions', repetitions + 1);
          return new EmberPromise(resolve => later(() => resolve(this.fetchPromise()), interval));
        } else {
          let exception =
            new Error(`Timed out looking for owner of installation ${this.get('installation_id')}`);
          this.get('raven').logException(exception, true);
        }
      }
    });
  }
});
<commit_msg>Fix apps redirect issue (#1867)<commit_after>import Controller from '@ember/controller';

import { fetch, Headers } from 'fetch';
import { service } from 'ember-decorators/service';
import config from 'travis/config/environment';
import { later } from '@ember/runloop';
import { Promise as EmberPromise } from 'rsvp';

const interval = config.intervals.githubAppsInstallationPolling;

export default Controller.extend({
  @service auth: null,
  @service raven: null,

  queryParams: ['installation_id'],

  repetitions: 0,
  maxRepetitions: 10,

  startPolling() {
    this.initialDelayPromise().then(() => this.fetchPromise().then(installation => {
      this.transitionToRoute('account');
    }));
  },

  initialDelayPromise() {
    return new Promise(((resolve) => {
      setTimeout(resolve.bind(null), interval);
    }));
  },

  fetchPromise() {
    let headers = new Headers({
      'Authorization': `token ${this.get('auth.token')}`,
      'Travis-API-Version': '3'
    });

    let url = `${config.apiEndpoint}/installation/` +
      `${this.get('installation_id')}?include=installation.owner`;

    return fetch(url, {headers}).then(response => {
      if (response.ok) {
        return response.json();
      } else {
        let repetitions = this.get('repetitions');
        let maxRepetitions = this.get('maxRepetitions');

        if (repetitions < maxRepetitions) {
          this.set('repetitions', repetitions + 1);
          return new EmberPromise(resolve => later(() => resolve(this.fetchPromise()), interval));
        } else {
          let exception =
            new Error(`Timed out looking for owner of installation ${this.get('installation_id')}`);
          this.get('raven').logException(exception, true);
        }
      }
    });
  }
});
<|endoftext|>


<commit_before>import { List } from 'immutable';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import RegistrationPolicyBucket from './RegistrationPolicyBucket';

export default class RegistrationPolicy {
  static propType = PropTypes.shape({
    buckets: ImmutablePropTypes.listOf(RegistrationPolicyBucket.propType.isRequired).isRequired,
    preventNoPreferenceSignups: PropTypes.bool.isRequired,
  });
  static apiRepresentationPropType = PropTypes.shape({
    buckets:
      PropTypes.arrayOf(RegistrationPolicyBucket.apiRepresentationPropType.isRequired).isRequired,
    prevent_no_preference_signups: PropTypes.bool,
  });

  static fromAPI(json) {
    return new RegistrationPolicy().setAttributesFromAPI(json);
  }

  constructor(buckets = null, preventNoPreferenceSignups = false) {
    this.buckets = buckets || new List();
    this.preventNoPreferenceSignups = preventNoPreferenceSignups;
  }

  getAPIRepresentation() {
    return {
      prevent_no_preference_signups: this.preventNoPreferenceSignups,
      buckets: this.buckets.map(bucket => bucket.getAPIRepresentation()).toJS(),
    };
  }

  setAttributesFromAPI(json) {
    let returnRecord = this;

    if (json.buckets !== undefined) {
      const buckets = json.buckets.map(bucket => RegistrationPolicyBucket.fromAPI(bucket));
      returnRecord = returnRecord.setBuckets(buckets);
    }

    returnRecord = returnRecord.setPreventNoPreferenceSignups((
      Boolean(json.prevent_no_preference_signups)
    ));

    return returnRecord;
  }

  sumBucketProperty = getter => (
    this.buckets.reduce((sum, bucket) => sum + (getter(bucket) || 0), 0)
  )

  getTotalSlots = () => this.sumBucketProperty(bucket => bucket.totalSlots)
  getMinimumSlots = () => this.sumBucketProperty(bucket => bucket.minimumSlots)
  getPreferredSlots = () => this.sumBucketProperty(bucket => bucket.preferredSlots)
  slotsLimited = () => this.buckets.every(bucket => bucket.slotsLimited)

  addBucket(key, props) {
    const bucket = new RegistrationPolicyBucket({ key });
    return new RegistrationPolicy(
      this.buckets.push(bucket.setAttributesFromAPI(props || {})),
      this.preventNoPreferenceSignups,
    );
  }

  getBucket(key) {
    return this.buckets.find(bucket => bucket.get('key') === key);
  }

  deleteBucket(key) {
    return new RegistrationPolicy(
      this.buckets.filter(bucket => bucket.get('key') !== key),
      this.preventNoPreferenceSignups,
    );
  }

  updateBucket(key, newBucket) {
    const index = this.buckets.findIndex(bucket => bucket.get('key') === key);

    if (index === -1) {
      return new RegistrationPolicy(
        this.buckets.push(newBucket),
        this.preventNoPreferenceSignups,
      );
    }

    return new RegistrationPolicy(
      this.buckets.set(index, newBucket),
      this.preventNoPreferenceSignups,
    );
  }

  // eslint-disable-next-line class-methods-use-this
  setBuckets(buckets) {
    if (Array.isArray(buckets)) {
      return new RegistrationPolicy(
        new List(buckets),
        this.preventNoPreferenceSignups,
      );
    }

    return new RegistrationPolicy(buckets, this.preventNoPreferenceSignups);
  }

  getAnythingBucket() {
    return this.buckets.find(bucket => bucket.get('anything'));
  }

  getPreventNoPreferenceSignups() {
    return this.preventNoPreferenceSignups;
  }

  setPreventNoPreferenceSignups(preventNoPreferenceSignups) {
    return new RegistrationPolicy(this.buckets, preventNoPreferenceSignups);
  }
}
<commit_msg>Don't break if there is no registration policy<commit_after>import { List } from 'immutable';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import RegistrationPolicyBucket from './RegistrationPolicyBucket';

export default class RegistrationPolicy {
  static propType = PropTypes.shape({
    buckets: ImmutablePropTypes.listOf(RegistrationPolicyBucket.propType.isRequired).isRequired,
    preventNoPreferenceSignups: PropTypes.bool.isRequired,
  });
  static apiRepresentationPropType = PropTypes.shape({
    buckets:
      PropTypes.arrayOf(RegistrationPolicyBucket.apiRepresentationPropType.isRequired).isRequired,
    prevent_no_preference_signups: PropTypes.bool,
  });

  static fromAPI(json) {
    return new RegistrationPolicy().setAttributesFromAPI(json);
  }

  constructor(buckets = null, preventNoPreferenceSignups = false) {
    this.buckets = buckets || new List();
    this.preventNoPreferenceSignups = preventNoPreferenceSignups;
  }

  getAPIRepresentation() {
    return {
      prevent_no_preference_signups: this.preventNoPreferenceSignups,
      buckets: this.buckets.map(bucket => bucket.getAPIRepresentation()).toJS(),
    };
  }

  setAttributesFromAPI(json) {
    let returnRecord = this;
    if (json == null) {
      return returnRecord;
    }

    if (json.buckets !== undefined) {
      const buckets = json.buckets.map(bucket => RegistrationPolicyBucket.fromAPI(bucket));
      returnRecord = returnRecord.setBuckets(buckets);
    }

    returnRecord = returnRecord.setPreventNoPreferenceSignups((
      Boolean(json.prevent_no_preference_signups)
    ));

    return returnRecord;
  }

  sumBucketProperty = getter => (
    this.buckets.reduce((sum, bucket) => sum + (getter(bucket) || 0), 0)
  )

  getTotalSlots = () => this.sumBucketProperty(bucket => bucket.totalSlots)
  getMinimumSlots = () => this.sumBucketProperty(bucket => bucket.minimumSlots)
  getPreferredSlots = () => this.sumBucketProperty(bucket => bucket.preferredSlots)
  slotsLimited = () => this.buckets.every(bucket => bucket.slotsLimited)

  addBucket(key, props) {
    const bucket = new RegistrationPolicyBucket({ key });
    return new RegistrationPolicy(
      this.buckets.push(bucket.setAttributesFromAPI(props || {})),
      this.preventNoPreferenceSignups,
    );
  }

  getBucket(key) {
    return this.buckets.find(bucket => bucket.get('key') === key);
  }

  deleteBucket(key) {
    return new RegistrationPolicy(
      this.buckets.filter(bucket => bucket.get('key') !== key),
      this.preventNoPreferenceSignups,
    );
  }

  updateBucket(key, newBucket) {
    const index = this.buckets.findIndex(bucket => bucket.get('key') === key);

    if (index === -1) {
      return new RegistrationPolicy(
        this.buckets.push(newBucket),
        this.preventNoPreferenceSignups,
      );
    }

    return new RegistrationPolicy(
      this.buckets.set(index, newBucket),
      this.preventNoPreferenceSignups,
    );
  }

  // eslint-disable-next-line class-methods-use-this
  setBuckets(buckets) {
    if (Array.isArray(buckets)) {
      return new RegistrationPolicy(
        new List(buckets),
        this.preventNoPreferenceSignups,
      );
    }

    return new RegistrationPolicy(buckets, this.preventNoPreferenceSignups);
  }

  getAnythingBucket() {
    return this.buckets.find(bucket => bucket.get('anything'));
  }

  getPreventNoPreferenceSignups() {
    return this.preventNoPreferenceSignups;
  }

  setPreventNoPreferenceSignups(preventNoPreferenceSignups) {
    return new RegistrationPolicy(this.buckets, preventNoPreferenceSignups);
  }
}
<|endoftext|>


<commit_before>"use strict";

angular.module('arethusa.core').directive('toBottom', [
  '$window',
  '$timeout',
  function($window, $timeout) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs) {
        var canvas = angular.element(document.getElementById('canvas'));
        var win  = angular.element($window);
        win.on('resize', function() {
          setHeight();
        });

        function setHeight() {
          $timeout(function() {
            var offset = element.offset().top;
            var bottom = canvas.offset().top + canvas.height();
            element.height(bottom - offset);
          });
        }

        setHeight();
      }
    };
  }
]);
<commit_msg>Fix svg height through toBottom directive<commit_after>"use strict";

angular.module('arethusa.core').directive('toBottom', [
  '$window',
  '$timeout',
  function($window, $timeout) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs) {
        var canvas = angular.element(document.getElementById('canvas'));
        var win  = angular.element($window);
        win.on('resize', function() {
          setHeight();
        });

        function setHeight() {
          $timeout(function() {
            var offset = element.offset().top;
            var bottom = canvas.offset().top + canvas.height();
            element.height(bottom - offset);
            var svg = element.find('svg');
            if (svg[0]) {
              var elBottom = element[0].getBoundingClientRect().bottom;
              var svgTop = svg.offset().top;
              svg.height(elBottom - svgTop);
            }
          });
        }

        setHeight();
      }
    };
  }
]);
<|endoftext|>


<commit_before>import React from 'react';

function BrowserWarning() {
  return (

        Currently, Varaamo does not support IE11.
        We are investigating this issue and finding a solution.
        Meanwhile, use another browser (such as
         Chrome
        ,
         Firefox
        or
         Edge
        ).

        Varaamo ei tue IE11 selainta tällä hetkellä.
        Selvitämme ongelmaa sen ratkaisemiseksi.
        Sillä välin, käytä toista selainta (kuten
         Chrome
        ,
         Firefox
        tai
         Edge
        ).

        Varaamo fungerar inte längre med Internet Explorer 11.
        Vi arbetar med att lösa problemet.
        Under tiden så var vänlig och använd någon annan browser (t.ex
         Chrome
        ,
         Firefox
        eller
         Edge
        ).

  );
}

export default BrowserWarning;
<commit_msg>Update warning info to be more general for Internet Explorer<commit_after>import React from 'react';

function BrowserWarning() {
  return (

        Currently, Varaamo does not support Internet Explorer.
        We are investigating this issue and finding a solution.
        Meanwhile, use another browser (such as
         Chrome
        ,
         Firefox
        or
         Edge
        ).

        Varaamo ei tue Internet Explorer selainta tällä hetkellä.
        Selvitämme ongelmaa sen ratkaisemiseksi.
        Sillä välin, käytä toista selainta (kuten
         Chrome
        ,
         Firefox
        tai
         Edge
        ).

        Varaamo fungerar inte längre med Internet Explorer.
        Vi arbetar med att lösa problemet.
        Under tiden så var vänlig och använd någon annan browser (t.ex
         Chrome
        ,
         Firefox
        eller
         Edge
        ).

  );
}

export default BrowserWarning;
<|endoftext|>


<commit_before>var apiClientManager = {
    baseUrl: "",
    beforeSendCallback: function() {},

    setBasicUrl: function(baseUrl) {
        this.baseUrl = baseUrl;
    },
    setBeforeSendCallback: function(callback) {
        this.beforeSendCallback = callback;
    },
    get: function(url, callback) {
        this.request('GET', url, callback);
    },
    post: function(url, data, callback) {
        this.request('POST', url, callback, data);
    },
    put: function(url, data, callback) {
        this.request('PUT', url, callback, data);
    },
    delete: function(url, callback) {
        this.request('DELETE', url, callback);
    },
    request: function(type, url, callback, data) {
        var that = this;
        $.ajax({
            url: (this.baseUrl + url),
            type: type,
            data: data,
            success: function(result) {
                callback.success(JSON.parse(result));
            },
            error: function(result) {
                try {
                    responseText = JSON.parse(result.responseText);
                }
                catch (e) {
                    responseText = {};
                }
                callback.error(result.status, responseText);
            },
            beforeSend: function(xhr) {
                that.beforeSendCallback(xhr);
            },
        });
    }
};
<commit_msg>apiClientManager expect only json<commit_after>var apiClientManager = {
    baseUrl: "",
    beforeSendCallback: function() {},

    setBasicUrl: function(baseUrl) {
        this.baseUrl = baseUrl;
    },
    setBeforeSendCallback: function(callback) {
        this.beforeSendCallback = callback;
    },
    get: function(url, callback) {
        this.request('GET', url, callback);
    },
    post: function(url, data, callback) {
        this.request('POST', url, callback, data);
    },
    put: function(url, data, callback) {
        this.request('PUT', url, callback, data);
    },
    delete: function(url, callback) {
        this.request('DELETE', url, callback);
    },
    request: function(type, url, callback, data) {
        var that = this;
        $.ajax({
            url: (this.baseUrl + url),
            type: type,
            data: data,
            dataType: "json",
            success: function(result) {
                callback.success(result);
            },
            error: function(result) {
                try {
                    responseText = JSON.parse(result.responseText);
                }
                catch (e) {
                    responseText = {};
                }
                callback.error(result.status, responseText);
            },
            beforeSend: function(xhr) {
                that.beforeSendCallback(xhr);
            },
        });
    }
};
<|endoftext|>


<commit_before>angular.module('facebook')

.controller('FacebookExampleController', ['$rootScope', '$scope', '$state', '$stateParams', 'FacebookAngularPatch', 'ParseQueryAngular', function($rootScope, $scope, $state, $stateParams, FacebookAngularPatch, ParseQueryAngular) {

  $scope.facebookCtrl = {
    response : {}
  };

  if(Parse.User.current()) {
    $scope.facebookCtrl.fbAuthData = Parse.User.current().get('authData');
  }

  $scope.fbConnect = function() {

  	// NB: this is a contrived example for demo purposes, you would never write the following code in a real app

 	// normally you would define a User.js data module for all your user objects and the method below would be on the user, e.g. $rootScope.currentUser.fbConnect()

  	ParseQueryAngular(Parse.FacebookUtils,{functionToCall:"logIn", params:[Parse.User.current(), "user_likes"]}).then(function(user) {
  		alert('facebook connected!');

  		// $scope.facebookCtrl.fbAuthData = user.get('authData');

  	}, function(error) {

  		alert('something went wrong, try again');

  		$scope.facebookCtrl.fbAuthData = error;

  	});

  }

  $scope.exampleCall = function() {

  	FB.apiAngular(
  		'/me/apprequests',
  		{ message: 'From the app to the user.' },
  		'POST')

  	.then(function(data) {

  		alert('FB Request Successfully Sent!');

  		$scope.facebookCtrl.response = data;

  	}, function(error) {

  		alert('FB Request Unsuccessful!');

		$scope.facebookCtrl.response = error;

	});

  }

}]);<commit_msg>fixed some login out issues<commit_after>angular.module('facebook')

.controller('FacebookExampleController', ['$rootScope', '$scope', '$state', '$stateParams', 'FacebookAngularPatch', 'ParseQueryAngular', function($rootScope, $scope, $state, $stateParams, FacebookAngularPatch, ParseQueryAngular) {

  $scope.facebookCtrl = {
    fbAuthData : {},
    response : {}
  };

  if(Parse.User.current()) {
    $scope.facebookCtrl.fbAuthData = Parse.User.current().get('authData');
  }

  $scope.fbConnect = function() {

  	// NB: this is a contrived example for demo purposes, you would never write the following code in a real app

 	// normally you would define a User.js data module for all your user objects and the method below would be on the user, e.g. $rootScope.currentUser.fbConnect()

  	ParseQueryAngular(Parse.FacebookUtils,{functionToCall:"logIn", params:[Parse.User.current(), "user_likes"]}).then(function(user) {
  		alert('facebook connected!');

  		$scope.facebookCtrl.fbAuthData = user.get('authData');

  	}, function(error) {

  		alert('something went wrong, try again');

  		$scope.facebookCtrl.fbAuthData = error;

  	});

  }

  $scope.exampleCall = function() {

  	FB.apiAngular(
  		'/me/apprequests',
  		{ message: 'From the app to the user.' },
  		'POST')

  	.then(function(data) {

  		alert('FB Request Successfully Sent!');

  		$scope.facebookCtrl.response = data;

  	}, function(error) {

  		alert('FB Request Unsuccessful!');

		$scope.facebookCtrl.response = error;

	});

  }

}]);<|endoftext|>


<commit_before>/**
 *
 * @license
 * Copyright (C) 2016 Joseph Roque
 *
 * 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.
 *
 * @author Joseph Roque
 * @created 2016-10-19
 * @file header-test.js
 * @description Tests header reducers
 *
 */
'use strict';

// Imports
import reducer from '../header';

// Expected initial state
const initialState = {
  title: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
  tabTitles: {
    find: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
    schedule: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
    discover: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
    search: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
    settings: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
  },
  shouldShowBack: false,
  tabShowBack: {
    find: false,
    schedule: false,
    discover: false,
    search: false,
    settings: false,
  },
  shouldShowSearch: true,
  tabShowSearch: {
    find: true,
    schedule: false,
    discover: false,
    search: true,
    settings: false,
  },
};

describe('navigation reducer', () => {
  it('should return the initial state', () => {
    expect(reducer(undefined, {})).toEqual(initialState);
  });

  it('should set a new header title', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'SET_HEADER_TITLE',
          title: {
            name: 'New title',
          },
        }
      )
    ).toEqual(
      {
        ...initialState,
        title: {
          name: 'New title',
        },
      }
    );
  });

  it('should set a new header title for a tab', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'SET_HEADER_TITLE',
          tab: 'find',
          title: {
            name: 'New title',
          },
        }
      )
    ).toEqual(
      {
        ...initialState,
        title: {
          name: 'New title',
        },
        tabTitles: {
          find: {name: 'New title'},
          schedule: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
          discover: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
          search: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
          settings: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
        },
      }
    );
  });

  it('should use the default header title', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'SET_HEADER_TITLE',
          title: null,
        }
      )
    ).toEqual(
      initialState
    );
  });

  it('should use the default header title for a tab', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'SET_HEADER_TITLE',
          title: null,
          tab: 'find',
        }
      )
    ).toEqual(
      initialState
    );
  });

  it('should show the back button', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'HEADER_SHOW_BACK',
          shouldShowBack: true,
        }
      )
    ).toEqual(
      {
        ...initialState,
        shouldShowBack: true,
      }
    );
  });

  it('should show the back button for a tab', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'HEADER_SHOW_BACK',
          tab: 'find',
          shouldShowBack: true,
        }
      )
    ).toEqual(
      {
        ...initialState,
        shouldShowBack: true,
        tabShowBack: {
          find: true,
          schedule: false,
          discover: false,
          search: false,
          settings: false,
        },
      }
    );
  });

  it('should show the search button for a tab', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'HEADER_SHOW_SEARCH',
          tab: 'schedule',
          shouldShowSearch: true,
        }
      )
    ).toEqual(
      {
        ...initialState,
        shouldShowSearch: true,
        tabShowSearch: {
          find: true,
          schedule: true,
          discover: false,
          search: false,
          settings: false,
        },
      }
    );
  });

  it('should set the title and back/search buttons when the tab changes', () => {
    let updatedState = reducer(
      initialState,
      {
        type: 'SET_HEADER_TITLE',
        title: 'schedule',
        tab: 'schedule',
      }
    );

    updatedState = reducer(
      updatedState,
      {
        type: 'HEADER_SHOW_BACK',
        shouldShowBack: true,
        tab: 'schedule',
      }
    );

    updatedState = reducer(
      updatedState,
      {
        type: 'HEADER_SHOW_SEARCH',
        shouldShowSearch: true,
        tab: 'schedule',
      }
    );

    expect(
      reducer(
        updatedState,
        {
          type: 'SWITCH_TAB',
          tab: 'schedule',
        }
      )
    ).toEqual(
      {
        ...updatedState,
        title: 'schedule',
        shouldShowBack: true,
        shouldShowSearch: true,
      }
    );
  });

  it('should show the search button', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'HEADER_SHOW_SEARCH',
          shouldShowSearch: true,
        }
      )
    ).toEqual(
      {
        ...initialState,
        shouldShowSearch: true,
      }
    );
  });
});
<commit_msg>Fix failing header-test<commit_after>/**
 *
 * @license
 * Copyright (C) 2016 Joseph Roque
 *
 * 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.
 *
 * @author Joseph Roque
 * @created 2016-10-19
 * @file header-test.js
 * @description Tests header reducers
 *
 */
'use strict';

// Imports
import reducer from '../header';

// Expected initial state
const initialState = {
  title: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
  tabTitles: {
    find: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
    schedule: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
    discover: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
    search: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
    settings: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
  },
  shouldShowBack: false,
  tabShowBack: {
    find: false,
    schedule: false,
    discover: false,
    search: false,
    settings: false,
  },
  shouldShowSearch: true,
  tabShowSearch: {
    find: true,
    schedule: false,
    discover: false,
    search: true,
    settings: false,
  },
};

describe('navigation reducer', () => {
  it('should return the initial state', () => {
    expect(reducer(undefined, {})).toEqual(initialState);
  });

  it('should set a new header title', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'SET_HEADER_TITLE',
          title: {
            name: 'New title',
          },
        }
      )
    ).toEqual(
      {
        ...initialState,
        title: {
          name: 'New title',
        },
      }
    );
  });

  it('should set a new header title for a tab', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'SET_HEADER_TITLE',
          tab: 'find',
          title: {
            name: 'New title',
          },
        }
      )
    ).toEqual(
      {
        ...initialState,
        title: {
          name: 'New title',
        },
        tabTitles: {
          find: {name: 'New title'},
          schedule: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
          discover: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
          search: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
          settings: {name_en: 'Campus Guide', name_fr: 'Guide de campus'},
        },
      }
    );
  });

  it('should use the default header title', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'SET_HEADER_TITLE',
          title: null,
        }
      )
    ).toEqual(
      initialState
    );
  });

  it('should use the default header title for a tab', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'SET_HEADER_TITLE',
          title: null,
          tab: 'find',
        }
      )
    ).toEqual(
      initialState
    );
  });

  it('should show the back button', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'HEADER_SHOW_BACK',
          shouldShowBack: true,
        }
      )
    ).toEqual(
      {
        ...initialState,
        shouldShowBack: true,
      }
    );
  });

  it('should show the back button for a tab', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'HEADER_SHOW_BACK',
          tab: 'find',
          shouldShowBack: true,
        }
      )
    ).toEqual(
      {
        ...initialState,
        shouldShowBack: true,
        tabShowBack: {
          find: true,
          schedule: false,
          discover: false,
          search: false,
          settings: false,
        },
      }
    );
  });

  it('should show the search button for a tab', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'HEADER_SHOW_SEARCH',
          tab: 'schedule',
          shouldShowSearch: true,
        }
      )
    ).toEqual(
      {
        ...initialState,
        shouldShowSearch: true,
        tabShowSearch: {
          find: true,
          schedule: true,
          discover: false,
          search: true,
          settings: false,
        },
      }
    );
  });

  it('should set the title and back/search buttons when the tab changes', () => {
    let updatedState = reducer(
      initialState,
      {
        type: 'SET_HEADER_TITLE',
        title: 'schedule',
        tab: 'schedule',
      }
    );

    updatedState = reducer(
      updatedState,
      {
        type: 'HEADER_SHOW_BACK',
        shouldShowBack: true,
        tab: 'schedule',
      }
    );

    updatedState = reducer(
      updatedState,
      {
        type: 'HEADER_SHOW_SEARCH',
        shouldShowSearch: true,
        tab: 'schedule',
      }
    );

    expect(
      reducer(
        updatedState,
        {
          type: 'SWITCH_TAB',
          tab: 'schedule',
        }
      )
    ).toEqual(
      {
        ...updatedState,
        title: 'schedule',
        shouldShowBack: true,
        shouldShowSearch: true,
      }
    );
  });

  it('should show the search button', () => {
    expect(
      reducer(
        initialState,
        {
          type: 'HEADER_SHOW_SEARCH',
          shouldShowSearch: true,
        }
      )
    ).toEqual(
      {
        ...initialState,
        shouldShowSearch: true,
      }
    );
  });
});
<|endoftext|>


<commit_before>CT.pubsub = {
	"_": {
		"ws": null,
		"args": null,
		"open": false,
		"initialized": false,
		"reconnect": true,
		"reconnect_interval": 250,
		"log": CT.data.getLogger("CT.pubsub"),
		"queue": [],
		"channels": {},
		"cb": {
			"message": CT.data.getLogger("CT.pubsub|message"), // override w/ set_cb()
			"subscribe": CT.data.getLogger("CT.pubsub|subscribe"), // override w/ set_cb()
			"join": CT.data.getLogger("CT.pubsub|join"), // override w/ set_cb()
			"leave": CT.data.getLogger("CT.pubsub|leave"), // override w/ set_cb()
			"open": CT.data.getLogger("CT.pubsub|open"), // override w/ set_cb()
			"close": CT.data.getLogger("CT.pubsub|close"), // override w/ set_cb()
			"error": CT.data.getLogger("CT.pubsub|error"), // override w/ set_cb()
		},
		"process": {
			"channel": function(data) {
				CT.pubsub._.channels[data.channel] = data;
				data.history.forEach(CT.pubsub._.process.publish);
				CT.pubsub._.cb.subscribe(data);
			},
			"publish": function(data) {
				CT.pubsub._.cb.message(data);
			},
			"subscribe": function(data) {
				CT.pubsub._.cb.join(data.channel, data.user);
				CT.data.add(CT.pubsub._.channels[data.channel].users, data.user);
			},
			"unsubscribe": function(data) {
				CT.pubsub._.cb.leave(data.channel, data.user);
				CT.data.remove(CT.pubsub._.channels[data.channel].users, data.user);
			}
		},
		"on": {
			"open": function() {
				CT.pubsub._.open = true;
				CT.pubsub._.reconnect_interval = 250;
				CT.pubsub._.write({
					"action": "register",
					"data": CT.pubsub._.args[2]
				});
				for (var channel in CT.pubsub._.channels)
					CT.pubsub.subscribe(channel);
				CT.pubsub._.queue.forEach(function(item, i) {
					setTimeout(function() {
						CT.pubsub._.write(item);
					}, 100 * i);
				});
				CT.pubsub._.queue.length = 0;
				CT.pubsub._.cb.open();
			},
			"close": function() {
				CT.pubsub._.open = false;
				CT.pubsub._.cb.close();
				if (CT.pubsub._.reconnect)
					CT.pubsub._.try_reconnect()
			},
			"error": function() {
				CT.pubsub._.cb.error();
			},
			"message": function(msg) {
				var d = JSON.parse(msg.data);
				CT.pubsub._.process[d.action](d.data);
			}
		},
		"write": function(data) {
			if (CT.pubsub._.open) {
				var dstring = JSON.stringify(data);
				CT.pubsub._.ws.send(dstring);
				CT.pubsub._.log("WRITE", dstring);
			} else {
				CT.pubsub._.queue.push(data);
				CT.pubsub._.log("QUEUE", JSON.stringify(CT.pubsub._.queue));
			}
		},
		"try_reconnect": function() {
			var r_int = CT.pubsub._.reconnect_interval;
			CT.pubsub._.log("RECONNECT", r_int);
			setTimeout(function() {
				CT.pubsub.connect.apply(null, CT.pubsub._.args)
			}, r_int);
			CT.pubsub._.reconnect_interval = Math.min(2 * r_int, 30000);
		}
	},
	"isInitialized": function() {
		return CT.pubsub._.initialized;
	},
	"set_reconnect": function(bool) {
		CT.pubsub._.reconnect = bool;
	},
	"set_cb": function(action, cb) { // action: message|join|leave|open|close|error
		CT.pubsub._.cb[action] = cb;
	},
	"publish": function(channel, message) {
		CT.pubsub._.write({
			"action": "publish",
			"data": {
				"channel": channel,
				"message": message
			}
		});
	},
	"subscribe": function(channel) {
		CT.pubsub._.write({
			"action": "subscribe",
			"data": channel
		});
	},
	"unsubscribe": function(channel) {
		CT.pubsub._.write({
			"action": "unsubscribe",
			"data": channel
		});
	},
	"connect": function(host, port, uname) {
		CT.pubsub._.args = arguments;
		CT.pubsub._.initialized = true;
		CT.pubsub._.ws = new WebSocket("ws://" + host + ":" + port);
		for (var action in CT.pubsub._.on)
			CT.pubsub._.ws["on" + action] = CT.pubsub._.on[action];
	}
};<commit_msg>simplified queue push<commit_after>CT.pubsub = {
	"_": {
		"ws": null,
		"args": null,
		"open": false,
		"initialized": false,
		"reconnect": true,
		"reconnect_interval": 250,
		"log": CT.data.getLogger("CT.pubsub"),
		"queue": [],
		"channels": {},
		"cb": {
			"message": CT.data.getLogger("CT.pubsub|message"), // override w/ set_cb()
			"subscribe": CT.data.getLogger("CT.pubsub|subscribe"), // override w/ set_cb()
			"join": CT.data.getLogger("CT.pubsub|join"), // override w/ set_cb()
			"leave": CT.data.getLogger("CT.pubsub|leave"), // override w/ set_cb()
			"open": CT.data.getLogger("CT.pubsub|open"), // override w/ set_cb()
			"close": CT.data.getLogger("CT.pubsub|close"), // override w/ set_cb()
			"error": CT.data.getLogger("CT.pubsub|error"), // override w/ set_cb()
		},
		"process": {
			"channel": function(data) {
				CT.pubsub._.channels[data.channel] = data;
				data.history.forEach(CT.pubsub._.process.publish);
				CT.pubsub._.cb.subscribe(data);
			},
			"publish": function(data) {
				CT.pubsub._.cb.message(data);
			},
			"subscribe": function(data) {
				CT.pubsub._.cb.join(data.channel, data.user);
				CT.data.add(CT.pubsub._.channels[data.channel].users, data.user);
			},
			"unsubscribe": function(data) {
				CT.pubsub._.cb.leave(data.channel, data.user);
				CT.data.remove(CT.pubsub._.channels[data.channel].users, data.user);
			}
		},
		"on": {
			"open": function() {
				CT.pubsub._.open = true;
				CT.pubsub._.reconnect_interval = 250;
				CT.pubsub._.write({
					"action": "register",
					"data": CT.pubsub._.args[2]
				});
				for (var channel in CT.pubsub._.channels)
					CT.pubsub.subscribe(channel);
				CT.pubsub._.queue.forEach(CT.pubsub._.write);
				CT.pubsub._.queue.length = 0;
				CT.pubsub._.cb.open();
			},
			"close": function() {
				CT.pubsub._.open = false;
				CT.pubsub._.cb.close();
				if (CT.pubsub._.reconnect)
					CT.pubsub._.try_reconnect()
			},
			"error": function() {
				CT.pubsub._.cb.error();
			},
			"message": function(msg) {
				var d = JSON.parse(msg.data);
				CT.pubsub._.process[d.action](d.data);
			}
		},
		"write": function(data) {
			if (CT.pubsub._.open) {
				var dstring = JSON.stringify(data);
				CT.pubsub._.ws.send(dstring);
				CT.pubsub._.log("WRITE", dstring);
			} else {
				CT.pubsub._.queue.push(data);
				CT.pubsub._.log("QUEUE", JSON.stringify(CT.pubsub._.queue));
			}
		},
		"try_reconnect": function() {
			var r_int = CT.pubsub._.reconnect_interval;
			CT.pubsub._.log("RECONNECT", r_int);
			setTimeout(function() {
				CT.pubsub.connect.apply(null, CT.pubsub._.args)
			}, r_int);
			CT.pubsub._.reconnect_interval = Math.min(2 * r_int, 30000);
		}
	},
	"isInitialized": function() {
		return CT.pubsub._.initialized;
	},
	"set_reconnect": function(bool) {
		CT.pubsub._.reconnect = bool;
	},
	"set_cb": function(action, cb) { // action: message|subscribe|join|leave|open|close|error
		CT.pubsub._.cb[action] = cb;
	},
	"publish": function(channel, message) {
		CT.pubsub._.write({
			"action": "publish",
			"data": {
				"channel": channel,
				"message": message
			}
		});
	},
	"subscribe": function(channel) {
		CT.pubsub._.write({
			"action": "subscribe",
			"data": channel
		});
	},
	"unsubscribe": function(channel) {
		CT.pubsub._.write({
			"action": "unsubscribe",
			"data": channel
		});
	},
	"connect": function(host, port, uname) {
		CT.pubsub._.args = arguments;
		CT.pubsub._.initialized = true;
		CT.pubsub._.ws = new WebSocket("ws://" + host + ":" + port);
		for (var action in CT.pubsub._.on)
			CT.pubsub._.ws["on" + action] = CT.pubsub._.on[action];
	}
};<|endoftext|>


<commit_before>var config = require('./config/config.json');
var pattern = {
    js: {
        all: './**/*.js',
        spec: './**/*.spec.js',
        public: path.join(config.dir.public, '/**/*.js'),
        vendor: path.join(config.dir.vendor, '/**/*.js'),
        scripts: path.join(config.dir.scripts, '/**/*.js'),
        test: path.join(config.dir.test, '/**/*.js')
    },
    styles: {
        all: path.join(config.dir.styles, '/**/*.css')
    },
    not: {
        vendor: "!" + path.join(config.dir.vendor, '/**/*.js')
    }
};

    //
    //
    //

module.exports = function(grunt) {
    'use strict';
    // show elapsed time at the end
    require('time-grunt')(grunt);
    // load all grunt tasks
    require('load-grunt-tasks')(grunt);
    // Project Configuration
    grunt.initConfig({

        //
        // Development
        //

        watch: {
            js: {
                files: [
                    pattern.js.all,
                    pattern.not.vendor,
                    '!**/node_modules/**'
                ],
                tasks: ['jshint'],
                options: {
                    livereload: true,
                },
            },
            css: {
                files: [pattern.styles.all],
                options: {
                    livereload: true
                }
            },
            karma: {
                files: [pattern.js.spec],
                tasks: ['karma:unit:run'],
                options: {
                    livereload: true
                }
            }
        },

        jshint: {
            options: {
                globals: {
                    "require"    : false,
                    "define"     : false,
                    "module"     : false,
                    "angular"    : false,
                    "describe"   : false,
                    "it"         : false,
                    "before"     : false,
                    "beforeEach" : false,
                    "after"      : false,
                    "afterEach"  : false
                }
            },
            Gruntfile: [
                'Gruntfile.js'
            ],
            public: [
                pattern.js.all,
                pattern.not.vendor
            ],
            test: [
                pattern.js.test,
                pattern.js.spec
            ]
        },

        nodemon: {
            dev: {
                options: {
                    file: 'server.js',
                    args: [],
                    ignoredFiles: ['README.md', 'node_modules/**', config.dir.vendor + '/**', '.DS_Store'],
                    watchedExtensions: ['js'],
                    watchedFolders: [config.dir.config, config.dir.public],
                    debug: true,
                    delayTime: 1,
                    env: {
                        PORT: config.PORT
                    },
                    cwd: "./"
                }
            }
        },
        concurrent: {
            tasks: ['nodemon', 'watch'],
            options: {
                logConcurrentOutput: true
            }
        },

        //
        // Testing
        //

        karma: {
            unit: {
                background: true,
                options: {
                    basePath: '',
                    frameworks: ['jasmine'],
                    files: [
                        pattern.js.vendor,
                        pattern.js.spec,
                        pattern.js.all
                    ],
                    exclude: [

                    ],
                    colors: true,
                    captureTimeout: 60000,
                    runnerPort: 9000,
                    logLevel: config.LOG_INFO,
                    browsers: ['Chrome']
                }
            }
        }

    });

    grunt.option('force', true);

    //Default task.
    grunt.registerTask('default', ['jshint', 'concurrent']);

    //Test task.
    grunt.registerTask('test', ['jshint', 'karma:unit:start', 'watch']);

};

<commit_msg>Commented out nodemon and concurrent tasks as they are not always applicable.<commit_after>var config = require('./config/config.json');
var pattern = {
    js: {
        all: './**/*.js',
        spec: './**/*.spec.js',
        public: path.join(config.dir.public, '/**/*.js'),
        vendor: path.join(config.dir.vendor, '/**/*.js'),
        scripts: path.join(config.dir.scripts, '/**/*.js'),
        test: path.join(config.dir.test, '/**/*.js')
    },
    styles: {
        all: path.join(config.dir.styles, '/**/*.css')
    },
    not: {
        vendor: "!" + path.join(config.dir.vendor, '/**/*.js')
    }
};

    //
    //
    //

module.exports = function(grunt) {
    'use strict';
    // show elapsed time at the end
    require('time-grunt')(grunt);
    // load all grunt tasks
    require('load-grunt-tasks')(grunt);
    // Project Configuration
    grunt.initConfig({

        //
        // Development
        //

        watch: {
            js: {
                files: [
                    pattern.js.all,
                    pattern.not.vendor,
                    '!**/node_modules/**'
                ],
                tasks: ['jshint'],
                options: {
                    livereload: true,
                },
            },
            css: {
                files: [pattern.styles.all],
                options: {
                    livereload: true
                }
            },
            karma: {
                files: [pattern.js.spec],
                tasks: ['karma:unit:run'],
                options: {
                    livereload: true
                }
            }
        },

        jshint: {
            options: {
                globals: {
                    "require"    : false,
                    "define"     : false,
                    "module"     : false,
                    "angular"    : false,
                    "describe"   : false,
                    "it"         : false,
                    "before"     : false,
                    "beforeEach" : false,
                    "after"      : false,
                    "afterEach"  : false
                }
            },
            Gruntfile: [
                'Gruntfile.js'
            ],
            public: [
                pattern.js.all,
                pattern.not.vendor
            ],
            test: [
                pattern.js.test,
                pattern.js.spec
            ]
        },

        // nodemon: {
        //     dev: {
        //         options: {
        //             file: 'server.js',
        //             args: [],
        //             ignoredFiles: ['README.md', 'node_modules/**', config.dir.vendor + '/**', '.DS_Store'],
        //             watchedExtensions: ['js'],
        //             watchedFolders: [config.dir.config, config.dir.public],
        //             debug: true,
        //             delayTime: 1,
        //             env: {
        //                 PORT: config.PORT
        //             },
        //             cwd: "./"
        //         }
        //     }
        // },
        // concurrent: {
        //     tasks: ['nodemon', 'watch'],
        //     options: {
        //         logConcurrentOutput: true
        //     }
        // },

        //
        // Testing
        //

        karma: {
            unit: {
                background: true,
                options: {
                    basePath: '',
                    frameworks: ['jasmine'],
                    files: [
                        pattern.js.vendor,
                        pattern.js.spec,
                        pattern.js.all
                    ],
                    exclude: [

                    ],
                    colors: true,
                    captureTimeout: 60000,
                    runnerPort: 9000,
                    logLevel: config.LOG_INFO,
                    browsers: ['Chrome']
                }
            }
        }

    });

    grunt.option('force', true);

    //Default task.
    grunt.registerTask('default', [
        'jshint'
        // 'concurrent'
    ]);

    //Test task.
    grunt.registerTask('test', ['jshint', 'karma:unit:start', 'watch']);

};

<|endoftext|>


<commit_before>import Robot from './robot-name';

describe('Robot', () => {
  let robot;

  beforeEach(() => {
    robot = new Robot();
  });

  it('has a name', () => {
    expect(robot.name).toMatch(/^[A-Z]{2}\d{3}$/);
  });

  xit('name is the same each time', () => {
    expect(robot.name).toEqual(robot.name);
  });

  xit('different robots have different names', () => {
    const NUMBER_OF_ROBOTS = 10000;
    let usedNames = {};

    for (let i = 0; i < NUMBER_OF_ROBOTS; i++) {
      let newRobot = new Robot();
      usedNames[newRobot.name] = true;
    }

    expect(Object.keys(usedNames).length).toEqual(NUMBER_OF_ROBOTS);
  });

  xit('is able to reset the name', () => {
    let originalName = robot.name;

    robot.reset();
    let newName = robot.name;

    expect(newName).toMatch(/^[A-Z]{2}\d{3}$/);
    expect(originalName).not.toEqual(newName);
  });

  xit('should set a unique name after reset', () => {
    const NUMBER_OF_ROBOTS = 10000;
    let usedNames = {};

    usedNames[robot.name] = true;
    for (let i = 0; i < NUMBER_OF_ROBOTS; i++) {
      robot.reset();
      usedNames[robot.name] = true;
    }

    expect(Object.keys(usedNames).length).toEqual(NUMBER_OF_ROBOTS + 1);
  });

});
<commit_msg>Use ES2015 feature Set() to store unique robot names<commit_after>import Robot from './robot-name';

describe('Robot', () => {
  let robot;

  beforeEach(() => {
    robot = new Robot();
  });

  it('has a name', () => {
    expect(robot.name).toMatch(/^[A-Z]{2}\d{3}$/);
  });

  xit('name is the same each time', () => {
    expect(robot.name).toEqual(robot.name);
  });

  xit('different robots have different names', () => {
    const NUMBER_OF_ROBOTS = 10000;
    const usedNames = new Set();

    for (let i = 0; i < NUMBER_OF_ROBOTS; i++) {
      const newRobot = new Robot();
      usedNames.add(newRobot.name);
    }

    expect(usedNames.size).toEqual(NUMBER_OF_ROBOTS);
  });

  xit('is able to reset the name', () => {
    const originalName = robot.name;

    robot.reset();
    const newName = robot.name;

    expect(newName).toMatch(/^[A-Z]{2}\d{3}$/);
    expect(originalName).not.toEqual(newName);
  });

  xit('should set a unique name after reset', () => {
    const NUMBER_OF_ROBOTS = 10000;
    const usedNames = new Set();

    usedNames.add(robot.name);
    for (let i = 0; i < NUMBER_OF_ROBOTS; i++) {
      robot.reset();
      usedNames.add(robot.name);
    }

    expect(usedNames.size).toEqual(NUMBER_OF_ROBOTS + 1);
  });

});
<|endoftext|>


<commit_before>/* global define:true */
define([
    'pixi',
    'experience/mode',
    'experience/issue',
    'experience/responsive',
    'jquery',
    'jquery-mousewheel'
], function (
    PIXI,
    Mode,
    Issue,
    Responsive,
    $
) {
    'use strict';

    var IssuesMode = function (canvas) {
        this._canvas = canvas;
        Mode.MODES.push(this);

        return this;
    };

    IssuesMode.prototype = new Mode();
    IssuesMode.prototype.constructor = IssuesMode;

    IssuesMode.prototype.init = function () {
        Mode.prototype.init.call(this);
        this._scrollPosition = this._scrollFinalPosition = 0;
        this._touchPosition =  this._touchDelta = this._touchFinalDelta = 0;

        this._issueMargin = 80;

        this._issues = this._canvas.issues;
        this._margin = {};
        this._scrollArea = new PIXI.Rectangle(0, 0, 0, 0);
        this._updateScroll();
    };

    IssuesMode.prototype._updateScroll = function () {
        this._issues = this._issues.sort(function(a,b) {
            return (a.data.getId() > b.data.getId()) ? 1 : ((b.data.getId() > a.data.getId()) ? -1 : 0);
        });

        this._onResize();
    };

    IssuesMode.prototype._drawLines = function () {
        var i;
        var issue;
        var relatedItem;

        this._canvas.clearLines();

        for (i = 0; i < this._issues.length - 1; i ++) {
            issue = this._issues[i];
            relatedItem = this._issues[i + 1];

            this._canvas.drawLine(issue, relatedItem, 0x0, 0.10);
        }
    };

    IssuesMode.prototype._mouseOverIssue = function (issue) {
        this.selectedIssue = issue;
        issue.mouseOver(this._canvas.mousePosition);
    };

    IssuesMode.prototype._mouseOutIssue = function (issue) {
        this.selectedIssue = null;
        issue.mouseOut();
    };

    IssuesMode.prototype._onMouseWheel = function (event) {
        this._scrollTo(event.deltaY / 5);
    };

    IssuesMode.prototype._onTouching = function (event) {
        if (!this.isOpen) {
            return;
        }

        var newPosition = event.getLocalPosition(this._canvas._stage).y;
        newPosition -= this._canvas.canvasSize.y / 2;

        this._touchDelta = this._touchFinalDelta = newPosition - this._touchPosition;
        this._touchPosition = newPosition;

        this._scrollTo(this._touchDelta);
    };

    IssuesMode.prototype._onTouchStart = function (event) {
        if (!this.isOpen) {
            return;
        }

        if (this._touchInterval) {
            clearInterval(this._touchInterval);
        }

        this._touchPosition = event.getLocalPosition(this._canvas._stage).y;
        this._touchPosition -= this._canvas.canvasSize.y / 2;
    };

    IssuesMode.prototype._onTouchEnd = function () {
        if (!this.isOpen) {
            return;
        }

        this._touchInterval = setInterval(function () {
            this._touchDelta += (this._touchFinalDelta - this._touchDelta) / 5;
            this._scrollTo(this._touchDelta);

            if (Math.abs(this._touchFinalDelta - this._touchDelta) < 1) {
                clearInterval(this._touchInterval);
            }
        }.bind(this), 1000 / 15);
    };

    IssuesMode.prototype._tapIssue = function (issue) {
        issue._onMouseOver();
        setTimeout(function () {
            issue._onMouseOut();
            issue._onPress();
        }, 200);
    };

    IssuesMode.prototype._onResize = function() {
        if (Responsive.IS_SMALL()) {
            this._margin.top = 250;
            this._margin.left = 100;
        } else {
            this._margin.top = 200;
            this._margin.left = 500;
        }

        this._scrollArea.x = -((this._canvas.canvasSize.x - this._margin.left) / 2);
        this._scrollArea.y = -((this._canvas.canvasSize.y - this._margin.top) / 2);
        this._scrollArea.width = this._canvas.canvasSize.x - this._margin.left;
        this._scrollArea.height = this._canvas.canvasSize.y - this._margin.top;

        var i, issue;
        for (i = 0; i < this._issues.length; i ++) {
            issue = this._issues[i];
            issue.issueX = this._scrollArea.x;
            issue.issueY = this._scrollArea.y + (this._issueMargin * i);
            issue.elm.x = issue.issueX;
            issue.elm.y = issue.issueY;
        }
    };

    IssuesMode.prototype._scrollTo = function (delta) {
        this._scrollFinalPosition += delta;

        this._scrollFinalPosition = Math.max(
            Math.min(this._scrollFinalPosition, 0),
            (this._scrollArea.y - (this._issueMargin * this._canvas.issues.length) +
            this._scrollArea.height * 1.5)
        );

        this._scrollPosition += (this._scrollFinalPosition - this._scrollPosition) / 3;

        var i, issue;
        for (i = 0; i < this._canvas.issues.length; i ++) {
            issue = this._canvas.issues[i];
            issue.elm.y = Math.round(issue.issueY + this._scrollPosition);
        }
    };

    IssuesMode.prototype._setIssueMouseEvents = function (issue) {
        issue.issueMouseOver = this._mouseOverIssue.bind(this);
        issue.issueMouseOut = this._mouseOutIssue.bind(this);
        issue.issueTap = this._tapIssue.bind(this);
        issue.mouseOverS.add(issue.issueMouseOver);
        issue.mouseOutS.add(issue.issueMouseOut);
        issue.tapS.add(issue.issueTap);
    };

    IssuesMode.prototype._onStartShow = function () {
        var i;
        var issue;

        this._scrollPosition = this._scrollFinalPosition = 0;
        this._updateScroll();

        for (i = 0; i < this._issues.length; i ++) {
            issue = this._issues[i];
            issue.setMode(Issue.MODE_ISSUES);
            issue.elm.alpha = 1;
            issue.moveTo(issue.issueX, issue.issueY);
            // so mouse over doesnt block animation
            setTimeout(this._setIssueMouseEvents.bind(this), 500, issue);
        }

        for (i = 0; i < this._canvas.tags.length; i ++) {
            issue = this._canvas.tags[i];
            issue.explode();
        }

        for (i = 0; i < this._canvas.fakes.length; i ++) {
            this._canvas.fakes[i].explode();
        }

        this._drawLinesBind = this._drawLines.bind(this);
        this._canvas.renderStartS.add(this._drawLinesBind);

        this._onMouseWheelBind = this._onMouseWheel.bind(this);
        $(document).on('mousewheel', this._onMouseWheelBind);
        this._canvas._stage.touchstart = this._onTouchStart.bind(this);
        this._canvas._stage.touchend = this._onTouchEnd.bind(this);
        this._canvas._stage.touchmove = this._onTouching.bind(this);

        this._onResizeBind = this._onResize.bind(this);
        this._canvas.resizeS.add(this._onResizeBind);

        setTimeout(this._onShow.bind(this), 500);
    };

    IssuesMode.prototype._onStartHide = function () {
        var i;
        var issue;

        for (i = 0; i < this._issues.length; i ++) {
            issue = this._issues[i];
            issue.mouseOverS.remove(issue.issueMouseOver);
            issue.mouseOutS.remove(issue.issueMouseOut);
        }

        $(document).off('mousewheel', this._onMouseWheelBind);
        this._canvas.clearLines();
        this._canvas.renderStartS.remove(this._drawLinesBind);
        this._canvas.resizeS.remove(this._onResizeBind);

        setTimeout(this._onHide.bind(this), 100);
    };

    return IssuesMode;
});
<commit_msg>Fix bug 1120132: Multiply scroll by deltaFactor for true distance.<commit_after>/* global define:true */
define([
    'pixi',
    'experience/mode',
    'experience/issue',
    'experience/responsive',
    'jquery',
    'jquery-mousewheel'
], function (
    PIXI,
    Mode,
    Issue,
    Responsive,
    $
) {
    'use strict';

    var IssuesMode = function (canvas) {
        this._canvas = canvas;
        Mode.MODES.push(this);

        return this;
    };

    IssuesMode.prototype = new Mode();
    IssuesMode.prototype.constructor = IssuesMode;

    IssuesMode.prototype.init = function () {
        Mode.prototype.init.call(this);
        this._scrollPosition = this._scrollFinalPosition = 0;
        this._touchPosition =  this._touchDelta = this._touchFinalDelta = 0;

        this._issueMargin = 80;

        this._issues = this._canvas.issues;
        this._margin = {};
        this._scrollArea = new PIXI.Rectangle(0, 0, 0, 0);
        this._updateScroll();
    };

    IssuesMode.prototype._updateScroll = function () {
        this._issues = this._issues.sort(function(a,b) {
            return (a.data.getId() > b.data.getId()) ? 1 : ((b.data.getId() > a.data.getId()) ? -1 : 0);
        });

        this._onResize();
    };

    IssuesMode.prototype._drawLines = function () {
        var i;
        var issue;
        var relatedItem;

        this._canvas.clearLines();

        for (i = 0; i < this._issues.length - 1; i ++) {
            issue = this._issues[i];
            relatedItem = this._issues[i + 1];

            this._canvas.drawLine(issue, relatedItem, 0x0, 0.10);
        }
    };

    IssuesMode.prototype._mouseOverIssue = function (issue) {
        this.selectedIssue = issue;
        issue.mouseOver(this._canvas.mousePosition);
    };

    IssuesMode.prototype._mouseOutIssue = function (issue) {
        this.selectedIssue = null;
        issue.mouseOut();
    };

    IssuesMode.prototype._onMouseWheel = function (event) {
        this._scrollTo(event.deltaY * event.deltaFactor);
    };

    IssuesMode.prototype._onTouching = function (event) {
        if (!this.isOpen) {
            return;
        }

        var newPosition = event.getLocalPosition(this._canvas._stage).y;
        newPosition -= this._canvas.canvasSize.y / 2;

        this._touchDelta = this._touchFinalDelta = newPosition - this._touchPosition;
        this._touchPosition = newPosition;

        this._scrollTo(this._touchDelta);
    };

    IssuesMode.prototype._onTouchStart = function (event) {
        if (!this.isOpen) {
            return;
        }

        if (this._touchInterval) {
            clearInterval(this._touchInterval);
        }

        this._touchPosition = event.getLocalPosition(this._canvas._stage).y;
        this._touchPosition -= this._canvas.canvasSize.y / 2;
    };

    IssuesMode.prototype._onTouchEnd = function () {
        if (!this.isOpen) {
            return;
        }

        this._touchInterval = setInterval(function () {
            this._touchDelta += (this._touchFinalDelta - this._touchDelta) / 5;
            this._scrollTo(this._touchDelta);

            if (Math.abs(this._touchFinalDelta - this._touchDelta) < 1) {
                clearInterval(this._touchInterval);
            }
        }.bind(this), 1000 / 15);
    };

    IssuesMode.prototype._tapIssue = function (issue) {
        issue._onMouseOver();
        setTimeout(function () {
            issue._onMouseOut();
            issue._onPress();
        }, 200);
    };

    IssuesMode.prototype._onResize = function() {
        if (Responsive.IS_SMALL()) {
            this._margin.top = 250;
            this._margin.left = 100;
        } else {
            this._margin.top = 200;
            this._margin.left = 500;
        }

        this._scrollArea.x = -((this._canvas.canvasSize.x - this._margin.left) / 2);
        this._scrollArea.y = -((this._canvas.canvasSize.y - this._margin.top) / 2);
        this._scrollArea.width = this._canvas.canvasSize.x - this._margin.left;
        this._scrollArea.height = this._canvas.canvasSize.y - this._margin.top;

        var i, issue;
        for (i = 0; i < this._issues.length; i ++) {
            issue = this._issues[i];
            issue.issueX = this._scrollArea.x;
            issue.issueY = this._scrollArea.y + (this._issueMargin * i);
            issue.elm.x = issue.issueX;
            issue.elm.y = issue.issueY;
        }
    };

    IssuesMode.prototype._scrollTo = function (delta) {
        this._scrollFinalPosition += delta;

        this._scrollFinalPosition = Math.max(
            Math.min(this._scrollFinalPosition, 0),
            (this._scrollArea.y - (this._issueMargin * this._canvas.issues.length) +
            this._scrollArea.height * 1.5)
        );

        this._scrollPosition += (this._scrollFinalPosition - this._scrollPosition) / 3;

        var i, issue;
        for (i = 0; i < this._canvas.issues.length; i ++) {
            issue = this._canvas.issues[i];
            issue.elm.y = Math.round(issue.issueY + this._scrollPosition);
        }
    };

    IssuesMode.prototype._setIssueMouseEvents = function (issue) {
        issue.issueMouseOver = this._mouseOverIssue.bind(this);
        issue.issueMouseOut = this._mouseOutIssue.bind(this);
        issue.issueTap = this._tapIssue.bind(this);
        issue.mouseOverS.add(issue.issueMouseOver);
        issue.mouseOutS.add(issue.issueMouseOut);
        issue.tapS.add(issue.issueTap);
    };

    IssuesMode.prototype._onStartShow = function () {
        var i;
        var issue;

        this._scrollPosition = this._scrollFinalPosition = 0;
        this._updateScroll();

        for (i = 0; i < this._issues.length; i ++) {
            issue = this._issues[i];
            issue.setMode(Issue.MODE_ISSUES);
            issue.elm.alpha = 1;
            issue.moveTo(issue.issueX, issue.issueY);
            // so mouse over doesnt block animation
            setTimeout(this._setIssueMouseEvents.bind(this), 500, issue);
        }

        for (i = 0; i < this._canvas.tags.length; i ++) {
            issue = this._canvas.tags[i];
            issue.explode();
        }

        for (i = 0; i < this._canvas.fakes.length; i ++) {
            this._canvas.fakes[i].explode();
        }

        this._drawLinesBind = this._drawLines.bind(this);
        this._canvas.renderStartS.add(this._drawLinesBind);

        this._onMouseWheelBind = this._onMouseWheel.bind(this);
        $(document).on('mousewheel', this._onMouseWheelBind);
        this._canvas._stage.touchstart = this._onTouchStart.bind(this);
        this._canvas._stage.touchend = this._onTouchEnd.bind(this);
        this._canvas._stage.touchmove = this._onTouching.bind(this);

        this._onResizeBind = this._onResize.bind(this);
        this._canvas.resizeS.add(this._onResizeBind);

        setTimeout(this._onShow.bind(this), 500);
    };

    IssuesMode.prototype._onStartHide = function () {
        var i;
        var issue;

        for (i = 0; i < this._issues.length; i ++) {
            issue = this._issues[i];
            issue.mouseOverS.remove(issue.issueMouseOver);
            issue.mouseOutS.remove(issue.issueMouseOut);
        }

        $(document).off('mousewheel', this._onMouseWheelBind);
        this._canvas.clearLines();
        this._canvas.renderStartS.remove(this._drawLinesBind);
        this._canvas.resizeS.remove(this._onResizeBind);

        setTimeout(this._onHide.bind(this), 100);
    };

    return IssuesMode;
});
<|endoftext|>


<commit_before>/**
 * Copyright 2018 Google LLC
 *
 * 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.
 */

import loaderUtils from 'loader-utils';
import SingleEntryPlugin from 'webpack/lib/SingleEntryPlugin';
import WebWorkerTemplatePlugin from 'webpack/lib/webworker/WebWorkerTemplatePlugin';
import FetchCompileWasmTemplatePlugin from 'webpack/lib/web/FetchCompileWasmTemplatePlugin';
import WORKER_PLUGIN_SYMBOL from './symbol';

const NAME = 'WorkerPluginLoader';
let hasWarned = false;

export function pitch (request) {
  this.cacheable(false);
  const cb = this.async();

  const compilerOptions = this._compiler.options || {};

  const plugin = compilerOptions.plugins.find(p => p[WORKER_PLUGIN_SYMBOL]) || {};
  const pluginOptions = (plugin && plugin.options) || {};

  if (pluginOptions.globalObject == null && !hasWarned && compilerOptions.output && compilerOptions.output.globalObject === 'window') {
    hasWarned = true;
    console.warn('Warning (worker-plugin): output.globalObject is set to "window". It must be set to "self" to support HMR in Workers.');
  }

  const options = loaderUtils.getOptions(this) || {};
  const chunkFilename = compilerOptions.output.chunkFilename.replace(/\.([a-z]+)(\?.+)?$/i, '.worker.$1$2');
  const workerOptions = {
    filename: (options.filename || pluginOptions.filename || chunkFilename).replace(/\[(?:chunkhash|contenthash)(:\d+(?::\d+)?)?\]/g, '[hash$1]'),
    chunkFilename: options.chunkFilename || pluginOptions.chunkFilename || chunkFilename,
    globalObject: pluginOptions.globalObject || 'self'
  };

  const plugins = (pluginOptions.plugins || []).map(plugin => {
    if (typeof plugin !== 'string') {
      return plugin;
    }
    const found = compilerOptions.plugins.find(p => p.constructor.name === plugin);
    if (!found) {
      console.warn(`Warning (worker-plugin): Plugin "${plugin}" is not found.`);
    }
    return found;
  });

  const workerCompiler = this._compilation.createChildCompiler(NAME, workerOptions, plugins);
  workerCompiler.context = this._compiler.context;
  (new WebWorkerTemplatePlugin()).apply(workerCompiler);
  (new FetchCompileWasmTemplatePlugin({
    mangleImports: compilerOptions.optimization.mangleWasmImports
  })).apply(workerCompiler);
  (new SingleEntryPlugin(this.context, request, options.name)).apply(workerCompiler);

  const subCache = `subcache ${__dirname} ${request}`;
  workerCompiler.hooks.compilation.tap(NAME, compilation => {
    if (compilation.cache) {
      if (!compilation.cache[subCache]) compilation.cache[subCache] = {};
      compilation.cache = compilation.cache[subCache];
    }
  });

  workerCompiler.runAsChild((err, entries, compilation) => {
    if (!err && compilation.errors && compilation.errors.length) {
      err = compilation.errors[0];
    }
    const entry = entries && entries[0] && entries[0].files[0];
    if (!err && !entry) err = Error(`WorkerPlugin: no entry for ${request}`);
    if (err) return cb(err);
    return cb(null, `${options.esModule ? 'export default' : 'module.exports ='} __webpack_public_path__ + ${JSON.stringify(entry)}`);
  });
};

export default { pitch };
<commit_msg>Webpack 5 compatibility<commit_after>/**
 * Copyright 2018 Google LLC
 *
 * 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.
 */

import loaderUtils from 'loader-utils';
import SingleEntryPlugin from 'webpack/lib/SingleEntryPlugin';
import WebWorkerTemplatePlugin from 'webpack/lib/webworker/WebWorkerTemplatePlugin';
import WORKER_PLUGIN_SYMBOL from './symbol';

let FetchCompileWasmPlugin;
try {
  FetchCompileWasmPlugin = require('webpack/lib/web/FetchCompileWasmPlugin'); // Webpack 5
} catch (e) {}
FetchCompileWasmPlugin = FetchCompileWasmPlugin || require('webpack/lib/web/FetchCompileWasmTemplatePlugin'); // Webpack 4

const NAME = 'WorkerPluginLoader';
let hasWarned = false;

export function pitch (request) {
  this.cacheable(false);
  const cb = this.async();

  const compilerOptions = this._compiler.options || {};

  const plugin = compilerOptions.plugins.find(p => p[WORKER_PLUGIN_SYMBOL]) || {};
  const pluginOptions = (plugin && plugin.options) || {};

  if (pluginOptions.globalObject == null && !hasWarned && compilerOptions.output && compilerOptions.output.globalObject === 'window') {
    hasWarned = true;
    console.warn('Warning (worker-plugin): output.globalObject is set to "window". It must be set to "self" to support HMR in Workers.');
  }

  const options = loaderUtils.getOptions(this) || {};
  const chunkFilename = compilerOptions.output.chunkFilename.replace(/\.([a-z]+)(\?.+)?$/i, '.worker.$1$2');
  const workerOptions = {
    filename: (options.filename || pluginOptions.filename || chunkFilename).replace(/\[(?:chunkhash|contenthash)(:\d+(?::\d+)?)?\]/g, '[hash$1]'),
    chunkFilename: options.chunkFilename || pluginOptions.chunkFilename || chunkFilename,
    globalObject: pluginOptions.globalObject || 'self'
  };

  const plugins = (pluginOptions.plugins || []).map(plugin => {
    if (typeof plugin !== 'string') {
      return plugin;
    }
    const found = compilerOptions.plugins.find(p => p.constructor.name === plugin);
    if (!found) {
      console.warn(`Warning (worker-plugin): Plugin "${plugin}" is not found.`);
    }
    return found;
  });

  const workerCompiler = this._compilation.createChildCompiler(NAME, workerOptions, plugins);
  workerCompiler.context = this._compiler.context;
  (new WebWorkerTemplatePlugin()).apply(workerCompiler);
  (new FetchCompileWasmPlugin({
    mangleImports: compilerOptions.optimization.mangleWasmImports
  })).apply(workerCompiler);
  (new SingleEntryPlugin(this.context, request, options.name)).apply(workerCompiler);

  const subCache = `subcache ${__dirname} ${request}`;
  workerCompiler.hooks.compilation.tap(NAME, compilation => {
    if (compilation.cache) {
      if (!compilation.cache[subCache]) compilation.cache[subCache] = {};
      compilation.cache = compilation.cache[subCache];
    }
  });

  workerCompiler.runAsChild((err, entries, compilation) => {
    if (!err && compilation.errors && compilation.errors.length) {
      err = compilation.errors[0];
    }
    const entry = entries && entries[0] && entries[0].files.values().next().value; // compatible with Array (v4) and Set (v5) prototypes
    if (!err && !entry) err = Error(`WorkerPlugin: no entry for ${request}`);
    if (err) return cb(err);
    return cb(null, `${options.esModule ? 'export default' : 'module.exports ='} __webpack_public_path__ + ${JSON.stringify(entry)}`);
  });
};

export default { pitch };
<|endoftext|>