<commit_before>'use strict';

var util = require('util'),

    _ = require('lodash'),
    vow = require('vow'),
    Api = require('github'),

    errors = require('./errors').GhApi,
    config = require('./config'),
    logger = require('./logger'),

    gitPublic,
    gitPrivate,
    common = {
        version: '3.0.0',
        protocol: 'https',
        timeout: 5000,
        debug: false
    },
    isInitialized = false;

module.exports = {
    /**
     * Initialize github api connections to public and private repositories
     * with configured credentials
     */
    init: function () {
        if (isInitialized) {
            return vow.resolve();
        }

        logger.info('Initialize github API module', module);

        var ghConfig = config.get('github'),
            ghPublic = _.extend({ host: 'api.github.com' }, ghConfig.public || {}),
            ghPrivate = _.extend({ host: 'github.yandex-team.ru', pathPrefix: '/api/v3' }, ghConfig.private || {});

        if (ghPublic) {
            gitPublic = new Api(_.extend(ghPublic, common));

            var token = ghConfig.public.token;
            if (token && token.length) {
                gitPublic.authenticate({ type: 'oauth', token: token });
            }else {
                errors.createError(errors.CODES.NOT_AUTHENTIFICATED).log('warn');
            }
        }

        if (ghPrivate) {
            gitPrivate = new Api(_.extend(ghPrivate, common));
        }

        isInitialized = true;
        return vow.resolve();
    },

    /**
     * Returns gh module configured for public or private github depending on repository type
     * @param {Object} r -  repository configuration object
     * @returns {Object}
     */
    getGit: function (r) {
        return r.type === 'private' ? gitPrivate : gitPublic;
    },

    /**
     * Returns content of repository directory or file loaded by github api
     * @param {Object} options - object with fields:
     * - type {String} type of repository privacy ('public' or 'private')
     * - user {String} name of user or organization which this repository is belong to
     * - repo {String} name of repository
     * - ref {String} name of branch
     * - path {String} relative path from the root of repository
     * @returns {*}
     */
    load: function (options) {
        var def = vow.defer(),
            repository = options.repository;
        logger.verbose(util.format('Load data from %s %s %s %s',
            repository.user, repository.repo, repository.ref, repository.path), module);

        this.getGit(repository).repos.getContent(repository, function (err, res) {
            if (err || !res) {
                logger.error(util.format('Load data from %s %s %s %s',
                    repository.user, repository.repo, repository.ref, repository.path), module);
                errors.createError(errors.CODES.LOAD, {
                    path: repository.path,
                    user: repository.user,
                    repo: repository.repo,
                    ref: repository.ref,
                    err: err
                }).log();
                def.reject({ res: null, repo: repository });
            }else {
                def.resolve({ res: res, repo: repository });
            }
        });
        return def.promise();
    },

    /**
     * Returns info for given branch
     * @param {Object} options - object with fields:
     * - type {String} type of repository privacy ('public' or 'private')
     * - user {String} name of user or organization which this repository is belong to
     * - repo {String} name of repository
     * - branch {String} name of branch
     * @returns {*}
     */
    isBranchExists: function (options) {
        var def = vow.defer(),
            repository = options.repository;

        this.getGit(repository).repos.getBranch(repository, function (err, res) {
            if (err || !res) {
                if (err.code !== 404) {
                    errors.createError(errors.CODES.IS_BRANCH_EXISTS, {
                        user: repository.user,
                        repo: repository.repo,
                        branch: repository.branch,
                        err: err.message
                    }).log('warn');
                }
                def.resolve(false);
            }else {
                def.resolve(true);
            }
        });

        return def.promise();
    },

    /**
     * Returns list of commits of given file path
     * @param {Object} options - object with fields:
     * - type {String} type of repository privacy ('public' or 'private')
     * - user {String} name of user or organization which this repository is belong to
     * - repo {String} name of repository
     * - path {String} relative path from the root of repository
     * @returns {*}
     */
    getCommits: function (options) {
        var def = vow.defer(),
            repository = options.repository;

        this.getGit(repository).repos.getCommits(repository, function (err, res) {
            if (err || !res) {
                errors.createError(errors.CODES.GET_COMMITS, {
                    user: repository.user,
                    repo: repository.repo,
                    branch: repository.path,
                    err: err
                }).log();
            }
            def.resolve(res);
        });

        return def.promise();
    },

    /**
     * Returns name of default branch for current repository
     * @param {Object} options - object with fields:
     * - type {String} type of repository privacy ('public' or 'private')
     * - user {String} name of user or organization which this repository is belong to
     * - repo {String} name of repository
     * @returns {*}
     */
    getDefaultBranch: function (options) {
        var def = vow.defer(),
            repository = options.repository;

        this.getGit(repository).repos.get(repository, function (err, res) {
            if (err || !res) {
                errors.createError(errors.CODES.GET_DEFAULT_BRANCH, {
                    user: repository.user,
                    repo: repository.repo,
                    err: err
                }).log();
                def.resolve(null);
            }else {
                def.resolve(res['default_branch']);
            }
        });
        return def.promise();
    }
};
<commit_msg>Implement support of multiple gh tokens for work with large number of request to github<commit_after>'use strict';

var util = require('util'),

    _ = require('lodash'),
    vow = require('vow'),
    Api = require('github'),

    errors = require('./errors').GhApi,
    config = require('./config'),
    logger = require('./logger'),

    gitPublic,
    gitPrivate,
    common = {
        version: '3.0.0',
        protocol: 'https',
        timeout: 5000,
        debug: false
    },
    isInitialized = false;

function _initPrivate () {
    var ghConfig = config.get('github'),
        ghPrivate = ghConfig.private || {},
        conf = {
            host: ghPrivate.host || 'github.yandex-team.ru',
            pathPrefix: ghPrivate.pathPrefix || '/api/v3'
        };

    if (Object.keys(ghPrivate).length) {
        gitPrivate = new Api(_.extend(conf, common));
    }
}

function _initPublic () {
    var ghConfig = config.get('github'),
        ghPublic = ghConfig.public || {},
        conf = {
            host: ghPublic.host || 'api.github.com'
        };

    if (Object.keys(ghPublic).length) {
        var tokens = _.isArray(ghPublic.token) ? ghPublic.token : [ghPublic.token];

        gitPublic = [];
        tokens.forEach(function (item) {
            var gp = new Api(_.extend(conf, common));
            if (item.length) {
                gp.authenticate({ type: 'oauth', token: item });
            } else {
                errors.createError(errors.CODES.NOT_AUTHENTIFICATED).log('warn');
            }

            logger.debug(util.format('Initialize public ghAPI for token %s', item), module);
            gitPublic.push(gp);
        });
    }
}

module.exports = {
    /**
     * Initialize github api connections to public and private repositories
     * with configured credentials
     */
    init: function () {
        if (isInitialized) {
            return vow.resolve();
        }

        logger.info('Initialize github API module', module);

        _initPublic();
        _initPrivate();

        isInitialized = true;
        return vow.resolve();
    },

    /**
     * Returns gh module configured for public or private github depending on repository type
     * @param {Object} r -  repository configuration object
     * @returns {Object}
     */
    getGit: function (r) {
        return r.type === 'private' ? gitPrivate : _.sample(gitPublic);
    },

    /**
     * Returns content of repository directory or file loaded by github api
     * @param {Object} options - object with fields:
     * - type {String} type of repository privacy ('public' or 'private')
     * - user {String} name of user or organization which this repository is belong to
     * - repo {String} name of repository
     * - ref {String} name of branch
     * - path {String} relative path from the root of repository
     * @returns {*}
     */
    load: function (options) {
        var def = vow.defer(),
            repository = options.repository;
        logger.verbose(util.format('Load data from %s %s %s %s',
            repository.user, repository.repo, repository.ref, repository.path), module);

        this.getGit(repository).repos.getContent(repository, function (err, res) {
            if (err || !res) {
                logger.error(util.format('Load data from %s %s %s %s',
                    repository.user, repository.repo, repository.ref, repository.path), module);
                errors.createError(errors.CODES.LOAD, {
                    path: repository.path,
                    user: repository.user,
                    repo: repository.repo,
                    ref: repository.ref,
                    err: err
                }).log();
                def.reject({ res: null, repo: repository });
            }else {
                def.resolve({ res: res, repo: repository });
            }
        });
        return def.promise();
    },

    /**
     * Returns info for given branch
     * @param {Object} options - object with fields:
     * - type {String} type of repository privacy ('public' or 'private')
     * - user {String} name of user or organization which this repository is belong to
     * - repo {String} name of repository
     * - branch {String} name of branch
     * @returns {*}
     */
    isBranchExists: function (options) {
        var def = vow.defer(),
            repository = options.repository;

        this.getGit(repository).repos.getBranch(repository, function (err, res) {
            if (err || !res) {
                if (err.code !== 404) {
                    errors.createError(errors.CODES.IS_BRANCH_EXISTS, {
                        user: repository.user,
                        repo: repository.repo,
                        branch: repository.branch,
                        err: err.message
                    }).log('warn');
                }
                def.resolve(false);
            }else {
                def.resolve(true);
            }
        });

        return def.promise();
    },

    /**
     * Returns list of commits of given file path
     * @param {Object} options - object with fields:
     * - type {String} type of repository privacy ('public' or 'private')
     * - user {String} name of user or organization which this repository is belong to
     * - repo {String} name of repository
     * - path {String} relative path from the root of repository
     * @returns {*}
     */
    getCommits: function (options) {
        var def = vow.defer(),
            repository = options.repository;

        this.getGit(repository).repos.getCommits(repository, function (err, res) {
            if (err || !res) {
                errors.createError(errors.CODES.GET_COMMITS, {
                    user: repository.user,
                    repo: repository.repo,
                    branch: repository.path,
                    err: err
                }).log();
            }
            def.resolve(res);
        });

        return def.promise();
    },

    /**
     * Returns name of default branch for current repository
     * @param {Object} options - object with fields:
     * - type {String} type of repository privacy ('public' or 'private')
     * - user {String} name of user or organization which this repository is belong to
     * - repo {String} name of repository
     * @returns {*}
     */
    getDefaultBranch: function (options) {
        var def = vow.defer(),
            repository = options.repository;

        this.getGit(repository).repos.get(repository, function (err, res) {
            if (err || !res) {
                errors.createError(errors.CODES.GET_DEFAULT_BRANCH, {
                    user: repository.user,
                    repo: repository.repo,
                    err: err
                }).log();
                def.resolve(null);
            }else {
                def.resolve(res['default_branch']);
            }
        });
        return def.promise();
    }
};
<|endoftext|>


<commit_before>// Code ©2017 - 2019 Ecstatic Life Inc. All rights reserved.
console.log(window.location.href.indexOf('ecstaticliving.com') > -1 ? 'Welcome to EcstaticLiving.com' : 'TEST code at ', window.location.href)

// Urls
const containsUrl = str => window.location.href.indexOf(str) > -1
const endsWithUrl = str => window.location.href.endsWith(str)

// Page
const page = () => {
  if (containsUrl('/events/'))  					return 'Event'
  if (endsWithUrl('/update'))  						return 'Update'
  return null
}

// Device
const deviceOrientation = () => window.innerWidth > window.innerHeight
	? 'landscape'
	: 'portrait'

const deviceType = () => {
	//	Some large tablets exist, but for all intents and purposes, we’ll treat them as desktops.
	if (
		(deviceOrientation() === 'portrait' && window.innerWidth > 1024)
		|| (deviceOrientation() === 'landscape' && window.innerWidth > 1366)
	) {
		return 'desktop'
	}
	if (
		(deviceOrientation() === 'portrait' && window.innerWidth > 768)
		|| (deviceOrientation() === 'landscape' && window.innerWidth > 1024)
	) {
		return 'large tablet'
	}
	if (
		(deviceOrientation() === 'portrait' && window.innerWidth > 414)
		|| (deviceOrientation() === 'landscape' && window.innerWidth > 736)
	) {
		return 'tablet'
	}
	return 'mobile'
}

// Format input fields
const formatPhone = elem => {
	let intTel = window.intlTelInput(elem, {
		// Need to use cleave.js for validation instead, since IntTel removed formatting-as-you-type: https://github.com/jackocnr/intl-tel-input/issues/346
		formatOnDisplay: false,
		nationalMode: false,
		preferredCountries: ['us', 'ca'],
		separateDialCode: false,
		utilsScript: 'https://ecstaticliving.github.io/ecstaticliving.com/src/other/inttel-utils.js'
	})
	// Uses cleave.js for format-as-you-type validation
	const cleave = new Cleave(elem, {
		phone: true,
		phoneRegionCode: 'us'
	})
	elem.addEventListener('countrychange', e => cleave.phoneRegionCode = intTel.getSelectedCountryData().iso2)
}
const formatDate = elem => {
	new Cleave(elem, {
		date: true,
    delimiter: '/',
    datePattern: ['m', 'd', 'Y']
	})
}
const phoneInputs = document.querySelectorAll('input[name="phone"]')
phoneInputs.forEach(phoneInput => formatPhone(phoneInput))

// Element Collections
const querySelectorAll = (className, i) => document.querySelectorAll(className)[i || 0]
const querySelector = className => document.querySelector(className)
const getAttribute = (elem, attribute) => elem.getAttribute(attribute)
const getElementById = elem => document.getElementById(elem)
const getElementByClassName = (className, i) => document.getElementsByClassName(className)[i || 0]
const getElementsByClassName = className => document.getElementsByClassName(className)
const getElementsByTag = tag => document.getElementsByTagName(tag)

// Window Event Listener
const windowEventListener = (triggers, f) => triggers.forEach(trigger => window.addEventListener(trigger, f))

// Element Event Listeners
const onClick = (elem, f) => elem.addEventListener('click', e => f(e))
const onChange = (elem, f) => elem.addEventListener('change', e => f(e))
const onInput = (elem, f) => elem.addEventListener('input', f)
const onKeyPress = (elem, f) => elem.addEventListener('keypress', e => f(e))
const onLoad = (elem, f) => elem.addEventListener('load', f)
const onOrientationChange = (elem, f) => elem.addEventListener('orientationchange', f)
const onScroll = (elem, f) => elem.addEventListener('scroll', f)
const onSubmit = (elem, f) => elem.addEventListener('submit', f)

// Form behaviours
const formSubmit = elem => elem.submit()
const formErrorInit = elem => {
	// elem.parsley()
}
const formErrorValidation = elem => {
	// elem.parsley().validate()
}
const formReset = elem => elem.reset()

// Element Conditions
const isInput = elem => elem.type === 'input'
const isRadio = elem => elem.type === 'radio'
const isSelect = elem => elem.type === 'select-one'
const isBlank = elem => getValue(elem) === '' && getValue(elem) === ''
const isChecked = elem => elem.checked
const isVisible = elem => elem.style.display

// Element Behaviours
const animateElement = (elem, keyframes, options) => elem.animate(keyframes, options)
const clickElement = elem => elem.click()
const fadeInElement = elem => elem.style.opacity = '1.0'
const fadeOutElement = elem => elem.style.opacity = '0'
const focusElement = elem => elem.focus()
const hideElement = elem => elem.style.display = 'none'
const showElement = elem => elem.style.display = 'block'

// Values
const getValue = elem => elem.value
const emptyValue = elem => elem.value === ''
const setValue = (elem, val) => elem.value = val

// Text
const getText = elem => elem.textContent
const setText = (elem, val) => elem.textContent = val
const emptyText = elem => elem.textContent = ''
const properCase = text => text.toLowerCase().charAt(0).toUpperCase() + text.slice(1)

// Select
const emptySelect = elem => {
	const newSelect = elem.cloneNode()
	const optionLength = newSelect.options.length
	for (let i = 0; i < optionLength; i++) {
		elem.remove(i)
	}
}
const appendSelect = (elem, option) => elem.add(option)
const getIndex = elem => elem.selectedIndex

// HTML
const setHtml = (elem, val) => elem.innerHTML = val
const setCss = (elem, css) => elem.setAttribute(css.property, css.value)

// Check radio
const checkElement = elem => elem.checked = true
const unCheckElement = elem => elem.checked = false

// Combined Behaviours
const emptyHideText = elem => {
	emptyText(elem)
	hideElement(elem)
}
const emptyHideValue = elem => {
	emptyValue(elem)
	hideElement(elem)
}
const showAndScrollTo = elem => {
	showElement(elem)
	window.scrollTo(0, (window.pageYOffset || document.documentElement.scrollTop) - (document.documentElement.clientTop || 0) + 1)
}

// Regex
const isValidText = elem => /([-a-zA-Z\u0080-\uFFFF]){3,}$/.test(getValue(elem))
const isValidAlphaNum = elem => /([0-9a-zA-Z]){3,}$/.test(getValue(elem))
const isValidPhone = elem => /([- 0-9+]){7,}$/.test(getValue(elem))
const isValidEmail = elem => /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(getValue(elem))
const isValidDate = elem => /(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.](19|20)\d\d/.test(getValue(elem))<commit_msg>014 - eventOption<commit_after>// Code ©2017 - 2019 Ecstatic Life Inc. All rights reserved.
console.log(window.location.href.indexOf('ecstaticliving.com') > -1 ? 'Welcome to EcstaticLiving.com' : 'TEST code at ', window.location.href)

// Urls
const containsUrl = str => window.location.href.indexOf(str) > -1
const endsWithUrl = str => window.location.href.endsWith(str)

// Page
const page = () => {
  if (containsUrl('/events/'))  					return 'Event'
  if (endsWithUrl('/update'))  						return 'Update'
  return null
}

// Device
const deviceOrientation = () => window.innerWidth > window.innerHeight
	? 'landscape'
	: 'portrait'

const deviceType = () => {
	//	Some large tablets exist, but for all intents and purposes, we’ll treat them as desktops.
	if (
		(deviceOrientation() === 'portrait' && window.innerWidth > 1024)
		|| (deviceOrientation() === 'landscape' && window.innerWidth > 1366)
	) {
		return 'desktop'
	}
	if (
		(deviceOrientation() === 'portrait' && window.innerWidth > 768)
		|| (deviceOrientation() === 'landscape' && window.innerWidth > 1024)
	) {
		return 'large tablet'
	}
	if (
		(deviceOrientation() === 'portrait' && window.innerWidth > 414)
		|| (deviceOrientation() === 'landscape' && window.innerWidth > 736)
	) {
		return 'tablet'
	}
	return 'mobile'
}

// Format input fields
const formatPhone = elem => {
	let intTel = window.intlTelInput(elem, {
		// Need to use cleave.js for validation instead, since IntTel removed formatting-as-you-type: https://github.com/jackocnr/intl-tel-input/issues/346
		formatOnDisplay: false,
		nationalMode: false,
		preferredCountries: ['us', 'ca'],
		separateDialCode: false,
		utilsScript: 'https://ecstaticliving.github.io/ecstaticliving.com/src/other/inttel-utils.js'
	})
	// Uses cleave.js for format-as-you-type validation
	const cleave = new Cleave(elem, {
		phone: true,
		phoneRegionCode: 'us'
	})
	elem.addEventListener('countrychange', e => cleave.phoneRegionCode = intTel.getSelectedCountryData().iso2)
}
const formatDate = elem => {
	new Cleave(elem, {
		date: true,
    delimiter: '/',
    datePattern: ['m', 'd', 'Y']
	})
}
const phoneInputs = document.querySelectorAll('input[name="phone"]')
phoneInputs.forEach(phoneInput => formatPhone(phoneInput))

// Element Collections
const querySelectorAll = (className, i) => document.querySelectorAll(className)[i || 0]
const querySelector = className => document.querySelector(className)
const getAttribute = (elem, attribute) => elem.getAttribute(attribute)
const getElementById = elem => document.getElementById(elem)
const getElementByClassName = (className, i) => document.getElementsByClassName(className)[i || 0]
const getElementsByClassName = className => document.getElementsByClassName(className)
const getElementsByTag = tag => document.getElementsByTagName(tag)

// Window Event Listener
const windowEventListener = (triggers, f) => triggers.forEach(trigger => window.addEventListener(trigger, f))

// Element Event Listeners
const onClick = (elem, f) => elem.addEventListener('click', e => f(e))
const onChange = (elem, f) => elem.addEventListener('change', e => f(e))
const onInput = (elem, f) => elem.addEventListener('input', f)
const onKeyPress = (elem, f) => elem.addEventListener('keypress', e => f(e))
const onLoad = (elem, f) => elem.addEventListener('load', f)
const onOrientationChange = (elem, f) => elem.addEventListener('orientationchange', f)
const onScroll = (elem, f) => elem.addEventListener('scroll', f)
const onSubmit = (elem, f) => elem.addEventListener('submit', f)

// Form behaviours
const formSubmit = elem => elem.submit()
const formErrorInit = elem => {
	// elem.parsley()
}
const formErrorValidation = elem => {
	// elem.parsley().validate()
}
const formReset = elem => elem.reset()

// Element Conditions
const isInput = elem => elem.type === 'input'
const isRadio = elem => elem.type === 'radio'
const isSelect = elem => elem.type === 'select-one'
const isBlank = elem => getValue(elem) === '' && getValue(elem) === ''
const isChecked = elem => elem.checked
const isVisible = elem => elem.style.display

// Element Behaviours
const animateElement = (elem, keyframes, options) => elem.animate(keyframes, options)
const clickElement = elem => elem.click()
const fadeInElement = elem => elem.style.opacity = '1.0'
const fadeOutElement = elem => elem.style.opacity = '0'
const focusElement = elem => elem.focus()
const hideElement = elem => elem.style.display = 'none'
const showElement = elem => elem.style.display = 'block'

// Values
const getValue = elem => elem.value
const emptyValue = elem => elem.value === ''
const setValue = (elem, val) => elem.value = val

// Text
const getText = elem => elem.textContent
const setText = (elem, val) => elem.textContent = val
const emptyText = elem => elem.textContent = ''
const properCase = text => text.toLowerCase().charAt(0).toUpperCase() + text.slice(1)

// Select
const emptySelect = elem => {
	const newSelect = elem.cloneNode()
	console.log(newSelect)
	const optionLength = newSelect.options.length
	for (let i = 0; i < optionLength; i++) {
		elem.remove(i)
		console.log(i)
		console.log(optionLength)
	}
}
const appendSelect = (elem, option) => elem.add(option)
const getIndex = elem => elem.selectedIndex

// HTML
const setHtml = (elem, val) => elem.innerHTML = val
const setCss = (elem, css) => elem.setAttribute(css.property, css.value)

// Check radio
const checkElement = elem => elem.checked = true
const unCheckElement = elem => elem.checked = false

// Combined Behaviours
const emptyHideText = elem => {
	emptyText(elem)
	hideElement(elem)
}
const emptyHideValue = elem => {
	emptyValue(elem)
	hideElement(elem)
}
const showAndScrollTo = elem => {
	showElement(elem)
	window.scrollTo(0, (window.pageYOffset || document.documentElement.scrollTop) - (document.documentElement.clientTop || 0) + 1)
}

// Regex
const isValidText = elem => /([-a-zA-Z\u0080-\uFFFF]){3,}$/.test(getValue(elem))
const isValidAlphaNum = elem => /([0-9a-zA-Z]){3,}$/.test(getValue(elem))
const isValidPhone = elem => /([- 0-9+]){7,}$/.test(getValue(elem))
const isValidEmail = elem => /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(getValue(elem))
const isValidDate = elem => /(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.](19|20)\d\d/.test(getValue(elem))<|endoftext|>


<commit_before>'use strict'
module.exports = {
  router: {
    movie: '/test/movie/router.js',
    list: '/test/list/router.js'
  },
  controller: {
    movie: '/test/movie/controller/index.js',
    list: '/test/list/controller/index.js'
  }
}
<commit_msg>del: delete useless files<commit_after><|endoftext|>


<commit_before>'use strict'

const Https = require('https')
const Helper = require('../helper.js')

function run (msg) {
	// Make ajax request to wikipedia random url
	Https.get('https://en.wikipedia.org/w/api.php?action=query&generator=random&grnnamespace=0&prop=extracts&exchars=500&format=json', function(res) {
		res.setEncoding('utf8');
		let raw_data = '';
		res.on('data', (chunk) => { raw_data += chunk; });
		res.on('end', () => {
			try {
				const parsed_data = JSON.parse(raw_data);
				var page_id = Object.keys(parsed_data.query.pages)[0]
				var title = parsed_data.query.pages[page_id].title
				var extract = parsed_data.query.pages[page_id].extract
				msg.say({
					text: 'Tell me what you think of this random Wikipedia article:',
					attachments: [
					{
						fallback: '',
						color: '',
						pretext: '',
						title: title,
						title_link: 'https://en.wikipedia.org/wiki?curid=' + page_id,
						text: extract.replace(/<(?:.|\n)*?>/gm, ''),
						callback_id: 'nextcancel_callback',
						actions: [
							{ name: 'answer', text: 'Next', type: 'button', value: 'next' },
							{ name: 'answer', text: 'Cancel', type: 'button', value: 'cancel' },
						]
					}]
				})
					.route('wikipedia_response')
			} catch (e) {
				console.error(e.message);
			}
		});
	}).on('error', function(e) {
		console.log('Got error: ' + e.message)
	})
	// Creature-bot returns the wikipedia page url in message
}

function response (db, msg) {
	var message = Helper.returnMessageFromMsg(msg)

	if (message)
	{
		msg.say(['Thanks, I have taken note.', 'Sounds good, I am keeping track of these.', 'Thanks, keep up the good work.'])
	}
}

module.exports = {
	run: run,
	response: response
}
<commit_msg>Message respond instead of say.<commit_after>'use strict'

const Https = require('https')
const Helper = require('../helper.js')

function run (msg) {
	// Make ajax request to wikipedia random url
	Https.get('https://en.wikipedia.org/w/api.php?action=query&generator=random&grnnamespace=0&prop=extracts&exchars=500&format=json', function(res) {
		res.setEncoding('utf8');
		let raw_data = '';
		res.on('data', (chunk) => { raw_data += chunk; });
		res.on('end', () => {
			try {
				const parsed_data = JSON.parse(raw_data);
				var page_id = Object.keys(parsed_data.query.pages)[0]
				var title = parsed_data.query.pages[page_id].title
				var extract = parsed_data.query.pages[page_id].extract
				msg.say({
					text: 'Tell me what you think of this random Wikipedia article:',
					attachments: [
					{
						fallback: '',
						color: '',
						pretext: '',
						title: title,
						title_link: 'https://en.wikipedia.org/wiki?curid=' + page_id,
						text: extract.replace(/<(?:.|\n)*?>/gm, ''),
						callback_id: 'nextcancel_callback',
						actions: [
							{ name: 'answer', text: 'Next', type: 'button', value: 'next' },
							{ name: 'answer', text: 'Cancel', type: 'button', value: 'cancel' },
						]
					}]
				})
					.route('wikipedia_response')
			} catch (e) {
				console.error(e.message);
			}
		});
	}).on('error', function(e) {
		console.log('Got error: ' + e.message)
	})
	// Creature-bot returns the wikipedia page url in message
}

function response (db, msg) {
	var message = Helper.returnMessageFromMsg(msg)

	if (message)
	{
		msg.respond(msg.body.response_url,['Thanks, I have taken note.', 'Sounds good, I am keeping track of these.', 'Thanks, keep up the good work.'])
	}
}

module.exports = {
	run: run,
	response: response
}
<|endoftext|>


<commit_before>import chai, { expect } from 'chai';
import chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);

import Aggregate from '../src/aggregate.js';
import Command from '../src/command.js';
import Event from '../src/event.js';
import CommandHandler from '../src/commandHandling/aggregateCommandHandler.js';
import ValidationError from '../src/validationError.js';

describe('Command Handler', () => {
  it('should throw on a failed command validation', async () => {
    let handler = new CommandHandler(TestCommand_FailValidation);

    await expect(handler.handle({}, new TestAggregate())).to.be.rejectedWith('Failed Validation');
  });

  it('should throw on a failed aggregate validation', async () => {
    let handler = new CommandHandler_FailsValidation(TestCommand);

    await expect(handler.handle({}, new TestAggregate())).to.be.rejectedWith('Failed Aggregate Validation');
  });

  it('should apply events to aggregate', async () => {
    let handler = new CommandHandler(TestCommand);

    let aggregate = new TestAggregate();

    await handler.handle(new TestCommand({ message: 'Successful test' }), aggregate);

    expect(aggregate.lastMessage).to.equal('Successful test');

  });
});

class TestCommandHandler extends CommandHandler {
  execute = async (command, aggregate) => [new TestEvent({ message: command.message })];
}

class TestCommand_FailValidation extends Command {
  validate = async () => {
    throw new ValidationError({ command: this, message: 'Failed Validation' });
  }
}

class TestCommand extends Command {
  constructor(data = {}) {
    super(data);
    this.message = data.message;
  }

  validate = async () => true
}

class TestEvent extends Event {
  type = 'TestEvent'

  constructor(data = {}) {
    super(data);
    this.message = data.message;
  }

  update(aggregate) {
    aggregate.lastMessage = this.message;
  }
}

class TestAggregate extends Aggregate {
  constructor({ id, events } = {}) {
    super({ id, events });
  }
}

class CommandHandler_FailsValidation extends CommandHandler {
  validate = (command, aggregate) => {
    throw new ValidationError({ aggregate, command, message: 'Failed Aggregate Validation' });
  }
}
<commit_msg>Fix the broken unit test arising from redundant assignment in last checkin.<commit_after>import chai, { expect } from 'chai';
import chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);

import Aggregate from '../src/aggregate.js';
import Command from '../src/command.js';
import Event from '../src/event.js';
import CommandHandler from '../src/commandHandling/aggregateCommandHandler.js';
import ValidationError from '../src/validationError.js';

describe('Command Handler', () => {
  it('should throw on a failed command validation', async () => {
    let handler = new CommandHandler(TestCommand_FailValidation);

    await expect(handler.handle({}, new TestAggregate())).to.be.rejectedWith('Failed Validation');
  });

  it('should throw on a failed aggregate validation', async () => {
    let handler = new CommandHandler_FailsValidation(TestCommand);

    await expect(handler.handle({}, new TestAggregate())).to.be.rejectedWith('Failed Aggregate Validation');
  });

  it('should apply events to aggregate', async () => {
    let handler = new TestCommandHandler(TestCommand);

    let aggregate = new TestAggregate();

    await handler.handle(new TestCommand({ message: 'Successful test' }), aggregate);

    expect(aggregate.lastMessage).to.equal('Successful test');

  });
});

class TestCommandHandler extends CommandHandler {
  execute = async (command, aggregate) => [new TestEvent({ message: command.message })];
}

class TestCommand_FailValidation extends Command {
  validate = async () => {
    throw new ValidationError({ command: this, message: 'Failed Validation' });
  }
}

class TestCommand extends Command {
  constructor(data = {}) {
    super(data);
    this.message = data.message;
  }

  validate = async () => true
}

class TestEvent extends Event {
  type = 'TestEvent'

  constructor(data = {}) {
    super(data);
    this.message = data.message;
  }

  update(aggregate) {
    aggregate.lastMessage = this.message;
  }
}

class TestAggregate extends Aggregate {
  constructor({ id, events } = {}) {
    super({ id, events });
  }
}

class CommandHandler_FailsValidation extends CommandHandler {
  validate = (command, aggregate) => {
    throw new ValidationError({ aggregate, command, message: 'Failed Aggregate Validation' });
  }
}
<|endoftext|>


<commit_before>'use strict';

var bcrypt = require('bcrypt');

module.exports = function(sequelize, DataTypes) {
    var User = sequelize.define("User", {
        username: DataTypes.STRING,
        email: {
            type: DataTypes.STRING,
            allowNull: false,
            validate: {
                isEmail: true
            }
        },
        password_digest: {
            type: DataTypes.STRING,
            validate: {
                notEmpty: true
            }
        },
        password: {
            type: DataTypes.VIRTUAL,
            allowNull: false,
            validate: {
                notEmpty: true
            }
        },
        password_confirmation: {
            type: DataTypes.VIRTUAL
        },
        school: DataTypes.STRING,
        university: DataTypes.STRING,
        sex: {  // false -> male, true -> female
            type: DataTypes.BOOLEAN,
            allowNull: false,
            defaultValue: false
        },
        isChatting: {
            type: DataTypes.BOOLEAN,
            allowNull: false,
            defaultValue: false
        }
    }, {
        indexes: [
            {unique: true, fields: ['email']}
        ],
        instanceMethods: {
            authenticate: function(value) {
                if (bcrypt.compareSync(value, this.password_digest))
                    return this;
                else
                    return false;
            }
        }
    });

    const hasSecurePassword = (user, options, callback) => {
        if (user.password != user.password_confirmation) {
            throw new sequelize.ValidationError("Password confirmation: Password confirmation doesn't match Password");
        }
        if (user.password.length < 6) {
            throw new sequelize.ValidationError("Password should be at least 6 characters");
        }
        bcrypt.hash(user.get('password'), 10, function(err, hash) {
            if (err) return callback(err);
            user.set('password_digest', hash);
            return callback(null, options);
        });
    };

    User.beforeCreate(function(user, options, callback) {
        user.email = user.email.toLowerCase();
        if (user.password)
            hasSecurePassword(user, options, callback);
        else
            return callback(null, options);
    });

    User.beforeUpdate(function(user, options, callback) {
        user.email = user.email.toLowerCase();
        if (user.password)
            hasSecurePassword(user, options, callback);
        else
            return callback(null, options);
    });

    return User;
};
<commit_msg>Add interestedIn field to User<commit_after>'use strict';

var bcrypt = require('bcrypt');

module.exports = function(sequelize, DataTypes) {
    var User = sequelize.define("User", {
        username: DataTypes.STRING,
        email: {
            type: DataTypes.STRING,
            allowNull: false,
            validate: {
                isEmail: true
            }
        },
        password_digest: {
            type: DataTypes.STRING,
            validate: {
                notEmpty: true
            }
        },
        password: {
            type: DataTypes.VIRTUAL,
            allowNull: false,
            validate: {
                notEmpty: true
            }
        },
        password_confirmation: {
            type: DataTypes.VIRTUAL
        },
        school: DataTypes.STRING,
        university: DataTypes.STRING,
        sex: {  // false -> male, true -> female
            type: DataTypes.BOOLEAN,
            allowNull: false,
            defaultValue: false
        },
        interestedIn: DataTypes.BOOLEAN, // null -> both, false -> male, true -> female
        isChatting: {
            type: DataTypes.BOOLEAN,
            allowNull: false,
            defaultValue: false
        }
    }, {
        indexes: [
            {unique: true, fields: ['email']}
        ],
        instanceMethods: {
            authenticate: function(value) {
                if (bcrypt.compareSync(value, this.password_digest))
                    return this;
                else
                    return false;
            }
        }
    });

    const hasSecurePassword = (user, options, callback) => {
        if (user.password != user.password_confirmation) {
            throw new sequelize.ValidationError("Password confirmation: Password confirmation doesn't match Password");
        }
        if (user.password.length < 6) {
            throw new sequelize.ValidationError("Password should be at least 6 characters");
        }
        bcrypt.hash(user.get('password'), 10, function(err, hash) {
            if (err) return callback(err);
            user.set('password_digest', hash);
            return callback(null, options);
        });
    };

    User.beforeCreate(function(user, options, callback) {
        user.email = user.email.toLowerCase();
        if (user.password)
            hasSecurePassword(user, options, callback);
        else
            return callback(null, options);
    });

    User.beforeUpdate(function(user, options, callback) {
        user.email = user.email.toLowerCase();
        if (user.password)
            hasSecurePassword(user, options, callback);
        else
            return callback(null, options);
    });

    return User;
};
<|endoftext|>


<commit_before>/* jshint -W097 */// jshint strict:false
/*jslint node: true */
"use strict";

var adapter = require(__dirname + '/../../lib/adapter.js')({

    name:           'history',

    objectChange: function (id, obj) {
        if (obj && obj.common && obj.common.history && obj.common.history.enabled) {
            history[id] = obj.common.history;
            adapter.log.info('enabled logging of ' + id);
        } else {
            if (history[id]) {
                adapter.log.info('disabled logging of ' + id);
                delete history[id];
            }
        }
    },

    stateChange: function (id, state) {
        pushHistory(id, state);
    },

    unload: function (callback) {
        callback();
    },

    ready: function () {
        main();
    }

});

var history = {};

function main() {

    adapter.objects.getObjectView('history', 'state', {}, function (err, doc) {
        if (doc.rows) {
            for (var i = 0, l = doc.rows.length; i < l; i++) {
                if (doc.rows[i].value) {
                    adapter.log.info('enabled logging of ' + doc.rows[i].id);
                    history[doc.rows[i].id] = doc.rows[i].value;
                }
            }
        }
    });

    adapter.subscribeForeignStates('*');
    adapter.subscribeForeignObjects('*');
}

function pushHistory(id, state) {

    // Push into redis
    if (history[id] && history[id].enabled) {
        if (history[id].changesOnly && (state.ts !== state.lc)) return;

        setTimeout(function (_id, _state) {
            adapter.states.pushFifo(_id, _state);

            adapter.states.trimFifo(_id, history[id].minLength || adapter.config.minLength, history[id].maxLength || adapter.config.maxLength, function (err, obj) {
                if (!err && obj.length) {
                    adapter.log.info('moving ' + obj.length + ' entries to couchdb');
                    appendCouch(_id, obj);
                }
            });

        }, 1000, id, state);
    }

}

function appendCouch(id, states) {

    var day = ts2day(states[states.length - 1].ts);
    var cid = 'history.' + id + '.' + day;

    adapter.getForeignObject(cid, function (err, res) {
        var obj;
        if (err || !res) {
            obj = {
                type: 'history',
                common: {
                    source: id,
                    day:    day,
                    data:   []
                },
                native: {}
            };
        } else {
            obj = res;
        }

        for (var i = states.length - 1; i >= 0; i--) {
            if (ts2day(states[i].ts) === day) {
                obj.common.data.unshift(states[i]);
            } else {
                break;
            }
        }

        adapter.setForeignObject(cid, obj, function () {
            adapter.log.info('moved ' + states.length + ' history datapoints from Redis history.' + id + ' to CouchDB ' + cid);
        });

        if (i >= 0) {
            adapter.log.info((i + 1) + ' remaining datapoints of history.' + id);
            appendCouch(id, states.slice(0, (i + 1)));
        }

    });

}

function ts2day(ts) {
    var dateObj = new Date(ts * 1000);
    return dateObj.getFullYear() +
        ("0" + (dateObj.getMonth() + 1).toString(10)).slice(-2) +
        ("0" + (dateObj.getDate()).toString(10)).slice(-2);
}
<commit_msg>(Blufox) check small error<commit_after>/* jshint -W097 */// jshint strict:false
/*jslint node: true */
"use strict";

var adapter = require(__dirname + '/../../lib/adapter.js')({

    name: 'history',

    objectChange: function (id, obj) {
        if (obj && obj.common && obj.common.history && obj.common.history.enabled) {
            history[id] = obj.common.history;
            adapter.log.info('enabled logging of ' + id);
        } else {
            if (history[id]) {
                adapter.log.info('disabled logging of ' + id);
                delete history[id];
            }
        }
    },

    stateChange: function (id, state) {
        pushHistory(id, state);
    },

    unload: function (callback) {
        callback();
    },

    ready: function () {
        main();
    }

});

var history = {};

function main() {

    adapter.objects.getObjectView('history', 'state', {}, function (err, doc) {
        if (doc && doc.rows) {
            for (var i = 0, l = doc.rows.length; i < l; i++) {
                if (doc.rows[i].value) {
                    adapter.log.info('enabled logging of ' + doc.rows[i].id);
                    history[doc.rows[i].id] = doc.rows[i].value;
                }
            }
        }
    });

    adapter.subscribeForeignStates('*');
    adapter.subscribeForeignObjects('*');
}

function pushHistory(id, state) {

    // Push into redis
    if (history[id] && history[id].enabled) {
        if (history[id].changesOnly && (state.ts !== state.lc)) return;

        setTimeout(function (_id, _state) {
            adapter.states.pushFifo(_id, _state);

            adapter.states.trimFifo(_id, history[id].minLength || adapter.config.minLength, history[id].maxLength || adapter.config.maxLength, function (err, obj) {
                if (!err && obj.length) {
                    adapter.log.info('moving ' + obj.length + ' entries to couchdb');
                    appendCouch(_id, obj);
                }
            });

        }, 1000, id, state);
    }

}

function appendCouch(id, states) {

    var day = ts2day(states[states.length - 1].ts);
    var cid = 'history.' + id + '.' + day;

    adapter.getForeignObject(cid, function (err, res) {
        var obj;
        if (err || !res) {
            obj = {
                type: 'history',
                common: {
                    source: id,
                    day:    day,
                    data:   []
                },
                native: {}
            };
        } else {
            obj = res;
        }

        for (var i = states.length - 1; i >= 0; i--) {
            if (ts2day(states[i].ts) === day) {
                obj.common.data.unshift(states[i]);
            } else {
                break;
            }
        }

        adapter.setForeignObject(cid, obj, function () {
            adapter.log.info('moved ' + states.length + ' history datapoints from Redis history.' + id + ' to CouchDB ' + cid);
        });

        if (i >= 0) {
            adapter.log.info((i + 1) + ' remaining datapoints of history.' + id);
            appendCouch(id, states.slice(0, (i + 1)));
        }

    });

}

function ts2day(ts) {
    var dateObj = new Date(ts * 1000);
    return dateObj.getFullYear() +
        ("0" + (dateObj.getMonth() + 1).toString(10)).slice(-2) +
        ("0" + (dateObj.getDate()).toString(10)).slice(-2);
}
<|endoftext|>


<commit_before>
import { expect } from 'chai';

const RG = require('../../../client/src/battles');
const FactoryGame = require('../../../client/src/factory.game');
const OW = require('../../../client/src/overworld.map');

describe('Factory.Game', () => {
    it('can generate worldConf based on territory map', () => {
        const gameFact = new FactoryGame();

        const pRace = 'goblin';
        const [playerX, playerY] = [0, 0];
        const owConf = FactoryGame.getOwConf(1.0);
        const overworld = OW.createOverWorld(owConf);
        overworld.terrMap = gameFact.createTerritoryMap(overworld, pRace,
            playerX, playerY);

        const worldAndConf = RG.OverWorld.createOverWorldLevel(
          overworld, owConf);
        const [worldLevel, worldConf] = worldAndConf;
        expect(worldLevel).to.not.be.empty;

        gameFact.mapZonesToTerritoryMap(overworld.terrMap, worldConf);

        const citiesConf = worldConf.area[0].city;

        const coordMap = new RG.OverWorld.CoordMap();
        coordMap.setXYMap(10, 10);

        const terrMap = overworld.terrMap;
        const terrMapXY = terrMap.getMap();
        // const owMap = overworld.getMap();

        citiesConf.forEach(cityConf => {
            const {owX, owY} = cityConf;
            expect(owX).to.be.at.least(0);
            expect(owY).to.be.at.least(0);

            const char = terrMapXY[owX][owY];
            if (char !== '.' && char !== '#') {
                const {constraint} = cityConf;
                const {actor} = constraint;
                expect(actor).to.not.be.empty;

                const name = terrMap.getName(char);
                if (Array.isArray(actor)) {
                    const cc0 = actor[0];
                    expect(cc0.value).to.contains(name);
                    // expect(actor).to.have.deep.property('[0].value', name);
                }
                else if (Array.isArray(actor.value)) {
                    expect(actor.value).to.contains(name);
                }
                else {
                    expect(actor.value).to.equal(name);
                }
            }
        });

        // console.log(overworld.mapToString());
        // console.log(terrMap.mapToString());

    });
});
<commit_msg>Fixed failing test.<commit_after>
import { expect } from 'chai';

const RG = require('../../../client/src/battles');
const FactoryGame = require('../../../client/src/factory.game');
const OW = require('../../../client/src/overworld.map');

describe('Factory.Game', () => {
    it('can generate worldConf based on territory map', () => {
        const gameFact = new FactoryGame();

        const pRace = 'goblin';
        const [playerX, playerY] = [0, 0];
        const owConf = FactoryGame.getOwConf(1.0);
        const overworld = OW.createOverWorld(owConf);
        overworld.terrMap = gameFact.createTerritoryMap(overworld, pRace,
            playerX, playerY);

        const worldAndConf = RG.OverWorld.createOverWorldLevel(
          overworld, owConf);
        const [worldLevel, worldConf] = worldAndConf;
        expect(worldLevel).to.not.be.empty;

        gameFact.mapZonesToTerritoryMap(overworld.terrMap, worldConf);

        const citiesConf = worldConf.area[0].city;

        const coordMap = new RG.OverWorld.CoordMap();
        coordMap.setXYMap(10, 10);

        const terrMap = overworld.terrMap;
        const terrMapXY = terrMap.getMap();
        // const owMap = overworld.getMap();

        citiesConf.forEach(cityConf => {
            const {owX, owY} = cityConf;
            expect(owX).to.be.at.least(0);
            expect(owY).to.be.at.least(0);

            const char = terrMapXY[owX][owY];
            if (char !== '.' && char !== '#') {
                const {constraint} = cityConf;
                const {actor} = constraint;
                expect(actor).to.not.be.empty;

                const name = terrMap.getName(char);
                if (Array.isArray(actor)) {
                    const cc0 = actor[0];
                    expect(cc0.value).to.contains(name);
                    // expect(actor).to.have.deep.property('[0].value', name);
                }
                else if (Array.isArray(actor.value)) {
                    if (name !== 'winterbeing') {
                        expect(actor.value).to.contains(name);
                    }
                    else {
                        expect(actor.value).to.contains('WinterBeingBase');
                    }
                }
                else {
                    expect(actor.value).to.equal(name);
                }
            }
        });

        // console.log(overworld.mapToString());
        // console.log(terrMap.mapToString());

    });
});
<|endoftext|>


<commit_before>import Ember from 'ember';
import LinearScale from '../utils/scales/d3-linear-scale';

const { Component, observer, on } = Ember;

export default Component.extend({
  showDots: true,

  init() {
    this._super.apply(this, arguments);
    this.set('xMax', 100);
    this.set('yMax', 100);
    this.set('data', [{x: 0, y: 10}, {x: 10, y: 20}, {x: 20, y: 35}, {x: 30, y: 45}, {x: 50, y: 65}, {x: 70, y: 95}, {x: 80, y: 97}, {x: 90, y: 100}]);
    this.set('xScale', LinearScale.create({domain: [0, 100], range: [0, 450]}));
    this.set('yScale', LinearScale.create({domain: [100, 0], range: [0, 450]}));
  },

  xMaxChanged: observer('xMax', function() {
    this.set('xScale.domain', [0, this.get('xMax')]);
  }),

  yMaxChanged: observer('yMax', function() {
    this.set('yScale.domain', [this.get('yMax'), 0]);
  })
});
<commit_msg>Cleanup<commit_after>import Ember from 'ember';
import LinearScale from '../utils/scales/d3-linear-scale';

const { Component, observer } = Ember;

export default Component.extend({
  showDots: true,

  init() {
    this._super.apply(this, arguments);
    this.set('xMax', 100);
    this.set('yMax', 100);
    this.set('data', [{x: 0, y: 10}, {x: 10, y: 20}, {x: 20, y: 35}, {x: 30, y: 45}, {x: 50, y: 65}, {x: 70, y: 95}, {x: 80, y: 97}, {x: 90, y: 100}]);
    this.set('xScale', LinearScale.create({domain: [0, 100], range: [0, 450]}));
    this.set('yScale', LinearScale.create({domain: [100, 0], range: [0, 450]}));
  },

  xMaxChanged: observer('xMax', function() {
    this.set('xScale.domain', [0, this.get('xMax')]);
  }),

  yMaxChanged: observer('yMax', function() {
    this.set('yScale.domain', [this.get('yMax'), 0]);
  })
});
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Dickson Tam
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 */

(function() {

  function Houdini(arr) {
    this.reversed = false;
    this.arr = arr;
  }

  Houdini.prototype.reverse = function() {
    this.reversed = !this.reversed;
    return this;
  }

  Houdini.prototype.offset = function(index) {

    var getRealIndex = (function()  {
      return (this.reversed)? (this.arr.length - 1 - index) : index;
    }).bind(this);

    var get = (function() {
      try {
        return this.arr[getRealIndex()];
      } catch(err) {
        throw new Error('houdini-array: get element at houdini(array)[' + index + '] => array[' + index + '] failed. ' + err);
      }
    }).bind(this);

    var set = (function(value) {
      try {
        this.arr[getRealIndex()] = value;
      } catch(err) {
        throw new Error('houdini-array: set element at houdini index' + index + ' / real index ' + index + ' failed. ' + err);
      }
    }).bind(this);

    var obj = {
      get: get,
      set: set,
      getIndex: getRealIndex
    };

    Object.defineProperty(obj, 'value', {
      get: get,
      set: set,
      enumerable: true
    });

    return obj;

  }

  Object.defineProperty(Houdini.prototype, 'length', { get: function () {
      return this.arr.length;
    },
    enumerable: true
  });

  function houdini(arr) {
    return new Houdini(arr);
  }

  if (typeof module !== 'undefined' && module && module.exports) { // Node.js & CommonJS
    module.exports = houdini;
  } else if (typeof define === 'function' && define.amd) {
    define('houdini-array', [], function() {
      return houdini;
    });
  } else { // Browser
    window.houdini = houdini;
  }

})();
<commit_msg>Added pop, shift, push, and unshift methods.<commit_after>/*
 * Copyright (c) 2015 Dickson Tam
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 */

(function() {

  function Houdini(arr) {
    this.reversed = false;
    this.arr = arr;
  }

  Houdini.prototype.reverse = function() {
    this.reversed = !this.reversed;
    return this;
  }

  Houdini.prototype.pop = function() {
    return this.reversed? this.arr.shift() : this.arr.pop();
  }

  Houdini.prototype.shift = function() {
    return this.reversed? this.arr.pop() : this.arr.shift();
  }

  Houdini.prototype.push = function() {
    var args = Array.prototype.slice.call(arguments, 1);

    if (this.reversed) {
      return Array.prototype.unshift.apply(this.arr, args);
    } else {
      return Array.prototype.push.apply(this.arr, args);
    }
  }

  Houdini.prototype.unshift = function() {
    var args = Array.prototype.slice.call(arguments, 1);

    if (this.reversed) {
      return Array.prototype.push.apply(this.arr, args);
    } else {
      return Array.prototype.shift.apply(this.arr, args);
    }
  }

  Houdini.prototype.offset = function(index) {

    var getRealIndex = (function()  {
      return (this.reversed)? (this.arr.length - 1 - index) : index;
    }).bind(this);

    var get = (function() {
      try {
        return this.arr[getRealIndex()];
      } catch(err) {
        throw new Error('houdini-array: get element at houdini(array)[' + index + '] => array[' + index + '] failed. ' + err);
      }
    }).bind(this);

    var set = (function(value) {
      try {
        this.arr[getRealIndex()] = value;
      } catch(err) {
        throw new Error('houdini-array: set element at houdini index' + index + ' / real index ' + index + ' failed. ' + err);
      }
    }).bind(this);

    var obj = {
      get: get,
      set: set,
      getIndex: getRealIndex
    };

    Object.defineProperty(obj, 'value', {
      get: get,
      set: set,
      enumerable: true
    });

    return obj;

  }

  Object.defineProperty(Houdini.prototype, 'length', { get: function () {
      return this.arr.length;
    },
    enumerable: true
  });

  function houdini(arr) {
    return new Houdini(arr);
  }

  if (typeof module !== 'undefined' && module && module.exports) { // Node.js & CommonJS
    module.exports = houdini;
  } else if (typeof define === 'function' && define.amd) {
    define('houdini-array', [], function() {
      return houdini;
    });
  } else { // Browser
    window.houdini = houdini;
  }

})();
<|endoftext|>


<commit_before>/*jshint multistr: true */

'use strict'

var $ = require('jquery'),
    history = require('../../../libs/history.js/scripts/bundled/html5/jquery.history'),
    tab = require('../../../js/libs/tab'),
    dropdown = require('../../../js/libs/dropdown'),
    PulsarUIComponent = require('../../../js/PulsarUIComponent');

    $.fx.off = !$.fx.off;

describe('Pulsar UI Component', function() {

    beforeEach(function() {
        this.$html = $('');
        this.$body = $('').appendTo(this.$html);
        this.$code = $(`

                        foo
                        bar

                                <button data-toggle="dropdown" class="btn dropdown__toggle row-actions">
                                    Actions
                                </button>

action

            foo
            foo

            Expires in 6 hours\
`).appendTo(this.$html);

        this.$tabLink = this.$html.find('a[href="#tab"]');
        this.$pushStateTabLink = this.$html.find('a[href="#tab-foo"]');
        this.$isDisabled = this.$html.find('a[disabled]');
        this.$basicTable = this.$html.find('.qa-table');
        this.$datagridTable = this.$html.find('.qa-datagrid');
        this.$datatableTable = this.$html.find('.qa-datatable');
        this.$datatableWithCustomMessage = this.$html.find('.qa-datatable-empty-message');
        this.$datatableDisableSelection = this.$html.find('.qa-datatable-no-selection');
        this.$tableDupe = this.$html.find('.qa-table-dupe');
        this.$countdownOne = this.$html.find('.qa-countdown-one');
        this.$datatableActions = this.$html.find('.qa-datatable-actions');

        this.$rowActions = this.$html.find('.row-actions');

        this.history = {
            pushState: sinon.stub()
        };

        this.pulsarUIComponent = new PulsarUIComponent(this.$html, this.history);

    });

    describe('A countdown element', function() {

        beforeEach(function() {
            sinon.spy($.fn, 'countdown');
            this.pulsarUIComponent.init();
        });

        it('should call the countdown plugin', function() {
            expect($.fn.countdown).to.have.been.called;
        });
    });

    describe('disabled links', function() {

        beforeEach(function() {
            this.pulsarUIComponent.init();
        });

        it('should preventDefault', function() {
            var clickEvent = $.Event('click');
            this.$isDisabled.trigger(clickEvent);
            expect(clickEvent.isDefaultPrevented()).to.be.true;
        });

    });

    describe('initialising tables', function() {

        beforeEach(function() {
            this.pulsarUIComponent.init();
        });

        it('should wrap basic tables with the container', function() {
            expect(this.$basicTable.parent().hasClass('table-container')).to.be.true;
        });

        it('should wrap datagrid tables with the container', function() {
            expect(this.$datagridTable.parent().hasClass('table-container')).to.be.true;
        });

        it('should NOT wrap datatable tables with the container', function() {
            expect(this.$datatableTable.parent().hasClass('table-container')).to.be.false;
        });

        it('should NOT wrap tables which already have the container', function() {
            expect(this.$tableDupe.parent().parent().hasClass('table-container')).to.be.false;
        });

        it('should show the default empty table message', function() {
            expect(this.$datatableTable.find('.dataTables_empty').text()).to.equal('There are currently no items to display');
        });

        it('should allow the empty table message to be overridden', function() {
            expect(this.$datatableWithCustomMessage.find('.dataTables_empty').text()).to.equal('foo');
        });

        it('should wrap the table with the disable class when the data-select attribute is false', function() {
            expect(this.$datatableDisableSelection.parent().hasClass('dt-disable-selection')).to.be.true;
        });
    });

    describe('Table row-actions', function() {

        beforeEach(function() {
            sinon.spy(this.pulsarUIComponent, 'closeRowActions');
            this.pulsarUIComponent.init();
        });

        it('should be opened when clicked', function() {
            this.$rowActions.click();
            setTimeout(function(done){
                expect(this.$rowActions.parent().hasClass('open')).to.be.true;
                done();
            }, 1000);
        });

        it('should be closed when clicked again', function() {
            this.$rowActions.click();
            this.$rowActions.click();
            setTimeout(function(done){
                expect(this.$rowActions.parent().hasClass('open')).to.be.false;
                done();
            }, 1000);
        });

        it('should call the closeRowActions method when window resized', function() {
            this.$rowActions.click();
            this.$html.trigger('resize');
            setTimeout(function(done){
                expect(this.closeRowActions).to.have.been.called;
                done();
            }, 1000);
        });

        it('should call the closeRowActions method when table scrolled', function() {
            this.$rowActions.click();
            this.$datatableActions.trigger('scroll');
            setTimeout(function(){
                expect(this.closeRowActions).to.have.been.called;
            }, 1000);
        });

        it('should be closed when the window resized', function() {
            this.$rowActions.click();
            this.$html.trigger('resize');
            expect(this.$rowActions.parent().hasClass('open')).to.be.false;
        });

        it('should be closed when the table is scrolled resized', function() {
            this.$rowActions.click();
            this.$datatableActions.trigger('scroll');
            expect(this.$rowActions.parent().hasClass('open')).to.be.false;
        });

    });

    describe('Clicking a tab toggle with the data-href attribute', function() {

        beforeEach(function() {
            this.pulsarUIComponent.init();
        });

        it('should call the history plugin', function() {
            this.$pushStateTabLink.click();
            expect(this.history.pushState).to.have.been.calledOnce;
        });

        it('should push the correct state object onto the history stack', function () {
            this.$pushStateTabLink.click();
            expect(this.history.pushState).to.have.been.calledWith({state: 1});
        });

        it('should push the correct href onto the history stack', function () {
            this.$pushStateTabLink.click();
            expect(this.history.pushState).to.have.been.calledWith(sinon.match.any, '?tab=foo', '?tab=foo');
        });
    });

    describe('clicking a tab toggle', function() {

        beforeEach(function() {

            this.recalc = sinon.stub();

            $.fn.dataTable = {
                tables: sinon.stub()
            };

            $.fn.DataTable = sinon.stub().returns({
                columns: {
                    adjust: sinon.stub().returns({
                        responsive: {
                            recalc: this.recalc
                        }
                    })
                }
            });

            this.pulsarUIComponent.init();
            this.$tabLink.click();
            this.$tabLink.trigger('shown.bs.tab');

        });

        afterEach(function () {
            delete $.fn.dataTable;
            delete $.fn.DataTable;
        });

        it('should recalculate the table', function() {
            expect(this.recalc).to.have.been.calledOnce;
        });

    });
});
<commit_msg>Attempts to fix UI component tests with a fake DOM<commit_after>/*jshint multistr: true */

'use strict'

var $ = require('jquery'),
    history = require('../../../libs/history.js/scripts/bundled/html5/jquery.history'),
    tab = require('../../../js/libs/tab'),
    dropdown = require('../../../js/libs/dropdown'),
    PulsarUIComponent = require('../../../js/PulsarUIComponent');

    $.fx.off = !$.fx.off;

describe('Pulsar UI Component', function() {

    beforeEach(function() {
        this.$html = $('

');
        this.$body = $('

').appendTo(this.$html);
        this.$code = $(`

                        foo
                        bar

                                <button data-toggle="dropdown" class="btn dropdown__toggle row-actions">
                                    Actions
                                </button>

action

            foo
            foo

            Expires in 6 hours\
`).appendTo(this.$html);

        this.$tabLink = this.$html.find('a[href="#tab"]');
        this.$pushStateTabLink = this.$html.find('a[href="#tab-foo"]');
        this.$isDisabled = this.$html.find('a[disabled]');
        this.$basicTable = this.$html.find('.qa-table');
        this.$datagridTable = this.$html.find('.qa-datagrid');
        this.$datatableTable = this.$html.find('.qa-datatable');
        this.$datatableWithCustomMessage = this.$html.find('.qa-datatable-empty-message');
        this.$datatableDisableSelection = this.$html.find('.qa-datatable-no-selection');
        this.$tableDupe = this.$html.find('.qa-table-dupe');
        this.$countdownOne = this.$html.find('.qa-countdown-one');
        this.$datatableActions = this.$html.find('.qa-datatable-actions');

        this.$rowActions = this.$html.find('.row-actions');

        this.history = {
            pushState: sinon.stub()
        };

        this.pulsarUIComponent = new PulsarUIComponent(this.$html, this.history);

    });

    describe('A countdown element', function() {

        beforeEach(function() {
            sinon.spy($.fn, 'countdown');
            this.pulsarUIComponent.init();
        });

        it('should call the countdown plugin', function() {
            expect($.fn.countdown).to.have.been.called;
        });
    });

    describe('disabled links', function() {

        beforeEach(function() {
            this.pulsarUIComponent.init();
        });

        it('should preventDefault', function() {
            var clickEvent = $.Event('click');
            this.$isDisabled.trigger(clickEvent);
            expect(clickEvent.isDefaultPrevented()).to.be.true;
        });

    });

    describe('initialising tables', function() {

        beforeEach(function() {
            this.pulsarUIComponent.init();
        });

        it('should wrap basic tables with the container', function() {
            expect(this.$basicTable.parent().hasClass('table-container')).to.be.true;
        });

        it('should wrap datagrid tables with the container', function() {
            expect(this.$datagridTable.parent().hasClass('table-container')).to.be.true;
        });

        it('should NOT wrap datatable tables with the container', function() {
            expect(this.$datatableTable.parent().hasClass('table-container')).to.be.false;
        });

        it('should NOT wrap tables which already have the container', function() {
            expect(this.$tableDupe.parent().parent().hasClass('table-container')).to.be.false;
        });

        it('should show the default empty table message', function() {
            expect(this.$datatableTable.find('.dataTables_empty').text()).to.equal('There are currently no items to display');
        });

        it('should allow the empty table message to be overridden', function() {
            expect(this.$datatableWithCustomMessage.find('.dataTables_empty').text()).to.equal('foo');
        });

        it('should wrap the table with the disable class when the data-select attribute is false', function() {
            expect(this.$datatableDisableSelection.parent().hasClass('dt-disable-selection')).to.be.true;
        });
    });

    describe('Table row-actions', function() {

        beforeEach(function() {
            sinon.spy(this.pulsarUIComponent, 'closeRowActions');
            this.pulsarUIComponent.init();
        });

        it('should be opened when clicked', function() {
            this.$rowActions.click();
            setTimeout(function(done){
                expect(this.$rowActions.parent().hasClass('open')).to.be.true;
                done();
            }, 1000);
        });

        it('should be closed when clicked again', function() {
            this.$rowActions.click();
            this.$rowActions.click();
            setTimeout(function(done){
                expect(this.$rowActions.parent().hasClass('open')).to.be.false;
                done();
            }, 1000);
        });

        it('should call the closeRowActions method when window resized', function() {
            this.$rowActions.click();
            this.$html.trigger('resize');
            setTimeout(function(done){
                expect(this.closeRowActions).to.have.been.called;
                done();
            }, 1000);
        });

        it('should call the closeRowActions method when table scrolled', function() {
            this.$rowActions.click();
            this.$datatableActions.trigger('scroll');
            setTimeout(function(){
                expect(this.closeRowActions).to.have.been.called;
            }, 1000);
        });

        it('should be closed when the window resized', function() {
            this.$rowActions.click();
            this.$html.trigger('resize');
            expect(this.$rowActions.parent().hasClass('open')).to.be.false;
        });

        it('should be closed when the table is scrolled resized', function() {
            this.$rowActions.click();
            this.$datatableActions.trigger('scroll');
            expect(this.$rowActions.parent().hasClass('open')).to.be.false;
        });

    });

    describe('Clicking a tab toggle with the data-href attribute', function() {

        beforeEach(function() {
            this.pulsarUIComponent.init();
        });

        it('should call the history plugin', function() {
            this.$pushStateTabLink.click();
            expect(this.history.pushState).to.have.been.calledOnce;
        });

        it('should push the correct state object onto the history stack', function () {
            this.$pushStateTabLink.click();
            expect(this.history.pushState).to.have.been.calledWith({state: 1});
        });

        it('should push the correct href onto the history stack', function () {
            this.$pushStateTabLink.click();
            expect(this.history.pushState).to.have.been.calledWith(sinon.match.any, '?tab=foo', '?tab=foo');
        });
    });

    describe('clicking a tab toggle', function() {

        beforeEach(function() {

            this.recalc = sinon.stub();

            $.fn.dataTable = {
                tables: sinon.stub()
            };

            $.fn.DataTable = sinon.stub().returns({
                columns: {
                    adjust: sinon.stub().returns({
                        responsive: {
                            recalc: this.recalc
                        }
                    })
                }
            });

            this.pulsarUIComponent.init();
            this.$tabLink.click();
            this.$tabLink.trigger('shown.bs.tab');

        });

        afterEach(function () {
            delete $.fn.dataTable;
            delete $.fn.DataTable;
        });

        it('should recalculate the table', function() {
            expect(this.recalc).to.have.been.calledOnce;
        });

    });
});
<|endoftext|>


<commit_before>define(['underscore', 'chai', 'squire', 'mocha', 'sinon', 'sinonChai'], function (_, chai, Squire, mocha, sinon, sinonChai) {

    'use strict';
    var injector = new Squire(),
        should = chai.should();

    require(['underscore', 'sinonCall', 'sinonSpy']);
    // Using Sinon-Chai assertions for spies etc. https://github.com/domenic/sinon-chai
    chai.use(sinonChai);
    mocha.setup('bdd');

    describe('An instance MasseuseModel', function () {

        describe('ComputedProperty', function() {

            //-----------Setup-----------
            var Model,
                modelInstance,
                ComputedProperty,
                ProxyProperty;

            beforeEach(function (done) {
                injector.require(['masseuse'], function (masseuse) {
                        ComputedProperty = masseuse.ComputedProperty;
                        ProxyProperty = masseuse.ProxyProperty;
                        Model = masseuse.MasseuseModel;
                        modelInstance = new Model();
                        done();
                    },
                    function () {
                        console.log('Model error.');
                        done();
                    });
            });

            it('should allow the user to use a computed property when setting a single model property', function () {
                modelInstance.set('propA', 5);
                modelInstance.set('propB', new ComputedProperty(['propA'], function (propA) {
                    return propA * 2;
                }));

                should.exist(modelInstance.get('propB'));
                modelInstance.get('propB').should.equal(10);
            });

            it('should allow the user to use a computed property when setting a single model property', function () {
                modelInstance.set({
                    'propB': new ComputedProperty(['propA'], function (propA) {
                        return propA * 2;
                    }),
                    'propA': 5
                });

                should.exist(modelInstance.get('propB'));
                modelInstance.get('propB').should.equal(10);
            });

            it('should change the value of a computed property when a dependecy changes', function () {
                modelInstance.set({
                    'propB': new ComputedProperty(['propA'], function (propA) {
                        return propA * 2;
                    }),
                    'propA': 5
                });

                should.exist(modelInstance.get('propB'));
                modelInstance.get('propB').should.equal(10);

                modelInstance.set('propA', 6);
                modelInstance.get('propB').should.equal(12);
            });

            it('should update computed properties when they are computed off of more than one property', function () {
                modelInstance.set({
                    'propA': 5,
                    'propB': 5,
                    'propC': new ComputedProperty(['propA', 'propB'], function (propA, propB) {
                        return propA + propB;
                    })
                });

                modelInstance.get('propC').should.equal(10);

                modelInstance.set('propA', 6);

                modelInstance.get('propC').should.equal(11);

                modelInstance.set('propB', 6);

                modelInstance.get('propC').should.equal(12);

                modelInstance.set({
                    'propA': 7,
                    'propB': 7
                });

                modelInstance.get('propC').should.equal(14);
            });

            it('should update multiple computed properties off of the same property', function () {
                modelInstance.set({
                    'propA': 5,
                    'propB': new ComputedProperty(['propA'], function (propA) {
                        return propA;
                    }),
                    'propC': new ComputedProperty(['propA'], function (propA) {
                        return propA;
                    })
                });

                modelInstance.get('propB').should.equal(5);
                modelInstance.get('propC').should.equal(5);

                modelInstance.set('propA', 10);

                modelInstance.get('propB').should.equal(10);
                modelInstance.get('propC').should.equal(10);
            });

            it('should not set the initial computed value if 3rd paremeter is true', function() {
                modelInstance.set({
                    'propA': 5,
                    'propB': 5,
                    'propC': new ComputedProperty(['propA', 'propB'], function (propA, propB) {
                        return propA + propB;
                    }, true)
                });

                modelInstance.get('propA').should.equal(5);
                modelInstance.get('propB').should.equal(5);
                should.not.exist(modelInstance.get('propC'));
                modelInstance.set('propA', 6);
                modelInstance.get('propC').should.equal(11);
                modelInstance.set('propB', 7);
                modelInstance.get('propC').should.equal(13);
            });

            it('should be able to set computed values on instantiation', function() {
                modelInstance = new Model({
                    'propA': 5,
                    'propB': 5,
                    'propC': new ComputedProperty(['propA', 'propB'], function (propA, propB) {
                        return propA + propB;
                    })});

                modelInstance.get('propA').should.equal(5);
                modelInstance.get('propB').should.equal(5);
                modelInstance.get('propC').should.equal(10);
            });
        });
    });

});
<commit_msg>removing unneeded test<commit_after>define(['underscore', 'chai', 'squire', 'mocha', 'sinon', 'sinonChai'], function (_, chai, Squire, mocha, sinon, sinonChai) {

    'use strict';
    var injector = new Squire(),
        should = chai.should();

    require(['underscore', 'sinonCall', 'sinonSpy']);
    // Using Sinon-Chai assertions for spies etc. https://github.com/domenic/sinon-chai
    chai.use(sinonChai);
    mocha.setup('bdd');

    describe('ComputedProperty', function() {

        //-----------Setup-----------
        var Model,
            modelInstance,
            ComputedProperty,
            ProxyProperty;

        beforeEach(function (done) {
            injector.require(['masseuse'], function (masseuse) {
                    ComputedProperty = masseuse.ComputedProperty;
                    ProxyProperty = masseuse.ProxyProperty;
                    Model = masseuse.MasseuseModel;
                    modelInstance = new Model();
                    done();
                },
                function () {
                    console.log('Model error.');
                    done();
                });
        });

        it('should allow the user to use a computed property when setting a single model property', function () {
            modelInstance.set('propA', 5);
            modelInstance.set('propB', new ComputedProperty(['propA'], function (propA) {
                return propA * 2;
            }));

            should.exist(modelInstance.get('propB'));
            modelInstance.get('propB').should.equal(10);
        });

        it('should allow the user to use a computed property when setting a single model property', function () {
            modelInstance.set({
                'propB': new ComputedProperty(['propA'], function (propA) {
                    return propA * 2;
                }),
                'propA': 5
            });

            should.exist(modelInstance.get('propB'));
            modelInstance.get('propB').should.equal(10);
        });

        it('should change the value of a computed property when a dependecy changes', function () {
            modelInstance.set({
                'propB': new ComputedProperty(['propA'], function (propA) {
                    return propA * 2;
                }),
                'propA': 5
            });

            should.exist(modelInstance.get('propB'));
            modelInstance.get('propB').should.equal(10);

            modelInstance.set('propA', 6);
            modelInstance.get('propB').should.equal(12);
        });

        it('should update computed properties when they are computed off of more than one property', function () {
            modelInstance.set({
                'propA': 5,
                'propB': 5,
                'propC': new ComputedProperty(['propA', 'propB'], function (propA, propB) {
                    return propA + propB;
                })
            });

            modelInstance.get('propC').should.equal(10);

            modelInstance.set('propA', 6);

            modelInstance.get('propC').should.equal(11);

            modelInstance.set('propB', 6);

            modelInstance.get('propC').should.equal(12);

            modelInstance.set({
                'propA': 7,
                'propB': 7
            });

            modelInstance.get('propC').should.equal(14);
        });

        it('should update multiple computed properties off of the same property', function () {
            modelInstance.set({
                'propA': 5,
                'propB': new ComputedProperty(['propA'], function (propA) {
                    return propA;
                }),
                'propC': new ComputedProperty(['propA'], function (propA) {
                    return propA;
                })
            });

            modelInstance.get('propB').should.equal(5);
            modelInstance.get('propC').should.equal(5);

            modelInstance.set('propA', 10);

            modelInstance.get('propB').should.equal(10);
            modelInstance.get('propC').should.equal(10);
        });

        it('should not set the initial computed value if 3rd paremeter is true', function() {
            modelInstance.set({
                'propA': 5,
                'propB': 5,
                'propC': new ComputedProperty(['propA', 'propB'], function (propA, propB) {
                    return propA + propB;
                }, true)
            });

            modelInstance.get('propA').should.equal(5);
            modelInstance.get('propB').should.equal(5);
            should.not.exist(modelInstance.get('propC'));
            modelInstance.set('propA', 6);
            modelInstance.get('propC').should.equal(11);
            modelInstance.set('propB', 7);
            modelInstance.get('propC').should.equal(13);
        });

        it('should be able to set computed values on instantiation', function() {
            modelInstance = new Model({
                'propA': 5,
                'propB': 5,
                'propC': new ComputedProperty(['propA', 'propB'], function (propA, propB) {
                    return propA + propB;
                })});

            modelInstance.get('propA').should.equal(5);
            modelInstance.get('propB').should.equal(5);
            modelInstance.get('propC').should.equal(10);
        });
    });
});
<|endoftext|>


<commit_before>var Set = require('./set')

module.exports = function(params) {
  if (arguments.length <= 1)
    return new Stochator(params)
  else if (arguments.length === 2)
    return new Stochator(params, arguments[1])
  else if (arguments.length === 3) //refactor to support any amount
    return new Stochator(arguments[0], arguments[1], arguments[2])
}

function callFunctions(fns) {
  return fns.map(function(fn) { return fn() })
}

function randomBoundedFloat (min, max) {
  if (min == null) min = 0
  if (max == null) max = 1
  var spread = max - min
  return Math.random() * spread + min
}

function randomBoundedInteger (min, max) {
  if (min == null) min = 0
  if (max == null) max = 1
  var spread = 1 + max - min
  return Math.floor(Math.random() * spread) + min
}

function randomNormallyDistributedFloat (mean, stdev, min, max) {
  var seed = randomBoundedFloat()
  var float = inverseNormalCumulativeDistribution(seed) * stdev + mean

  if ((min != null) && (max != null))
    return Math.min(max, Math.max(min, float))
  else
    return float
}

function randomSetMember(set) {
  var max = set.length - 1
  return set.get(randomBoundedInteger(0, max))
}

function randomSetMemberWithoutReplacement (set) {
  if (!set.get(0)) return void 0

  set.length -= 1
  return set.pop(randomBoundedInteger(0, set.length))
}

function randomWeightedSetMember (set, weights) {
  var member = undefined
  var weightSum = 0
  var float = randomBoundedFloat()

  set.each(function(value, index) {
    if (member) return
    var weight = weights.get(index)
    if (float <= weightSum + weight && float >= weightSum)
      member = value

    return weightSum += weight
  })
  return member
}

function inverseNormalCumulativeDistribution(probability) {
  var high = probability > 0.97575, low = probability < 0.02425

  if (low || high) {
    var numCoefficients = new Set([-7.784894002430293e-3, -3.223964580411365e-1, -2.400758277161838, -2.549732539343734, 4.374664141464968])
    var denomCoeffcients = new Set([7.784695709041462e-3, 3.224671290700398e-1, 2.445134137142996, 3.754408661907416])
    var numMaxExponent = 5, denomMaxExponent = 4
    var coefficient = low ? 1 : -1
    var base = Math.sqrt(-2 * Math.log(low ? probability : 1 - probability))
  } else {
    var numCoefficients = new Set([-3.969683028665376e1, 2.209460984245205e2, -2.759285104469687e2, 1.383577518672690e2, -3.066479806614716e1, 2.506628277459239])
    var denomCoeffcients = new Set([-5.447609879822406e1, 1.615858368580409e2, -1.556989798598866e2, 6.680131188771972e1, -1.328068155288572e1])
    var numMaxExponent = 5, denomMaxExponent = 5
    var coefficient = probability - 0.5
    var base = Math.pow(coefficient, 2)
  }

  function mapMaxExp(maxExp) {
    return function(value, index) {
      return value * Math.pow(base, maxExp - index);
    }
  }

  var numerator = numCoefficients.map(mapMaxExp(numMaxExponent)).sum()
  var denominator = denomCoeffcients.map(mapMaxExp(denomMaxExponent)).sum() + 1
  return coefficient * numerator / denominator;
}

//todo: verify this is fisher-yates shuffle
function shuffleSet(set) {
  var values = set.copy()
  for (var index = values.length; index > 0; index -= 1) {
    var randomIndex = randomBoundedInteger(0, index)
    var tmp = values[index]
    values[index] = values[randomIndex]
    values[randomIndex] = tmp
  }
  return values
}

function floatGenerator(min, max, mean, stdev) {
  if (mean && stdev)
    return function() { return randomNormallyDistributedFloat(mean, stdev, min, max) }
  else
    return function() { return randomBoundedFloat(min, max) }
}

function integerGenerator (min, max) {
  if (min == null) min = 0
  if (max == null) max = 1
  return function() { return randomBoundedInteger(min, max) }
}

function setGenerator(values, replacement, shuffle, weights) {
  if (replacement == null) replacement = true
  if (shuffle == null) shuffle = false
  if (weights == null) weights = null
  if (!values || !values.length) throw Error("Must provide a 'values' array for a set generator.")

  var set = new Set(values)
  if (shuffle) {
    return function() { return shuffleSet(set) }
  } else if (replacement) {
    if (weights)
      return function() { return randomWeightedSetMember(set, new Set(weights)) }
    else
      return function() { return randomSetMember(set) }
  } else {
    return function() { return randomSetMemberWithoutReplacement(set) }
  }
}

function Stochator() {
  var configs = 1 <= arguments.length ? [].slice.call(arguments) : []
  this.setGenerator(configs)
}

Stochator.prototype.createGenerator = function(config) {
  config.kind = config.kind || "float"

  switch (config.kind) {
    case "float":
      var min = config.min, max = config.max, mean = config.mean, stdev = config.stdev;
      return floatGenerator(min, max, mean, stdev);
    case "integer":
      return integerGenerator(config.min, config.max);
    case "set":
      var values = config.values, replacement = config.replacement, shuffle = config.shuffle, weights = config.weights;
      return setGenerator(values, replacement, shuffle, weights);
  }
}

Stochator.prototype.createGenerators = function(configs, mutator) {
  var _this = this
  configs[0] = configs[0] || {}
  var generators = configs.map(function(cfg) { return _this.createGenerator(cfg) })

  if (!mutator) {
    if (generators.length === 1)
      var callGenerators = function() { return callFunctions(generators)[0] }
    else
      var callGenerators = function() { return callFunctions(generators) }
  } else {
    if (generators.length === 1)
      var caller = function() { return callFunctions(generators)[0] }
    else
      var caller = function() { return callFunctions(generators) }

    var callGenerators = function() {
      return _this.value = mutator.call(_this, caller(), _this.value);
    }
  }

  return function(times) {
    if (!times) return callGenerators()

    var results = []
    for (var i = 1; i <= times; ++i)
      results.push(callGenerators())
    return results
  }
}

//todo: refactor
Stochator.prototype.setGenerator = function(configs) {
  var generatorConfigs = []
  for (var i = 0; i < configs.length; ++i) {
    if (typeof configs[i] == 'object')
      generatorConfigs.push(configs[i])
    else
      break //<--- this is weird, todo: investigate cases
  }

  var _ref = configs.slice(generatorConfigs.length), name = _ref[0], mutator = _ref[1];
  name = name || "next"

  if (typeof name == 'function') {
    _ref1 = ["next", name], name = _ref1[0], mutator = _ref1[1];
  }
  return this[name] = this.createGenerators(generatorConfigs, mutator)
}

<commit_msg>removed shuffle ability<commit_after>var Set = require('./set')

module.exports = function(params) {
  if (arguments.length <= 1)
    return new Stochator(params)
  else if (arguments.length === 2)
    return new Stochator(params, arguments[1])
  else if (arguments.length === 3) //refactor to support any amount
    return new Stochator(arguments[0], arguments[1], arguments[2])
}

function callFunctions(fns) {
  return fns.map(function(fn) { return fn() })
}

function randomBoundedFloat (min, max) {
  if (min == null) min = 0
  if (max == null) max = 1
  var spread = max - min
  return Math.random() * spread + min
}

function randomBoundedInteger (min, max) {
  if (min == null) min = 0
  if (max == null) max = 1
  var spread = 1 + max - min
  return Math.floor(Math.random() * spread) + min
}

function randomNormallyDistributedFloat (mean, stdev, min, max) {
  var seed = randomBoundedFloat()
  var float = inverseNormalCumulativeDistribution(seed) * stdev + mean

  if ((min != null) && (max != null))
    return Math.min(max, Math.max(min, float))
  else
    return float
}

function randomSetMember(set) {
  var max = set.length - 1
  return set.get(randomBoundedInteger(0, max))
}

function randomSetMemberWithoutReplacement (set) {
  if (!set.get(0)) return void 0

  set.length -= 1
  return set.pop(randomBoundedInteger(0, set.length))
}

function randomWeightedSetMember (set, weights) {
  var member = undefined
  var weightSum = 0
  var float = randomBoundedFloat()

  set.each(function(value, index) {
    if (member) return
    var weight = weights.get(index)
    if (float <= weightSum + weight && float >= weightSum)
      member = value

    return weightSum += weight
  })
  return member
}

function inverseNormalCumulativeDistribution(probability) {
  var high = probability > 0.97575, low = probability < 0.02425

  if (low || high) {
    var numCoefficients = new Set([-7.784894002430293e-3, -3.223964580411365e-1, -2.400758277161838, -2.549732539343734, 4.374664141464968])
    var denomCoeffcients = new Set([7.784695709041462e-3, 3.224671290700398e-1, 2.445134137142996, 3.754408661907416])
    var numMaxExponent = 5, denomMaxExponent = 4
    var coefficient = low ? 1 : -1
    var base = Math.sqrt(-2 * Math.log(low ? probability : 1 - probability))
  } else {
    var numCoefficients = new Set([-3.969683028665376e1, 2.209460984245205e2, -2.759285104469687e2, 1.383577518672690e2, -3.066479806614716e1, 2.506628277459239])
    var denomCoeffcients = new Set([-5.447609879822406e1, 1.615858368580409e2, -1.556989798598866e2, 6.680131188771972e1, -1.328068155288572e1])
    var numMaxExponent = 5, denomMaxExponent = 5
    var coefficient = probability - 0.5
    var base = Math.pow(coefficient, 2)
  }

  function mapMaxExp(maxExp) {
    return function(value, index) {
      return value * Math.pow(base, maxExp - index);
    }
  }

  var numerator = numCoefficients.map(mapMaxExp(numMaxExponent)).sum()
  var denominator = denomCoeffcients.map(mapMaxExp(denomMaxExponent)).sum() + 1
  return coefficient * numerator / denominator;
}

function floatGenerator(min, max, mean, stdev) {
  if (mean && stdev)
    return function() { return randomNormallyDistributedFloat(mean, stdev, min, max) }
  else
    return function() { return randomBoundedFloat(min, max) }
}

function integerGenerator (min, max) {
  if (min == null) min = 0
  if (max == null) max = 1
  return function() { return randomBoundedInteger(min, max) }
}

function setGenerator(values, replacement, weights) {
  if (replacement == null) replacement = true
  if (weights == null) weights = null
  if (!values || !values.length) throw Error("Must provide a 'values' array for a set generator.")

  var set = new Set(values)
  if (replacement) {
    if (weights)
      return function() { return randomWeightedSetMember(set, new Set(weights)) }
    else
      return function() { return randomSetMember(set) }
  } else {
    return function() { return randomSetMemberWithoutReplacement(set) }
  }
}

function Stochator() {
  var configs = 1 <= arguments.length ? [].slice.call(arguments) : []
  this.setGenerator(configs)
}

Stochator.prototype.createGenerator = function(config) {
  config.kind = config.kind || "float"

  switch (config.kind) {
    case "float":
      var min = config.min, max = config.max, mean = config.mean, stdev = config.stdev;
      return floatGenerator(min, max, mean, stdev);
    case "integer":
      return integerGenerator(config.min, config.max);
    case "set":
      var values = config.values, replacement = config.replacement, weights = config.weights;
      return setGenerator(values, replacement, weights)
  }
}

Stochator.prototype.createGenerators = function(configs, mutator) {
  var _this = this
  configs[0] = configs[0] || {}
  var generators = configs.map(function(cfg) { return _this.createGenerator(cfg) })

  if (!mutator) {
    if (generators.length === 1)
      var callGenerators = function() { return callFunctions(generators)[0] }
    else
      var callGenerators = function() { return callFunctions(generators) }
  } else {
    if (generators.length === 1)
      var caller = function() { return callFunctions(generators)[0] }
    else
      var caller = function() { return callFunctions(generators) }

    var callGenerators = function() {
      return _this.value = mutator.call(_this, caller(), _this.value);
    }
  }

  return function(times) {
    if (!times) return callGenerators()

    var results = []
    for (var i = 1; i <= times; ++i)
      results.push(callGenerators())
    return results
  }
}

//todo: refactor
Stochator.prototype.setGenerator = function(configs) {
  var generatorConfigs = []
  for (var i = 0; i < configs.length; ++i) {
    if (typeof configs[i] == 'object')
      generatorConfigs.push(configs[i])
    else
      break //<--- this is weird, todo: investigate cases
  }

  var _ref = configs.slice(generatorConfigs.length), name = _ref[0], mutator = _ref[1];
  name = name || "next"

  if (typeof name == 'function') {
    _ref1 = ["next", name], name = _ref1[0], mutator = _ref1[1];
  }
  return this[name] = this.createGenerators(generatorConfigs, mutator)
}

<|endoftext|>