<commit_before>import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { withRouter } from 'react-router'
import { push } from 'react-router-redux'
import ChildrenToolbar from '../components/ChildrenToolbar'

export class ChildrenToolbarContainer extends Component {
  render() {
    return (
      <ChildrenToolbar {...this.props} />
    )
  }
}

function mapStateToProps(s, ownProps) {
  const actions = ownProps.actions
  const info = ownProps.info
  const state = actions.getState(s)

  const formInfo = info.tree ? info.tree(ownProps) : {}

  const children = state.children.data || []
  const deleting = state.children.deleting ? true : false
  const message = state.children.message
  const clipboard = state.clipboard.data || []
  const clipboardMode = state.clipboard.mode
  const selected = children.filter((node) => {
    return state.children.selected[node.id]
  })
  const parentNode = state.tree.db ? state.tree.db.data[formInfo.id] : null
  const title = selected.length == 0 ?
    (parentNode || {}).name :
    (
      selected.length == 1 ?
        selected[0].name :
        selected.length + ' items'
    )

  return {
    title,
    node:parentNode,
    data:children,
    selected,
    clipboard,
    clipboardMode,
    deleting,
    message
  }
}

function mapDispatchToProps(dispatch, ownProps) {
  const actions = ownProps.actions
  const handlers = ownProps.handlers
  return {
    onAdd:(parent, decriptor) => {
      if(!handlers.add || !parent || !decriptor) return
      dispatch(push(handlers.add(parent, decriptor)))
    },
    onEdit:(parent, node) => {
      if(!handlers.edit || !parent) return
      dispatch(push(handlers.edit(parent, node)))
    },
    onOpen:(node) => {
      if(!handlers.open && !node) return
      dispatch(push(handlers.open(node)))
    },
    onDelete:(nodes) => {
      dispatch(actions.deleteSelection())
    },
    onCopy:(nodes) => {
      dispatch(actions.setClipboard('copy', nodes))
      dispatch(actions.showChildrenMessage('copied ' + nodes.length + ' item' + (nodes.length==1?'':'s') + ' to the clipboard'))
    },
    onCut:(nodes) => {
      dispatch(actions.setClipboard('cut', nodes))
      dispatch(actions.showChildrenMessage('cut ' + nodes.length + ' item' + (nodes.length==1?'':'s') + ' to the clipboard'))
    },
    onPaste:(parent, mode, nodes) => {
      dispatch(actions.requestPasteItems(parent, mode, nodes, (err) => {
        if(err){
          // TODO show an error message
        }
        else{
          dispatch(actions.showChildrenMessage(nodes.length + ' item' + (nodes.length==1?'':'s') + ' ' + (mode=='copy' ? ' copied' : 'cut') + ' to ' + parent.name))
        }
      }))
    },
    onConfirmDelete:(parent, nodes) => {
      dispatch(actions.requestDeleteNodes(parent.id, nodes.map((node) => node.id), (err) => {
        if(err){
          // TODO show an error message
        }
        else{
          dispatch(actions.showChildrenMessage(nodes.length + ' item' + (nodes.length==1?'':'s') + ' deleted'))
          dispatch(actions.cancelDeleteSelection())
        }
      }))
    },
    onCancelDelete:() => {
      dispatch(actions.cancelDeleteSelection())
    },
    onCloseMessage:() => {
      dispatch(actions.showChildrenMessage(null))
    }

  }
}

ChildrenToolbarContainer.propTypes = {
  actions:React.PropTypes.object.isRequired,
  info:React.PropTypes.object.isRequired,
  handlers:React.PropTypes.object.isRequired
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(withRouter(ChildrenToolbarContainer))
<commit_msg>empty clipboard after paste<commit_after>import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { withRouter } from 'react-router'
import { push } from 'react-router-redux'
import ChildrenToolbar from '../components/ChildrenToolbar'

export class ChildrenToolbarContainer extends Component {
  render() {
    return (
      <ChildrenToolbar {...this.props} />
    )
  }
}

function mapStateToProps(s, ownProps) {
  const actions = ownProps.actions
  const info = ownProps.info
  const state = actions.getState(s)

  const formInfo = info.tree ? info.tree(ownProps) : {}

  const children = state.children.data || []
  const deleting = state.children.deleting ? true : false
  const message = state.children.message
  const clipboard = state.clipboard.data || []
  const clipboardMode = state.clipboard.mode
  const selected = children.filter((node) => {
    return state.children.selected[node.id]
  })
  const parentNode = state.tree.db ? state.tree.db.data[formInfo.id] : null
  const title = selected.length == 0 ?
    (parentNode || {}).name :
    (
      selected.length == 1 ?
        selected[0].name :
        selected.length + ' items'
    )

  return {
    title,
    node:parentNode,
    data:children,
    selected,
    clipboard,
    clipboardMode,
    deleting,
    message
  }
}

function mapDispatchToProps(dispatch, ownProps) {
  const actions = ownProps.actions
  const handlers = ownProps.handlers
  return {
    onAdd:(parent, decriptor) => {
      if(!handlers.add || !parent || !decriptor) return
      dispatch(push(handlers.add(parent, decriptor)))
    },
    onEdit:(parent, node) => {
      if(!handlers.edit || !parent) return
      dispatch(push(handlers.edit(parent, node)))
    },
    onOpen:(node) => {
      if(!handlers.open && !node) return
      dispatch(push(handlers.open(node)))
    },
    onDelete:(nodes) => {
      dispatch(actions.deleteSelection())
    },
    onCopy:(nodes) => {
      dispatch(actions.setClipboard('copy', nodes))
      dispatch(actions.showChildrenMessage('copied ' + nodes.length + ' item' + (nodes.length==1?'':'s') + ' to the clipboard'))
    },
    onCut:(nodes) => {
      dispatch(actions.setClipboard('cut', nodes))
      dispatch(actions.showChildrenMessage('cut ' + nodes.length + ' item' + (nodes.length==1?'':'s') + ' to the clipboard'))
    },
    onPaste:(parent, mode, nodes) => {
      dispatch(actions.requestPasteItems(parent, mode, nodes, (err) => {
        if(err){
          // TODO show an error message
        }
        else{
          dispatch(actions.setClipboard(null, []))
          dispatch(actions.showChildrenMessage(nodes.length + ' item' + (nodes.length==1?'':'s') + ' ' + (mode=='copy' ? ' copied' : 'cut') + ' to ' + parent.name))
        }
      }))
    },
    onConfirmDelete:(parent, nodes) => {
      dispatch(actions.requestDeleteNodes(parent.id, nodes.map((node) => node.id), (err) => {
        if(err){
          // TODO show an error message
        }
        else{
          dispatch(actions.showChildrenMessage(nodes.length + ' item' + (nodes.length==1?'':'s') + ' deleted'))
          dispatch(actions.cancelDeleteSelection())
        }
      }))
    },
    onCancelDelete:() => {
      dispatch(actions.cancelDeleteSelection())
    },
    onCloseMessage:() => {
      dispatch(actions.showChildrenMessage(null))
    }

  }
}

ChildrenToolbarContainer.propTypes = {
  actions:React.PropTypes.object.isRequired,
  info:React.PropTypes.object.isRequired,
  handlers:React.PropTypes.object.isRequired
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(withRouter(ChildrenToolbarContainer))
<|endoftext|>


<commit_before><commit_msg>Delete Water-Container.js<commit_after><|endoftext|>


<commit_before>import { moduleForComponent, test } from 'ember-qunit';
moduleForComponent('uic-modal-window', 'Unit | Component | uic modal window', {
  needs: [
    'component:uic-content-mask'
  ],
  unit: true
});

test('it renders', function(assert) {
  assert.expect(2);
  var component = this.subject();
  assert.equal(component._state, 'preRender');
  this.render();
  assert.equal(component._state, 'inDOM');
});

test('classNames', function(assert) {
  assert.expect(2);
  var component = this.subject();
  this.render();
  assert.equal(component.get('classNames').length, 2);
  assert.equal(component.get('classNames')[1], 'uic-modal-window');
});

test('showCloseButton', function(assert) {
  assert.expect(1);
  var component = this.subject();
  this.render();
  assert.equal(component.get('showCloseButton'), true);
});

test('parentRouteName top-level route', function(assert) {
  assert.expect(1);
  var component = this.subject();
  component.set('lookup', { currentRouteName: 'child-route' });
  this.render();
  assert.equal(component.get('parentRouteName'), 'index');
});

test('parentRouteName 1 nested route', function(assert) {
  assert.expect(1);
  var component = this.subject();
  component.set('lookup', { currentRouteName: 'parent-route.child-route' });
  this.render();
  assert.equal(component.get('parentRouteName'), 'parent-route');
});

test('parentRouteName 2 nested routes', function(assert) {
  assert.expect(1);
  var component = this.subject();
  component.set('lookup', { currentRouteName: 'top-level-route.parent-route.child-route' });
  this.render();
  assert.equal(component.get('parentRouteName'), 'top-level-route.parent-route');
});

test('_closeModal() method', function(assert) {
  assert.expect(1);
  var component = this.subject();
  this.render();
  component._closeModal();
  assert.ok(component);
});

test('closeModal action', function(assert) {
  assert.expect(1);
  var component = this.subject();
  component.set('_closeModal',() => assert.ok(true));
  this.render();
  component.send('closeModal');
});
<commit_msg>update modal-window test<commit_after>import { moduleForComponent, test } from 'ember-qunit';
moduleForComponent('uic-modal-window', 'Unit | Component | uic modal window', {
  needs: [
    'component:uic-content-mask',
    'component:uic-modal'
  ],
  unit: true
});

test('it renders', function(assert) {
  assert.expect(2);
  var component = this.subject();
  assert.equal(component._state, 'preRender');
  this.render();
  assert.equal(component._state, 'inDOM');
});

test('classNames', function(assert) {
  assert.expect(2);
  var component = this.subject();
  this.render();
  assert.equal(component.get('classNames').length, 2);
  assert.equal(component.get('classNames')[1], 'uic-modal-window');
});

test('showCloseButton', function(assert) {
  assert.expect(1);
  var component = this.subject();
  this.render();
  assert.equal(component.get('showCloseButton'), true);
});

test('parentRouteName top-level route', function(assert) {
  assert.expect(1);
  var component = this.subject();
  component.set('lookup', { currentRouteName: 'child-route' });
  this.render();
  assert.equal(component.get('parentRouteName'), 'index');
});

test('parentRouteName 1 nested route', function(assert) {
  assert.expect(1);
  var component = this.subject();
  component.set('lookup', { currentRouteName: 'parent-route.child-route' });
  this.render();
  assert.equal(component.get('parentRouteName'), 'parent-route');
});

test('parentRouteName 2 nested routes', function(assert) {
  assert.expect(1);
  var component = this.subject();
  component.set('lookup', { currentRouteName: 'top-level-route.parent-route.child-route' });
  this.render();
  assert.equal(component.get('parentRouteName'), 'top-level-route.parent-route');
});

test('_closeModal() method', function(assert) {
  assert.expect(1);
  var component = this.subject();
  this.render();
  component._closeModal();
  assert.ok(component);
});

test('closeModal action', function(assert) {
  assert.expect(1);
  var component = this.subject();
  component.set('_closeModal',() => assert.ok(true));
  this.render();
  component.send('closeModal');
});
<|endoftext|>


<commit_before>import clearCache from 'ember-cli-hot-loader/utils/clear-container-cache';
import moduleForAcceptance from 'dummy/tests/helpers/module-for-acceptance';
import { test } from 'qunit';

moduleForAcceptance('Acceptance | Utility | clear container cache');

// Replace this with your real tests.
test('it works', function(assert) {
  assert.expect(0);
  // Just want to make sure this doesn\'t crash in the different versions of Ember
   clearCache(this.application.__container__.lookup('component:inline-template-pod', 'inline-template-pod'));
});
<commit_msg>[TESTS]: updated clear cache test for glimmer 2<commit_after>import clearCache from 'ember-cli-hot-loader/utils/clear-container-cache';
import moduleForAcceptance from 'dummy/tests/helpers/module-for-acceptance';
import { test } from 'qunit';

moduleForAcceptance('Acceptance | Utility | clear container cache');

// Replace this with your real tests.
test('it works', function(assert) {
  assert.expect(0);
  let done = assert.async();
  visit('/');
  andThen(() => {
    // Just want to make sure this doesn\'t crash in the different versions of Ember
    clearCache(this.application.__container__.lookup('component:inline-template-pod', 'inline-template-pod'));
    done();
  });
});
<|endoftext|>


<commit_before>
"use strict";

let params;
let route;
let modal;

class ListController {

    constructor($route, $translatePartialLoader, $modal) {
        if ($route.current && $route.current.locals) {
            for (let p in $route.current.locals) {
                if (p.substring(0, 1) == '$') {
                    continue;
                }
                this[p] = $route.current.locals[p];
            }
        }
        $translatePartialLoader.addPart(this.module);
        this.$new = new this.Manager.model();
        this.items = [];
        params = $route.current.params;
        modal = $modal;
        route = $route;
        this.page = params.page || 1;
    }

    get page() {
        return this._page;
    }

    set page(page) {
        this._page = page;
        while (this.items.length) {
            this.items.pop();
        }
        this.Manager.list(params, {offset: (page - 1) * 10}).success(items => items.map(item => this.items.push(item)));
    };

    /**
     * Method allowing item deletion directly from a list:
     */
    ['delete'](item) {
        let modalInstance = modal.open({
            template: `

{{'monad.delete.title' | translate}}

    {{'monad.delete.body' | translate}}

    <button class="btn btn-primary" ng-click="ok()">{{'monad.delete.ok' | translate}}</button>
    <button class="btn btn-warning" ng-click="cancel()">{{'monad.delete.cancel' | translate}}</button>

`,
            controller: ['$scope', '$modalInstance', ($scope, $modalInstance) => {
                $scope.ok = () => {
                    this.Manager['delete'](item);
                    $modalInstance.close(item);
                    route.reload();
                };
                $scope.cancel = () => {
                    $modalInstance.dismiss('cancel');
                };
            }]
        });
    }

};

ListController.$inject = ['$route', '$translatePartialLoader', '$modal'];

export {ListController};

<commit_msg>this needs a reload method<commit_after>
"use strict";

let params;
let route;
let modal;

class ListController {

    constructor($route, $translatePartialLoader, $modal) {
        if ($route.current && $route.current.locals) {
            for (let p in $route.current.locals) {
                if (p.substring(0, 1) == '$') {
                    continue;
                }
                this[p] = $route.current.locals[p];
            }
        }
        $translatePartialLoader.addPart(this.module);
        this.$new = new this.Manager.model();
        this.items = [];
        params = $route.current.params;
        modal = $modal;
        route = $route;
        this.page = params.page || 1;
    }

    reload() {
        route.reload();
    }

    get page() {
        return this._page;
    }

    set page(page) {
        this._page = page;
        while (this.items.length) {
            this.items.pop();
        }
        this.Manager.list(params, {offset: (page - 1) * 10}).success(items => items.map(item => this.items.push(item)));
    };

    /**
     * Method allowing item deletion directly from a list:
     */
    ['delete'](item) {
        let modalInstance = modal.open({
            template: `

{{'monad.delete.title' | translate}}

    {{'monad.delete.body' | translate}}

    <button class="btn btn-primary" ng-click="ok()">{{'monad.delete.ok' | translate}}</button>
    <button class="btn btn-warning" ng-click="cancel()">{{'monad.delete.cancel' | translate}}</button>

`,
            controller: ['$scope', '$modalInstance', ($scope, $modalInstance) => {
                $scope.ok = () => {
                    this.Manager['delete'](item);
                    $modalInstance.close(item);
                    route.reload();
                };
                $scope.cancel = () => {
                    $modalInstance.dismiss('cancel');
                };
            }]
        });
    }

};

ListController.$inject = ['$route', '$translatePartialLoader', '$modal'];

export {ListController};

<|endoftext|>


<commit_before>// @flow

import * as React from 'react'
import {StyleSheet, ScrollView, Platform, View} from 'react-native'
import Icon from 'react-native-vector-icons/Ionicons'
import {TabBarIcon} from '@frogpond/navigation-tabs'
import {connect} from 'react-redux'
import {hasSeenAcknowledgement} from '../../redux/parts/settings'
import {type ReduxState} from '../../redux'
import type {TopLevelViewPropsType} from '../types'
import {Avatar, Button, Card, Paragraph as AndroidP} from 'react-native-paper'
import {Paragraph as IosP} from '@frogpond/markdown'
import {Card as IosCard} from '@frogpond/silly-card'
import {Button as IosButton} from '@frogpond/button'
import BalancesView from './balances'

type ReduxStateProps = {
	alertSeen: boolean,
}

type Props = {
	...TopLevelViewPropsType,
	...ReduxStateProps,
	// from redux mapDispatch
	hasSeenAcknowledgement: () => any,
}

let Acknowledgement = Platform.OS === 'android' ? AndroidAck : IosAck
let Paragraph = Platform.OS === 'android' ? AndroidP : IosP

function BalancesOrAcknowledgementView(props: Props) {
	if (props.alertSeen) {
		return <BalancesView navigation={props.navigation} />
	}

	return (
		<ScrollView contentContainerStyle={styles.container}>
			<Acknowledgement
				onPositive={props.hasSeenAcknowledgement}
				subtitle="Bon Appétit is always right"
				title="Before you continue…"
			>
				<Paragraph>
					While we strive to keep this app and the data therein up-to-date,
					there will always be issues, especially seeing as we are not part of
					the college. (Students and alumni of, yes, but officially sponsored
					by, no.)
				</Paragraph>
				<Paragraph>
					As such, we require that you agree to the following statement before
					you can see your balances within the app:
				</Paragraph>
				<Paragraph style={styles.bonappNotice}>
					This data may be inaccurate.{'\n'}
					Bon Appétit is always right.{'\n'}
					This app is unofficial.
				</Paragraph>
				<Paragraph>
					If you disagree, you will simply not be able to access this Balances
					view. The rest of the app will remain available for perusal.
				</Paragraph>
			</Acknowledgement>
		</ScrollView>
	)
}

BalancesOrAcknowledgementView.navigationOptions = {
	tabBarLabel: 'Balances',
	tabBarIcon: TabBarIcon('card'),
}

function mapState(state: ReduxState): ReduxStateProps {
	return {
		alertSeen: state.settings ? state.settings.unofficiallyAcknowledged : false,
	}
}

export default connect(
	mapState,
	{hasSeenAcknowledgement},
)(BalancesOrAcknowledgementView)

type AcknowledgementProps = {|
	title: string,
	subtitle: string,
	children: React.Node,
	onPositive: () => any,
|}

function AndroidAck(props: AcknowledgementProps) {
	let {title, subtitle, children, onPositive} = props

	return (
		<Card style={styles.androidCard}>
			<Card.Title
				left={props => (
					<Avatar.Icon
						{...props}
						icon={({size, color}) => (
							<Icon name="md-warning" size={size} style={{color}} />
						)}
					/>
				)}
				subtitle={subtitle}
				title={title}
			/>
			<Card.Content>{children}</Card.Content>
			<Card.Actions>
				<Button onPress={onPositive}>
					I Agree
				</Button>
			</Card.Actions>
		</Card>
	)
}

function IosAck(props: AcknowledgementProps) {
	let {title, children, onPositive} = props

	return (
		<IosCard header={title}>
			{children}

			<View style={styles.iosButtonRow}>
				<IosButton onPress={onPositive} title="I Agree" />
			</View>
		</IosCard>
	)
}

let styles = StyleSheet.create({
	container: {
		marginVertical: 10,
	},
	androidCard: {
		marginHorizontal: 10,
		marginBottom: 10,
	},
	bonappNotice: {
		fontWeight: Platform.select({
			ios: '600',
			android: '700',
		}),
		textAlign: 'center',
	},
	iosButtonRow: {
		flexDirection: 'row',
		justifyContent: 'space-around',
	},
})
<commit_msg>prettify<commit_after>// @flow

import * as React from 'react'
import {StyleSheet, ScrollView, Platform, View} from 'react-native'
import Icon from 'react-native-vector-icons/Ionicons'
import {TabBarIcon} from '@frogpond/navigation-tabs'
import {connect} from 'react-redux'
import {hasSeenAcknowledgement} from '../../redux/parts/settings'
import {type ReduxState} from '../../redux'
import type {TopLevelViewPropsType} from '../types'
import {Avatar, Button, Card, Paragraph as AndroidP} from 'react-native-paper'
import {Paragraph as IosP} from '@frogpond/markdown'
import {Card as IosCard} from '@frogpond/silly-card'
import {Button as IosButton} from '@frogpond/button'
import BalancesView from './balances'

type ReduxStateProps = {
	alertSeen: boolean,
}

type Props = {
	...TopLevelViewPropsType,
	...ReduxStateProps,
	// from redux mapDispatch
	hasSeenAcknowledgement: () => any,
}

let Acknowledgement = Platform.OS === 'android' ? AndroidAck : IosAck
let Paragraph = Platform.OS === 'android' ? AndroidP : IosP

function BalancesOrAcknowledgementView(props: Props) {
	if (props.alertSeen) {
		return <BalancesView navigation={props.navigation} />
	}

	return (
		<ScrollView contentContainerStyle={styles.container}>
			<Acknowledgement
				onPositive={props.hasSeenAcknowledgement}
				subtitle="Bon Appétit is always right"
				title="Before you continue…"
			>
				<Paragraph>
					While we strive to keep this app and the data therein up-to-date,
					there will always be issues, especially seeing as we are not part of
					the college. (Students and alumni of, yes, but officially sponsored
					by, no.)
				</Paragraph>
				<Paragraph>
					As such, we require that you agree to the following statement before
					you can see your balances within the app:
				</Paragraph>
				<Paragraph style={styles.bonappNotice}>
					This data may be inaccurate.{'\n'}
					Bon Appétit is always right.{'\n'}
					This app is unofficial.
				</Paragraph>
				<Paragraph>
					If you disagree, you will simply not be able to access this Balances
					view. The rest of the app will remain available for perusal.
				</Paragraph>
			</Acknowledgement>
		</ScrollView>
	)
}

BalancesOrAcknowledgementView.navigationOptions = {
	tabBarLabel: 'Balances',
	tabBarIcon: TabBarIcon('card'),
}

function mapState(state: ReduxState): ReduxStateProps {
	return {
		alertSeen: state.settings ? state.settings.unofficiallyAcknowledged : false,
	}
}

export default connect(
	mapState,
	{hasSeenAcknowledgement},
)(BalancesOrAcknowledgementView)

type AcknowledgementProps = {|
	title: string,
	subtitle: string,
	children: React.Node,
	onPositive: () => any,
|}

function AndroidAck(props: AcknowledgementProps) {
	let {title, subtitle, children, onPositive} = props

	return (
		<Card style={styles.androidCard}>
			<Card.Title
				left={props => (
					<Avatar.Icon
						{...props}
						icon={({size, color}) => (
							<Icon name="md-warning" size={size} style={{color}} />
						)}
					/>
				)}
				subtitle={subtitle}
				title={title}
			/>
			<Card.Content>{children}</Card.Content>
			<Card.Actions>
				<Button onPress={onPositive}>I Agree</Button>
			</Card.Actions>
		</Card>
	)
}

function IosAck(props: AcknowledgementProps) {
	let {title, children, onPositive} = props

	return (
		<IosCard header={title}>
			{children}

			<View style={styles.iosButtonRow}>
				<IosButton onPress={onPositive} title="I Agree" />
			</View>
		</IosCard>
	)
}

let styles = StyleSheet.create({
	container: {
		marginVertical: 10,
	},
	androidCard: {
		marginHorizontal: 10,
		marginBottom: 10,
	},
	bonappNotice: {
		fontWeight: Platform.select({
			ios: '600',
			android: '700',
		}),
		textAlign: 'center',
	},
	iosButtonRow: {
		flexDirection: 'row',
		justifyContent: 'space-around',
	},
})
<|endoftext|>


<commit_before>import errors from 'restify-errors';
import api from '../api';
import person from '../../services/person';

jest.mock('../../services/person');

const req = {};
const res = {};
let next;

describe('api', () => {
  beforeEach(() => {
    req.query = {};
    next = jest.fn();
    res.send = jest.fn();
  });

  describe('api::get', () => {
    it('executes successfully', async () => {
      expect.assertions(4);

      req.query.name = 'Jeff';
      await api.get(req, res, next);
      expect(person.get.mock.calls.length).toBe(1);
      expect(res.send.mock.calls.length).toBe(1);
      expect(res.send).toBeCalledWith({
        data: req.query.name,
        message: '',
        status: 200,
      });
      expect(next.mock.calls.length).toBe(1);
    });

    it('returns an error', async () => {
      expect.assertions(4);

      await api.get(req, res, next);

      expect(person.get.mock.calls.length).toBe(1);
      expect(res.send.mock.calls.length).toBe(1);
      expect(res.send).toBeCalledWith(500, {
        data: {},
        error: new errors.InternalServerError(),
        status: 500,
      });
      expect(next.mock.calls.length).toBe(1);
    });
  });

  describe('api::post', () => {
    it('accepts a valid person', async () => {
      expect.assertions(5);
      req.body = {
        name: 'Jeff Detmer',
        age: 29,
      };

      res.setHeader = jest.fn();
      req.contentType = jest.fn().mockReturnValue('application/json');

      await api.post(req, res, next);

      expect(person.save.mock.calls.length).toBe(1);
      expect(res.send.mock.calls.length).toBe(1);
      expect(res.setHeader).toBeCalledWith('Content-Type', 'application/json');
      expect(res.send).toBeCalledWith(201, {
        data: { age: 29, name: 'Jeff Detmer' },
        message: '',
        status: 201,
      });
      expect(next.mock.calls.length).toBe(1);
    });

    it('errors on an invalid person', () => {
      expect.assertions(4);
      req.body = {
        fullName: 'Jeff Detmer',
        age: 29,
      };

      res.setHeader = jest.fn();
      req.contentType = jest.fn().mockReturnValue('application/json');

      api.post(req, res, next);

      expect(res.send.mock.calls.length).toBe(1);
      expect(res.setHeader).toBeCalledWith('Content-Type', 'application/json');
      expect(res.send).toBeCalledWith(400, {
        data: {},
        error: new errors.InvalidArgumentError('Invalid Person'),
        status: 400,
      });
      expect(next.mock.calls.length).toBe(1);
    });
  });
});
<commit_msg>test(api.error): add test for api error controller (#39)<commit_after>import errors from 'restify-errors';
import api from '../api';
import person from '../../services/person';

jest.mock('../../services/person');

const req = {};
const res = {};
let next;

describe('api', () => {
  beforeEach(() => {
    req.query = {};
    next = jest.fn();
    res.send = jest.fn();
  });

  describe('api::get', () => {
    it('executes successfully', async () => {
      expect.assertions(4);

      req.query.name = 'Jeff';
      await api.get(req, res, next);
      expect(person.get.mock.calls.length).toBe(1);
      expect(res.send.mock.calls.length).toBe(1);
      expect(res.send).toBeCalledWith({
        data: req.query.name,
        message: '',
        status: 200,
      });
      expect(next.mock.calls.length).toBe(1);
    });

    it('returns an error', async () => {
      expect.assertions(4);

      await api.get(req, res, next);

      expect(person.get.mock.calls.length).toBe(1);
      expect(res.send.mock.calls.length).toBe(1);
      expect(res.send).toBeCalledWith(500, {
        data: {},
        error: new errors.InternalServerError(),
        status: 500,
      });
      expect(next.mock.calls.length).toBe(1);
    });
  });

  describe('api::post', () => {
    it('accepts a valid person', async () => {
      expect.assertions(5);
      req.body = {
        name: 'Jeff Detmer',
        age: 29,
      };

      res.setHeader = jest.fn();
      req.contentType = jest.fn().mockReturnValue('application/json');

      await api.post(req, res, next);

      expect(person.save.mock.calls.length).toBe(1);
      expect(res.send.mock.calls.length).toBe(1);
      expect(res.setHeader).toBeCalledWith('Content-Type', 'application/json');
      expect(res.send).toBeCalledWith(201, {
        data: { age: 29, name: 'Jeff Detmer' },
        message: '',
        status: 201,
      });
      expect(next.mock.calls.length).toBe(1);
    });

    it('errors on an invalid person', () => {
      expect.assertions(4);
      req.body = {
        fullName: 'Jeff Detmer',
        age: 29,
      };

      res.setHeader = jest.fn();
      req.contentType = jest.fn().mockReturnValue('application/json');

      api.post(req, res, next);

      expect(res.send.mock.calls.length).toBe(1);
      expect(res.setHeader).toBeCalledWith('Content-Type', 'application/json');
      expect(res.send).toBeCalledWith(400, {
        data: {},
        error: new errors.InvalidArgumentError('Invalid Person'),
        status: 400,
      });
      expect(next.mock.calls.length).toBe(1);
    });
  });
  describe('api::error', () => {
    it('throws an error', () => {
      expect.assertions(2);

      api.error(req, res, next);

      expect(res.send.mock.calls.length).toBe(1);
      expect(res.send).toBeCalledWith(400, {
        data: {},
        error: new errors.RestError('This is expected'),
        status: 400,
      });
    });
  });
});
<|endoftext|>


<commit_before>/* eslint-env jest */

import { Auditor } from '../auditor'
import type { ServiceUserAccount, FlaggedInfo } from '../types'

let individualStore = {

}

let groupStore = {

}

let individual, auditor

beforeEach(() => {
  individual = {
    id: "1",
    fullname:"test individual",
    primaryEmail: "test@test.com",
    serviceUserIdentities: {},
    accessRules: {},
    groups: []
  }
  auditor = new Auditor(individualStore, groupStore)
})

describe("without a matching individual record", () => {

  test("it should not match based on user id for different services", () => {
    // arrange
    let identity = {
      userId: "test123"
    }
    let account = {
      serviceId: "service in question",
      userAccount: {
        identity: identity,
        assets: [
          { name: "project a", role: "member" }
        ]
      }
    }
    individual.serviceUserIdentities["a different service"] = identity

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(flaggedInfo).not.toBeNull()
    expect(flaggedInfo).not.toBeUndefined()
    if (flaggedInfo) {
      expect(flaggedInfo.individual).toBeNull()
      expect(flaggedInfo.identity).toEqual({ userId: "test123" })
      expect(flaggedInfo.assets).toEqual([{ name: "project a", role: "member" }])
    }
  })

  test("it should not match based on full name", () => {
    // arrange
    let identity = {
      fullname: "test individual",
      userId: "some user id"
    }

    let account = {
      serviceId: "service in question",
      userAccount: {
        identity: identity,
        assets: [
          { name: "project a", role: "member" }
        ]
      }
    }
    individual.serviceUserIdentities["some other service"] = {
      fullname: "test individual",
      email: "test@test.com"
    }

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(flaggedInfo).not.toBeNull()
    expect(flaggedInfo).not.toBeUndefined()
    if(flaggedInfo) {
      expect(flaggedInfo.individual).toBeNull()
      expect(flaggedInfo.identity).toEqual({ fullname: "test individual", userId: "some user id" })
      expect(flaggedInfo.assets).toEqual([{ name: "project a", role: "member" }])
    }
  })
})

const matchingIndividualTests = (account) => {
  test("it flags if they have no service access rule at all", () => {

    // arrange

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(false).toBe(true)
  })

  test("it flags if they have a service access rule, with full access, for different roles", () => {
    // arrange

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(false).toBe(true)
  })

  test("it flags if they have per asset access for the wrong assets", () => {
    // arrange

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(false).toBe(true)
  })

  test("it flags if they have per asset access for the wrong roles", () => {
    // arrange

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(false).toBe(true)
  })

  test("it flags if they have full access through group membership, for the wrong role", () => {
    // arrange

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(false).toBe(true)
  })

  test("it does not flag if they have full access for the same role", () => {
    // arrange

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(false).toBe(true)
  })

  test("it does not flag if they have full access through group membership, for the same role", () => {
    // arrange

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(false).toBe(true)
  })

  test("it does not flag if they have matching per asset access for the same role", () => {
    // arrange

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(false).toBe(true)
  })
}

describe("with matching individual based on email", () => {
  let account = {
    serviceId: "test service",
    userAccount: {
      identity: {
        email: "test@test.com"
      },
      assets: [
        { name: "project a", role: "member" }
      ]
    }
  }
  matchingIndividualTests(account)
})

describe("with matching individual based on service user id", () => {
  let account = {
    serviceId: "test service",
    userAccount: {
      identity: {
        userId: "matching user id"
      },
      assets: [
        { name: "project a", role: "member" }
      ]
    }
  }
  beforeEach(() => {
    individual.serviceUserIdentities["test service"] = {
      userId: "matching user id"
    }
  })
  matchingIndividualTests(account)
})
<commit_msg>write auditor tests<commit_after>/* eslint-env jest */

import { Auditor } from '../auditor'
import type { ServiceUserAccount, FlaggedInfo } from '../types'

let individualStore = {

}

let groupStore = {
  groups: []
}

let individual, auditor

beforeEach(() => {
  individual = {
    id: "123",
    fullname:"test individual",
    primaryEmail: "test@test.com",
    serviceUserIdentities: {},
    accessRules: {},
    groups: []
  }
  groupStore.groups = []
  auditor = new Auditor(individualStore, groupStore)
})

function expectFlaggedInfo(flaggedInfo, expectationsBlock) {
  expect(flaggedInfo).not.toBeNull()
  expect(flaggedInfo).not.toBeUndefined()
  if (flaggedInfo) {
    expectationsBlock()
  }
}

describe("without a matching individual record", () => {

  test("it should not match based on user id for different services", () => {
    // arrange
    let identity = {
      userId: "test123"
    }
    let account = {
      serviceId: "service in question",
      userAccount: {
        identity: identity,
        assets: [
          { name: "project a", role: "member" }
        ]
      }
    }
    individual.serviceUserIdentities["a different service"] = identity

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expectFlaggedInfo(flaggedInfo, () => {
      expect(flaggedInfo.individualId).toBeNull()
      expect(flaggedInfo.identity).toEqual({ userId: "test123" })
      expect(flaggedInfo.assets).toEqual([{ name: "project a", role: "member" }])
    })
  })

  test("it should not match based on full name", () => {
    // arrange
    let identity = {
      fullname: "test individual",
      userId: "some user id"
    }

    let account = {
      serviceId: "service in question",
      userAccount: {
        identity: identity,
        assets: [
          { name: "project a", role: "member" }
        ]
      }
    }
    individual.serviceUserIdentities["some other service"] = {
      fullname: "test individual",
      email: "test@test.com"
    }

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expectFlaggedInfo(flaggedInfo, () => {
      expect(flaggedInfo.individualId).toBeNull()
      expect(flaggedInfo.identity).toEqual({ fullname: "test individual", userId: "some user id" })
      expect(flaggedInfo.assets).toEqual([{ name: "project a", role: "member" }])
    })
  })
})

const matchingIndividualTests = (account) => {
  test("it flags if they have no service access rule at all", () => {
    // arrange
    individual.accessRules = {}

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expectFlaggedInfo(flaggedInfo, () => {
      expect(flaggedInfo.individualId).toBe("123")
      expect(flaggedInfo.serviceId).toBe("test service")
      expect(flaggedInfo.userIdentity).toEqual(account.userAccount.identity)
      expect(flaggedInfo.assets).toEqual([
        { name: "project a", role: "member" },
        { name: "project b", role: "owner" }
      ])
    })
  })

  test("it flags if they have a service access rule, with full access, for different roles", () => {
    // arrange
    individual.accessRules["test service"] = [{ asset: "*", role: "member" }]

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expectFlaggedInfo(flaggedInfo, () => {
      expect(flaggedInfo.individualId).toBe("123")
      expect(flaggedInfo.serviceId).toBe("test service")
      expect(flaggedInfo.userIdentity).toEqual(account.userAccount.identity)
      expect(flaggedInfo.assets).toEqual([
        { name: "project b", role: "owner" }
      ])
    })
  })

  test("it flags if they have per asset access for the wrong assets", () => {
    // arrange
    individual.accessRules["test service"] = [{ asset: "project b", role: "owner" }]

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expectFlaggedInfo(flaggedInfo, () => {
      expect(flaggedInfo.individualId).toBe("123")
      expect(flaggedInfo.serviceId).toBe("test service")
      expect(flaggedInfo.userIdentity).toEqual(account.userAccount.identity)
      expect(flaggedInfo.assets).toEqual([
        { name: "project a", role: "member" }
      ])
    })
  })

  test("it flags if they have per asset access for the wrong roles", () => {
    // arrange
    individual.accessRules["test service"] = [
      { asset: "project b", role: "admin" },
      { asset: "project a", role: "admin" }
    ]

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expectFlaggedInfo(flaggedInfo, () => {
      expect(flaggedInfo.individualId).toBe("123")
      expect(flaggedInfo.serviceId).toBe("test service")
      expect(flaggedInfo.userIdentity).toEqual(account.userAccount.identity)
      expect(flaggedInfo.assets).toEqual([
        { name: "project a", role: "member" },
        { name: "project b", role: "owner" }
      ])
    })
  })

  test("it flags if they have full access through group membership, for the wrong role", () => {
    // arrange
    individual.accessRules = {}
    individual.groups = ["employee"]
    groupStore.groups = [{
      name: "employee",
      accessRules: {
        "test service": [{ asset: "*", role: "member"}]
      }
    }]

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expectFlaggedInfo(flaggedInfo, () => {
      expect(flaggedInfo.individualId).toBe("123")
      expect(flaggedInfo.serviceId).toBe("test service")
      expect(flaggedInfo.userIdentity).toEqual(account.userAccount.identity)
      expect(flaggedInfo.assets).toEqual([
        { name: "project b", role: "owner" }
      ])
    })
  })

  test("it does not flag if they have full access for the same role", () => {
    // arrange
    individual.accessRules["test service"] = [
      { asset: "*", role: "member" },
      { asset: "*", role: "owner" }
    ]

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(flaggedInfo).toBeUndefined()
  })

  test("it does not flag if they have full access through group membership, for the same role", () => {
    // arrange
    individual.accessRules = {}
    individual.groups = ["employee"]
    groupStore.groups = [{
      name: "employee",
      accessRules: {
        "test service": [
          { asset: "*", role: "member"},
          { asset: "*", role: "owner"}
        ]
      }
    }]

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(flaggedInfo).toBeUndefined()
  })

  test("it does not flag if they have matching per asset access for the same role", () => {
    // arrange
    individual.accessRules["test service"] = [
      { asset: "project b", role: "owner" },
      { asset: "project a", role: "member" }
    ]

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(flaggedInfo).toBeUndefined()
  })
}

describe("with matching individual based on email", () => {
  let account = {
    serviceId: "test service",
    userAccount: {
      identity: {
        email: "test@test.com"
      },
      assets: [
        { name: "project a", role: "member" },
        { name: "project b", role: "owner" }
      ]
    }
  }
  matchingIndividualTests(account)
})

describe("with matching individual based on service user id", () => {
  let account = {
    serviceId: "test service",
    userAccount: {
      identity: {
        userId: "matching user id"
      },
      assets: [
        { name: "project a", role: "member" },
        { name: "project b", role: "owner" }
      ]
    }
  }
  beforeEach(() => {
    individual.serviceUserIdentities["test service"] = {
      userId: "matching user id"
    }
  })
  matchingIndividualTests(account)
})

describe("with matching individual, when the service doesn't have roles", () => {
  let account = {
    serviceId: "test service",
    userAccount: {
      identity: {
        email: "test@test.com"
      },
      assets: [
        { name: "project a" },
        { name: "project b" }
      ]
    }
  }

  test("it does not flag, if they have full access", () => {
    // arrange
    individual.accessRules["test service"] = [{ asset: "*", role: "*" }]

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(flaggedInfo).toBeUndefined()
  })

  test("it does not flag, if they have full access through group membership", () => {
    // arrange
    individual.accessRules = {}
    individual.groups = ["employee"]
    groupStore.groups = [{
      name: "employee",
      accessRules: {
        "test service": [
          { asset: "*", role: "*"}
        ]
      }
    }]

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(flaggedInfo).toBeUndefined()
  })

  test("it does not flag if they have matching per asset access", () => {
    // arrange
    individual.accessRules["test service"] = [
      { asset: "project b", role: "*" },
      { asset: "project a", role: "*" }
    ]

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expect(flaggedInfo).toBeUndefined()
  })

  test("it does flag assets that do not have access", () => {
    // arrange
    individual.accessRules["test service"] = [
      { asset: "project b", role: "*" }
    ]

    // act
    let flaggedInfo = auditor.auditAccount(account)

    // assert
    expectFlaggedInfo(flaggedInfo, () => {
      expect(flaggedInfo.individualId).toBe("123")
      expect(flaggedInfo.serviceId).toBe("test service")
      expect(flaggedInfo.userIdentity).toEqual(account.userAccount.identity)
      expect(flaggedInfo.assets).toEqual([
        { name: "project a" }
      ])
    })
  })

})
<|endoftext|>


<commit_before>var CONST = require('../../const');

/**
 * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height.
 *
 * @class
 * @memberof PIXI
 * @param x {number} The X coordinate of the upper-left corner of the rectangle
 * @param y {number} The Y coordinate of the upper-left corner of the rectangle
 * @param width {number} The overall width of this rectangle
 * @param height {number} The overall height of this rectangle
 */
function Rectangle(x, y, width, height)
{
    /**
     * @member {number}
     * @default 0
     */
    this.x = x || 0;

    /**
     * @member {number}
     * @default 0
     */
    this.y = y || 0;

    /**
     * @member {number}
     * @default 0
     */
    this.width = width || 0;

    /**
     * @member {number}
     * @default 0
     */
    this.height = height || 0;

    /**
     * The type of the object, mainly used to avoid `instanceof` checks
     *
     * @member {number}
     * @readOnly
     * @default CONST.SHAPES.RECT
     * @see PIXI.SHAPES
     */
    this.type = CONST.SHAPES.RECT;
}

Rectangle.prototype.constructor = Rectangle;
module.exports = Rectangle;

/**
 * A constant empty rectangle.
 *
 * @static
 * @constant
 */
Rectangle.EMPTY = new Rectangle(0, 0, 0, 0);

/**
 * Creates a clone of this Rectangle
 *
 * @return {PIXI.Rectangle} a copy of the rectangle
 */
Rectangle.prototype.clone = function ()
{
    return new Rectangle(this.x, this.y, this.width, this.height);
};

Rectangle.prototype.copy = function (rectangle)
{
    this.x = rectangle.x;
    this.y = rectangle.y;
    this.width = rectangle.width;
    this.height = rectangle.height;

    return this;
};

/**
 * Checks whether the x and y coordinates given are contained within this Rectangle
 *
 * @param x {number} The X coordinate of the point to test
 * @param y {number} The Y coordinate of the point to test
 * @return {boolean} Whether the x/y coordinates are within this Rectangle
 */
Rectangle.prototype.contains = function (x, y)
{
    if (this.width <= 0 || this.height <= 0)
    {
        return false;
    }

    if (x >= this.x && x < this.x + this.width)
    {
        if (y >= this.y && y < this.y + this.height)
        {
            return true;
        }
    }

    return false;
};

Rectangle.prototype.pad = function (paddingX, paddingY)
{
    paddingX = paddingX || 0;
    paddingY = paddingY || ( (paddingY !== 0) ? paddingX : 0 );

    this.x -= paddingX;
    this.y -= paddingY;

    this.width += paddingX * 2;
    this.height += paddingY * 2;
};

Rectangle.prototype.fit = function (rectangle)
{
    if (this.x < rectangle.x)
    {
        this.width += this.x;
        if(this.width < 0) {
          this.width = 0;
        }

        this.x = rectangle.x;
    }

    if (this.y < rectangle.y)
    {
        this.height += this.y;
        if(this.height < 0) {
          this.height = 0;
        }
        this.y = rectangle.y;
    }

    if ( this.x + this.width > rectangle.x + rectangle.width )
    {
        this.width = rectangle.width - this.x;
        if(this.width < 0) {
          this.width = 0;
        }
    }

    if ( this.y + this.height > rectangle.y + rectangle.height )
    {
        this.height = rectangle.height - this.y;
        if(this.height < 0) {
          this.height = 0;
        }
    }
};

Rectangle.prototype.enlarge = function (rect)
{

    if (rect === Rectangle.EMPTY)
    {
        return;
    }

    var x1 = Math.min(this.x, rect.x);
    var x2 = Math.max(this.x + this.width, rect.x + rect.width);
    var y1 = Math.min(this.y, rect.y);
    var y2 = Math.max(this.y + this.height, rect.y + rect.height);
    this.x = x1;
    this.width = x2 - x1;
    this.y = y1;
    this.height = y2 - y1;
};
<commit_msg>added left/right/bottom/top props to rect<commit_after>var CONST = require('../../const');

/**
 * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height.
 *
 * @class
 * @memberof PIXI
 * @param x {number} The X coordinate of the upper-left corner of the rectangle
 * @param y {number} The Y coordinate of the upper-left corner of the rectangle
 * @param width {number} The overall width of this rectangle
 * @param height {number} The overall height of this rectangle
 */
function Rectangle(x, y, width, height)
{
    /**
     * @member {number}
     * @default 0
     */
    this.x = x || 0;

    /**
     * @member {number}
     * @default 0
     */
    this.y = y || 0;

    /**
     * @member {number}
     * @default 0
     */
    this.width = width || 0;

    /**
     * @member {number}
     * @default 0
     */
    this.height = height || 0;

    /**
     * The type of the object, mainly used to avoid `instanceof` checks
     *
     * @member {number}
     * @readOnly
     * @default CONST.SHAPES.RECT
     * @see PIXI.SHAPES
     */
    this.type = CONST.SHAPES.RECT;
}

Rectangle.prototype.constructor = Rectangle;
module.exports = Rectangle;

Object.defineProperties(Rectangle.prototype, {
    /**
     * returns the left edge of the rectangle
     *
     * @member {number}
     * @memberof PIXI.Rectangle#
     */
    left: {
        get: function ()
        {
            return this.x;
        }
    },

    /**
     * returns the right edge of the rectangle
     *
     * @member {number}
     * @memberof PIXI.Rectangle
     */
    right: {
        get: function ()
        {
            return this.x + this.width;
        }
    },

    /**
     * returns the top edge of the rectangle
     *
     * @member {number}
     * @memberof PIXI.Rectangle
     */
    top: {
        get: function ()
        {
            return this.y;
        }
    },

    /**
     * returns the bottom edge of the rectangle
     *
     * @member {number}
     * @memberof PIXI.Rectangle
     */
    bottom: {
        get: function ()
        {
            return this.y + this.height;
        }
    }

});

/**
 * A constant empty rectangle.
 *
 * @static
 * @constant
 */
Rectangle.EMPTY = new Rectangle(0, 0, 0, 0);

/**
 * Creates a clone of this Rectangle
 *
 * @return {PIXI.Rectangle} a copy of the rectangle
 */
Rectangle.prototype.clone = function ()
{
    return new Rectangle(this.x, this.y, this.width, this.height);
};

Rectangle.prototype.copy = function (rectangle)
{
    this.x = rectangle.x;
    this.y = rectangle.y;
    this.width = rectangle.width;
    this.height = rectangle.height;

    return this;
};

/**
 * Checks whether the x and y coordinates given are contained within this Rectangle
 *
 * @param x {number} The X coordinate of the point to test
 * @param y {number} The Y coordinate of the point to test
 * @return {boolean} Whether the x/y coordinates are within this Rectangle
 */
Rectangle.prototype.contains = function (x, y)
{
    if (this.width <= 0 || this.height <= 0)
    {
        return false;
    }

    if (x >= this.x && x < this.x + this.width)
    {
        if (y >= this.y && y < this.y + this.height)
        {
            return true;
        }
    }

    return false;
};

Rectangle.prototype.pad = function (paddingX, paddingY)
{
    paddingX = paddingX || 0;
    paddingY = paddingY || ( (paddingY !== 0) ? paddingX : 0 );

    this.x -= paddingX;
    this.y -= paddingY;

    this.width += paddingX * 2;
    this.height += paddingY * 2;
};

Rectangle.prototype.fit = function (rectangle)
{
    if (this.x < rectangle.x)
    {
        this.width += this.x;
        if(this.width < 0) {
          this.width = 0;
        }

        this.x = rectangle.x;
    }

    if (this.y < rectangle.y)
    {
        this.height += this.y;
        if(this.height < 0) {
          this.height = 0;
        }
        this.y = rectangle.y;
    }

    if ( this.x + this.width > rectangle.x + rectangle.width )
    {
        this.width = rectangle.width - this.x;
        if(this.width < 0) {
          this.width = 0;
        }
    }

    if ( this.y + this.height > rectangle.y + rectangle.height )
    {
        this.height = rectangle.height - this.y;
        if(this.height < 0) {
          this.height = 0;
        }
    }
};

Rectangle.prototype.enlarge = function (rect)
{

    if (rect === Rectangle.EMPTY)
    {
        return;
    }

    var x1 = Math.min(this.x, rect.x);
    var x2 = Math.max(this.x + this.width, rect.x + rect.width);
    var y1 = Math.min(this.y, rect.y);
    var y2 = Math.max(this.y + this.height, rect.y + rect.height);
    this.x = x1;
    this.width = x2 - x1;
    this.y = y1;
    this.height = y2 - y1;
};
<|endoftext|>


<commit_before>var Croaker = (function () {
  'use strict';

  var metricDefs = [{ name: 'ClassCoupling',
    friendlyName: 'Class Coupling',
    shortName: 'CC'
  },
                   {
                     name: 'DepthOfInheritance',
                     friendlyName: 'Depth of Inheritance',
                     shortName: 'DoI'
                   },
                   {
                     name: 'CyclomaticComplexity',
                     friendlyName: 'Cyclomatic Complexity',
                     shortName: 'CYC'
                   },
                   {
                     name: 'LinesOfCode',
                     friendlyName: 'Lines of Code',
                     shortName: 'LoC'
                   },
                   {
                     name: 'MaintainabilityIndex',
                     friendlyName: 'Maintainability Index',
                     shortName: 'MI'
                   }];

  var metricNames = _.pluck(metricDefs, 'name');

  function named(name, spec) {
    spec = spec || {};
    spec.name = name;
    return spec;
  }

  function parent(name, childrenName, spec) {
    spec = named(name, spec);
    spec[childrenName] = [];
    spec.metrics = [];
    spec.parent = null;

    if (childrenName) {
      spec.add = function (items) {
        _.each(items, function (i) {
          spec[childrenName].push(i);
          i.parent = spec;
        });
        return spec;
      };
    }

    spec.addMetrics = function (items) {
      _.each(items, function (i) {
        spec.metrics.push(i);
        i.parent = spec;
      });
      return spec;
    };

    return spec;
  }

  function module(name, version) {
    return parent(name, 'namespaces', { version: version, tag: 'MOD' });
  }

  function namespace(name) {
    return parent(name, 'types', { tag: 'NS' });
  }

  function type(name) {
    return parent(name, 'members', { tag: 'TY' });
  }

  function member(name) {
    return parent(name, null, { tag: 'M' });
  }

  function metric(name, value) {
    return named(name, { value: value });
  }

  var parser = (function () {
    function parseXml(xml) {
      return $.xml2json(xml, true);
    }

    function getRoot(xml) {
      return parseXml(xml).Targets[0].Target[0].Modules[0].Module[0];
    }

    function shouldProcessMembers(members) {
      return members[0] !== '';
    }

    function addMissingMetrics(metrics) {
      var names = _.pluck(metrics, 'name');
      var missing = _.reject(metricNames, function (n) { return _.include(names, n); });
      _.each(missing, function (n) { metrics.push(metric(n, 'N/A')); });
      return metrics;
    }

    function sortMetrics(metrics) {
      return _.sortBy(metrics, function (m) { return m.name; });
    }

    function parseMetrics(node) {
      var metrics = _.map(node.Metrics[0].Metric, function (n) {
        return metric(n.Name, parseInt(n.Value, 10));
      });
      return sortMetrics(addMissingMetrics(metrics));
    }

    function parseMembers(node) {
      if (!shouldProcessMembers(node.Members)) {
        return [];
      }

      return _.map(node.Members[0].Member, function (n) {
        return member(n.Name).addMetrics(parseMetrics(n));
      });
    }

    function parseTypes(node) {
      return _.map(node.Types[0].Type, function (t) {
        return type(t.Name)
          .addMetrics(parseMetrics(t))
          .add(parseMembers(t));
      });
    }

    function parseNamespaces(root) {
      return _.map(root.Namespaces[0].Namespace, function (n) {
        return namespace(n.Name, root)
          .addMetrics(parseMetrics(n))
          .add(parseTypes(n));
      });
    }

    function parse(xml) {
      var root = getRoot(xml);
      return module(root.Name, root.AssemblyVersion)
        .addMetrics(parseMetrics(root))
        .add(parseNamespaces(root));
    }

    return { parse: parse };
  } ());

  return {
    module: module,
    namespace: namespace,
    type: type,
    member: member,
    metric: metric,
    parser: parser,
    metricDefs: metricDefs
  };
} ());<commit_msg>only types with children should have a children property<commit_after>var Croaker = (function () {
  'use strict';

  var metricDefs = [{ name: 'ClassCoupling',
    friendlyName: 'Class Coupling',
    shortName: 'CC'
  },
                   {
                     name: 'DepthOfInheritance',
                     friendlyName: 'Depth of Inheritance',
                     shortName: 'DoI'
                   },
                   {
                     name: 'CyclomaticComplexity',
                     friendlyName: 'Cyclomatic Complexity',
                     shortName: 'CYC'
                   },
                   {
                     name: 'LinesOfCode',
                     friendlyName: 'Lines of Code',
                     shortName: 'LoC'
                   },
                   {
                     name: 'MaintainabilityIndex',
                     friendlyName: 'Maintainability Index',
                     shortName: 'MI'
                   }];

  var metricNames = _.pluck(metricDefs, 'name');

  function named(name, spec) {
    spec = spec || {};
    spec.name = name;
    return spec;
  }

  function parent(name, childrenName, spec) {
    spec = named(name, spec);
    spec.metrics = [];
    spec.parent = null;

    if (childrenName) {
      spec[childrenName] = [];
      spec.add = function (items) {
        _.each(items, function (i) {
          spec[childrenName].push(i);
          i.parent = spec;
        });
        return spec;
      };
    }

    spec.addMetrics = function (items) {
      _.each(items, function (i) {
        spec.metrics.push(i);
        i.parent = spec;
      });
      return spec;
    };

    return spec;
  }

  function module(name, version) {
    return parent(name, 'namespaces', { version: version, tag: 'MOD' });
  }

  function namespace(name) {
    return parent(name, 'types', { tag: 'NS' });
  }

  function type(name) {
    return parent(name, 'members', { tag: 'TY' });
  }

  function member(name) {
    return parent(name, null, { tag: 'M' });
  }

  function metric(name, value) {
    return named(name, { value: value });
  }

  var parser = (function () {
    function parseXml(xml) {
      return $.xml2json(xml, true);
    }

    function getRoot(xml) {
      return parseXml(xml).Targets[0].Target[0].Modules[0].Module[0];
    }

    function shouldProcessMembers(members) {
      return members[0] !== '';
    }

    function addMissingMetrics(metrics) {
      var names = _.pluck(metrics, 'name');
      var missing = _.reject(metricNames, function (n) { return _.include(names, n); });
      _.each(missing, function (n) { metrics.push(metric(n, 'N/A')); });
      return metrics;
    }

    function sortMetrics(metrics) {
      return _.sortBy(metrics, function (m) { return m.name; });
    }

    function parseMetrics(node) {
      var metrics = _.map(node.Metrics[0].Metric, function (n) {
        return metric(n.Name, parseInt(n.Value, 10));
      });
      return sortMetrics(addMissingMetrics(metrics));
    }

    function parseMembers(node) {
      if (!shouldProcessMembers(node.Members)) {
        return [];
      }

      return _.map(node.Members[0].Member, function (n) {
        return member(n.Name).addMetrics(parseMetrics(n));
      });
    }

    function parseTypes(node) {
      return _.map(node.Types[0].Type, function (t) {
        return type(t.Name)
          .addMetrics(parseMetrics(t))
          .add(parseMembers(t));
      });
    }

    function parseNamespaces(root) {
      return _.map(root.Namespaces[0].Namespace, function (n) {
        return namespace(n.Name, root)
          .addMetrics(parseMetrics(n))
          .add(parseTypes(n));
      });
    }

    function parse(xml) {
      var root = getRoot(xml);
      return module(root.Name, root.AssemblyVersion)
        .addMetrics(parseMetrics(root))
        .add(parseNamespaces(root));
    }

    return { parse: parse };
  } ());

  return {
    module: module,
    namespace: namespace,
    type: type,
    member: member,
    metric: metric,
    parser: parser,
    metricDefs: metricDefs
  };
} ());<|endoftext|>


<commit_before>/* Fluid font size (experimental) */
/* REF: https://www.smashingmagazine.com/2016/05/fluid-typography/ */

// font-size: calc( 12px + (24 - 12) * ( (100vw - 400px) / ( 800 - 400) ));

const baseFontSize = '16'; // px, browser default font size

function getUnit(value) {
  const match = value.match(/px|rem|em/);

  if (match) {
    return match.toString();
  }
  return null;
}

function remToPx(size) {
  return `${parseFloat(size) * baseFontSize}px`;
}

const fluidFontSize = (mixin, minFontSize, maxFontSize, fromScreenWidth, toScreenWidth) => {
  const min = getUnit(minFontSize) === 'rem' ? remToPx(minFontSize) : minFontSize;
  const max = getUnit(maxFontSize) === 'rem' ? remToPx(maxFontSize) : maxFontSize;
  const fromWidth = getUnit(fromScreenWidth) === 'em' ? remToPx(fromScreenWidth) : fromScreenWidth;
  const toWidth = getUnit(toScreenWidth) === 'em' ? remToPx(toScreenWidth) : toScreenWidth;

  // console.log('minFontSize', minFontSize);
  // console.log('maxFontSize', maxFontSize);
  // console.log('min', min);
  // console.log('max', max);
  // console.log('fromWidth', fromWidth);
  // console.log('toWidth', toWidth);

  const fontRange = parseFloat(max) - parseFloat(min);
  const mediaRange = parseFloat(toWidth) - parseFloat(fromWidth);
  const sizeCalc = `calc(${min} + (${fontRange}) * (100vw - ${fromWidth}) / (${mediaRange}));`;

  return {
    '&': {
      [`@media screen and (max-width: ${fromWidth})`]: {
        'font-size': min,
      },

      [`@media screen and (min-width: ${fromWidth}) and (max-width: ${toWidth})`]: {
        'font-size': sizeCalc,
      },

      [`@media screen and (min-width: ${toWidth})`]: {
        'font-size': max,
      },
    },
  };
};

module.exports = fluidFontSize;
<commit_msg>Rename variables in fluid font size mixin for better understanding<commit_after>/* Fluid font size (experimental) */
/* REF: https://www.smashingmagazine.com/2016/05/fluid-typography/ */

// font-size: calc( 12px + (24 - 12) * ( (100vw - 400px) / ( 800 - 400) ));

const baseFontSize = '16'; // px, browser default font size

function getUnit(value) {
  const match = value.match(/px|rem|em/);

  if (match) {
    return match.toString();
  }
  return null;
}

function remToPx(size) {
  return `${parseFloat(size) * baseFontSize}px`;
}

const fluidFontSize = (mixin, minFontSize, maxFontSize, fromScreenWidth, toScreenWidth) => {
  const minFont = getUnit(minFontSize) === 'rem' ? remToPx(minFontSize) : minFontSize;
  const maxFont = getUnit(maxFontSize) === 'rem' ? remToPx(maxFontSize) : maxFontSize;
  const minMedia = getUnit(fromScreenWidth) === 'em' ? remToPx(fromScreenWidth) : fromScreenWidth;
  const maxMedia = getUnit(toScreenWidth) === 'em' ? remToPx(toScreenWidth) : toScreenWidth;

  // console.log('minFontSize', minFontSize);
  // console.log('maxFontSize', maxFontSize);
  // console.log('minFont', minFont);
  // console.log('maxFont', maxFont);
  // console.log('minMedia', minMedia);
  // console.log('maxMedia', maxMedia);

  const fontRange = parseFloat(maxFont) - parseFloat(minFont);
  const mediaRange = parseFloat(maxMedia) - parseFloat(minMedia);
  const sizeCalc = `calc(${minFont} + (${fontRange}) * (100vw - ${minMedia}) / (${mediaRange}));`;

  return {
    '&': {
      [`@media screen and (max-width: ${minMedia})`]: {
        'font-size': minFont,
      },

      [`@media screen and (min-width: ${minMedia}) and (max-width: ${maxMedia})`]: {
        'font-size': sizeCalc,
      },

      [`@media screen and (min-width: ${maxMedia})`]: {
        'font-size': maxFont,
      },
    },
  };
};

module.exports = fluidFontSize;
<|endoftext|>


<commit_before>import React from 'react';
import {connect} from 'react-redux';

import {CONFIG} from 'dashboard/config';
import {fetchPageAction, fetchPagelistAction} from 'dashboard/reducers/actions';
import {makeGetPage, makeGetPagelist} from 'dashboard/reducers/selectors';
import {Input, Textarea} from 'views';

const h = React.createElement;

class PageDisplay extends React.Component {
  render(){
    return

pageid

      {this.props.pageid}

title

      {this.props.title}

tags

      {this.props.tags.join(', ')}

content

{this.props.content}

;
  }
}

class PageEdit extends React.Component {
  render(){
    return

      <Input label="pageid" value={this.props.pageid} handleBlur={(value)=>{console.log(value);}}/>
      <Input label="title" value={this.props.title}/>
      <Input label="tags" value={this.props.tags.join(', ')}/>
      <Textarea label="content" rows={12} value={this.props.content}/>

;
  }
}

class Pages extends React.Component {
  constructor(props){
    super(props);
    this.state = {edit: false};
  }

  componentWillMount(){
    this.props.fetchPagelist();
  }

  render(){
    return

Pages

      {this.props.pagelist.loading &&
loading
}
      {this.props.pagelist.failed &&
failed
}
      {(!this.props.pagelist.loading && !this.props.pagelist.failed) && this.props.pagelist.content &&

            {this.props.pagelist.content.map((i)=>{
              return
{this.setState({edit: false}); this.props.fetchPage(i);}} key={i}>{i}
;
            })}

      }
      {this.props.page.loading &&
loading
}
      {this.props.page.failed &&
failed
}
      {(!this.props.page.loading && !this.props.page.failed) && this.props.page.content &&

          {!this.state.edit &&

            <button className="button-outline-primary"
              onClick={()=>{
                this.setState({edit: true});
              }}>Edit</button>
            {h(PageDisplay, this.props.page.content)}

}
          {this.state.edit &&

            <button className="button-outline"
              onClick={()=>{
                this.setState({edit: false});
              }}>Cancel</button>
            <button className="button-primary"
              onClick={()=>{
                this.setState({edit: false});
              }}>Save</button>
            {h(PageEdit, this.props.page.content)}

}

      }

;
  }
}

const makeMapStateToProps = ()=>{
  const getPage = makeGetPage();
  const getPagelist = makeGetPagelist();
  return (state)=>{
    return {
      page: getPage(state),
      pagelist: getPagelist(state)
    };
  };
};

const mapDispatchToProps = (dispatch)=>{
  return {
    fetchPage: (pageid, method=false, body=false)=>{
      dispatch(fetchPageAction(CONFIG.retrieve('basePagesUrl'), pageid, method, body));
    },
    fetchPagelist: ()=>{
      dispatch(fetchPagelistAction(CONFIG.retrieve('basePagesUrl')));
    }
  };
};

Pages = connect(
  makeMapStateToProps,
  mapDispatchToProps
)(Pages);

export {Pages};
<commit_msg>page edit state<commit_after>import React from 'react';
import {connect} from 'react-redux';
import Immutable from 'immutable';

import {CONFIG} from 'dashboard/config';
import {fetchPageAction, fetchPagelistAction} from 'dashboard/reducers/actions';
import {makeGetPage, makeGetPagelist} from 'dashboard/reducers/selectors';
import {Input, Textarea} from 'views';

const h = React.createElement;

class PageDisplay extends React.Component {
  render(){
    return

pageid

      {this.props.pageid}

title

      {this.props.title}

tags

      {this.props.tags.join(', ')}

content

{this.props.content}

;
  }
}

class PageEdit extends React.Component {
  constructor(props){
    super(props);
    this.state = {data: Immutable.fromJS(this.props)};
  }
  render(){
    console.log(this.state.data.toJSON());
    return

      <Input label="pageid" value={this.state.data.get('pageid')}
        handleBlur={(value)=>{
          this.setState({data: this.state.data.set('pageid', value)});}}/>
      <Input label="title" value={this.state.data.get('title')}
        handleBlur={(value)=>{
          this.setState({data: this.state.data.set('title', value)});}}/>
      <Input label="tags" value={this.state.data.get('tags').join(', ')}
        handleBlur={(value)=>{
          this.setState({data: this.state.data.set('tags', value.split(/\s*,\s*/))});}}/>
      <Textarea label="content" rows={12} value={this.state.data.get('content')}
        handleBlur={(value)=>{
          this.setState({data: this.state.data.set('content', value)});}}/>

;
  }
}

class Pages extends React.Component {
  constructor(props){
    super(props);
    this.state = {edit: false};
  }

  componentWillMount(){
    this.props.fetchPagelist();
  }

  render(){
    return

Pages

      {this.props.pagelist.loading &&
loading
}
      {this.props.pagelist.failed &&
failed
}
      {(!this.props.pagelist.loading && !this.props.pagelist.failed) && this.props.pagelist.content &&

            {this.props.pagelist.content.map((i)=>{
              return
{this.setState({edit: false}); this.props.fetchPage(i);}} key={i}>{i}
;
            })}

      }
      {this.props.page.loading &&
loading
}
      {this.props.page.failed &&
failed
}
      {(!this.props.page.loading && !this.props.page.failed) && this.props.page.content &&

          {!this.state.edit &&

            <button className="button-outline-primary"
              onClick={()=>{
                this.setState({edit: true});
              }}>Edit</button>
            {h(PageDisplay, this.props.page.content)}

}
          {this.state.edit &&

            <button className="button-outline"
              onClick={()=>{
                this.setState({edit: false});
              }}>Cancel</button>
            <button className="button-primary"
              onClick={()=>{
                this.setState({edit: false});
              }}>Save</button>
            {h(PageEdit, this.props.page.content)}

}

      }

;
  }
}

const makeMapStateToProps = ()=>{
  const getPage = makeGetPage();
  const getPagelist = makeGetPagelist();
  return (state)=>{
    return {
      page: getPage(state),
      pagelist: getPagelist(state)
    };
  };
};

const mapDispatchToProps = (dispatch)=>{
  return {
    fetchPage: (pageid, method=false, body=false)=>{
      dispatch(fetchPageAction(CONFIG.retrieve('basePagesUrl'), pageid, method, body));
    },
    fetchPagelist: ()=>{
      dispatch(fetchPagelistAction(CONFIG.retrieve('basePagesUrl')));
    }
  };
};

Pages = connect(
  makeMapStateToProps,
  mapDispatchToProps
)(Pages);

export {Pages};
<|endoftext|>