<commit_before>/**
 * @class CM_FormField_Suggest
 * @extends CM_FormField_Abstract
 */
var CM_FormField_Suggest = CM_FormField_Abstract.extend({
	_class: 'CM_FormField_Suggest',

	$input: null,

	ready: function() {
		var field = this;
		var cardinality = this.getOption("cardinality");
		this.$input = this.$('input[type="text"]');

		this.$input.select2({
			tags: null,
			dropdownCssClass: this.$el.attr('class'),
			allowClear: true,
			openOnEnter: false,
			maximumSelectionSize: cardinality,
			formatResult: this._formatItem,
			formatSelection: this._formatItemSelected,
			escapeMarkup: function(item) {
				return item;
			},
			query: function(options) {
				field.ajax('getSuggestions', {'term': options.term, 'options': field.getOptions()}, {
					success: function(results) {
						options.callback({
							results: results
						});
					}
				});
			},
			createSearchChoice: function(term, data) {
				if (field.getOption("enableChoiceCreate")) {
					if ($(data).filter(function() {
						return this.name.localeCompare(term) === 0;
					}).length === 0) {
						return {id: term, name: term, new: 1};
					}
				}
			},
			formatSelectionTooBig: null
		}).select2('data', this._getPrePopulateValue());

		this.$('.select2-container').removeClass('textinput');
		this.$('.select2-choices').addClass('textinput');

		this.$input.on("change", function(e) {
			if (!_.isUndefined(e.added)) {
				var items = field.$input.select2("data");
				if (cardinality && items.length > cardinality) {
					items.pop();
					field.$input.select2('data', items);
					field.$el.popover('destroy').popoverInfo(cm.language.get('You can only select {$cardinality} items.', {'cardinality': cardinality}), 2000);
					return false;
				}
				field.onAdd(e.added);
				field.trigger('add', e.added);
			}
			if (!_.isUndefined(e.removed)) {
				field.onDelete(e.removed);
				field.trigger('delete', e.removed);
			}
			field.onChange(field.$input.select2("data"));
		});

		if (1 == cardinality) {
			this.$input.on("open", function(e) {
				field.$input.select2('data', null);
			});
		}

		this.getForm().$().bind("reset", function() {
			field.$input.select2('data', null);
		});

		this.onChange(this.$input.select2("data"));
	},

	/**
	 * @param {Object} item
	 */
	onAdd: function(item) {
	},

	/**
	 * @param {Object} item
	 */
	onDelete: function(item) {
	},

	/**
	 * @param {Object[]} items
	 */
	onChange: function(items) {
	},

	blur: function() {
		this.setTimeout(function() {
			this.$('input.select2-input').blur();
		}, 10);
	},

	/**
	 * @return {Object[]|null}
	 */
	_getPrePopulateValue: function() {
		var prePopulate = this.$input.attr('data-prePopulate');
		if (prePopulate && prePopulate.length) {
			return JSON.parse(prePopulate);
		}
		return null;
	},

	/**
	 * @param {Object} item
	 * @return String
	 */
	_formatItem: function(item) {
		var cssClass = 'suggestItem';
		if (item.class) {
			cssClass += ' ' + _.escape(item.class);
		}
		var output = '
';
		if (item.img) {
			output += '

';
		}
		output += '' + _.escape(item.name) + '';
		if (item.description) {
			output += '' + _.escape(item.description) + '';
		}
		output += '
';
		return output;
	},

	/**
	 * @param {Object} item
	 * @return String
	 */
	_formatItemSelected: function(item) {
		var output = _.escape(item.name);
		if (item.img) {
			output = '

' + output;
		}
		return output;
	}
});
<commit_msg>fix naming bug in CM_FormField_Suggest<commit_after>/**
 * @class CM_FormField_Suggest
 * @extends CM_FormField_Abstract
 */
var CM_FormField_Suggest = CM_FormField_Abstract.extend({
	_class: 'CM_FormField_Suggest',

	$input: null,

	ready: function() {
		var field = this;
		var cardinality = this.getOption("cardinality");
		this.$input = this.$('input[type="text"]');

		this.$input.select2({
			tags: null,
			dropdownCssClass: this.$el.attr('class'),
			allowClear: true,
			openOnEnter: false,
			maximumSelectionSize: cardinality,
			formatResult: this._formatItem,
			formatSelection: this._formatItemSelected,
			escapeMarkup: function(item) {
				return item;
			},
			query: function(options) {
				field.ajax('getSuggestions', {'term': options.term, 'options': field.getOptions()}, {
					success: function(results) {
						options.callback({
							results: results
						});
					}
				});
			},
			createSearchChoice: function(term, data) {
				if (field.getOption("enableChoiceCreate")) {
					if ($(data).filter(function() {
						return this.name.localeCompare(term) === 0;
					}).length === 0) {
						return {'id': term, 'name': term, 'new': 1};
					}
				}
			},
			formatSelectionTooBig: null
		}).select2('data', this._getPrePopulateValue());

		this.$('.select2-container').removeClass('textinput');
		this.$('.select2-choices').addClass('textinput');

		this.$input.on("change", function(e) {
			if (!_.isUndefined(e.added)) {
				var items = field.$input.select2("data");
				if (cardinality && items.length > cardinality) {
					items.pop();
					field.$input.select2('data', items);
					field.$el.popover('destroy').popoverInfo(cm.language.get('You can only select {$cardinality} items.', {'cardinality': cardinality}), 2000);
					return false;
				}
				field.onAdd(e.added);
				field.trigger('add', e.added);
			}
			if (!_.isUndefined(e.removed)) {
				field.onDelete(e.removed);
				field.trigger('delete', e.removed);
			}
			field.onChange(field.$input.select2("data"));
		});

		if (1 == cardinality) {
			this.$input.on("open", function(e) {
				field.$input.select2('data', null);
			});
		}

		this.getForm().$().bind("reset", function() {
			field.$input.select2('data', null);
		});

		this.onChange(this.$input.select2("data"));
	},

	/**
	 * @param {Object} item
	 */
	onAdd: function(item) {
	},

	/**
	 * @param {Object} item
	 */
	onDelete: function(item) {
	},

	/**
	 * @param {Object[]} items
	 */
	onChange: function(items) {
	},

	blur: function() {
		this.setTimeout(function() {
			this.$('input.select2-input').blur();
		}, 10);
	},

	/**
	 * @return {Object[]|null}
	 */
	_getPrePopulateValue: function() {
		var prePopulate = this.$input.attr('data-prePopulate');
		if (prePopulate && prePopulate.length) {
			return JSON.parse(prePopulate);
		}
		return null;
	},

	/**
	 * @param {Object} item
	 * @return String
	 */
	_formatItem: function(item) {
		var cssClass = 'suggestItem';
		if (item['class']) {
			cssClass += ' ' + _.escape(item['class']);
		}
		var output = '
';
		if (item['img']) {
			output += '

';
		}
		output += '' + _.escape(item['name']) + '';
		if (item['description']) {
			output += '' + _.escape(item['description']) + '';
		}
		output += '
';
		return output;
	},

	/**
	 * @param {Object} item
	 * @return String
	 */
	_formatItemSelected: function(item) {
		var output = _.escape(item['name']);
		if (item['img']) {
			output = '

' + output;
		}
		return output;
	}
});
<|endoftext|>


<commit_before>const fs = require('fs');
const path = require('path');
const { spawnSync } = require('child_process');

function getNextStep(content, pos, stop) {
    while (pos < content.length && content[pos] !== stop &&
           (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) {
        pos += 1;
    }
    if (pos >= content.length) {
        return null;
    }
    if (content[pos] !== stop) {
        return pos * -1;
    }
    return pos;
}

// Stupid function extractor based on indent. Doesn't support block
// comments. If someone puts a ' or an " in a block comment this
// will blow up. Template strings are not tested and might also be
// broken.
function extractFunction(content, functionName) {
    var indent = 0;
    var splitter = "function " + functionName + "(";

    while (true) {
        var start = content.indexOf(splitter);
        if (start === -1) {
            break;
        }
        var pos = start;
        while (pos < content.length && content[pos] !== ')') {
            pos += 1;
        }
        if (pos >= content.length) {
            break;
        }
        pos = getNextStep(content, pos + 1, '{');
        if (pos === null) {
            break;
        } else if (pos < 0) {
            content = content.slice(-pos);
            continue;
        }
        while (pos < content.length) {
            // Eat single-line comments
            if (content[pos] === '/' && pos > 0 && content[pos-1] === '/') {
                do {
                    pos += 1;
                } while (pos < content.length && content[pos] !== '\n');

            // Eat quoted strings
            } else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") {
                var stop = content[pos];
                var is_escaped = false;
                do {
                    if (content[pos] === '\\') {
                        pos += 2;
                    } else {
                        pos += 1;
                    }
                } while (pos < content.length &&
                         (content[pos] !== stop || content[pos - 1] === '\\'));

            // Otherwise, check for indent
            } else if (content[pos] === '{') {
                indent += 1;
            } else if (content[pos] === '}') {
                indent -= 1;
                if (indent === 0) {
                    return content.slice(start, pos + 1);
                }
            }
            pos += 1;
        }
        content = content.slice(start + 1);
    }
    return null;
}

// Stupid function extractor for array.
function extractArrayVariable(content, arrayName) {
    var splitter = "var " + arrayName;
    while (true) {
        var start = content.indexOf(splitter);
        if (start === -1) {
            break;
        }
        var pos = getNextStep(content, start, '=');
        if (pos === null) {
            break;
        } else if (pos < 0) {
            content = content.slice(-pos);
            continue;
        }
        pos = getNextStep(content, pos, '[');
        if (pos === null) {
            break;
        } else if (pos < 0) {
            content = content.slice(-pos);
            continue;
        }
        while (pos < content.length) {
            if (content[pos] === '"' || content[pos] === "'") {
                var stop = content[pos];
                do {
                    if (content[pos] === '\\') {
                        pos += 2;
                    } else {
                        pos += 1;
                    }
                } while (pos < content.length &&
                         (content[pos] !== stop || content[pos - 1] === '\\'));
            } else if (content[pos] === ']' &&
                       pos + 1 < content.length &&
                       content[pos + 1] === ';') {
                return content.slice(start, pos + 2);
            }
            pos += 1;
        }
        content = content.slice(start + 1);
    }
    return null;
}

// Stupid function extractor for variable.
function extractVariable(content, varName) {
    var splitter = "var " + varName;
    while (true) {
        var start = content.indexOf(splitter);
        if (start === -1) {
            break;
        }
        var pos = getNextStep(content, start, '=');
        if (pos === null) {
            break;
        } else if (pos < 0) {
            content = content.slice(-pos);
            continue;
        }
        while (pos < content.length) {
            if (content[pos] === '"' || content[pos] === "'") {
                var stop = content[pos];
                do {
                    if (content[pos] === '\\') {
                        pos += 2;
                    } else {
                        pos += 1;
                    }
                } while (pos < content.length &&
                         (content[pos] !== stop || content[pos - 1] === '\\'));
            } else if (content[pos] === ';') {
                return content.slice(start, pos + 1);
            }
            pos += 1;
        }
        content = content.slice(start + 1);
    }
    return null;
}

function loadContent(content) {
    var Module = module.constructor;
    var m = new Module();
    m._compile(content, "tmp.js");
    m.exports.ignore_order = content.indexOf("\n// ignore-order\n") !== -1 ||
        content.startsWith("// ignore-order\n");
    m.exports.exact_check = content.indexOf("\n// exact-check\n") !== -1 ||
        content.startsWith("// exact-check\n");
    m.exports.should_fail = content.indexOf("\n// should-fail\n") !== -1 ||
        content.startsWith("// should-fail\n");
    return m.exports;
}

function readFile(filePath) {
    return fs.readFileSync(filePath, 'utf8');
}

function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) {
    var content = '';
    for (var i = 0; i < thingsToLoad.length; ++i) {
        var tmp = funcToCall(fileContent, thingsToLoad[i]);
        if (tmp === null) {
            console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
            process.exit(1);
        }
        content += tmp;
        content += 'exports.' + thingsToLoad[i] + ' = ' + thingsToLoad[i] + ';';
    }
    return content;
}

function lookForEntry(entry, data) {
    for (var i = 0; i < data.length; ++i) {
        var allGood = true;
        for (var key in entry) {
            if (!entry.hasOwnProperty(key)) {
                continue;
            }
            var value = data[i][key];
            // To make our life easier, if there is a "parent" type, we add it to the path.
            if (key === 'path' && data[i]['parent'] !== undefined) {
                if (value.length > 0) {
                    value += '::' + data[i]['parent']['name'];
                } else {
                    value = data[i]['parent']['name'];
                }
            }
            if (value !== entry[key]) {
                allGood = false;
                break;
            }
        }
        if (allGood === true) {
            return i;
        }
    }
    return null;
}

function load_files(out_folder, crate) {
    var mainJs = readFile(out_folder + "/main.js");
    var ALIASES = readFile(out_folder + "/aliases.js");
    var searchIndex = readFile(out_folder + "/search-index.js").split("\n");
    if (searchIndex[searchIndex.length - 1].length === 0) {
        searchIndex.pop();
    }
    searchIndex.pop();
    searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;');
    finalJS = "";

    var arraysToLoad = ["itemTypes"];
    var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS",
                           "GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA",
                           "TY_PRIMITIVE", "TY_KEYWORD",
                           "levenshtein_row2"];
    // execQuery first parameter is built in getQuery (which takes in the search input).
    // execQuery last parameter is built in buildIndex.
    // buildIndex requires the hashmap from search-index.
    var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
                           "getQuery", "buildIndex", "execQuery", "execSearch"];

    finalJS += 'window = { "currentCrate": "' + crate + '" };\n';
    finalJS += 'var rootPath = "../";\n';
    finalJS += ALIASES;
    finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
    finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
    finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs);

    var loaded = loadContent(finalJS);
    return [loaded, loaded.buildIndex(searchIndex.searchIndex)];
}

function main(argv) {
    if (argv.length < 4) {
        console.error("USAGE: node tester.js OUT_FOLDER [TESTS]");
        return 1;
    }
    if (argv[2].substr(-1) !== "/") {
        argv[2] += "/";
    }
    const out_folder = argv[2];

    var errors = 0;

    for (var j = 3; j < argv.length; ++j) {
        const test_file = argv[j];
        const test_name = path.basename(test_file, ".js");

        process.stdout.write('Checking "' + test_name + '" ... ');
        if (!fs.existsSync(test_file)) {
            errors += 1;
            console.error("FAILED");
            console.error("==> Missing '" + test_name + ".js' file...");
            continue;
        }

        const test_out_folder = out_folder + test_name;

        var [loaded, index] = load_files(test_out_folder, test_name);
        var loadedFile = loadContent(readFile(test_file) +
                               'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
        const expected = loadedFile.EXPECTED;
        const query = loadedFile.QUERY;
        const filter_crate = loadedFile.FILTER_CRATE;
        const ignore_order = loadedFile.ignore_order;
        const exact_check = loadedFile.exact_check;
        const should_fail = loadedFile.should_fail;
        var results = loaded.execSearch(loaded.getQuery(query), index);
        var error_text = [];
        for (var key in expected) {
            if (!expected.hasOwnProperty(key)) {
                continue;
            }
            if (!results.hasOwnProperty(key)) {
                error_text.push('==> Unknown key "' + key + '"');
                break;
            }
            var entry = expected[key];
            var prev_pos = -1;
            for (var i = 0; i < entry.length; ++i) {
                var entry_pos = lookForEntry(entry[i], results[key]);
                if (entry_pos === null) {
                    error_text.push("==> Result not found in '" + key + "': '" +
                                    JSON.stringify(entry[i]) + "'");
                } else if (exact_check === true && prev_pos + 1 !== entry_pos) {
                    error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " +
                                    "expected '" + JSON.stringify(entry[i]) + "' but found '" +
                                    JSON.stringify(results[key][i]) + "'");
                } else if (ignore_order === false && entry_pos < prev_pos) {
                    error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " +
                                    " before '" + JSON.stringify(results[key][entry_pos]) + "'");
                } else {
                    prev_pos = entry_pos;
                }
            }
        }
        if (error_text.length === 0 && should_fail === true) {
            errors += 1;
            console.error("FAILED");
            console.error("==> Test was supposed to fail but all items were found...");
        } else if (error_text.length !== 0 && should_fail === false) {
            errors += 1;
            console.error("FAILED");
            console.error(error_text.join("\n"));
        } else {
            console.log("OK");
        }
    }
    return errors;
}

process.exit(main(process.argv));
<commit_msg>Add missing variable to load in non-std tester as well<commit_after>const fs = require('fs');
const path = require('path');
const { spawnSync } = require('child_process');

function getNextStep(content, pos, stop) {
    while (pos < content.length && content[pos] !== stop &&
           (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) {
        pos += 1;
    }
    if (pos >= content.length) {
        return null;
    }
    if (content[pos] !== stop) {
        return pos * -1;
    }
    return pos;
}

// Stupid function extractor based on indent. Doesn't support block
// comments. If someone puts a ' or an " in a block comment this
// will blow up. Template strings are not tested and might also be
// broken.
function extractFunction(content, functionName) {
    var indent = 0;
    var splitter = "function " + functionName + "(";

    while (true) {
        var start = content.indexOf(splitter);
        if (start === -1) {
            break;
        }
        var pos = start;
        while (pos < content.length && content[pos] !== ')') {
            pos += 1;
        }
        if (pos >= content.length) {
            break;
        }
        pos = getNextStep(content, pos + 1, '{');
        if (pos === null) {
            break;
        } else if (pos < 0) {
            content = content.slice(-pos);
            continue;
        }
        while (pos < content.length) {
            // Eat single-line comments
            if (content[pos] === '/' && pos > 0 && content[pos-1] === '/') {
                do {
                    pos += 1;
                } while (pos < content.length && content[pos] !== '\n');

            // Eat quoted strings
            } else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") {
                var stop = content[pos];
                var is_escaped = false;
                do {
                    if (content[pos] === '\\') {
                        pos += 2;
                    } else {
                        pos += 1;
                    }
                } while (pos < content.length &&
                         (content[pos] !== stop || content[pos - 1] === '\\'));

            // Otherwise, check for indent
            } else if (content[pos] === '{') {
                indent += 1;
            } else if (content[pos] === '}') {
                indent -= 1;
                if (indent === 0) {
                    return content.slice(start, pos + 1);
                }
            }
            pos += 1;
        }
        content = content.slice(start + 1);
    }
    return null;
}

// Stupid function extractor for array.
function extractArrayVariable(content, arrayName) {
    var splitter = "var " + arrayName;
    while (true) {
        var start = content.indexOf(splitter);
        if (start === -1) {
            break;
        }
        var pos = getNextStep(content, start, '=');
        if (pos === null) {
            break;
        } else if (pos < 0) {
            content = content.slice(-pos);
            continue;
        }
        pos = getNextStep(content, pos, '[');
        if (pos === null) {
            break;
        } else if (pos < 0) {
            content = content.slice(-pos);
            continue;
        }
        while (pos < content.length) {
            if (content[pos] === '"' || content[pos] === "'") {
                var stop = content[pos];
                do {
                    if (content[pos] === '\\') {
                        pos += 2;
                    } else {
                        pos += 1;
                    }
                } while (pos < content.length &&
                         (content[pos] !== stop || content[pos - 1] === '\\'));
            } else if (content[pos] === ']' &&
                       pos + 1 < content.length &&
                       content[pos + 1] === ';') {
                return content.slice(start, pos + 2);
            }
            pos += 1;
        }
        content = content.slice(start + 1);
    }
    return null;
}

// Stupid function extractor for variable.
function extractVariable(content, varName) {
    var splitter = "var " + varName;
    while (true) {
        var start = content.indexOf(splitter);
        if (start === -1) {
            break;
        }
        var pos = getNextStep(content, start, '=');
        if (pos === null) {
            break;
        } else if (pos < 0) {
            content = content.slice(-pos);
            continue;
        }
        while (pos < content.length) {
            if (content[pos] === '"' || content[pos] === "'") {
                var stop = content[pos];
                do {
                    if (content[pos] === '\\') {
                        pos += 2;
                    } else {
                        pos += 1;
                    }
                } while (pos < content.length &&
                         (content[pos] !== stop || content[pos - 1] === '\\'));
            } else if (content[pos] === ';') {
                return content.slice(start, pos + 1);
            }
            pos += 1;
        }
        content = content.slice(start + 1);
    }
    return null;
}

function loadContent(content) {
    var Module = module.constructor;
    var m = new Module();
    m._compile(content, "tmp.js");
    m.exports.ignore_order = content.indexOf("\n// ignore-order\n") !== -1 ||
        content.startsWith("// ignore-order\n");
    m.exports.exact_check = content.indexOf("\n// exact-check\n") !== -1 ||
        content.startsWith("// exact-check\n");
    m.exports.should_fail = content.indexOf("\n// should-fail\n") !== -1 ||
        content.startsWith("// should-fail\n");
    return m.exports;
}

function readFile(filePath) {
    return fs.readFileSync(filePath, 'utf8');
}

function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) {
    var content = '';
    for (var i = 0; i < thingsToLoad.length; ++i) {
        var tmp = funcToCall(fileContent, thingsToLoad[i]);
        if (tmp === null) {
            console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
            process.exit(1);
        }
        content += tmp;
        content += 'exports.' + thingsToLoad[i] + ' = ' + thingsToLoad[i] + ';';
    }
    return content;
}

function lookForEntry(entry, data) {
    for (var i = 0; i < data.length; ++i) {
        var allGood = true;
        for (var key in entry) {
            if (!entry.hasOwnProperty(key)) {
                continue;
            }
            var value = data[i][key];
            // To make our life easier, if there is a "parent" type, we add it to the path.
            if (key === 'path' && data[i]['parent'] !== undefined) {
                if (value.length > 0) {
                    value += '::' + data[i]['parent']['name'];
                } else {
                    value = data[i]['parent']['name'];
                }
            }
            if (value !== entry[key]) {
                allGood = false;
                break;
            }
        }
        if (allGood === true) {
            return i;
        }
    }
    return null;
}

function load_files(out_folder, crate) {
    var mainJs = readFile(out_folder + "/main.js");
    var ALIASES = readFile(out_folder + "/aliases.js");
    var searchIndex = readFile(out_folder + "/search-index.js").split("\n");
    if (searchIndex[searchIndex.length - 1].length === 0) {
        searchIndex.pop();
    }
    searchIndex.pop();
    searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;');
    finalJS = "";

    var arraysToLoad = ["itemTypes"];
    var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", "NO_TYPE_FILTER",
                           "GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA",
                           "TY_PRIMITIVE", "TY_KEYWORD",
                           "levenshtein_row2"];
    // execQuery first parameter is built in getQuery (which takes in the search input).
    // execQuery last parameter is built in buildIndex.
    // buildIndex requires the hashmap from search-index.
    var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
                           "getQuery", "buildIndex", "execQuery", "execSearch"];

    finalJS += 'window = { "currentCrate": "' + crate + '" };\n';
    finalJS += 'var rootPath = "../";\n';
    finalJS += ALIASES;
    finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
    finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
    finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs);

    var loaded = loadContent(finalJS);
    return [loaded, loaded.buildIndex(searchIndex.searchIndex)];
}

function main(argv) {
    if (argv.length < 4) {
        console.error("USAGE: node tester.js OUT_FOLDER [TESTS]");
        return 1;
    }
    if (argv[2].substr(-1) !== "/") {
        argv[2] += "/";
    }
    const out_folder = argv[2];

    var errors = 0;

    for (var j = 3; j < argv.length; ++j) {
        const test_file = argv[j];
        const test_name = path.basename(test_file, ".js");

        process.stdout.write('Checking "' + test_name + '" ... ');
        if (!fs.existsSync(test_file)) {
            errors += 1;
            console.error("FAILED");
            console.error("==> Missing '" + test_name + ".js' file...");
            continue;
        }

        const test_out_folder = out_folder + test_name;

        var [loaded, index] = load_files(test_out_folder, test_name);
        var loadedFile = loadContent(readFile(test_file) +
                               'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
        const expected = loadedFile.EXPECTED;
        const query = loadedFile.QUERY;
        const filter_crate = loadedFile.FILTER_CRATE;
        const ignore_order = loadedFile.ignore_order;
        const exact_check = loadedFile.exact_check;
        const should_fail = loadedFile.should_fail;
        var results = loaded.execSearch(loaded.getQuery(query), index);
        var error_text = [];
        for (var key in expected) {
            if (!expected.hasOwnProperty(key)) {
                continue;
            }
            if (!results.hasOwnProperty(key)) {
                error_text.push('==> Unknown key "' + key + '"');
                break;
            }
            var entry = expected[key];
            var prev_pos = -1;
            for (var i = 0; i < entry.length; ++i) {
                var entry_pos = lookForEntry(entry[i], results[key]);
                if (entry_pos === null) {
                    error_text.push("==> Result not found in '" + key + "': '" +
                                    JSON.stringify(entry[i]) + "'");
                } else if (exact_check === true && prev_pos + 1 !== entry_pos) {
                    error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " +
                                    "expected '" + JSON.stringify(entry[i]) + "' but found '" +
                                    JSON.stringify(results[key][i]) + "'");
                } else if (ignore_order === false && entry_pos < prev_pos) {
                    error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " +
                                    " before '" + JSON.stringify(results[key][entry_pos]) + "'");
                } else {
                    prev_pos = entry_pos;
                }
            }
        }
        if (error_text.length === 0 && should_fail === true) {
            errors += 1;
            console.error("FAILED");
            console.error("==> Test was supposed to fail but all items were found...");
        } else if (error_text.length !== 0 && should_fail === false) {
            errors += 1;
            console.error("FAILED");
            console.error(error_text.join("\n"));
        } else {
            console.log("OK");
        }
    }
    return errors > 0 ? 1 : 0;
}

process.exit(main(process.argv));
<|endoftext|>


<commit_before>// older browsers have some problems with the request object
// The ActiveX object for IE6 and IE5 cannot be extended
// The onreadystatechange is not acting on Request object in Firefox 2
// Opera 11 does not support addEventListener on XHR object
// Sharepoint cancel native onreadystatechange (so this must be set using addEventListener)

// The solution is to wrap the Request object in a plain object, and transfer all required variables

if(typeof(window.XMLHttpRequest) == "undefined" || function(){return (typeof(window.XMLHttpRequest.addEventListener) != "function")}() || function(){try {new XMLHttpRequest().channel; return false;} catch(exception) {return true;}}()) {

	// Create xmlhttprequest object
	Util.createRequestObject = function() {
		var xmlhttp;

		if(window.XMLHttpRequest) {
			xmlhttp = new XMLHttpRequest();

		}
		else if(window.ActiveXObject) {
			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

		}
		else {
			return {
				"open":function() {},
				"setRequestHeader":function() {},
				"send":function(){
					this.response({"status":"404", "responseText":"No Ajax support"});
				}
			};

		}

//		u.xInObject(xmlhttp);

		if(xmlhttp) {

			var wrapper = u.ae(document.body, "div", {"style":"display: none;"});

//			var wrapper = new Object();
			wrapper.xmlhttp = xmlhttp;

			// perform
			wrapper.xmlhttp.onreadystatechange = function() {
				// wrapper.xmlhttp should be this, but does not work in IE or Firefox 2
				// wait for correct readyState, map variables and call back to main loop
				if(wrapper.xmlhttp.readyState == 4) {
					wrapper.responseText = wrapper.xmlhttp.responseText;
					wrapper.status = wrapper.xmlhttp.status;

					// IE 6 cannot update readyState value on element
					try {
						wrapper.readyState = 4;
					}
					catch(exception) {
						wrapper.IEreadyState = true;
					}

					if(typeof(wrapper.statechanged) == "function") {
						wrapper.statechanged();
						wrapper.parentNode.removeChild(wrapper);
					}
					// else if(typeof(wrapper.onreadystatechange) == "function") {
					// 	wrapper.onreadystatechange();
					// }
				}
			}

			wrapper.setRequestHeader = function(type, value) {
				this.xmlhttp.setRequestHeader(type, value);
			}

			wrapper.open = function(method, url, async) {
				this.async = async;

				// avoid heavy caching by activex component
				url += (url.match(/\?/) ? "&" : "?") + "refresh_activex=" + u.randomString();
				this.xmlhttp.open(method, url, async);
			}

			wrapper.send = function(params) {
				this.xmlhttp.send(params);

				// make variables available on wrapper
				if(!this.async) {
					this.responseText = this.xmlhttp.responseText;
					this.status = this.xmlhttp.status;
				}

			}

			return wrapper;

		}
		else {
			u.bug("NO XMLHTTP");
			return false;
		}

	}

}

<commit_msg>IE6 edge case - no callback for illegal request<commit_after>// older browsers have some problems with the request object
// The ActiveX object for IE6 and IE5 cannot be extended
// The onreadystatechange is not acting on Request object in Firefox 2
// Opera 11 does not support addEventListener on XHR object
// Sharepoint cancel native onreadystatechange (so this must be set using addEventListener)

// The solution is to wrap the Request object in a plain object, and transfer all required variables

if(typeof(window.XMLHttpRequest) == "undefined" || function(){return (typeof(window.XMLHttpRequest.addEventListener) != "function")}() || function(){try {new XMLHttpRequest().channel; return false;} catch(exception) {return true;}}()) {

	// Create xmlhttprequest object
	Util.createRequestObject = function() {
		var xmlhttp;

		if(window.XMLHttpRequest) {
			xmlhttp = new XMLHttpRequest();

		}
		else if(window.ActiveXObject) {
			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

		}
		else {
			return {
				"open":function() {},
				"setRequestHeader":function() {},
				"send":function(){
					this.response({"status":"404", "responseText":"No Ajax support"});
				}
			};

		}

//		u.xInObject(xmlhttp);

		if(xmlhttp) {

			var wrapper = u.ae(document.body, "div", {"style":"display: none;"});

//			var wrapper = new Object();
			wrapper.xmlhttp = xmlhttp;

			// perform
			wrapper.xmlhttp.onreadystatechange = function() {
				// wrapper.xmlhttp should be this, but does not work in IE or Firefox 2
				// wait for correct readyState, map variables and call back to main loop
				if(wrapper.xmlhttp.readyState == 4) {
					wrapper.responseText = wrapper.xmlhttp.responseText;
					wrapper.status = wrapper.xmlhttp.status;

					// IE 6 cannot update readyState value on element
					try {
						wrapper.readyState = 4;
					}
					catch(exception) {
						wrapper.IEreadyState = true;
					}

					if(typeof(wrapper.statechanged) == "function") {
						wrapper.statechanged();
						wrapper.parentNode.removeChild(wrapper);
					}
					// else if(typeof(wrapper.onreadystatechange) == "function") {
					// 	wrapper.onreadystatechange();
					// }
				}
			}

			wrapper.setRequestHeader = function(type, value) {
				this.xmlhttp.setRequestHeader(type, value);
			}

			wrapper.open = function(method, url, async) {
				this.async = async;

				// avoid heavy caching by activex component
				url += (url.match(/\?/) ? "&" : "?") + "refresh_activex=" + u.randomString();
				// Old IE will not return error unless we catch it and do it manuallt
				try {
					this.xmlhttp.open(method, url, async);
				}
				catch(exception) {

					if(typeof(wrapper.statechanged) == "function") {
						this.status = 400;
						this.IEreadyState = true;

						this.statechanged();
						this.parentNode.removeChild(wrapper);
					}

				}
			}

			wrapper.send = function(params) {
				this.xmlhttp.send(params);

				// make variables available on wrapper
				if(!this.async) {
					this.responseText = this.xmlhttp.responseText;
					this.status = this.xmlhttp.status;
				}

			}

			return wrapper;

		}
		else {
			u.bug("NO XMLHTTP");
			return false;
		}

	}

}

<|endoftext|>


<commit_before>import docuri from 'docuri'
import uniqBy from 'lodash/fp/uniqBy'
import chunk from 'lodash/fp/chunk'
import flatten from 'lodash/fp/flatten'

import db from 'src/pouchdb'
import randomString from 'src/util/random-string'
import { generatePageDocId } from 'src/page-storage'
import { generateVisitDocId } from 'src/activity-logger'
import { STORAGE_KEY as BLACKLIST_KEY } from 'src/options/blacklist/constants'

export const INDEX_KEY = 'index'
export const BOOKMARKS_KEY = 'bookmarks'

/**
 * @typedef IBlacklistOldExt
 * @type {Object}
 * @property {Array<String>} PAGE An array of blocked pages (UNUSED).
 * @property {Array<String>} SITE An array of blocked sites (UNUSED).
 * @property {Array<String>} REGEX An array of strings to use to match sites.
 */

/**
 * @typedef IPageOldExt
 * @type {Object}
 * @property {String} text The extracted page text.
 * @property {String} time The time the page data was stored.
 * @property {String} title The page title.
 * @property {String} url The URL pointing to the page.
 */

/**
 * @param {IPageOldExt} pageData Page data from old extension to convert to visit doc.
 * @param {string} assocPageDocId The `_id` of the associated page doc.
 */
const convertToMinimalVisit = assocPageDoc => ({ time, url }) => ({
    _id: generateVisitDocId({ timestamp: time }),
    visitStart: time,
    url,
    page: { _id: assocPageDoc._id },
})

// TODO: Merge with imports code
const transformToVisitDoc = assocPageDoc => visitItem => ({
    _id: generateVisitDocId({
        timestamp: visitItem.visitTime,
        // We set the nonce manually, to prevent duplicating items if
        // importing multiple times (thus making importHistory idempotent).
        nonce: visitItem.visitId,
    }),
    visitStart: visitItem.visitTime,
    referringVisitItemId: visitItem.referringVisitId,
    url: assocPageDoc.url,
    page: { _id: assocPageDoc._id },
})

// TODO: Merge with imports code
const pageKeyPrefix = 'page/'
const pageDocsSelector = { _id: { $gte: pageKeyPrefix, $lte: `${pageKeyPrefix}\uffff` } }
const bookmarkKeyPrefix = 'bookmark/'
const convertBookmarkDocId = docuri.route(`${bookmarkKeyPrefix}:timestamp/:nonce`)
const generateBookmarkDocId = ({
    timestamp = Date.now(),
    nonce = randomString(),
} = {}) => convertBookmarkDocId({ timestamp, nonce })

/**
 * @param {IPageOldExt} oldPage
 * @return {IPageDoc} The converted minimal page doc.
 */
const transformToPageDoc = isStub => ({ text, time, title, url }) => ({
    _id: generatePageDocId({ timestamp: time }),
    title,
    url,
    isStub,
    content: {
        fullText: text,
        title,
    },
})

/**
 * @param {IPageDoc} assocPageDoc The page doc with which to associate this bookmark doc.
 * @param {IPageOldExt} oldPage
 * @return {IBookmarkDoc} The converted minimal bookmark doc.
 */
const transformToBookmarkDoc = assocPageDoc => ({ text, time, title, url }) => ({
    _id: generateBookmarkDocId({ timestamp: time }),
    title,
    url,
    page: { _id: assocPageDoc._id },
})

const transformToBlacklistEntry = dateAdded => expression => ({ expression, dateAdded })

/**
 * @param {IBlacklistOldExt} blacklist The old extension-formatted blacklist.
 * @return {String} The new extension serialized array of `{ expression: String, dateAdded: Date }` elements.
 */
function convertBlacklist(blacklist) {
    const mapToNewModel = transformToBlacklistEntry(Date.now())
    const uniqByExpression = uniqBy('expression')

    // Map all old values to enries in new model; uniq them on 'expression'
    const blacklistArr = uniqByExpression([
        ...blacklist.PAGE.map(mapToNewModel),
        ...blacklist.SITE.map(mapToNewModel),
        ...blacklist.REGEX.map(mapToNewModel),
    ])

    return JSON.stringify(blacklistArr) // Serialize it, as stored in new model
}

/**
 * Given old page data, attemps to convert it to the new model and generate any visit docs that can be
 * found in the browser along with a bookmark doc if needed.
 *
 * @param {boolean} isStub Denotes whether to set new pages as stubs to schedule for later import.
 * @param {Array<String>} bookmarkUrls List of URLs denoting bookmark page data.
 * @param {IPageOldExt} pageData The old ext model's page data to convert.
 * @param {IPageDoc?} [assocPageDoc] A page doc found to match the pageData param.
 * @return {Array<any>} List of converted docs ready to insert into PouchDB.
 */
const convertPageData = (isStub, bookmarkUrls) => async (pageData, assocPageDoc) => {
    // Do page conversion + visits generation
    const pageDoc = assocPageDoc || transformToPageDoc(isStub)(pageData)
    const visitItems = await browser.history.getVisits({ url: pageData.url })
    const visitDocs = [
        ...visitItems.map(transformToVisitDoc(pageDoc)), // Visits from browser API
        convertToMinimalVisit(pageDoc)(pageData), // Minimal visit straight from old ext data
    ]

    // Create bookmark doc if URL shows up in bookmark URL list
    const bookmarkDocs = bookmarkUrls.includes(pageData.url) ? [transformToBookmarkDoc(pageDoc)(pageData)] : []

    return [
        pageDoc,
        ...visitDocs,
        ...bookmarkDocs,
    ]
}

/**
 * @param {Array<IPageOldExt>} pageDataArr Array of page data to check against existing data for matches.
 * @return {Array<IPageDoc>} Array of page docs that are deemed to match any of the input data.
 */
const getMatchingPageDocs = async pageDataArr => {
    const pageDataUrls = pageDataArr.map(data => data.url)
    const fields = ['_id', 'url']
    const selector = { ...pageDocsSelector, url: { $in: pageDataUrls } }

    const { docs } = await db.find({ selector, fields })
    return docs
}

/**
 * @param {IBlacklistOldExt} blacklist
 */
const handleBlacklistConversion = blacklist =>
    browser.storage.local.set({ [BLACKLIST_KEY]: convertBlacklist(blacklist) })

/**
 * Performs the conversion of old extension page data to new extension. For each page data
 * in the old model, the following may be inserted into PouchDB:
 *  - 0/1 page docs (0 if processed earlier in index)
 *  - 0/1 bookmark docs (if present in `bookmarkUrls` param)
 *  - 1+ visit docs (1 minimal from old page data + whatever in in the browser history)
 *
 * @param {Array<string>} index The old extension index, containing sorted keys of page data.
 * @param {Array<string>} bookmarkUrls The old extension bookmark tracking list, containing URLs.
 */
async function handlePageDataConversion(index, bookmarkUrls, setAsStubs, chunkSize) {
    const convertOldData = convertPageData(setAsStubs, bookmarkUrls)
    const uniqByUrl = uniqBy('url')

    // Split index into chunks to process at once; reverse to process from latest first
    const indexChunks = chunk(chunkSize)(index.reverse())

    for (const keyChunk of indexChunks) {
        try {
            // Grab old page data from storae, ignoring duplicate URLs
            const oldPageData = uniqByUrl(Object.values(await browser.storage.local.get(keyChunk)))

            // Get any matching pages docs to those data in current chunk
            const matchingPages = await getMatchingPageDocs(oldPageData)

            // Map over local storage chunk, async processing each page data entry
            const docs = await Promise.all(oldPageData.map(data => {
                // Pass in any existing page doc that matches
                const assocPageDoc = matchingPages.find(doc => doc.url === data.url)
                return convertOldData(data, assocPageDoc)
            }))

            // Bulk insert all docs for this chunk
            await db.bulkDocs(flatten(docs))
        } catch (error) {
            console.error('DEBUG: Error encountered in storage conversion:')
            console.error(error)
            continue    // Continue processing next chunk if this one failed
        }
    }
}

/**
 * Converts the old extension's local storage object into one compatible with the new extension's
 * storage models, placing resulting conversions into either PouchDB or local storage, depending on the
 * data converted.
 *
 * @param {boolean} [setAsStubs=false] Denotes whether to set new pages as stubs to schedule for later import.
 * @param {number} [chunkSize=10] The amount of index items to process at any time.
 */
export default async function convertOldData(setAsStubs = false, chunkSize = 10) {
    // Grab initial needed local storage keys, providing defaults if not available
    const {
        [INDEX_KEY]: index,
        [BLACKLIST_KEY]: blacklist,
        [BOOKMARKS_KEY]: bookmarkUrls,
    } = await browser.storage.local.get({
        [INDEX_KEY]: [],
        [BLACKLIST_KEY]: { PAGE: [], SITE: [], REGEX: [] },
        [BOOKMARKS_KEY]: [],
    })

    // Only attempt blacklist conversion if it matches shape of old extension blacklist
    if (Object.prototype.toString.call(blacklist) === '[object Object]'
        && 'PAGE' in blacklist && 'SITE' in blacklist && 'REGEX' in blacklist) {
        await handleBlacklistConversion(blacklist)
    }

    // Only attempt page data conversion if index + bookmark URLs are some sort of arrays
    if (index instanceof Array && bookmarkUrls instanceof Array) {
        await handlePageDataConversion(index, bookmarkUrls, setAsStubs, chunkSize)
    }
}
<commit_msg>Write post-conversion storage cleanup<commit_after>import docuri from 'docuri'
import uniqBy from 'lodash/fp/uniqBy'
import chunk from 'lodash/fp/chunk'
import flatten from 'lodash/fp/flatten'
import omit from 'lodash/fp/omit'

import db from 'src/pouchdb'
import randomString from 'src/util/random-string'
import { generatePageDocId } from 'src/page-storage'
import { generateVisitDocId } from 'src/activity-logger'
import { STORAGE_KEY as NEW_BLACKLIST_KEY } from 'src/options/blacklist/constants'

export const KEYS = {
    INDEX: 'index',
    BOOKMARKS: 'bookmarks',
    HIST: 'history',
    PREFS: 'preferences',
    BLACKLIST: 'blacklist',
}

/**
 * @typedef IBlacklistOldExt
 * @type {Object}
 * @property {Array<String>} PAGE An array of blocked pages (UNUSED).
 * @property {Array<String>} SITE An array of blocked sites (UNUSED).
 * @property {Array<String>} REGEX An array of strings to use to match sites.
 */

/**
 * @typedef IPageOldExt
 * @type {Object}
 * @property {String} text The extracted page text.
 * @property {String} time The time the page data was stored.
 * @property {String} title The page title.
 * @property {String} url The URL pointing to the page.
 */

/**
 * @param {IPageOldExt} pageData Page data from old extension to convert to visit doc.
 * @param {string} assocPageDocId The `_id` of the associated page doc.
 */
const convertToMinimalVisit = assocPageDoc => ({ time, url }) => ({
    _id: generateVisitDocId({ timestamp: time }),
    visitStart: time,
    url,
    page: { _id: assocPageDoc._id },
})

// TODO: Merge with imports code
const transformToVisitDoc = assocPageDoc => visitItem => ({
    _id: generateVisitDocId({
        timestamp: visitItem.visitTime,
        // We set the nonce manually, to prevent duplicating items if
        // importing multiple times (thus making importHistory idempotent).
        nonce: visitItem.visitId,
    }),
    visitStart: visitItem.visitTime,
    referringVisitItemId: visitItem.referringVisitId,
    url: assocPageDoc.url,
    page: { _id: assocPageDoc._id },
})

// TODO: Merge with imports code
const pageKeyPrefix = 'page/'
const pageDocsSelector = { _id: { $gte: pageKeyPrefix, $lte: `${pageKeyPrefix}\uffff` } }
const bookmarkKeyPrefix = 'bookmark/'
const convertBookmarkDocId = docuri.route(`${bookmarkKeyPrefix}:timestamp/:nonce`)
const generateBookmarkDocId = ({
    timestamp = Date.now(),
    nonce = randomString(),
} = {}) => convertBookmarkDocId({ timestamp, nonce })

/**
 * @param {IPageOldExt} oldPage
 * @return {IPageDoc} The converted minimal page doc.
 */
const transformToPageDoc = isStub => ({ text, time, title, url }) => ({
    _id: generatePageDocId({ timestamp: time }),
    title,
    url,
    isStub,
    content: {
        fullText: text,
        title,
    },
})

/**
 * @param {IPageDoc} assocPageDoc The page doc with which to associate this bookmark doc.
 * @param {IPageOldExt} oldPage
 * @return {IBookmarkDoc} The converted minimal bookmark doc.
 */
const transformToBookmarkDoc = assocPageDoc => ({ text, time, title, url }) => ({
    _id: generateBookmarkDocId({ timestamp: time }),
    title,
    url,
    page: { _id: assocPageDoc._id },
})

const transformToBlacklistEntry = dateAdded => expression => ({ expression, dateAdded })

/**
 * @param {IBlacklistOldExt} blacklist The old extension-formatted blacklist.
 * @return {String} The new extension serialized array of `{ expression: String, dateAdded: Date }` elements.
 */
function convertBlacklist(blacklist) {
    const mapToNewModel = transformToBlacklistEntry(Date.now())
    const uniqByExpression = uniqBy('expression')

    // Map all old values to enries in new model; uniq them on 'expression'
    const blacklistArr = uniqByExpression([
        ...blacklist.PAGE.map(mapToNewModel),
        ...blacklist.SITE.map(mapToNewModel),
        ...blacklist.REGEX.map(mapToNewModel),
    ])

    return JSON.stringify(blacklistArr) // Serialize it, as stored in new model
}

/**
 * Given old page data, attemps to convert it to the new model and generate any visit docs that can be
 * found in the browser along with a bookmark doc if needed.
 *
 * @param {boolean} isStub Denotes whether to set new pages as stubs to schedule for later import.
 * @param {Array<String>} bookmarkUrls List of URLs denoting bookmark page data.
 * @param {IPageOldExt} pageData The old ext model's page data to convert.
 * @param {IPageDoc?} [assocPageDoc] A page doc found to match the pageData param.
 * @return {Array<any>} List of converted docs ready to insert into PouchDB.
 */
const convertPageData = (isStub, bookmarkUrls) => async (pageData, assocPageDoc) => {
    // Do page conversion + visits generation
    const pageDoc = assocPageDoc || transformToPageDoc(isStub)(pageData)
    const visitItems = await browser.history.getVisits({ url: pageData.url })
    const visitDocs = [
        ...visitItems.map(transformToVisitDoc(pageDoc)), // Visits from browser API
        convertToMinimalVisit(pageDoc)(pageData), // Minimal visit straight from old ext data
    ]

    // Create bookmark doc if URL shows up in bookmark URL list
    const bookmarkDocs = bookmarkUrls.includes(pageData.url) ? [transformToBookmarkDoc(pageDoc)(pageData)] : []

    return [
        pageDoc,
        ...visitDocs,
        ...bookmarkDocs,
    ]
}

/**
 * @param {Array<IPageOldExt>} pageDataArr Array of page data to check against existing data for matches.
 * @return {Array<IPageDoc>} Array of page docs that are deemed to match any of the input data.
 */
const getMatchingPageDocs = async pageDataArr => {
    const pageDataUrls = pageDataArr.map(data => data.url)
    const fields = ['_id', 'url']
    const selector = { ...pageDocsSelector, url: { $in: pageDataUrls } }

    const { docs } = await db.find({ selector, fields })
    return docs
}

/**
 * @param {IBlacklistOldExt} blacklist
 */
const handleBlacklistConversion = async blacklist => {
    const converted = convertBlacklist(blacklist)
    await browser.storage.local.set({ [NEW_BLACKLIST_KEY]: converted })

    if (NEW_BLACKLIST_KEY !== KEYS.BLACKLIST) { // Don't accidently remove what we just stored
        await browser.storage.local.remove(KEYS.BLACKLIST)
    }
}

/**
 * Performs the conversion of old extension page data to new extension. For each page data
 * in the old model, the following may be inserted into PouchDB:
 *  - 0/1 page docs (0 if processed earlier in index)
 *  - 0/1 bookmark docs (if present in `bookmarkUrls` param)
 *  - 1+ visit docs (1 minimal from old page data + whatever in in the browser history)
 *
 * @param {Array<string>} index The old extension index, containing sorted keys of page data.
 * @param {Array<string>} bookmarkUrls The old extension bookmark tracking list, containing URLs.
 * @param {ConversionOpts} opts
 */
async function handlePageDataConversion(index, bookmarkUrls, { setAsStubs, concurrency }) {
    const convertOldData = convertPageData(setAsStubs, bookmarkUrls)
    const uniqByUrl = uniqBy('url')
    let hasErrorOccurred = false

    // Split index into chunks to process at once; reverse to process from latest first
    const indexChunks = chunk(concurrency)(index.reverse())

    for (const keyChunk of indexChunks) {
        try {
            // Grab old page data from storae, ignoring duplicate URLs
            const oldPageData = uniqByUrl(Object.values(await browser.storage.local.get(keyChunk)))

            // Get any matching pages docs to those data in current chunk
            const matchingPages = await getMatchingPageDocs(oldPageData)

            // Map over local storage chunk, async processing each page data entry
            const docs = await Promise.all(oldPageData.map(data => {
                // Pass in any existing page doc that matches
                const assocPageDoc = matchingPages.find(doc => doc.url === data.url)
                return convertOldData(data, assocPageDoc)
            }))

            // Bulk insert all docs for this chunk
            await db.bulkDocs(flatten(docs))

            // Clean up this chunk from local storage
            await browser.storage.local.remove(keyChunk)
        } catch (error) {
            hasErrorOccurred = true
            console.error(`DEBUG: Error in converting of old extension data with keys: ${keyChunk}`)
            console.error(error)
            continue    // Continue processing next chunk if this one failed
        }
    }

    if (!hasErrorOccurred) { // Clean other old ext data up if no problem happened
        const pageRelatedKeys = omit('BLACKLIST')(KEYS)
        browser.storage.local.remove(Object.values(pageRelatedKeys))
    }
}

/**
 * @typedef ConversionOpts
 * @type {Object}
 * @property {boolean} [setAsStubs=false] Denotes whether to set new pages as stubs to schedule for later import.
 * @property {number} [concurrency=10] The amount of index items to process at any time.
 */

/**
 * Converts the old extension's local storage object into one compatible with the new extension's
 * storage models, placing resulting conversions into either PouchDB or local storage, depending on the
 * data converted.
 * @param {ConversionOpts} opts
 */
export default async function convertOldData(opts = { setAsStubs: false, concurrency: 10 }) {
    // Grab initial needed local storage keys, providing defaults if not available
    const {
        [KEYS.INDEX]: index,
        [KEYS.BLACKLIST]: blacklist,
        [KEYS.BOOKMARKS]: bookmarkUrls,
    } = await browser.storage.local.get({
        [KEYS.INDEX]: [],
        [KEYS.BLACKLIST]: { PAGE: [], SITE: [], REGEX: [] },
        [KEYS.BOOKMARKS]: [],
    })

    // Only attempt blacklist conversion if it matches shape of old extension blacklist
    if (Object.prototype.toString.call(blacklist) === '[object Object]'
        && 'PAGE' in blacklist && 'SITE' in blacklist && 'REGEX' in blacklist) {
        await handleBlacklistConversion(blacklist)
    }

    // Only attempt page data conversion if index + bookmark URLs are some sort of arrays
    if (index instanceof Array && bookmarkUrls instanceof Array) {
        await handlePageDataConversion(index, bookmarkUrls, opts)
    }
}
<|endoftext|>


<commit_before>// ---------------- Operation --------------------------------------------------

var express = require('express'),
    // Server
    server = require('./../../../webserver'),
    URL = server.serverUrl,
    // REST-API-Router
    api = require('./../rest-api'),
    // Database Access (salesforce REST-API)
    db = require('./../database/salesforce/database');
    // Express.js Application
    app = module.exports = express();

// ---------------- API --------------------------------------------------------

var OPERATION = '/animation';

// ---------------- Routing ----------------------------------------------------

/*
 * ## List all receivers
 */
app.get('/', function(req, res) {

  db.getBars(req, res);

});
<commit_msg>Animation<commit_after>// ---------------- Operation --------------------------------------------------

var bodyParser = require('body-parser'),
    express = require('express'),
    // Server
    server = require('./../../../webserver'),
    URL = server.serverUrl,
    // REST-API-Router
    api = require('./../rest-api'),
    // Database Access (salesforce REST-API)
    db = require('./../database/salesforce/database'),

    i2c = require('masterthesis-i2c-library');
    // Express.js Application
    app = module.exports = express();

app.use( bodyParser.json() );       // to support JSON-encoded bodies

// ---------------- API --------------------------------------------------------

var OPERATION = '/animation';

// ---------------- Operations --------------------------------------------

var requestBars = function (req, res, next) {
  db.getBars(req, res, next);
};

var requestBar = function (req, res, next) {
  db.getBar(req, res, next);
};

var requestAnimation = function (req, res, next) {
  db.getAnimation(req, res, next);
};

// ---------------- Routing -----------------------------------------------

/*
 * ## List all receivers
 */
app.get('/', [requestBars], function(req, res) {
  res.json(req.response);
});

/*
 * ## Get a bar by label
 */
app.get('/:label', [requestBar], function(req, res) {
 res.json(req.response);
});

/*
 * ## Get a bar by label
 */
app.get('/:label/:animation', [requestBar, requestAnimation], function(req, res) {
 res.json(req.response);
});

<|endoftext|>


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

import {LitElement, html} from "lit";
import UtilsNew from "../../../core/utilsNew.js";

/**
 * This is a wrapper component of a group of filters
* */
export default class SectionFilter extends LitElement {

    constructor() {
        super();

        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            filters: {
                type: Array
            },
            config: {
                type: Object
            }
        };
    }

    _init() {
        this._prefix = UtilsNew.randomString(8);
    }

    firstUpdated() {
        UtilsNew.initTooltip(this);
    }

    render() {
        return this.config && this.filters?.length > 0 ? html`

                            ${this.config.name || this.config.title}

                        ${this.filters?.map(filter => html`${filter}`)}

        ` : "";
    }

}

customElements.define("section-filter", SectionFilter);
<commit_msg>wc: minor fixes in section-filter.js<commit_after>/**
 * Copyright 2015-2019 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "lit";
import UtilsNew from "../../../core/utilsNew.js";

/**
 * This is a wrapper component of a group of filters
* */
export default class SectionFilter extends LitElement {

    constructor() {
        super();

        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            filters: {
                type: Array
            },
            config: {
                type: Object
            }
        };
    }

    _init() {
        this._prefix = UtilsNew.randomString(8);
    }

    firstUpdated() {
        UtilsNew.initTooltip(this);
    }

    render() {
        const id = this.config.title.replace(/ /g, "");
        return this.config && this.filters?.length > 0 ? html`

                            ${this.config.title}

                        ${this.filters?.map(filter => html`${filter}`)}

        ` : "";
    }

}

customElements.define("section-filter", SectionFilter);
<|endoftext|>


<commit_before>/*
Copyright 2017 Vector Creations Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// The prescribed way of doing this import would be:
//import {IndexedDbStoreWorker} from 'matrix-js-sdk';
// However, this still pulls in all of the js-sdk and we only use a tiny fraction
// of it. It also causes an Olm error to appear because we don't have an Olm in scope.
// Instead, we do this:
import IndexedDBStoreWorker from 'matrix-js-sdk/lib/store/indexeddb-store-worker';

const remoteWorker = new IndexedDBStoreWorker(postMessage);

onmessage = remoteWorker.onMessage;
<commit_msg>Use dedicated indexeddb worker import<commit_after>/*
Copyright 2017 Vector Creations Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import {IndexedDBStoreWorker} from 'matrix-js-sdk/lib/indexeddb-worker.js';

const remoteWorker = new IndexedDBStoreWorker(postMessage);

onmessage = remoteWorker.onMessage;
<|endoftext|>


<commit_before>vars.default_params["tickplot"] = function(scope) {

  var params = {};

  params.accessor_values = function(d) { return d.values; };
  params.accessor_items = function(d) { return d; };

  params.items = [];
  params.items.marks = [];

  params.x_scale = [{
    func: d3.scale.linear()
            .range([scope.margin.left, scope.width - scope.margin.left - scope.margin.right])
            .domain(d3.extent(vars.new_data, function(d) {
              return scope.accessor_data(d)[vars.var_x];
            })).nice()
  }];

  params.y_scale = [{
    func: d3.scale.linear()
            .range([scope.height - scope.margin.top - scope.margin.bottom, scope.margin.top])
            .domain(d3.extent(vars.new_data, function(d) {
              return scope.accessor_data(d)[vars.var_y];
            })).nice()
  }];

  scope.time.points.forEach(function(time) {

    // Draw items with a specific filter
    var mark = [{
        type: "tick",
        rotate: 90
      }, {
        type: "text"
      }, {
        accessor_data: function(d) {
          return d.values.filter(function(e) {
            return e[vars.time.var_time] == time;
          })[0];
        }
      }];
      console.log("Adding", mark)
    params.items.marks.push(mark);

  });
/*
  params.connect = [{
    marks: [{
      type: "path",
      stroke: function(d) {
        return vars.color(params.accessor_items(d)[vars.var_color]);
      },
      func: d3.svg.line()
           .interpolate(vars.interpolate)
           .x(function(d) { return params.x_scale[0]["func"](d[vars.var_x]); })
           .y(function(d) { return params.y_scale[0]["func"](d[vars.var_y]); }),
      fill: "none"
    }]
  }];
*/
  params.x_ticks = vars.time.points.length;
  params.x_tickValues = null;
  params.x_axis_orient = "top";
  params.x_axis_show = true;
  params.x_grid_show = true;
  params.x_text = false;

  params.y_axis_show = false
  params.y_grid_show = false;
  params.y_invert = true;

  return params;

};
<commit_msg>Progress on tick plot<commit_after>vars.default_params["tickplot"] = function(scope) {

  var params = {};

  params.items = [];

  params.x_scale = [{
    func: d3.scale.linear()
            .range([scope.margin.left, scope.width - scope.margin.left - scope.margin.right])
            .domain(d3.extent(vars.new_data, function(d) {
              return scope.accessor_data(d)[vars.var_x];
            })).nice()
  }];

  params.y_scale = [{
    func: d3.scale.linear()
            .range([scope.height - scope.margin.top - scope.margin.bottom, scope.margin.top])
            .domain(d3.extent(vars.new_data, function(d) {
              return scope.accessor_data(d)[vars.var_y];
            })).nice()
  }];

  scope.time.points.forEach(function(time) {

    var item = {};
    item.marks = [];
    // Draw items with a specific filter
    var mark = [{
        type: "rect",
        rotate: 90
      }];

    item.marks[0] = mark;

    item.accessor_data = function(d) {
      return d.values.filter(function(e) {
        return e.year == time;
      })[0];
    };

    params.items = params.items.concat(item);

  });

  params.x_ticks = vars.time.points.length;
  params.x_tickValues = null;
  params.x_axis_orient = "top";
  params.x_axis_show = true;
  params.x_grid_show = true;
  params.x_text = false;

  params.y_axis_show = false
  params.y_grid_show = false;
  params.y_invert = true;

  return params;

};
<|endoftext|>


<commit_before>/*!
 * VIZABI GAPMINDER PREFERENCES (included only in Gapminder build)
 */

(function () {
    'use strict';
    var root = this;
    var Vizabi = root.Vizabi;

    //DEFAULT OPTIONS
    var BarChart = this.Vizabi.Tool.get('BarChart');
    var LineChart = this.Vizabi.Tool.get('LineChart');
    var BubbleChart = this.Vizabi.Tool.get('BubbleChart');
    var MountainChart = this.Vizabi.Tool.get('MountainChart');
    var MountainChartComponent = this.Vizabi.Component.get('gapminder-mountainchart');
    var PopByAge = this.Vizabi.Tool.get('PopByAge');

    var language = {
        id: "en",
        strings: {}
    };

    BarChart.define('default_options', {
        state: {
            time: {
                start: "1952",
                end: "2012",
                value: "2000",
                step: 1,
                speed: 300,
                formatInput: "%Y"
            },
            entities: {
                dim: "geo",
                show: {
                    _defs_: {
                        "geo": ["*"],
                        "geo.cat": ["region"]
                    }
                }
            },
            marker: {
                space: ["entities", "time"],
                label: {
                    use: "property",
                    which: "geo.name"
                },
                axis_y: {
                    use: "indicator",
                    which: "lex",
                    scaleType: "linear",
                    allow: {scales: ["linear", "log"]}
                },
                axis_x: {
                    use: "property",
                    which: "geo.name",
                    allow: {scales: ["ordinal"]}
                },
                color: {
                    use: "property",
                    which: "geo",
                    palette: {
                        "asi": "#FF5872",
                        "eur": "#FFE700",
                        "ame": "#7FEB00",
                        "afr": "#00D5E9",
                        "_default": "#ffb600"
                    }
                }
            }
        },
        data: {
            reader: "waffle-server"
        },
        language: language,
        ui: {
            buttons: []
        }
    });

    MountainChart.define('default_options', {
        state: {
            time: {
                start: 1800,
                end: 2030,
                value: 2030,
                step: 1,
                speed: 100,
                formatInput: "%Y",
                xLogStops: [1, 2, 5],
                yMaxMethod: "latest",
                povertyline: 1.82,
                povertyCutoff: 0.2,
                povertyFade: 0.7,
                gdpFactor: 1.039781626,
                //0.9971005335,
                gdpShift: -1.127066411,
                //-1.056221322,
                xPoints: 50
            },
            entities: {
                dim: "geo",
                opacitySelectDim: 0.3,
                opacityRegular: 0.6,
                show: {
                    _defs_: {
                        "geo": ['*'], //['swe', 'nor', 'fin', 'bra', 'usa', 'chn', 'jpn', 'zaf', 'ind', 'ago'],
                        "geo.cat": ["country"]
                    }
                }
            },
            marker: {
                space: ["entities", "time"],
                label: {
                    use: "property",
                    which: "geo.name"
                },
                axis_y: {
                    use: "indicator",
                    which: "pop",
                    scaleType: 'linear'
                },
                axis_x: {
                    use: "indicator",
                    //which: "mean",
                    which: "gdp_per_cap",
                    scaleType: 'log',
                    unit: "gdp_per_cap_daily",
                    min: 0.11, //0
                    max: 500 //100
                },
                size: {
                    use: "indicator",
                    //which: "variance",
                    which: "gini",
                    scaleType: 'linear'
                },
                color: {
                    use: "property",
                    which: "geo.region",
                    scaleType: "ordinal"
                },
                stack: {
                    use: "value",
                    which: "all" // set a property of data or values "all" or "none"
                },
                group: {
                    which: "geo.region", // set a property of data
                    manualSorting: ["eur", "ame", "afr", "asi"],
                    merge: false
                }
            }
        },
        language: language,
        data: {
            //reader: "waffle-server"
            reader: "csv-file",
            path: "local_data/waffles/mountains-pop-gdp-gini-1800-2030.csv"
            //path: "https://dl.dropboxusercontent.com/u/21736853/data/process/inc_mount_data_2015test/mountains-pop-gdp-gini-1800-2030.csv"
        }
    });

    LineChart.define('default_options', {
        state: {
            time: {
                start: 1990,
                end: 2012,
                value: 2012,
                step: 1,
                speed: 300,
                formatInput: "%Y"
            },
            //entities we want to show
            entities: {
                dim: "geo",
                show: {
                    _defs_: {
                        "geo": ["*"],
                        "geo.cat": ["region"]
                    }
                }
            },
            //how we show it
            marker: {
                space: ["entities", "time"],
                label: {
                    use: "property",
                    which: "geo.name"
                },
                axis_y: {
                    use: "indicator",
                    which: "gdp_per_cap",
                    scaleType: "log"
                },
                axis_x: {
                    use: "indicator",
                    which: "time",
                    scaleType: "time"
                },
                color: {
                    use: "property",
                    which: "geo",
                    palette: {
                        "asi": "#FF5872",
                        "eur": "#FFE700",
                        "ame": "#7FEB00",
                        "afr": "#00D5E9",
                        "_default": "#ffb600"
                    }
                },
                color_shadow: {
                    use: "property",
                    which: "geo",
                    palette: {
                        "asi": "#FF5872",
                        "eur": "#FFE700",
                        "ame": "#7FEB00",
                        "afr": "#00D5E9",
                        "_default": "#ffb600"
                    }
                }
            }
        },

        data: {
            reader: "waffle-server"
        },
        language: language,
        ui: {
            'vzb-tool-line-chart': {
                entity_labels: {
                    min_number_of_entities_when_values_hide: 2 //values hide when showing 2 entities or more
                },
                whenHovering: {
                    hideVerticalNow: 0,
                    showProjectionLineX: true,
                    showProjectionLineY: true,
                    higlightValueX: true,
                    higlightValueY: true,
                    showTooltip: 0
                }
            },
            buttons: []
        }
    });

    BubbleChart.define('default_options', {

        state: {
            time: {
                start: "1990",
                end: "2014",
                value: "2000",
                step: 1,
                speed: 300,
                formatInput: "%Y",
                round: "ceil",
                trails: true,
                lockNonSelected: 0,
                adaptMinMaxZoom: false
            },
            entities: {
                dim: "geo",
                show: {
                    _defs_: {
                        "geo": ["*"],
                        "geo.cat": ["country"]
                    }
                }
            },
            marker: {
                space: ["entities", "time"],
                type: "geometry",
                shape: "circle",
                label: {
                    use: "property",
                    which: "geo.name"
                },
                axis_y: {
                    use: "indicator",
                    which: "lex",
                    scaleType: "linear",
                    allow: {scales: ["linear", "log", "genericLog"]},
                    unit: "lex"
                },
                axis_x: {
                    use: "indicator",
                    which: "gdp_per_cap",
                    scaleType: "log",
                    allow: {scales: ["linear", "log", "genericLog"]},
                    unit: "gdp_per_cap"
                },
                color: {
                    use: "property",
                    which: "geo.region",
                    scaleType: "ordinal",
                    unit: ""
                },
                size: {
                    use: "indicator",
                    which: "pop",
                    scaleType: "linear",
                    allow: {scales: ["linear", "log"]},
                    min: 0.04,
                    max: 0.75,
                    unit: ""
                }
            }
        },
        data: {
            //reader: "waffle-server",
            reader: "csv-file",
            path: "local_data/waffles/basic-indicators.csv",
            //path: "local_data/waffles/bub_data_u5mr_inc_etc_20150823.csv"
            //path: "https://dl.dropboxusercontent.com/u/21736853/data/process/childsurv_2015test/bub_data_u5mr_inc_etc_20150823.csv"
        },
        language: language,
        ui: {
            'vzb-tool-bubble-chart': {
                whenHovering: {
                    showProjectionLineX: true,
                    showProjectionLineY: true,
                    higlightValueX: true,
                    higlightValueY: true
                },
                labels: {
                    autoResolveCollisions: true,
                    dragging: true
                }
            },
            buttons: []
        }
    });

    PopByAge.define('default_options', {
        state: {
            time: {
                value: '2013'
            },
            entities: {
                dim: "geo",
                show: {
                    _defs_: {
                        "geo": ["usa"]
                    }
                }
            },
            entities_age: {
                dim: "age",
                show: {
                    _defs_: {
                        "age": [[1, 100]] //show 1 through 100
                    }
                }
            },
            marker: {
                space: ["entities", "entities_age", "time"],
                group_by: 1,
                label: {
                    use: "indicator",
                    which: "age"
                },
                label_name: {
                    use: "property",
                    which: "geo"
                },
                axis_y: {
                    use: "indicator",
                    which: "age"
                },
                axis_x: {
                    use: "indicator",
                    which: "population"
                },
                color: {
                    use: "value",
                    which: "#ffb600"
                }
            }
        },
        data: {
            reader: "csv-file",
            path: "local_data/waffles/{{geo}}.csv",
        },
        language: language,
        ui: {
            buttons: []
        }
    });

    //Waffle Server Reader custom path
    var WaffleReader = this.Vizabi.Reader.get('waffle-server');
    WaffleReader.define('basepath', "http://52.18.235.31:8001/values/waffle");

    Vizabi._globals.gapminder_paths = {
        baseUrl: ""
    };

    //preloading mountain chart precomputed shapes
    MountainChartComponent.define("preload", function(done) {
        var shape_path = Vizabi._globals.gapminder_paths.baseUrl + "local_data/mc_precomputed_shapes.json";

        d3.json(shape_path, function(error, json) {
            if (error) return console.warn("Failed loading json " + shape_path + ". " + error);
            MountainChartComponent.define('precomputedShapes', json);
            done.resolve();
        });
    });

    //preloading metadata for all charts
    Vizabi.Tool.define("preload", function(promise) {

        var metadata_path = Vizabi._globals.gapminder_paths.baseUrl + "local_data/waffles/metadata.json";
        var globals = Vizabi._globals;

        //TODO: concurrent
        //load language first
        this.preloadLanguage().then(function() {
            //then metadata
            d3.json(metadata_path, function(metadata) {
                globals.metadata = metadata;
                promise.resolve();
            });
        });

    });

    Vizabi.Tool.define("preloadLanguage", function() {

        var promise = new Vizabi.Promise();

        var langModel = this.model.language;
        var translation_path = Vizabi._globals.gapminder_paths.baseUrl + "local_data/translation/"+langModel.id+".json";

        if(langModel && !langModel.strings[langModel.id]) {
            d3.json(translation_path, function(langdata) {
                langModel.strings[langModel.id] = langdata;
                promise.resolve();
            });
        }
        else {
            promise = promise.resolve();
        }

        return promise;

    });

}.call(this));
<commit_msg>Include hardcoded path of Vizabi files #hotfix<commit_after>/*!
 * VIZABI GAPMINDER PREFERENCES (included only in Gapminder build)
 */

(function () {
    'use strict';
    var root = this;
    var Vizabi = root.Vizabi;

    //DEFAULT OPTIONS
    var BarChart = this.Vizabi.Tool.get('BarChart');
    var LineChart = this.Vizabi.Tool.get('LineChart');
    var BubbleChart = this.Vizabi.Tool.get('BubbleChart');
    var MountainChart = this.Vizabi.Tool.get('MountainChart');
    var MountainChartComponent = this.Vizabi.Component.get('gapminder-mountainchart');
    var PopByAge = this.Vizabi.Tool.get('PopByAge');

    var language = {
        id: "en",
        strings: {}
    };

    BarChart.define('default_options', {
        state: {
            time: {
                start: "1952",
                end: "2012",
                value: "2000",
                step: 1,
                speed: 300,
                formatInput: "%Y"
            },
            entities: {
                dim: "geo",
                show: {
                    _defs_: {
                        "geo": ["*"],
                        "geo.cat": ["region"]
                    }
                }
            },
            marker: {
                space: ["entities", "time"],
                label: {
                    use: "property",
                    which: "geo.name"
                },
                axis_y: {
                    use: "indicator",
                    which: "lex",
                    scaleType: "linear",
                    allow: {scales: ["linear", "log"]}
                },
                axis_x: {
                    use: "property",
                    which: "geo.name",
                    allow: {scales: ["ordinal"]}
                },
                color: {
                    use: "property",
                    which: "geo",
                    palette: {
                        "asi": "#FF5872",
                        "eur": "#FFE700",
                        "ame": "#7FEB00",
                        "afr": "#00D5E9",
                        "_default": "#ffb600"
                    }
                }
            }
        },
        data: {
            reader: "waffle-server"
        },
        language: language,
        ui: {
            buttons: []
        }
    });

    MountainChart.define('default_options', {
        state: {
            time: {
                start: 1800,
                end: 2030,
                value: 2030,
                step: 1,
                speed: 100,
                formatInput: "%Y",
                xLogStops: [1, 2, 5],
                yMaxMethod: "latest",
                povertyline: 1.82,
                povertyCutoff: 0.2,
                povertyFade: 0.7,
                gdpFactor: 1.039781626,
                //0.9971005335,
                gdpShift: -1.127066411,
                //-1.056221322,
                xPoints: 50
            },
            entities: {
                dim: "geo",
                opacitySelectDim: 0.3,
                opacityRegular: 0.6,
                show: {
                    _defs_: {
                        "geo": ['*'], //['swe', 'nor', 'fin', 'bra', 'usa', 'chn', 'jpn', 'zaf', 'ind', 'ago'],
                        "geo.cat": ["country"]
                    }
                }
            },
            marker: {
                space: ["entities", "time"],
                label: {
                    use: "property",
                    which: "geo.name"
                },
                axis_y: {
                    use: "indicator",
                    which: "pop",
                    scaleType: 'linear'
                },
                axis_x: {
                    use: "indicator",
                    //which: "mean",
                    which: "gdp_per_cap",
                    scaleType: 'log',
                    unit: "gdp_per_cap_daily",
                    min: 0.11, //0
                    max: 500 //100
                },
                size: {
                    use: "indicator",
                    //which: "variance",
                    which: "gini",
                    scaleType: 'linear'
                },
                color: {
                    use: "property",
                    which: "geo.region",
                    scaleType: "ordinal"
                },
                stack: {
                    use: "value",
                    which: "all" // set a property of data or values "all" or "none"
                },
                group: {
                    which: "geo.region", // set a property of data
                    manualSorting: ["eur", "ame", "afr", "asi"],
                    merge: false
                }
            }
        },
        language: language,
        data: {
            //reader: "waffle-server"
            reader: "csv-file",
            path: "local_data/waffles/mountains-pop-gdp-gini-1800-2030.csv"
            //path: "https://dl.dropboxusercontent.com/u/21736853/data/process/inc_mount_data_2015test/mountains-pop-gdp-gini-1800-2030.csv"
        }
    });

    LineChart.define('default_options', {
        state: {
            time: {
                start: 1990,
                end: 2012,
                value: 2012,
                step: 1,
                speed: 300,
                formatInput: "%Y"
            },
            //entities we want to show
            entities: {
                dim: "geo",
                show: {
                    _defs_: {
                        "geo": ["*"],
                        "geo.cat": ["region"]
                    }
                }
            },
            //how we show it
            marker: {
                space: ["entities", "time"],
                label: {
                    use: "property",
                    which: "geo.name"
                },
                axis_y: {
                    use: "indicator",
                    which: "gdp_per_cap",
                    scaleType: "log"
                },
                axis_x: {
                    use: "indicator",
                    which: "time",
                    scaleType: "time"
                },
                color: {
                    use: "property",
                    which: "geo",
                    palette: {
                        "asi": "#FF5872",
                        "eur": "#FFE700",
                        "ame": "#7FEB00",
                        "afr": "#00D5E9",
                        "_default": "#ffb600"
                    }
                },
                color_shadow: {
                    use: "property",
                    which: "geo",
                    palette: {
                        "asi": "#FF5872",
                        "eur": "#FFE700",
                        "ame": "#7FEB00",
                        "afr": "#00D5E9",
                        "_default": "#ffb600"
                    }
                }
            }
        },

        data: {
            reader: "waffle-server"
        },
        language: language,
        ui: {
            'vzb-tool-line-chart': {
                entity_labels: {
                    min_number_of_entities_when_values_hide: 2 //values hide when showing 2 entities or more
                },
                whenHovering: {
                    hideVerticalNow: 0,
                    showProjectionLineX: true,
                    showProjectionLineY: true,
                    higlightValueX: true,
                    higlightValueY: true,
                    showTooltip: 0
                }
            },
            buttons: []
        }
    });

    BubbleChart.define('default_options', {

        state: {
            time: {
                start: "1990",
                end: "2014",
                value: "2000",
                step: 1,
                speed: 300,
                formatInput: "%Y",
                round: "ceil",
                trails: true,
                lockNonSelected: 0,
                adaptMinMaxZoom: false
            },
            entities: {
                dim: "geo",
                show: {
                    _defs_: {
                        "geo": ["*"],
                        "geo.cat": ["country"]
                    }
                }
            },
            marker: {
                space: ["entities", "time"],
                type: "geometry",
                shape: "circle",
                label: {
                    use: "property",
                    which: "geo.name"
                },
                axis_y: {
                    use: "indicator",
                    which: "lex",
                    scaleType: "linear",
                    allow: {scales: ["linear", "log", "genericLog"]},
                    unit: "lex"
                },
                axis_x: {
                    use: "indicator",
                    which: "gdp_per_cap",
                    scaleType: "log",
                    allow: {scales: ["linear", "log", "genericLog"]},
                    unit: "gdp_per_cap"
                },
                color: {
                    use: "property",
                    which: "geo.region",
                    scaleType: "ordinal",
                    unit: ""
                },
                size: {
                    use: "indicator",
                    which: "pop",
                    scaleType: "linear",
                    allow: {scales: ["linear", "log"]},
                    min: 0.04,
                    max: 0.75,
                    unit: ""
                }
            }
        },
        data: {
            //reader: "waffle-server",
            reader: "csv-file",
            path: "local_data/waffles/basic-indicators.csv",
            //path: "local_data/waffles/bub_data_u5mr_inc_etc_20150823.csv"
            //path: "https://dl.dropboxusercontent.com/u/21736853/data/process/childsurv_2015test/bub_data_u5mr_inc_etc_20150823.csv"
        },
        language: language,
        ui: {
            'vzb-tool-bubble-chart': {
                whenHovering: {
                    showProjectionLineX: true,
                    showProjectionLineY: true,
                    higlightValueX: true,
                    higlightValueY: true
                },
                labels: {
                    autoResolveCollisions: true,
                    dragging: true
                }
            },
            buttons: []
        }
    });

    PopByAge.define('default_options', {
        state: {
            time: {
                value: '2013'
            },
            entities: {
                dim: "geo",
                show: {
                    _defs_: {
                        "geo": ["usa"]
                    }
                }
            },
            entities_age: {
                dim: "age",
                show: {
                    _defs_: {
                        "age": [[1, 100]] //show 1 through 100
                    }
                }
            },
            marker: {
                space: ["entities", "entities_age", "time"],
                group_by: 1,
                label: {
                    use: "indicator",
                    which: "age"
                },
                label_name: {
                    use: "property",
                    which: "geo"
                },
                axis_y: {
                    use: "indicator",
                    which: "age"
                },
                axis_x: {
                    use: "indicator",
                    which: "population"
                },
                color: {
                    use: "value",
                    which: "#ffb600"
                }
            }
        },
        data: {
            reader: "csv-file",
            path: "local_data/waffles/{{geo}}.csv",
        },
        language: language,
        ui: {
            buttons: []
        }
    });

    //Waffle Server Reader custom path
    var WaffleReader = this.Vizabi.Reader.get('waffle-server');
    WaffleReader.define('basepath', "http://52.18.235.31:8001/values/waffle");

    //TODO: remove hardcoded path from source code
    Vizabi._globals.gapminder_paths = {
        baseUrl: "http://static.gapminderdev.org/vizabi/release/v0.7.1/preview/"
    };

    //preloading mountain chart precomputed shapes
    MountainChartComponent.define("preload", function(done) {
        var shape_path = Vizabi._globals.gapminder_paths.baseUrl + "local_data/mc_precomputed_shapes.json";

        d3.json(shape_path, function(error, json) {
            if (error) return console.warn("Failed loading json " + shape_path + ". " + error);
            MountainChartComponent.define('precomputedShapes', json);
            done.resolve();
        });
    });

    //preloading metadata for all charts
    Vizabi.Tool.define("preload", function(promise) {

        var metadata_path = Vizabi._globals.gapminder_paths.baseUrl + "local_data/waffles/metadata.json";
        var globals = Vizabi._globals;

        //TODO: concurrent
        //load language first
        this.preloadLanguage().then(function() {
            //then metadata
            d3.json(metadata_path, function(metadata) {
                globals.metadata = metadata;
                promise.resolve();
            });
        });

    });

    Vizabi.Tool.define("preloadLanguage", function() {

        var promise = new Vizabi.Promise();

        var langModel = this.model.language;
        var translation_path = Vizabi._globals.gapminder_paths.baseUrl + "local_data/translation/"+langModel.id+".json";

        if(langModel && !langModel.strings[langModel.id]) {
            d3.json(translation_path, function(langdata) {
                langModel.strings[langModel.id] = langdata;
                promise.resolve();
            });
        }
        else {
            promise = promise.resolve();
        }

        return promise;

    });

}.call(this));
<|endoftext|>


<commit_before>Easemob.im.config = {
    /*
        The global value set for xmpp server
    */
    xmppURL: 'im-api.sandbox.easemob.com',
    /*
        The global value set for Easemob backend REST API
        "http://a1.easemob.com"
    */
    apiURL: 'https://a1.sdb.easemob.com',
    /*
        连接时提供appkey
    */
    appkey: "easemob-demo#chatdemoui",
    /*
     * 是否使用https
     */
    https : true,
    /*
     * 是否使用多resource
     */
    multiResources: false

}
<commit_msg>release v1.1.0<commit_after>Easemob.im.config = {
    /*
        The global value set for xmpp server
    */
    xmppURL: 'im-api.easemob.com',
    /*
        The global value set for Easemob backend REST API
        "http://a1.easemob.com"
    */
    apiURL: 'https://a1.easemob.com',
    /*
        连接时提供appkey
    */
    appkey: "easemob-demo#chatdemoui",
    /*
     * 是否使用https
     */
    https : true,
    /*
     * 是否使用多resource
     */
    multiResources: false

}
<|endoftext|>


<commit_before>const expect = require('chai').expect;

import $ from 'jquery';
global.$ = $;

import { Client } from "../client";

describe('client connection', () => {

    const client = new Client('localhost', 8884, 'test-client');

    const userName = 'admin';

    it('should connect', function(done) {

        client.connect(userName, {
            onSuccess: () => {
                done();
            },
            onFailure: (cntxt, errorCode, errorMessage) => {
                done(errorMessage);
            }
        });

    });

    it('is connected', function() {

        expect(client.mqttClient.isConnected).to.equal(true);

    });

    it('should disconnect', function(done) {

        const resolvingPromise = new Promise(function(resolve, reject) {
            // the function is executed automatically when the promise is constructed
            client.disconnect();
            while (client.isConnected) { /* wait */ }
            resolve('disconnected');

            setTimeout(() => reject(new Error("timeout!")), 1000);
        });

        resolvingPromise
            .then(
                (result) => {
                    expect(result).to.equal('disconnected');
                    expect(client.isConnected).to.equal(false);
                    expect(client.client).to.equal(null);
                },
                () => {}
            )
            .finally(done);

    })

});
<commit_msg>Client testing.<commit_after>const expect = require('chai').expect;

global.$ = require('jquery')(window);

import { Client } from "../client";

describe('client connection', () => {

    const client = new Client('localhost', 8884, 'test-client');

    const userName = 'admin';

    it('should connect', function(done) {

        client.connect(userName, {
            onSuccess: () => {
                done();
            },
            onFailure: (cntxt, errorCode, errorMessage) => {
                done(errorMessage);
            }
        });

    });

    it('is connected', function() {

        expect(client.mqttClient.isConnected).to.equal(true);

    });

    it('should disconnect', function(done) {

        const resolvingPromise = new Promise(function(resolve, reject) {
            // the function is executed automatically when the promise is constructed
            client.disconnect();
            while (client.isConnected) { /* wait */ }
            resolve('disconnected');

            setTimeout(() => reject(new Error("timeout!")), 1000);
        });

        resolvingPromise
            .then(
                (result) => {
                    expect(result).to.equal('disconnected');
                    expect(client.isConnected).to.equal(false);
                    expect(client.client).to.equal(null);
                },
                () => {}
            )
            .finally(done);

    })

});
<|endoftext|>