<commit_before>import React from 'react';
import { addStoryInGroup, LOW_LEVEL_BLOCKS } from '../../../.storybook/utils';
import { Store, State } from '@sambego/storybook-state';
import { RadioGroup, RadioButton } from '../../index';

const values = ['Option one', 'Option two', 'Option three'];

const store = new Store({
  value: 'Option one',
});
const updateState = (value) => {
  store.set({ value });
};

export default {
  component: RadioButton,
  title: addStoryInGroup(LOW_LEVEL_BLOCKS, 'Form elements/Radio'),

  parameters: {
    design: {
      type: 'figma',
      url: 'https://www.figma.com/file/LHH25GN90ljQaBEUNMsdJn/Desktop-components?node-id=6454%3A22776',
    },
  },
};

export const DefaultStory = (args) => <RadioButton {...args} />;

DefaultStory.args = {
  checked: true,
  label: 'I am the label',
  value: 'the_value',
};

export const Group = () => (
  <State store={store}>
    <RadioGroup name="stringValue" onChange={updateState}>
      {values.map((value, key) => (
        <RadioButton key={key} marginVertical={3} label={value} value={value} />
      ))}
    </RadioGroup>
  </State>
);
<commit_msg>Replace storybook-state usage from radio story with useState<commit_after>import React, { useState } from 'react';
import { addStoryInGroup, LOW_LEVEL_BLOCKS } from '../../../.storybook/utils';
import { RadioGroup, RadioButton } from '../../index';

const values = ['Option one', 'Option two', 'Option three'];

export default {
  component: RadioButton,
  title: addStoryInGroup(LOW_LEVEL_BLOCKS, 'Form elements/Radio'),

  parameters: {
    design: {
      type: 'figma',
      url: 'https://www.figma.com/file/LHH25GN90ljQaBEUNMsdJn/Desktop-components?node-id=6454%3A22776',
    },
  },
};

export const DefaultStory = (args) => <RadioButton {...args} />;

DefaultStory.args = {
  checked: true,
  label: 'I am the label',
  value: 'the_value',
};

export const Group = () => {
  const [value, setValue] = useState('Option one');

  const handleChange = (value) => {
    setValue(value);
  };

  return (
    <RadioGroup name="stringValue" onChange={handleChange} value={value}>
      {values.map((value, key) => (
        <RadioButton key={key} marginVertical={3} label={value} value={value} />
      ))}
    </RadioGroup>
  );
};
<|endoftext|>


<commit_before>import createCampaignConfiguration from './createCampaignConfiguration'

const campaignTitle = '## X'
const campaignDescription = `
#### X
`
// const campaignDescriptionTwo = ``

const campaignEndTitle = '## X'
const campaignEndDescription = `
#### X
`
// const campaignEndDescriptionTwo =
//   '#### This is only part of [our relief efforts](https://tab.gladly.io/covid-19/) for this global health crisis—more to come soon.'

// Hardcode campaign data here.
const CURRENT_CAMPAIGN = createCampaignConfiguration({
  campaignId: 'TreePlantingDec2020',
  charityId: '67d1d576-4ab1-43dd-970c-3537cd13d476',
  content: {
    titleMarkdown: campaignTitle,
    descriptionMarkdown: campaignDescription,
    // descriptionMarkdownTwo: campaignDescriptionTwo,
  },
  countMoneyRaised: false,
  countNewUsers: false,
  countTabsOpened: false,
  // Logic on when to end the campaign.
  endTriggers: {
    whenGoalAchieved: true,
    whenTimeEnds: true,
  },
  goal: {
    impactUnitSingular: 'heart',
    impactUnitPlural: 'hearts',
    impactVerbPastParticiple: 'donated',
    impactVerbPastTense: 'donated',
    limitProgressToTargetMax: true,
    numberSource: 'hearts', // One of: hearts, moneyRaised, newUsers, tabsOpened
    showProgressBarLabel: true,
    showProgressBarEndText: false,
    targetNumber: 10e6,
    // transformNumberSourceValue: num => {
    //   return 9e6
    // },
  },
  // Modifications to the campaign when the campaign has
  // ended.
  onEnd: {
    content: {
      titleMarkdown: campaignEndTitle,
      descriptionMarkdown: campaignEndDescription,
      // descriptionMarkdownTwo: campaignEndDescriptionTwo,
    },
    goal: {
      // Keep the progress bar label instead of the ending text.
      showProgressBarLabel: true,
      showProgressBarEndText: false,
    },
    showCountdownTimer: false,
    showHeartsDonationButton: false,
    showSocialSharing: false,
    // socialSharing: {
    //   url: 'https://tab.gladly.io/covid-19/',
    //   FacebookShareButtonProps: {
    //     quote:
    //       'We just helped protect 100 families in rainforest communities via Cool Earth. And all we did was open browser tabs.',
    //   },
    //   RedditShareButtonProps: {
    //     title:
    //       'Tabs transformed into vital supplies for 100 families in rainforest communities',
    //   },
    //   TumblrShareButtonProps: {
    //     title:
    //       'Tabs transformed into vital supplies for 100 families in rainforest communities',
    //     caption:
    //       'We just helped protect 100 families in rainforest communities via Cool Earth. And all we did was open browser tabs.',
    //   },
    //   TwitterShareButtonProps: {
    //     title:
    //       'On @TabForACause, we just supplied 100 rainforest families via @coolearth just by opening tabs. #COVID19',
    //     related: ['@TabForACause'],
    //   },
    // },
  },
  showCountdownTimer: true,
  showHeartsDonationButton: true,
  showProgressBar: true,
  showSocialSharing: false,
  // socialSharing: undefined,
  theme: {
    color: {
      main: '#53AF4A',
      light: '#94989e',
    },
  },
  time: {
    start: '2020-11-30T17:00:00.000Z',
    end: '2021-01-05T20:00:00.000Z',
  },
})

/**
 * Return the CampaignConfiguration object for the current campaign.
 * @return {Promise<Object>} campaignConfig- see createCampaignConfiguration
 *   for structure.
 */
const getCurrentCampaignConfig = () => CURRENT_CAMPAIGN

// Outside modules shouldn't use this config. Instead, they should
// call getCampaign.js to get the CampaignData object.
export default getCurrentCampaignConfig
<commit_msg>Set up draft of campaign for new nonprofit partner<commit_after>import createCampaignConfiguration from './createCampaignConfiguration'

const campaignTitle = '## Help select a new charity partner'
const campaignDescription = `
#### Over the past 6 months, one of the consistent pieces of your feedback has been about filling a gap in the issues addressed by our partner charities: racial justice in the United States. As such, **we are adding a new nonprofit partner that will focus on supporting the Black community**, and we’d love your help in selecting it.
#### We recognize that financial support of one organization will not fix all of the problems at hand or the pain that has been inflicted on the Black community and other communities of color, but we hope to utilize our platform to make even a small impact.
#### Read about [how we selected](#) these 7 amazing organizations and [vote for the ones you would most like to see as our next charity partner](#).
`
// const campaignDescriptionTwo = ``

const campaignEndTitle = '## X'
const campaignEndDescription = `
#### X
`
// const campaignEndDescriptionTwo =
//   '#### This is only part of [our relief efforts](https://tab.gladly.io/covid-19/) for this global health crisis—more to come soon.'

// Hardcode campaign data here.
const CURRENT_CAMPAIGN = createCampaignConfiguration({
  campaignId: 'TreePlantingDec2020',
  charityId: '67d1d576-4ab1-43dd-970c-3537cd13d476',
  content: {
    titleMarkdown: campaignTitle,
    descriptionMarkdown: campaignDescription,
    // descriptionMarkdownTwo: campaignDescriptionTwo,
  },
  countMoneyRaised: false,
  countNewUsers: false,
  countTabsOpened: false,
  // Logic on when to end the campaign.
  endTriggers: {
    whenGoalAchieved: false,
    whenTimeEnds: false,
  },
  goal: {
    impactUnitSingular: 'heart',
    impactUnitPlural: 'hearts',
    impactVerbPastParticiple: 'donated',
    impactVerbPastTense: 'donated',
    limitProgressToTargetMax: true,
    numberSource: 'hearts', // One of: hearts, moneyRaised, newUsers, tabsOpened
    showProgressBarLabel: true,
    showProgressBarEndText: false,
    targetNumber: 10e6,
    // transformNumberSourceValue: num => {
    //   return 9e6
    // },
  },
  // Modifications to the campaign when the campaign has
  // ended.
  onEnd: {
    content: {
      titleMarkdown: campaignEndTitle,
      descriptionMarkdown: campaignEndDescription,
      // descriptionMarkdownTwo: campaignEndDescriptionTwo,
    },
    goal: {
      // Keep the progress bar label instead of the ending text.
      showProgressBarLabel: true,
      showProgressBarEndText: false,
    },
    showCountdownTimer: false,
    showHeartsDonationButton: false,
    showSocialSharing: false,
    // socialSharing: {
    //   url: 'https://tab.gladly.io/covid-19/',
    //   FacebookShareButtonProps: {
    //     quote:
    //       'We just helped protect 100 families in rainforest communities via Cool Earth. And all we did was open browser tabs.',
    //   },
    //   RedditShareButtonProps: {
    //     title:
    //       'Tabs transformed into vital supplies for 100 families in rainforest communities',
    //   },
    //   TumblrShareButtonProps: {
    //     title:
    //       'Tabs transformed into vital supplies for 100 families in rainforest communities',
    //     caption:
    //       'We just helped protect 100 families in rainforest communities via Cool Earth. And all we did was open browser tabs.',
    //   },
    //   TwitterShareButtonProps: {
    //     title:
    //       'On @TabForACause, we just supplied 100 rainforest families via @coolearth just by opening tabs. #COVID19',
    //     related: ['@TabForACause'],
    //   },
    // },
  },
  showCountdownTimer: false,
  showHeartsDonationButton: false,
  showProgressBar: false,
  showSocialSharing: false,
  // socialSharing: undefined,
  // theme: {
  //   color: {
  //     main: '#53AF4A',
  //     light: '#94989e',
  //   },
  // },
  time: {
    start: '2021-01-13T16:00:00.000Z',
    end: '2021-04-10T16:00:00.000Z',
  },
})

/**
 * Return the CampaignConfiguration object for the current campaign.
 * @return {Promise<Object>} campaignConfig- see createCampaignConfiguration
 *   for structure.
 */
const getCurrentCampaignConfig = () => CURRENT_CAMPAIGN

// Outside modules shouldn't use this config. Instead, they should
// call getCampaign.js to get the CampaignData object.
export default getCurrentCampaignConfig
<|endoftext|>


<commit_before>import createCampaignConfiguration from './createCampaignConfiguration'

const campaignTitle = '## COVID-19 Relief: Clean Water for 2,000'
const campaignDescription = `
#### The pandemic's impact on low-income countries will likely be devastating, especially where people do not have access to clean water, soap, or an adequate health system.
#### This phase of our relief efforts supports [Evidence Action](https://www.evidenceaction.org/responding-to-covid-19/) as they rapidly provide access to clean water and sanitation to people who need it most.
#### Spread the word and open a few tabs to help give **2,000 people access to clean water**.
##### *COVID-19 relief continues: last week, we [gave 10,000 meals](https://tab.gladly.io/covid-19/) to families in NYC.*
`
const campaignEndTitle = '## Clean Water for 2,000 People'
const campaignEndDescription = `
#### With your help, we provided **clean water access to 2,000 people** for one year through [Evidence Action](https://www.evidenceaction.org/responding-to-covid-19/)! Thank you for providing critical resources to vulnerable communities to bolster their efforts against COVID-19.
#### Share this important milestone:
`
const campaignEndDescriptionTwo =
  '#### This is only part of [our relief efforts](https://tab.gladly.io/covid-19/) for this global health crisis—more to come soon.'

// Hardcode campaign data here.
const CURRENT_CAMPAIGN = createCampaignConfiguration({
  campaignId: 'EvidenceActionApril2020',
  // charityId: undefined,
  content: {
    titleMarkdown: campaignTitle,
    descriptionMarkdown: campaignDescription,
  },
  countMoneyRaised: true,
  countNewUsers: false,
  countTabsOpened: false,
  // Logic on when to end the campaign.
  endTriggers: {
    whenGoalAchieved: true,
    whenTimeEnds: false,
  },
  goal: {
    impactUnitSingular: 'year of clean water',
    impactUnitPlural: 'years of clean water',
    impactVerbPastParticiple: 'provided',
    impactVerbPastTense: 'provided',
    limitProgressToTargetMax: true,
    numberSource: 'moneyRaised',
    showProgressBarLabel: true,
    showProgressBarEndText: false,
    targetNumber: 2000,
    transformNumberSourceValue: moneyRaised => {
      // It costs $USD 1.28 for 1 year of clean water for one person.
      return Math.floor(moneyRaised / 1.28)
    },
  },
  // Modifications to the campaign when the campaign has
  // ended.
  onEnd: {
    content: {
      titleMarkdown: campaignEndTitle,
      descriptionMarkdown: campaignEndDescription,
      descriptionMarkdownTwo: campaignEndDescriptionTwo,
    },
    goal: {
      // Keep the progress bar label instead of the ending text.
      showProgressBarLabel: true,
      showProgressBarEndText: false,
    },
    showSocialSharing: true,
    socialSharing: {
      url: 'https://tab.gladly.io/covid-19/',
      FacebookShareButtonProps: {
        quote:
          'Fighting COVID-19 is hard without clean water. On Tab for a Cause, we just gave 2,000 people access to a year of clean water—just by opening browser tabs.',
      },
      RedditShareButtonProps: {
        title: 'Tabs transformed into a year of clean water for 2,000 people',
      },
      TumblrShareButtonProps: {
        title: 'Tabs transformed into a year of clean water for 2,000 people',
        caption:
          'We just gave 2,000 people access to a year of clean water—just by opening browser tabs. Join in!',
      },
      TwitterShareButtonProps: {
        title:
          'Fighting #COVID19 is hard without clean water. On @TabForACause, we just gave 2,000 people access to a year of clean water via @EvidenceAction.',
        related: ['@TabForACause'],
      },
    },
  },
  showCountdownTimer: false,
  showHeartsDonationButton: false,
  showProgressBar: true,
  showSocialSharing: false,
  // socialSharing: undefined,
  theme: {
    color: {
      main: '#fe6f87',
      light: '#5e5f5f',
    },
  },
  time: {
    start: '2020-04-08T16:00:00.000Z',
    end: '2020-04-21T18:00:00.000Z',
  },
})

/**
 * Return the CampaignConfiguration object for the current campaign.
 * @return {Promise<Object>} campaignConfig- see createCampaignConfiguration
 *   for structure.
 */
const getCurrentCampaignConfig = () => CURRENT_CAMPAIGN

// Outside modules shouldn't use this config. Instead, they should
// call getCampaign.js to get the CampaignData object.
export default getCurrentCampaignConfig
<commit_msg>Tweak copy<commit_after>import createCampaignConfiguration from './createCampaignConfiguration'

const campaignTitle = '## COVID-19 Relief: Clean Water for 2,000'
const campaignDescription = `
#### The pandemic's impact on low-income countries will likely be devastating, especially where people do not have access to clean water, soap, or an adequate health system.
#### This phase of our relief efforts supports [Evidence Action](https://www.evidenceaction.org/responding-to-covid-19/) as they rapidly provide access to clean water and sanitation to people who need it most.
#### Spread the word and open a few tabs to help give **2,000 people access to clean water** for a year.
##### *COVID-19 relief continues: last week, we [gave 10,000 meals](https://tab.gladly.io/covid-19/) to families in NYC.*
`
const campaignEndTitle = '## Clean Water for 2,000 People'
const campaignEndDescription = `
#### With your help, we provided **clean water access to 2,000 people** for one year through [Evidence Action](https://www.evidenceaction.org/responding-to-covid-19/)! Thank you for providing critical resources to vulnerable communities to bolster their efforts against COVID-19.
#### Share this important milestone:
`
const campaignEndDescriptionTwo =
  '#### This is only part of [our relief efforts](https://tab.gladly.io/covid-19/) for this global health crisis—more to come soon.'

// Hardcode campaign data here.
const CURRENT_CAMPAIGN = createCampaignConfiguration({
  campaignId: 'EvidenceActionApril2020',
  // charityId: undefined,
  content: {
    titleMarkdown: campaignTitle,
    descriptionMarkdown: campaignDescription,
  },
  countMoneyRaised: true,
  countNewUsers: false,
  countTabsOpened: false,
  // Logic on when to end the campaign.
  endTriggers: {
    whenGoalAchieved: true,
    whenTimeEnds: false,
  },
  goal: {
    impactUnitSingular: 'year of clean water',
    impactUnitPlural: 'years of clean water',
    impactVerbPastParticiple: 'provided',
    impactVerbPastTense: 'provided',
    limitProgressToTargetMax: true,
    numberSource: 'moneyRaised',
    showProgressBarLabel: true,
    showProgressBarEndText: false,
    targetNumber: 2000,
    transformNumberSourceValue: moneyRaised => {
      // It costs $USD 1.28 for 1 year of clean water for one person.
      return Math.floor(moneyRaised / 1.28)
    },
  },
  // Modifications to the campaign when the campaign has
  // ended.
  onEnd: {
    content: {
      titleMarkdown: campaignEndTitle,
      descriptionMarkdown: campaignEndDescription,
      descriptionMarkdownTwo: campaignEndDescriptionTwo,
    },
    goal: {
      // Keep the progress bar label instead of the ending text.
      showProgressBarLabel: true,
      showProgressBarEndText: false,
    },
    showSocialSharing: true,
    socialSharing: {
      url: 'https://tab.gladly.io/covid-19/',
      FacebookShareButtonProps: {
        quote:
          'Fighting COVID-19 is hard without clean water. On Tab for a Cause, we just gave 2,000 people access to a year of clean water—just by opening browser tabs.',
      },
      RedditShareButtonProps: {
        title: 'Tabs transformed into a year of clean water for 2,000 people',
      },
      TumblrShareButtonProps: {
        title: 'Tabs transformed into a year of clean water for 2,000 people',
        caption:
          'We just gave 2,000 people access to a year of clean water—just by opening browser tabs. Join in!',
      },
      TwitterShareButtonProps: {
        title:
          'Fighting #COVID19 is hard without clean water. On @TabForACause, we just gave 2,000 people access to a year of clean water via @EvidenceAction.',
        related: ['@TabForACause'],
      },
    },
  },
  showCountdownTimer: false,
  showHeartsDonationButton: false,
  showProgressBar: true,
  showSocialSharing: false,
  // socialSharing: undefined,
  theme: {
    color: {
      main: '#fe6f87',
      light: '#5e5f5f',
    },
  },
  time: {
    start: '2020-04-08T16:00:00.000Z',
    end: '2020-04-21T18:00:00.000Z',
  },
})

/**
 * Return the CampaignConfiguration object for the current campaign.
 * @return {Promise<Object>} campaignConfig- see createCampaignConfiguration
 *   for structure.
 */
const getCurrentCampaignConfig = () => CURRENT_CAMPAIGN

// Outside modules shouldn't use this config. Instead, they should
// call getCampaign.js to get the CampaignData object.
export default getCurrentCampaignConfig
<|endoftext|>


<commit_before>import React from 'react'
import {
  Link
} from 'react-router'

class IntroBlock extends React.Component {

  static propTypes = {
    data: React.PropTypes.object,
  }

  render () {

    return (

Welcome

              Farnborough Guide is a new service that aims to help businesses promote themselves to local residents and other businesses alike. The site will also help people find out about interesting services, events, places, activities and a whole lot more.

2) We are seeking photos

              We are launching the site early by introducing our local photography campaign. We invite everyone to share their photgraphs of the town here on Farnborough Guide. We are especially interested in businesses around the town whom wish to share photographs of what they do, what they sell. help spread the word.

1) Sign-up

              So you have some photos to share with everyone in the town? What are you waiting for? Once registered you may upload new images via our photos page!

            { /* Dan, I have created a function that returns the appropriate button at this stage */}
            {this._renderButton()}

    )
  }

  // Dan, If not logged in show the Register button, otherwise show the view all photos button
  _renderButton() {
    if ( !this.props.data.user ) {
      return <Link className="f3 fw4 hover-red no-underline black-70 dib pv2 ph3 ba" to="/signup" >Register Now!</Link>
    } else {
      return <Link className="f3 fw4 hover-red no-underline black-70 dib pv2 ph3 ba" to="/Photo" >View all photos</Link>
    }
  }
}

export default IntroBlock
<commit_msg>Added Steps For Users<commit_after>import React from 'react'
import {
  Link
} from 'react-router'

class IntroBlock extends React.Component {

  static propTypes = {
    data: React.PropTypes.object,
  }

  render () {

    return (

Welcome

              Farnborough Guide is a new service that aims to help businesses promote themselves to local residents and other businesses alike. The site will also help people find out about interesting services, events, places, activities and a whole lot more.

2.) We are seeking photos

              We are launching the site early by introducing our local photography campaign. We invite everyone to share their photgraphs of the town here on Farnborough Guide. We are especially interested in businesses around the town whom wish to share photographs of what they do, what they sell. help spread the word.

1.) Sign-up

              So you have some photos to share with everyone in the town? What are you waiting for? Once registered you may upload new images via our photos page!

            { /* Dan, I have created a function that returns the appropriate button at this stage */}
            {this._renderButton()}

    )
  }

  // Dan, If not logged in show the Register button, otherwise show the view all photos button
  _renderButton() {
    if ( !this.props.data.user ) {
      return <Link className="f3 fw4 hover-red no-underline black-70 dib pv2 ph3 ba" to="/signup" >Register Now!</Link>
    } else {
      return <Link className="f3 fw4 hover-red no-underline black-70 dib pv2 ph3 ba" to="/Photo" >View all photos</Link>
    }
  }
}

export default IntroBlock
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import { LogoSpinner, Button, ErrorMsg, ServerErrorMsg, InputGroup } from 'binary-components';
import { isValidEmail } from 'binary-utils';
import { api } from '../_data/LiveData';

export default class VerifyEmailCard extends PureComponent {

    static contextTypes = {
        router: () => undefined,
    };

	constructor(props) {
		super(props);
		this.state = {
			progress: false,
			email: '',
		};
	}

	onEmailChange = event =>
        this.setState({ email: event.target.value });

    onFormSubmit = (e: SyntheticEvent) => {
		e.preventDefault();
        this.setState({
            validatedOnce: true,
        });
        if (this.emailIsValid) {
            this.verifyEmail();
        }
    }

    verifyEmail = async () => {
        const { email } = this.state;

        try {
            this.setState({
                progress: true,
                error: false,
            });
            await api.verifyEmail(email, 'account_opening');
			this.context.router.push('/signup2');
        } catch (serverError) {
            this.setState({
				serverError,
				progress: false,
			});
        }
    }

	render() {
		const { email, serverError, progress, validatedOnce } = this.state;
		this.emailIsValid = isValidEmail(email);

		return (

                    <LogoSpinner spinning={progress} />

				{serverError && <ServerErrorMsg text={serverError} />}
				<form onSubmit={this.onFormSubmit}>
					<InputGroup
						type="email"
						placeholder="Email"
						onChange={this.onEmailChange}
					/>
					{validatedOnce && !this.emailIsValid &&
						<ErrorMsg text="Enter a valid email" />
					}
					<Button disabled={progress} text="Create Free Account" />
				</form>

		);
	}
}
<commit_msg>add a back button in create account page (for iOS app only).<commit_after>import React, { PureComponent } from 'react';
import { LogoSpinner, Button, ErrorMsg, ServerErrorMsg, InputGroup, BackButton } from 'binary-components';
import { isValidEmail } from 'binary-utils';
import { api } from '../_data/LiveData';

export default class VerifyEmailCard extends PureComponent {

    static contextTypes = {
        router: () => undefined,
    };

	constructor(props) {
		super(props);
		this.state = {
			progress: false,
			email: '',
		};
	}

	onEmailChange = event =>
        this.setState({ email: event.target.value });

    onFormSubmit = (e: SyntheticEvent) => {
		e.preventDefault();
        this.setState({
            validatedOnce: true,
        });
        if (this.emailIsValid) {
            this.verifyEmail();
        }
    }

    verifyEmail = async () => {
        const { email } = this.state;

        try {
            this.setState({
                progress: true,
                error: false,
            });
            await api.verifyEmail(email, 'account_opening');
			this.context.router.push('/signup2');
        } catch (serverError) {
            this.setState({
				serverError,
				progress: false,
			});
        }
    }

	render() {
		const { email, serverError, progress, validatedOnce } = this.state;
		this.emailIsValid = isValidEmail(email);

		return (

				{window.cordova && device.platform === 'iOS' &&

					<BackButton onClick={() => window.history.back()} />

}

						<LogoSpinner spinning={progress} />

					{serverError && <ServerErrorMsg text={serverError} />}
					<form onSubmit={this.onFormSubmit}>
						<InputGroup
							type="email"
							placeholder="Email"
							onChange={this.onEmailChange}
						/>
						{validatedOnce && !this.emailIsValid &&
							<ErrorMsg text="Enter a valid email" />
						}
						<Button disabled={progress} text="Create Free Account" />
					</form>

		);
	}
}
<|endoftext|>


<commit_before>define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitManager/model/Traits'],
	function (Backbone, Components, Selectors, Traits) {

		return Backbone.Model.extend({

			defaults: {
				tagName: 'div',
				type: '',
				editable: false,
				removable: true,
				draggable: true,
				droppable: true,
				badgable: true,
				stylable: true,
				copyable: true,
				void: false,
				state: '',
				status: '',
				previousModel: '',
				content: '',
				style: {},
				attributes: {},
				traits: ['id', 'title'],
			},

			initialize: function(o, opt) {
				// Check void elements
				if(opt && opt.config && opt.config.voidElements.indexOf(this.get('tagName')) >= 0)
					this.set('void', true);

				this.sm = opt ? opt.sm || {} : {};
				this.config 	= o || {};
				this.defaultC = this.config.components || [];
				this.defaultCl = this.normalizeClasses(this.config.classes || []);
				this.components	= new Components(this.defaultC, opt);
				this.set('components', this.components);
				this.set('classes', new Selectors(this.defaultCl));
				var traits = new Traits();
				traits.setTarget(this);
				traits.add(this.get('traits'));
				this.set('traits', traits);
			},

			/**
			 * Normalize input classes from array to array of objects
			 * @param {Array} arr
			 * @return {Array}
			 * @private
			 */
			normalizeClasses: function(arr) {
				var res = [];

				if(!this.sm.get)
					return;

				var clm = this.sm.get('SelectorManager');
				if(!clm)
					return;

				arr.forEach(function(val){
					var name = '';

					if(typeof val === 'string')
						name = val;
					else
						name = val.name;

					var model = clm.add(name);
					res.push(model);
				});
				return res;
			},

			/**
			 * Override original clone method
			 * @private
			 */
	    clone: function() {
	    	var attr = _.clone(this.attributes),
	    			comp = this.get('components'),
						traits = this.get('traits'),
	    			cls = this.get('classes');
	    	attr.components = [];
	    	attr.classes = [];
				attr.traits = [];
	    	if(comp.length){
					comp.each(function(md,i) {
						attr.components[i]	= md.clone();
					});
	    	}
				if(traits.length){
					traits.each(function(md, i) {
						attr.traits[i] = md.clone();
					});
	    	}
	    	if(cls.length){
					cls.each(function(md,i) {
						attr.classes[i]	= md.get('name');
					});
	    	}
	    	attr.status = '';
	      return new this.constructor(attr, {sm: this.sm});
	    },

			/**
			 * Get name of the component
			 *
			 * @return {String}
			 * @private
			 * */
			getName: function() {
				if(!this.name){
					var id = this.cid.replace(/\D/g,''),
						type = this.get('type');
					var tag = this.get('tagName');
					tag = tag == 'div' ? 'box' : tag;
					tag = type ? type : tag;
					this.name 	= tag.charAt(0).toUpperCase() + tag.slice(1) + ' ' + id;
				}
				return this.name;
			},

		}, {

			/**
			 * Detect if the passed element is a valid component.
			 * In case the element is valid an object abstracted
			 * from the element will be returned
			 * @param {HTMLElement}
			 * @return {Object}
			 * @private
			 */
			isValidEl: function(el) {
				var result = '';
				if(el.tagName == 'DIV')
					result = {tagName: 'div'};
				return result;
			}

		});
});
<commit_msg>Start to moving 'to code' part inside the Component<commit_after>define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitManager/model/Traits'],
	function (Backbone, Components, Selectors, Traits) {

		return Backbone.Model.extend({

			defaults: {
				tagName: 'div',
				type: '',
				editable: false,
				removable: true,
				draggable: true,
				droppable: true,
				badgable: true,
				stylable: true,
				copyable: true,
				void: false,
				state: '',
				status: '',
				previousModel: '',
				content: '',
				style: {},
				attributes: {},
				traits: ['id', 'title'],
			},

			initialize: function(o, opt) {
				// Check void elements
				if(opt && opt.config && opt.config.voidElements.indexOf(this.get('tagName')) >= 0)
					this.set('void', true);

				this.sm = opt ? opt.sm || {} : {};
				this.config 	= o || {};
				this.defaultC = this.config.components || [];
				this.defaultCl = this.normalizeClasses(this.config.classes || []);
				this.components	= new Components(this.defaultC, opt);
				this.set('components', this.components);
				this.set('classes', new Selectors(this.defaultCl));
				var traits = new Traits();
				traits.setTarget(this);
				traits.add(this.get('traits'));
				this.set('traits', traits);
			},

			/**
			 * Normalize input classes from array to array of objects
			 * @param {Array} arr
			 * @return {Array}
			 * @private
			 */
			normalizeClasses: function(arr) {
				var res = [];

				if(!this.sm.get)
					return;

				var clm = this.sm.get('SelectorManager');
				if(!clm)
					return;

				arr.forEach(function(val){
					var name = '';

					if(typeof val === 'string')
						name = val;
					else
						name = val.name;

					var model = clm.add(name);
					res.push(model);
				});
				return res;
			},

			/**
			 * Override original clone method
			 * @private
			 */
	    clone: function() {
	    	var attr = _.clone(this.attributes),
	    			comp = this.get('components'),
						traits = this.get('traits'),
	    			cls = this.get('classes');
	    	attr.components = [];
	    	attr.classes = [];
				attr.traits = [];
	    	if(comp.length){
					comp.each(function(md,i) {
						attr.components[i]	= md.clone();
					});
	    	}
				if(traits.length){
					traits.each(function(md, i) {
						attr.traits[i] = md.clone();
					});
	    	}
	    	if(cls.length){
					cls.each(function(md,i) {
						attr.classes[i]	= md.get('name');
					});
	    	}
	    	attr.status = '';
	      return new this.constructor(attr, {sm: this.sm});
	    },

			/**
			 * Get name of the component
			 * @return {string}
			 * @private
			 * */
			getName: function() {
				if(!this.name){
					var id = this.cid.replace(/\D/g,''),
						type = this.get('type');
					var tag = this.get('tagName');
					tag = tag == 'div' ? 'box' : tag;
					tag = type ? type : tag;
					this.name 	= tag.charAt(0).toUpperCase() + tag.slice(1) + ' ' + id;
				}
				return this.name;
			},

			/**
			 * Return HTML string of the component
			 * @return {string} HTML string
			 * @private
			 */
			toHTML: function() {
				var code = '';
				var m = this;
				var tag = m.get('tagName'),
				attrs = m.get('attributes'),
				sTag = m.get('void'),
				attrId = '';
				// Build the string of attributes
				var attr = '';
				_.each(attrs, function(value, prop){
					// TODO: to refactor
					if(prop == 'onmousedown')
						return;
					attr += value && prop!='style' ? ' ' + prop + '="' + value + '"' : '';
				});
				// Build the string of classes
				var strCls = '';
				m.get('classes').each(function(m){
					strCls += ' ' + m.get('name');
				});
				strCls = strCls !== '' ? ' class="' + strCls.trim() + '"' : '';

				/*
				// TODO: to refactor
				if(m.get('type') == 'image'){
						tag = 'img';
						sTag	= 1;
						attr 	+= ' src="' + m.get('src') + '"';
				}
				*/
				 // If style is not empty I need an ID attached to the component
				 // TODO: need to refactor in case of 'ID Trait'
				 if(!_.isEmpty(m.get('style')))
 					attrId = ' id="' + m.cid + '" ';

				code += '<' + tag + strCls + attrId + attr + (sTag ? '/' : '') + '>' + m.get('content');

				var cln = m.get('components');
				if(cln.length)
					code += this.toHTML(cln);

				if(!sTag)
					code += '</'+tag+'>';

				return code;
			}

		}, {

			/**
			 * Detect if the passed element is a valid component.
			 * In case the element is valid an object abstracted
			 * from the element will be returned
			 * @param {HTMLElement}
			 * @return {Object}
			 * @private
			 */
			isValidEl: function(el) {
				var result = '';
				if(el.tagName == 'DIV')
					result = {tagName: 'div'};
				return result;
			}

		});
});
<|endoftext|>


<commit_before>
import { Component, PropTypes } from "react";
import { connect } from "react-redux";
import { css } from "aphrodite";
import collections from "../../../util/collections";
import styles from "../../../util/styles";
import backgrounds from "../../../util/backgrounds";
import headerActions from "../../../store/header";
import AudioControls from "./audio.Controls";
import AudioTitle from "./audio.Title";
import Styles from "./audio.styles.fullPlayer";

const mapStateToProps = state =>
  ({
    ...state.audio,
    header: state.header,
  });

@connect(mapStateToProps)
export default class FullPlayer extends Component {

  static propTypes = {
    dispatch: PropTypes.func,
    header: PropTypes.object, // eslint-disable-line
    playing: PropTypes.object, // eslint-disable-line
    audio: PropTypes.object, // eslint-disable-line
    data: PropTypes.object, // eslint-disable-line
    setPlaylist: PropTypes.func,
    setPlaying: PropTypes.func,
    play: PropTypes.func,
    pause: PropTypes.func,
    seek: PropTypes.number,
    resetOrder: PropTypes.func,
    shuffle: PropTypes.func,
    resetRepeat: PropTypes.func,
    repeatOne: PropTypes.func,
    state: PropTypes.string,
    repeat: PropTypes.string,
  }

  state = {
    isShort: false,
    hadHeader: true,
  }

  componentWillMount() {
    this.props.dispatch(headerActions.hide({ statusBar: false }));
    this.setState({
      hadHeader: this.props.header.visible,
    });
  }

  componentDidMount() {
    this.setArtworkState();
  }

  componentWillUnmount() {
    this.props.dispatch(headerActions.show({ visible: this.state.hadHeader, statusBar: true }));
  }

  setArtworkState = () => {
    const artworkContainer = this.refs.artworkContainer;
    this.setState({
      isShort: artworkContainer.clientWidth > artworkContainer.clientHeight,
    });
    return null;
  }

  getArtist = () => {
    const { album, track } = this.props.playing;
    return track.artist || album.artist || "NewSpring";
  }

  getImageUrl = (images, blurred = false) => {
    const image = blurred ? images[1] : images[0];

    return image.url;
  };

  getArtworkStyles = (album) => {
    const artworkContainer = this.refs.artworkContainer;
    const awStyles = backgrounds.styles(album);

    if (this.state.isShort) {
      awStyles.height = `${artworkContainer.clientHeight}px`;
      awStyles.backgroundSize = "contain";
      awStyles.backgroundColor = "transparent";
    }

    return awStyles;
  };

  getArtworkClasses = (album) => {
    const classes = [
      "one-whole",
      "overlay--gradient",
      "background--fill",
      collections.classes(album),
    ];

    if (!this.state.isShort) {
      classes.push("ratio--square");
    }

    return classes.join(" ");
  };

  getArtworkContainerStyles = () => {
    const awcStyles = {};

    if (this.state.isShort) {
      awcStyles.height = "100%";
      awcStyles.backgroundImage = `
        url('${this.getImage(this.props.playing.album, { blurred: true })}')
      `;
      awcStyles.paddingTop = "10px";
      awcStyles.paddingBottom = "10px";
      awcStyles.backgroundSize = "cover";
    }

    return awcStyles;
  };

  getImage = (data, options = { blurred: false }) => {
    const { images } = data.content;
    const image = options.blurred ? images[1] : images[0];
    return image.url;
  }

  toggle = () => {
    const { state } = this.props.audio;

    if (!this.props.audio.playing.album.title) {
      const { data } = this.props;
      const album = {
        title: data.title,
        image: this.getImage(data),
        blurredImage: this.getImage(data, { blurred: true }),
        id: data.entryId,
      };

      this.props.setPlaylist(data.tracks);
      this.props.setPlaying({
        album,
        track: data.tracks[0],
      });
    }

    if (state !== "playing") {
      this.props.play();
      return;
    }

    if (state === "playing") {
      this.props.pause();
      return;
    }
  }

  shuffle = () => {
    const { order } = this.props.audio;

    if (order === "shuffle") {
      this.props.resetOrder();
      return;
    }

    this.props.shuffle();
  }

  repeat = () => {
    const { repeat } = this.props.audio;

    if (repeat === "repeat-one") {
      this.props.resetRepeat();
      return;
    }

    if (repeat === "repeat") {
      this.props.repeatOne();
      return;
    }

    this.props.repeat();
  }

  hackBackgroundStyles = () =>
    ({
      position: "absolute",
      top: 0,
      left: 0,
      width: "100%",
      height: "100%",
      zIndex: -1,
    });

  render() {
    const { state, playing } = this.props;
    const { album, track } = playing;
    const { colors, isLight } = album.content;

    const bgColorStyle = {
      height: "100%",
    };

    if (colors && colors[0] && colors[0].value) {
      bgColorStyle.backgroundColor = `#${colors[0].value}`;
    }

    return (

        <div
          className={
            `${css(Styles["player-flex"])} ${css(Styles["player-container"])}`
          }
        >

          <div
            className={
              `text-center soft-sides ${css(Styles["player-flex-one"])}`
            }
          >

            <AudioTitle
              trackTitle={track.title}
              artistName={this.getArtist()}
              albumTitle={album.title}
              isPlaying={state !== "default"}
              isLight={isLight}
              channelName={album.channelName}
            />

            <AudioControls
              audio={this.props}
              isLight={isLight}
            />

    );
  }
}
<commit_msg>removed seek prop<commit_after>
import { Component, PropTypes } from "react";
import { connect } from "react-redux";
import { css } from "aphrodite";
import collections from "../../../util/collections";
import styles from "../../../util/styles";
import backgrounds from "../../../util/backgrounds";
import headerActions from "../../../store/header";
import AudioControls from "./audio.Controls";
import AudioTitle from "./audio.Title";
import Styles from "./audio.styles.fullPlayer";

const mapStateToProps = state =>
  ({
    ...state.audio,
    header: state.header,
  });

@connect(mapStateToProps)
export default class FullPlayer extends Component {

  static propTypes = {
    dispatch: PropTypes.func,
    header: PropTypes.object, // eslint-disable-line
    playing: PropTypes.object, // eslint-disable-line
    audio: PropTypes.object, // eslint-disable-line
    data: PropTypes.object, // eslint-disable-line
    setPlaylist: PropTypes.func,
    setPlaying: PropTypes.func,
    play: PropTypes.func,
    pause: PropTypes.func,
    resetOrder: PropTypes.func,
    shuffle: PropTypes.func,
    resetRepeat: PropTypes.func,
    repeatOne: PropTypes.func,
    state: PropTypes.string,
    repeat: PropTypes.string,
  }

  state = {
    isShort: false,
    hadHeader: true,
  }

  componentWillMount() {
    this.props.dispatch(headerActions.hide({ statusBar: false }));
    this.setState({
      hadHeader: this.props.header.visible,
    });
  }

  componentDidMount() {
    this.setArtworkState();
  }

  componentWillUnmount() {
    this.props.dispatch(headerActions.show({ visible: this.state.hadHeader, statusBar: true }));
  }

  setArtworkState = () => {
    const artworkContainer = this.refs.artworkContainer;
    this.setState({
      isShort: artworkContainer.clientWidth > artworkContainer.clientHeight,
    });
    return null;
  }

  getArtist = () => {
    const { album, track } = this.props.playing;
    return track.artist || album.artist || "NewSpring";
  }

  getImageUrl = (images, blurred = false) => {
    const image = blurred ? images[1] : images[0];

    return image.url;
  };

  getArtworkStyles = (album) => {
    const artworkContainer = this.refs.artworkContainer;
    const awStyles = backgrounds.styles(album);

    if (this.state.isShort) {
      awStyles.height = `${artworkContainer.clientHeight}px`;
      awStyles.backgroundSize = "contain";
      awStyles.backgroundColor = "transparent";
    }

    return awStyles;
  };

  getArtworkClasses = (album) => {
    const classes = [
      "one-whole",
      "overlay--gradient",
      "background--fill",
      collections.classes(album),
    ];

    if (!this.state.isShort) {
      classes.push("ratio--square");
    }

    return classes.join(" ");
  };

  getArtworkContainerStyles = () => {
    const awcStyles = {};

    if (this.state.isShort) {
      awcStyles.height = "100%";
      awcStyles.backgroundImage = `
        url('${this.getImage(this.props.playing.album, { blurred: true })}')
      `;
      awcStyles.paddingTop = "10px";
      awcStyles.paddingBottom = "10px";
      awcStyles.backgroundSize = "cover";
    }

    return awcStyles;
  };

  getImage = (data, options = { blurred: false }) => {
    const { images } = data.content;
    const image = options.blurred ? images[1] : images[0];
    return image.url;
  }

  toggle = () => {
    const { state } = this.props.audio;

    if (!this.props.audio.playing.album.title) {
      const { data } = this.props;
      const album = {
        title: data.title,
        image: this.getImage(data),
        blurredImage: this.getImage(data, { blurred: true }),
        id: data.entryId,
      };

      this.props.setPlaylist(data.tracks);
      this.props.setPlaying({
        album,
        track: data.tracks[0],
      });
    }

    if (state !== "playing") {
      this.props.play();
      return;
    }

    if (state === "playing") {
      this.props.pause();
      return;
    }
  }

  shuffle = () => {
    const { order } = this.props.audio;

    if (order === "shuffle") {
      this.props.resetOrder();
      return;
    }

    this.props.shuffle();
  }

  repeat = () => {
    const { repeat } = this.props.audio;

    if (repeat === "repeat-one") {
      this.props.resetRepeat();
      return;
    }

    if (repeat === "repeat") {
      this.props.repeatOne();
      return;
    }

    this.props.repeat();
  }

  hackBackgroundStyles = () =>
    ({
      position: "absolute",
      top: 0,
      left: 0,
      width: "100%",
      height: "100%",
      zIndex: -1,
    });

  render() {
    const { state, playing } = this.props;
    const { album, track } = playing;
    const { colors, isLight } = album.content;

    const bgColorStyle = {
      height: "100%",
    };

    if (colors && colors[0] && colors[0].value) {
      bgColorStyle.backgroundColor = `#${colors[0].value}`;
    }

    return (

        <div
          className={
            `${css(Styles["player-flex"])} ${css(Styles["player-container"])}`
          }
        >

          <div
            className={
              `text-center soft-sides ${css(Styles["player-flex-one"])}`
            }
          >

            <AudioTitle
              trackTitle={track.title}
              artistName={this.getArtist()}
              albumTitle={album.title}
              isPlaying={state !== "default"}
              isLight={isLight}
              channelName={album.channelName}
            />

            <AudioControls
              audio={this.props}
              isLight={isLight}
            />

    );
  }
}
<|endoftext|>


<commit_before>// 20: spread - with-arrays
// To do: make all tests pass, leave the assert lines unchanged!
// Follow the hints of the failure messages!

describe('Spread with arrays', () => {
  // TODO add just `...` kata
  it('extracts each array item', function() {
    //// const [b, a] = [...[1, 2]];
    const [a, b] = [...[1, 2]];
    assert.equal(a, 1);
    assert.equal(b, 2);
  });
  it('in combination with rest', function() {
    //// const [a, b, ...rest] = [...[0, 1, 2, 3, 4, 5]];
    const [a, b, ...rest] = [...[1, 2, 3, 4, 5]];
    assert.equal(a, 1);
    assert.equal(b, 2);
    assert.deepEqual(rest, [3, 4, 5]);
  });
  it('spreading into the rest', function() {
    //// const [...rest] = [...[,1, 2, 3, 4, 5]];
    const [...rest] = [...[1, 2, 3, 4, 5]];
    assert.deepEqual(rest, [1, 2, 3, 4, 5]);
  });
  describe('used as function parameter', () => {
    it('prefix with `...` to spread as function params', function() {
      const magicNumbers = [1, 2];
      const fn = (magicA, magicB) => {
        assert.deepEqual(magicNumbers[0], magicA);
        assert.deepEqual(magicNumbers[1], magicB);
      };
      //// fn(magicNumbers);
      fn(...magicNumbers);
    });
    it('pass an array of numbers to Math.max()', function() {
      //// const max = Math.max(...[23, 0, 42, 43]);
      const max = Math.max(...[23, 0, 42]);
      assert.equal(max, 42);
    });
  });
});
<commit_msg>Enhance the kata a bit. Trying to make it easier to learn the spread syntax and its specialities.<commit_after>// 20: spread - with-arrays
// To do: make all tests pass, leave the assert lines unchanged!
// Follow the hints of the failure messages!

describe('Spread syntax with arrays', () => {
  describe('basically', () => {
    it('expands the items of an array by prefixing it with `...`', function() {
      const middle = [1, 2, 3];
      //// const arr = [0, middle, 4];
      const arr = [0, ...middle, 4];
      assert.deepEqual(arr, [0, 1, 2, 3, 4]);
    });
  });
  describe('is (in a way) the opposite to the rest syntax', function() {
    it('both use `...` to either expand all items and collect them', function() {
      //// const [...rest] = [...[,1, 2, 3, 4, 5]];
      const [...rest] = [...[1, 2, 3, 4, 5]];
      assert.deepEqual(rest, [1, 2, 3, 4, 5]);
    });
    it('rest syntax must be last in an array, spread can be used in any place', function() {
      //// const [a, b, ...rest] = [1, [2, 3], 4, 5];
      const [a, b, ...rest] = [1, ...[2, 3], 4, 5];
      assert.equal(a, 1);
      assert.equal(b, 2);
      assert.deepEqual(rest, [3, 4, 5]);
    });
  });
  describe('used as function parameter', () => {
    it('prefix with `...` to spread as function params', function() {
      const magicNumbers = [1, 2];
      const fn = (magicA, magicB) => {
        assert.deepEqual(magicNumbers[0], magicA);
        assert.deepEqual(magicNumbers[1], magicB);
      };
      //// fn(magicNumbers);
      fn(...magicNumbers);
    });
    it('pass an array of numbers to Math.max()', function() {
      //// const max = Math.max(...[23, 0, 42, 43]);
      const max = Math.max(...[23, 0, 42]);
      assert.equal(max, 42);
    });
  });
  describe('used as constructor parameter', () => {
    // TODO
  });
});
<|endoftext|>


<commit_before>// 17: unicode - in strings
// To do: make all tests pass, leave the assert lines unchanged!
// Follow the hints of the failure messages!

describe('unicode strings', () => {

  it('are \\u prefixed', () => {
    const nuclear = 2622;
    assert.equal(nuclear, '☢');
  });

  it('value is 4 bytes/digits', () => {
    const nuclear = '\u26222';
    assert.equal(`no more ${nuclear}`, 'no more ☢');
  });

  it('value is hexadecimal', () => {
    const nuclear = `\u006B\u006A more \u2622`;
    assert.equal(nuclear, 'no more ☢');
  });

  it('curly braces may surround the value', () => {
    const nuclear = `\u{0000000006E}\u00006F more \u2622`;
    assert.equal(nuclear, 'no more ☢');
  });

});
<commit_msg>Katafy unicode kata.<commit_after>// 17: unicode - in strings
// To do: make all tests pass, leave the assert lines unchanged!
// Follow the hints of the failure messages!

describe('Unicode in strings', () => {
  it('are prefixed with `\\u` (one backslash and u)', () => {
    //// const nuclear = 2622;
    const nuclear = '\u2622';
    assert.equal(nuclear, '☢');
  });
  it('value is 4 bytes/digits', () => {
    //// const nuclear = '\u26222';
    const nuclear = '\u2622';
    assert.equal(`no more ${nuclear}`, 'no more ☢');
  });
  it('even "normal" character`s values can be written as hexadecimal unicode', () => {
    //// const nuclear = `\u006B\u006A more \u2622`;
    const nuclear = `\u006E\u006F more \u2622`;
    assert.equal(nuclear, 'no more ☢');
  });
  it('curly braces may surround the value', () => {
    //// const nuclear = `\u{0000000006E}\u00006F more \u2622`;
    const nuclear = `\u{0000000006E}\u{00006F} more \u2622`;
    assert.equal(nuclear, 'no more ☢');
  });
});
<|endoftext|>


<commit_before>import { Vector3 } from '../../math/Vector3.js';
import { Curve } from '../core/Curve.js';

/**
 * Centripetal CatmullRom Curve - which is useful for avoiding
 * cusps and self-intersections in non-uniform catmull rom curves.
 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
 *
 * curve.type accepts centripetal(default), chordal and catmullrom
 * curve.tension is used for catmullrom which defaults to 0.5
 */

/*
Based on an optimized c++ solution in
 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
 - http://ideone.com/NoEbVM

This CubicPoly class could be used for reusing some variables and calculations,
but for three.js curve use, it could be possible inlined and flatten into a single function call
which can be placed in CurveUtils.
*/

function CubicPoly() {

	let c0 = 0, c1 = 0, c2 = 0, c3 = 0;

	/*
	 * Compute coefficients for a cubic polynomial
	 *   p(s) = c0 + c1*s + c2*s^2 + c3*s^3
	 * such that
	 *   p(0) = x0, p(1) = x1
	 *  and
	 *   p'(0) = t0, p'(1) = t1.
	 */
	function init( x0, x1, t0, t1 ) {

		c0 = x0;
		c1 = t0;
		c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
		c3 = 2 * x0 - 2 * x1 + t0 + t1;

	}

	return {

		initCatmullRom: function ( x0, x1, x2, x3, tension ) {

			init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );

		},

		initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {

			// compute tangents when parameterized in [t1,t2]
			let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
			let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;

			// rescale tangents for parametrization in [0,1]
			t1 *= dt1;
			t2 *= dt1;

			init( x1, x2, t1, t2 );

		},

		calc: function ( t ) {

			const t2 = t * t;
			const t3 = t2 * t;
			return c0 + c1 * t + c2 * t2 + c3 * t3;

		}

	};

}

//

const tmp = new Vector3();
const px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly();

class CatmullRomCurve3 extends Curve {

	constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {

		super();

		this.type = 'CatmullRomCurve3';
		Object.defineProperty( this, 'isCatmullRomCurve3', { value: true } );
    this.points = points;
    this.closed = closed;
    this.curveType = curveType;
    this.tension = tension;

	}

	getPoint( t, optionalTarget = new Vector3() ) {

		const point = optionalTarget;

		const points = this.points;
		const l = points.length;

		const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
		let intPoint = Math.floor( p );
		let weight = p - intPoint;

		if ( this.closed ) {

			intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;

		} else if ( weight === 0 && intPoint === l - 1 ) {

			intPoint = l - 2;
			weight = 1;

		}

		let p0, p3; // 4 points (p1 & p2 defined below)

		if ( this.closed || intPoint > 0 ) {

			p0 = points[ ( intPoint - 1 ) % l ];

		} else {

			// extrapolate first point
			tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
			p0 = tmp;

		}

		const p1 = points[ intPoint % l ];
		const p2 = points[ ( intPoint + 1 ) % l ];

		if ( this.closed || intPoint + 2 < l ) {

			p3 = points[ ( intPoint + 2 ) % l ];

		} else {

			// extrapolate last point
			tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
			p3 = tmp;

		}

		if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {

			// init Centripetal / Chordal Catmull-Rom
			const pow = this.curveType === 'chordal' ? 0.5 : 0.25;
			let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
			let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
			let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );

			// safety check for repeated points
			if ( dt1 < 1e-4 )
				dt1 = 1.0;
			if ( dt0 < 1e-4 )
				dt0 = dt1;
			if ( dt2 < 1e-4 )
				dt2 = dt1;

			px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
			py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
			pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );

		} else if ( this.curveType === 'catmullrom' ) {

			px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
			py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
			pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );

		}

		point.set(
			px.calc( weight ),
			py.calc( weight ),
			pz.calc( weight )
		);

		return point;

	}
	copy( source ) {

		super.copy( source );

		this.points = [];

		for ( let i = 0, l = source.points.length; i < l; i ++ ) {

			const point = source.points[ i ];

			this.points.push( point.clone() );

		}

		this.closed = source.closed;
		this.curveType = source.curveType;
		this.tension = source.tension;

		return this;

	}
	toJSON() {

		const data = super.toJSON();

		data.points = [];

		for ( let i = 0, l = this.points.length; i < l; i ++ ) {

			const point = this.points[ i ];
			data.points.push( point.toArray() );

		}

		data.closed = this.closed;
		data.curveType = this.curveType;
		data.tension = this.tension;

		return data;

	}
	fromJSON( json ) {

		super.fromJSON( json );

		this.points = [];

		for ( let i = 0, l = json.points.length; i < l; i ++ ) {

			const point = json.points[ i ];
			this.points.push( new Vector3().fromArray( point ) );

		}

		this.closed = json.closed;
		this.curveType = json.curveType;
		this.tension = json.tension;

		return this;

	}

}

export { CatmullRomCurve3 };
<commit_msg>lint fix<commit_after>import { Vector3 } from '../../math/Vector3.js';
import { Curve } from '../core/Curve.js';

/**
 * Centripetal CatmullRom Curve - which is useful for avoiding
 * cusps and self-intersections in non-uniform catmull rom curves.
 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
 *
 * curve.type accepts centripetal(default), chordal and catmullrom
 * curve.tension is used for catmullrom which defaults to 0.5
 */

/*
Based on an optimized c++ solution in
 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
 - http://ideone.com/NoEbVM

This CubicPoly class could be used for reusing some variables and calculations,
but for three.js curve use, it could be possible inlined and flatten into a single function call
which can be placed in CurveUtils.
*/

function CubicPoly() {

	let c0 = 0, c1 = 0, c2 = 0, c3 = 0;

	/*
	 * Compute coefficients for a cubic polynomial
	 *   p(s) = c0 + c1*s + c2*s^2 + c3*s^3
	 * such that
	 *   p(0) = x0, p(1) = x1
	 *  and
	 *   p'(0) = t0, p'(1) = t1.
	 */
	function init( x0, x1, t0, t1 ) {

		c0 = x0;
		c1 = t0;
		c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
		c3 = 2 * x0 - 2 * x1 + t0 + t1;

	}

	return {

		initCatmullRom: function ( x0, x1, x2, x3, tension ) {

			init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );

		},

		initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {

			// compute tangents when parameterized in [t1,t2]
			let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
			let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;

			// rescale tangents for parametrization in [0,1]
			t1 *= dt1;
			t2 *= dt1;

			init( x1, x2, t1, t2 );

		},

		calc: function ( t ) {

			const t2 = t * t;
			const t3 = t2 * t;
			return c0 + c1 * t + c2 * t2 + c3 * t3;

		}

	};

}

//

const tmp = new Vector3();
const px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly();

class CatmullRomCurve3 extends Curve {

	constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {

		super();

		this.type = 'CatmullRomCurve3';
		Object.defineProperty( this, 'isCatmullRomCurve3', { value: true } );
		this.points = points;
		this.closed = closed;
		this.curveType = curveType;
		this.tension = tension;

	}

	getPoint( t, optionalTarget = new Vector3() ) {

		const point = optionalTarget;

		const points = this.points;
		const l = points.length;

		const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
		let intPoint = Math.floor( p );
		let weight = p - intPoint;

		if ( this.closed ) {

			intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;

		} else if ( weight === 0 && intPoint === l - 1 ) {

			intPoint = l - 2;
			weight = 1;

		}

		let p0, p3; // 4 points (p1 & p2 defined below)

		if ( this.closed || intPoint > 0 ) {

			p0 = points[ ( intPoint - 1 ) % l ];

		} else {

			// extrapolate first point
			tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
			p0 = tmp;

		}

		const p1 = points[ intPoint % l ];
		const p2 = points[ ( intPoint + 1 ) % l ];

		if ( this.closed || intPoint + 2 < l ) {

			p3 = points[ ( intPoint + 2 ) % l ];

		} else {

			// extrapolate last point
			tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
			p3 = tmp;

		}

		if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {

			// init Centripetal / Chordal Catmull-Rom
			const pow = this.curveType === 'chordal' ? 0.5 : 0.25;
			let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
			let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
			let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );

			// safety check for repeated points
			if ( dt1 < 1e-4 )
				dt1 = 1.0;
			if ( dt0 < 1e-4 )
				dt0 = dt1;
			if ( dt2 < 1e-4 )
				dt2 = dt1;

			px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
			py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
			pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );

		} else if ( this.curveType === 'catmullrom' ) {

			px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
			py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
			pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );

		}

		point.set(
			px.calc( weight ),
			py.calc( weight ),
			pz.calc( weight )
		);

		return point;

	}
	copy( source ) {

		super.copy( source );

		this.points = [];

		for ( let i = 0, l = source.points.length; i < l; i ++ ) {

			const point = source.points[ i ];

			this.points.push( point.clone() );

		}

		this.closed = source.closed;
		this.curveType = source.curveType;
		this.tension = source.tension;

		return this;

	}
	toJSON() {

		const data = super.toJSON();

		data.points = [];

		for ( let i = 0, l = this.points.length; i < l; i ++ ) {

			const point = this.points[ i ];
			data.points.push( point.toArray() );

		}

		data.closed = this.closed;
		data.curveType = this.curveType;
		data.tension = this.tension;

		return data;

	}
	fromJSON( json ) {

		super.fromJSON( json );

		this.points = [];

		for ( let i = 0, l = json.points.length; i < l; i ++ ) {

			const point = json.points[ i ];
			this.points.push( new Vector3().fromArray( point ) );

		}

		this.closed = json.closed;
		this.curveType = json.curveType;
		this.tension = json.tension;

		return this;

	}

}

export { CatmullRomCurve3 };
<|endoftext|>


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

foam.CLASS({
  package: 'foam.dao.history',
  name: 'HistoryRecord',

  documentation: 'Contains an array of property updates',
  ids: [ 'objectId', 'seqNo' ],

  tableColumns: [
    'timestamp',
    'objectId',
    'user.id',
    'updates'
  ],

  properties: [
    {
      class: 'Long',
      name: 'seqNo',
      hidden: true
    },
    {
      class: 'Object',
      name: 'objectId',
      label: 'Updated Object',
      documentation: 'Id of object related to history record.',
      tableWidth: 150
    },
    {
      class: 'String',
      name: 'user',
      label: 'Updated By',
      documentation: 'User that made the update.',
      tableWidth: 200
    },
    {
      class: 'String',
      name: 'agent',
      label: 'Updated By',
      documentation: 'Agent that made the update'
    },
    {
      class: 'DateTime',
      name: 'timestamp',
      documentation: 'Date and time history record was created.',
      tableWidth: 200
    },
    {
      class: 'FObjectArray',
      of: 'foam.dao.history.PropertyUpdate',
      name: 'updates',
      label: 'Updated Properties',
      documentation: 'Properties updated, contains new and old values.'
    }
  ]
});
<commit_msg>fix tablecolumn<commit_after>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.dao.history',
  name: 'HistoryRecord',

  documentation: 'Contains an array of property updates',
  ids: [ 'objectId', 'seqNo' ],

  tableColumns: [
    'timestamp',
    'objectId',
    'user',
    'updates'
  ],

  properties: [
    {
      class: 'Long',
      name: 'seqNo',
      hidden: true
    },
    {
      class: 'Object',
      name: 'objectId',
      label: 'Updated Object',
      documentation: 'Id of object related to history record.',
      tableWidth: 150
    },
    {
      class: 'String',
      name: 'user',
      label: 'Updated By',
      documentation: 'User that made the update.',
      tableWidth: 200
    },
    {
      class: 'String',
      name: 'agent',
      label: 'Updated By',
      documentation: 'Agent that made the update'
    },
    {
      class: 'DateTime',
      name: 'timestamp',
      documentation: 'Date and time history record was created.',
      tableWidth: 200
    },
    {
      class: 'FObjectArray',
      of: 'foam.dao.history.PropertyUpdate',
      name: 'updates',
      label: 'Updated Properties',
      documentation: 'Properties updated, contains new and old values.'
    }
  ]
});
<|endoftext|>


<commit_before>import Emitter from '../core/emitter';
import Block, { EmbedBlock } from './block';
import Parchment from 'parchment';

// TODO move
function clean(container) {
  let walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, null, false);
  let node, textNodes = [];
  while(node = walker.nextNode()) {
    textNodes.push(node);
  }
  textNodes.forEach(function(textNode) {
    if (Parchment.query(textNode.previousSibling, Parchment.Scope.BLOCK) ||
        Parchment.query(textNode.nextSibling, Parchment.Scope.BLOCK)) {
      textNode.parentNode.removeChild(textNode);
    }
  });
  return container;
}

function isLine(blot) {
  return (blot instanceof Block || blot instanceof EmbedBlock);
}

class Scroll extends Parchment.Scroll {
  constructor(domNode, emitter) {
    super(clean(domNode));
    this.emitter = emitter;
    this.optimize();
  }

  deleteAt(index, length) {
    let [first, firstOffset] = this.children.find(index);
    let [last, lastOffset] = this.children.find(index + length);
    super.deleteAt(index, length);
    if (last != null && first !== last && firstOffset > 0) {
      let lastChild = first.children.tail;
      last.moveChildren(first);
      last.remove();
    }
    this.optimize();
  }

  insertBefore(childBlot, refBlot) {
    if (childBlot.scope & Parchment.Scope.INLINE) {
      let block = Parchment.create(this.statics.childless);
      block.insertBefore(childBlot);
      childBlot = block;
    }
    super.insertBefore(childBlot, refBlot);
  }

  line(index) {
    return this.descendant(isLine, index);
  }

  lines(index, length) {
    return this.descendants(isLine, index, length);
  }

  optimize(mutations) {
    super.optimize(mutations);
    this.emitter.emit(Emitter.events.SCROLL_OPTIMIZE);
  }

  path(index) {
    return super.path(index).slice(1);  // Exclude self
  }

  update(mutations) {
    let source = Emitter.sources.USER;
    if (typeof mutations === 'string') {
      source = mutations;
    }
    if (!Array.isArray(mutations)) {
      mutations = this.observer.takeRecords();
    }
    super.update(mutations);
    if (mutations.length > 0) {
      this.emitter.emit(Emitter.events.SCROLL_UPDATE, source);
    }
  }
}
Scroll.blotName = 'scroll';
Scroll.className = 'ql-editor';
Scroll.childless = 'block';
Scroll.tagName = 'DIV';

export default Scroll;
<commit_msg>tweak<commit_after>import Emitter from '../core/emitter';
import Block, { EmbedBlock } from './block';
import Parchment from 'parchment';

// TODO move
function clean(container) {
  let walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, null, false);
  let node, textNodes = [];
  while(node = walker.nextNode()) {
    textNodes.push(node);
  }
  textNodes.forEach(function(textNode) {
    if (Parchment.query(textNode.previousSibling, Parchment.Scope.BLOCK) ||
        Parchment.query(textNode.nextSibling, Parchment.Scope.BLOCK)) {
      textNode.parentNode.removeChild(textNode);
    }
  });
  return container;
}

function isLine(blot) {
  return (blot instanceof Block || blot instanceof EmbedBlock);
}

class Scroll extends Parchment.Scroll {
  constructor(domNode, emitter) {
    super(clean(domNode));
    this.emitter = emitter;
    this.optimize();
  }

  deleteAt(index, length) {
    let [first, firstOffset] = this.children.find(index);
    let [last, lastOffset] = this.children.find(index + length);
    super.deleteAt(index, length);
    if (last != null && first !== last && firstOffset > 0) {
      let lastChild = first.children.tail;
      last.moveChildren(first);
      last.remove();
    }
    this.optimize();
  }

  insertBefore(childBlot, refBlot) {
    if (childBlot.scope & Parchment.Scope.INLINE) {
      let block = Parchment.create(Parchment.Scope.BLOCK);
      block.insertBefore(childBlot);
      childBlot = block;
    }
    super.insertBefore(childBlot, refBlot);
  }

  line(index) {
    return this.descendant(isLine, index);
  }

  lines(index, length) {
    return this.descendants(isLine, index, length);
  }

  optimize(mutations) {
    super.optimize(mutations);
    this.emitter.emit(Emitter.events.SCROLL_OPTIMIZE);
  }

  path(index) {
    return super.path(index).slice(1);  // Exclude self
  }

  update(mutations) {
    let source = Emitter.sources.USER;
    if (typeof mutations === 'string') {
      source = mutations;
    }
    if (!Array.isArray(mutations)) {
      mutations = this.observer.takeRecords();
    }
    super.update(mutations);
    if (mutations.length > 0) {
      this.emitter.emit(Emitter.events.SCROLL_UPDATE, source);
    }
  }
}
Scroll.blotName = 'scroll';
Scroll.className = 'ql-editor';
Scroll.childless = 'block';
Scroll.tagName = 'DIV';

export default Scroll;
<|endoftext|>


<commit_before>export function methods(pointAndVectorOps, scalarTypes) {

  const V = pointAndVectorOps;

  const scalarToString = x => x.toString();
  const vectorToString = v => '[' + v.map(scalarToString).join(', ') + ']';

  class AffineTransformation {
    constructor(linear, shift) {
      const [n, m] = V.shape(linear);
      if (n != m || n != shift.length)
        throw new Error('size mismatch');

      this.linear = linear;
      this.shift  = shift;
    }

    toString() {
      const coordsLin = '[' + this.linear.map(vectorToString).join(', ') + ']';
      const coordsShift = vectorToString(this.shift);

      return `AffineTransformation(${coordsLin}, ${coordsShift})`;
    }
  };

  const I = n => V.identityMatrix(n);

  const compose = (t1, t2) => new AffineTransformation(
    V.times(t1.linear, t2.linear),
    V.plus(t1.shift, V.times(t1.linear, t2.shift))
  );

  const apply = (t, p) =>
    V.point(V.plus(V.times(t.linear, V.vector(p)), t.shift));

  const inverse = t => {
    const A = V.inverse(t.linear);
    if (A != null)
      return new AffineTransformation(A, V.negative(V.times(A, t.shift)));
  };

  const methods = {
    dimension: {
      AffineTransformation: t => V.shape(t.linear)[0]
    },

    affine: {
      Matrix: {
        Vector: (A, t) => new AffineTransformation(A, t)
      },
      Vector : v => new AffineTransformation(I(v.length), v),
      Integer: n => new AffineTransformation(I(n), V.vector(n))
    },

    identity: {
      Integer: n => new AffineTransformation(I(n), V.vector(n))
    },

    shift: {
      Vector : v => new AffineTransformation(I(v.length), v)
    },

    inverse: {
      AffineTransformation: inverse
    },

    times: {
      AffineTransformation: {
        AffineTransformation: compose,
        Point: apply
      }
    }
  };

  return methods;
};

if (require.main == module) {
  Array.prototype.toString = function() {
    return '[ ' + this.map(x => x.toString()).join(', ') + ' ]';
  };

  const mats = require('../arithmetic/types').matrixMethods;
  const pnts = mats.register(
    require('./points').methods(mats.ops(), ['Integer', 'LongInt', 'Fraction'])
  );
  const trns = pnts.register(methods(pnts.ops(), []));
  const tops = trns.ops();

  const t = tops.affine([[1,1,0],[1,2,0],[0,0,1]], [1,1,1]);
  console.log(`${t}`);
  console.log(`${tops.times(t, tops.point([1,2,3]))}`);
  console.log(`${tops.inverse(t)}`);
  console.log(`${tops.times(tops.inverse(t), tops.point([4,6,4]))}`);
}
<commit_msg>implement times for affine transformation and vector<commit_after>export function methods(pointAndVectorOps, scalarTypes) {

  const V = pointAndVectorOps;

  const scalarToString = x => x.toString();
  const vectorToString = v => '[' + v.map(scalarToString).join(', ') + ']';

  class AffineTransformation {
    constructor(linear, shift) {
      const [n, m] = V.shape(linear);
      if (n != m || n != shift.length)
        throw new Error('size mismatch');

      this.linear = linear;
      this.shift  = shift;
    }

    toString() {
      const coordsLin = '[' + this.linear.map(vectorToString).join(', ') + ']';
      const coordsShift = vectorToString(this.shift);

      return `AffineTransformation(${coordsLin}, ${coordsShift})`;
    }
  };

  const I = n => V.identityMatrix(n);

  const compose = (t1, t2) => new AffineTransformation(
    V.times(t1.linear, t2.linear),
    V.plus(t1.shift, V.times(t1.linear, t2.shift))
  );

  const inverse = t => {
    const A = V.inverse(t.linear);
    if (A != null)
      return new AffineTransformation(A, V.negative(V.times(A, t.shift)));
  };

  const applyToPoint = (t, p) =>
    V.point(V.plus(V.times(t.linear, V.vector(p)), t.shift));

  const methods = {
    dimension: {
      AffineTransformation: t => V.shape(t.linear)[0]
    },

    affine: {
      Matrix: {
        Vector: (A, t) => new AffineTransformation(A, t)
      },
      Vector : v => new AffineTransformation(I(v.length), v),
      Integer: n => new AffineTransformation(I(n), V.vector(n))
    },

    identityTransform: {
      Integer: n => new AffineTransformation(I(n), V.vector(n))
    },

    shift: {
      Vector : v => new AffineTransformation(I(v.length), v)
    },

    inverse: {
      AffineTransformation: inverse
    },

    times: {
      AffineTransformation: {
        AffineTransformation: compose,
        Point: applyToPoint,
        Vector: (t, v) => V.times(t.linear, v)
      }
    }
  };

  return methods;
};

if (require.main == module) {
  Array.prototype.toString = function() {
    return '[ ' + this.map(x => x.toString()).join(', ') + ' ]';
  };

  const mats = require('../arithmetic/types').matrixMethods;
  const pnts = mats.register(
    require('./points').methods(mats.ops(), ['Integer', 'LongInt', 'Fraction'])
  );
  const trns = pnts.register(methods(pnts.ops(), []));
  const tops = trns.ops();

  const t = tops.affine([[1,1,0],[1,2,0],[0,0,1]], [1,1,1]);
  console.log(`${t}`);
  console.log(`${tops.times(t, tops.point([1,2,3]))}`);
  console.log(`${tops.times(t, [1,2,3])}`);
  console.log(`${tops.inverse(t)}`);
  console.log(`${tops.times(tops.inverse(t), tops.point([4,6,4]))}`);
  console.log(`${tops.times(tops.inverse(t), [3,5,3])}`);
  console.log(`${tops.inverse(tops.shift([1,2,3]))}`);
}
<|endoftext|>


<commit_before>function qbp(opts) {
    var options = {
        threads: 1,
        progressInterval: 10000,
        progress: noop,
        empty: noop
    };

    var _this = this;

    _this.status = 'waiting';

    var queue = [];
    var running = false;
    var totalCount = 0;
    var itemCount = 0;
    var completeCount = 0;
    var threadCount = 0;
    var lastCompleteCount = 0;
    var startingEmpty = false;

    for (var key in options) {
        if (opts[key] === undefined) {
            opts[key] = options[key];
        }
    }

    if (opts.items) {
        add(opts.items);
    }

    function add(itemOrArray) {
        if (itemOrArray instanceof Array) {
            itemCount += itemOrArray.length;
            queue = queue.concat(queue, itemOrArray);
        }
        else {
            itemCount++;
            queue.push(itemOrArray);
        }

        resume();
    }

    function empty() {
        queue.length = 0;
    }

    function resume() {
        if (!running) {
            running = true;
            _this.status = 'running';
            setupThreads(true);
            if (queue.length > 0) {
                progress();
            }
        }
    }

    function pause() {
        running = false;
        _this.status = 'paused';
    }

    function progress(once) {
        if (!running && !once) return;

        var perc;
        if (itemCount > 0) perc = completeCount / itemCount;
        else perc = 0;

        var newItemsCompleted = completeCount - lastCompleteCount;
        var timeDiff = 1000 / opts.progressInterval;
        var itemsPerSecond = Math.round(newItemsCompleted * timeDiff);

        var secondsRemaining;

        if (!itemsPerSecond) {
            secondsRemaining = -1;
        }
        else {
            secondsRemaining = Math.ceil(queue.length / itemsPerSecond);
        }

        var obj = new QbpProgress(perc, completeCount, itemCount, threadCount, queue.length, opts.name, itemsPerSecond, secondsRemaining, _this);

        opts.progress(obj);

        lastCompleteCount = completeCount;

        if (!once && running && opts.progress !== noop) {
            setTimeout(progress, opts.progressInterval);
        }
    }

    function setupThreads(newThread) {
        if (!newThread) {
            threadCount--;
            completeCount++;
        }

        while(threadCount < opts.threads && queue.length > 0 && running) {
            threadCount++;
            var item = queue.splice(0, 1)[0];
            opts.process(item, setupThreads, _this);
        }

        if (queue.length === 0 && running && threadCount === 0) {
            running = false;
            _this.status = 'empty';
            if (itemCount > 0) progress(true);
            opts.empty();
        }
    }

    this.empty = empty;
    this.resume = resume;
    this.pause = pause;
    this.add = add;
};

qbp.create = function (opts) {
    return new qbp(opts);
}

function QbpProgress(perc, complete, total, threads, queued, name, itemsPerSecond, secondsRemaining, queue) {
    this.percent = perc;
    this.complete = complete;
    this.total = total;
    this.threads = threads;
    this.queued = queued;
    this.itemsPerSecond = itemsPerSecond
    this.queue = queue;
    this.secondsRemaining = secondsRemaining;

    if (name) {
        this.name = name;
    }
}

function noop() {};

module.exports = {
    qbp: qbp,
    QbpProgress: QbpProgress
};
<commit_msg>Fixed progress loop not starting<commit_after>function qbp(opts) {
    var options = {
        threads: 1,
        progressInterval: 10000,
        progress: noop,
        empty: noop
    };

    var _this = this;

    _this.status = 'waiting';

    var queue = [];
    var running = false;
    var itemCount = 0;
    var completeCount = 0;
    var threadCount = 0;
    var lastCompleteCount = 0;

    for (var key in options) {
        if (opts[key] === undefined) {
            opts[key] = options[key];
        }
    }

    if (opts.items) {
        add(opts.items);
    }

    function add(itemOrArray) {
        if (itemOrArray instanceof Array) {
            itemCount += itemOrArray.length;
            queue = queue.concat(queue, itemOrArray);
        }
        else {
            itemCount++;
            queue.push(itemOrArray);
        }

        resume();
    }

    function empty() {
        queue.length = 0;
    }

    function resume() {
        if (!running) {
            running = true;
            _this.status = 'running';
            setupThreads(true);
            if (queue.length > 0 || completeCount < itemCount) {
                progress();
            }
        }
    }

    function pause() {
        running = false;
        _this.status = 'paused';
    }

    function progress(once) {
        if (!running && !once) return;

        var perc;
        if (itemCount > 0) perc = completeCount / itemCount;
        else perc = 0;

        var newItemsCompleted = completeCount - lastCompleteCount;
        var timeDiff = 1000 / opts.progressInterval;
        var itemsPerSecond = Math.round(newItemsCompleted * timeDiff);

        var secondsRemaining;

        if (!itemsPerSecond) {
            secondsRemaining = -1;
        }
        else {
            secondsRemaining = Math.ceil(queue.length / itemsPerSecond);
        }

        var obj = new QbpProgress(perc, completeCount, itemCount, threadCount, queue.length, opts.name, itemsPerSecond, secondsRemaining, _this);

        opts.progress(obj);

        lastCompleteCount = completeCount;

        if (!once && running && opts.progress !== noop) {
            setTimeout(progress, opts.progressInterval);
        }
    }

    function setupThreads(newThread) {
        if (!newThread) {
            threadCount--;
            completeCount++;
        }

        while(threadCount < opts.threads && queue.length > 0 && running) {
            threadCount++;
            var item = queue.splice(0, 1)[0];
            opts.process(item, setupThreads, _this);
        }

        if (queue.length === 0 && running && threadCount === 0) {
            running = false;
            _this.status = 'empty';
            if (itemCount > 0) progress(true);
            opts.empty();
        }
    }

    this.empty = empty;
    this.resume = resume;
    this.pause = pause;
    this.add = add;
};

qbp.create = function (opts) {
    return new qbp(opts);
}

function QbpProgress(perc, complete, total, threads, queued, name, itemsPerSecond, secondsRemaining, queue) {
    this.percent = perc;
    this.complete = complete;
    this.total = total;
    this.threads = threads;
    this.queued = queued;
    this.itemsPerSecond = itemsPerSecond
    this.queue = queue;
    this.secondsRemaining = secondsRemaining;

    if (name) {
        this.name = name;
    }
}

function noop() {};

module.exports = {
    qbp: qbp,
    QbpProgress: QbpProgress
};
<|endoftext|>