<commit_before>var Utils = Utils || {};
Utils.amazon = {
    onlyASINRegex: new RegExp("([a-zA-Z0-9]{10})"),

    extractASIN: function (url) {
        var regex = new RegExp("/([a-zA-Z0-9]{10})(?:[/?]|$)");
        var m = url.match(regex);
        if (m) {
            return m[0].replace(new RegExp('\/|\\?', 'g'), '');
        }
        return '';
    },
    isValidASIN: function (input) {
        return input && input.length == 10 && this.onlyASINRegex.test(input);
    },
    createCleanAffiliateURL: function (url, asin, tag) {
        tag = tag || 'fromdevtools-20';
        return this.getCleanURL(url) + '?tag=' + tag;
    },
    getCleanURL: function (url, asin) {
        var cleanurl = url;
        asin = asin || this.extractASIN(url);
        if (asin) {
            var asinIndex = url.indexOf(asin);
            if (asinIndex > -1) {
                var asinEnd = asinIndex + asin.length;
                cleanurl = url.substring(0, asinEnd);
            }
        }
        return cleanurl;
    }

};
//wrapper around storage to use only if supported
Utils.storage = {
    setItem: function (key, value) {
        if (typeof (Storage) !== "undefined") {
            // Store
            localStorage.setItem(key, value);
        }
    },

    getItem: function (key) {
        if (typeof (Storage) !== "undefined") {
            return localStorage.getItem(key);
        }
        return '';
    },
    getJSON: function (key) {
        var jsonObject;
        try {
            jsonObject = JSON.parse(StorageUtils.getItem(key)); // this is how you parse a string into JSON
        } catch (ex) {
            console.error(ex);
        }
        return jsonObject;
    }
};

Utils.arrayutil = {
    removeDuplicates: function (arr) {
        var uniques = [];
        if (arr) {
            arr.forEach(function (item) {
                if (uniques.indexOf(item) < 0) {
                    uniques.push(item);
                }
            });
        }
        return uniques;

    },
    shuffle: function (array) {
        var counter = array.length;

        // While there are elements in the array
        while (counter > 0) {
            // Pick a random index
            var index = Math.floor(Math.random() * counter);

            // Decrease counter by 1
            counter--;

            // And swap the last element with it
            var temp = array[counter];
            array[counter] = array[index];
            array[index] = temp;
        }

        return array;
    }
};

Utils.urlutil = {
    extractDomain: function (url) {
        var domain = '';
        if (url) {
            //find & remove protocol (http, ftp, etc.) and get domain
            if (url.indexOf("://") > -1) {
                domain = url.split('/')[2];
            } else {
                domain = url.split('/')[0];
            }
            //find & remove port number
            domain = domain.split(':')[0];
        }
        return domain;
    },
    extractDomainList: function (arr) {
        var domains = [];
        if (arr) {
            arr.forEach(function (item) {
                domains.push(Utils.urlutil.extractDomain(item));
            });
        }
        return domains;
    }
};

Utils.randomutil = {
    getRandomInt: function (min, max) {
        min = min || 0;
        max = max || 0;
        return Math.floor(Math.random() * (max - min + 1) + min);
    }
};

Utils.logutil = {
    log: function (msg) {
        if (debug) {
            console.log(msg);
        }
    }
};

Utils.mathutil = {
    standardDeviation: function (values) {
        const average = function (data) {
            const sum = data.reduce((s, value) => s + value, 0);
            const avg = sum / data.length;
            return avg;
        };
        const avg = average(values);
        const squareDiffs = values.map((value) => {
            const diff = value - avg;
            const sqrDiff = diff * diff;
            return sqrDiff;
        });

        const avgSquareDiff = average(squareDiffs);

        const stdDev = Math.sqrt(avgSquareDiff);
        return stdDev;
    }
};

Utils.textutil = {
    newlineSeparator: {
        name: 'Newline',
        value: '\n'
    },
    supportedSeparators: [
        newlineSeparator,
        {
            name: 'Comma',
            value: ','
        },
        {
            name: 'Colon',
            value: ':'
        },
        {
            name: 'Semicolor',
            value: ';'
        },
        {
            name: 'Tab',
            value: '\t'
        },
        {
            name: 'PIpe',
            value: '|'
        }
    ],
    guessSeparator = (inVal) => {
        const separator = (inVal) ? supportedSeparators.find(v => inVal.indexOf(v.value) > -1) : newlineSeparator;
        return separator || newlineSeparator;
    }
};

const AmazonUtils = Utils.amazon;
const StorageUtils = Utils.storage;
const ArrayUtils = Utils.arrayutil;
const UrlUtils = Utils.urlutil;
const RandomUtils = Utils.randomutil;
const LogUtils = Utils.logutil;
const MathUtils = Utils.mathutil;
const TextUtils = Utils.textutil;
<commit_msg>compilation fix for function<commit_after>var Utils = Utils || {};
Utils.amazon = {
    onlyASINRegex: new RegExp("([a-zA-Z0-9]{10})"),

    extractASIN: function (url) {
        var regex = new RegExp("/([a-zA-Z0-9]{10})(?:[/?]|$)");
        var m = url.match(regex);
        if (m) {
            return m[0].replace(new RegExp('\/|\\?', 'g'), '');
        }
        return '';
    },
    isValidASIN: function (input) {
        return input && input.length == 10 && this.onlyASINRegex.test(input);
    },
    createCleanAffiliateURL: function (url, asin, tag) {
        tag = tag || 'fromdevtools-20';
        return this.getCleanURL(url) + '?tag=' + tag;
    },
    getCleanURL: function (url, asin) {
        var cleanurl = url;
        asin = asin || this.extractASIN(url);
        if (asin) {
            var asinIndex = url.indexOf(asin);
            if (asinIndex > -1) {
                var asinEnd = asinIndex + asin.length;
                cleanurl = url.substring(0, asinEnd);
            }
        }
        return cleanurl;
    }

};
//wrapper around storage to use only if supported
Utils.storage = {
    setItem: function (key, value) {
        if (typeof (Storage) !== "undefined") {
            // Store
            localStorage.setItem(key, value);
        }
    },

    getItem: function (key) {
        if (typeof (Storage) !== "undefined") {
            return localStorage.getItem(key);
        }
        return '';
    },
    getJSON: function (key) {
        var jsonObject;
        try {
            jsonObject = JSON.parse(StorageUtils.getItem(key)); // this is how you parse a string into JSON
        } catch (ex) {
            console.error(ex);
        }
        return jsonObject;
    }
};

Utils.arrayutil = {
    removeDuplicates: function (arr) {
        var uniques = [];
        if (arr) {
            arr.forEach(function (item) {
                if (uniques.indexOf(item) < 0) {
                    uniques.push(item);
                }
            });
        }
        return uniques;

    },
    shuffle: function (array) {
        var counter = array.length;

        // While there are elements in the array
        while (counter > 0) {
            // Pick a random index
            var index = Math.floor(Math.random() * counter);

            // Decrease counter by 1
            counter--;

            // And swap the last element with it
            var temp = array[counter];
            array[counter] = array[index];
            array[index] = temp;
        }

        return array;
    }
};

Utils.urlutil = {
    extractDomain: function (url) {
        var domain = '';
        if (url) {
            //find & remove protocol (http, ftp, etc.) and get domain
            if (url.indexOf("://") > -1) {
                domain = url.split('/')[2];
            } else {
                domain = url.split('/')[0];
            }
            //find & remove port number
            domain = domain.split(':')[0];
        }
        return domain;
    },
    extractDomainList: function (arr) {
        var domains = [];
        if (arr) {
            arr.forEach(function (item) {
                domains.push(Utils.urlutil.extractDomain(item));
            });
        }
        return domains;
    }
};

Utils.randomutil = {
    getRandomInt: function (min, max) {
        min = min || 0;
        max = max || 0;
        return Math.floor(Math.random() * (max - min + 1) + min);
    }
};

Utils.logutil = {
    log: function (msg) {
        if (debug) {
            console.log(msg);
        }
    }
};

Utils.mathutil = {
    standardDeviation: function (values) {
        const average = function (data) {
            const sum = data.reduce((s, value) => s + value, 0);
            const avg = sum / data.length;
            return avg;
        };
        const avg = average(values);
        const squareDiffs = values.map((value) => {
            const diff = value - avg;
            const sqrDiff = diff * diff;
            return sqrDiff;
        });

        const avgSquareDiff = average(squareDiffs);

        const stdDev = Math.sqrt(avgSquareDiff);
        return stdDev;
    }
};

Utils.textutil = {
    newlineSeparator: {
        name: 'Newline',
        value: '\n'
    },
    supportedSeparators: [
        newlineSeparator,
        {
            name: 'Comma',
            value: ','
        },
        {
            name: 'Colon',
            value: ':'
        },
        {
            name: 'Semicolor',
            value: ';'
        },
        {
            name: 'Tab',
            value: '\t'
        },
        {
            name: 'PIpe',
            value: '|'
        }
    ],
    guessSeparator: (inVal) => {
        const separator = (inVal) ? supportedSeparators.find(v => inVal.indexOf(v.value) > -1) : newlineSeparator;
        return separator || newlineSeparator;
    }
};

const AmazonUtils = Utils.amazon;
const StorageUtils = Utils.storage;
const ArrayUtils = Utils.arrayutil;
const UrlUtils = Utils.urlutil;
const RandomUtils = Utils.randomutil;
const LogUtils = Utils.logutil;
const MathUtils = Utils.mathutil;
const TextUtils = Utils.textutil;
<|endoftext|>


<commit_before>(function($) {
    "use strict";

    var defaultOptions = {
        defaultText: 'Please Select...'
    };
    $.fn.fallzuSelectpicker = function(devOptions) {
        var options = $.extend(defaultOptions, devOptions);
        var skinRender = function(el, name, template) {
            el.after(
                '
' +
                    '<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">' +
                        '' + options.defaultText + '' +
                        '' +
                    '</button>' +
                    '
' + template + '
' +
                '
'
            );
        };

        var templateRender = function(el, labelStr, hrStr, isGroup) {
            var labelStr = labelStr || '';
            var hrStr = hrStr || '';
            var subtext = (el.data('subtext') === undefined)
                          ? ('')
                          : (' ' + el.data('subtext') + '');
            var subtextAttr = (el.data('subtext') === undefined)
                              ? ('')
                              : ('data-subtext="' + el.data('subtext') + '"');
            var group = (isGroup === true) ? ('opt') : ('');
            var imgText = (el.data('img') === undefined)
                          ? ('')
                          : ('');

            var template =
                '
' +
                    labelStr +
                    '' +
                        '' + el.text() + subtext + '' +
                        '' +
                        imgText +
                    '' +
                    hrStr +
                '
';
            return template;
        };

        $(this).each(function() {
            var el = $(this);

            // Reset
            el.find('option:selected').prop('', false);

            // Check select element
            var elName = el.attr('name');
            if (el.is('select') && elName != undefined) {
                var template = '';
                var seletLength = el.children().length;
                el.children().each(function(optionIndex) {
                    var rootOption = $(this);

                    // Check isGroup
                    if (rootOption.is('optgroup')) {
                        rootOption.each(function() {
                            var optionGroup = $(this);
                            var label = optionGroup.attr('label');
                            var length = optionGroup.children().length;

                            optionGroup.children().each(function(index) {
                                var option = $(this);
                                // Label
                                var labelStr = (index === 0) ? ('
' + label + '
') : ('');
                                // hr line
                                var hrStr = (index === length - 1 && optionIndex != seletLength - 1)
                                            ? ('

')
                                            : ('');

                                template += templateRender(option, labelStr, hrStr, true);
                            });
                        });
                    } else {
                        template += templateRender(rootOption);
                    }

                });

                skinRender(el, elName, template);
                el.hide();

                // Binding event
                var dropdownDiv = el.next('.fallzu-select-dropdown[data-name=' + elName + ']').first();

                // Option Click
                dropdownDiv.find('.fallzu-select-option').on('click', function(e) {
                    e.preventDefault();
                    var ul = $(this).parents('ul');
                    var value = $(this).data('val');
                    var originalOption = el.find('option[value=' + value + ']');
                    // Without children element
                    var text = $(this).find('.fallzu-option-text').clone().children().remove().end().text();
                    var subtext = $(this).data('subtext');
                    var subtextStr = (subtext === undefined)
                                    ? ('')
                                    : (' ' + subtext + '');

                    // Multiple
                    if (el.prop('multiple')) {
                        var isSelect = originalOption.prop('selected');

                        if (isSelect) {
                            $(this).removeClass('fallzu-option-active');
                            originalOption.prop('selected', false);
                        } else {
                            $(this).addClass('fallzu-option-active');
                            originalOption.prop('selected', true);
                        }

                        var textArr = [];
                        el.find('option:selected').each(function() {
                            textArr.push($(this).text());
                        });

                        var title = (textArr.length == 0) ? (options.defaultText) : (textArr.join());

                        dropdownDiv.find('.fallzu-select-text').html(title);
                        return false;
                    } else {
                        originalOption.prop('selected', true);
                        ul.find('.fallzu-option-active').removeClass('fallzu-option-active');
                        $(this).addClass('fallzu-option-active');
                        dropdownDiv.find('.fallzu-select-text').html(text + subtextStr);
                        originalOption.prop('selected', true);
                    }
                });
            }
        });
    };
})(jQuery);
<commit_msg>refactor<commit_after>(function($) {
    "use strict";

    var defaultOptions = {
        defaultText: 'Please Select...'
    };
    $.fn.fallzuSelectpicker = function(devOptions) {
        var options = $.extend(defaultOptions, devOptions);
        var skinRender = function(el, name, template) {
            el.after(
                '
' +
                    '<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">' +
                        '' + options.defaultText + '' +
                        '' +
                    '</button>' +
                    '
' + template + '
' +
                '
'
            );
        };

        var templateRender = function(el, labelStr, hrStr, isGroup) {
            var labelStr = labelStr || '';
            var hrStr = hrStr || '';
            var subtext = (el.data('subtext') === undefined)
                          ? ('')
                          : (' ' + el.data('subtext') + '');
            var subtextAttr = (el.data('subtext') === undefined)
                              ? ('')
                              : ('data-subtext="' + el.data('subtext') + '"');
            var group = (isGroup === true) ? ('opt') : ('');
            var activeText = '';
            var imgText = (el.data('img') === undefined)
                          ? (undefined)
                          : ('');
            var rightText = imgText || activeText;

            var template =
                '
' +
                    labelStr +
                    '' +
                        '' + el.text() + subtext + '' +
                        rightText +
                    '' +
                    hrStr +
                '
';
            return template;
        };

        $(this).each(function() {
            var el = $(this);

            // Reset
            el.find('option:selected').prop('', false);

            // Check select element
            var elName = el.attr('name');
            if (el.is('select') && elName != undefined) {
                var template = '';
                var seletLength = el.children().length;
                el.children().each(function(optionIndex) {
                    var rootOption = $(this);

                    // Check isGroup
                    if (rootOption.is('optgroup')) {
                        rootOption.each(function() {
                            var optionGroup = $(this);
                            var label = optionGroup.attr('label');
                            var length = optionGroup.children().length;

                            optionGroup.children().each(function(index) {
                                var option = $(this);
                                // Label
                                var labelStr = (index === 0) ? ('
' + label + '
') : ('');
                                // hr line
                                var hrStr = (index === length - 1 && optionIndex != seletLength - 1)
                                            ? ('

')
                                            : ('');

                                template += templateRender(option, labelStr, hrStr, true);
                            });
                        });
                    } else {
                        template += templateRender(rootOption);
                    }

                });

                skinRender(el, elName, template);
                el.hide();

                // Binding event
                var dropdownDiv = el.next('.fallzu-select-dropdown[data-name=' + elName + ']').first();

                // Option Click
                dropdownDiv.find('.fallzu-select-option').on('click', function(e) {
                    e.preventDefault();
                    var ul = $(this).parents('ul');
                    var value = $(this).data('val');
                    var originalOption = el.find('option[value=' + value + ']');
                    // Without children element
                    var text = $(this).find('.fallzu-option-text').clone().children().remove().end().text();
                    var subtext = $(this).data('subtext');
                    var subtextStr = (subtext === undefined)
                                    ? ('')
                                    : (' ' + subtext + '');

                    // Multiple
                    if (el.prop('multiple')) {
                        var isSelect = originalOption.prop('selected');

                        if (isSelect) {
                            $(this).removeClass('fallzu-option-active');
                            originalOption.prop('selected', false);
                        } else {
                            $(this).addClass('fallzu-option-active');
                            originalOption.prop('selected', true);
                        }

                        var textArr = [];
                        el.find('option:selected').each(function() {
                            textArr.push($(this).text());
                        });

                        var title = (textArr.length == 0) ? (options.defaultText) : (textArr.join());

                        dropdownDiv.find('.fallzu-select-text').html(title);
                        return false;
                    } else {
                        originalOption.prop('selected', true);
                        ul.find('.fallzu-option-active').removeClass('fallzu-option-active');
                        $(this).addClass('fallzu-option-active');
                        dropdownDiv.find('.fallzu-select-text').html(text + subtextStr);
                        originalOption.prop('selected', true);
                    }
                });
            }
        });
    };
})(jQuery);
<|endoftext|>


<commit_before>/**
 * @class CM_View_Abstract
 * @extends Backbone.View
 */
var CM_View_Abstract = Backbone.View.extend({
	_class: 'CM_View_Abstract',

	_children: [],

	initialize: function() {
		this._children = [];

		if (this.getParent()) {
			this.getParent().registerChild(this);
		}

		if (this.actions) {
			this._bindActions(this.actions);
		}
		if (this.streams) {
			this._bindStreams(this.streams);
		}
	},

	ready: function() {
	},

	_ready: function() {
		this.ready();
		_.each(this.getChildren(), function(child) {
			child._ready();
		});
	},

	/**
	 * @param {CM_View_Abstract} child
	 */
	registerChild: function(child) {
		this._children.push(child);
	},

	/**
	 * @return CM_View_Abstract[]
	 */
	getChildren: function() {
		return this._children;
	},

	/**
	 * @param {String} className
	 * @return CM_View_Abstract|null
	 */
	findChild: function(className) {
		return _.find(this.getChildren(), function(child) {
			return _.contains(child.getClasses(), className);
		}) || null;
	},

	/**
	 * @return CM_View_Abstract|null
	 */
	getParent: function() {
		if (this.options.parent) {
			return this.options.parent;
		}
		return null;
	},

	/**
	 * @param {String} className
	 * @return CM_View_Abstract|null
	 */
	findParent: function(className) {
		var parent = this.getParent();
		if (!parent) {
			return null;
		}
		if (_.contains(parent.getClasses(), className)) {
			return parent;
		}
		return parent.findParent(className);
	},

	/**
	 * @return String
	 */
	getAutoId: function() {
		return this.el.id;
	},

	/**
	 * @return Object
	 */
	getParams: function() {
		return this.options.params || {};
	},

	/**
	 * @return string[]
	 */
	getClasses: function() {
		var classes = [this.getClass()];
		if ('CM_View_Abstract' != this.getClass()) {
			classes = classes.concat(this.constructor.__super__.getClasses());
		}
		return classes;
	},

	/**
	 * @return String
	 */
	getClass: function() {
		return this._class;
	},

	/**
	 * @param {Boolean} skipDomRemoval OPTIONAL
	 */
	remove: function(skipDomRemoval) {
		this.trigger("destruct");

		if (this.getParent()) {
			var siblings = this.getParent().getChildren();
			for (var i = 0, sibling; sibling = siblings[i]; i++) {
				if (sibling.getAutoId() == this.getAutoId()) {
					siblings.splice(i, 1);
				}
			}
		}

		_.each(this.getChildren(), function(child) {
			child.remove();
		});

		delete cm.views[this.getAutoId()];

		if (!skipDomRemoval) {
			this.$().remove();
		}
	},

	disable: function() {
		this.$().disable();
	},

	enable: function() {
		this.$().enable();
	},

	/**
	 * @param {String} functionName
	 * @param {Array|Null} params
	 * @param {Object|Null} callbacks
	 * @param {Boolean|Null} cache
	 * @return jqXHR
	 */
	ajax: function(functionName, params, callbacks, cache) {
		callbacks = callbacks || {};
		params = params || {};
		var handler = this;
		var xhr = cm.ajax('ajax', {view:this._getArray(), method:functionName, params:params}, {
			success: function(response) {
				if (response.exec) {
					new Function(response.exec).call(handler);
				}
				if (callbacks.success) {
					return callbacks.success.call(handler, response.data);
				}
			},
			error: function(msg, type) {
				if (callbacks.error) {
					return callbacks.error.call(handler, msg, type);
				}
			},
			complete: function() {
				if (callbacks.complete) {
					return callbacks.complete.call(handler);
				}
			}
		}, cache);
		this.on('destruct', function() {
			xhr.abort();
		});
		return xhr;
	},

	/**
	 * @param {String} functionName
	 * @param {Array|Null} params
	 * @param {Object|Null} callbacks
	 * @return jqXHR
	 */
	ajaxModal: function(functionName, params, callbacks) {
		callbacks = callbacks || {};
		var handler = this;
		var callbackComplete = callbacks.complete;
		callbacks.complete = function() {
			handler.enable();
			if (callbackComplete) {
				return callbackComplete(handler);
			}
		};
		this.disable();
		this.ajax(functionName, params, callbacks);
	},

	/**
	 * @param {String} className
	 * @param {Object|Null} params
	 * @param {Object|Null} options
	 * @return jqXHR
	 */
	loadComponent: function(className, params, options) {
		options = options || {};
		params = params || {};
		params.className = className;
		var successPopOut = options.successPopOut || function() {};
		var successPre = options.success ? options.success :  function() { this.popOut(); };
		var successPost = options.success ? function() {} : function() { successPopOut.call(this); }
		options.success = function(autoId) {
			var handlerNew = cm.views[autoId];
			successPre.call(handlerNew);
			handlerNew._ready();
			successPost.call(handlerNew);
		};
		return this.ajaxModal('loadComponent', params, options);
	},

	/**
	 * @param {String} path
	 * @param {Object|Null} options
	 * @return {jqXHR}
	 */
	loadPage: function (path, options) {
		options = options || {};
		var success = options.success || function() {};

		return this.ajaxModal('loadPage', {path: path}, {
			success: function(response) {
				cm.window.appendHidden(response.html);
				new Function(response.js).call(this);
				var page = cm.views[response.autoId];
				success.call(page, response.title, response.path);
				page._ready();
			}
		});
	},

	/**
	 * @param {int} actionVerb
	 * @param {int} modelType
	 * @param {Function} callback fn(CM_Action_Abstract action, CM_Model_Abstract model, array data)
	 */
	bindAction: function(actionVerb, modelType, callback) {
		cm.action.bind(actionVerb, modelType, callback, this);
		this.on('destruct', function() {
			cm.action.unbind(actionVerb, modelType, callback, this);
		});
	},

	/**
	 * @param {String} event
	 * @param {Function} callback fn(array data)
	 */
	bindStream: function(event, callback) {
		var namespace = this.getClass() + ':' + event;
		cm.stream.bind(namespace, callback, this);
		this.on('destruct', function() {
			cm.stream.unbind(namespace, callback, this);
		});
	},

	/**
	 * @param {Object}
	 */
	_bindActions: function(actions) {
		for (key in actions) {
			var callback = actions[key];
			var match = key.match(/^(\S+)\s+(.+)$/);
			var modelType = cm.model.types[match[1]];
			var actionNames = match[2].split(/\s*,\s*/);
			_.each(actionNames, function(actionName) {
				var actionVerb = cm.action.verbs[actionName];
				this.bindAction(actionVerb, modelType, callback);
			}, this);
		}
	},

	/**
	 * @param {Object}
	 */
	_bindStreams: function(streams) {
		for (key in streams) {
			var callback = streams[key];
			this.bindStream(key, callback);
		}
	},

	/**
	 * @return Object
	 */
	_getArray: function() {
		return {
			className: this.getClass(),
			id: this.getAutoId(),
			params: this.getParams(),
			parentId: this.getParent() ? this.getParent().getAutoId() : null
		};
	}
});<commit_msg>t404: add error- and complete-callbacks to view.loadPage()<commit_after>/**
 * @class CM_View_Abstract
 * @extends Backbone.View
 */
var CM_View_Abstract = Backbone.View.extend({
	_class: 'CM_View_Abstract',

	_children: [],

	initialize: function() {
		this._children = [];

		if (this.getParent()) {
			this.getParent().registerChild(this);
		}

		if (this.actions) {
			this._bindActions(this.actions);
		}
		if (this.streams) {
			this._bindStreams(this.streams);
		}
	},

	ready: function() {
	},

	_ready: function() {
		this.ready();
		_.each(this.getChildren(), function(child) {
			child._ready();
		});
	},

	/**
	 * @param {CM_View_Abstract} child
	 */
	registerChild: function(child) {
		this._children.push(child);
	},

	/**
	 * @return CM_View_Abstract[]
	 */
	getChildren: function() {
		return this._children;
	},

	/**
	 * @param {String} className
	 * @return CM_View_Abstract|null
	 */
	findChild: function(className) {
		return _.find(this.getChildren(), function(child) {
			return _.contains(child.getClasses(), className);
		}) || null;
	},

	/**
	 * @return CM_View_Abstract|null
	 */
	getParent: function() {
		if (this.options.parent) {
			return this.options.parent;
		}
		return null;
	},

	/**
	 * @param {String} className
	 * @return CM_View_Abstract|null
	 */
	findParent: function(className) {
		var parent = this.getParent();
		if (!parent) {
			return null;
		}
		if (_.contains(parent.getClasses(), className)) {
			return parent;
		}
		return parent.findParent(className);
	},

	/**
	 * @return String
	 */
	getAutoId: function() {
		return this.el.id;
	},

	/**
	 * @return Object
	 */
	getParams: function() {
		return this.options.params || {};
	},

	/**
	 * @return string[]
	 */
	getClasses: function() {
		var classes = [this.getClass()];
		if ('CM_View_Abstract' != this.getClass()) {
			classes = classes.concat(this.constructor.__super__.getClasses());
		}
		return classes;
	},

	/**
	 * @return String
	 */
	getClass: function() {
		return this._class;
	},

	/**
	 * @param {Boolean} skipDomRemoval OPTIONAL
	 */
	remove: function(skipDomRemoval) {
		this.trigger("destruct");

		if (this.getParent()) {
			var siblings = this.getParent().getChildren();
			for (var i = 0, sibling; sibling = siblings[i]; i++) {
				if (sibling.getAutoId() == this.getAutoId()) {
					siblings.splice(i, 1);
				}
			}
		}

		_.each(this.getChildren(), function(child) {
			child.remove();
		});

		delete cm.views[this.getAutoId()];

		if (!skipDomRemoval) {
			this.$().remove();
		}
	},

	disable: function() {
		this.$().disable();
	},

	enable: function() {
		this.$().enable();
	},

	/**
	 * @param {String} functionName
	 * @param {Array|Null} params
	 * @param {Object|Null} callbacks
	 * @param {Boolean|Null} cache
	 * @return jqXHR
	 */
	ajax: function(functionName, params, callbacks, cache) {
		callbacks = callbacks || {};
		params = params || {};
		var handler = this;
		var xhr = cm.ajax('ajax', {view:this._getArray(), method:functionName, params:params}, {
			success: function(response) {
				if (response.exec) {
					new Function(response.exec).call(handler);
				}
				if (callbacks.success) {
					return callbacks.success.call(handler, response.data);
				}
			},
			error: function(msg, type, isPublic) {
				if (callbacks.error) {
					return callbacks.error.call(handler, msg, type, isPublic);
				}
			},
			complete: function() {
				if (callbacks.complete) {
					return callbacks.complete.call(handler);
				}
			}
		}, cache);
		this.on('destruct', function() {
			xhr.abort();
		});
		return xhr;
	},

	/**
	 * @param {String} functionName
	 * @param {Array|Null} params
	 * @param {Object|Null} callbacks
	 * @return jqXHR
	 */
	ajaxModal: function(functionName, params, callbacks) {
		callbacks = callbacks || {};
		var handler = this;
		var callbackComplete = callbacks.complete;
		callbacks.complete = function() {
			handler.enable();
			if (callbackComplete) {
				return callbackComplete(handler);
			}
		};
		this.disable();
		this.ajax(functionName, params, callbacks);
	},

	/**
	 * @param {String} className
	 * @param {Object|Null} params
	 * @param {Object|Null} options
	 * @return jqXHR
	 */
	loadComponent: function(className, params, options) {
		options = options || {};
		params = params || {};
		params.className = className;
		var successPopOut = options.successPopOut || function() {};
		var successPre = options.success ? options.success :  function() { this.popOut(); };
		var successPost = options.success ? function() {} : function() { successPopOut.call(this); }
		options.success = function(autoId) {
			var handlerNew = cm.views[autoId];
			successPre.call(handlerNew);
			handlerNew._ready();
			successPost.call(handlerNew);
		};
		return this.ajaxModal('loadComponent', params, options);
	},

	/**
	 * @param {String} path
	 * @param {Object|Null} callbacks
	 * @return {jqXHR}
	 */
	loadPage: function (path, callbacks) {
		callbacks = callbacks || {};
		var success = callbacks.success || function() {};

		return this.ajaxModal('loadPage', {path: path}, {
			success: function(response) {
				cm.window.appendHidden(response.html);
				new Function(response.js).call(this);
				var page = cm.views[response.autoId];
				success.call(page, response.title, response.path);
				page._ready();
			},
			error: callbacks.error,
			complete: callbacks.complete
		});
	},

	/**
	 * @param {int} actionVerb
	 * @param {int} modelType
	 * @param {Function} callback fn(CM_Action_Abstract action, CM_Model_Abstract model, array data)
	 */
	bindAction: function(actionVerb, modelType, callback) {
		cm.action.bind(actionVerb, modelType, callback, this);
		this.on('destruct', function() {
			cm.action.unbind(actionVerb, modelType, callback, this);
		});
	},

	/**
	 * @param {String} event
	 * @param {Function} callback fn(array data)
	 */
	bindStream: function(event, callback) {
		var namespace = this.getClass() + ':' + event;
		cm.stream.bind(namespace, callback, this);
		this.on('destruct', function() {
			cm.stream.unbind(namespace, callback, this);
		});
	},

	/**
	 * @param {Object}
	 */
	_bindActions: function(actions) {
		for (key in actions) {
			var callback = actions[key];
			var match = key.match(/^(\S+)\s+(.+)$/);
			var modelType = cm.model.types[match[1]];
			var actionNames = match[2].split(/\s*,\s*/);
			_.each(actionNames, function(actionName) {
				var actionVerb = cm.action.verbs[actionName];
				this.bindAction(actionVerb, modelType, callback);
			}, this);
		}
	},

	/**
	 * @param {Object}
	 */
	_bindStreams: function(streams) {
		for (key in streams) {
			var callback = streams[key];
			this.bindStream(key, callback);
		}
	},

	/**
	 * @return Object
	 */
	_getArray: function() {
		return {
			className: this.getClass(),
			id: this.getAutoId(),
			params: this.getParams(),
			parentId: this.getParent() ? this.getParent().getAutoId() : null
		};
	}
});<|endoftext|>


<commit_before>import setupCalendar from './utils/setup';
import Calendar from '@/components/Calendar';
import DatePicker from '@/components/DatePicker';

// Export components individually
export { setupCalendar, Calendar, DatePicker };

// Installs the library as a plugin
const components = {
  Calendar,
  DatePicker,
};

// Declare install function executed by Vue.use()
export default function install(Vue, opts) {
  // Don't install more than once
  if (install.installed) return;
  install.installed = true;
  // Manually setup calendar with options
  const defaults = setupCalendar(Vue, opts);
  // Register components
  Object.keys(components).forEach(k =>
    Vue.component(`${defaults.componentPrefix}${k}`, components[k]),
  );
}

// Create module definition for Vue.use()
const plugin = {
  install,
};

// Use automatically when global Vue instance detected
let GlobalVue = null;
if (typeof window !== 'undefined') {
  GlobalVue = window.Vue;
} else if (typeof global !== 'undefined') {
  GlobalVue = global.Vue;
}
if (GlobalVue) {
  GlobalVue.use(plugin);
}
<commit_msg>Fix bug when calling `setupCalendar`<commit_after>import setupCalendar from './utils/setup';
import Calendar from '@/components/Calendar';
import DatePicker from '@/components/DatePicker';

// Export components individually
export { setupCalendar, Calendar, DatePicker };

// Installs the library as a plugin
const components = {
  Calendar,
  DatePicker,
};

// Declare install function executed by Vue.use()
export default function install(Vue, opts) {
  // Don't install more than once
  if (install.installed) return;
  install.installed = true;
  // Manually setup calendar with options
  const defaults = setupCalendar(opts);
  // Register components
  Object.keys(components).forEach(k =>
    Vue.component(`${defaults.componentPrefix}${k}`, components[k]),
  );
}

// Create module definition for Vue.use()
const plugin = {
  install,
};

// Use automatically when global Vue instance detected
let GlobalVue = null;
if (typeof window !== 'undefined') {
  GlobalVue = window.Vue;
} else if (typeof global !== 'undefined') {
  GlobalVue = global.Vue;
}
if (GlobalVue) {
  GlobalVue.use(plugin);
}
<|endoftext|>


<commit_before>/* Javascript for AnimationXBlock. */
function AnimationXBlock(runtime, element) {
    $(function ($) {
	// Grab XBlocks data.
	handlerUrl = runtime.handlerUrl(element, 'update_position');
	var data = JSON.parse($(".animation_source", element).text())
	var animation = data['animation'];

	var position = data['position'];
	var max_position = data['max_position'];

	// Set the correct image and text when the slider moves. Also,
	// make an AJAX call to the server to save position and
	// maximum position.
	//
	// TODO: Should we do this less often for lower load?
	// (It's okay right now, but less would be cleaner)
	function update_animation() {
	    position = $(".animation_slider").slider("value")
	    $(".animation_image").attr("src", animation[position].src);
	    $(".animation_text").html(animation[position].desc);
	    if (position > max_position) { max_position = position; }
	    if (max_position == animation.length-1) {
		$('.animation_wrapper', element).addClass("animation_done");
	    }
	    $.ajax({
		type: "POST",
		url: handlerUrl,
		data: JSON.stringify({"position" : position,
				      "max_position" : max_position}),
	    });
	}

	// Initialize slider. On any change, update the state
	$( ".animation_slider", element ).slider({
	    value: position,
	    min: 0,
	    max: animation.length-1,
	    step: 1,
	    stop: function( event, ui) { update_animation(); },
	    slide: function( event, ui) { update_animation(); },
	    change: function( event, ui) { update_animation(); }
	});

	// Go to current position in animation
	update_animation();

	// Preload images
	for(i=0; i<position.length; i++){
	    animation[position]["image"] = new Image();
	    animation[position]["image"].src = animation[position].src;
	}
    });
}<commit_msg>Comments<commit_after>/* Javascript for AnimationXBlock. */
function AnimationXBlock(runtime, element) {
    $(function ($) {
	// Grab XBlocks data.
	handlerUrl = runtime.handlerUrl(element, 'update_position');
	var data = JSON.parse($(".animation_source", element).text())
	var animation = data['animation'];

	var position = data['position'];
	var max_position = data['max_position'];

	// Set the correct image and text when the slider moves. Also,
	// make an AJAX call to the server to save position and
	// maximum position.
	//
	// TODO: Should we do this less often for lower load?
	// (It's okay right now, but less would be cleaner)
	function update_animation() {
	    position = $(".animation_slider").slider("value")
	    $(".animation_image").attr("src", animation[position].src);
	    $(".animation_text").html(animation[position].desc);
	    if (position > max_position) { max_position = position; }
	    if (max_position == animation.length-1) {
		$('.animation_wrapper', element).addClass("animation_done");
	    }
	    $.ajax({
		type: "POST",
		url: handlerUrl,
		data: JSON.stringify({"position" : position,
				      "max_position" : max_position}),
	    });
	}

	// Initialize slider. On any change, update the state
	$( ".animation_slider", element ).slider({
	    value: position,
	    min: 0,
	    max: animation.length-1,
	    step: 1,
	    stop: function( event, ui) { update_animation(); },
	    slide: function( event, ui) { update_animation(); },
	    change: function( event, ui) { update_animation(); }
	});

	// Go to current position in animation
	update_animation();

	// Preload images. I'm not sure this works. Internet
	// said it did, but I think it might not, just from
	// performance
	for(i=0; i<position.length; i++){
	    animation[position]["image"] = new Image();
	    animation[position]["image"].src = animation[position].src;
	}
    });
}<|endoftext|>


<commit_before>const config = require('../config.js');
const db = require('knex')(config.database);
const randomstring = require('randomstring');
const utils = require('./utilsController.js');
const path = require('path');
const fs = require('fs');
const Zip = require('jszip');
const albumsController = {};

albumsController.list = async (req, res, next) => {
	const user = await utils.authorize(req, res);

	const fields = ['id', 'name'];
	if (req.params.sidebar === undefined) {
		fields.push('timestamp');
		fields.push('identifier');
	}

	const albums = await db.table('albums').select(fields).where({ enabled: 1, userid: user.id });
	if (req.params.sidebar !== undefined) {
		return res.json({ success: true, albums });
	}

	let ids = [];
	for (let album of albums) {
		album.date = new Date(album.timestamp * 1000)
		album.date = utils.getPrettyDate(album.date)

		album.identifier = `${config.domain}/a/${album.identifier}`;
		ids.push(album.id);
	}

	const files = await db.table('files').whereIn('albumid', ids).select('albumid');
	const albumsCount = {};

	for (let id of ids) albumsCount[id] = 0;
	for (let file of files) albumsCount[file.albumid] += 1;
	for (let album of albums) album.files = albumsCount[album.id];

	return res.json({ success: true, albums });
};

albumsController.create = async (req, res, next) => {
	const user = await utils.authorize(req, res);

	const name = req.body.name;
	if (name === undefined || name === '') {
		return res.json({ success: false, description: 'No album name specified' });
	}

	const album = await db.table('albums').where({
		name: name,
		enabled: 1,
		userid: user.id
	}).first();

	if (album) {
		return res.json({ success: false, description: 'There\'s already an album with that name' })
	}

	await db.table('albums').insert({
		name: name,
		enabled: 1,
		userid: user.id,
		identifier: randomstring.generate(8),
		timestamp: Math.floor(Date.now() / 1000)
	});

	return res.json({ success: true });
};

albumsController.delete = async (req, res, next) => {
	const user = await utils.authorize(req, res);

	const id = req.body.id;
	if (id === undefined || id === '') {
		return res.json({ success: false, description: 'No album specified' });
	}

	await db.table('albums').where({ id: id, userid: user.id }).update({ enabled: 0 });
	return res.json({ success: true });
};

albumsController.rename = async (req, res, next) => {
	const user = await utils.authorize(req, res);

	const id = req.body.id;
	if (id === undefined || id === '') {
		return res.json({ success: false, description: 'No album specified' });
	}

	const name = req.body.name;
	if (name === undefined || name === '') {
		return res.json({ success: false, description: 'No name specified' });
	}

	const album = await db.table('albums').where({ name: name, userid: user.id }).first();
	if (album) {
		return res.json({ success: false, description: 'Name already in use' })
	}

	await db.table('albums').where({ id: id, userid: user.id }).update({ name: name })
	return res.json({ success: true });
};

albumsController.get = async (req, res, next) => {
	const identifier = req.params.identifier;
	if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' });

	const album = await db.table('albums').where({ identifier, enabled: 1 }).first();
	if (!album) return res.json({ success: false, description: 'Album not found' });

	const title = album.name;
	const files = await db.table('files').select('name').where('albumid', album.id).orderBy('id', 'DESC');

	for (let file of files) {
		file.file = `${config.domain}/${file.name}`;

		const ext = path.extname(file.name).toLowerCase();
		if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
			file.thumb = `${config.domain}/thumbs/${file.name.slice(0, -ext.length)}.png`;
		}
	}

	return res.json({
		success: true,
		title: title,
		count: files.length,
		files
	});
};

albumsController.generateZip = async (req, res, next) => {
	const identifier = req.params.identifier;
	if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' });
	if (!config.uploads.generateZips) return res.status(401).json({ success: false, description: 'Zip generation disabled' });

	const album = await db.table('albums').where({ identifier, enabled: 1 }).first();
	if (!album) return res.json({ success: false, description: 'Album not found' });

	if (album.zipGeneratedAt > album.editedAt) {
		const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`);
		const fileName = `${album.name}.zip`;
		return res.download(filePath, fileName);
	} else {
		console.log(`Generating zip for album identifier: ${identifier}`);
		const files = await db.table('files').select('name').where('albumid', album.id);
		if (files.length === 0) return res.json({ success: false, description: 'There are no files in the album' });

		const zipPath = path.join(__dirname, '..', config.uploads.folder, 'zips', `${album.identifier}.zip`);
		let archive = new Zip();

		for (let file of files) {
			fs.stat(path.join(__dirname, '..', config.uploads.folder, file.name), (err, stats) => {
				if (err) {
					console.log(err);
				} else {
					archive.file(file.name, fs.readFileSync(path.join(__dirname, '..', config.uploads.folder, file.name)));
				}
			});
		}

		archive
			.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
			.pipe(fs.createWriteStream(zipPath))
			.on('finish', async () => {
				console.log(`Generated zip for album identifier: ${identifier}`);
				await db.table('albums')
					.where('id', album.id)
					.update({ zipGeneratedAt: Math.floor(Date.now() / 1000) });

				const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`);
				const fileName = `${album.name}.zip`;
				return res.download(filePath, fileName);
			});
	}
};

module.exports = albumsController;
<commit_msg>Async who?<commit_after>const config = require('../config.js');
const db = require('knex')(config.database);
const randomstring = require('randomstring');
const utils = require('./utilsController.js');
const path = require('path');
const fs = require('fs');
const Zip = require('jszip');
const albumsController = {};

albumsController.list = async (req, res, next) => {
	const user = await utils.authorize(req, res);

	const fields = ['id', 'name'];
	if (req.params.sidebar === undefined) {
		fields.push('timestamp');
		fields.push('identifier');
	}

	const albums = await db.table('albums').select(fields).where({ enabled: 1, userid: user.id });
	if (req.params.sidebar !== undefined) {
		return res.json({ success: true, albums });
	}

	let ids = [];
	for (let album of albums) {
		album.date = new Date(album.timestamp * 1000)
		album.date = utils.getPrettyDate(album.date)

		album.identifier = `${config.domain}/a/${album.identifier}`;
		ids.push(album.id);
	}

	const files = await db.table('files').whereIn('albumid', ids).select('albumid');
	const albumsCount = {};

	for (let id of ids) albumsCount[id] = 0;
	for (let file of files) albumsCount[file.albumid] += 1;
	for (let album of albums) album.files = albumsCount[album.id];

	return res.json({ success: true, albums });
};

albumsController.create = async (req, res, next) => {
	const user = await utils.authorize(req, res);

	const name = req.body.name;
	if (name === undefined || name === '') {
		return res.json({ success: false, description: 'No album name specified' });
	}

	const album = await db.table('albums').where({
		name: name,
		enabled: 1,
		userid: user.id
	}).first();

	if (album) {
		return res.json({ success: false, description: 'There\'s already an album with that name' })
	}

	await db.table('albums').insert({
		name: name,
		enabled: 1,
		userid: user.id,
		identifier: randomstring.generate(8),
		timestamp: Math.floor(Date.now() / 1000)
	});

	return res.json({ success: true });
};

albumsController.delete = async (req, res, next) => {
	const user = await utils.authorize(req, res);

	const id = req.body.id;
	if (id === undefined || id === '') {
		return res.json({ success: false, description: 'No album specified' });
	}

	await db.table('albums').where({ id: id, userid: user.id }).update({ enabled: 0 });
	return res.json({ success: true });
};

albumsController.rename = async (req, res, next) => {
	const user = await utils.authorize(req, res);

	const id = req.body.id;
	if (id === undefined || id === '') {
		return res.json({ success: false, description: 'No album specified' });
	}

	const name = req.body.name;
	if (name === undefined || name === '') {
		return res.json({ success: false, description: 'No name specified' });
	}

	const album = await db.table('albums').where({ name: name, userid: user.id }).first();
	if (album) {
		return res.json({ success: false, description: 'Name already in use' })
	}

	await db.table('albums').where({ id: id, userid: user.id }).update({ name: name })
	return res.json({ success: true });
};

albumsController.get = async (req, res, next) => {
	const identifier = req.params.identifier;
	if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' });

	const album = await db.table('albums').where({ identifier, enabled: 1 }).first();
	if (!album) return res.json({ success: false, description: 'Album not found' });

	const title = album.name;
	const files = await db.table('files').select('name').where('albumid', album.id).orderBy('id', 'DESC');

	for (let file of files) {
		file.file = `${config.domain}/${file.name}`;

		const ext = path.extname(file.name).toLowerCase();
		if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
			file.thumb = `${config.domain}/thumbs/${file.name.slice(0, -ext.length)}.png`;
		}
	}

	return res.json({
		success: true,
		title: title,
		count: files.length,
		files
	});
};

albumsController.generateZip = async (req, res, next) => {
	const identifier = req.params.identifier;
	if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' });
	if (!config.uploads.generateZips) return res.status(401).json({ success: false, description: 'Zip generation disabled' });

	const album = await db.table('albums').where({ identifier, enabled: 1 }).first();
	if (!album) return res.json({ success: false, description: 'Album not found' });

	if (album.zipGeneratedAt > album.editedAt) {
		const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`);
		const fileName = `${album.name}.zip`;
		return res.download(filePath, fileName);
	} else {
		console.log(`Generating zip for album identifier: ${identifier}`);
		const files = await db.table('files').select('name').where('albumid', album.id);
		if (files.length === 0) return res.json({ success: false, description: 'There are no files in the album' });

		const zipPath = path.join(__dirname, '..', config.uploads.folder, 'zips', `${album.identifier}.zip`);
		let archive = new Zip();

		for (let file of files) {
			try {
				const exists = fs.statSync(path.join(__dirname, '..', config.uploads.folder, file.name));
				archive.file(file.name, fs.readFileSync(path.join(__dirname, '..', config.uploads.folder, file.name)));
			} catch (err) {
				console.log(err);
			}
		}

		archive
			.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
			.pipe(fs.createWriteStream(zipPath))
			.on('finish', async () => {
				console.log(`Generated zip for album identifier: ${identifier}`);
				await db.table('albums')
					.where('id', album.id)
					.update({ zipGeneratedAt: Math.floor(Date.now() / 1000) });

				const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`);
				const fileName = `${album.name}.zip`;
				return res.download(filePath, fileName);
			});
	}
};

module.exports = albumsController;
<|endoftext|>


<commit_before>/**
 * Created by haozi on 3/23/2017.
 */
(function (q) {
    /**
     * 给元素添加animate.css 的class并自动删除相反的 class
     * @param className 需要添加的 class
     * @returns {$}
     */
    $.fn.animateCSS = function (className) {
        if(!$(this).hasClass('animated'))
            $(this).addClass('animated')
        if(/In/.test(className)){
            $(this).removeClass(className.match(/(.*)In/)[1] + 'Out' + ' ' + className).addClass(className)
            $(this).css('display', 'block')
        }else {
            $(this).removeClass(className.match(/(.*)Out/)[1] + 'Out' + ' ' + className).addClass(className)
            var that = this
            setTimeout(function () {
                $(that).css('display', 'none')
            }, 400)
        }
        return this
    }

    var ImageZoom = function (setting) {
        modelWindow.init()
        var imgList = this.find('img')
        imgList.map(function (index, el){
            (function (index) {
                $(el).on('click',function (event) {
                    /**
                     * 停止冒泡
                     */
                    event.stopPropagation()
                    modelWindow.show($(this).attr('src') || 'https://haozi.moe/content/images/2016/11/ph.png')

                })
            })(index)
        })
    }

    /**
     * 加载Image
     * @param src  图片地址
     * @param callback  加载完成回调
     */
    function loadImage(src, callback) {
        var image = new Image(src)
        image.src = src
        image.onload = function () {
            $(image).removeAttr('width')
            var width = height = 0;
            var boxWidth = $('.ImageZoom-image').width() - 50,
                boxHeight = $('.ImageZoom-image').height() - 50
            if(image.naturalHeight > $('.ImageZoom-image').height()) {
                 width = boxHeight * image.naturalWidth / image.naturalHeight
                 height = image.naturalHeight * width / image.naturalWidth
                $(image).css({
                    width: width + 'px',
                    height: height + 'px'
                })
            }else {
                $(image).css('margin',($('.ImageZoom-image').height() / 2) - (image.naturalHeght)/2  + 'px auto 0')
                width = image.naturalWidth
                height = image.naturalHeight
            }
            $('.ImageZoom-image-box').css({
                left: 'calc(50% - ' + (width / 2) +'px)',
                top: 'calc(50% - ' + (height / 2) +'px)',
                'max-height': boxHeight + 'px',
                'max-width': boxWidth + 'px',
                width: width + 'px',
                height: height + 'px'
            })
            callback(image)
        }
    }
    var modelWindow = {
        init :function () {
            //最外一层的遮罩
            $('body').append('

')
            //loading 界面
            $('body').append('

')
            //图片显示界面
            $('body').append('

')
            //当图片层被点击的时候退出图片放大
            $('.ImageZoom-image').on('click', function () {
                modelWindow.exit()
            })
        },
        show: function (src) {
            /**
             * 加载模态窗体
             */
            $('.ImageZoom-loading').animateCSS('rotateInDownLeft')
            $('.ImageZoom-cover').animateCSS('zoomIn')
            $('body').css('overflow', 'hidden')
            $('.ImageZoom-image-box img').remove()
            loadImage(src, function (imageElement) {
                $('.ImageZoom-image').animateCSS('zoomIn')
                $('.ImageZoom-loading').animateCSS('zoomOut')
                $('.ImageZoom-image-box').css({
                    left: 'calc(50% - ' + (src.naturalwidth / 2)+'px)',
                    top: 'calc(50% - ' + (src.naturalheight / 2)+'px)'
                })

                $(imageElement).appendTo($('.ImageZoom-image-box'))
            })
        },

        hide: function () {
            $('.ImageZoom-cover').animateCSS('rotateOut')

        },
        nextImage: function () {

        },
        exit: function () {
            $('body').css('overflow', 'auto')
            $('.ImageZoom-cover').animateCSS('rotateOut')
            $('.ImageZoom-image').animateCSS('zoomOut')
        }
    }

    $.fn.ImageZoom = ImageZoom
})(jQuery)<commit_msg>fix : cdn图片读取<commit_after>/**
 * Created by haozi on 3/23/2017.
 */
(function (q) {
    /**
     * 给元素添加animate.css 的class并自动删除相反的 class
     * @param className 需要添加的 class
     * @returns {$}
     */
    $.fn.animateCSS = function (className) {
        if(!$(this).hasClass('animated'))
            $(this).addClass('animated')
        if(/In/.test(className)){
            $(this).removeClass(className.match(/(.*)In/)[1] + 'Out' + ' ' + className).addClass(className)
            $(this).css('display', 'block')
        }else {
            $(this).removeClass(className.match(/(.*)Out/)[1] + 'Out' + ' ' + className).addClass(className)
            var that = this
            setTimeout(function () {
                $(that).css('display', 'none')
            }, 400)
        }
        return this
    }

    var ImageZoom = function (setting) {
        modelWindow.init()
        var imgList = this.find('img')
        imgList.map(function (index, el){
            (function (index) {
                $(el).on('click',function (event) {
                    /**
                     * 停止冒泡
                     */
                    event.stopPropagation()
                    modelWindow.show($(this).attr('src') || 'https://haozi.moe/content/images/2016/11/ph.png')

                })
            })(index)
        })
    }

    /**
     * 加载Image
     * @param src  图片地址
     * @param callback  加载完成回调
     */
    function loadImage(src, callback) {
        src = src.replace(/\?.*/,'')
        var image = new Image(src)
        image.src = src
        image.onload = function () {
            $(image).removeAttr('width')
            var width = height = 0;
            var boxWidth = $('.ImageZoom-image').width() - 50,
                boxHeight = $('.ImageZoom-image').height() - 50
            if(image.naturalHeight > $('.ImageZoom-image').height()) {
                 width = boxHeight * image.naturalWidth / image.naturalHeight
                 height = image.naturalHeight * width / image.naturalWidth
                $(image).css({
                    width: width + 'px',
                    height: height + 'px'
                })
            }else {
                $(image).css('margin',($('.ImageZoom-image').height() / 2) - (image.naturalHeght)/2  + 'px auto 0')
                width = image.naturalWidth
                height = image.naturalHeight
            }
            $('.ImageZoom-image-box').css({
                left: 'calc(50% - ' + (width / 2) +'px)',
                top: 'calc(50% - ' + (height / 2) +'px)',
                'max-height': boxHeight + 'px',
                'max-width': boxWidth + 'px',
                width: width + 'px',
                height: height + 'px'
            })
            callback(image)
        }
    }
    var modelWindow = {
        init :function () {
            //最外一层的遮罩
            $('body').append('

')
            //loading 界面
            $('body').append('

')
            //图片显示界面
            $('body').append('

')
            //当图片层被点击的时候退出图片放大
            $('.ImageZoom-image').on('click', function () {
                modelWindow.exit()
            })
        },
        show: function (src) {
            /**
             * 加载模态窗体
             */
            $('.ImageZoom-loading').animateCSS('rotateInDownLeft')
            $('.ImageZoom-cover').animateCSS('zoomIn')
            $('body').css('overflow', 'hidden')
            $('.ImageZoom-image-box img').remove()
            loadImage(src, function (imageElement) {
                $('.ImageZoom-image').animateCSS('zoomIn')
                $('.ImageZoom-loading').animateCSS('zoomOut')
                $('.ImageZoom-image-box').css({
                    left: 'calc(50% - ' + (src.naturalwidth / 2)+'px)',
                    top: 'calc(50% - ' + (src.naturalheight / 2)+'px)'
                })

                $(imageElement).appendTo($('.ImageZoom-image-box'))
            })
        },

        hide: function () {
            $('.ImageZoom-cover').animateCSS('rotateOut')

        },
        nextImage: function () {

        },
        exit: function () {
            $('body').css('overflow', 'auto')
            $('.ImageZoom-cover').animateCSS('rotateOut')
            $('.ImageZoom-image').animateCSS('zoomOut')
        }
    }

    $.fn.ImageZoom = ImageZoom
})(jQuery)<|endoftext|>


<commit_before>jsio('from shared.javascript import Class, bind')
jsio('import fan.ui.Component')

exports = Class(fan.ui.Component, function(supr) {

	this._className = 'KeyboardFocus'
	this._borderWidth = 7

	this.init = function() {
		supr(this, 'init')
		this._on(document, 'keydown', bind(this, '_onKeyDown'))

		this._focusIndex = -1
		this._panelIndex = -1
		this._keyMap = {}

		var keys = this.keys,
			keyMap = this._keyMap

		keyMap[keys['j']] = bind(this, '_moveFocus', 1)
		keyMap[keys['k']] = bind(this, '_moveFocus', -1)
		keyMap[keys['up arrow']] = this._keyMap[keys['j']]
		keyMap[keys['down arrow']] = this._keyMap[keys['k']]
		keyMap[keys['enter']] = bind(this, '_selectFocusedItem'),
		keyMap[keys['tab']] = bind(this, '_movePanel', 1)
		keyMap[keys['`']] = bind(this, '_movePanel', -1)
	}

	this.grabFocus = function(uiComponent) { this._focusedUIComponent = uiComponent }
	this.releaseFocus = function(uiComponent) {
		if (uiComponent != this._focusedUIComponent) { return }
		delete this._focusedUIComponent
	}

	this._onKeyDown = function(e) {
		if (this._focusedUIComponent) { return }
		var callback = this._keyMap[e.keyCode]
		if (callback) {
			e.cancel()
			callback()
		}
	}

	this._movePanel = function(steps) {
		var newPanelIndex = this._panelIndex + steps
		if (newPanelIndex < 0 || newPanelIndex >= gPanels.length) { return }
		this._focusIndex = -1
		this._panelIndex = newPanelIndex
		this._moveFocus(1)
	}

	this._moveFocus = function(steps) {
		var panel = gPanels[this._panelIndex];
		if (!panel) { return }

		var newFocusIndex = this._focusIndex + steps,
			targets = panel.getElement().getElementsByClassName('fan-focusable')

		if (newFocusIndex < 0 || newFocusIndex >= targets.length) { return; }
		this._targetEl = targets[newFocusIndex]
		this._focusIndex = newFocusIndex
		this._showAt(this._targetEl)
	}

	this._selectFocusedItem = function() {
		var targetEl = this._targetEl
		if (!targetEl) { return }
		this._getFocusableComponent(targetEl).handleKeyboardSelect(targetEl)
	}

	this._createContent = function() {
		var borderWidth = this._borderWidth

		this._top = this._create({ className: 'piece top', parent: this._element })
		this._left = this._create({ className: 'piece left', parent: this._element })
		this._right = this._create({ className: 'piece right', parent: this._element })
		this._bottom = this._create({ className: 'piece bottom', parent: this._element })

		this._left.style.width = this._right.style.width = borderWidth + 'px'
		this._top.style.height = this._bottom.style.height = borderWidth + 'px'
	}

	this._showAt = function(targetEl) {
		var focusPadding = 2,
			borderWidth = this._borderWidth,
			layout = this.getLayout(targetEl)

		document.body.appendChild(this.getElement())

		layout.width += focusPadding * 2;
		layout.height += focusPadding * 2;
		layout.left -= focusPadding;
		layout.top -= focusPadding;

		this.layout(this._top, { top: layout.top - borderWidth, left: layout.left - borderWidth,
			width: layout.width + borderWidth });
		this.layout(this._bottom, { top: layout.top + layout.height, left: layout.left - borderWidth,
			width: layout.width + borderWidth });
		this.layout(this._left, { top: layout.top, left: layout.left - borderWidth, height: layout.height });
		this.layout(this._right, { top: layout.top, left: layout.left + layout.width - borderWidth,
			height: layout.height });
	}
})<commit_msg>Make right/left arrows mmic tab/` keystrokes, and make sure to call the keyboard select callback for a UI component in a timeout such that the event can complete first<commit_after>jsio('from shared.javascript import Class, bind')
jsio('import fan.ui.Component')

exports = Class(fan.ui.Component, function(supr) {

	this._className = 'KeyboardFocus'
	this._borderWidth = 7

	this.init = function() {
		supr(this, 'init')
		this._on(document, 'keydown', bind(this, '_onKeyDown'))

		this._focusIndex = -1
		this._panelIndex = -1
		this._keyMap = {}

		var keys = this.keys,
			keyMap = this._keyMap

		keyMap[keys['j']] = bind(this, '_moveFocus', 1)
		keyMap[keys['k']] = bind(this, '_moveFocus', -1)
		keyMap[keys['tab']] = bind(this, '_movePanel', 1)
		keyMap[keys['`']] = bind(this, '_movePanel', -1)

		keyMap[keys['up arrow']] = keyMap[keys['j']]
		keyMap[keys['down arrow']] = keyMap[keys['k']]
		keyMap[keys['right arrow']] = keyMap[keys['tab']]
		keyMap[keys['left arrow']] = keyMap[keys['`']]

		keyMap[keys['enter']] = bind(this, '_selectFocusedItem')
	}

	this.grabFocus = function(uiComponent) { this._focusedUIComponent = uiComponent }
	this.releaseFocus = function(uiComponent) {
		if (uiComponent != this._focusedUIComponent) { return }
		delete this._focusedUIComponent
	}

	this._onKeyDown = function(e) {
		if (this._focusedUIComponent) { return }
		var callback = this._keyMap[e.keyCode]
		if (callback) {
			e.cancel()
			setTimeout(callback)
		}
	}

	this._movePanel = function(steps) {
		var newPanelIndex = this._panelIndex + steps
		if (newPanelIndex < 0 || newPanelIndex >= gPanels.length) { return }
		this._focusIndex = -1
		this._panelIndex = newPanelIndex
		this._moveFocus(1)
	}

	this._moveFocus = function(steps) {
		var panel = gPanels[this._panelIndex];
		if (!panel) { return }

		var newFocusIndex = this._focusIndex + steps,
			targets = panel.getElement().getElementsByClassName('fan-focusable')

		if (newFocusIndex < 0 || newFocusIndex >= targets.length) { return; }
		this._targetEl = targets[newFocusIndex]
		this._focusIndex = newFocusIndex
		this._showAt(this._targetEl)
	}

	this._selectFocusedItem = function() {
		var targetEl = this._targetEl
		if (!targetEl) { return }
		this._getFocusableComponent(targetEl).handleKeyboardSelect(targetEl)
	}

	this._createContent = function() {
		var borderWidth = this._borderWidth

		this._top = this._create({ className: 'piece top', parent: this._element })
		this._left = this._create({ className: 'piece left', parent: this._element })
		this._right = this._create({ className: 'piece right', parent: this._element })
		this._bottom = this._create({ className: 'piece bottom', parent: this._element })

		this._left.style.width = this._right.style.width = borderWidth + 'px'
		this._top.style.height = this._bottom.style.height = borderWidth + 'px'
	}

	this._showAt = function(targetEl) {
		var focusPadding = 2,
			borderWidth = this._borderWidth,
			layout = this.getLayout(targetEl)

		document.body.appendChild(this.getElement())

		layout.width += focusPadding * 2;
		layout.height += focusPadding * 2;
		layout.left -= focusPadding;
		layout.top -= focusPadding;

		this.layout(this._top, { top: layout.top - borderWidth, left: layout.left - borderWidth,
			width: layout.width + borderWidth });
		this.layout(this._bottom, { top: layout.top + layout.height, left: layout.left - borderWidth,
			width: layout.width + borderWidth });
		this.layout(this._left, { top: layout.top, left: layout.left - borderWidth, height: layout.height });
		this.layout(this._right, { top: layout.top, left: layout.left + layout.width - borderWidth,
			height: layout.height });
	}
})<|endoftext|>


<commit_before>"use strict";

const path = require("path");

const snapshot = require("jest-snapshot");

const relative = require("../relative.js");

expect.extend({
    toMatchLogspySnapshot(spy) {
        if(!spy || !spy.mock) {
            // eslint-disable-next-line no-console
            console.log({ spy, "spy.mock" : spy.mock });

            return {
                message : () => `Invalid spy passed to .toMatchLogspySnapshot()`,
                pass    : false,
            };
        }

        const calls = spy.mock.calls.map((call) =>
            call.map((arg) => (path.isAbsolute(arg) ?
                relative([ arg ])[0] :
                arg
            ))
        );

        return snapshot.toMatchSnapshot.call(this, calls);
    },
});
<commit_msg>fix(test-utils): don't try to check non-strings<commit_after>"use strict";

const path = require("path");

const snapshot = require("jest-snapshot");

const relative = require("../relative.js");

expect.extend({
    toMatchLogspySnapshot(spy) {
        if(!spy || !spy.mock) {
            // eslint-disable-next-line no-console
            console.log({ spy, "spy.mock" : spy.mock });

            return {
                message : () => `Invalid spy passed to .toMatchLogspySnapshot()`,
                pass    : false,
            };
        }

        const calls = spy.mock.calls.map((call) =>
            call.map((arg) => (typeof arg === "string" && path.isAbsolute(arg) ?
                relative([ arg ])[0] :
                arg
            ))
        );

        return snapshot.toMatchSnapshot.call(this, calls);
    },
});
<|endoftext|>


<commit_before>/**
 * Arrays of compound selectors and combinators that form a complex selector
 * when interleaved.
 *
 * @typedef {{
 *   compoundSelectors: !Array<string>,
 *   combinators: !Array<string>,
 * }}
 */
export let ComplexSelectorParts;

/**
 * @type {!Map<string, {end: string, matchNestedParens: boolean}>}
 */
const PARENS = new Map([
  ['(', {end: ')', matchNestedParens: true}],
  ['[', {end: ']', matchNestedParens: true}],
  ['"', {end: '"', matchNestedParens: false}],
  ["'", {end: "'", matchNestedParens: false}],
]);

/**
 * @param {string} str
 * @param {number} start
 * @param {!Array<string>} queryChars
 * @param {boolean} matchNestedParens
 * @return {number}
 */
const findNext = (str, start, queryChars, matchNestedParens = true) => {
  for (let i = start; i < str.length; i++) {
    if (str[i] === '\\' && i < str.length - 1 && str[i + 1] !== '\n') {
      // Skip escaped character.
      i++;
    } else if (queryChars.includes(str[i])) {
      return i;
    } else if (matchNestedParens && PARENS.has(str[i])) {
      const parenInfo = PARENS.get(str[i]);
      i = findNext(str, i + 1, [parenInfo.end], parenInfo.matchNestedParens);
      continue;
    }

    // Do nothing, let `i++` happen.
  }

  // Reached the end of the string without finding a final char.
  return str.length;
};

/**
 * @param {string} str
 * @return {!ComplexSelectorParts}
 */
const parseComplexSelector = (str) => {
  str = str.trim();

  /**
   * @type {!Array<string>}
   */
  const chunks = [];

  for (let i = 0; i < str.length; ) {
    const prev = chunks[chunks.length - 1];
    const nextIndex = findNext(str, i, [' ', '>', '~', '+']);
    const next = nextIndex === i ? str[i] : str.substring(i, nextIndex);

    if (['>', '+', '~'].includes(prev) && next === ' ') {
      // Do nothing.
    } else if (prev === ' ' && ['>', '+', '~'].includes(next)) {
      chunks[chunks.length - 1] = next;
    } else {
      chunks.push(next);
    }

    i = nextIndex + (nextIndex === i ? 1 : 0);
  }

  return {
    compoundSelectors: chunks.filter((x, i) => i % 2 === 0),
    combinators: chunks.filter((x, i) => i % 2 === 1),
  };
};

/**
 * @param {string} str
 * @return {!Array<!ComplexSelectorParts>}
 */
export const parseSelectorList = (str) => {
  const results = [];

  for (let i = 0; i < str.length; ) {
    const next = findNext(str, i, [',']);
    results.push(parseComplexSelector(str.substring(i, next)));
    i = next + 1;
  }

  return results;
};
<commit_msg>Fix a bug where consecutive whitespace was not being collapsed.<commit_after>/**
 * Arrays of compound selectors and combinators that form a complex selector
 * when interleaved.
 *
 * @typedef {{
 *   compoundSelectors: !Array<string>,
 *   combinators: !Array<string>,
 * }}
 */
export let ComplexSelectorParts;

/**
 * @type {!Map<string, {end: string, matchNestedParens: boolean}>}
 */
const PARENS = new Map([
  ['(', {end: ')', matchNestedParens: true}],
  ['[', {end: ']', matchNestedParens: true}],
  ['"', {end: '"', matchNestedParens: false}],
  ["'", {end: "'", matchNestedParens: false}],
]);

/**
 * @param {string} str
 * @param {number} start
 * @param {!Array<string>} queryChars
 * @param {boolean} matchNestedParens
 * @return {number}
 */
const findNext = (str, start, queryChars, matchNestedParens = true) => {
  for (let i = start; i < str.length; i++) {
    if (str[i] === '\\' && i < str.length - 1 && str[i + 1] !== '\n') {
      // Skip escaped character.
      i++;
    } else if (queryChars.includes(str[i])) {
      return i;
    } else if (matchNestedParens && PARENS.has(str[i])) {
      const parenInfo = PARENS.get(str[i]);
      i = findNext(str, i + 1, [parenInfo.end], parenInfo.matchNestedParens);
      continue;
    }

    // Do nothing, let `i++` happen.
  }

  // Reached the end of the string without finding a final char.
  return str.length;
};

/**
 * @param {string} str
 * @return {!ComplexSelectorParts}
 */
const parseComplexSelector = (str) => {
  str = str.trim();

  /**
   * @type {!Array<string>}
   */
  const chunks = [];

  for (let i = 0; i < str.length; ) {
    const prev = chunks[chunks.length - 1];
    const nextIndex = findNext(str, i, [' ', '>', '~', '+']);
    const next = nextIndex === i ? str[i] : str.substring(i, nextIndex);

    if ([' ', '>', '+', '~'].includes(prev) && next === ' ') {
      // Do nothing.
    } else if (prev === ' ' && ['>', '+', '~'].includes(next)) {
      chunks[chunks.length - 1] = next;
    } else {
      chunks.push(next);
    }

    i = nextIndex + (nextIndex === i ? 1 : 0);
  }

  return {
    compoundSelectors: chunks.filter((x, i) => i % 2 === 0),
    combinators: chunks.filter((x, i) => i % 2 === 1),
  };
};

/**
 * @param {string} str
 * @return {!Array<!ComplexSelectorParts>}
 */
export const parseSelectorList = (str) => {
  const results = [];

  for (let i = 0; i < str.length; ) {
    const next = findNext(str, i, [',']);
    results.push(parseComplexSelector(str.substring(i, next)));
    i = next + 1;
  }

  return results;
};
<|endoftext|>


<commit_before>/* <!-- Asynchronous Baidu Analytics snippet --> */
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "//hm.baidu.com/hm.js?11224c4b3c0923fa6de6e431325fe387";
  var s = document.getElementsByTagName("script")[0];
  s.parentNode.insertBefore(hm, s);
})();

/* <!-- Aysnchronous CNZZ Analytics  -->  */
(function() {
  var cnzz_protocol = (("https:" == document.location.protocol) ? "https://" : "http://");
  document.write(unescape("%3Cspan id='cnzz_stat_icon_1256833726'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s95.cnzz.com/z_stat.php%3Fid%3D1256833726' type='text/javascript'%3E%3C/script%3E"));
})();

/* <!-- Asynchronous Google Analytics snippet --> */
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-39438576-1', 'auto');
ga('require', 'linkid', 'linkid.js');
ga('send', 'pageview');

<commit_msg>make it async<commit_after>/* <!-- Asynchronous Baidu Analytics snippet --> */
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.async=1;
  hm.src = "//hm.baidu.com/hm.js?11224c4b3c0923fa6de6e431325fe387";
  var s = document.getElementsByTagName("script")[0];
  s.parentNode.insertBefore(hm, s);
})();

/* <!-- Aysnchronous CNZZ Analytics  -->  */
(function() {
  var cnzz_protocol = (("https:" == document.location.protocol) ? "https://" : "http://");
  document.write(unescape("%3Cspan id='cnzz_stat_icon_1256833726'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s95.cnzz.com/z_stat.php%3Fid%3D1256833726' type='text/javascript'%3E%3C/script%3E"));
})();
(function(document) {
  /* <!-- Aysnchronous CNZZ Analytics  -->  */
  var hm = document.createElement("script");
  hm.async=1;
  hm.src = "//s95.cnzz.com/z_stat.php?id=1256833726&web_id=1256833726";
  var s = document.getElementsByTagName("script")[0];
  s.parentNode.insertBefore(hm, s);
})(document);

/* <!-- Asynchronous Google Analytics snippet --> */
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-39438576-1', 'auto');
ga('require', 'linkid', 'linkid.js');
ga('send', 'pageview');

<|endoftext|>


<commit_before>var NATIVE = require('./native')
var ERRORS = require('./errors')

function _Buffer (value) {
  return Buffer.isBuffer(value)
}

function Hex (value) {
  return typeof value === 'string' && /^([0-9a-f]{2})+$/i.test(value)
}

function _LengthN (type, length) {
  var name = type.toJSON()

  function Length (value) {
    if (!type(value)) return false
    if (value.length === length) return true

    throw ERRORS.tfCustomError(name + '(Length: ' + length + ')', name + '(Length: ' + value.length + ')')
  }
  Length.toJSON = function () { return name }

  return Length
}

var _ArrayN = _LengthN.bind(null, NATIVE.Array)
var _BufferN = _LengthN.bind(null, _Buffer)
var _HexN = _LengthN.bind(null, Hex)
var _StringN = _LengthN.bind(null, NATIVE.String)

function Range (a, b, f) {
  f = f || NATIVE.Number
  function _range (value, strict) {
    return f(value) && (value > a) && (value < b)
  }
  _range.toJSON = function () {
    return `${f.toJSON()} between [${a}, ${b}]`
  }
  return _range
}

var UINT53_MAX = Math.pow(2, 53) - 1

function Finite (value) {
  return typeof value === 'number' && isFinite(value)
}
function Int8 (value) { return ((value << 24) >> 24) === value }
function Int16 (value) { return ((value << 16) >> 16) === value }
function Int32 (value) { return (value | 0) === value }
function UInt8 (value) { return (value & 0xff) === value }
function UInt16 (value) { return (value & 0xffff) === value }
function UInt32 (value) { return (value >>> 0) === value }
function UInt53 (value) {
  return typeof value === 'number' &&
    value >= 0 &&
    value <= UINT53_MAX &&
    Math.floor(value) === value
}

var types = {
  ArrayN: _ArrayN,
  Buffer: _Buffer,
  BufferN: _BufferN,
  Finite: Finite,
  Hex: Hex,
  HexN: _HexN,
  Int8: Int8,
  Int16: Int16,
  Int32: Int32,
  Range: Range,
  StringN: _StringN,
  UInt8: UInt8,
  UInt16: UInt16,
  UInt32: UInt32,
  UInt53: UInt53
}

for (var typeName in types) {
  types[typeName].toJSON = function (t) {
    return t
  }.bind(null, typeName)
}

module.exports = types
<commit_msg>pass strict through<commit_after>var NATIVE = require('./native')
var ERRORS = require('./errors')

function _Buffer (value) {
  return Buffer.isBuffer(value)
}

function Hex (value) {
  return typeof value === 'string' && /^([0-9a-f]{2})+$/i.test(value)
}

function _LengthN (type, length) {
  var name = type.toJSON()

  function Length (value) {
    if (!type(value)) return false
    if (value.length === length) return true

    throw ERRORS.tfCustomError(name + '(Length: ' + length + ')', name + '(Length: ' + value.length + ')')
  }
  Length.toJSON = function () { return name }

  return Length
}

var _ArrayN = _LengthN.bind(null, NATIVE.Array)
var _BufferN = _LengthN.bind(null, _Buffer)
var _HexN = _LengthN.bind(null, Hex)
var _StringN = _LengthN.bind(null, NATIVE.String)

function Range (a, b, f) {
  f = f || NATIVE.Number
  function _range (value, strict) {
    return f(value, strict) && (value > a) && (value < b)
  }
  _range.toJSON = function () {
    return `${f.toJSON()} between [${a}, ${b}]`
  }
  return _range
}

var UINT53_MAX = Math.pow(2, 53) - 1

function Finite (value) {
  return typeof value === 'number' && isFinite(value)
}
function Int8 (value) { return ((value << 24) >> 24) === value }
function Int16 (value) { return ((value << 16) >> 16) === value }
function Int32 (value) { return (value | 0) === value }
function UInt8 (value) { return (value & 0xff) === value }
function UInt16 (value) { return (value & 0xffff) === value }
function UInt32 (value) { return (value >>> 0) === value }
function UInt53 (value) {
  return typeof value === 'number' &&
    value >= 0 &&
    value <= UINT53_MAX &&
    Math.floor(value) === value
}

var types = {
  ArrayN: _ArrayN,
  Buffer: _Buffer,
  BufferN: _BufferN,
  Finite: Finite,
  Hex: Hex,
  HexN: _HexN,
  Int8: Int8,
  Int16: Int16,
  Int32: Int32,
  Range: Range,
  StringN: _StringN,
  UInt8: UInt8,
  UInt16: UInt16,
  UInt32: UInt32,
  UInt53: UInt53
}

for (var typeName in types) {
  types[typeName].toJSON = function (t) {
    return t
  }.bind(null, typeName)
}

module.exports = types
<|endoftext|>


<commit_before>var join = require('path').join,
    fs = require('fs'),
    assert = require('assert'),
    async = require('async'),
    mkdirp = require('mkdirp'),
    lwip = require('../../'),
    utils = require('../utils'),
    imgs = require('../imgs');

var tmpDir = join(__dirname, '../results'),
    outpathJpeg = join(tmpDir, 'stress.jpg'),
    outpathPng = join(tmpDir, 'stress.png');

describe('stress tests', function() {

    this.timeout(120000); // 120 seconds per test

    before(function(done) {
        mkdirp(tmpDir, done);
    });

    describe('open image 300 times (in parallel) and save to disk as jpeg', function() {
        it('should succeed', function(done) {
            async.times(300, function(i, done) {
                lwip.open(imgs.png.rgb, 'png', function(err, image) {
                    if (err) return done(err);
                    image.writeFile(outpathJpeg, 'jpeg', {
                        quality: 50
                    }, done);
                });
            }, done);
        });
    });

    describe('open image 100 times (in parallel) and save to disk as png (high compression, interlaced)', function() {
        it('should succeed', function(done) {
            async.times(100, function(i, done) {
                lwip.open(imgs.jpg.rgb, 'jpeg', function(err, image) {
                    if (err) return done(err);
                    image.writeFile(outpathPng, 'png', {
                        compression: 'high',
                        interlaced: true
                    }, done);
                });
            }, done);
        });
    });

    describe('open image 300 times (in parallel) and save to disk as png (fast compression, not interlaced)', function() {
        it('should succeed', function(done) {
            async.times(300, function(i, done) {
                lwip.open(imgs.jpg.rgb, 'jpeg', function(err, image) {
                    if (err) return done(err);
                    image.writeFile(outpathPng, 'png', {
                        compression: 'fast',
                        interlaced: false
                    }, done);
                });
            }, done);
        });
    });

    describe('7 random manipulations for 50 images (in parallel)', function() {
        it('should succeed', function(done) {
            async.times(50, function(i, done) {
                lwip.open(imgs.jpg.rgb, 'jpeg', function(err, image) {
                    if (err) return done(err);
                    var batch = image.batch();
                    var ops = utils.generateRandomBatch(batch, 7);
                    batch.writeFile(join(tmpDir, 'stress-rnd-' + i + '.jpg'), 'jpeg', {
                        quality: 50
                    }, function(err) {
                        if (err) return done(err);
                        var data = ops.join('\n');
                        fs.writeFile(join(tmpDir, 'stress-rnd-' + i + '.txt'), data, done);
                    });
                });
            }, done);
        });
    });

    describe('rotate an image 30 times (up to 90degs) (1)', function() {
        it('should succeed', function(done) {
            var a = 3;
            lwip.open(imgs.jpg.rgb, 'jpeg', function(err, image) {
                if (err) return done(err);
                async.timesSeries(50, function(i, done) {
                    image.rotate(a, utils.getRandomColor(), done);
                }, function(err) {
                    if (err) return done(err);
                    image.writeFile(outpathJpeg, 'jpeg', {
                        quality: 90
                    }, done);
                });
            });
        });
    });

    describe('rotate an image 30 times (up to 90degs) (2)', function() {
        it('should succeed', function(done) {
            var a = 3;
            lwip.open(imgs.png.trans, 'png', function(err, image) {
                if (err) return done(err);
                async.timesSeries(50, function(i, done) {
                    image.rotate(a, utils.getRandomColor(), done);
                }, function(err) {
                    if (err) return done(err);
                    image.writeFile(outpathPng, 'png', {
                        compression: 'fast',
                        interlaced: false
                    }, done);
                });
            });
        });
    });

    describe('25 random manipulations on one image (1)', function() {
        it('should succeed', function(done) {
            lwip.open(imgs.png.rgb, 'png', function(err, image) {
                if (err) return done(err);
                var batch = image.batch();
                var ops = utils.generateRandomBatch(batch, 25);
                batch.writeFile(join(tmpDir, 'stress-25rnd.jpg'), 'jpeg', {
                    quality: 85
                }, function(err) {
                    if (err) return done(err);
                    var data = ops.join('\n');
                    fs.writeFile(join(tmpDir, 'stress-25rnd.jpg.txt'), data, done);
                });
            });
        });
    });

    describe('25 random manipulations on one image (2)', function() {
        it('should succeed', function(done) {
            lwip.open(imgs.png.trans, 'png', function(err, image) {
                if (err) return done(err);
                var batch = image.batch();
                var ops = utils.generateRandomBatch(batch, 25);
                batch.writeFile(join(tmpDir, 'stress-25rnd.png'), 'png', {
                    compression: 'fast',
                    interlaced: false
                }, function(err) {
                    if (err) return done(err);
                    var data = ops.join('\n');
                    fs.writeFile(join(tmpDir, 'stress-25rnd.png.txt'), data, done);
                });
            });
        });
    });

});
<commit_msg>fixes stress tests<commit_after>var join = require('path').join,
    fs = require('fs'),
    assert = require('assert'),
    async = require('async'),
    mkdirp = require('mkdirp'),
    lwip = require('../../'),
    utils = require('../utils'),
    imgs = require('../imgs');

var tmpDir = join(__dirname, '../results'),
    outpathJpeg = join(tmpDir, 'stress.jpg'),
    outpathPng = join(tmpDir, 'stress.png');

describe('stress tests', function() {

    this.timeout(120000); // 120 seconds per test

    before(function(done) {
        mkdirp(tmpDir, done);
    });

    describe('open image 300 times (in parallel) and save to disk as jpeg', function() {
        it('should succeed', function(done) {
            async.times(300, function(i, done) {
                lwip.open(imgs.png.rgb, 'png', function(err, image) {
                    if (err) return done(err);
                    image.writeFile(outpathJpeg, 'jpeg', {
                        quality: 50
                    }, done);
                });
            }, done);
        });
    });

    describe('open image 100 times (in parallel) and save to disk as png (high compression, interlaced)', function() {
        it('should succeed', function(done) {
            async.times(100, function(i, done) {
                lwip.open(imgs.jpg.rgb, 'jpeg', function(err, image) {
                    if (err) return done(err);
                    image.writeFile(outpathPng, 'png', {
                        compression: 'high',
                        interlaced: true
                    }, done);
                });
            }, done);
        });
    });

    describe('open image 300 times (in parallel) and save to disk as png (fast compression, not interlaced)', function() {
        it('should succeed', function(done) {
            async.times(300, function(i, done) {
                lwip.open(imgs.jpg.rgb, 'jpeg', function(err, image) {
                    if (err) return done(err);
                    image.writeFile(outpathPng, 'png', {
                        compression: 'fast',
                        interlaced: false
                    }, done);
                });
            }, done);
        });
    });

    describe('7 random manipulations for 50 images (in parallel)', function() {
        it('should succeed', function(done) {
            async.times(50, function(i, done) {
                lwip.open(imgs.jpg.rgb, 'jpeg', function(err, image) {
                    if (err) return done(err);
                    var batch = image.batch();
                    var ops = utils.generateRandomBatch(batch, 7);
                    batch.writeFile(join(tmpDir, 'stress-rnd-' + i + '.jpg'), 'jpeg', {
                        quality: 50
                    }, function(err) {
                        if (err) return done(err);
                        var data = ops.join('\n');
                        fs.writeFile(join(tmpDir, 'stress-rnd-' + i + '.txt'), data, done);
                    });
                });
            }, done);
        });
    });

    describe('rotate an image 30 times (up to 90degs) (1)', function() {
        it('should succeed', function(done) {
            var a = 3;
            lwip.open(imgs.jpg.rgb, 'jpeg', function(err, image) {
                if (err) return done(err);
                async.timesSeries(90 / a, function(i, done) {
                    image.rotate(a, utils.getRandomColor(), done);
                }, function(err) {
                    if (err) return done(err);
                    image.writeFile(outpathJpeg, 'jpeg', {
                        quality: 90
                    }, done);
                });
            });
        });
    });

    describe('rotate an image 30 times (up to 90degs) (2)', function() {
        it('should succeed', function(done) {
            var a = 3;
            lwip.open(imgs.png.trans, 'png', function(err, image) {
                if (err) return done(err);
                async.timesSeries(90 / a, function(i, done) {
                    image.rotate(a, utils.getRandomColor(), done);
                }, function(err) {
                    if (err) return done(err);
                    image.writeFile(outpathPng, 'png', {
                        compression: 'fast',
                        interlaced: false
                    }, done);
                });
            });
        });
    });

    describe('25 random manipulations on one image (1)', function() {
        it('should succeed', function(done) {
            lwip.open(imgs.png.rgb, 'png', function(err, image) {
                if (err) return done(err);
                var batch = image.batch();
                var ops = utils.generateRandomBatch(batch, 25);
                batch.writeFile(join(tmpDir, 'stress-25rnd.jpg'), 'jpeg', {
                    quality: 85
                }, function(err) {
                    if (err) return done(err);
                    var data = ops.join('\n');
                    fs.writeFile(join(tmpDir, 'stress-25rnd.jpg.txt'), data, done);
                });
            });
        });
    });

    describe('25 random manipulations on one image (2)', function() {
        it('should succeed', function(done) {
            lwip.open(imgs.png.trans, 'png', function(err, image) {
                if (err) return done(err);
                var batch = image.batch();
                var ops = utils.generateRandomBatch(batch, 25);
                batch.writeFile(join(tmpDir, 'stress-25rnd.png'), 'png', {
                    compression: 'fast',
                    interlaced: false
                }, function(err) {
                    if (err) return done(err);
                    var data = ops.join('\n');
                    fs.writeFile(join(tmpDir, 'stress-25rnd.png.txt'), data, done);
                });
            });
        });
    });

});
<|endoftext|>