<commit_before>var _ = require('underscore'),
    AssetGraph = require('../'),
    uglifyJs = AssetGraph.JavaScript.uglifyJs,
    uglifyAst = AssetGraph.JavaScript.uglifyAst,
    symbolNames = {
        ' ': 'SPACE',
        '!': 'BANG',
        '.': 'DOT',
        '=': 'EQUALS',
        '~': 'TILDE',
        '$': 'DOLLAR',
        '#': 'HASH',
        '%': 'PERCENT',
        '/': 'SLASH',
        '<': 'LESSTHAN',
        '>': 'GREATERTHAN',
        '&': 'AMPERSAND',
        '?': 'QUESTIONMARK',
        '\'': 'SINGLEQUOTE',
        '"': 'DOUBLEQUOTE',
        '+': 'PLUS',
        ',': 'COMMA',
        ';': 'SEMICOLON',
        ':': 'COLON',
        '(': 'LPAREN',
        ')': 'RPAREN',
        '{': 'LBRACE',
        '}': 'RBRACE',
        '[': 'LSQBRACE',
        ']': 'RSQBRACE'
    };

module.exports = function (queryObj, options) {
    options = options || {};
    options.globalNames = options.globalNames || [];
    Array.prototype.push.apply(options.globalNames, ['eval', 'clearInterval', 'clearTimeout', 'document', 'event', 'frames', 'history', 'Image', 'localStorage', 'location', 'name', 'navigator', 'Option', 'parent', 'screen', 'sessionStorage', 'setInterval', 'setTimeout', 'Storage', 'window', 'XMLHttpRequest', 'Math', 'Math.min', 'Math.max', 'Math.round', 'Function', 'Date', 'Date.prototype', 'Math.E', 'Math.LN2', 'Math.LN10', 'Math.LOG2E', 'Math.LOG10E', 'Math.PI', 'Math.SQRT1_2', 'Math.SQRT2', 'Math.abs', 'Math.acos', 'Math.asin', 'Math.atan', 'Math.atan2', 'Math.ceil', 'Math.cos', 'Math.exp', 'Math.floor', 'Math.log', 'Math.max', 'Math.min', 'Math.pow', 'Math.random', 'Math.round', 'Math.sin', 'Math.sqrt', 'Math.tan', 'parseInt', 'parseFloat', 'isNaN', 'NaN', 'RegExp', 'RegExp.prototype', 'RegExp.prototype.compile', 'RegExp.prototype.test', 'RegExp.prototype.exec', 'String', 'String.fromCharCode', 'String.prototype', 'String.prototype.charAt', 'String.prototype.charCodeAt', 'String.prototype.indexOf', 'String.prototype.match', 'String.prototype.replace', 'String.prototype.slice', 'String.prototype.split', 'String.prototype.substr', 'String.prototype.substring', 'String.prototype.toLowerCase', 'String.prototype.toUpperCase', 'Array', 'Array.prototype', 'Array.prototype.concat', 'Array.prototype.indexOf', 'Array.prototype.join', 'Array.prototype.pop', 'Array.prototype.push', 'Array.prototype.reverse', 'Array.prototype.shift', 'Array.prototype.slice', 'Array.prototype.sort', 'Array.prototype.splice', 'Array.prototype.unshift', 'Number', 'Number.prototype', 'Number.prototype.toFixed', 'Number.MAX_VALUE', 'Number.MIN_VALUE', 'Number.NEGATIVE_INFINITY', 'Number.NaN', 'Number.POSITIVE_INFINITY', 'Number.prototype', 'Boolean', 'Boolean.prototype', 'Error', 'Error.prototype', 'EvalError', 'EvalError.prototype', 'Infinity', 'JSON', 'JSON.stringify', 'JSON.parse', 'Object', 'Object.prototype', 'Object.prototype.toString', 'RangeError', 'RangeError.prototype', 'ReferenceError', 'ReferenceError.prototype', 'SyntaxError', 'SyntaxError.prototype', 'TypeError', 'TypeError.prototype', 'URIError', 'URIError.prototype', 'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', 'isFinite', 'undefined']);

    var globalsObj = {};
    options.globalNames.forEach(function (global) {
        globalsObj[global] = true;
    });
    return function pullGlobalsIntoVariables(assetGraph) {
        assetGraph.findAssets(_.extend({type: 'JavaScript'}, queryObj)).forEach(function (javaScriptAsset) {
            var occurrencesByGlobalName = {},
                occurrencesByString = {},
                ast = javaScriptAsset.parseTree,
                seenNames = {}, // To avoid collisions when introducing new vars
                seenLocals = {}, // To avoid aliasing globals that are shadowed by a local var somewhere
                walker = new uglifyJs.TreeWalker(function (node) {
                    if (node instanceof uglifyJs.AST_Dot) {
                        var name = node.print_to_string();
                        if (name in globalsObj) {
                            if (!occurrencesByGlobalName.hasOwnProperty(name)) {
                                occurrencesByGlobalName[name] = [];
                            }
                            occurrencesByGlobalName[name].push({node: node, parentNode: walker.parent()});
                        } else if (node.property.length > 2) {
                            // .foo() => [a]() won't save anything if the method name is 2 chars or less

                            if (!Object.prototype.hasOwnProperty.call(occurrencesByString, node.property)) {
                                occurrencesByString[node.property] = [];
                            }
                            occurrencesByString[node.property].push({node: node, parentNode: walker.parent()});
                        }
                    } else if (node instanceof uglifyJs.AST_Defun) {
                        seenLocals[node.name.name] = true;
                    } else if (node instanceof uglifyJs.AST_Function) {
                        if (node.name) {
                            seenLocals[node.name.name] = true;
                        }
                    } else if (node instanceof uglifyJs.AST_Definitions) {
                        node.definitions.forEach(function (definition) {
                            seenNames[definition.name.name] = true;
                            seenLocals[definition.name.name] = true;
                        });
                    } else if (node instanceof uglifyJs.AST_String) {
                        if (!Object.prototype.hasOwnProperty.call(occurrencesByString, node.value)) {
                            occurrencesByString[node.value] = [];
                        }
                        occurrencesByString[node.value].push({node: node, parentNode: walker.parent()});
                    } else if (node instanceof uglifyJs.AST_SymbolRef) {
                        seenNames[node.name] = true;
                        if (globalsObj.hasOwnProperty(node.name)) {
                            if (!occurrencesByGlobalName.hasOwnProperty(node.name)) {
                                occurrencesByGlobalName[node.name] = [];
                            }
                            occurrencesByGlobalName[node.name].push({node: node, parentNode: walker.parent()});
                        }
                    }
                });

            ast.walk(walker);

            // Order by number of dots ascending so e.g. Math is considered before Math.min:
            var globalNames = Object.keys(occurrencesByGlobalName).sort(function (a, b) {
                return a.split('.').length - b.split('.').length;
            });
            var aliasDeclarations = [],
                aliasByGlobalName = {};

            function nameToAst(name) {
                name = (!options.wrapInFunction && aliasByGlobalName.hasOwnProperty(name) && aliasByGlobalName[name]) || name;
                var nameFragments = name.split('.');
                if (nameFragments.length > 1) {
                    return new uglifyJs.AST_Dot({
                        expression: nameToAst(nameFragments.slice(0, nameFragments.length - 1).join('.')),
                        property: nameFragments[nameFragments.length - 1]
                    });
                } else {
                    return new uglifyJs.AST_SymbolRef({name: nameFragments[0]});
                }
            }

            globalNames.forEach(function (globalName) {
                if (!seenLocals.hasOwnProperty(globalName) && occurrencesByGlobalName[globalName].length > 1) {
                    var alias = globalName.replace(/\./g, '').toUpperCase();
                    while (seenNames.hasOwnProperty(alias)) {
                        alias += '_';
                    }
                    seenNames[alias] = true;
                    aliasDeclarations.push({name: alias, valueAst: nameToAst(globalName)});
                    occurrencesByGlobalName[globalName].forEach(function (occurrence) {
                        uglifyAst.replaceDescendantNode(occurrence.parentNode, occurrence.node, new uglifyJs.AST_SymbolRef({name: alias}));
                    });
                    aliasByGlobalName[globalName] = alias;
                } else {
                    delete occurrencesByGlobalName[globalName];
                }
            });

            if (options.stringLiterals) {
                Object.keys(occurrencesByString).forEach(function (string) {
                    var occurrences = occurrencesByString[string],
                        savedBytes = -string.length - 5;
                    occurrences.forEach(function (occurrence) {
                        if (occurrence.node instanceof uglifyJs.AST_String) {
                            savedBytes += string.length + 4;
                        } else {
                            // parent is AST_Dot
                            savedBytes += string.length - 3;
                        }
                    });

                    if (occurrences.length >= 2) {
                        var alias = string || 'EMPTY';
                        Object.keys(symbolNames).forEach(function (symbol) {
                            while (alias.indexOf(symbol) !== -1) {
                                alias = alias.replace(symbol, symbolNames[symbol]);
                            }
                        });

                        if (/^[0-9]/.test(alias)) {
                            alias = '_' + alias;
                        }
                        alias = alias.replace(/[^a-z0-9_]/gi, '').toUpperCase();
                        while (!alias || Object.prototype.hasOwnProperty.call(seenNames, alias)) {
                            alias += '_';
                        }
                        seenNames[alias] = true;
                        aliasDeclarations.push({name: alias, valueAst: new uglifyJs.AST_String({value: string})});
                        occurrences.forEach(function (occurrence) {
                            if (occurrence.node instanceof uglifyJs.AST_String) {
                                uglifyAst.replaceDescendantNode(occurrence.parentNode, occurrence.node, new uglifyJs.AST_SymbolRef({name: alias}));
                            } else {
                                // parent is AST_Dot
                                uglifyAst.replaceDescendantNode(occurrence.parentNode,
                                                                occurrence.node,
                                                                new uglifyJs.AST_Sub({
                                                                    property: new uglifyJs.AST_SymbolRef({name: alias}),
                                                                    expression: occurrence.node.expression
                                                                })
                                );
                            }
                        });
                    }
                });
            }

            if (aliasDeclarations.length) {
                if (options.wrapInFunction) {
                    ast.body = [
                        new uglifyJs.AST_SimpleStatement({
                            body: new uglifyJs.AST_Call({
                                expression: new uglifyJs.AST_Function({
                                    argnames: aliasDeclarations.map(function (aliasDeclaration) {
                                        return new uglifyJs.AST_SymbolFunarg({name: aliasDeclaration.name});
                                    }),
                                    body: ast.body
                                }),
                                args: _.pluck(aliasDeclarations, 'valueAst')
                            })
                        })
                    ];
                } else {
                    ast.body.unshift(new uglifyJs.AST_Var({
                        definitions: aliasDeclarations.map(function (aliasDeclaration) {
                            return new uglifyJs.AST_VarDef({
                                name: new uglifyJs.AST_SymbolVar({name: aliasDeclaration.name}),
                                value: aliasDeclaration.valueAst
                            });
                        })
                    }));
                }
                javaScriptAsset.markDirty();
            }
        });
    };
};
<commit_msg>pullGlobalsIntoVariables<commit_after>var _ = require('underscore'),
    AssetGraph = require('../'),
    uglifyJs = AssetGraph.JavaScript.uglifyJs,
    uglifyAst = AssetGraph.JavaScript.uglifyAst,
    symbolNames = {
        ' ': 'SPACE',
        '!': 'BANG',
        '.': 'DOT',
        '=': 'EQUALS',
        '~': 'TILDE',
        '$': 'DOLLAR',
        '#': 'HASH',
        '%': 'PERCENT',
        '/': 'SLASH',
        '<': 'LESSTHAN',
        '>': 'GREATERTHAN',
        '&': 'AMPERSAND',
        '?': 'QUESTIONMARK',
        '\'': 'SINGLEQUOTE',
        '"': 'DOUBLEQUOTE',
        '+': 'PLUS',
        ',': 'COMMA',
        ';': 'SEMICOLON',
        ':': 'COLON',
        '(': 'LPAREN',
        ')': 'RPAREN',
        '{': 'LBRACE',
        '}': 'RBRACE',
        '[': 'LSQBRACE',
        ']': 'RSQBRACE'
    };

module.exports = function (queryObj, options) {
    options = options || {};
    options.globalNames = options.globalNames || [];
    Array.prototype.push.apply(options.globalNames, ['eval', 'clearInterval', 'clearTimeout', 'document', 'event', 'frames', 'history', 'Image', 'localStorage', 'location', 'name', 'navigator', 'Option', 'parent', 'screen', 'sessionStorage', 'setInterval', 'setTimeout', 'Storage', 'window', 'XMLHttpRequest', 'Math', 'Math.min', 'Math.max', 'Math.round', 'Function', 'Date', 'Date.prototype', 'Math.E', 'Math.LN2', 'Math.LN10', 'Math.LOG2E', 'Math.LOG10E', 'Math.PI', 'Math.SQRT1_2', 'Math.SQRT2', 'Math.abs', 'Math.acos', 'Math.asin', 'Math.atan', 'Math.atan2', 'Math.ceil', 'Math.cos', 'Math.exp', 'Math.floor', 'Math.log', 'Math.max', 'Math.min', 'Math.pow', 'Math.random', 'Math.round', 'Math.sin', 'Math.sqrt', 'Math.tan', 'parseInt', 'parseFloat', 'isNaN', 'NaN', 'RegExp', 'RegExp.prototype', 'RegExp.prototype.compile', 'RegExp.prototype.test', 'RegExp.prototype.exec', 'String', 'String.fromCharCode', 'String.prototype', 'String.prototype.charAt', 'String.prototype.charCodeAt', 'String.prototype.indexOf', 'String.prototype.match', 'String.prototype.replace', 'String.prototype.slice', 'String.prototype.split', 'String.prototype.substr', 'String.prototype.substring', 'String.prototype.toLowerCase', 'String.prototype.toUpperCase', 'Array', 'Array.prototype', 'Array.prototype.concat', 'Array.prototype.indexOf', 'Array.prototype.join', 'Array.prototype.pop', 'Array.prototype.push', 'Array.prototype.reverse', 'Array.prototype.shift', 'Array.prototype.slice', 'Array.prototype.sort', 'Array.prototype.splice', 'Array.prototype.unshift', 'Number', 'Number.prototype', 'Number.prototype.toFixed', 'Number.MAX_VALUE', 'Number.MIN_VALUE', 'Number.NEGATIVE_INFINITY', 'Number.NaN', 'Number.POSITIVE_INFINITY', 'Number.prototype', 'Boolean', 'Boolean.prototype', 'Error', 'Error.prototype', 'EvalError', 'EvalError.prototype', 'Infinity', 'JSON', 'JSON.stringify', 'JSON.parse', 'Object', 'Object.prototype', 'Object.prototype.toString', 'RangeError', 'RangeError.prototype', 'ReferenceError', 'ReferenceError.prototype', 'SyntaxError', 'SyntaxError.prototype', 'TypeError', 'TypeError.prototype', 'URIError', 'URIError.prototype', 'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', 'isFinite', 'undefined']);

    var globalsObj = {};
    options.globalNames.forEach(function (global) {
        globalsObj[global] = true;
    });
    return function pullGlobalsIntoVariables(assetGraph) {
        assetGraph.findAssets(_.extend({type: 'JavaScript'}, queryObj)).forEach(function (javaScriptAsset) {
            var occurrencesByGlobalName = {},
                occurrencesByString = {},
                ast = javaScriptAsset.parseTree,
                seenNames = {}, // To avoid collisions when introducing new vars
                seenLocals = {}, // To avoid aliasing globals that are shadowed by a local var somewhere
                walker = new uglifyJs.TreeWalker(function (node) {
                    if (node instanceof uglifyJs.AST_Dot) {
                        var name = node.print_to_string();
                        if (name in globalsObj) {
                            if (!occurrencesByGlobalName.hasOwnProperty(name)) {
                                occurrencesByGlobalName[name] = [];
                            }
                            occurrencesByGlobalName[name].push({node: node, parentNode: walker.parent()});
                        } else if (node.property.length > 2) {
                            // .foo() => [a]() won't save anything if the method name is 2 chars or less

                            if (!Object.prototype.hasOwnProperty.call(occurrencesByString, node.property)) {
                                occurrencesByString[node.property] = [];
                            }
                            occurrencesByString[node.property].push({node: node, parentNode: walker.parent()});
                        }
                    } else if (node instanceof uglifyJs.AST_Defun) {
                        seenLocals[node.name.name] = true;
                    } else if (node instanceof uglifyJs.AST_Function) {
                        if (node.name) {
                            seenLocals[node.name.name] = true;
                        }
                    } else if (node instanceof uglifyJs.AST_Definitions) {
                        node.definitions.forEach(function (definition) {
                            seenNames[definition.name.name] = true;
                            seenLocals[definition.name.name] = true;
                        });
                    } else if (node instanceof uglifyJs.AST_String) {
                        if (!Object.prototype.hasOwnProperty.call(occurrencesByString, node.value)) {
                            occurrencesByString[node.value] = [];
                        }
                        occurrencesByString[node.value].push({node: node, parentNode: walker.parent()});
                    } else if (node instanceof uglifyJs.AST_SymbolRef) {
                        seenNames[node.name] = true;
                        if (globalsObj.hasOwnProperty(node.name)) {
                            if (!occurrencesByGlobalName.hasOwnProperty(node.name)) {
                                occurrencesByGlobalName[node.name] = [];
                            }
                            occurrencesByGlobalName[node.name].push({node: node, parentNode: walker.parent()});
                        }
                    }
                });

            ast.walk(walker);

            // Order by number of dots ascending so e.g. Math is considered before Math.min:
            var globalNames = Object.keys(occurrencesByGlobalName).sort(function (a, b) {
                return a.split('.').length - b.split('.').length;
            });
            var aliasDeclarations = [],
                aliasByGlobalName = {};

            function nameToAst(name) {
                name = (!options.wrapInFunction && aliasByGlobalName.hasOwnProperty(name) && aliasByGlobalName[name]) || name;
                var nameFragments = name.split('.');
                if (nameFragments.length > 1) {
                    return new uglifyJs.AST_Dot({
                        expression: nameToAst(nameFragments.slice(0, nameFragments.length - 1).join('.')),
                        property: nameFragments[nameFragments.length - 1]
                    });
                } else {
                    return new uglifyJs.AST_SymbolRef({name: nameFragments[0]});
                }
            }

            globalNames.forEach(function (globalName) {
                if (!seenLocals.hasOwnProperty(globalName) && occurrencesByGlobalName[globalName].length > 1) {
                    var alias = globalName.replace(/\./g, '').toUpperCase();
                    while (seenNames.hasOwnProperty(alias)) {
                        alias += '_';
                    }
                    seenNames[alias] = true;
                    aliasDeclarations.push({name: alias, valueAst: nameToAst(globalName)});
                    occurrencesByGlobalName[globalName].forEach(function (occurrence) {
                        uglifyAst.replaceDescendantNode(occurrence.parentNode, occurrence.node, new uglifyJs.AST_SymbolRef({name: alias}));
                    });
                    aliasByGlobalName[globalName] = alias;
                } else {
                    delete occurrencesByGlobalName[globalName];
                }
            });

            if (options.stringLiterals) {
                Object.keys(occurrencesByString).forEach(function (string) {
                    var occurrences = occurrencesByString[string],
                        savedBytes = -string.length - 5;
                    occurrences.forEach(function (occurrence) {
                        if (occurrence.node instanceof uglifyJs.AST_String) {
                            savedBytes += string.length + 4;
                        } else {
                            // parent is AST_Dot
                            savedBytes += string.length - 3;
                        }
                    });

                    if (occurrences.length >= 2) {
                        var alias = string || 'EMPTY';
                        Object.keys(symbolNames).forEach(function (symbol) {
                            while (alias.indexOf(symbol) !== -1) {
                                alias = alias.replace(symbol, symbolNames[symbol]);
                            }
                        });

                        if (/^[0-9]/.test(alias)) {
                            alias = '_' + alias;
                        }
                        alias = alias.replace(/[^a-z0-9_]/gi, '').toUpperCase();
                        while (!alias || Object.prototype.hasOwnProperty.call(seenNames, alias)) {
                            alias += '_';
                        }
                        seenNames[alias] = true;
                        aliasDeclarations.push({name: alias, valueAst: new uglifyJs.AST_String({value: string})});
                        occurrences.forEach(function (occurrence) {
                            if (occurrence.node instanceof uglifyJs.AST_String) {
                                uglifyAst.replaceDescendantNode(occurrence.parentNode, occurrence.node, new uglifyJs.AST_SymbolRef({name: alias}));
                            } else {
                                // parent is AST_Dot
                                uglifyAst.replaceDescendantNode(occurrence.parentNode,
                                    occurrence.node,
                                    new uglifyJs.AST_Sub({
                                        property: new uglifyJs.AST_SymbolRef({name: alias}),
                                        expression: occurrence.node.expression
                                    })
                                );
                            }
                        });
                    }
                });
            }

            if (aliasDeclarations.length) {
                if (options.wrapInFunction) {
                    ast.body = [
                        new uglifyJs.AST_SimpleStatement({
                            body: new uglifyJs.AST_Call({
                                expression: new uglifyJs.AST_Function({
                                    argnames: aliasDeclarations.map(function (aliasDeclaration) {
                                        return new uglifyJs.AST_SymbolFunarg({name: aliasDeclaration.name});
                                    }),
                                    body: ast.body
                                }),
                                args: _.pluck(aliasDeclarations, 'valueAst')
                            })
                        })
                    ];
                } else {
                    ast.body.unshift(new uglifyJs.AST_Var({
                        definitions: aliasDeclarations.map(function (aliasDeclaration) {
                            return new uglifyJs.AST_VarDef({
                                name: new uglifyJs.AST_SymbolVar({name: aliasDeclaration.name}),
                                value: aliasDeclaration.valueAst
                            });
                        })
                    }));
                }
                javaScriptAsset.markDirty();
            }
        });
    };
};
<|endoftext|>


<commit_before>/** MIT License (c) copyright 2010-2013 B Cavalier & J Hann */

/**
 * curl CommonJS Modules/1.1 loader
 *
 * This loader loads modules that conform to the CommonJS Modules/1.1 spec.
 * The loader also accommodates node.js, which  adds features beyond the
 * spec, such as `module.exports` and `this === exports`.
 *
 * CommonJS modules can't run in browser environments without help. This
 * loader wraps the modules in AMD and injects the CommonJS "free vars":
 *
 * define(function (require, exports, module) {
 *     // CommonJS code goes here.
 * });
 *
 * Config options:
 *
 * `injectSourceUrl` {boolean} If truthy (default), a //@sourceURL is injected
 * into the script so that debuggers may display a meaningful name in the
 * list of scripts. Setting this to false may save a few bytes.
 *
 * `injectScript` {boolean} If truthy, a <script> element will be inserted,
 * rather than using a global `eval()` to execute the module.  You typically
 * won't need to use this option.
 *
 * `dontAddFileExt` {RegExp|string} An expression that determines when *not*
 * to add a '.js' extension onto a url when fetching a module from a server.
 */

(function (global, document, globalEval) {

define(/*=='curl/loader/cjsm11',==*/ ['../plugin/_fetchText', 'curl/_privileged'], function (fetchText, priv) {

	var head, insertBeforeEl, extractCjsDeps, checkToAddJsExt;

	head = document && (document['head'] || document.getElementsByTagName('head')[0]);
	// to keep IE from crying, we need to put scripts before any
	// <base> elements, but after any <meta>. this should do it:
	insertBeforeEl = head && head.getElementsByTagName('base')[0] || null;

	extractCjsDeps = priv['core'].extractCjsDeps;
	checkToAddJsExt = priv['core'].checkToAddJsExt;

	function wrapSource (source, resourceId, fullUrl) {
		var sourceUrl = fullUrl ? '/*\n////@ sourceURL=' + fullUrl.replace(/\s/g, '%20') + '.js\n*/' : '';
		return "define('" + resourceId + "'," +
			"['require','exports','module'],function(require,exports,module){" +
			source + "\n});\n" + sourceUrl + "\n";
	}

	var injectSource = function (el, source) {
		// got this from Stoyan Stefanov (http://www.phpied.com/dynamic-script-and-style-elements-in-ie/)
		injectSource = ('text' in el) ?
			function (el, source) { el.text = source; } :
			function (el, source) { el.appendChild(document.createTextNode(source)); };
		injectSource(el, source);
	};

	function injectScript (source) {
		var el = document.createElement('script');
		injectSource(el, source);
		el.charset = 'utf-8';
		head.insertBefore(el, insertBeforeEl);
	}

	wrapSource['load'] = function (resourceId, require, callback, config) {
		var errback, url, sourceUrl;

		errback = callback['error'] || function (ex) { throw ex; };
		url = checkToAddJsExt(require.toUrl(resourceId), config);
		sourceUrl = config['injectSourceUrl'] !== false && url;

		fetchText(url, function (source) {
			var moduleMap;

			// find (and replace?) dependencies
			moduleMap = extractCjsDeps(source);

			// get deps
			require(moduleMap, function () {

				// wrap source in a define
				source = wrapSource(source, resourceId, sourceUrl);

				if (config['injectScript']) {
					injectScript(source);
				}
				else {
					//eval(source);
					globalEval(source);
				}

				// call callback now that the module is defined
				callback(require(resourceId));

			}, errback);
		}, errback);
	};

	wrapSource['cramPlugin'] = '../cram/cjsm11';

	return wrapSource;

});

}(this, this.document, function () { /* FB needs direct eval here */ eval(arguments[0]); }));
<commit_msg>Ensure that `define` is undefined when wrapping cjs/node modules.<commit_after>/** MIT License (c) copyright 2010-2013 B Cavalier & J Hann */

/**
 * curl CommonJS Modules/1.1 loader
 *
 * This loader loads modules that conform to the CommonJS Modules/1.1 spec.
 * The loader also accommodates node.js, which  adds features beyond the
 * spec, such as `module.exports` and `this === exports`.
 *
 * CommonJS modules can't run in browser environments without help. This
 * loader wraps the modules in AMD and injects the CommonJS "free vars":
 *
 * define(function (require, exports, module) {
 *     // CommonJS code goes here.
 * });
 *
 * Config options:
 *
 * `injectSourceUrl` {boolean} If truthy (default), a //@sourceURL is injected
 * into the script so that debuggers may display a meaningful name in the
 * list of scripts. Setting this to false may save a few bytes.
 *
 * `injectScript` {boolean} If truthy, a <script> element will be inserted,
 * rather than using a global `eval()` to execute the module.  You typically
 * won't need to use this option.
 *
 * `dontAddFileExt` {RegExp|string} An expression that determines when *not*
 * to add a '.js' extension onto a url when fetching a module from a server.
 */

(function (global, document, globalEval) {

define(/*=='curl/loader/cjsm11',==*/ ['../plugin/_fetchText', 'curl/_privileged'], function (fetchText, priv) {

	var head, insertBeforeEl, extractCjsDeps, checkToAddJsExt;

	head = document && (document['head'] || document.getElementsByTagName('head')[0]);
	// to keep IE from crying, we need to put scripts before any
	// <base> elements, but after any <meta>. this should do it:
	insertBeforeEl = head && head.getElementsByTagName('base')[0] || null;

	extractCjsDeps = priv['core'].extractCjsDeps;
	checkToAddJsExt = priv['core'].checkToAddJsExt;

	function wrapSource (source, resourceId, fullUrl) {
		var sourceUrl = fullUrl ? '/*\n////@ sourceURL=' + fullUrl.replace(/\s/g, '%20') + '.js\n*/' : '';
		return "define('" + resourceId + "'," +
			"['require','exports','module'],function(require,exports,module){var define;" +
			source + "\n});\n" + sourceUrl + "\n";
	}

	var injectSource = function (el, source) {
		// got this from Stoyan Stefanov (http://www.phpied.com/dynamic-script-and-style-elements-in-ie/)
		injectSource = ('text' in el) ?
			function (el, source) { el.text = source; } :
			function (el, source) { el.appendChild(document.createTextNode(source)); };
		injectSource(el, source);
	};

	function injectScript (source) {
		var el = document.createElement('script');
		injectSource(el, source);
		el.charset = 'utf-8';
		head.insertBefore(el, insertBeforeEl);
	}

	wrapSource['load'] = function (resourceId, require, callback, config) {
		var errback, url, sourceUrl;

		errback = callback['error'] || function (ex) { throw ex; };
		url = checkToAddJsExt(require.toUrl(resourceId), config);
		sourceUrl = config['injectSourceUrl'] !== false && url;

		fetchText(url, function (source) {
			var moduleMap;

			// find (and replace?) dependencies
			moduleMap = extractCjsDeps(source);

			// get deps
			require(moduleMap, function () {

				// wrap source in a define
				source = wrapSource(source, resourceId, sourceUrl);

				if (config['injectScript']) {
					injectScript(source);
				}
				else {
					//eval(source);
					globalEval(source);
				}

				// call callback now that the module is defined
				callback(require(resourceId));

			}, errback);
		}, errback);
	};

	wrapSource['cramPlugin'] = '../cram/cjsm11';

	return wrapSource;

});

}(this, this.document, function () { /* FB needs direct eval here */ eval(arguments[0]); }));
<|endoftext|>


<commit_before>## -*- coding: utf-8 -*-
<%
from classes.utils import js_escape
%>

% if HAVE_SSO_LOGIN:
var HAVE_SSO_LOGIN = true;
var SSO_TOKEN_EXPIRE_DT = new Date('${SSO_TOKEN_EXPIRE_DT}'); // in UTC
var SSO_CHAR_ID = '${SSO_CHAR_ID}';
var SSO_CHAR_NAME = '${SSO_CHAR_NAME|js_escape}';
var SSO_CORP_ID = '${SSO_CORP_ID}';
var SSO_CORP_NAME = '${SSO_CORP_NAME|js_escape}';
var SSO_SHIP_ID = '${SSO_SHIP_ID}';
var SSO_SHIP_NAME = '${SSO_SHIP_NAME|js_escape}';
var SSO_SHIP_TITLE = '${SSO_SHIP_TITLE|js_escape}';
var SSO_SOLARSYSTEM_ID = '${SSO_SOLARSYSTEM_ID}';
var SSO_SOLARSYSTEM_NAME = '${SSO_SOLARSYSTEM_NAME|js_escape}';
var SSO_IS_DOCKED = false;
window.setTimeout(evesso_refresher, 2000);
% else:
var HAVE_SSO_LOGIN = false;
var SSO_TOKEN_EXPIRE_DT = new Date(new Date().getTime()); // current time in UTC
%endif
<commit_msg>JS: add global var SSO_IS_ONLINE<commit_after>## -*- coding: utf-8 -*-
<%
from classes.utils import js_escape
%>

% if HAVE_SSO_LOGIN:
var HAVE_SSO_LOGIN = true;
var SSO_TOKEN_EXPIRE_DT = new Date('${SSO_TOKEN_EXPIRE_DT}'); // in UTC
var SSO_CHAR_ID = '${SSO_CHAR_ID}';
var SSO_CHAR_NAME = '${SSO_CHAR_NAME|js_escape}';
var SSO_CORP_ID = '${SSO_CORP_ID}';
var SSO_CORP_NAME = '${SSO_CORP_NAME|js_escape}';
var SSO_SHIP_ID = '${SSO_SHIP_ID}';
var SSO_SHIP_NAME = '${SSO_SHIP_NAME|js_escape}';
var SSO_SHIP_TITLE = '${SSO_SHIP_TITLE|js_escape}';
var SSO_SOLARSYSTEM_ID = '${SSO_SOLARSYSTEM_ID}';
var SSO_SOLARSYSTEM_NAME = '${SSO_SOLARSYSTEM_NAME|js_escape}';
var SSO_IS_DOCKED = false;
var SSO_IS_ONLINE = false;
window.setTimeout(evesso_refresher, 2000);
% else:
var HAVE_SSO_LOGIN = false;
var SSO_TOKEN_EXPIRE_DT = new Date(new Date().getTime()); // current time in UTC
%endif
<|endoftext|>


<commit_before>/*
* @author Johan Oakes
* Application to send message from phone by way of console
*/
const PUSHBULLET_API =  'https://api.pushbullet.com/v2/';
const request = require('request');
const config = require('../config');

/*
* Constructs a new instance of the Pushbullet Client
* @constructor
* @this {Pushbullet Client}
*/
function PushbulletClient() {
  const _this = this;

  // The current profile's user id
  _this.userID = null;

  /*
  * Helper for getting the request object
  * @param path {String} path the relative URI path
  * @param data {Object} data an object of extra values
  */
  var getRequestOptions = function(path, data) {
    var options = {
      url: PUSHBULLET_API + path,
      json: data
    };

    var headers = {
      'Access-Token' : config.auth.access_token
    }

    options.headers = headers;

    return options;
  };

  /*
  * Issues a GET request to the Pushbullet API
  * @param {String} path the relative URI path
  * @param {String} method GET, POST, PUT, etc.
  * @param {Object} data an object of extra values
  * @param {Function} callback the callback to invoke when the req completes
  */
  var bulletMethod = function(path, method, data, callback) {
    var opts = getRequestOptions(path, data);
    opts.method = method;
    request(opts, callback);
  };

  /*
  * Helper for transforming the request callback values
  * @param {Function} callback the callback to invoke when req completes
  */
  var makeBulletCallback = function(callback) {
    return function(err, res, body) {
      var data = null;

      if(!err) {
        if (typeof body === "string") {
          try {
            data = JSON.parse(body);
          } catch (err) {
            // TODO : Catch the error
          }
        } else if (typeof body === "object") data = body;
      }
      if (callback) {
        callback(err, data);
      }
    };
  };

  /*
  * Gets the current users
  * @param {Object} data
  * @param {Function} callback
  * TODO: Revise callback
  */
  _this.getUser = function(data, callback) {
    bulletMethod('users/me', 'GET', data, makeBulletCallback((err, data) => console.dir(data)));
  };

  /*
  * Get a list of chats belonging to the current user
  * @param {Object} data
  * @param {Function} callback callback to invoke when req completes
  * TODO: Revise callback
  */
  _this.getDevicesList = function(data, callback) {
    bulletMethod('devices', 'GET',data, makeBulletCallback((err, data) => console.dir(data)));
  };

  /*
  * Send out an SMS
  */
  _this.sendSMS = function(data, callback) {
    bulletMethod('ephemerals', 'POST', data, makeBulletCallback(
      callback));
  };

};

exports.PushbulletClient = PushbulletClient;
<commit_msg>Fix callback and error catching<commit_after>/*
* @author Johan Oakes
* Application to send message from phone by way of console
*/
const PUSHBULLET_API =  'https://api.pushbullet.com/v2/';
const request = require('request');
const config = require('../config');

/*
* Constructs a new instance of the Pushbullet Client
* @constructor
* @this {Pushbullet Client}
*/
function PushbulletClient() {
  const _this = this;

  // The current profile's user id
  _this.userID = null;

  /*
  * Helper for getting the request object
  * @param path {String} path the relative URI path
  * @param data {Object} data an object of extra values
  */
  var getRequestOptions = function(path, data) {
    var options = {
      url: PUSHBULLET_API + path,
      json: data
    };

    var headers = {
      'Access-Token' : config.auth.access_token
    };

    options.headers = headers;

    return options;
  };

  /*
  * Issues a GET request to the Pushbullet API
  * @param {String} path the relative URI path
  * @param {String} method GET, POST, PUT, etc.
  * @param {Object} data an object of extra values
  * @param {Function} callback the callback to invoke when the req completes
  */
  var bulletMethod = function(path, method, data, callback) {
    var opts = getRequestOptions(path, data);
    opts.method = method;
    request(opts, callback);
  };

  /*
  * Helper for transforming the request callback values
  * @param {Function} callback the callback to invoke when req completes
  */
  var makeBulletCallback = function(callback) {
    return function(err, res, body) {
      var data = null;

      if(!err) {
        if (typeof body === "string") {
          try {
            data = JSON.parse(body);
          } catch (err) {
            return console.error(err);
          }
        } else if (typeof body === "object") data = body;
      } else {
        console.log("Error in trying to parse data in callback function");
      }
      if (callback) {
        callback(err, data);
      }
    };
  };

  /*
  * Gets the current users
  * @param {Object} data"
  * @param {Function} callback
  * TODO: Revise callback
  */
  _this.getUser = function(data, callback) {
    bulletMethod('users/me', 'GET', data, makeBulletCallback(callback));
  };

  /*
  * Get a list of chats belonging to the current user
  * @param {Object} data
  * @param {Function} callback callback to invoke when req completes
  * TODO: Revise callback
  */
  _this.getDevicesList = function(data, callback) {
    bulletMethod('devices', 'GET',data, makeBulletCallback(callback));
  };

  /*
  * Send out an SMS
  */
  _this.sendSMS = function(data, callback) {
    bulletMethod('ephemerals', 'POST', data, makeBulletCallback(callback));
  };

};

exports.PushbulletClient = PushbulletClient;
<|endoftext|>


<commit_before>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

//  Based on the three.js Curve classes created by [zz85](http://www.lab4games.net/zz85/blog)

var CatmullRom = require('../math/CatmullRom');
var Class = require('../utils/Class');
var Curve = require('./Curve');
var Vector2 = require('../math/Vector2');

/**
 * @classdesc
 * Create a smooth 2d spline curve from a series of points.
 *
 * @class Spline
 * @extends Phaser.Curves.Curve
 * @memberof Phaser.Curves
 * @constructor
 * @since 3.0.0
 *
 * @param {(Phaser.Math.Vector2[]|number[]|number[][])} [points] - The points that configure the curve.
 */
var SplineCurve = new Class({

    Extends: Curve,

    initialize:

    function SplineCurve (points)
    {
        if (points === undefined) { points = []; }

        Curve.call(this, 'SplineCurve');

        /**
         * The Vector2 points that configure the curve.
         *
         * @name Phaser.Curves.Spline#points
         * @type {Phaser.Math.Vector2[]}
         * @default []
         * @since 3.0.0
         */
        this.points = [];

        this.addPoints(points);
    },

    /**
     * Add a list of points to the current list of Vector2 points of the curve.
     *
     * @method Phaser.Curves.Spline#addPoints
     * @since 3.0.0
     *
     * @param {(Phaser.Math.Vector2[]|number[]|number[][])} points - The points that configure the curve.
     *
     * @return {Phaser.Curves.Spline} This curve object.
     */
    addPoints: function (points)
    {
        for (var i = 0; i < points.length; i++)
        {
            var p = new Vector2();

            if (typeof points[i] === 'number')
            {
                p.x = points[i];
                p.y = points[i + 1];
                i++;
            }
            else if (Array.isArray(points[i]))
            {
                //  An array of arrays?
                p.x = points[i][0];
                p.y = points[i][1];
            }
            else
            {
                p.x = points[i].x;
                p.y = points[i].y;
            }

            this.points.push(p);
        }

        return this;
    },

    /**
     * Add a point to the current list of Vector2 points of the curve.
     *
     * @method Phaser.Curves.Spline#addPoint
     * @since 3.0.0
     *
     * @param {number} x - The x coordinate of this curve
     * @param {number} y - The y coordinate of this curve
     *
     * @return {Phaser.Math.Vector2} The new Vector2 added to the curve
     */
    addPoint: function (x, y)
    {
        var vec = new Vector2(x, y);

        this.points.push(vec);

        return vec;
    },

    /**
     * Gets the starting point on the curve.
     *
     * @method Phaser.Curves.Spline#getStartPoint
     * @since 3.0.0
     *
     * @generic {Phaser.Math.Vector2} O - [out,$return]
     *
     * @param {Phaser.Math.Vector2} [out] - A Vector2 object to store the result in. If not given will be created.
     *
     * @return {Phaser.Math.Vector2} The coordinates of the point on the curve. If an `out` object was given this will be returned.
     */
    getStartPoint: function (out)
    {
        if (out === undefined) { out = new Vector2(); }

        return out.copy(this.points[0]);
    },

    /**
     * [description]
     *
     * @method Phaser.Curves.Spline#getResolution
     * @since 3.0.0
     *
     * @param {number} divisions - [description]
     *
     * @return {number} [description]
     */
    getResolution: function (divisions)
    {
        return divisions * this.points.length;
    },

    /**
     * Get point at relative position in curve according to length.
     *
     * @method Phaser.Curves.Spline#getPoint
     * @since 3.0.0
     *
     * @generic {Phaser.Math.Vector2} O - [out,$return]
     *
     * @param {number} t - The position along the curve to return. Where 0 is the start and 1 is the end.
     * @param {Phaser.Math.Vector2} [out] - A Vector2 object to store the result in. If not given will be created.
     *
     * @return {Phaser.Math.Vector2} The coordinates of the point on the curve. If an `out` object was given this will be returned.
     */
    getPoint: function (t, out)
    {
        if (out === undefined) { out = new Vector2(); }

        var points = this.points;

        var point = (points.length - 1) * t;

        var intPoint = Math.floor(point);

        var weight = point - intPoint;

        var p0 = points[(intPoint === 0) ? intPoint : intPoint - 1];
        var p1 = points[intPoint];
        var p2 = points[(intPoint > points.length - 2) ? points.length - 1 : intPoint + 1];
        var p3 = points[(intPoint > points.length - 3) ? points.length - 1 : intPoint + 2];

        return out.set(CatmullRom(weight, p0.x, p1.x, p2.x, p3.x), CatmullRom(weight, p0.y, p1.y, p2.y, p3.y));
    },

    /**
     * Exports a JSON object containing this curve data.
     *
     * @method Phaser.Curves.Spline#toJSON
     * @since 3.0.0
     *
     * @return {Phaser.Types.Curves.JSONCurve} The JSON object containing this curve data.
     */
    toJSON: function ()
    {
        var points = [];

        for (var i = 0; i < this.points.length; i++)
        {
            points.push(this.points[i].x);
            points.push(this.points[i].y);
        }

        return {
            type: this.type,
            points: points
        };
    }

});

/**
 * Imports a JSON object containing this curve data.
 *
 * @function Phaser.Curves.Spline.fromJSON
 * @since 3.0.0
 *
 * @param {Phaser.Types.Curves.JSONCurve} data - The JSON object containing this curve data.
 *
 * @return {Phaser.Curves.Spline} The spline curve created.
 */
SplineCurve.fromJSON = function (data)
{
    return new SplineCurve(data.points);
};

module.exports = SplineCurve;
<commit_msg>Fixed `this` return types for `Phaser.Curves.Spline`<commit_after>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

//  Based on the three.js Curve classes created by [zz85](http://www.lab4games.net/zz85/blog)

var CatmullRom = require('../math/CatmullRom');
var Class = require('../utils/Class');
var Curve = require('./Curve');
var Vector2 = require('../math/Vector2');

/**
 * @classdesc
 * Create a smooth 2d spline curve from a series of points.
 *
 * @class Spline
 * @extends Phaser.Curves.Curve
 * @memberof Phaser.Curves
 * @constructor
 * @since 3.0.0
 *
 * @param {(Phaser.Math.Vector2[]|number[]|number[][])} [points] - The points that configure the curve.
 */
var SplineCurve = new Class({

    Extends: Curve,

    initialize:

    function SplineCurve (points)
    {
        if (points === undefined) { points = []; }

        Curve.call(this, 'SplineCurve');

        /**
         * The Vector2 points that configure the curve.
         *
         * @name Phaser.Curves.Spline#points
         * @type {Phaser.Math.Vector2[]}
         * @default []
         * @since 3.0.0
         */
        this.points = [];

        this.addPoints(points);
    },

    /**
     * Add a list of points to the current list of Vector2 points of the curve.
     *
     * @method Phaser.Curves.Spline#addPoints
     * @since 3.0.0
     *
     * @param {(Phaser.Math.Vector2[]|number[]|number[][])} points - The points that configure the curve.
     *
     * @return {this} This curve object.
     */
    addPoints: function (points)
    {
        for (var i = 0; i < points.length; i++)
        {
            var p = new Vector2();

            if (typeof points[i] === 'number')
            {
                p.x = points[i];
                p.y = points[i + 1];
                i++;
            }
            else if (Array.isArray(points[i]))
            {
                //  An array of arrays?
                p.x = points[i][0];
                p.y = points[i][1];
            }
            else
            {
                p.x = points[i].x;
                p.y = points[i].y;
            }

            this.points.push(p);
        }

        return this;
    },

    /**
     * Add a point to the current list of Vector2 points of the curve.
     *
     * @method Phaser.Curves.Spline#addPoint
     * @since 3.0.0
     *
     * @param {number} x - The x coordinate of this curve
     * @param {number} y - The y coordinate of this curve
     *
     * @return {Phaser.Math.Vector2} The new Vector2 added to the curve
     */
    addPoint: function (x, y)
    {
        var vec = new Vector2(x, y);

        this.points.push(vec);

        return vec;
    },

    /**
     * Gets the starting point on the curve.
     *
     * @method Phaser.Curves.Spline#getStartPoint
     * @since 3.0.0
     *
     * @generic {Phaser.Math.Vector2} O - [out,$return]
     *
     * @param {Phaser.Math.Vector2} [out] - A Vector2 object to store the result in. If not given will be created.
     *
     * @return {Phaser.Math.Vector2} The coordinates of the point on the curve. If an `out` object was given this will be returned.
     */
    getStartPoint: function (out)
    {
        if (out === undefined) { out = new Vector2(); }

        return out.copy(this.points[0]);
    },

    /**
     * [description]
     *
     * @method Phaser.Curves.Spline#getResolution
     * @since 3.0.0
     *
     * @param {number} divisions - [description]
     *
     * @return {number} [description]
     */
    getResolution: function (divisions)
    {
        return divisions * this.points.length;
    },

    /**
     * Get point at relative position in curve according to length.
     *
     * @method Phaser.Curves.Spline#getPoint
     * @since 3.0.0
     *
     * @generic {Phaser.Math.Vector2} O - [out,$return]
     *
     * @param {number} t - The position along the curve to return. Where 0 is the start and 1 is the end.
     * @param {Phaser.Math.Vector2} [out] - A Vector2 object to store the result in. If not given will be created.
     *
     * @return {Phaser.Math.Vector2} The coordinates of the point on the curve. If an `out` object was given this will be returned.
     */
    getPoint: function (t, out)
    {
        if (out === undefined) { out = new Vector2(); }

        var points = this.points;

        var point = (points.length - 1) * t;

        var intPoint = Math.floor(point);

        var weight = point - intPoint;

        var p0 = points[(intPoint === 0) ? intPoint : intPoint - 1];
        var p1 = points[intPoint];
        var p2 = points[(intPoint > points.length - 2) ? points.length - 1 : intPoint + 1];
        var p3 = points[(intPoint > points.length - 3) ? points.length - 1 : intPoint + 2];

        return out.set(CatmullRom(weight, p0.x, p1.x, p2.x, p3.x), CatmullRom(weight, p0.y, p1.y, p2.y, p3.y));
    },

    /**
     * Exports a JSON object containing this curve data.
     *
     * @method Phaser.Curves.Spline#toJSON
     * @since 3.0.0
     *
     * @return {Phaser.Types.Curves.JSONCurve} The JSON object containing this curve data.
     */
    toJSON: function ()
    {
        var points = [];

        for (var i = 0; i < this.points.length; i++)
        {
            points.push(this.points[i].x);
            points.push(this.points[i].y);
        }

        return {
            type: this.type,
            points: points
        };
    }

});

/**
 * Imports a JSON object containing this curve data.
 *
 * @function Phaser.Curves.Spline.fromJSON
 * @since 3.0.0
 *
 * @param {Phaser.Types.Curves.JSONCurve} data - The JSON object containing this curve data.
 *
 * @return {Phaser.Curves.Spline} The spline curve created.
 */
SplineCurve.fromJSON = function (data)
{
    return new SplineCurve(data.points);
};

module.exports = SplineCurve;
<|endoftext|>


<commit_before>/**
 * Sandbox for executing javascript, parsing css styles and doing dom operations in a secure way
 *
 * Browser Compatibility:
 *  - Secure in MSIE 6+, but only when the user hasn't made changes to his security level "restricted"
 *  - Partially secure in other browsers (Firefox, Opera, Safari, Chrome, ...)
 *
 * Please note that this class can't benefit from the HTML5 sandbox attribute for the following reasons:
 *    - sandboxing doesn't work correctly with inlined content (src="javascript:'...'")
 *    - sandboxing of physical documents causes that the dom isn't accessible anymore from the outside (iframe.contentWindow, ...)
 *    - setting the "allow-same-origin" flag would fix that, but then still javascript and dom events refuse to fire
 *    - therefore the "allow-scripts" flag is needed, which then would deactivate any security, as the js executed inside the iframe
 *      can do anything as if the sandbox attribute wasn't set
 *
 * @param {Function} [readyCallback] Method that gets invoked when the sandbox is ready
 * @param {Object} [config] Optional parameters
 *
 * @example
 *    new wysihtml5.dom.Sandbox(function(sandbox) {
 *      sandbox.getWindow().document.body.innerHTML = '';
 *    });
 */
(function(wysihtml5) {
  var /**
       * Default configuration
       */
      doc                 = document,
      /**
       * Properties to unset/protect on the window object
       */
      windowProperties    = [
        "parent", "top", "opener", "frameElement", "frames",
        "localStorage", "globalStorage", "sessionStorage", "indexedDB"
      ],
      /**
       * Properties on the window object which are set to an empty function
       */
      windowProperties2   = [
        "open", "close", "openDialog", "showModalDialog",
        "alert", "confirm", "prompt",
        "openDatabase", "postMessage",
        "XMLHttpRequest", "XDomainRequest"
      ],
      /**
       * Properties to unset/proetect on the document object
       */
      documentProperties  = [
        "referrer",
        "write", "open", "close"
      ];

  wysihtml5.dom.Sandbox = Base.extend(
    /** @scope wysihtml5.dom.Sandbox.prototype */ {

    constructor: function(readyCallback, config) {
      this.callback = readyCallback || wysihtml5.EMPTY_FUNCTION;
      this.config   = wysihtml5.lang.object({}).merge(config).get();
      this.iframe   = this._createIframe();
    },

    insertInto: function(element) {
      if (typeof(element) === "string") {
        element = doc.getElementById(element);
      }

      element.appendChild(this.iframe);
    },

    getIframe: function() {
      return this.iframe;
    },

    getWindow: function() {
      this._readyError();
    },

    getDocument: function() {
      this._readyError();
    },

    destroy: function() {
      var iframe = this.getIframe();
      iframe.parentNode.removeChild(iframe);
    },

    _readyError: function() {
      throw new Error("wysihtml5.Sandbox: Sandbox iframe isn't loaded yet");
    },

    /**
     * Creates the sandbox iframe
     *
     * Some important notes:
     *  - We can't use HTML5 sandbox for now:
     *    setting it causes that the iframe's dom can't be accessed from the outside
     *    Therefore we need to set the "allow-same-origin" flag which enables accessing the iframe's dom
     *    But then there's another problem, DOM events (focus, blur, change, keypress, ...) aren't fired.
     *    In order to make this happen we need to set the "allow-scripts" flag.
     *    A combination of allow-scripts and allow-same-origin is almost the same as setting no sandbox attribute at all.
     *  - Chrome & Safari, doesn't seem to support sandboxing correctly when the iframe's html is inlined (no physical document)
     *  - IE needs to have the security="restricted" attribute set before the iframe is
     *    inserted into the dom tree
     *  - Believe it or not but in IE "security" in document.createElement("iframe") is false, even
     *    though it supports it
     *  - When an iframe has security="restricted", in IE eval() & execScript() don't work anymore
     *  - IE doesn't fire the onload event when the content is inlined in the src attribute, therefore we rely
     *    on the onreadystatechange event
     */
    _createIframe: function() {
      var that   = this,
          iframe = doc.createElement("iframe");
      iframe.className = "wysihtml5-sandbox";
      wysihtml5.dom.setAttributes({
        "security":           "restricted",
        "allowtransparency":  "true",
        "frameborder":        0,
        "width":              0,
        "height":             0,
        "marginwidth":        0,
        "marginheight":       0
      }).on(iframe);

      // Setting the src like this prevents ssl warnings in IE6
      if (wysihtml5.browser.throwsMixedContentWarningWhenIframeSrcIsEmpty()) {
        iframe.src = "javascript:''";
      }

      iframe.onload = function() {
        iframe.onreadystatechange = iframe.onload = null;
        that._onLoadIframe(iframe);
      };

      iframe.onreadystatechange = function() {
        if (/loaded|complete/.test(iframe.readyState)) {
          iframe.onreadystatechange = iframe.onload = null;
          that._onLoadIframe(iframe);
        }
      };

      return iframe;
    },

    /**
     * Callback for when the iframe has finished loading
     */
    _onLoadIframe: function(iframe) {
      // don't resume when the iframe got unloaded (eg. by removing it from the dom)
      if (!wysihtml5.dom.contains(doc.documentElement, iframe)) {
        return;
      }

      var that           = this,
          iframeWindow   = iframe.contentWindow,
          iframeDocument = iframe.contentWindow.document,
          charset        = doc.characterSet || doc.charset || "utf-8",
          sandboxHtml    = this._getHtml({
            charset:      charset,
            stylesheets:  this.config.stylesheets
          });

      // Create the basic dom tree including proper DOCTYPE and charset
      iframeDocument.open("text/html", "replace");
      iframeDocument.write(sandboxHtml);
      iframeDocument.close();

      this.getWindow = function() { return iframe.contentWindow; };
      this.getDocument = function() { return iframe.contentWindow.document; };

      // Catch js errors and pass them to the parent's onerror event
      // addEventListener("error") doesn't work properly in some browsers
      // TODO: apparently this doesn't work in IE9!
      iframeWindow.onerror = function(errorMessage, fileName, lineNumber) {
        throw new Error("wysihtml5.Sandbox: " + errorMessage, fileName, lineNumber);
      };

      if (!wysihtml5.browser.supportsSandboxedIframes()) {
        // Unset a bunch of sensitive variables
        // Please note: This isn't hack safe!
        // It more or less just takes care of basic attacks and prevents accidental theft of sensitive information
        // IE is secure though, which is the most important thing, since IE is the only browser, who
        // takes over scripts & styles into contentEditable elements when copied from external websites
        // or applications (Microsoft Word, ...)
        var i, length;
        for (i=0, length=windowProperties.length; i<length; i++) {
          this._unset(iframeWindow, windowProperties[i]);
        }
        for (i=0, length=windowProperties2.length; i<length; i++) {
          this._unset(iframeWindow, windowProperties2[i], wysihtml5.EMPTY_FUNCTION);
        }
        for (i=0, length=documentProperties.length; i<length; i++) {
          this._unset(iframeDocument, documentProperties[i]);
        }
        // This doesn't work in Safari 5
        // See http://stackoverflow.com/questions/992461/is-it-possible-to-override-document-cookie-in-webkit
        this._unset(iframeDocument, "cookie", "", true);
      }

      this.loaded = true;

      // Trigger the callback
      setTimeout(function() { that.callback(that); }, 0);
    },

    _getHtml: function(templateVars) {
      var stylesheets = templateVars.stylesheets,
          html        = "",
          i           = 0,
          length;
      stylesheets = typeof(stylesheets) === "string" ? [stylesheets] : stylesheets;
      if (stylesheets) {
        length = stylesheets.length;
        for (; i<length; i++) {
          html += '<link rel="stylesheet" href="' + stylesheets[i] + '">';
        }
      }
      templateVars.stylesheets = html;

      return wysihtml5.lang.string(
        '<!DOCTYPE html>'
        + '<meta charset="#{charset}">#{stylesheets}'
        + ''
      ).interpolate(templateVars);
    },

    /**
     * Method to unset/override existing variables
     * @example
     *    // Make cookie unreadable and unwritable
     *    this._unset(document, "cookie", "", true);
     */
    _unset: function(object, property, value, setter) {
      try { object[property] = value; } catch(e) {}

      try { object.__defineGetter__(property, function() { return value; }); } catch(e) {}
      if (setter) {
        try { object.__defineSetter__(property, function() {}); } catch(e) {}
      }

      if (!wysihtml5.browser.crashesWhenDefineProperty(property)) {
        try {
          var config = {
            get: function() { return value; }
          };
          if (setter) {
            config.set = function() {};
          }
          Object.defineProperty(object, property, config);
        } catch(e) {}
      }
    }
  });
})(wysihtml5);
<commit_msg>Fix typo in comment<commit_after>/**
 * Sandbox for executing javascript, parsing css styles and doing dom operations in a secure way
 *
 * Browser Compatibility:
 *  - Secure in MSIE 6+, but only when the user hasn't made changes to his security level "restricted"
 *  - Partially secure in other browsers (Firefox, Opera, Safari, Chrome, ...)
 *
 * Please note that this class can't benefit from the HTML5 sandbox attribute for the following reasons:
 *    - sandboxing doesn't work correctly with inlined content (src="javascript:'...'")
 *    - sandboxing of physical documents causes that the dom isn't accessible anymore from the outside (iframe.contentWindow, ...)
 *    - setting the "allow-same-origin" flag would fix that, but then still javascript and dom events refuse to fire
 *    - therefore the "allow-scripts" flag is needed, which then would deactivate any security, as the js executed inside the iframe
 *      can do anything as if the sandbox attribute wasn't set
 *
 * @param {Function} [readyCallback] Method that gets invoked when the sandbox is ready
 * @param {Object} [config] Optional parameters
 *
 * @example
 *    new wysihtml5.dom.Sandbox(function(sandbox) {
 *      sandbox.getWindow().document.body.innerHTML = '';
 *    });
 */
(function(wysihtml5) {
  var /**
       * Default configuration
       */
      doc                 = document,
      /**
       * Properties to unset/protect on the window object
       */
      windowProperties    = [
        "parent", "top", "opener", "frameElement", "frames",
        "localStorage", "globalStorage", "sessionStorage", "indexedDB"
      ],
      /**
       * Properties on the window object which are set to an empty function
       */
      windowProperties2   = [
        "open", "close", "openDialog", "showModalDialog",
        "alert", "confirm", "prompt",
        "openDatabase", "postMessage",
        "XMLHttpRequest", "XDomainRequest"
      ],
      /**
       * Properties to unset/protect on the document object
       */
      documentProperties  = [
        "referrer",
        "write", "open", "close"
      ];

  wysihtml5.dom.Sandbox = Base.extend(
    /** @scope wysihtml5.dom.Sandbox.prototype */ {

    constructor: function(readyCallback, config) {
      this.callback = readyCallback || wysihtml5.EMPTY_FUNCTION;
      this.config   = wysihtml5.lang.object({}).merge(config).get();
      this.iframe   = this._createIframe();
    },

    insertInto: function(element) {
      if (typeof(element) === "string") {
        element = doc.getElementById(element);
      }

      element.appendChild(this.iframe);
    },

    getIframe: function() {
      return this.iframe;
    },

    getWindow: function() {
      this._readyError();
    },

    getDocument: function() {
      this._readyError();
    },

    destroy: function() {
      var iframe = this.getIframe();
      iframe.parentNode.removeChild(iframe);
    },

    _readyError: function() {
      throw new Error("wysihtml5.Sandbox: Sandbox iframe isn't loaded yet");
    },

    /**
     * Creates the sandbox iframe
     *
     * Some important notes:
     *  - We can't use HTML5 sandbox for now:
     *    setting it causes that the iframe's dom can't be accessed from the outside
     *    Therefore we need to set the "allow-same-origin" flag which enables accessing the iframe's dom
     *    But then there's another problem, DOM events (focus, blur, change, keypress, ...) aren't fired.
     *    In order to make this happen we need to set the "allow-scripts" flag.
     *    A combination of allow-scripts and allow-same-origin is almost the same as setting no sandbox attribute at all.
     *  - Chrome & Safari, doesn't seem to support sandboxing correctly when the iframe's html is inlined (no physical document)
     *  - IE needs to have the security="restricted" attribute set before the iframe is
     *    inserted into the dom tree
     *  - Believe it or not but in IE "security" in document.createElement("iframe") is false, even
     *    though it supports it
     *  - When an iframe has security="restricted", in IE eval() & execScript() don't work anymore
     *  - IE doesn't fire the onload event when the content is inlined in the src attribute, therefore we rely
     *    on the onreadystatechange event
     */
    _createIframe: function() {
      var that   = this,
          iframe = doc.createElement("iframe");
      iframe.className = "wysihtml5-sandbox";
      wysihtml5.dom.setAttributes({
        "security":           "restricted",
        "allowtransparency":  "true",
        "frameborder":        0,
        "width":              0,
        "height":             0,
        "marginwidth":        0,
        "marginheight":       0
      }).on(iframe);

      // Setting the src like this prevents ssl warnings in IE6
      if (wysihtml5.browser.throwsMixedContentWarningWhenIframeSrcIsEmpty()) {
        iframe.src = "javascript:''";
      }

      iframe.onload = function() {
        iframe.onreadystatechange = iframe.onload = null;
        that._onLoadIframe(iframe);
      };

      iframe.onreadystatechange = function() {
        if (/loaded|complete/.test(iframe.readyState)) {
          iframe.onreadystatechange = iframe.onload = null;
          that._onLoadIframe(iframe);
        }
      };

      return iframe;
    },

    /**
     * Callback for when the iframe has finished loading
     */
    _onLoadIframe: function(iframe) {
      // don't resume when the iframe got unloaded (eg. by removing it from the dom)
      if (!wysihtml5.dom.contains(doc.documentElement, iframe)) {
        return;
      }

      var that           = this,
          iframeWindow   = iframe.contentWindow,
          iframeDocument = iframe.contentWindow.document,
          charset        = doc.characterSet || doc.charset || "utf-8",
          sandboxHtml    = this._getHtml({
            charset:      charset,
            stylesheets:  this.config.stylesheets
          });

      // Create the basic dom tree including proper DOCTYPE and charset
      iframeDocument.open("text/html", "replace");
      iframeDocument.write(sandboxHtml);
      iframeDocument.close();

      this.getWindow = function() { return iframe.contentWindow; };
      this.getDocument = function() { return iframe.contentWindow.document; };

      // Catch js errors and pass them to the parent's onerror event
      // addEventListener("error") doesn't work properly in some browsers
      // TODO: apparently this doesn't work in IE9!
      iframeWindow.onerror = function(errorMessage, fileName, lineNumber) {
        throw new Error("wysihtml5.Sandbox: " + errorMessage, fileName, lineNumber);
      };

      if (!wysihtml5.browser.supportsSandboxedIframes()) {
        // Unset a bunch of sensitive variables
        // Please note: This isn't hack safe!
        // It more or less just takes care of basic attacks and prevents accidental theft of sensitive information
        // IE is secure though, which is the most important thing, since IE is the only browser, who
        // takes over scripts & styles into contentEditable elements when copied from external websites
        // or applications (Microsoft Word, ...)
        var i, length;
        for (i=0, length=windowProperties.length; i<length; i++) {
          this._unset(iframeWindow, windowProperties[i]);
        }
        for (i=0, length=windowProperties2.length; i<length; i++) {
          this._unset(iframeWindow, windowProperties2[i], wysihtml5.EMPTY_FUNCTION);
        }
        for (i=0, length=documentProperties.length; i<length; i++) {
          this._unset(iframeDocument, documentProperties[i]);
        }
        // This doesn't work in Safari 5
        // See http://stackoverflow.com/questions/992461/is-it-possible-to-override-document-cookie-in-webkit
        this._unset(iframeDocument, "cookie", "", true);
      }

      this.loaded = true;

      // Trigger the callback
      setTimeout(function() { that.callback(that); }, 0);
    },

    _getHtml: function(templateVars) {
      var stylesheets = templateVars.stylesheets,
          html        = "",
          i           = 0,
          length;
      stylesheets = typeof(stylesheets) === "string" ? [stylesheets] : stylesheets;
      if (stylesheets) {
        length = stylesheets.length;
        for (; i<length; i++) {
          html += '<link rel="stylesheet" href="' + stylesheets[i] + '">';
        }
      }
      templateVars.stylesheets = html;

      return wysihtml5.lang.string(
        '<!DOCTYPE html>'
        + '<meta charset="#{charset}">#{stylesheets}'
        + ''
      ).interpolate(templateVars);
    },

    /**
     * Method to unset/override existing variables
     * @example
     *    // Make cookie unreadable and unwritable
     *    this._unset(document, "cookie", "", true);
     */
    _unset: function(object, property, value, setter) {
      try { object[property] = value; } catch(e) {}

      try { object.__defineGetter__(property, function() { return value; }); } catch(e) {}
      if (setter) {
        try { object.__defineSetter__(property, function() {}); } catch(e) {}
      }

      if (!wysihtml5.browser.crashesWhenDefineProperty(property)) {
        try {
          var config = {
            get: function() { return value; }
          };
          if (setter) {
            config.set = function() {};
          }
          Object.defineProperty(object, property, config);
        } catch(e) {}
      }
    }
  });
})(wysihtml5);
<|endoftext|>


<commit_before>/**
 * @module Data
 * @submodule LocalStorage
 * @requires core
 *
 * This module defines the p5 methods for working with local storage
 */

'use strict';
var p5 = require('../core/main');
/**
 *
 * Stores a value in local storage under the key name. The key can
 * be the name of the variable but it does not have to be. To retrieve
 * stored items see loadItem.
 *
 * @method storeItem
 * @for p5
 * @param {String} key
 * @param {String|Number|Object|Boolean|p5.Color} value
 *
 * @example
 *

 * // Type to change the letter in the
 * // center of the canvas.
 * // If you reload the page, it will
 * // still display the last key you entered
 *
 * let myText;
 *
 * function setup() {
 *   createCanvas(100, 100);
 *   myText = loadItem('myText');
 *   if (myText === null) {
 *     myText = '';
 *   }
 * }
 *
 * function draw() {
 *   textSize(40);
 *   background(255);
 *   text(myText, width / 2, height / 2);
 * }
 *
 * function keyPressed() {
 *   myText = key;
 *   storeItem('myText', myText);
 * }
 *

 *
 * @alt
 * When you type the key name is displayed as black text on white background.
 * If you reload the page, the last letter typed is still displaying.
 *
 */
p5.prototype.storeItem = function(key, value) {
  if (value === 'undefined') {
    console.log('You cannot store undefined variables using storeItem()');
  }
  var type = typeof value;
  switch (type) {
    case 'number':
    case 'boolean':
      value = value.toString();
      break;
    case 'object':
      value = JSON.stringify(value);
      break;
    case 'string':
    default:
      break;
  }

  localStorage.setItem(key, value);
  var typeKey = key + 'Type';
  localStorage.setItem(typeKey, type);
};

/**
 *
 * Returns the value of an item that was stored in local storage
 * using storeItem()
 *
 * @method loadItem
 * @for p5
 * @param {String} key name that you wish to use to store in local storage
 * @return {Number|Object|String|Boolean|p5.Color} Value of stored item
 *
 * @example
 *

 * // Click the mouse to change
 * // the color of the background
 * // Once you have changed the color
 * // it will stay changed even when you
 * // reload the page.
 *
 * let myColor;
 *
 * function setup() {
 *   createCanvas(100, 100);
 *   myColor = loadItem('myColor');
 * }
 *
 * function draw() {
 *   if (myColor !== null) {
 *     background(myColor);
 *   }
 * }
 *
 * function mousePressed() {
 *   myColor = color(random(255), random(255), random(255));
 *   storeItem('myColor', myColor);
 * }
 *

 *
 * @alt
 * If you click, the canvas changes to a random color.
 * If you reload the page, the canvas is still the color it
 * was when the page was previously loaded.
 *
 */
p5.prototype.loadItem = function(key) {
  var value = localStorage.getItem(key);
  var type = localStorage.getItem(key + 'Type');
  if (type === undefined) {
    console.log(
      'Unable to determine type of item stored under ' +
        key +
        'in local storage. Did you save the item with something other than setItem()?'
    );
  } else if (value !== null) {
    switch (type) {
      case 'number':
        value = parseInt(value);
        break;
      case 'boolean':
        value = value === 'true';
        break;
      case 'object':
        value = JSON.parse(value);
        //If an object is meant to be a p5.Color
        if (value.maxes.hsb !== undefined) {
          value = this.color.apply(this, value.levels);
        }
        break;
      case 'string':
      default:
        break;
    }
  }
  return value;
};

/**
 *
 * Clears all local storage items set with storeItem()
 * for the current domain.
 *
 * @method clearStorage
 * @for p5
 *
 * @example
 *

 *
 * function setup() {
 *   let myNum = 10;
 *   let myBool = false;
 *   storeItem('myNum', myNum);
 *   storeItem('myBool', myBool);
 *   print(loadItem('myNum')); // logs 10 to the console
 *   print(loadItem('myBool')); // logs false to the console
 *   clearStorage();
 *   print(loadItem('myNum')); // logs null to the console
 *   print(loadItem('myBool')); // logs null to the console
 * }
 *

 */
p5.prototype.clearStorage = function() {
  localStorage.clear();
};

/**
 *
 * Removes an item that was stored with storeItem()
 *
 * @method removeItem
 * @param {String} key
 * @for p5
 *
 * @example
 *

 *
 * function setup() {
 *   let myVar = 10;
 *   storeItem('myVar', myVar);
 *   print(loadItem('myVar')); // logs 10 to the console
 *   removeItem('myVar');
 *   print(loadItem('myVar')); // logs null to the console
 * }
 *

 */
p5.prototype.removeItem = function(key) {
  if (typeof key !== 'string') {
    console.log(
      'The argument that you passed to removeItem() - ' +
        key +
        ' is not a string.'
    );
  }
  localStorage.removeItem(key);
  localStorage.removeItem(key + 'Type');
};
<commit_msg>always do typeof === 'undefined checks instead<commit_after>/**
 * @module Data
 * @submodule LocalStorage
 * @requires core
 *
 * This module defines the p5 methods for working with local storage
 */

'use strict';
var p5 = require('../core/main');
/**
 *
 * Stores a value in local storage under the key name. The key can
 * be the name of the variable but it does not have to be. To retrieve
 * stored items see loadItem.
 *
 * @method storeItem
 * @for p5
 * @param {String} key
 * @param {String|Number|Object|Boolean|p5.Color} value
 *
 * @example
 *

 * // Type to change the letter in the
 * // center of the canvas.
 * // If you reload the page, it will
 * // still display the last key you entered
 *
 * let myText;
 *
 * function setup() {
 *   createCanvas(100, 100);
 *   myText = loadItem('myText');
 *   if (myText === null) {
 *     myText = '';
 *   }
 * }
 *
 * function draw() {
 *   textSize(40);
 *   background(255);
 *   text(myText, width / 2, height / 2);
 * }
 *
 * function keyPressed() {
 *   myText = key;
 *   storeItem('myText', myText);
 * }
 *

 *
 * @alt
 * When you type the key name is displayed as black text on white background.
 * If you reload the page, the last letter typed is still displaying.
 *
 */
p5.prototype.storeItem = function(key, value) {
  if (typeof value === 'undefined') {
    console.log('You cannot store undefined variables using storeItem()');
  }
  var type = typeof value;
  switch (type) {
    case 'number':
    case 'boolean':
      value = value.toString();
      break;
    case 'object':
      value = JSON.stringify(value);
      break;
    case 'string':
    default:
      break;
  }

  localStorage.setItem(key, value);
  var typeKey = key + 'Type';
  localStorage.setItem(typeKey, type);
};

/**
 *
 * Returns the value of an item that was stored in local storage
 * using storeItem()
 *
 * @method loadItem
 * @for p5
 * @param {String} key name that you wish to use to store in local storage
 * @return {Number|Object|String|Boolean|p5.Color} Value of stored item
 *
 * @example
 *

 * // Click the mouse to change
 * // the color of the background
 * // Once you have changed the color
 * // it will stay changed even when you
 * // reload the page.
 *
 * let myColor;
 *
 * function setup() {
 *   createCanvas(100, 100);
 *   myColor = loadItem('myColor');
 * }
 *
 * function draw() {
 *   if (myColor !== null) {
 *     background(myColor);
 *   }
 * }
 *
 * function mousePressed() {
 *   myColor = color(random(255), random(255), random(255));
 *   storeItem('myColor', myColor);
 * }
 *

 *
 * @alt
 * If you click, the canvas changes to a random color.
 * If you reload the page, the canvas is still the color it
 * was when the page was previously loaded.
 *
 */
p5.prototype.loadItem = function(key) {
  var value = localStorage.getItem(key);
  var type = localStorage.getItem(key + 'Type');
  if (typeof type === 'undefined') {
    console.log(
      'Unable to determine type of item stored under ' +
        key +
        'in local storage. Did you save the item with something other than setItem()?'
    );
  } else if (value !== null) {
    switch (type) {
      case 'number':
        value = parseInt(value);
        break;
      case 'boolean':
        value = value === 'true';
        break;
      case 'object':
        value = JSON.parse(value);
        //If an object is meant to be a p5.Color
        if (typeof value.maxes.hsb !== 'undefined') {
          value = this.color.apply(this, value.levels);
        }
        break;
      case 'string':
      default:
        break;
    }
  }
  return value;
};

/**
 *
 * Clears all local storage items set with storeItem()
 * for the current domain.
 *
 * @method clearStorage
 * @for p5
 *
 * @example
 *

 *
 * function setup() {
 *   let myNum = 10;
 *   let myBool = false;
 *   storeItem('myNum', myNum);
 *   storeItem('myBool', myBool);
 *   print(loadItem('myNum')); // logs 10 to the console
 *   print(loadItem('myBool')); // logs false to the console
 *   clearStorage();
 *   print(loadItem('myNum')); // logs null to the console
 *   print(loadItem('myBool')); // logs null to the console
 * }
 *

 */
p5.prototype.clearStorage = function() {
  localStorage.clear();
};

/**
 *
 * Removes an item that was stored with storeItem()
 *
 * @method removeItem
 * @param {String} key
 * @for p5
 *
 * @example
 *

 *
 * function setup() {
 *   let myVar = 10;
 *   storeItem('myVar', myVar);
 *   print(loadItem('myVar')); // logs 10 to the console
 *   removeItem('myVar');
 *   print(loadItem('myVar')); // logs null to the console
 * }
 *

 */
p5.prototype.removeItem = function(key) {
  if (typeof key !== 'string') {
    console.log(
      'The argument that you passed to removeItem() - ' +
        key +
        ' is not a string.'
    );
  }
  localStorage.removeItem(key);
  localStorage.removeItem(key + 'Type');
};
<|endoftext|>


<commit_before>/**
 * @file Check entity definition
 * @since 0.1.6
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GpfClassDefinition*/ // Class definition
/*global _GpfEntityDefinition*/ // Entity definition
/*global _gpfDefineGenerate$Keys*/ // Generate an array of names prefixed with $ from a comma separated list
/*global _gpfErrorDeclare*/ // Declare new gpf.Error names
/*global _gpfExtend*/ // gpf.extend
/*#endif*/

_gpfErrorDeclare("define/class/check", {
    /**
     * ### Summary
     *
     * The class name is invalid
     *
     * ### Description
     *
     * Only a valid JavaScript identifier (starting with an uppercase letter, $ or _) is allowed
     * @since 0.1.6
     */
    invalidClassName: "Invalid class name",

    /**
     * ### Summary
     *
     * The class definition contains an property
     *
     * ### Description
     *
     * Some keywords are reserved
     * @since 0.1.6
     */
    invalidClassProperty: "Invalid class property"

});

_gpfExtend(_GpfClassDefinition.prototype, /** @lends _gpfClassDefinition.prototype */ {

    /**
     * @inheritdoc
     * @since 0.1.6
     */
    _allowed$Properties: _GpfEntityDefinition.prototype._allowed$Properties
        .concat(_gpfDefineGenerate$Keys("class,extend")),

    /**
     * Check that the member name is a valid one
     *
     * @param {String} name Member name
     * @throws {gpf.Error.InvalidClassProperty}
     * @since 0.1.6
     */
    _checkMemberName: function (name) {
        if (!new RegExp("^[a-z_$][a-zA-Z0-9]*$").exec(name)) {
            gpf.Error.invalidClassProperty();
        }
    },

    /**
     * List of reserved member names
     *
     * @type {String[]}
     * @readonly
     * @constant
     * @since 0.1.6
     */
    _reservedNames: "super,class,public,private,protected,static,mixin".split(","),

    /**
     * Check that the member name is not a reserved one
     *
     * @param {String} name Member name
     * @throws {gpf.Error.InvalidClassProperty}
     * @since 0.1.6
     */
    _checkReservedMemberName: function (name) {
        if (-1 !== this._reservedNames.indexOf(name)) {
            gpf.Error.invalidClassProperty();
        }
    },

    /**
     * @inheritdoc
     * @throws {gpf.Error.InvalidClassProperty}
     * @since 0.1.6
     */
    _checkProperty: function (name) {
        _GpfEntityDefinition.prototype._checkProperty.call(this, name);
        this._checkMemberName(name);
        this._checkReservedMemberName(name);
    },

    /**
     * @inheritdoc
     * @throws {gpf.Error.InvalidClassName}
     * @since 0.1.6
     */
    _checkName: function () {
        _GpfEntityDefinition.prototype._checkName.call(this);
        if (!new RegExp("^[A-Z_$][a-zA-Z0-9]*$").exec(this._name)) {
            gpf.Error.invalidClassName();
        }
    }

});
<commit_msg>Reads & check $extend<commit_after>/**
 * @file Check entity definition
 * @since 0.1.6
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GpfClassDefinition*/ // Class definition
/*global _GpfEntityDefinition*/ // Entity definition
/*global _gpfContext*/ // Resolve contextual string
/*global _gpfDefineGenerate$Keys*/ // Generate an array of names prefixed with $ from a comma separated list
/*global _gpfErrorDeclare*/ // Declare new gpf.Error names
/*global _gpfExtend*/ // gpf.extend
/*#endif*/

_gpfErrorDeclare("define/class/check", {
    /**
     * ### Summary
     *
     * The class name is invalid
     *
     * ### Description
     *
     * Only a valid JavaScript identifier (starting with an uppercase letter, $ or _) is allowed
     * @since 0.1.6
     */
    invalidClassName: "Invalid class name",

    /**
     * ### Summary
     *
     * The class definition contains an invalid property
     *
     * ### Description
     *
     * Some keywords are reserved
     * @since 0.1.6
     */
    invalidClassProperty: "Invalid class property",

    /**
     * ### Summary
     *
     * The class definition contains an invalid $extend
     *
     * ### Description
     *
     * $extend can be either a class or a string that must resolve to a class using {@see gpf.context}
     * @since 0.1.6
     */
    invalidClassExtend: "Invalid class extend"

});

/**
 * If extend is a string, apply _gpfContext on it
 *
 * @param {*} extend Extend value
 * @return {*} The initial value or the context one
 * @since 0.1.6
 */
function _gpfDefineClassDecontextifyExtend (extend) {
    if ("string" === typeof extend) {
        return _gpfContext(extend.split("."));
    }
    return extend;
}

_gpfExtend(_GpfClassDefinition.prototype, /** @lends _gpfClassDefinition.prototype */ {

    /**
     * @inheritdoc
     * @since 0.1.6
     */
    _allowed$Properties: _GpfEntityDefinition.prototype._allowed$Properties
        .concat(_gpfDefineGenerate$Keys("class,extend")),

    /**
     * Check that the member name is a valid one
     *
     * @param {String} name Member name
     * @throws {gpf.Error.InvalidClassProperty}
     * @since 0.1.6
     */
    _checkMemberName: function (name) {
        if (!new RegExp("^[a-z_$][a-zA-Z0-9]*$").exec(name)) {
            gpf.Error.invalidClassProperty();
        }
    },

    /**
     * List of reserved member names
     *
     * @type {String[]}
     * @readonly
     * @constant
     * @since 0.1.6
     */
    _reservedNames: "super,class,public,private,protected,static,mixin".split(","),

    /**
     * Check that the member name is not a reserved one
     *
     * @param {String} name Member name
     * @throws {gpf.Error.InvalidClassProperty}
     * @since 0.1.6
     */
    _checkReservedMemberName: function (name) {
        if (-1 !== this._reservedNames.indexOf(name)) {
            gpf.Error.invalidClassProperty();
        }
    },

    /**
     * @inheritdoc
     * @throws {gpf.Error.InvalidClassProperty}
     * @since 0.1.6
     */
    _checkProperty: function (name) {
        _GpfEntityDefinition.prototype._checkProperty.call(this, name);
        this._checkMemberName(name);
        this._checkReservedMemberName(name);
    },

    /**
     * @inheritdoc
     * @throws {gpf.Error.InvalidClassName}
     * @since 0.1.6
     */
    _checkName: function () {
        _GpfEntityDefinition.prototype._checkName.call(this);
        if (!new RegExp("^[A-Z_$][a-zA-Z0-9]*$").exec(this._name)) {
            gpf.Error.invalidClassName();
        }
    },

    /**
     * Base class
     *
     * @type {Function}
     * @since 0.1.6
     */
    _extend: Object,

    /**
     * Read extend property
     * @since 0.1.6
     */
    _readExtend: function () {
        var extend = _gpfDefineClassDecontextifyExtend(this._initialDefinition.$extend);
        if (extend) {
            this._extend = extend;
        }
    },

    /**
     * Check extend property
     *
     * @throws {gpf.Error.InvalidClassExtend}
     * @since 0.1.6
     */
    _checkExtend: function () {
        if ("function" !== typeof this._extend) {
            gpf.Error.invalidClassExtend();
        }
    },

    /**
     * @inheritdoc
     * @since 0.1.6
     */
    check: function () {
        _GpfEntityDefinition.prototype.check.call(this);
        this._readExtend();
        this._checkExtend();
    }

});
<|endoftext|>


<commit_before>/**
 * @file Class definition
 * @since 0.1.6
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GpfEntityDefinition*/ // Entity definition
/*global _gpfDefineTypedBuilders*/ // Dictionary mapping type (class...) to the corresponding typed Entity constructor
/*exported _GpfClassDefinition*/ // Class definition
/*#endif*/

/**
 * Class definition
 *
 * @param {Object} definition Entity definition
 * @extends _GpfEntityDefinition
 * @constructor
 * @since 0.1.6
 */
function _GpfClassDefinition (definition) {
    /*jshint validthis:true*/ // constructor
    /*eslint-disable no-invalid-this*/
    _GpfEntityDefinition.call(this, definition);
    /*eslint-enable no-invalid-this*/
}

_GpfClassDefinition.prototype = Object.create(_GpfEntityDefinition.prototype);

Object.assign(_GpfClassDefinition.prototype, {

    constructor: _GpfClassDefinition,

    /**
     * @inheritdoc
     * @since 0.1.6
     */
    _type: "class",

    /**
     * Class is abstract
     * @since 0.2.7
     */
    _abstract: false

});

_gpfDefineTypedBuilders["class"] = _GpfClassDefinition;

/*#ifndef(UMD)*/

gpf.internals._GpfClassDefinition = _GpfClassDefinition;

/*#endif*/
<commit_msg>Isolates $abstract (#285)<commit_after>/**
 * @file Class definition
 * @since 0.1.6
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GpfEntityDefinition*/ // Entity definition
/*global _gpfDefineTypedBuilders*/ // Dictionary mapping type (class...) to the corresponding typed Entity constructor
/*exported _GpfClassDefinition*/ // Class definition
/*#endif*/

/**
 * Class definition
 *
 * @param {Object} definition Entity definition
 * @extends _GpfEntityDefinition
 * @constructor
 * @since 0.1.6
 */
function _GpfClassDefinition (definition) {
    /*jshint validthis:true*/ // constructor
    /*eslint-disable no-invalid-this*/
    _GpfEntityDefinition.call(this, definition);
    /*eslint-enable no-invalid-this*/
}

_GpfClassDefinition.prototype = Object.create(_GpfEntityDefinition.prototype);

Object.assign(_GpfClassDefinition.prototype, {

    constructor: _GpfClassDefinition,

    /**
     * @inheritdoc
     * @since 0.1.6
     */
    _type: "class"

});

_gpfDefineTypedBuilders["class"] = _GpfClassDefinition;

/*#ifndef(UMD)*/

gpf.internals._GpfClassDefinition = _GpfClassDefinition;

/*#endif*/
<|endoftext|>