<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import CloseRoundedIcon from '@material-ui/icons/CloseRounded';
import MuiDialog, { DialogProps } from '@material-ui/core/Dialog';
import MuiDialogContent, { DialogContentProps } from '@material-ui/core/DialogContent';
import MuiDialogActions, { DialogActionsProps } from '@material-ui/core/DialogActions';
import styled from 'styled-components';
import { Flex } from 'rebass/styled-components';

import { IconButton } from './IconButton';

import {
  space,
} from '../../themes/baseTheme';

/* Dialog Title Start */
const StyledDialogTitle = styled(Flex)`
  justify-content: space-between;
  padding: ${space[3]}px;
`;

export const DialogTitle = props => {
  const {
    children,
    closeIcon,
    onClose,
    ...dialogTitleProps
  } = props;

  return (
    <StyledDialogTitle {...dialogTitleProps}>
      {children}
      {closeIcon && <IconButton label="close dialog" onClick={onClose} icon={CloseRoundedIcon} />}
    </StyledDialogTitle>
  );
};

DialogTitle.propTypes = {
  closeIcon: PropTypes.bool,
};

DialogTitle.defaultProps = {
  closeIcon: true,
};
/* Dialog Title End */

/* Dialog Content Start */
const StyledDialogContent = styled(MuiDialogContent)`
  padding: ${space[4]}px ${space[3]}px;

  div:first-child {
    margin-top: 0;
  }

  div:last-child {
    margin-bottom: 0;
  }
`;

export const DialogContent = props => <StyledDialogContent {...props} />;

DialogContent.propTypes = {
  ...DialogContentProps,
};

DialogContent.defaultProps = {
  dividers: true,
};
/* Dialog Content End */

/* Dialog Actions Start */
const StyledDialogActions = styled(MuiDialogActions)`
  padding: ${space[3]}px;

  button {
    margin-left: ${space[2]}px;
  }
`;

export const DialogActions = props => <StyledDialogActions {...props} />;

DialogActions.propTypes = {
  ...DialogActionsProps,
};

DialogActions.defaultProps = {
  disableSpacing: true,
};
/* Dialog Actions End */

/* Dialog Start */
const StyledDialog = styled(MuiDialog)``;

export const Dialog = props => <StyledDialog {...props} />;

Dialog.propTypes = {
  ...DialogProps,
  id: PropTypes.string.isRequired,
};
/* Dialog End */
<commit_msg>[WEB-589] Remove unused style-components wrapper from around MuiDialog<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import CloseRoundedIcon from '@material-ui/icons/CloseRounded';
import MuiDialog, { DialogProps } from '@material-ui/core/Dialog';
import MuiDialogContent, { DialogContentProps } from '@material-ui/core/DialogContent';
import MuiDialogActions, { DialogActionsProps } from '@material-ui/core/DialogActions';
import styled from 'styled-components';
import { Flex } from 'rebass/styled-components';

import { IconButton } from './IconButton';

import {
  space,
} from '../../themes/baseTheme';

/* Dialog Title Start */
const StyledDialogTitle = styled(Flex)`
  justify-content: space-between;
  padding: ${space[3]}px;
`;

export const DialogTitle = props => {
  const {
    children,
    closeIcon,
    onClose,
    ...dialogTitleProps
  } = props;

  return (
    <StyledDialogTitle {...dialogTitleProps}>
      {children}
      {closeIcon && <IconButton label="close dialog" onClick={onClose} icon={CloseRoundedIcon} />}
    </StyledDialogTitle>
  );
};

DialogTitle.propTypes = {
  closeIcon: PropTypes.bool,
};

DialogTitle.defaultProps = {
  closeIcon: true,
};
/* Dialog Title End */

/* Dialog Content Start */
const StyledDialogContent = styled(MuiDialogContent)`
  padding: ${space[4]}px ${space[3]}px;

  div:first-child {
    margin-top: 0;
  }

  div:last-child {
    margin-bottom: 0;
  }
`;

export const DialogContent = props => <StyledDialogContent {...props} />;

DialogContent.propTypes = DialogContentProps;

DialogContent.defaultProps = {
  dividers: true,
};
/* Dialog Content End */

/* Dialog Actions Start */
const StyledDialogActions = styled(MuiDialogActions)`
  padding: ${space[3]}px;

  button {
    margin-left: ${space[2]}px;
  }
`;

export const DialogActions = props => <StyledDialogActions {...props} />;

DialogActions.propTypes = DialogActionsProps;

DialogActions.defaultProps = {
  disableSpacing: true,
};
/* Dialog Actions End */

/* Dialog Start */
export const Dialog = props => <MuiDialog {...props} />;

Dialog.propTypes = {
  ...DialogProps,
  id: PropTypes.string.isRequired,
};
/* Dialog End */
<|endoftext|>


<commit_before>/* @flow */

import { join } from 'path';
import express from 'express';
import graphqlHTTP from 'express-graphql';
import { reduce } from 'lodash';
import schema from '../shared/schema';
import * as conn from './data';

const app = express();

const publicPath = join(__dirname, '..', '..', '.tmp');
app.use(express.static(publicPath));

app.use('/graphql', graphqlHTTP({
  schema,
  rootValue: conn,
}));

const serverPort = process.env.PORT || 1337;
const server = app.listen(serverPort, () => {
  const host = server.address().address;
  const port = server.address().port;

  console.log('Listening at http://%s:%s', host, port); // eslint-disable-line no-console
});

app.get('/', (req, res) => {
  res.send(`
    <!DOCTYPE html>

        <meta charset="utf-8">
        <title></title>

  `);
});
<commit_msg>example fix<commit_after>/* @flow */

import { join } from 'path';
import express from 'express';
import graphqlHTTP from 'express-graphql';
import schema from '../shared/schema';
import * as conn from './data';

const app = express();

const publicPath = join(__dirname, '..', '..', '.tmp');
app.use(express.static(publicPath));

app.use('/graphql', graphqlHTTP({
  schema,
  rootValue: conn,
}));

const serverPort = process.env.PORT || 1337;
const server = app.listen(serverPort, () => {
  const host = server.address().address;
  const port = server.address().port;

  console.log('Listening at http://%s:%s', host, port); // eslint-disable-line no-console
});

app.get('/', (req, res) => {
  res.send(`
    <!DOCTYPE html>

        <meta charset="utf-8">
        <title></title>

  `);
});
<|endoftext|>


<commit_before>import colors from '../../util/colors'
import { horizontalAbsolutePosition } from '../../util/StyleUtils'
import commonStyle from '../style'

const styles = {
  outerContainer: {
    ...horizontalAbsolutePosition(0, 0),
    height: 204
  },
  loginContainer: {
    backgroundColor: 'white',
    ...commonStyle.shadow
  },
  loginButton: {
    height: 68,
    padding: 20,
  },
  loginButtonText: {
    fontSize: 24,
    textAlign: 'center'
  },
  loginAttemptLeftText: {
    fontSize: 18
  },
  input: {
    height: 68,
    fontSize: 20,
    color: colors.bristolBlue,
    backgroundColor: 'white',
    textAlign: 'center'
  },
  separator: {
    height: 1,
    backgroundColor: colors.gray5
  }
}

export default styles
<commit_msg>made attempt left text italic<commit_after>import colors from '../../util/colors'
import { horizontalAbsolutePosition } from '../../util/StyleUtils'
import commonStyle from '../style'

const styles = {
  outerContainer: {
    ...horizontalAbsolutePosition(0, 0),
    height: 204
  },
  loginContainer: {
    backgroundColor: 'white',
    ...commonStyle.shadow
  },
  loginButton: {
    height: 68,
    padding: 20,
  },
  loginButtonText: {
    fontSize: 24,
    textAlign: 'center'
  },
  loginAttemptLeftText: {
    fontSize: 18,
    fontStyle: 'italic'
  },
  input: {
    height: 68,
    fontSize: 20,
    color: colors.bristolBlue,
    backgroundColor: 'white',
    textAlign: 'center'
  },
  separator: {
    height: 1,
    backgroundColor: colors.gray5
  }
}

export default styles
<|endoftext|>


<commit_before>import Vue from 'vue'
import Router from 'vue-router'
import recommended from 'components/recommended/recommended'
import singerDes from 'components/singer-des/singer-des'
import singer from 'components/singer/singer'
import rankings from 'components/rankings/rankings'
import topList from 'components/top-list/top-list'
import search from 'components/search/search'
Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      redirect: '/recommended'
    },
    {
      path: '/recommended',
      component: recommended
    },
    {
      path: '/singer',
      component: singer,
      children: [
        { path: ":id",
          component: singerDes
        }
      ]
    },
    {
      path: '/rankings',
      component: rankings,
      children: [
        { path: ":id",
          component: topList
        }
      ]
    },
    {
      path: '/search',
      component: search
    },
  ]
})
<commit_msg>开启路由懒加载<commit_after>import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)

// 开启路由懒加载
const recommended = (resolve) => {
  import('components/recommended/recommended').then((module) => {
    resolve(module)
  })
}
const singerDes = (resolve) => {
  import('components/singer-des/singer-des').then((module) => {
    resolve(module)
  })
}
const singer = (resolve) => {
  import('components/singer/singer').then((module) => {
    resolve(module)
  })
}
const rankings = (resolve) => {
  import('components/rankings/rankings').then((module) => {
    resolve(module)
  })
}
const topList = (resolve) => {
  import('components/top-list/top-list').then((module) => {
    resolve(module)
  })
}
const search = (resolve) => {
  import('components/search/search').then((module) => {
    resolve(module)
  })
}
export default new Router({
  routes: [
    {
      path: '/',
      redirect: '/recommended'
    },
    {
      path: '/recommended',
      component: recommended
    },
    {
      path: '/singer',
      component: singer,
      children: [
        { path: ":id",
          component: singerDes
        }
      ]
    },
    {
      path: '/rankings',
      component: rankings,
      children: [
        { path: ":id",
          component: topList
        }
      ]
    },
    {
      path: '/search',
      component: search
    },
  ]
})
<|endoftext|>


<commit_before>var tswcalc = tswcalc || {};
tswcalc.data = tswcalc.data || {};

tswcalc.data.findItems = function(slot) {
    var slotItems = tswcalc.data.items.filter(function (item) {
        return item.slots.indexOf(slot) != -1;
    });
    return slotItems;
}

tswcalc.data.items = [
    {
        id: '3',
        name: 'DPS',
        role: 'dps',
        slots: ['head', 'major', 'minor']
    },
    {
        id: '1',
        name: 'Tank',
        role: 'tank',
        slots: ['head', 'major', 'minor']
    },
    {
        id: '2',
        name: 'Healer',
        role: 'healer',
        slots: ['head', 'major', 'minor']
    },

    //NY Items
    {
        id: '80',
        name: 'Blood of the Old Ones',
        ql: '10.4',
        role: 'healer',
        slots: ['head'],
        signet: {
            name: 'Blood of the Old Ones',
            description: 'Whenever you apply a heal effect to a friend, there is a 10% chance that you will heal the target for an additional 3% of their maximum health.',
            quality: 'epic',
            cooldown: 5,
            icon: 'blood_of_the_old_ones'
        }
    },
    {
        id: '81',
        name: 'Mark of the Starspawn',
        ql: '10.4',
        role: 'tank',
        slots: ['head'],
        signet: {
            name: 'Mark of the Starspawn',
            description: 'Whenever you are attacked, you have a 5% chance to gain a beneficial effect that reduces damage received from penetrating attacks for 15 seconds. The duration of this effect is not refreshed when reapplied.',
            quality: 'epic',
            icon: 'mark_of_the_starspawn'
        }
    },
    {
        id: '82',
        name: 'Ashes of Elder Things',
        ql: '10.4',
        role: 'dps',
        slots: ['head'],
        signet: {
            name: 'Ashes of Elder Things',
            description: 'Whenever you penetrate, you gain a beneficial effect that increases your Penetration Rating by 25% for 15 seconds. The duration of this effect is not refreshed when reapplied.',
            quality: 'epic',
            bonus: {
                stat: ['penetration-rating'],
                multiply: 1.25
            },
            icon: 'ashes_of_elder_things'
        }
    },
    {
        id: '83',
        name: 'Coney Island Band',
        ql: '10.4',
        slots: ['ring'],
        role: 'healer',
        signet: {
            name: 'Coney Island Band',
            description: 'Whenever you critically heal, you gain a beneficial effect that increases your Crit Power by 25% for 15 seconds. The duration of this effect is not refreshed when reapplied.',
            quality: 'epic',
            bonus: {
                stat: ['critical-power-percentage'],
                add: 25
            },
            icon: 'coney_island_band'
        }
    },
    {
        id: '84',
        name: 'Egon Pendant',
        ql: '10.4',
        slots: ['neck'],
        role: 'dps',
        signet: {
            name: 'Egon Pendant',
            description: 'Whenever you critically hit, you gain a beneficial effect that increases the effectiveness of your Critical Rating for 12 seconds. The duration of this effect is not refreshed when reapplied.',
            quality: 'epic',
            bonus: {
                stat: ['critical-rating'],
                multiply: 1.25
            },
            icon: 'egon_pendant'
        }
    },
    {
        id: '85',
        name: 'Brooklyn Bracer',
        ql: '10.4',
        slots: ['wrist'],
        role: 'tank',
        signet: {
            name: 'Brooklyn Bracer',
            description: 'Whenever you are attacked, you gain a single stack of a beneficial effect that increases your Evade Chance by 5% per stack. This effect is removed after you successfully evade.',
            quality: 'epic',
            icon: 'brooklyn_bracer'
        }
    },
    {
        id: '86',
        name: 'Subway Tokens',
        ql: '10.4',
        slots: ['luck'],
        role: 'dps',
        signet: {
            name: 'Subway Tokens',
            description: 'Every 6 seconds, you gain a single stack of a beneficial effect that increases all damage dealt by 1% per stack. This effect is removed whenever you glance or the number of stacks exceeds 10.',
            quality: 'epic',
            icon: 'subway_tokens'
        }
    },
    {
        id: '87',
        name: 'NY Buckle',
        ql: '10.4',
        slots: ['waist'],
        role: 'tank',
        signet: {
            name: 'NY Buckle',
            description: 'Every 6 seconds, you gain a single stack of a beneficial effect that increases your Physical and Magical Protection by 3% per stack. This effect is removed whenever you are penetrated or the number of stacks exceeds 10.',
            quality: 'epic',
            bonus: {
                stat: ['physical-protection', 'magical-protection'],
                multiply: 1.30
            },
            icon: 'ny_buckle'
        }
    },
    {
        id: '88',
        name: 'Broadway Charm',
        ql: '10.4',
        slots: ['occult'],
        role: 'healer',
        signet: {
            name: 'Broadway Charm',
            description: 'Whenever you heal a target that is below 66% of their health, there is a 33% chance that you will also give them a beneficial effect that increases their Physical and Magical Protection by 400 for 10 seconds. 6 seconds cooldown.',
            quality: 'epic',
            icon: 'broadway_charm'
        }
    },

    //Woodcutters
    {
        id: '90',
        name: 'The Woodcutter\'s Sorrow',
        ql: '10.9',
        role: 'healer',
        slots: ['neck'],
        glyph: {
            ql: '10.5',
            primary: {
                stat: 'critical-power',
                dist: 4
            },
            secondary: {
                stat: 'none',
                dist: 0
            }
        },
        signet: {
            name: 'The Woodcutter\'s Sorrow',
            description: 'Whenever you directly heal an ally, you trigger Maternal Band: If your ally has an existing barrier, they are healed for twice the strength of that barrier. Maternal Band can only occur once per ally every 4 seconds.',
            quality: 'heroic',
            icon: 'woodcutter_sorrow'
        }
    },
    {
        id: '91',
        name: 'The Woodcutter\'s Regret',
        role: 'tank',
        slots: ['neck'],
        glyph: {
            ql: '10.5',
            primary: {
                stat: 'magical-protection',
                dist: 2
            },
            secondary: {
                stat: 'physical-protection',
                dist: 2
            }
        },
        signet: {
            name: 'The Woodcutter\'s Regret',
            description: 'Whenever you are hit, you have a 33% chance to trigger Guardian Spirit: Increases the lowest of your Evade, Defence and Block Rating by 300 for 5 seconds. This effect will not trigger if two or more of these stats are of equal value.',
            quality: 'heroic',
            icon: 'woodcutter_regret'
        }
    },
    {
        id: '92',
        name: 'The Woodcutter\'s Wrath',
        role: 'dps',
        slots: ['neck'],
        glyph: {
            ql: '10.5',
            primary: {
                stat: 'critical-power',
                dist: 4
            },
            secondary: {
                stat: 'none',
                dist: 0
            }
        },
        signet: {
            name: 'The Woodcutter\'s Wrath',
            description: 'Whenever an attack fails to penetrate, you gain a Mother\'s Wrath counter. When you reach 5 counters, they are removed and you gain a beneficial effect which increases your Penetration Chance by 40% for 3 seconds. Whenever you penetrate, all Mother\'s Wrath counters are removed. 6 seconds cooldown.',
            quality: 'heroic',
            icon: 'woodcutter_wrath'
        }
    }
];
<commit_msg>WC Wrath/Regret QL Level Fix<commit_after>var tswcalc = tswcalc || {};
tswcalc.data = tswcalc.data || {};

tswcalc.data.findItems = function(slot) {
    var slotItems = tswcalc.data.items.filter(function (item) {
        return item.slots.indexOf(slot) != -1;
    });
    return slotItems;
}

tswcalc.data.items = [
    {
        id: '3',
        name: 'DPS',
        role: 'dps',
        slots: ['head', 'major', 'minor']
    },
    {
        id: '1',
        name: 'Tank',
        role: 'tank',
        slots: ['head', 'major', 'minor']
    },
    {
        id: '2',
        name: 'Healer',
        role: 'healer',
        slots: ['head', 'major', 'minor']
    },

    //NY Items
    {
        id: '80',
        name: 'Blood of the Old Ones',
        ql: '10.4',
        role: 'healer',
        slots: ['head'],
        signet: {
            name: 'Blood of the Old Ones',
            description: 'Whenever you apply a heal effect to a friend, there is a 10% chance that you will heal the target for an additional 3% of their maximum health.',
            quality: 'epic',
            cooldown: 5,
            icon: 'blood_of_the_old_ones'
        }
    },
    {
        id: '81',
        name: 'Mark of the Starspawn',
        ql: '10.4',
        role: 'tank',
        slots: ['head'],
        signet: {
            name: 'Mark of the Starspawn',
            description: 'Whenever you are attacked, you have a 5% chance to gain a beneficial effect that reduces damage received from penetrating attacks for 15 seconds. The duration of this effect is not refreshed when reapplied.',
            quality: 'epic',
            icon: 'mark_of_the_starspawn'
        }
    },
    {
        id: '82',
        name: 'Ashes of Elder Things',
        ql: '10.4',
        role: 'dps',
        slots: ['head'],
        signet: {
            name: 'Ashes of Elder Things',
            description: 'Whenever you penetrate, you gain a beneficial effect that increases your Penetration Rating by 25% for 15 seconds. The duration of this effect is not refreshed when reapplied.',
            quality: 'epic',
            bonus: {
                stat: ['penetration-rating'],
                multiply: 1.25
            },
            icon: 'ashes_of_elder_things'
        }
    },
    {
        id: '83',
        name: 'Coney Island Band',
        ql: '10.4',
        slots: ['ring'],
        role: 'healer',
        signet: {
            name: 'Coney Island Band',
            description: 'Whenever you critically heal, you gain a beneficial effect that increases your Crit Power by 25% for 15 seconds. The duration of this effect is not refreshed when reapplied.',
            quality: 'epic',
            bonus: {
                stat: ['critical-power-percentage'],
                add: 25
            },
            icon: 'coney_island_band'
        }
    },
    {
        id: '84',
        name: 'Egon Pendant',
        ql: '10.4',
        slots: ['neck'],
        role: 'dps',
        signet: {
            name: 'Egon Pendant',
            description: 'Whenever you critically hit, you gain a beneficial effect that increases the effectiveness of your Critical Rating for 12 seconds. The duration of this effect is not refreshed when reapplied.',
            quality: 'epic',
            bonus: {
                stat: ['critical-rating'],
                multiply: 1.25
            },
            icon: 'egon_pendant'
        }
    },
    {
        id: '85',
        name: 'Brooklyn Bracer',
        ql: '10.4',
        slots: ['wrist'],
        role: 'tank',
        signet: {
            name: 'Brooklyn Bracer',
            description: 'Whenever you are attacked, you gain a single stack of a beneficial effect that increases your Evade Chance by 5% per stack. This effect is removed after you successfully evade.',
            quality: 'epic',
            icon: 'brooklyn_bracer'
        }
    },
    {
        id: '86',
        name: 'Subway Tokens',
        ql: '10.4',
        slots: ['luck'],
        role: 'dps',
        signet: {
            name: 'Subway Tokens',
            description: 'Every 6 seconds, you gain a single stack of a beneficial effect that increases all damage dealt by 1% per stack. This effect is removed whenever you glance or the number of stacks exceeds 10.',
            quality: 'epic',
            icon: 'subway_tokens'
        }
    },
    {
        id: '87',
        name: 'NY Buckle',
        ql: '10.4',
        slots: ['waist'],
        role: 'tank',
        signet: {
            name: 'NY Buckle',
            description: 'Every 6 seconds, you gain a single stack of a beneficial effect that increases your Physical and Magical Protection by 3% per stack. This effect is removed whenever you are penetrated or the number of stacks exceeds 10.',
            quality: 'epic',
            bonus: {
                stat: ['physical-protection', 'magical-protection'],
                multiply: 1.30
            },
            icon: 'ny_buckle'
        }
    },
    {
        id: '88',
        name: 'Broadway Charm',
        ql: '10.4',
        slots: ['occult'],
        role: 'healer',
        signet: {
            name: 'Broadway Charm',
            description: 'Whenever you heal a target that is below 66% of their health, there is a 33% chance that you will also give them a beneficial effect that increases their Physical and Magical Protection by 400 for 10 seconds. 6 seconds cooldown.',
            quality: 'epic',
            icon: 'broadway_charm'
        }
    },

    //Woodcutters
    {
        id: '90',
        name: 'The Woodcutter\'s Sorrow',
        ql: '10.9',
        role: 'healer',
        slots: ['neck'],
        glyph: {
            ql: '10.5',
            primary: {
                stat: 'critical-power',
                dist: 4
            },
            secondary: {
                stat: 'none',
                dist: 0
            }
        },
        signet: {
            name: 'The Woodcutter\'s Sorrow',
            description: 'Whenever you directly heal an ally, you trigger Maternal Band: If your ally has an existing barrier, they are healed for twice the strength of that barrier. Maternal Band can only occur once per ally every 4 seconds.',
            quality: 'heroic',
            icon: 'woodcutter_sorrow'
        }
    },
    {
        id: '91',
        name: 'The Woodcutter\'s Regret',
        ql: '10.9',
        role: 'tank',
        slots: ['neck'],
        glyph: {
            ql: '10.5',
            primary: {
                stat: 'magical-protection',
                dist: 2
            },
            secondary: {
                stat: 'physical-protection',
                dist: 2
            }
        },
        signet: {
            name: 'The Woodcutter\'s Regret',
            description: 'Whenever you are hit, you have a 33% chance to trigger Guardian Spirit: Increases the lowest of your Evade, Defence and Block Rating by 300 for 5 seconds. This effect will not trigger if two or more of these stats are of equal value.',
            quality: 'heroic',
            icon: 'woodcutter_regret'
        }
    },
    {
        id: '92',
        name: 'The Woodcutter\'s Wrath',
        ql: '10.9',
        role: 'dps',
        slots: ['neck'],
        glyph: {
            ql: '10.5',
            primary: {
                stat: 'critical-power',
                dist: 4
            },
            secondary: {
                stat: 'none',
                dist: 0
            }
        },
        signet: {
            name: 'The Woodcutter\'s Wrath',
            description: 'Whenever an attack fails to penetrate, you gain a Mother\'s Wrath counter. When you reach 5 counters, they are removed and you gain a beneficial effect which increases your Penetration Chance by 40% for 3 seconds. Whenever you penetrate, all Mother\'s Wrath counters are removed. 6 seconds cooldown.',
            quality: 'heroic',
            icon: 'woodcutter_wrath'
        }
    }
];
<|endoftext|>


<commit_before>var util = require('util');
var validators = require('./validators');
exports.defaultError = require('./defaultError');

var ValidatorError = exports.ValidatorError = function(msg) {
    Error.captureStackTrace(this, this);
    this.name = 'ValidatorError';
    this.message = msg;
};
util.inherits(ValidatorError, Error);

var Validator = exports.Validator = function() {}

Validator.prototype.error = function (msg) {
    throw new ValidatorError(msg);
};

Validator.prototype.check = function(str, fail_msg) {
    if (typeof str === 'object' && str !== null && str.toString) {
        str = str.toString();
    }
    this.str = (str == null || (isNaN(str) && str.length == undefined)) ? '' : str;
    if (typeof this.str == 'number') {
        this.str += '';
    }
    this.msg = fail_msg;
    this._errors = this._errors || [];
    return this;
}

for (var key in validators) {
    if (validators.hasOwnProperty(key)) {
        (function (key) {
            Validator.prototype[key] = function() {
                var args = Array.prototype.slice.call(arguments);
                args.unshift(this.str);
                if(!validators[key].apply(this, args)) {
                    var msg = this.msg || exports.defaultError[key];
                    if (typeof msg === 'string') {
                        args.forEach(function(arg, i) { msg = msg.replace('%'+i, arg); });
                    }
                    return this.error(msg);
                }
                return this;
            };
        })(key);
    }
}

//Create some aliases - may help code readability
Validator.prototype.validate = Validator.prototype.check;
Validator.prototype.assert = Validator.prototype.check;
Validator.prototype.isFloat = Validator.prototype.isDecimal;
Validator.prototype.is = Validator.prototype.regex;
Validator.prototype.not = Validator.prototype.notRegex;
<commit_msg>Added ability to have a validation message per check.<commit_after>var util = require('util');
var validators = require('./validators');
exports.defaultError = require('./defaultError');

var ValidatorError = exports.ValidatorError = function(msg) {
    Error.captureStackTrace(this, this);
    this.name = 'ValidatorError';
    this.message = msg;
};
util.inherits(ValidatorError, Error);

var Validator = exports.Validator = function() {}

Validator.prototype.error = function (msg) {
    throw new ValidatorError(msg);
};

Validator.prototype.check = function(str, fail_msg) {
    if (typeof str === 'object' && str !== null && str.toString) {
        str = str.toString();
    }
    this.str = (str == null || (isNaN(str) && str.length == undefined)) ? '' : str;
    if (typeof this.str == 'number') {
        this.str += '';
    }

    // This is a key, value pair of error messages to use
    if (typeof fail_msg === 'object') {
        this.errorDictionary = fail_msg;
        this.msg = null
    }
    else {
        this.errorDictionary = {};
        this.msg = fail_msg;
    }

    this._errors = this._errors || [];
    return this;
}

for (var key in validators) {
    if (validators.hasOwnProperty(key)) {
        (function (key) {
            Validator.prototype[key] = function() {
                var args = Array.prototype.slice.call(arguments);
                args.unshift(this.str);
                if(!validators[key].apply(this, args)) {
                    var msg = this.errorDictionary[key] || this.msg || exports.defaultError[key];
                    if (typeof msg === 'string') {
                        args.forEach(function(arg, i) { msg = msg.replace('%'+i, arg); });
                    }
                    return this.error(msg);
                }
                return this;
            };
        })(key);
    }
}

//Create some aliases - may help code readability
Validator.prototype.validate = Validator.prototype.check;
Validator.prototype.assert = Validator.prototype.check;
Validator.prototype.isFloat = Validator.prototype.isDecimal;
Validator.prototype.is = Validator.prototype.regex;
Validator.prototype.not = Validator.prototype.notRegex;
<|endoftext|>


<commit_before>/**
	_moon.VideoFeedback_ is a control used by	[moon.VideoPlayer](#moon.VideoPlayer)
	to display feedback in response to input from video playback controls.  It may
	also be used to display custom messages.
*/
enyo.kind({
	name: "moon.VideoFeedback",
	kind: "enyo.Control",
	//* @protected
	classes: "moon-video-player-feedback",
	//* @public
	published: {
		/**
			Length of time (in milliseconds) after which the on-screen feedback will
			automatically disappear
		*/
		autoTimeoutMS:	2000
	},
	//* @protected
	_showingFeedback: false,
	_imagePath:				"$lib/moonstone/images/video-player/",
	_jumpBackImg:			"jumpbackward",
	_rewindImg:				"backward",
	_playImg:				"play",
	_pauseImg:				"pause",
	_fastForwardImg:		"forward",
	_jumpForwardImg:		"jumpforward",
	_pauseBackImg:			"pausebackward",
	_pauseForwardImg:		"pauseforward",
	_pauseJumpBackImg:		"pausejumpbackward",
	_pauseJumpForwardImg:	"pausejumpforward",
	_autoTimer: null,

	components: [
		{name: "leftIcon", kind: "moon.Icon", classes: "moon-video-feedback-icon-left", allowHtml: true, showing: false},
		{name: "feedText",  classes: "moon-video-feedback-text", allowHtml: true, showing: false},
		{name: "rightIcon", kind: "moon.Icon", classes: "moon-video-feedback-icon-right", allowHtml: true, showing: false}
	],

	//* @public
	create: function() {
		this.inherited(arguments);
		if (window.ilib) {
			this.df = new ilib.DurFmt({length: "medium", useNative: false});
		}
	},

	//* @public
	/**
		Updates IconButton image and Slider message with current state and
		playback rate when any of the playback controls are triggered.

		Playback states are mapped to _playbackRate_ values according to the
		following hash:

			{
				"fastForward": ["2", "4", "8", "16"],
				"rewind": ["-2", "-4", "-8", "-16"],
				"slowForward": ["1/4", "1/2"],
				"slowRewind": ["-1/2", "-1"]
			}
	*/
	checkIconType: function(inIcon) {
		var imagesrcRegex = /\.(jpg|jpeg|png|gif)$/i;
		return imagesrcRegex.test(inIcon) ? "image" : "iconfont";
	},
	retriveImgOrIconPath:function(inIcon){
		if (this.checkIconType(inIcon) == "image") {
			return enyo.path.rewrite(this._imagePath + inIcon);
		} else {
			return enyo.path.rewrite(inIcon);
		}
	},
	feedback: function(inMessage, inParams, inPersistShowing, inLeftSrc, inRightSrc, isInPreview) {
		var customMessage = false;
		inMessage = inMessage || "";
		inParams = inParams || {};

		if (inMessage !== "") { this.$.feedText.show(); }

		switch (inMessage) {
		case "Play":
			inMessage = moon.$L("PLAY"); // i18n "PLAY" feedback text in moon.VideoPlayer widget, should be translated to ALL CAPS in all languages
			inRightSrc = this.retriveImgOrIconPath(this._playImg);
			break;

		case "Pause":
			inMessage = moon.$L("PAUSE"); // i18n "PAUSE" feedback text in moon.VideoPlayer widget, should be translated to ALL CAPS in all languages
			inRightSrc = this.retriveImgOrIconPath(this._pauseImg);
			break;

		case "Rewind":
			inMessage = Math.abs(inParams.playbackRate) + "x";
			inLeftSrc = this.retriveImgOrIconPath(this._rewindImg);
			break;

		case "Slowrewind":
			inMessage = inParams.playbackRate + "x";
			inLeftSrc = this.retriveImgOrIconPath(this._pauseBackImg);
			break;

		case "Fastforward":
			inMessage = Math.abs(inParams.playbackRate) + "x";
			inRightSrc = this.retriveImgOrIconPath(this._fastForwardImg);
			break;

		case "Slowforward":
			inMessage = inParams.playbackRate + "x";
			inRightSrc = this.retriveImgOrIconPath(this._pauseForwardImg);
			break;

		case "JumpBackward":
			inMessage = this.df ? enyo.toUpperCase(this.df.format({second: inParams.jumpSize})) : inParams.jumpSize + " SEC";
			inLeftSrc = this.retriveImgOrIconPath(this._pauseJumpBackImg);
			break;

		case "JumpForward":
			inMessage = this.df ? enyo.toUpperCase(this.df.format({second: inParams.jumpSize})) : inParams.jumpSize + " SEC";
			inRightSrc = this.retriveImgOrIconPath(this._pauseJumpForwardImg);
			break;

		case "JumpToStart":
			inMessage = "";
			inLeftSrc = this.retriveImgOrIconPath(this._pauseJumpBackImg);
			break;

		case "JumpToEnd":
			inMessage = "";
			inRightSrc = this.retriveImgOrIconPath(this._pauseJumpForwardImg);
			break;

		case "Stop":
			inMessage = moon.$L("STOP"); // i18n "STOP" feedback text in moon.VideoPlayer widget, should be translated to ALL CAPS in all languages
			inRightSrc = "";
			break;

		// If the user sends in a custom message, block other messages until it's hidden
		default:
			customMessage = true;
			this._showingFeedback = true;
			break;
		}

		// Don't show feedback if we are showing custom feedback already, unless this is a new custom message
		if (!customMessage && this._showingFeedback) {
			return;
		}

		// Set content as _inMessage_
		this.$.feedText.setContent( enyo.toUpperCase(inMessage) );

		// Show output controls when video player is not preview mode
		if (!isInPreview {
			this.showFeedback();
		})

		// Show icons as appropriate
		this.updateIcons(inLeftSrc, inRightSrc);

		//* Don't set up hide timer if _inPersistShowing_ is true
		if (inPersistShowing) {
			this.resetAutoTimer();
		} else {
			this.setAutoTimer();
		}
		this.inPersistShowing = inPersistShowing;
	},

	/**
		Returns boolean value previously passed into _feedback()_. A return value of
		true indicates that the current feedback message has no timeout.
	*/
	isPersistShowing: function() {
		return this.inPersistShowing;
	},

	//* Shows this control.
	showFeedback: function() {
		this.setShowing(true);
	},
	//* Hides this control and sets _this.showingFeedback_ to false.
	hideFeedback: function() {
		this.setShowing(false);
		this._showingFeedback = false;
	},

	//* @protected

	//* Starts job that will hide this control.
	setAutoTimer: function() {
		this.hideJob = enyo.job(this.id + "hide", this.bindSafely("hideFeedback"), this.getAutoTimeoutMS());
	},
	//* Clears job that will hide this control.
	resetAutoTimer: function() {
		enyo.job.stop(this.id + "hide");
	},
	//* Shows or hides icons and sets sources.
	updateIcons: function(inLeftSrc, inRightSrc) {
		if (inLeftSrc) {
			this.$.leftIcon.show();
			this.displayIconSrcOrFont(this.$.leftIcon, inLeftSrc);
		} else {
			this.$.leftIcon.hide();
		}

		if (inRightSrc) {
			this.$.rightIcon.show();
			this.displayIconSrcOrFont(this.$.rightIcon, inRightSrc);
		} else {
			this.$.rightIcon.hide();
		}
	},
	displayIconSrcOrFont: function(inIconKind, inIcon) {
		if (this.checkIconType(inIcon) == "image") {
			inIconKind.set("icon", "");
			inIconKind.set("src", inIcon);
		} else {
			inIconKind.set("src", "");
			inIconKind.set("icon", inIcon);
		}
	}
});
<commit_msg>BHV-6773  Fix typo<commit_after>/**
	_moon.VideoFeedback_ is a control used by	[moon.VideoPlayer](#moon.VideoPlayer)
	to display feedback in response to input from video playback controls.  It may
	also be used to display custom messages.
*/
enyo.kind({
	name: "moon.VideoFeedback",
	kind: "enyo.Control",
	//* @protected
	classes: "moon-video-player-feedback",
	//* @public
	published: {
		/**
			Length of time (in milliseconds) after which the on-screen feedback will
			automatically disappear
		*/
		autoTimeoutMS:	2000
	},
	//* @protected
	_showingFeedback: false,
	_imagePath:				"$lib/moonstone/images/video-player/",
	_jumpBackImg:			"jumpbackward",
	_rewindImg:				"backward",
	_playImg:				"play",
	_pauseImg:				"pause",
	_fastForwardImg:		"forward",
	_jumpForwardImg:		"jumpforward",
	_pauseBackImg:			"pausebackward",
	_pauseForwardImg:		"pauseforward",
	_pauseJumpBackImg:		"pausejumpbackward",
	_pauseJumpForwardImg:	"pausejumpforward",
	_autoTimer: null,

	components: [
		{name: "leftIcon", kind: "moon.Icon", classes: "moon-video-feedback-icon-left", allowHtml: true, showing: false},
		{name: "feedText",  classes: "moon-video-feedback-text", allowHtml: true, showing: false},
		{name: "rightIcon", kind: "moon.Icon", classes: "moon-video-feedback-icon-right", allowHtml: true, showing: false}
	],

	//* @public
	create: function() {
		this.inherited(arguments);
		if (window.ilib) {
			this.df = new ilib.DurFmt({length: "medium", useNative: false});
		}
	},

	//* @public
	/**
		Updates IconButton image and Slider message with current state and
		playback rate when any of the playback controls are triggered.

		Playback states are mapped to _playbackRate_ values according to the
		following hash:

			{
				"fastForward": ["2", "4", "8", "16"],
				"rewind": ["-2", "-4", "-8", "-16"],
				"slowForward": ["1/4", "1/2"],
				"slowRewind": ["-1/2", "-1"]
			}
	*/
	checkIconType: function(inIcon) {
		var imagesrcRegex = /\.(jpg|jpeg|png|gif)$/i;
		return imagesrcRegex.test(inIcon) ? "image" : "iconfont";
	},
	retriveImgOrIconPath:function(inIcon){
		if (this.checkIconType(inIcon) == "image") {
			return enyo.path.rewrite(this._imagePath + inIcon);
		} else {
			return enyo.path.rewrite(inIcon);
		}
	},
	feedback: function(inMessage, inParams, inPersistShowing, inLeftSrc, inRightSrc, isInPreview) {
		var customMessage = false;
		inMessage = inMessage || "";
		inParams = inParams || {};

		if (inMessage !== "") { this.$.feedText.show(); }

		switch (inMessage) {
		case "Play":
			inMessage = moon.$L("PLAY"); // i18n "PLAY" feedback text in moon.VideoPlayer widget, should be translated to ALL CAPS in all languages
			inRightSrc = this.retriveImgOrIconPath(this._playImg);
			break;

		case "Pause":
			inMessage = moon.$L("PAUSE"); // i18n "PAUSE" feedback text in moon.VideoPlayer widget, should be translated to ALL CAPS in all languages
			inRightSrc = this.retriveImgOrIconPath(this._pauseImg);
			break;

		case "Rewind":
			inMessage = Math.abs(inParams.playbackRate) + "x";
			inLeftSrc = this.retriveImgOrIconPath(this._rewindImg);
			break;

		case "Slowrewind":
			inMessage = inParams.playbackRate + "x";
			inLeftSrc = this.retriveImgOrIconPath(this._pauseBackImg);
			break;

		case "Fastforward":
			inMessage = Math.abs(inParams.playbackRate) + "x";
			inRightSrc = this.retriveImgOrIconPath(this._fastForwardImg);
			break;

		case "Slowforward":
			inMessage = inParams.playbackRate + "x";
			inRightSrc = this.retriveImgOrIconPath(this._pauseForwardImg);
			break;

		case "JumpBackward":
			inMessage = this.df ? enyo.toUpperCase(this.df.format({second: inParams.jumpSize})) : inParams.jumpSize + " SEC";
			inLeftSrc = this.retriveImgOrIconPath(this._pauseJumpBackImg);
			break;

		case "JumpForward":
			inMessage = this.df ? enyo.toUpperCase(this.df.format({second: inParams.jumpSize})) : inParams.jumpSize + " SEC";
			inRightSrc = this.retriveImgOrIconPath(this._pauseJumpForwardImg);
			break;

		case "JumpToStart":
			inMessage = "";
			inLeftSrc = this.retriveImgOrIconPath(this._pauseJumpBackImg);
			break;

		case "JumpToEnd":
			inMessage = "";
			inRightSrc = this.retriveImgOrIconPath(this._pauseJumpForwardImg);
			break;

		case "Stop":
			inMessage = moon.$L("STOP"); // i18n "STOP" feedback text in moon.VideoPlayer widget, should be translated to ALL CAPS in all languages
			inRightSrc = "";
			break;

		// If the user sends in a custom message, block other messages until it's hidden
		default:
			customMessage = true;
			this._showingFeedback = true;
			break;
		}

		// Don't show feedback if we are showing custom feedback already, unless this is a new custom message
		if (!customMessage && this._showingFeedback) {
			return;
		}

		// Set content as _inMessage_
		this.$.feedText.setContent( enyo.toUpperCase(inMessage) );

		// Show output controls when video player is not preview mode
		if (!isInPreview) {
			this.showFeedback();
		}

		// Show icons as appropriate
		this.updateIcons(inLeftSrc, inRightSrc);

		//* Don't set up hide timer if _inPersistShowing_ is true
		if (inPersistShowing) {
			this.resetAutoTimer();
		} else {
			this.setAutoTimer();
		}
		this.inPersistShowing = inPersistShowing;
	},

	/**
		Returns boolean value previously passed into _feedback()_. A return value of
		true indicates that the current feedback message has no timeout.
	*/
	isPersistShowing: function() {
		return this.inPersistShowing;
	},

	//* Shows this control.
	showFeedback: function() {
		this.setShowing(true);
	},
	//* Hides this control and sets _this.showingFeedback_ to false.
	hideFeedback: function() {
		this.setShowing(false);
		this._showingFeedback = false;
	},

	//* @protected

	//* Starts job that will hide this control.
	setAutoTimer: function() {
		this.hideJob = enyo.job(this.id + "hide", this.bindSafely("hideFeedback"), this.getAutoTimeoutMS());
	},
	//* Clears job that will hide this control.
	resetAutoTimer: function() {
		enyo.job.stop(this.id + "hide");
	},
	//* Shows or hides icons and sets sources.
	updateIcons: function(inLeftSrc, inRightSrc) {
		if (inLeftSrc) {
			this.$.leftIcon.show();
			this.displayIconSrcOrFont(this.$.leftIcon, inLeftSrc);
		} else {
			this.$.leftIcon.hide();
		}

		if (inRightSrc) {
			this.$.rightIcon.show();
			this.displayIconSrcOrFont(this.$.rightIcon, inRightSrc);
		} else {
			this.$.rightIcon.hide();
		}
	},
	displayIconSrcOrFont: function(inIconKind, inIcon) {
		if (this.checkIconType(inIcon) == "image") {
			inIconKind.set("icon", "");
			inIconKind.set("src", inIcon);
		} else {
			inIconKind.set("src", "");
			inIconKind.set("icon", inIcon);
		}
	}
});
<|endoftext|>


<commit_before>import Rx from 'rxjs';
import expect from 'expect';
import { createLogic, createLogicMiddleware } from '../src/index';

describe('createLogicMiddleware-debounce', () => {
  describe('[logicA] debounce validate async allow', () => {
    let mw;
    let logicA;
    let next;
    let dispatch;
    const actionFoo1 = { type: 'FOO', id: 1 };
    const actionFoo2 = { type: 'FOO', id: 2 };
    beforeEach(done => {
      next = expect.createSpy().andCall(() => done());
      dispatch = expect.createSpy().andCall(cb);
      let dispatchCount = 0;
      function cb() {
        if (++dispatchCount >= 0) {
          done();
        }
      }
      logicA = createLogic({
        type: 'FOO',
        debounce: 10,
        validate({ action }, allow) {
          setTimeout(() => {
            allow(action);
          }, 0);
        }
      });
      mw = createLogicMiddleware([logicA]);
      const storeFn = mw({ dispatch })(next);
      storeFn(actionFoo1);
      storeFn(actionFoo2);
    });

    it('passes only actionFoo2 since validate async', () => {
      expect(next.calls.length).toBe(1);
      expect(next.calls[0].arguments[0]).toEqual(actionFoo2);
    });

    it('no dispatches', () => {
      expect(dispatch.calls.length).toBe(0);
    });
  });

  describe('[logicA] debounce validate async reject', () => {
    let mw;
    let logicA;
    let next;
    let dispatch;
    const actionFoo1 = { type: 'FOO', id: 1 };
    const actionFoo2 = { type: 'FOO', id: 2 };
    beforeEach(done => {
      next = expect.createSpy().andCall(() => done());
      dispatch = expect.createSpy().andCall(cb);
      let dispatchCount = 0;
      function cb() {
        if (++dispatchCount >= 0) {
          done();
        }
      }
      logicA = createLogic({
        type: 'FOO',
        debounce: 10,
        validate({ action }, allow, reject) {
          setTimeout(() => {
            reject(action);
          }, 0);
        }
      });
      mw = createLogicMiddleware([logicA]);
      const storeFn = mw({ dispatch })(next);
      storeFn(actionFoo1);
      storeFn(actionFoo2);
    });

    it('passes only actionFoo2 since validate async', () => {
      expect(next.calls.length).toBe(1);
      expect(next.calls[0].arguments[0]).toEqual(actionFoo2);
    });

    it('no dispatches', () => {
      expect(dispatch.calls.length).toBe(0);
    });
  });

  describe('[logicA] debounce next async', () => {
    let mw;
    let logicA;
    let next;
    let dispatch;
    const actionFoo1 = { type: 'FOO', id: 1 };
    const actionFoo2 = { type: 'FOO', id: 2 };
    const actionResult = { type: 'FOO', id: 2, trans: ['a'] };
    beforeEach(done => {
      next = expect.createSpy().andCall(() => done());
      dispatch = expect.createSpy().andCall(cb);
      let dispatchCount = 0;
      function cb() {
        if (++dispatchCount >= 0) {
          done();
        }
      }
      logicA = createLogic({
        type: 'FOO',
        debounce: 10,
        transform({ action }, next) {
          setTimeout(() => {
            next({
              ...action,
              trans: ['a']
            });
          }, 0);
        }
      });
      mw = createLogicMiddleware([logicA]);
      const storeFn = mw({ dispatch })(next);
      storeFn(actionFoo1);
      storeFn(actionFoo2);
    });

    it('passes only actionFoo2 since validate async', () => {
      expect(next.calls.length).toBe(1);
      expect(next.calls[0].arguments[0]).toEqual(actionResult);
    });

    it('no dispatches', () => {
      expect(dispatch.calls.length).toBe(0);
    });
  });

  describe('[logicA] debounce process', () => {
    let mw;
    let logicA;
    let next;
    let dispatch;
    const actionFoo1 = { type: 'FOO', id: 1 };
    const actionFoo2 = { type: 'FOO', id: 2 };
    const actionResultFoo2 = { type: 'BAR', id: 2 };
    beforeEach(done => {
      next = expect.createSpy();
      dispatch = expect.createSpy().andCall(cb);
      let dispatchCount = 0;
      function cb() {
        if (++dispatchCount >= 1) { done(); }
      }
      logicA = createLogic({
        type: 'FOO',
        debounce: 10,
        process({ action }, dispatch) {
          setTimeout(() => {
            dispatch({
              ...action,
              type: 'BAR'
            });
          }, 20);
        }
      });
      mw = createLogicMiddleware([logicA]);
      const storeFn = mw({ dispatch })(next);
      storeFn(actionFoo1);
      setTimeout(() => {
        storeFn(actionFoo2);
      }, 0);
    });

    it('passes only actionFoo2', () => {
      expect(next.calls.length).toBe(1);
      expect(next.calls[0].arguments[0]).toEqual(actionFoo2);
    });

    it('dispatch only actionResult2', () => {
      expect(dispatch.calls.length).toBe(1);
      expect(dispatch.calls[0].arguments[0]).toEqual(actionResultFoo2);
    });
  });

  describe('[logicA] debounce process syncDispatch(x, true) dispatch(y)', () => {
    let mw;
    let logicA;
    let next;
    let dispatch;
    const actionFoo1 = { type: 'FOO', id: 1 };
    const actionFoo2 = { type: 'FOO', id: 2 };
    const actionSyncResult2 = { type: 'BAR', id: 2 };
    const actionResultFoo2 = { type: 'CAT', id: 2 };
    beforeEach(done => {
      next = expect.createSpy();
      dispatch = expect.createSpy().andCall(cb);
      let dispatchCount = 0;
      function cb() {
        if (++dispatchCount >= 2) { done(); }
      }
      logicA = createLogic({
        type: 'FOO',
        debounce: 20,
        process({ action }, dispatch) {
          // immediate dispatch
          dispatch({
            ...action,
            type: 'BAR'
          }, { allowMore: true });

          // followed by later async dispatch
          setTimeout(() => {
            dispatch({
              ...action,
              type: 'CAT'
            });
          }, 20);
        }
      });
      mw = createLogicMiddleware([logicA]);
      const storeFn = mw({ dispatch })(next);
      storeFn(actionFoo1);
      setTimeout(() => {
        storeFn(actionFoo2);
      }, 10);
    });

    it('passes only actionFoo2', () => {
      expect(next.calls.length).toBe(1);
      expect(next.calls[0].arguments[0]).toEqual(actionFoo2);
    });

    it('dispatch only sync2, async2', () => {
      expect(dispatch.calls.length).toBe(2);
      expect(dispatch.calls[0].arguments[0]).toEqual(actionSyncResult2);
      expect(dispatch.calls[1].arguments[0]).toEqual(actionResultFoo2);
    });
  });

  describe('[logicA] debounce process obs(sync x, async y)', () => {
    let mw;
    let logicA;
    let next;
    let dispatch;
    const actionFoo1 = { type: 'FOO', id: 1 };
    const actionFoo2 = { type: 'FOO', id: 2 };
    const actionSyncResult2 = { type: 'BAR', id: 2 };
    const actionResultFoo2 = { type: 'CAT', id: 2 };
    beforeEach(done => {
      next = expect.createSpy();
      dispatch = expect.createSpy().andCall(cb);
      let dispatchCount = 0;
      function cb() {
        if (++dispatchCount >= 2) { done(); }
      }
      logicA = createLogic({
        type: 'FOO',
        debounce: 20,
        process({ action }, dispatch) {
          dispatch(Rx.Observable.create(obs => {
            // immediate dispatch
            obs.next({
              ...action,
              type: 'BAR'
            });

            // followed by later async dispatch
            setTimeout(() => {
              obs.next({
                ...action,
                type: 'CAT'
              });
            }, 30);
          }));
        }
      });
      mw = createLogicMiddleware([logicA]);
      const storeFn = mw({ dispatch })(next);
      storeFn(actionFoo1);
      setTimeout(() => {
        storeFn(actionFoo2);
      }, 10);
    });

    it('passes actionFoo2', () => {
      expect(next.calls.length).toBe(1);
      expect(next.calls[0].arguments[0]).toEqual(actionFoo2);
    });

    it('dispatch only sync1, async1', () => {
      expect(dispatch.calls.length).toBe(2);
      expect(dispatch.calls[0].arguments[0]).toEqual(actionSyncResult2);
      expect(dispatch.calls[1].arguments[0]).toEqual(actionResultFoo2);
    });
  });
});
<commit_msg>improve timing of sporadic debounce test<commit_after>import Rx from 'rxjs';
import expect from 'expect';
import { createLogic, createLogicMiddleware } from '../src/index';

describe('createLogicMiddleware-debounce', () => {
  describe('[logicA] debounce validate async allow', () => {
    let mw;
    let logicA;
    let next;
    let dispatch;
    const actionFoo1 = { type: 'FOO', id: 1 };
    const actionFoo2 = { type: 'FOO', id: 2 };
    beforeEach(done => {
      next = expect.createSpy().andCall(() => done());
      dispatch = expect.createSpy().andCall(cb);
      let dispatchCount = 0;
      function cb() {
        if (++dispatchCount >= 0) {
          done();
        }
      }
      logicA = createLogic({
        type: 'FOO',
        debounce: 10,
        validate({ action }, allow) {
          setTimeout(() => {
            allow(action);
          }, 0);
        }
      });
      mw = createLogicMiddleware([logicA]);
      const storeFn = mw({ dispatch })(next);
      storeFn(actionFoo1);
      storeFn(actionFoo2);
    });

    it('passes only actionFoo2 since validate async', () => {
      expect(next.calls.length).toBe(1);
      expect(next.calls[0].arguments[0]).toEqual(actionFoo2);
    });

    it('no dispatches', () => {
      expect(dispatch.calls.length).toBe(0);
    });
  });

  describe('[logicA] debounce validate async reject', () => {
    let mw;
    let logicA;
    let next;
    let dispatch;
    const actionFoo1 = { type: 'FOO', id: 1 };
    const actionFoo2 = { type: 'FOO', id: 2 };
    beforeEach(done => {
      next = expect.createSpy().andCall(() => done());
      dispatch = expect.createSpy().andCall(cb);
      let dispatchCount = 0;
      function cb() {
        if (++dispatchCount >= 0) {
          done();
        }
      }
      logicA = createLogic({
        type: 'FOO',
        debounce: 10,
        validate({ action }, allow, reject) {
          setTimeout(() => {
            reject(action);
          }, 0);
        }
      });
      mw = createLogicMiddleware([logicA]);
      const storeFn = mw({ dispatch })(next);
      storeFn(actionFoo1);
      storeFn(actionFoo2);
    });

    it('passes only actionFoo2 since validate async', () => {
      expect(next.calls.length).toBe(1);
      expect(next.calls[0].arguments[0]).toEqual(actionFoo2);
    });

    it('no dispatches', () => {
      expect(dispatch.calls.length).toBe(0);
    });
  });

  describe('[logicA] debounce next async', () => {
    let mw;
    let logicA;
    let next;
    let dispatch;
    const actionFoo1 = { type: 'FOO', id: 1 };
    const actionFoo2 = { type: 'FOO', id: 2 };
    const actionResult = { type: 'FOO', id: 2, trans: ['a'] };
    beforeEach(done => {
      next = expect.createSpy().andCall(() => done());
      dispatch = expect.createSpy().andCall(cb);
      let dispatchCount = 0;
      function cb() {
        if (++dispatchCount >= 0) {
          done();
        }
      }
      logicA = createLogic({
        type: 'FOO',
        debounce: 10,
        transform({ action }, next) {
          setTimeout(() => {
            next({
              ...action,
              trans: ['a']
            });
          }, 0);
        }
      });
      mw = createLogicMiddleware([logicA]);
      const storeFn = mw({ dispatch })(next);
      storeFn(actionFoo1);
      storeFn(actionFoo2);
    });

    it('passes only actionFoo2 since validate async', () => {
      expect(next.calls.length).toBe(1);
      expect(next.calls[0].arguments[0]).toEqual(actionResult);
    });

    it('no dispatches', () => {
      expect(dispatch.calls.length).toBe(0);
    });
  });

  describe('[logicA] debounce process', () => {
    let mw;
    let logicA;
    let next;
    let dispatch;
    const actionFoo1 = { type: 'FOO', id: 1 };
    const actionFoo2 = { type: 'FOO', id: 2 };
    const actionResultFoo2 = { type: 'BAR', id: 2 };
    beforeEach(done => {
      next = expect.createSpy();
      dispatch = expect.createSpy().andCall(cb);
      let dispatchCount = 0;
      function cb() {
        if (++dispatchCount >= 1) { done(); }
      }
      logicA = createLogic({
        type: 'FOO',
        debounce: 10,
        process({ action }, dispatch) {
          setTimeout(() => {
            dispatch({
              ...action,
              type: 'BAR'
            });
          }, 20);
        }
      });
      mw = createLogicMiddleware([logicA]);
      const storeFn = mw({ dispatch })(next);
      storeFn(actionFoo1);
      setTimeout(() => {
        storeFn(actionFoo2);
      }, 0);
    });

    it('passes only actionFoo2', () => {
      expect(next.calls.length).toBe(1);
      expect(next.calls[0].arguments[0]).toEqual(actionFoo2);
    });

    it('dispatch only actionResult2', () => {
      expect(dispatch.calls.length).toBe(1);
      expect(dispatch.calls[0].arguments[0]).toEqual(actionResultFoo2);
    });
  });

  describe('[logicA] debounce process syncDispatch(x, true) dispatch(y)', () => {
    let mw;
    let logicA;
    let next;
    let dispatch;
    const actionFoo1 = { type: 'FOO', id: 1 };
    const actionFoo2 = { type: 'FOO', id: 2 };
    const actionSyncResult2 = { type: 'BAR', id: 2 };
    const actionResultFoo2 = { type: 'CAT', id: 2 };
    beforeEach(done => {
      next = expect.createSpy();
      dispatch = expect.createSpy().andCall(cb);
      let dispatchCount = 0;
      function cb() {
        if (++dispatchCount >= 2) { done(); }
      }
      logicA = createLogic({
        type: 'FOO',
        debounce: 30,
        process({ action }, dispatch) {
          // immediate dispatch
          dispatch({
            ...action,
            type: 'BAR'
          }, { allowMore: true });

          // followed by later async dispatch
          setTimeout(() => {
            dispatch({
              ...action,
              type: 'CAT'
            });
          }, 50);
        }
      });
      mw = createLogicMiddleware([logicA]);
      const storeFn = mw({ dispatch })(next);
      storeFn(actionFoo1);
      setTimeout(() => {
        storeFn(actionFoo2);
      }, 15);
    });

    it('passes only actionFoo2', () => {
      expect(next.calls.length).toBe(1);
      expect(next.calls[0].arguments[0]).toEqual(actionFoo2);
    });

    it('dispatch only sync2, async2', () => {
      expect(dispatch.calls.length).toBe(2);
      expect(dispatch.calls[0].arguments[0]).toEqual(actionSyncResult2);
      expect(dispatch.calls[1].arguments[0]).toEqual(actionResultFoo2);
    });
  });

  describe('[logicA] debounce process obs(sync x, async y)', () => {
    let mw;
    let logicA;
    let next;
    let dispatch;
    const actionFoo1 = { type: 'FOO', id: 1 };
    const actionFoo2 = { type: 'FOO', id: 2 };
    const actionSyncResult2 = { type: 'BAR', id: 2 };
    const actionResultFoo2 = { type: 'CAT', id: 2 };
    beforeEach(done => {
      next = expect.createSpy();
      dispatch = expect.createSpy().andCall(cb);
      let dispatchCount = 0;
      function cb() {
        if (++dispatchCount >= 2) { done(); }
      }
      logicA = createLogic({
        type: 'FOO',
        debounce: 20,
        process({ action }, dispatch) {
          dispatch(Rx.Observable.create(obs => {
            // immediate dispatch
            obs.next({
              ...action,
              type: 'BAR'
            });

            // followed by later async dispatch
            setTimeout(() => {
              obs.next({
                ...action,
                type: 'CAT'
              });
            }, 30);
          }));
        }
      });
      mw = createLogicMiddleware([logicA]);
      const storeFn = mw({ dispatch })(next);
      storeFn(actionFoo1);
      setTimeout(() => {
        storeFn(actionFoo2);
      }, 10);
    });

    it('passes actionFoo2', () => {
      expect(next.calls.length).toBe(1);
      expect(next.calls[0].arguments[0]).toEqual(actionFoo2);
    });

    it('dispatch only sync1, async1', () => {
      expect(dispatch.calls.length).toBe(2);
      expect(dispatch.calls[0].arguments[0]).toEqual(actionSyncResult2);
      expect(dispatch.calls[1].arguments[0]).toEqual(actionResultFoo2);
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

angular.module('myApp.factories')

    .factory('lemma', function (nlp) {

        //returns an array of result objects with institute, course, degree, date and grade fields
        var parseEducationBackground = function (sentenceArray) {
            function Result() {
                this.institute = [];
                this.course = [];
                this.degree = [];
                this.date = [];
                this.grade = [];
            };
            var results = [];
            var instituteKeyWords = ["college", "university", "institute"];
            var courseKeyWords = ["computer", "computing", "engineering", "information technology", "physics", "it", "neuroscience"];
            var degreeKeyWords = ["bachelor's", "bachelor", "bsc", "master", "master's", "phd", "ph.d", "degree", "mscs", "msc", "be"];
            var gradeKeyWords = ["grade:", "cap", "gpa"];
            var prev = null;
            var result = new Result();
            sentenceArray.forEach(
                function (sentence) {
                    //assume 1 sentence
                    var tokens = nlp.pos(sentence).sentences[0].tokens;
                    tokens.forEach(
                        function (token) {
                            var hasKeyWord = function (keyWord) {
                                return token.text.toLowerCase().indexOf(keyWord) >= 0;
                            };
                            if (token.pos.tag === "NN" || token.pos.tag === "PRP") {
                                var isGrade = gradeKeyWords.some(hasKeyWord);
                                var isInstitute = instituteKeyWords.some(hasKeyWord);
                                var isCourse = courseKeyWords.some(hasKeyWord);
                                var isDegree = degreeKeyWords.some(hasKeyWord);
                                var idk = !(isInstitute || isCourse || isDegree || isGrade);
                                if (isInstitute || (idk && prev === "institute")) {
                                    if (prev !== "institute" && result.institute.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.institute.push(token.text);
                                    prev = "institute"
                                } else if (isCourse || (idk && prev === "course")) {
                                    if (prev !== "course" && result.course.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.course.push(token.text);
                                    prev = "course"
                                } else if (isDegree || (idk && prev === "degree")) {
                                    if (prev !== "degree" && result.degree.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.degree.push(token.text);
                                    prev = "degree"
                                } else if (isGrade) {
                                    if (prev !== "grade" && result.grade.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    prev = "grade"
                                } else {
                                    result.institute.push(token.text);
                                    prev = "institute"
                                }
                            } else if (token.pos.tag === "CD") {
                                //we have a number
                                if (prev == "grade") {
                                    result.grade.push(token.text);
                                } else {
                                    if (prev !== "date" && result.date.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.date.push(token.text);
                                    prev = "date"
                                }
                            } else if (token.pos.tag == "UH") {
                                //for symbol
                            } else {
                                //push into the same place as the last pushed place
                                if (prev === "course") {
                                    result.course.push(token.text);
                                } else if (prev === "degree") {
                                    result.degree.push(token.text);
                                } else if (prev === "grade") {
                                    result.grade.push(token.text);
                                } else if (prev === "date") {
                                    result.date.push(token.text);
                                } else {
                                    result.institute.push(token.text);
                                }
                            }
                        }
                    )
                    results.push(result);
                }
            )
            return results;
        }

        //returns all the sentence splitted up by " "
        var parseLanguages = function (sentenceArray) {
            var results = [];
            sentenceArray.forEach(
                function (sentence) {
                    var tokens = sentence.split(" ");
                    results = results.concat(tokens);
                }
            )
            return results;
            //function LanguageResult() {
            //    this.language = "";
            //    this.level = [];
            //};
            ////assume one sentence -> no full stops
            //var languageResults = [];
            //var result = new LanguageResult();
            //sentenceArray.forEach(
            //    function (sentence) {
            //        var tokens = nlp.pos(sentence).sentences[0].tokens;
            //        console.log(tokens);
            //        var prev = null;
            //        tokens.forEach(
            //            function (token) {
            //                if (token.pos.tag === "JJ") {
            //                    if (prev !== "level" && result.level.length > 0 && result.language !== "") {
            //                        languageResults.push(result);
            //                        result = new LanguageResult();
            //                    }
            //                    result.level.push(token.text);
            //                } else {
            //                    if (result.language !== "") {
            //                        languageResults.push(result);
            //                        result = new LanguageResult();
            //                    }
            //                    result.language = token.text;
            //                }
            //            }
            //        )
            //        languageResults.push(result);
            //    }
            //)
            //return languageResults;
        }

        //var test = ["National University of Singapore", "MSCS, IT, 2010 - 2012"];
        //console.log(parseEducationBackground(test));
        return {
            parse_education: parseEducationBackground,
            parse_language: parseLanguages
        }
    }
)
;<commit_msg>write method to parse interests<commit_after>'use strict';

angular.module('myApp.factories')

    .factory('lemma', function (nlp) {

        //returns an array of result objects with institute, course, degree, date and grade fields
        var parseEducationBackground = function (sentenceArray) {
            function Result() {
                this.institute = [];
                this.course = [];
                this.degree = [];
                this.date = [];
                this.grade = [];
            };
            var results = [];
            var instituteKeyWords = ["college", "university", "institute"];
            var courseKeyWords = ["computer", "computing", "engineering", "information technology", "physics", "it", "neuroscience"];
            var degreeKeyWords = ["bachelor's", "bachelor", "bsc", "master", "master's", "phd", "ph.d", "degree", "mscs", "msc", "be"];
            var gradeKeyWords = ["grade:", "cap", "gpa"];
            var prev = null;
            var result = new Result();
            sentenceArray.forEach(
                function (sentence) {
                    //assume 1 sentence
                    var tokens = nlp.pos(sentence).sentences[0].tokens;
                    tokens.forEach(
                        function (token) {
                            var hasKeyWord = function (keyWord) {
                                return token.text.toLowerCase().indexOf(keyWord) >= 0;
                            };
                            if (token.pos.tag === "NN" || token.pos.tag === "PRP") {
                                var isGrade = gradeKeyWords.some(hasKeyWord);
                                var isInstitute = instituteKeyWords.some(hasKeyWord);
                                var isCourse = courseKeyWords.some(hasKeyWord);
                                var isDegree = degreeKeyWords.some(hasKeyWord);
                                var idk = !(isInstitute || isCourse || isDegree || isGrade);
                                if (isInstitute || (idk && prev === "institute")) {
                                    if (prev !== "institute" && result.institute.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.institute.push(token.text);
                                    prev = "institute"
                                } else if (isCourse || (idk && prev === "course")) {
                                    if (prev !== "course" && result.course.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.course.push(token.text);
                                    prev = "course"
                                } else if (isDegree || (idk && prev === "degree")) {
                                    if (prev !== "degree" && result.degree.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.degree.push(token.text);
                                    prev = "degree"
                                } else if (isGrade) {
                                    if (prev !== "grade" && result.grade.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    prev = "grade"
                                } else {
                                    result.institute.push(token.text);
                                    prev = "institute"
                                }
                            } else if (token.pos.tag === "CD") {
                                //we have a number
                                if (prev == "grade") {
                                    result.grade.push(token.text);
                                } else {
                                    if (prev !== "date" && result.date.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.date.push(token.text);
                                    prev = "date"
                                }
                            } else if (token.pos.tag == "UH") {
                                //for symbol
                            } else {
                                //push into the same place as the last pushed place
                                if (prev === "course") {
                                    result.course.push(token.text);
                                } else if (prev === "degree") {
                                    result.degree.push(token.text);
                                } else if (prev === "grade") {
                                    result.grade.push(token.text);
                                } else if (prev === "date") {
                                    result.date.push(token.text);
                                } else {
                                    result.institute.push(token.text);
                                }
                            }
                        }
                    )
                    results.push(result);
                }
            )
            return results;
        }

        //split by commas
        var parseInterests = function(sentenceArray) {
            var results = [];
            sentenceArray.forEach(
                function (sentence) {
                    var tokens = sentence.split(",");
                    results = results.concat(tokens.map(Function.prototype.call, String.prototype.trim));
                }
            )
            return results;
        }

        //returns all the sentence splitted up by " "
        var parseLanguages = function (sentenceArray) {
            var results = [];
            sentenceArray.forEach(
                function (sentence) {
                    var tokens = sentence.split(" ");
                    results = results.concat(tokens);
                }
            )
            return results;
            //function LanguageResult() {
            //    this.language = "";
            //    this.level = [];
            //};
            ////assume one sentence -> no full stops
            //var languageResults = [];
            //var result = new LanguageResult();
            //sentenceArray.forEach(
            //    function (sentence) {
            //        var tokens = nlp.pos(sentence).sentences[0].tokens;
            //        console.log(tokens);
            //        var prev = null;
            //        tokens.forEach(
            //            function (token) {
            //                if (token.pos.tag === "JJ") {
            //                    if (prev !== "level" && result.level.length > 0 && result.language !== "") {
            //                        languageResults.push(result);
            //                        result = new LanguageResult();
            //                    }
            //                    result.level.push(token.text);
            //                } else {
            //                    if (result.language !== "") {
            //                        languageResults.push(result);
            //                        result = new LanguageResult();
            //                    }
            //                    result.language = token.text;
            //                }
            //            }
            //        )
            //        languageResults.push(result);
            //    }
            //)
            //return languageResults;
        }

        //var test = ["National University of Singapore", "MSCS, IT, 2010 - 2012"];
        //console.log(parseEducationBackground(test));
        return {
            parse_education: parseEducationBackground,
            parse_language: parseLanguages,
            parse_interest: parseInterests
        }
    }
)
;<|endoftext|>


<commit_before>/*
 * Component properties.
 */
export default {
    bindings: {
        blockClass: "@",
        customClass: "<",
        title: "@",
        placeholder: "@",
        model: "=?",
        disabled: "<",
        options: "<",
        click: "&",
        focus: "&",
        blur: "&",
        change: "&",
        keypress: "&",
        keydown: "&",
        keyup: "&"
    },

    templateUrl: ["$element", "$attrs", function($element, $attrs) {
        return "./field-" + $attrs.type + ".html";
    }]
};
<commit_msg>Fixed templateUrl path<commit_after>/*
 * Component properties.
 */
export default {
    bindings: {
        blockClass: "@",
        customClass: "<",
        title: "@",
        placeholder: "@",
        model: "=?",
        disabled: "<",
        options: "<",
        click: "&",
        focus: "&",
        blur: "&",
        change: "&",
        keypress: "&",
        keydown: "&",
        keyup: "&"
    },

    templateUrl: ["$element", "$attrs", function($element, $attrs) {
        return "field-" + $attrs.type + ".html";
    }]
};
<|endoftext|>


<commit_before>import React from 'react';
import {connectToStores} from 'fluxible-addons-react';
import classNames from 'classnames';
import NavigationPanel from './../NavigationPanel/NavigationPanel';
import changeTemplate from '../../../actions/slide/changeTemplate';
import addInputBox from '../../../actions/slide/addInputBox';
import uploadMediaClick from '../../../actions/slide/uploadMediaClick';
import uploadVideoClick from '../../../actions/slide/uploadVideoClick';

class SlideEditPanel extends React.Component {

    constructor(props) {
        super(props);
        this.showTemplate = false;
        this.state = {
        };
    }
    handleTemplateClick(){
        console.log('clicked');
        this.showTemplate = true;
        this.forceUpdate();
    }
    handleTemplatechange(){
        this.context.executeAction(changeTemplate, {
            template: this.refs.template.value
        });
    }
    handleAddInputBox(){
        this.context.executeAction(addInputBox, {});
    }
    handleUploadMediaClick(){
        this.context.executeAction(uploadMediaClick, {});
    }
    handleUploadVideoClick(){
        this.context.executeAction(uploadVideoClick, {});
    }
    componentDidMount() {
        $(this.refs.TemplateDropdown).dropdown();
    }
    componentDidUpdate() {
        $(this.refs.TemplateDropdown).dropdown();
    }
    render() {
        const dropDownItemStyle = {
            //minWidth: '100%',
            minHeight: '100px',
            //borderStyle: 'dashed dashed none dashed',
            //borderColor: '#e7e7e7',
        };
        //TODO: put in separate component
        let templateOptions =

                Title and bullets

                Empty document

                1 row 1 column

                1 row 2 columns

                2 rows 2 columns

                2 rows 1 column

                1 row 1 column image

                Document with title

                Open University Theme Title Page

                OEG Theme Title Page

                SlideWiki template

                EKDDA template

                EKDDA template - English

                EKDDA template - English no footer

;
        let templateDropDown;
        if(this.showTemplate){
            templateDropDown = (

                    <input type="hidden" name="template" id="template" ref="template" defaultValue={this.props.template} />

Use template

                    {templateOptions}

);
        }else {
            templateDropDown = '';
        }
        return (

                <NavigationPanel mode='edit' />
                {/*
                    give mode='edit' to navigationpane

                    <button className="ui small basic right floated icon button"></button>

                */}

                              Text

                              Image

                              Video

                              Other

                              Embed

                              Template

                          {templateDropDown}

                              HTML editor

                          { /*

                              Sources
                          */}

        );
    }
}

SlideEditPanel.contextTypes = {
    executeAction: React.PropTypes.func.isRequired
};
export default SlideEditPanel;
<commit_msg>Keyboard access for slide edit panel<commit_after>import React from 'react';
import {connectToStores} from 'fluxible-addons-react';
import classNames from 'classnames';
import NavigationPanel from './../NavigationPanel/NavigationPanel';
import changeTemplate from '../../../actions/slide/changeTemplate';
import addInputBox from '../../../actions/slide/addInputBox';
import uploadMediaClick from '../../../actions/slide/uploadMediaClick';
import uploadVideoClick from '../../../actions/slide/uploadVideoClick';

class SlideEditPanel extends React.Component {

    constructor(props) {
        super(props);
        this.showTemplate = false;
        this.state = {
        };
    }
    handleAddInputBox(){
        this.context.executeAction(addInputBox, {});
    }
    handleUploadMediaClick(){
        this.context.executeAction(uploadMediaClick, {});
    }
    handleUploadVideoClick(){
        this.context.executeAction(uploadVideoClick, {});
    }
    handleOtherClick(){}
    handleEmbedClick(){}

    handleTemplateClick(){
        console.log('clicked');
        this.showTemplate = true;
        this.forceUpdate();
    }
    handleTemplatechange(){
        this.context.executeAction(changeTemplate, {
            template: this.refs.template.value
        });
    }
    handleHTMLEditorClick(){}

    componentDidMount() {
        $(this.refs.TemplateDropdown).dropdown();
        $('#handleAddInputBox').on('keyup', (e) => {if (e.keyCode === 13 || e.keyCode === 32) {this.handleAddInputBox();}});
        $('#handleUploadMediaClick').on('keyup', (e) => {if (e.keyCode === 13 || e.keyCode === 32) {this.handleUploadMediaClick();}});
        $('#handleUploadVideoClick').on('keyup', (e) => {if (e.keyCode === 13 || e.keyCode === 32) {this.handleUploadVideoClick();}});
        $('#handleOtherClick').on('keyup', (e) => {if (e.keyCode === 13 || e.keyCode === 32) {this.handleOtherClick();}});
        $('#handleEmbedClick').on('keyup', (e) => {if (e.keyCode === 13 || e.keyCode === 32) {this.handleEmbedClick();}});
        $('#handleTemplatechange').on('keyup', (e) => {if (e.keyCode === 13 || e.keyCode === 32) {this.handleTemplatechange();}});
        $('#handleHTMLEditorClick').on('keyup', (e) => {if (e.keyCode === 13 || e.keyCode === 32) {this.handleHTMLEditorClick();}});
    }
    componentDidUpdate() {
        $(this.refs.TemplateDropdown).dropdown();
    }
    render() {
        const dropDownItemStyle = {
            //minWidth: '100%',
            minHeight: '100px',
            //borderStyle: 'dashed dashed none dashed',
            //borderColor: '#e7e7e7',
        };
        //TODO: put in separate component
        let templateOptions =

                Title and bullets

                Empty document

                1 row 1 column

                1 row 2 columns

                2 rows 2 columns

                2 rows 1 column

                1 row 1 column image

                Document with title

                Open University Theme Title Page

                OEG Theme Title Page

                SlideWiki template

                EKDDA template

                EKDDA template - English

                EKDDA template - English no footer

;
        let templateDropDown;
        if(this.showTemplate){
            templateDropDown = (

                    <input type="hidden" name="template" id="template" ref="template" defaultValue={this.props.template} />

Use template

                    {templateOptions}

);
        }else {
            templateDropDown = '';
        }
        return (

                <NavigationPanel mode='edit' />
                {/*
                    give mode='edit' to navigationpane

                    <button className="ui small basic right floated icon button"></button>

                */}

                              Text

                              Image

                              Video

                              Other

                              Embed

                              Template

                          {templateDropDown}

                              HTML editor

                          { /*

                              Sources
                          */}

        );
    }
}

SlideEditPanel.contextTypes = {
    executeAction: React.PropTypes.func.isRequired
};
export default SlideEditPanel;
<|endoftext|>


<commit_before>Players = new Mongo.Collection('players');
console.log("Init players");

Players.helpers({
	/**
	 * Find one player by logged user Id
	 * @param  {int} userId Id of a login user
	 * @return {[Player]}        Found player list
	 */
	byUserId(userId) {
		return Players.findOne({
			userId: userId
		});
	},
	/**
	 * Find a list of score series for this player
	 * @return {[ScoreSeries]}
	 */
	scoreSeries() {
		return ScoreSeries.find({playerId: this._id});
	},
	/**
	 * Find a list of closed score series for this player
	 * @return {[ScoreSeries]}
	 */
	closedScoreSeries() {
		return ScoreSeries.find({playerId: this._id, state: "CLOSED"});
	},
	/**
	 * Find list of scores for this player
	 *
	 * @return {[Scores]}
	 */
	scores() {
		var scores = [];
		// Map function to sum scores
		// WARNING: USE ALL SCORE SERIES (NOT ONLY THE CLOSED ONES)
		var scoreSeries = this.scoreSeries().map(function(doc){
			var innerScores = doc.scores().fetch();
			if(innerScores.length > 0){
				scores = scores.concat(innerScores);
			}
		});
		return scores;
	},
	/**
	 * Find and sum the scores of this player.
	 * Finally, it returns the total score
	 *
	 * @return {Int} Sum of player scores
	 */
	totalScore() {
		var total = 0;
		// Map function to sum scores
		var scores = this.scores().map(function(doc){
			if(!isNaN(doc.score)){
				total += doc.score;
			}
		});
		return total;
	},
	/**
	 * Gets the user in relation with this player using
	 * the userId saved as field
	 *
	 * @return {User} User in relation with this player
	 */
	user() {
		return Meteor.users.findOne(this.userId);
	}
});

Players.findSortByTotalScore = function(order) {
	var list = Players.find({},{sort:{totalScore : -1}}).fetch();
	list.sort(function(a,b) {
		if (a.totalScore() < b.totalScore()) {
			return 1;
		}
		if (a.totalScore() > b.totalScore()) {
			return -1;
		}
		return 0;
	});

	return list;
};

/**
 * Create and insert a new Players object with given parameters.
 * Direct insert() should be avoided, because this function
 * request all the necessary parameters for a correct Players object.
 * @param  {String} email  email of player
 * @param  {String} name   name of player
 * @param  {String} userId (Optional) Id of logged user in relation with this player
 * @return {String}        id of newly created user
 */
Players.createPlayer = function(email, name, userId) {
	var playerData = {
		email: email,
		name: name,
		userId: userId
	};
	return Players.insert(playerData);
};<commit_msg>Show in leaderboard only no-user players and currently logged user<commit_after>Players = new Mongo.Collection('players');
console.log("Init players");

Players.helpers({
	/**
	 * Find one player by logged user Id
	 * @param  {int} userId Id of a login user
	 * @return {[Player]}        Found player list
	 */
	byUserId(userId) {
		return Players.findOne({
			userId: userId
		});
	},
	/**
	 * Find a list of score series for this player
	 * @return {[ScoreSeries]}
	 */
	scoreSeries() {
		return ScoreSeries.find({playerId: this._id});
	},
	/**
	 * Find a list of closed score series for this player
	 * @return {[ScoreSeries]}
	 */
	closedScoreSeries() {
		return ScoreSeries.find({playerId: this._id, state: "CLOSED"});
	},
	/**
	 * Find list of scores for this player
	 *
	 * @return {[Scores]}
	 */
	scores() {
		var scores = [];
		// Map function to sum scores
		// WARNING: USE ALL SCORE SERIES (NOT ONLY THE CLOSED ONES)
		var scoreSeries = this.scoreSeries().map(function(doc){
			var innerScores = doc.scores().fetch();
			if(innerScores.length > 0){
				scores = scores.concat(innerScores);
			}
		});
		return scores;
	},
	/**
	 * Find and sum the scores of this player.
	 * Finally, it returns the total score
	 *
	 * @return {Int} Sum of player scores
	 */
	totalScore() {
		var total = 0;
		// Map function to sum scores
		var scores = this.scores().map(function(doc){
			if(!isNaN(doc.score)){
				total += doc.score;
			}
		});
		return total;
	},
	/**
	 * Gets the user in relation with this player using
	 * the userId saved as field
	 *
	 * @return {User} User in relation with this player
	 */
	user() {
		return Meteor.users.findOne(this.userId);
	}
});

Players.findSortByTotalScore = function(order) {
	var list = Players.find({},{sort:{totalScore : -1}}).fetch();
	// Sort players by score
	list.sort(function(a,b) {
		if (a.totalScore() < b.totalScore()) {
			return 1;
		}
		if (a.totalScore() > b.totalScore()) {
			return -1;
		}
		return 0;
	});

	var result = [];
	// Players are added to list only if they are mocked user (no userId found)
	// or if it's the currently logged user's player
	for(var i = 0; i < list.length; i++) {
		var element = list[i];
		if(!element.userId || element.userId == Meteor.user()._id){
			result.push(element);
		}
	}

	return result;
};

/**
 * Create and insert a new Players object with given parameters.
 * Direct insert() should be avoided, because this function
 * request all the necessary parameters for a correct Players object.
 * @param  {String} email  email of player
 * @param  {String} name   name of player
 * @param  {String} userId (Optional) Id of logged user in relation with this player
 * @return {String}        id of newly created user
 */
Players.createPlayer = function(email, name, userId) {
	var playerData = {
		email: email,
		name: name,
		userId: userId
	};
	return Players.insert(playerData);
};<|endoftext|>


<commit_before>/*
 *  query_simple.js
 *
 *  David Janes
 *  IOTDB.org
 *  2017-08-06
 *
 *  Copyright [2013-2018] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict";

/**

    DELETE ME

const _ = require("iotdb-helpers");
const errors = require("iotdb-errors");

const assert = require("assert");

const mongodb = require('mongodb');

const mongo = require("../lib");
const util = require("../lib/util");

const query_simple = _.promise.make((self, done) => {
    const self = _.d.clone.shallow(_self)
    const method = "dynamodb.query_simple";

    assert.ok(self.mongodbd, `${method}: expected self.mongodbd`)
    assert.ok(self.mongo_db, `${method}: expected self.mongo_db`)
    assert.ok(_.is.JSON(self.query), `${method}: expected self.query to be a JSON-like object`)
    assert.ok(self.table_schema, `${method}: expected self.table_schema`)
    assert.ok(self.table_name || self.table_schema.name, `${method}: expected self.table_name`)

    let keys = self.table_schema.keys;
    if (self.index_name) {
        keys = self.table_schema.indexes[self.index_name]
        assert.ok(keys, `${method}: expected index for ${self.table_name||self.table_schema.name} / ${self.index_name}`)
    }

    // XXX - THIS NEEDS TO BE GENERALIZED FFSJFC
    const sort = keys.map(key => [ key, key === "created" ? -1 : 1 ])
    const options = {
        skip: 0
    }

    if (self.pager) {
        options.skip = _.coerce.to.Integer(self.pager, 0)
    }
    if (self.query_limit) {
        options.limit = self.query_limit;
    }

    // rewrite query to be Mongoish
    const query = _.d.clone.shallow(self.query)
    const query_keys = _.keys(query)
    query_keys
        .filter(query_key => _.is.Array(query[query_key]))
        .forEach(query_key => {
            const parts = query[query_key];

            let position = 0;
            while (position < parts.length) {
                let comparitor;
                let q;

                switch (parts[position].toLowerCase()) {
                case "=":
                case "eq":
                    q = {
                        "$eq": parts[position + 1]
                    }

                    position += 2;
                    break;

                case "<": case "lt":
                    q = {
                        "$lt": parts[position + 1]
                    }

                    position += 2;
                    break;

                case "<=": case "le":
                    q = {
                        "$lte": parts[position + 1]
                    }

                    position += 2;
                    break;

                case ">": case "gt":
                    q = {
                        "$gt": parts[position + 1]
                    }

                    position += 2;
                    break;

                case ">=": case "ge":
                    q = {
                        "$gte": parts[position + 1]
                    }

                    position += 2;
                    break;

                case "!=": case "ne":
                    q = {
                        "$ne": parts[position + 1]
                    }

                    position += 2;
                    break;

                case "between":
                    q = {
                        "$gte": parts[position + 1],
                        "$lte": parts[position + 2],
                    }

                    position += 3;
                    break;

                default:
                    throw new error.Invalid("unknown operator: " + parts[position])
                }

                query[query_key] = q;
            }
        })

    _.promise.make(self)
        .then(mongo.collection)
        .then(sd => {
            sd.mongo_collection.find(query, options).sort(sort).toArray((error, mongo_result) => {
                if (error) {
                    return done(error)
                }

                self.jsons = util.scrub_ids(mongo_result);
                self.json = self.jsons.length ? self.jsons[0] : null;

                self.cursor = null;

                if (options.limit) {
                    self.cursor = {
                        first: "0",
                        previous: null,
                        current: `${options.skip}`,
                        next: null,

                        is_first: null,
                        is_last: null,
                        has_next: null,
                        has_previous: null,
                        is_previous_first: null,

                        implements_previous: true,

                        n_results: self.jsons.length,
                        n_start: options.skip,
                    }

                    if (self.jsons.length > 0) {
                        self.cursor.next = `${Math.min(options.limit, self.jsons.length) + options.skip}`;

                        if (self.jsons.length < options.limit) {
                            self.cursor.next = null;
                            self.cursor.is_last = true;
                            self.cursor.has_next = false;
                        } else {
                            self.cursor.has_next = true;
                        }

                        if (options.skip === 0) {
                            self.cursor.is_first = true;
                        }

                        const previous = options.skip - options.limit;
                        self.cursor.previous = `${Math.max(0, previous)}`
                        if (previous === 0) {
                            self.cursor.has_previous = true;
                            self.cursor.is_previous_first = true;
                        } else if (previous < 0) {
                            self.cursor.has_previous = false;
                        } else {
                            self.cursor.has_previous = true;
                        }

                    }
                }

                self.mongo_result = mongo_result;

                done(null, self)
            })
        })
        .catch(done)
}

exports.query_simple = _.promise.denodeify(query_simple)
exports.scan_simple = _.promise.denodeify(query_simple)
/**
 *  API
 */
<commit_msg>no longer used<commit_after><|endoftext|>