<commit_before>/* vim:ts=4:sts=4:sw=4:
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Ajax.org Code Editor (ACE).
 *
 * The Initial Developer of the Original Code is
 * Ajax.org B.V.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *      Fabian Jakobs <fabian AT ajax DOT org>
 *      Mihai Sucan <mihai DOT sucan AT gmail DOT com>
 *      Chris Spencer <chris.ag.spencer AT googlemail DOT com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

define('ace/mode/markdown', function(require, exports, module) {

var oop = require("pilot/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var MarkdownHighlightRules = require("ace/mode/markdown_highlight_rules").MarkdownHighlightRules;

var Mode = function() {
    this.$tokenizer = new Tokenizer(new MarkdownHighlightRules().getRules());
};
oop.inherits(Mode, TextMode);

(function() {
    this.getNextLineIndent = function(state, line, tab) {
        if (state == "listblock") {
            var match = /^((?:.+)?)([-+*][ ]+)/.exec(line);
            if (match) {
                return new Array(match[1].length + 1).join(" ") + match[2];
            } else {
                return "";
            }
        } else {
            return this.$getIndent(line);
        }
    };
}).call(Mode.prototype);

exports.Mode = Mode;
});

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Ajax.org Code Editor (ACE).
 *
 * The Initial Developer of the Original Code is
 * Ajax.org B.V.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *      Fabian Jakobs <fabian AT ajax DOT org>
 *      Chris Spencer <chris.ag.spencer AT googlemail DOT com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

define('ace/mode/markdown_highlight_rules', function(require, exports, module) {

var oop = require("pilot/oop");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;

var MarkdownHighlightRules = function() {

    // regexp must not have capturing parentheses
    // regexps are ordered -> the first match is used

    this.$rules = {
        "start" : [ {
            token : "empty_line",
            regex : '^$'
        }, { // code span `
            token : "support.function",
            regex : "(`+)([^\\r]*?[^`])(\\1)"
        }, { // code block
            token : "support.function",
            regex : "^[ ]{4}.+"
        }, { // block quote
            token : "string",
            regex : "^>[ ].+$",
            next  : "blockquote"
        }, { // header
            token : ["constant", "keyword"],
            regex : "^(#{1,6})(.+)$"
        }, { // reference
            token : ["text", "constant", "text", "url", "string", "text"],
            regex : "^([ ]{0,3}\\[)([^\\]]+)(\\]:\\s*)([^ ]+)(\\s*(?:[\"][^\"]+[\"])?\\s*)$"
        }, { // link by reference
            token : ["text", "string", "text", "constant", "text"],
            regex : "(\\[)((?:[[^\\]]*\\]|[^\\[\\]])*)(\\][ ]?(?:\\n[ ]*)?\\[)(.*?)(\\])"
        }, { // link by url
            token : ["text", "string", "text", "url", "string", "text"],
            regex : "(\\[)"+
                    "(\\[[^\\]]*\\]|[^\\[\\]]*)"+
                    "(\\]\\([ \\t]*)"+
                    "(<?(?:(?:[^\\(]*?\\([^\\)]*?\\)\\S*?)|(?:.*?))>?)"+
                    "((?:[ \t]*\"(?:.*?)\"[ \\t]*)?)"+
                    "(\\))"
        }, { // HR *
            token : "constant",
            regex : "^[ ]{0,2}(?:[ ]?\\*[ ]?){3,}[ \\t]*$"
        }, { // HR -
            token : "constant",
            regex : "^[ ]{0,2}(?:[ ]?\\-[ ]?){3,}[ \\t]*$"
        }, { // HR _
            token : "constant",
            regex : "^[ ]{0,2}(?:[ ]?\\_[ ]?){3,}[ \\t]*$"
        }, { // list
            token : "support.function",
            regex : "^(?:[*+-]\\s.+)",
            next  : "listblock"
        }, { // math span
            token : "keyword",
            regex : "%%.+?%%"
        }, { // math div
            token : "keyword",
            regex : "[$]{2}.+?[$]{2}"
        }, { // strong ** __
            token : "string",
            regex : "([*]{2}|[_]{2}(?=\\S))([^\\r]*?\\S[*_]*)(\\1)"
        }, { // emphasis * _
            token : "string",
            regex : "([*]|[_](?=\\S))([^\\r]*?\\S[*_]*)(\\1)"
        }, { //
            token : ["text", "url", "text"],
            regex : "(<)("+
                      "(?:https?|ftp|dict):[^'\">\\s]+"+
                      "|"+
                      "(?:mailto:)?[-.\\w]+\\@[-a-z0-9]+(?:\\.[-a-z0-9]+)*\\.[a-z]+"+
                    ")(>)"
        }, {
            token : "text",
            regex : "[^\\*_%$`\\[#<>]+"
        } ],

        "listblock" : [ { // Lists only escape on completely blank lines.
            token : "empty_line",
            regex : "^$",
            next  : "start",
        }, {
            token : "support.function",
            regex : ".+"
        } ],

        "blockquote" : [ { // BLockquotes only escape on blank lines.
            token : "empty_line",
            regex : "^\\s*$",
            next  : "start",
        }, {
            token : "string",
            regex : ".+"
        } ]
    };
};
oop.inherits(MarkdownHighlightRules, TextHighlightRules);

exports.MarkdownHighlightRules = MarkdownHighlightRules;
});<commit_msg>Github block highlighting, and experimental mixed mode javascript highlighting<commit_after>/* vim:ts=4:sts=4:sw=4:
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Ajax.org Code Editor (ACE).
 *
 * The Initial Developer of the Original Code is
 * Ajax.org B.V.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *      Fabian Jakobs <fabian AT ajax DOT org>
 *      Mihai Sucan <mihai DOT sucan AT gmail DOT com>
 *      Chris Spencer <chris.ag.spencer AT googlemail DOT com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

define('ace/mode/markdown', function(require, exports, module) {

var oop = require("pilot/oop");
var TextMode = require("ace/mode/text").Mode;
var JavaScriptMode = require("ace/mode/javascript").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var MarkdownHighlightRules = require("ace/mode/markdown_highlight_rules").MarkdownHighlightRules;

var Mode = function() {
    this.$tokenizer = new Tokenizer(new MarkdownHighlightRules().getRules());

    this.$js = new JavaScriptMode();
};
oop.inherits(Mode, TextMode);

(function() {

    this.toggleCommentLines = function(state, doc, startRow, endRow) {
        this.$delegate("toggleCommentLines", arguments, function() {
            return 0;
        });
    };

    this.getNextLineIndent = function(state, line, tab) {
        var self = this;

        return this.$delegate("getNextLineIndent", arguments, function(state, line, tab) {
            if (state == "listblock") {
                var match = /^((?:.+)?)([-+*][ ]+)/.exec(line);
                if (match) {
                    return new Array(match[1].length + 1).join(" ") + match[2];
                } else {
                    return "";
                }
            } else {
                return self.$getIndent(line);
            }
        });
    };

    this.checkOutdent = function(state, line, input) {
        return this.$delegate("checkOutdent", arguments, function() {
            return false;
        });
    };

    this.autoOutdent = function(state, doc, row) {
        this.$delegate("autoOutdent", arguments);
    };

    this.$delegate = function(method, args, defaultHandler) {
        var state = args[0];
        var split = state.split("js-");

        console.log(state, method);

        if (!split[0] && split[1]) {
            args[0] = split[1];
            return this.$js[method].apply(this.$js, args);
        }

        return defaultHandler ? defaultHandler.apply(this, args) : undefined;
    };

}).call(Mode.prototype);

exports.Mode = Mode;
});

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Ajax.org Code Editor (ACE).
 *
 * The Initial Developer of the Original Code is
 * Ajax.org B.V.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *      Fabian Jakobs <fabian AT ajax DOT org>
 *      Chris Spencer <chris.ag.spencer AT googlemail DOT com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

define('ace/mode/markdown_highlight_rules', function(require, exports, module) {

var oop = require("pilot/oop");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var JavaScriptHighlightRules = require("ace/mode/javascript_highlight_rules").JavaScriptHighlightRules;

var MarkdownHighlightRules = function() {

    // regexp must not have capturing parentheses
    // regexps are ordered -> the first match is used

    this.$rules = {
        "start" : [ {
            token : "empty_line",
            regex : '^$'
        }, { // code span `
            token : "support.function",
            regex : "(`+)([^\\r]*?[^`])(\\1)"
        }, { // code block
            token : "support.function",
            regex : "^[ ]{4}.+"
        }, { // Github style javascript block
            token : "invalid.illegal.deprecated", // Pick something really obvious
            regex : "^```javascript\\s*$",
            next  : "js-start"
        }, { // Github style block
            token : "support.function",
            regex : "^```[a-zA-Z]+\\s*$",
            next  : "githubblock"
        }, { // block quote
            token : "string",
            regex : "^>[ ].+$",
            next  : "blockquote"
        }, { // header
            token : ["constant", "keyword"],
            regex : "^(#{1,6})(.+)$"
        }, { // reference
            token : ["text", "constant", "text", "url", "string", "text"],
            regex : "^([ ]{0,3}\\[)([^\\]]+)(\\]:\\s*)([^ ]+)(\\s*(?:[\"][^\"]+[\"])?\\s*)$"
        }, { // link by reference
            token : ["text", "string", "text", "constant", "text"],
            regex : "(\\[)((?:[[^\\]]*\\]|[^\\[\\]])*)(\\][ ]?(?:\\n[ ]*)?\\[)(.*?)(\\])"
        }, { // link by url
            token : ["text", "string", "text", "url", "string", "text"],
            regex : "(\\[)"+
                    "(\\[[^\\]]*\\]|[^\\[\\]]*)"+
                    "(\\]\\([ \\t]*)"+
                    "(<?(?:(?:[^\\(]*?\\([^\\)]*?\\)\\S*?)|(?:.*?))>?)"+
                    "((?:[ \t]*\"(?:.*?)\"[ \\t]*)?)"+
                    "(\\))"
        }, { // HR *
            token : "constant",
            regex : "^[ ]{0,2}(?:[ ]?\\*[ ]?){3,}[ \\t]*$"
        }, { // HR -
            token : "constant",
            regex : "^[ ]{0,2}(?:[ ]?\\-[ ]?){3,}[ \\t]*$"
        }, { // HR _
            token : "constant",
            regex : "^[ ]{0,2}(?:[ ]?\\_[ ]?){3,}[ \\t]*$"
        }, { // list
            token : "support.function",
            regex : "^(?:[*+-]\\s.+)",
            next  : "listblock"
        }, { // math span
            token : "keyword",
            regex : "%%.+?%%"
        }, { // math div
            token : "keyword",
            regex : "[$]{2}.+?[$]{2}"
        }, { // strong ** __
            token : "string",
            regex : "([*]{2}|[_]{2}(?=\\S))([^\\r]*?\\S[*_]*)(\\1)"
        }, { // emphasis * _
            token : "string",
            regex : "([*]|[_](?=\\S))([^\\r]*?\\S[*_]*)(\\1)"
        }, { //
            token : ["text", "url", "text"],
            regex : "(<)("+
                      "(?:https?|ftp|dict):[^'\">\\s]+"+
                      "|"+
                      "(?:mailto:)?[-.\\w]+\\@[-a-z0-9]+(?:\\.[-a-z0-9]+)*\\.[a-z]+"+
                    ")(>)"
        }, {
            token : "text",
            regex : "[^\\*_%$`\\[#<>]+"
        } ],

        "listblock" : [ { // Lists only escape on completely blank lines.
            token : "empty_line",
            regex : "^$",
            next  : "start",
        }, {
            token : "support.function",
            regex : ".+"
        } ],

        "blockquote" : [ { // BLockquotes only escape on blank lines.
            token : "empty_line",
            regex : "^\\s*$",
            next  : "start",
        }, {
            token : "string",
            regex : ".+"
        } ],

        "githubblock" : [ {
            token : "support.function",
            regex : "^```",
            next  : "start"
        }, {
            token : "support.function",
            regex : ".+"
        } ]
    };

    var jsRules = new JavaScriptHighlightRules().getRules();
    this.addRules(jsRules, "js-");

    this.$rules["js-start"].unshift({
       token : "invalid.illegal.deprecated", // Pick something really obvious
       regex : "^```",
       next  : "start"
    });
};
oop.inherits(MarkdownHighlightRules, TextHighlightRules);

exports.MarkdownHighlightRules = MarkdownHighlightRules;
});<|endoftext|>


<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";
let nextIdent = 0;

class CommonsChunkPlugin {
	constructor(options) {
		if(arguments.length > 1) {
			throw new Error(`Deprecation notice: CommonsChunkPlugin now only takes a single argument. Either an options
object *or* the name of the chunk.
Example: if your old code looked like this:
	new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js')
You would change it to:
	new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js' })
The available options are:
	name: string
	names: string[]
	filename: string
	minChunks: number
	chunks: string[]
	children: boolean
	async: boolean
	minSize: number`);
		}

		const normalizedOptions = this.normalizeOptions(options);

		this.chunkNames = normalizedOptions.chunkNames;
		this.filenameTemplate = normalizedOptions.filenameTemplate;
		this.minChunks = normalizedOptions.minChunks;
		this.selectedChunks = normalizedOptions.selectedChunks;
		this.children = normalizedOptions.children;
		this.deepChildren = normalizedOptions.deepChildren;
		this.async = normalizedOptions.async;
		this.minSize = normalizedOptions.minSize;
		this.ident = __filename + (nextIdent++);
	}

	normalizeOptions(options) {
		if(Array.isArray(options)) {
			return {
				chunkNames: options,
			};
		}

		if(typeof options === "string") {
			return {
				chunkNames: [options],
			};
		}

		// options.children and options.chunk may not be used together
		if(options.children && options.chunks) {
			throw new Error("You can't and it does not make any sense to use \"children\" and \"chunk\" options together.");
		}

		/**
		 * options.async and options.filename are also not possible together
		 * as filename specifies how the chunk is called but "async" implies
		 * that webpack will take care of loading this file.
		 */
		if(options.async && options.filename) {
			throw new Error(`You can not specify a filename if you use the "async" option.
You can however specify the name of the async chunk by passing the desired string as the "async" option.`);
		}

		/**
		 * Make sure this is either an array or undefined.
		 * "name" can be a string and
		 * "names" a string or an array
		 */
		const chunkNames = options.name || options.names ? [].concat(options.name || options.names) : undefined;
		return {
			chunkNames: chunkNames,
			filenameTemplate: options.filename,
			minChunks: options.minChunks,
			selectedChunks: options.chunks,
			children: options.children,
			deepChildren: options.deepChildren,
			async: options.async,
			minSize: options.minSize
		};
	}

	apply(compiler) {
		compiler.plugin("this-compilation", (compilation) => {
			compilation.plugin(["optimize-chunks", "optimize-extracted-chunks"], (chunks) => {
				// only optimize once
				if(compilation[this.ident]) return;
				compilation[this.ident] = true;

				/**
				 * Creates a list of "common"" chunks based on the options.
				 * The list is made up of preexisting or newly created chunks.
				 * - If chunk has the name as specified in the chunkNames it is put in the list
				 * - If no chunk with the name as given in chunkNames exists a new chunk is created and added to the list
				 *
				 * These chunks are the "targets" for extracted modules.
				 */
				const targetChunks = this.getTargetChunks(chunks, compilation, this.chunkNames, this.children, this.async);

				// iterate over all our new chunks
				targetChunks.forEach((targetChunk, idx) => {

					/**
					 * These chunks are subject to get "common" modules extracted and moved to the common chunk
					 */
					const affectedChunks = this.getAffectedChunks(compilation, chunks, targetChunk, targetChunks, idx, this.selectedChunks, this.async, this.children, this.deepChildren);

					// bail if no chunk is affected
					if(!affectedChunks) {
						return;
					}

					// If we are async create an async chunk now
					// override the "commonChunk" with the newly created async one and use it as commonChunk from now on
					let asyncChunk;
					if(this.async) {
						// If async chunk is one of the affected chunks, just use it
						asyncChunk = affectedChunks.filter(c => c.name === this.async)[0];
						// Elsewise create a new one
						if(!asyncChunk) {
							asyncChunk = this.createAsyncChunk(
								compilation,
								targetChunks.length <= 1 || typeof this.async !== "string" ? this.async :
								targetChunk.name ? `${this.async}-${targetChunk.name}` :
								true,
								targetChunk
							);
						}
						targetChunk = asyncChunk;
					}

					/**
					 * Check which modules are "common" and could be extracted to a "common" chunk
					 */
					const extractableModules = this.getExtractableModules(this.minChunks, affectedChunks, targetChunk);

					// If the minSize option is set check if the size extracted from the chunk is reached
					// else bail out here.
					// As all modules/commons are interlinked with each other, common modules would be extracted
					// if we reach this mark at a later common chunk. (quirky I guess).
					if(this.minSize) {
						const modulesSize = this.calculateModulesSize(extractableModules);
						// if too small, bail
						if(modulesSize < this.minSize)
							return;
					}

					// Remove modules that are moved to commons chunk from their original chunks
					// return all chunks that are affected by having modules removed - we need them later (apparently)
					const chunksWithExtractedModules = this.extractModulesAndReturnAffectedChunks(extractableModules, affectedChunks);

					// connect all extracted modules with the common chunk
					this.addExtractedModulesToTargetChunk(targetChunk, extractableModules);

					// set filenameTemplate for chunk
					if(this.filenameTemplate)
						targetChunk.filenameTemplate = this.filenameTemplate;

					// if we are async connect the blocks of the "reallyUsedChunk" - the ones that had modules removed -
					// with the commonChunk and get the origins for the asyncChunk (remember "asyncChunk === commonChunk" at this moment).
					// bail out
					if(this.async) {
						this.moveExtractedChunkBlocksToTargetChunk(chunksWithExtractedModules, targetChunk);
						asyncChunk.origins = this.extractOriginsOfChunksWithExtractedModules(chunksWithExtractedModules);
						return;
					}

					// we are not in "async" mode
					// connect used chunks with commonChunk - shouldnt this be reallyUsedChunks here?
					this.makeTargetChunkParentOfAffectedChunks(affectedChunks, targetChunk);
				});
				return true;
			});
		});
	}

	getTargetChunks(allChunks, compilation, chunkNames, children, asyncOption) {
		const asyncOrNoSelectedChunk = children || asyncOption;

		// we have specified chunk names
		if(chunkNames) {
			// map chunks by chunkName for quick access
			const allChunksNameMap = allChunks.reduce((map, chunk) => {
				if(chunk.name) {
					map.set(chunk.name, chunk);
				}
				return map;
			}, new Map());

			// Ensure we have a chunk per specified chunk name.
			// Reuse existing chunks if possible
			return chunkNames.map(chunkName => {
				if(allChunksNameMap.has(chunkName)) {
					return allChunksNameMap.get(chunkName);
				}
				// add the filtered chunks to the compilation
				return compilation.addChunk(chunkName);
			});
		}

		// we dont have named chunks specified, so we just take all of them
		if(asyncOrNoSelectedChunk) {
			return allChunks;
		}

		/**
		 * No chunk name(s) was specified nor is this an async/children commons chunk
		 */
		throw new Error(`You did not specify any valid target chunk settings.
Take a look at the "name"/"names" or async/children option.`);
	}

	getAffectedUnnamedChunks(affectedChunks, targetChunk, rootChunk, asyncOption, deepChildrenOption) {
		for(const chunk of targetChunk.chunksIterable) {
			if(chunk.isInitial()) {
				continue;
			}
			// If all the parents of a chunk are either
			// a) the target chunk we started with
			// b) themselves affected chunks
			// we can assume that this chunk is an affected chunk too, as there is no way a chunk that
			// isn't only depending on the target chunk is a parent of the chunk tested
			if(asyncOption || chunk.getParents().every((parentChunk) => parentChunk === rootChunk || affectedChunks.has(parentChunk))) {
				// This check not only dedupes the affectedChunks but also guarantees we avoid endless loops
				if(!affectedChunks.has(chunk)) {
					// We mutate the affected chunks before going deeper, so the deeper levels and other branches
					// have the information of this chunk being affected for their assertion if a chunk should
					// not be affected
					affectedChunks.add(chunk);

					// We recurse down to all the children of the chunk, applying the same assumption.
					// This guarantees that if a chunk should be an affected chunk,
					// at the latest the last connection to the same chunk meets the
					// condition to add it to the affected chunks.
					if(deepChildrenOption === true) {
						this.getAffectedUnnamedChunks(affectedChunks, chunk, rootChunk, asyncOption, deepChildrenOption);
					}
				}
			}
		}
	}

	getAffectedChunks(compilation, allChunks, targetChunk, targetChunks, currentIndex, selectedChunks, asyncOption, childrenOption, deepChildrenOption) {
		const asyncOrNoSelectedChunk = childrenOption || asyncOption;

		if(Array.isArray(selectedChunks)) {
			return allChunks.filter(chunk => {
				const notCommmonChunk = chunk !== targetChunk;
				const isSelectedChunk = selectedChunks.indexOf(chunk.name) > -1;
				return notCommmonChunk && isSelectedChunk;
			});
		}

		if(asyncOrNoSelectedChunk) {
			let affectedChunks = new Set();
			this.getAffectedUnnamedChunks(affectedChunks, targetChunk, targetChunk, asyncOption, deepChildrenOption);
			return Array.from(affectedChunks);
		}

		/**
		 * past this point only entry chunks are allowed to become commonChunks
		 */
		if(targetChunk.getNumberOfParents() > 0) {
			compilation.errors.push(new Error("CommonsChunkPlugin: While running in normal mode it's not allowed to use a non-entry chunk (" + targetChunk.name + ")"));
			return;
		}

		/**
		 * If we find a "targetchunk" that is also a normal chunk (meaning it is probably specified as an entry)
		 * and the current target chunk comes after that and the found chunk has a runtime*
		 * make that chunk be an 'affected' chunk of the current target chunk.
		 *
		 * To understand what that means take a look at the "examples/chunkhash", this basically will
		 * result in the runtime to be extracted to the current target chunk.
		 *
		 * *runtime: the "runtime" is the "webpack"-block you may have seen in the bundles that resolves modules etc.
		 */
		return allChunks.filter((chunk) => {
			const found = targetChunks.indexOf(chunk);
			if(found >= currentIndex) return false;
			return chunk.isInitial();
		});
	}

	createAsyncChunk(compilation, asyncOption, targetChunk) {
		const asyncChunk = compilation.addChunk(typeof asyncOption === "string" ? asyncOption : undefined);
		asyncChunk.chunkReason = "async commons chunk";
		asyncChunk.extraAsync = true;
		asyncChunk.addParent(targetChunk);
		targetChunk.addChunk(asyncChunk);
		return asyncChunk;
	}

	// If minChunks is a function use that
	// otherwhise check if a module is used at least minChunks or 2 or usedChunks.length time
	getModuleFilter(minChunks, targetChunk, usedChunksLength) {
		if(typeof minChunks === "function") {
			return minChunks;
		}
		const minCount = (minChunks || Math.max(2, usedChunksLength));
		const isUsedAtLeastMinTimes = (module, count) => count >= minCount;
		return isUsedAtLeastMinTimes;
	}

	getExtractableModules(minChunks, usedChunks, targetChunk) {
		if(minChunks === Infinity) {
			return [];
		}

		// count how many chunks contain a module
		const commonModulesToCountMap = usedChunks.reduce((map, chunk) => {
			for(const module of chunk.modulesIterable) {
				const count = map.has(module) ? map.get(module) : 0;
				map.set(module, count + 1);
			}
			return map;
		}, new Map());

		// filter by minChunks
		const moduleFilterCount = this.getModuleFilter(minChunks, targetChunk, usedChunks.length);
		// filter by condition
		const moduleFilterCondition = (module, chunk) => {
			if(!module.chunkCondition) {
				return true;
			}
			return module.chunkCondition(chunk);
		};

		return Array.from(commonModulesToCountMap).filter(entry => {
			const module = entry[0];
			const count = entry[1];
			// if the module passes both filters, keep it.
			return moduleFilterCount(module, count) && moduleFilterCondition(module, targetChunk);
		}).map(entry => entry[0]);
	}

	calculateModulesSize(modules) {
		return modules.reduce((totalSize, module) => totalSize + module.size(), 0);
	}

	extractModulesAndReturnAffectedChunks(reallyUsedModules, usedChunks) {
		return reallyUsedModules.reduce((affectedChunksSet, module) => {
			for(const chunk of usedChunks) {
				// removeChunk returns true if the chunk was contained and succesfully removed
				// false if the module did not have a connection to the chunk in question
				if(module.removeChunk(chunk)) {
					affectedChunksSet.add(chunk);
				}
			}
			return affectedChunksSet;
		}, new Set());
	}

	addExtractedModulesToTargetChunk(chunk, modules) {
		for(const module of modules) {
			chunk.addModule(module);
			module.addChunk(chunk);
		}
	}

	makeTargetChunkParentOfAffectedChunks(usedChunks, commonChunk) {
		for(const chunk of usedChunks) {
			// set commonChunk as new sole parent
			chunk.setParents([commonChunk]);
			// add chunk to commonChunk
			commonChunk.addChunk(chunk);

			for(const entrypoint of chunk.getEntrypoints()) {
				entrypoint.insertChunk(commonChunk, chunk);
			}
		}
	}

	moveExtractedChunkBlocksToTargetChunk(chunks, targetChunk) {
		for(const chunk of chunks) {
			if(chunk === targetChunk) continue;
			for(const block of chunk.blocksIterable) {
				if(block.chunks.indexOf(targetChunk) === -1) {
					block.chunks.unshift(targetChunk);
				}
				targetChunk.addBlock(block);
			}
		}
	}

	extractOriginsOfChunksWithExtractedModules(chunks) {
		const origins = [];
		for(const chunk of chunks) {
			for(const origin of chunk.origins) {
				const newOrigin = Object.create(origin);
				newOrigin.reasons = (origin.reasons || []).concat("async commons");
				origins.push(newOrigin);
			}
		}
		return origins;
	}
}

module.exports = CommonsChunkPlugin;
<commit_msg>fix incorrect behavior of CommonsChunkPlugin<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";
let nextIdent = 0;

class CommonsChunkPlugin {
	constructor(options) {
		if(arguments.length > 1) {
			throw new Error(`Deprecation notice: CommonsChunkPlugin now only takes a single argument. Either an options
object *or* the name of the chunk.
Example: if your old code looked like this:
	new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js')
You would change it to:
	new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js' })
The available options are:
	name: string
	names: string[]
	filename: string
	minChunks: number
	chunks: string[]
	children: boolean
	async: boolean
	minSize: number`);
		}

		const normalizedOptions = this.normalizeOptions(options);

		this.chunkNames = normalizedOptions.chunkNames;
		this.filenameTemplate = normalizedOptions.filenameTemplate;
		this.minChunks = normalizedOptions.minChunks;
		this.selectedChunks = normalizedOptions.selectedChunks;
		this.children = normalizedOptions.children;
		this.deepChildren = normalizedOptions.deepChildren;
		this.async = normalizedOptions.async;
		this.minSize = normalizedOptions.minSize;
		this.ident = __filename + (nextIdent++);
	}

	normalizeOptions(options) {
		if(Array.isArray(options)) {
			return {
				chunkNames: options,
			};
		}

		if(typeof options === "string") {
			return {
				chunkNames: [options],
			};
		}

		// options.children and options.chunk may not be used together
		if(options.children && options.chunks) {
			throw new Error("You can't and it does not make any sense to use \"children\" and \"chunk\" options together.");
		}

		/**
		 * options.async and options.filename are also not possible together
		 * as filename specifies how the chunk is called but "async" implies
		 * that webpack will take care of loading this file.
		 */
		if(options.async && options.filename) {
			throw new Error(`You can not specify a filename if you use the "async" option.
You can however specify the name of the async chunk by passing the desired string as the "async" option.`);
		}

		/**
		 * Make sure this is either an array or undefined.
		 * "name" can be a string and
		 * "names" a string or an array
		 */
		const chunkNames = options.name || options.names ? [].concat(options.name || options.names) : undefined;
		return {
			chunkNames: chunkNames,
			filenameTemplate: options.filename,
			minChunks: options.minChunks,
			selectedChunks: options.chunks,
			children: options.children,
			deepChildren: options.deepChildren,
			async: options.async,
			minSize: options.minSize
		};
	}

	apply(compiler) {
		compiler.plugin("this-compilation", (compilation) => {
			compilation.plugin(["optimize-chunks", "optimize-extracted-chunks"], (chunks) => {
				// only optimize once
				if(compilation[this.ident]) return;
				compilation[this.ident] = true;

				/**
				 * Creates a list of "common"" chunks based on the options.
				 * The list is made up of preexisting or newly created chunks.
				 * - If chunk has the name as specified in the chunkNames it is put in the list
				 * - If no chunk with the name as given in chunkNames exists a new chunk is created and added to the list
				 *
				 * These chunks are the "targets" for extracted modules.
				 */
				const targetChunks = this.getTargetChunks(chunks, compilation, this.chunkNames, this.children, this.async);

				// iterate over all our new chunks
				targetChunks.forEach((targetChunk, idx) => {

					/**
					 * These chunks are subject to get "common" modules extracted and moved to the common chunk
					 */
					const affectedChunks = this.getAffectedChunks(compilation, chunks, targetChunk, targetChunks, idx, this.selectedChunks, this.async, this.children, this.deepChildren);

					// bail if no chunk is affected
					if(!affectedChunks) {
						return;
					}

					// If we are async create an async chunk now
					// override the "commonChunk" with the newly created async one and use it as commonChunk from now on
					let asyncChunk;
					if(this.async) {
						// If async chunk is one of the affected chunks, just use it
						asyncChunk = affectedChunks.filter(c => c.name === this.async)[0];
						// Elsewise create a new one
						if(!asyncChunk) {
							asyncChunk = this.createAsyncChunk(
								compilation,
								targetChunks.length <= 1 || typeof this.async !== "string" ? this.async :
								targetChunk.name ? `${this.async}-${targetChunk.name}` :
								true,
								targetChunk
							);
						}
						targetChunk = asyncChunk;
					}

					/**
					 * Check which modules are "common" and could be extracted to a "common" chunk
					 */
					const extractableModules = this.getExtractableModules(this.minChunks, affectedChunks, targetChunk);

					// If the minSize option is set check if the size extracted from the chunk is reached
					// else bail out here.
					// As all modules/commons are interlinked with each other, common modules would be extracted
					// if we reach this mark at a later common chunk. (quirky I guess).
					if(this.minSize) {
						const modulesSize = this.calculateModulesSize(extractableModules);
						// if too small, bail
						if(modulesSize < this.minSize)
							return;
					}

					// Remove modules that are moved to commons chunk from their original chunks
					// return all chunks that are affected by having modules removed - we need them later (apparently)
					const chunksWithExtractedModules = this.extractModulesAndReturnAffectedChunks(extractableModules, affectedChunks);

					// connect all extracted modules with the common chunk
					this.addExtractedModulesToTargetChunk(targetChunk, extractableModules);

					// set filenameTemplate for chunk
					if(this.filenameTemplate)
						targetChunk.filenameTemplate = this.filenameTemplate;

					// if we are async connect the blocks of the "reallyUsedChunk" - the ones that had modules removed -
					// with the commonChunk and get the origins for the asyncChunk (remember "asyncChunk === commonChunk" at this moment).
					// bail out
					if(this.async) {
						this.moveExtractedChunkBlocksToTargetChunk(chunksWithExtractedModules, targetChunk);
						asyncChunk.origins = this.extractOriginsOfChunksWithExtractedModules(chunksWithExtractedModules);
						return;
					}

					// we are not in "async" mode
					// connect used chunks with commonChunk - shouldnt this be reallyUsedChunks here?
					this.makeTargetChunkParentOfAffectedChunks(affectedChunks, targetChunk);
				});
				return true;
			});
		});
	}

	getTargetChunks(allChunks, compilation, chunkNames, children, asyncOption) {
		const asyncOrNoSelectedChunk = children || asyncOption;

		// we have specified chunk names
		if(chunkNames) {
			// map chunks by chunkName for quick access
			const allChunksNameMap = allChunks.reduce((map, chunk) => {
				if(chunk.name) {
					map.set(chunk.name, chunk);
				}
				return map;
			}, new Map());

			// Ensure we have a chunk per specified chunk name.
			// Reuse existing chunks if possible
			return chunkNames.map(chunkName => {
				if(allChunksNameMap.has(chunkName)) {
					return allChunksNameMap.get(chunkName);
				}
				// add the filtered chunks to the compilation
				return compilation.addChunk(chunkName);
			});
		}

		// we dont have named chunks specified, so we just take all of them
		if(asyncOrNoSelectedChunk) {
			return allChunks;
		}

		/**
		 * No chunk name(s) was specified nor is this an async/children commons chunk
		 */
		throw new Error(`You did not specify any valid target chunk settings.
Take a look at the "name"/"names" or async/children option.`);
	}

	getAffectedUnnamedChunks(affectedChunks, targetChunk, rootChunk, asyncOption, deepChildrenOption) {
		for(const chunk of targetChunk.chunksIterable) {
			if(chunk.isInitial()) {
				continue;
			}
			// If all the parents of a chunk are either
			// a) the target chunk we started with
			// b) themselves affected chunks
			// we can assume that this chunk is an affected chunk too, as there is no way a chunk that
			// isn't only depending on the target chunk is a parent of the chunk tested
			if(asyncOption || chunk.getParents().every((parentChunk) => parentChunk === rootChunk || affectedChunks.has(parentChunk))) {
				// This check not only dedupes the affectedChunks but also guarantees we avoid endless loops
				if(!affectedChunks.has(chunk)) {
					// We mutate the affected chunks before going deeper, so the deeper levels and other branches
					// have the information of this chunk being affected for their assertion if a chunk should
					// not be affected
					affectedChunks.add(chunk);

					// We recurse down to all the children of the chunk, applying the same assumption.
					// This guarantees that if a chunk should be an affected chunk,
					// at the latest the last connection to the same chunk meets the
					// condition to add it to the affected chunks.
					if(deepChildrenOption === true) {
						this.getAffectedUnnamedChunks(affectedChunks, chunk, rootChunk, asyncOption, deepChildrenOption);
					}
				}
			}
		}
	}

	getAffectedChunks(compilation, allChunks, targetChunk, targetChunks, currentIndex, selectedChunks, asyncOption, childrenOption, deepChildrenOption) {
		const asyncOrNoSelectedChunk = childrenOption || asyncOption;

		if(Array.isArray(selectedChunks)) {
			return allChunks.filter(chunk => {
				const notCommmonChunk = chunk !== targetChunk;
				const isSelectedChunk = selectedChunks.indexOf(chunk.name) > -1;
				return notCommmonChunk && isSelectedChunk;
			});
		}

		if(asyncOrNoSelectedChunk) {
			let affectedChunks = new Set();
			this.getAffectedUnnamedChunks(affectedChunks, targetChunk, targetChunk, asyncOption, deepChildrenOption);
			return Array.from(affectedChunks);
		}

		/**
		 * past this point only entry chunks are allowed to become commonChunks
		 */
		if(targetChunk.getNumberOfParents() > 0) {
			compilation.errors.push(new Error("CommonsChunkPlugin: While running in normal mode it's not allowed to use a non-entry chunk (" + targetChunk.name + ")"));
			return;
		}

		/**
		 * If we find a "targetchunk" that is also a normal chunk (meaning it is probably specified as an entry)
		 * and the current target chunk comes after that and the found chunk has a runtime*
		 * make that chunk be an 'affected' chunk of the current target chunk.
		 *
		 * To understand what that means take a look at the "examples/chunkhash", this basically will
		 * result in the runtime to be extracted to the current target chunk.
		 *
		 * *runtime: the "runtime" is the "webpack"-block you may have seen in the bundles that resolves modules etc.
		 */
		return allChunks.filter((chunk) => {
			const found = targetChunks.indexOf(chunk);
			if(found >= currentIndex) return false;
			return chunk.hasRuntime();
		});
	}

	createAsyncChunk(compilation, asyncOption, targetChunk) {
		const asyncChunk = compilation.addChunk(typeof asyncOption === "string" ? asyncOption : undefined);
		asyncChunk.chunkReason = "async commons chunk";
		asyncChunk.extraAsync = true;
		asyncChunk.addParent(targetChunk);
		targetChunk.addChunk(asyncChunk);
		return asyncChunk;
	}

	// If minChunks is a function use that
	// otherwhise check if a module is used at least minChunks or 2 or usedChunks.length time
	getModuleFilter(minChunks, targetChunk, usedChunksLength) {
		if(typeof minChunks === "function") {
			return minChunks;
		}
		const minCount = (minChunks || Math.max(2, usedChunksLength));
		const isUsedAtLeastMinTimes = (module, count) => count >= minCount;
		return isUsedAtLeastMinTimes;
	}

	getExtractableModules(minChunks, usedChunks, targetChunk) {
		if(minChunks === Infinity) {
			return [];
		}

		// count how many chunks contain a module
		const commonModulesToCountMap = usedChunks.reduce((map, chunk) => {
			for(const module of chunk.modulesIterable) {
				const count = map.has(module) ? map.get(module) : 0;
				map.set(module, count + 1);
			}
			return map;
		}, new Map());

		// filter by minChunks
		const moduleFilterCount = this.getModuleFilter(minChunks, targetChunk, usedChunks.length);
		// filter by condition
		const moduleFilterCondition = (module, chunk) => {
			if(!module.chunkCondition) {
				return true;
			}
			return module.chunkCondition(chunk);
		};

		return Array.from(commonModulesToCountMap).filter(entry => {
			const module = entry[0];
			const count = entry[1];
			// if the module passes both filters, keep it.
			return moduleFilterCount(module, count) && moduleFilterCondition(module, targetChunk);
		}).map(entry => entry[0]);
	}

	calculateModulesSize(modules) {
		return modules.reduce((totalSize, module) => totalSize + module.size(), 0);
	}

	extractModulesAndReturnAffectedChunks(reallyUsedModules, usedChunks) {
		return reallyUsedModules.reduce((affectedChunksSet, module) => {
			for(const chunk of usedChunks) {
				// removeChunk returns true if the chunk was contained and succesfully removed
				// false if the module did not have a connection to the chunk in question
				if(module.removeChunk(chunk)) {
					affectedChunksSet.add(chunk);
				}
			}
			return affectedChunksSet;
		}, new Set());
	}

	addExtractedModulesToTargetChunk(chunk, modules) {
		for(const module of modules) {
			chunk.addModule(module);
			module.addChunk(chunk);
		}
	}

	makeTargetChunkParentOfAffectedChunks(usedChunks, commonChunk) {
		for(const chunk of usedChunks) {
			// set commonChunk as new sole parent
			chunk.setParents([commonChunk]);
			// add chunk to commonChunk
			commonChunk.addChunk(chunk);

			for(const entrypoint of chunk.getEntrypoints()) {
				entrypoint.insertChunk(commonChunk, chunk);
			}
		}
	}

	moveExtractedChunkBlocksToTargetChunk(chunks, targetChunk) {
		for(const chunk of chunks) {
			if(chunk === targetChunk) continue;
			for(const block of chunk.blocksIterable) {
				if(block.chunks.indexOf(targetChunk) === -1) {
					block.chunks.unshift(targetChunk);
				}
				targetChunk.addBlock(block);
			}
		}
	}

	extractOriginsOfChunksWithExtractedModules(chunks) {
		const origins = [];
		for(const chunk of chunks) {
			for(const origin of chunk.origins) {
				const newOrigin = Object.create(origin);
				newOrigin.reasons = (origin.reasons || []).concat("async commons");
				origins.push(newOrigin);
			}
		}
		return origins;
	}
}

module.exports = CommonsChunkPlugin;
<|endoftext|>


<commit_before>/*global NMTdata,window*/
/***
 * Provides data and methods for serving ads.
 * @author: Duane.Jennings@niit-mediatech.com
 * @version: 201402261642:443263
 *
 */
var NMTdata = NMTdata || {};

    NMTdata.ads = (function () {
        // REQUIRES: NMTdata.data module to be loaded prior to this module.
        // ads related methods and properties.
        if(!window.console){
            console={};
            console.log = function(){};
        }
        console.log("NMTdata.ads init");

        var data = NMTdata.data,
        adunitPrefixDomainMappings = new Array(),
        adunitPrefixURLMappings = new Array(),
        adunitPathMappings = new Array(),
        adunitURLMappings = new Array(),
        cccPathMappings = new Array(),
        cccURLMappings = new Array(),
        i = 0,
        mmo_ccc = '',
        mmo_console = '',
        pathlength = 0,
        maxAdunitPathLength = 3,  // limit the adunit path elements.
        dfp_adunit_prefix = '', // example: /11365842/peninsulaclarion.com
        dfp_adunit = '', // example: /news/local
		dfp_ccc = ''; // customTargeting value

        // AdPay global variable for classifieds category.
        if (typeof paperCategoryID == 'undefined') paperCategoryID = 'classifieds';

////////////////////////////////////////////////////////////////////////
/***
 * mapping_version: 201501231116:443265
 */
dfp_adunit_prefix = '/11365842/savannahnow.com';
        adunitPrefixDomainMappings = [
                                      // These mappings will do a contains match against domain host.
                                      // MBU custom mappings
                                      {'autos\.coastalautos\.com': '/11365842/savannahnow.com/autos'},
                                      {'bis\.yelvington\.com': '/11365842/businessinsavannah.com'},
                                      {'businessinsavannah\.com': '/11365842/businessinsavannah.com'},
                                      {'classifieds\.savannahnow\.com': '/11365842/savannahnow.com/classifieds'},
                                      {'class\.savannahnow\.com': '/11365842/savannahnow.com/classifieds'},
                                      {'coastalmommies\.com': '/11365842/coastalmommies.com'},
                                      {'dosavannah\.com': '/11365842/savannahnow.com/entertainment'},
                                      {'events\.savannahnow\.com': '/11365842/savannahnow.com/events'},
                                      {'giftguide\.': '/11365842/giftguide.savannahnow.com'},
                                      {'physicianguide\.': '/11365842/savannahnow.com/physicianguide'},
                                      {'^m\.savannahnow\.com': '/11365842/m.savannahnow.com'},
                                      {'^m\.pfsav': '/11365842/m.savannahnow.com'},
                                      {'^www\.jaspersuntimes\.com': '/11365842/savannahnow.com/jaspersuntimes'},
                                      {'jaspercountysun\.com': '/11365842/savannahnow.com/jaspersuntimes'},
                                      {'jobs\.savannahnow\.com': '/11365842/savannahnow.com/jobs'},
                                      {'savannahhomesforsale\.com': '/11365842/savannahhomesforsale.com'},
                                      {'savannahmagazine\.com': '/11365842/savannahmagazine.com'},
                                      {'spotted\.savannahnow\.com': '/11365842/savannahnow.com/spotted'},
                                      {'rentals\.savannahnow\.com': '/11365842/savannahnow.com/rentals'},
                                      {'thebootandjetstream\.com': '/11365842/thebootandjetstream.com'},
                                      {'legacy\.com': '/11365842/savannahnow.com/obits'}
                              ];
        adunitPathMappings = [
                              // MBU custom mappings
                              {'^\/fast-physicianguide.php': '/physicianguide'},
                              // Common mappings
                              {'^\/homepageSMN$': '/homepage'}
                      ];
        cccPathMappings = [
                           // MBU custom mappings
                           {'^\/homepageSMN$': 'homepage'}
                   ];
/***
 * common mappings: 201404031011:447642
 */
        adunitURLMappings.push({'\.adpay\.com': '/classifieds'});

        adunitPathMappings.push({'^\/home$': '/homepage'});
        adunitPathMappings.push({'^\/home/am$': '/homepage'});
        adunitPathMappings.push({'^\/home/pm$': '/homepage'});
        adunitPathMappings.push({'^\/index$': '/homepage'});
        adunitPathMappings.push({'^\/$': '/homepage'});

        cccURLMappings.push({'\/clicknbuy\.aspx': NMTdata.data.getQueryParam("pcatid") || paperCategoryID});
        cccURLMappings.push({'\/searchresults\.aspx': NMTdata.data.getQueryParam("pcatid") || paperCategoryID});

        cccPathMappings.push({'^\/$': 'homepage'});
////////////////////////////////////////////////////////////////////////

        // Process domain mapping for dfp_adunit_prefix
        dfp_adunit_prefix = data.processMapping(adunitPrefixDomainMappings, location.host, dfp_adunit_prefix);

        // Process URL mapping for dfp_adunit_prefix
        dfp_adunit_prefix = data.processMapping(adunitPrefixURLMappings, document.URL, dfp_adunit_prefix);

        // build dfp_adunit default value
        // Limit adunit to 3 path elements.
        pathlength = (data.pathnames.length > maxAdunitPathLength) ? maxAdunitPathLength : data.pathnames.length;
        for (i = 0; i < pathlength; i++) {
            if (data.pathnames[i] !== '') {
                dfp_adunit += '/' + data.pathnames[i].slice(0,100);
            }
        }

        // Process Path mappings for dfp_adunit
        dfp_adunit = data.processMapping(adunitPathMappings, window.location.pathname, dfp_adunit);
        // Process URL mappings for dfp_adunit
        dfp_adunit = data.processMapping(adunitURLMappings, document.URL, dfp_adunit);

        // dfp_ccc default value
        // Paths that have trailing slash will leave the last path element empty.
        // Let's check for this case and go back one more for the ccc value.
        if (data.pathnames.length > 1 && data.pathnames[data.pathnames.length-1] == '') {
            dfp_ccc = data.pathnames[data.pathnames.length - 2];
        } else {
            dfp_ccc = data.pathnames[data.pathnames.length - 1];
        }

        // Process Path mappings for dfp_ccc
        dfp_ccc = data.processMapping(cccPathMappings, window.location.pathname, dfp_ccc);
        // Process URL mappings for dfp_ccc
        dfp_ccc = data.processMapping(cccURLMappings, document.URL, dfp_ccc);

        // override dfp_ccc with query_string mmo_ccc
        mmo_ccc = data.getQueryParam('mmo_ccc');
        if (mmo_ccc !== undefined) { dfp_ccc = mmo_ccc; }

        // Google DFP has 40 character limit on targeting values.
        dfp_ccc = dfp_ccc.slice(0,40);

        // Google DFP does not allow certain characters for adunit values.
        dfp_adunit = dfp_adunit.replace(/\s/g, '-');
        dfp_adunit = dfp_adunit.replace(/%20/g, '-');
        dfp_adunit = dfp_adunit.replace(/,/g, '-');
        dfp_adunit = dfp_adunit.replace(/%2C/g, '-');
        dfp_adunit = dfp_adunit.replace(/'/g, '');

        // output debug information to console
        mmo_console = data.getQueryParam('google_console');
        if (mmo_console !== undefined) {
            console.log("NMTdata.ads.dfp_adunit_prefix: "+dfp_adunit_prefix);
            console.log("NMTdata.ads.dfp_adunit: "+dfp_adunit);
            console.log("DFP AdUnit: "+dfp_adunit_prefix+dfp_adunit);
            console.log("NMTdata.ads.dfp_ccc: "+dfp_ccc);
        }

        // output debug information to console
        mmo_console = data.getQueryParam('nmt_console');
        if (mmo_console !== undefined) {
            document.write("
NMTdata.ads.dfp_adunit_prefix: "+dfp_adunit_prefix);
            document.write("
NMTdata.ads.dfp_adunit: "+dfp_adunit);
            document.write("
DFP AdUnit: "+dfp_adunit_prefix+dfp_adunit);
            document.write("
NMTdata.ads.dfp_ccc: "+data.escapeHtml(dfp_ccc));
        }

        return { // return object
            dfp_nmt_mapping_version: '201501231116:443265',
            dfp_nmt_ads_version: '201402261642:443263',
            dfp_adunit_prefix: dfp_adunit_prefix,
            dfp_adunit: dfp_adunit,
            dfp_ccc: data.escapeHtml(dfp_ccc)
        };

    }());

<commit_msg>SBM-048392 added mapping for dining.savannahnow.com<commit_after>/*global NMTdata,window*/
/***
 * Provides data and methods for serving ads.
 * @author: Duane.Jennings@niit-mediatech.com
 * @version: 201402261642:443263
 *
 */
var NMTdata = NMTdata || {};

    NMTdata.ads = (function () {
        // REQUIRES: NMTdata.data module to be loaded prior to this module.
        // ads related methods and properties.
        if(!window.console){
            console={};
            console.log = function(){};
        }
        console.log("NMTdata.ads init");

        var data = NMTdata.data,
        adunitPrefixDomainMappings = new Array(),
        adunitPrefixURLMappings = new Array(),
        adunitPathMappings = new Array(),
        adunitURLMappings = new Array(),
        cccPathMappings = new Array(),
        cccURLMappings = new Array(),
        i = 0,
        mmo_ccc = '',
        mmo_console = '',
        pathlength = 0,
        maxAdunitPathLength = 3,  // limit the adunit path elements.
        dfp_adunit_prefix = '', // example: /11365842/peninsulaclarion.com
        dfp_adunit = '', // example: /news/local
		dfp_ccc = ''; // customTargeting value

        // AdPay global variable for classifieds category.
        if (typeof paperCategoryID == 'undefined') paperCategoryID = 'classifieds';

////////////////////////////////////////////////////////////////////////
/***
 * mapping_version: 201501231351:443265
 */
dfp_adunit_prefix = '/11365842/savannahnow.com';
        adunitPrefixDomainMappings = [
                                      // These mappings will do a contains match against domain host.
                                      // MBU custom mappings
                                      {'autos\.coastalautos\.com': '/11365842/savannahnow.com/autos'},
                                      {'bis\.yelvington\.com': '/11365842/businessinsavannah.com'},
                                      {'businessinsavannah\.com': '/11365842/businessinsavannah.com'},
                                      {'classifieds\.savannahnow\.com': '/11365842/savannahnow.com/classifieds'},
                                      {'class\.savannahnow\.com': '/11365842/savannahnow.com/classifieds'},
                                      {'coastalmommies\.com': '/11365842/coastalmommies.com'},
                                      {'^dining\.savannahnow\.com': '/11365842/savannahnow.com/diningguide'},
                                      {'dosavannah\.com': '/11365842/savannahnow.com/entertainment'},
                                      {'events\.savannahnow\.com': '/11365842/savannahnow.com/events'},
                                      {'giftguide\.': '/11365842/giftguide.savannahnow.com'},
                                      {'physicianguide\.': '/11365842/savannahnow.com/physicianguide'},
                                      {'^m\.savannahnow\.com': '/11365842/m.savannahnow.com'},
                                      {'^m\.pfsav': '/11365842/m.savannahnow.com'},
                                      {'^www\.jaspersuntimes\.com': '/11365842/savannahnow.com/jaspersuntimes'},
                                      {'jaspercountysun\.com': '/11365842/savannahnow.com/jaspersuntimes'},
                                      {'jobs\.savannahnow\.com': '/11365842/savannahnow.com/jobs'},
                                      {'savannahhomesforsale\.com': '/11365842/savannahhomesforsale.com'},
                                      {'savannahmagazine\.com': '/11365842/savannahmagazine.com'},
                                      {'spotted\.savannahnow\.com': '/11365842/savannahnow.com/spotted'},
                                      {'rentals\.savannahnow\.com': '/11365842/savannahnow.com/rentals'},
                                      {'thebootandjetstream\.com': '/11365842/thebootandjetstream.com'},
                                      {'legacy\.com': '/11365842/savannahnow.com/obits'}
                              ];
        adunitPathMappings = [
                              // MBU custom mappings
                              {'^\/fast-physicianguide.php': '/physicianguide'},
                              // Common mappings
                              {'^\/homepageSMN$': '/homepage'}
                      ];
        cccPathMappings = [
                           // MBU custom mappings
                           {'^\/homepageSMN$': 'homepage'}
                   ];
/***
 * common mappings: 201404031011:447642
 */
        adunitURLMappings.push({'\.adpay\.com': '/classifieds'});

        adunitPathMappings.push({'^\/home$': '/homepage'});
        adunitPathMappings.push({'^\/home/am$': '/homepage'});
        adunitPathMappings.push({'^\/home/pm$': '/homepage'});
        adunitPathMappings.push({'^\/index$': '/homepage'});
        adunitPathMappings.push({'^\/$': '/homepage'});

        cccURLMappings.push({'\/clicknbuy\.aspx': NMTdata.data.getQueryParam("pcatid") || paperCategoryID});
        cccURLMappings.push({'\/searchresults\.aspx': NMTdata.data.getQueryParam("pcatid") || paperCategoryID});

        cccPathMappings.push({'^\/$': 'homepage'});
////////////////////////////////////////////////////////////////////////

        // Process domain mapping for dfp_adunit_prefix
        dfp_adunit_prefix = data.processMapping(adunitPrefixDomainMappings, location.host, dfp_adunit_prefix);

        // Process URL mapping for dfp_adunit_prefix
        dfp_adunit_prefix = data.processMapping(adunitPrefixURLMappings, document.URL, dfp_adunit_prefix);

        // build dfp_adunit default value
        // Limit adunit to 3 path elements.
        pathlength = (data.pathnames.length > maxAdunitPathLength) ? maxAdunitPathLength : data.pathnames.length;
        for (i = 0; i < pathlength; i++) {
            if (data.pathnames[i] !== '') {
                dfp_adunit += '/' + data.pathnames[i].slice(0,100);
            }
        }

        // Process Path mappings for dfp_adunit
        dfp_adunit = data.processMapping(adunitPathMappings, window.location.pathname, dfp_adunit);
        // Process URL mappings for dfp_adunit
        dfp_adunit = data.processMapping(adunitURLMappings, document.URL, dfp_adunit);

        // dfp_ccc default value
        // Paths that have trailing slash will leave the last path element empty.
        // Let's check for this case and go back one more for the ccc value.
        if (data.pathnames.length > 1 && data.pathnames[data.pathnames.length-1] == '') {
            dfp_ccc = data.pathnames[data.pathnames.length - 2];
        } else {
            dfp_ccc = data.pathnames[data.pathnames.length - 1];
        }

        // Process Path mappings for dfp_ccc
        dfp_ccc = data.processMapping(cccPathMappings, window.location.pathname, dfp_ccc);
        // Process URL mappings for dfp_ccc
        dfp_ccc = data.processMapping(cccURLMappings, document.URL, dfp_ccc);

        // override dfp_ccc with query_string mmo_ccc
        mmo_ccc = data.getQueryParam('mmo_ccc');
        if (mmo_ccc !== undefined) { dfp_ccc = mmo_ccc; }

        // Google DFP has 40 character limit on targeting values.
        dfp_ccc = dfp_ccc.slice(0,40);

        // Google DFP does not allow certain characters for adunit values.
        dfp_adunit = dfp_adunit.replace(/\s/g, '-');
        dfp_adunit = dfp_adunit.replace(/%20/g, '-');
        dfp_adunit = dfp_adunit.replace(/,/g, '-');
        dfp_adunit = dfp_adunit.replace(/%2C/g, '-');
        dfp_adunit = dfp_adunit.replace(/'/g, '');

        // output debug information to console
        mmo_console = data.getQueryParam('google_console');
        if (mmo_console !== undefined) {
            console.log("NMTdata.ads.dfp_adunit_prefix: "+dfp_adunit_prefix);
            console.log("NMTdata.ads.dfp_adunit: "+dfp_adunit);
            console.log("DFP AdUnit: "+dfp_adunit_prefix+dfp_adunit);
            console.log("NMTdata.ads.dfp_ccc: "+dfp_ccc);
        }

        // output debug information to console
        mmo_console = data.getQueryParam('nmt_console');
        if (mmo_console !== undefined) {
            document.write("
NMTdata.ads.dfp_adunit_prefix: "+dfp_adunit_prefix);
            document.write("
NMTdata.ads.dfp_adunit: "+dfp_adunit);
            document.write("
DFP AdUnit: "+dfp_adunit_prefix+dfp_adunit);
            document.write("
NMTdata.ads.dfp_ccc: "+data.escapeHtml(dfp_ccc));
        }

        return { // return object
            dfp_nmt_mapping_version: '201501231351:443265',
            dfp_nmt_ads_version: '201402261642:443263',
            dfp_adunit_prefix: dfp_adunit_prefix,
            dfp_adunit: dfp_adunit,
            dfp_ccc: data.escapeHtml(dfp_ccc)
        };

    }());

<|endoftext|>


<commit_before>mi2JS.comp.add('base/MultiCheck', 'base/InputBase', '',

// component initializer function that defines constructor and adds methods to the prototype
function(proto, superProto, comp, superComp){

	var mi2 = mi2JS;

	mi2.mixin(comp,mi2.NWGroup);

	proto.itemTpl = {tag:'B'};

	proto.construct = function(el, tpl, parent){
		this.items = {};
		superProto.construct.call(this, el, tpl, parent);

		this.listen(el,'click');
		this.mapItems(el.children);
	};

	proto.mapItems = function(it){
		var id, nw;
		for(var i=0; i<it.length; i++){
			nw = this.findRef(it[i]);
			id = nw.data('id');
			if(id !== null) this.items[id] = nw;
		}
	};

	proto.on_click = function(evt){
		var target = this.item(evt.target);
		if(target){
			if(this.attr('single-value')){
				this.selectedIs(target.data('id'));
			}else{
				target.setSelected(!target.isSelected());
			}
			this.fireIfChanged();
		}
	};

	proto.setConfig = function(data){
		// NodeWrapper is cheap, so we discard the old ones
		this.innerHTML = '';
		this.items = {};
		// allow key:value object or array of {id:'',text:''} objects
		var isArray = data instanceof Array;
		for(var p in data){
			var id = isArray ? data[p].id : p;
			var item = mi2.add(this.el, this.itemTpl);
			item.data('id', id);
			item.setText(   isArray ? data[p].text  : data[p]);
			this.items[id] = item;
		}
	};

	proto.setRawValue = function(value){
		this.selectedIs( value );
	};

	proto.getRawValue = function(value){
		var ret = this.forEachGetArray(function(item){
			if(item.isSelected()) return item.data('id');
		});

		if(this.attr('single-value')) ret = ret[0];

		return ret;
	};

});
<commit_msg>set readonly to buttons too so css can be reused for checkbox<commit_after>mi2JS.comp.add('base/MultiCheck', 'base/InputBase', '',

// component initializer function that defines constructor and adds methods to the prototype
function(proto, superProto, comp, superComp){

	var mi2 = mi2JS;

	mi2.mixin(comp,mi2.NWGroup);

	proto.itemTpl = {tag:'B'};

	proto.construct = function(el, tpl, parent){
		this.items = {};
		superProto.construct.call(this, el, tpl, parent);

		this.listen(el,'click');
		this.mapItems(el.children);
		if(this.isReadOnly()) this.setReadOnly(true);
	};

	proto.mapItems = function(it){
		var id, nw;
		for(var i=0; i<it.length; i++){
			nw = this.findRef(it[i]);
			id = nw.data('id');
			if(id !== null) this.items[id] = nw;
		}
	};

	proto.setReadOnly = function(v){
		superProto.setReadOnly.call(this,v);
		this.callFunc('attr',['readonly',v ? '':null]);
	};

	proto.on_click = function(evt){
		if(this.isReadOnly() || !this.isEnabled()) return;

		var target = this.item(evt.target);
		if(target){
			if(this.attr('single-value')){
				this.selectedIs(target.data('id'));
			}else{
				target.setSelected(!target.isSelected());
			}
			this.fireIfChanged();
		}
	};

	proto.setConfig = function(data){
		// NodeWrapper is cheap, so we discard the old ones
		this.innerHTML = '';
		this.items = {};
		// allow key:value object or array of {id:'',text:''} objects
		var isArray = data instanceof Array;
		for(var p in data){
			var id = isArray ? data[p].id : p;
			var item = mi2.add(this.el, this.itemTpl);
			item.data('id', id);
			item.setText(   isArray ? data[p].text  : data[p]);
			this.items[id] = item;
		}
	};

	proto.setRawValue = function(value){
		this.selectedIs( value );
	};

	proto.getRawValue = function(value){
		var ret = this.forEachGetArray(function(item){
			if(item.isSelected()) return item.data('id');
		});

		if(this.attr('single-value')) ret = ret[0];

		return ret;
	};

});
<|endoftext|>


<commit_before>/**
 *  Build Script for Docker Image
 *
 *  1. cleanup output directories
 *  2. build poinz client (webpack)
 *  3. copy client and backend to "deploy" folder
 *  4. build docker image (see Dockerfile)
 *
 * */
const
  path = require('path'),
  Promise = require('bluebird'),
  fs = Promise.promisifyAll(require('fs-extra')),
  spawn = require('child_process').spawn,
  exec = Promise.promisify(require('child_process').exec),
  del = require('del');

// first let's clean up
del([
  './deploy/src/',
  './deploy/public',
  './deploy/package.json',
  '!./client/dist/index.html',
  './client/dist/**/*'
])
  .then(() => {
    console.log('installing npm dependencies for client...');
    return spawnAndPrint('npm', ['install'], {cwd: path.resolve(__dirname, '../client')});
  })
  .then(() => {
    console.log('building client with webpack...');
    return spawnAndPrint(
      './node_modules/.bin/webpack', '-p --colors --bail --config webpack.production.config.js'.split(' '),
      {cwd: path.resolve(__dirname, '../client')});
  })
  .then(() => fs.copy('./client/dist', './deploy/public/assets'))
  .then(() => fs.copy('./client/index.html', './deploy/public/index.html'))
  .then(() => fs.copy('./server/src', './deploy/src'))
  .then(() => fs.copy('./server/package.json', './deploy/package.json'))
  .then(getGitInformation)
  .then(startBuildingDockerImage)
  .catch(error => {
    console.error(error);
    process.exit(1);
  });

/**
 * spawns a child process (nodejs' child_process.spawn)
 * and pipes stdout and stderr to the node process.
 *
 * @param command
 * @param arguments
 * @param options
 * @returns {Promise<T>} Returns a promise that will reject if childprocess does not exit with code 0.
 */
function spawnAndPrint(command, arguments, options) {

  var spawned = spawn(command, arguments, options);
  spawned.stdout.pipe(process.stdout);
  spawned.stderr.pipe(process.stderr);

  return new Promise((resolve, reject) => spawned.on('exit', code => code != 0 ? reject(new Error('Error in child process')) : resolve()));
}

function startBuildingDockerImage(gitInfo) {
  console.log(`building docker container for ${gitInfo.hash} on ${gitInfo.branch}`);

  const userAndProject = 'xeronimus/poinz';
  const arguments = `build -t ${userAndProject}:latest -t ${userAndProject}:${gitInfo.branch} -t ${userAndProject}:${gitInfo.hash} .`;

  return spawnAndPrint('docker', arguments.split(' '), {cwd: path.resolve(__dirname, '..')});
}

function getGitInformation() {
  return Promise.all([
      exec('git rev-parse --abbrev-ref HEAD', {cdw: __dirname}),
      exec('git rev-parse --short HEAD', {cdw: __dirname})
    ])
    .spread((abbrev, short) => ({
      branch: abbrev.split('\n').join(''),
      hash: short.split('\n').join('')
    }));
}

<commit_msg>fix bug in dockerImage build script<commit_after>/**
 *  Build Script for Docker Image
 *
 *  1. cleanup output directories
 *  2. build poinz client (webpack)
 *  3. copy client and backend to "deploy" folder
 *  4. build docker image (see Dockerfile)
 *
 * */
const
  path = require('path'),
  Promise = require('bluebird'),
  fs = Promise.promisifyAll(require('fs-extra')),
  spawn = require('child_process').spawn,
  exec = Promise.promisify(require('child_process').exec),
  del = require('del');

// first let's clean up
del([
  './deploy/src/',
  './deploy/public',
  './deploy/package.json',
  '!./client/dist/index.html',
  './client/dist/**/*'
])
  .then(() => {
    console.log('installing npm dependencies for client...');
    return spawnAndPrint('npm', ['install'], {cwd: path.resolve(__dirname, '../client')});
  })
  .then(() => {
    console.log('building client with webpack...');
    return spawnAndPrint(
      './node_modules/.bin/webpack', '-p --colors --bail --config webpack.production.config.js'.split(' '),
      {cwd: path.resolve(__dirname, '../client')});
  })
  .then(() => fs.copy('./client/dist', './deploy/public/assets'))
  .then(() => fs.copy('./client/index.html', './deploy/public/index.html'))
  .then(() => fs.copy('./server/src', './deploy/src'))
  .then(() => fs.copy('./server/package.json', './deploy/package.json'))
  .then(getGitInformation)
  .then(startBuildingDockerImage)
  .catch(error => {
    console.error(error);
    console.error(error.stack);
    process.exit(1);
  });

/**
 * spawns a child process (nodejs' child_process.spawn)
 * and pipes stdout and stderr to the node process.
 *
 * @param command
 * @param arguments
 * @param options
 * @returns {Promise<T>} Returns a promise that will reject if childprocess does not exit with code 0.
 */
function spawnAndPrint(command, arguments, options) {

  var spawned = spawn(command, arguments, options);
  spawned.stdout.pipe(process.stdout);
  spawned.stderr.pipe(process.stderr);

  return new Promise((resolve, reject) => spawned.on('exit', code => code != 0 ? reject(new Error('Error in child process')) : resolve()));
}

function startBuildingDockerImage(gitInfo) {
  console.log(`building docker container for ${gitInfo.hash} on ${gitInfo.branch}`);

  const userAndProject = 'xeronimus/poinz';
  const cmdArgs = `build -t ${userAndProject}:latest -t ${userAndProject}:${gitInfo.branch} -t ${userAndProject}:${gitInfo.hash} .`;

  return spawnAndPrint('docker', cmdArgs.split(' '), {cwd: path.resolve(__dirname, '..')});
}

function getGitInformation() {
  return Promise.all([
      exec('git rev-parse --abbrev-ref HEAD', {cdw: __dirname}),
      exec('git rev-parse --short HEAD', {cdw: __dirname})
    ])
    .spread((abbrev, short) => ({
      branch: abbrev.split('\n').join(''),
      hash: short.split('\n').join('')
    }));
}

<|endoftext|>


<commit_before>var chalk = require('chalk');

//Let's override some functionality to make my life easier.
//From http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format/4673436#4673436
// First, checks if it isn't implemented yet.
if (!String.prototype.format) {
    String.prototype.format = function() {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function(match, number) {
            return typeof args[number] != 'undefined' ? args[number] : match;
        });
    };
}

exports.RedBlackTree = function() {
    //Init
    var self = this;
    var rootNode;

    //////////////////
    //Private
    //////////////////

    function Node(value) {
        var self = this;
        var left = undefined;
        var right = undefined;
        var parent = undefined;

        self.ValidColors = {
            Red: "red",
            Black: "grey"
        };

        self.Color = self.ValidColors.Red;
        self.Value = value;

        self.IsLeftChild = function() {
            var result = false;
            if (parent != undefined && parent.Left() == self) {
                result = true;
            }
            return result;
        }

        self.IsRightChild = function() {
            var result = false;
            if (parent != undefined && parent.Right() == self) {
                result = true;
            }
            return result;
        }

        self.Grandparent = function() {
            var result = undefined;
            if (parent != undefined) {
                result = parent.Parent();
            }
            return result;
        }

        self.Uncle = function() {
            var result = undefined;
            if (self.IsRightChild()) {
                if (self.Grandparent() != undefined) {
                    result = self.Grandparent().Left();
                    if (result == undefined) {
                        result = new Node();
                    }
                }
            } else if (self.IsLeftChild()) {
                if (self.Grandparent() != undefined) {
                    result = self.Grandparent().Right();
                }
            }
            return result;
        }

        self.SwapColors = function() {
            if (self.Color == ValidColors.Red) {
                self.Color = ValidColors.Black;
            } else {
                self.Color = ValidColors.Red;
            }
        }

        self.Left = function(node) {
            if (node) {
                left = node;
            }

            var result = undefined;
            if (left != undefined) {
                result = left;
            } else {
                result = new Node();
                result.Value = undefined;
                result.Color = self.ValidColors.Black;
            }

            return result;
        }

        self.Right = function(node) {
            if (node) {
                right = node;
            }

            var result = undefined;
            if (right != undefined) {
                result = right;
            } else {
                result = new Node();
                result.Value = undefined;
                result.Color = self.ValidColors.Black;
            }

            return result;
        }

        self.Parent = function(node) {
            if (node) {
                parent = node;
            }
            return parent;
        };

        return self;
    }

    function RotateLeft() {

    }

    function RotateRight() {

    }

    function Compare(val1, val2) {
        return val1 - val2;
    }

    function TreeInsert(item) {
        var newNode = undefined;
        if (rootNode == undefined) {
            rootNode = new Node(item);
            newNode = rootNode;
        } else {
            var currentNode = rootNode;
            var nextNode = undefined;
            while (true) {
                if (Compare(item, currentNode.Value) <= 0) {
                    nextNode = currentNode.Left();
                    if (nextNode.Value == undefined) {
                        newNode = currentNode.Left(new Node(item));
                        newNode.Parent(currentNode);
                        break;
                    }
                } else {
                    nextNode = currentNode.Right();
                    if (nextNode.Value == undefined) {
                        newNode = currentNode.Right(new Node(item));
                        newNode.Parent(currentNode);
                        break;
                    }
                }
                currentNode = nextNode;
            }
        }

        return newNode;
    }

    //////////////////
    //Public Methods
    //////////////////

    self.Depth = function(starterNode) {
        function DepthHelper(node) {
            if (node.Value == undefined) {
                return 0;
            } else {
                return Math.max(DepthHelper(node.Left()), DepthHelper(node.Right())) + 1;
            }
        }
        if (!starterNode) {
            starterNode = rootNode;
        }

        return DepthHelper(starterNode);
    }

    //    Case 1:
    // 1. Uncle is Red

    // Solution for Case 1:
    // 1. Swap colors of Parent, Uncle, and Grandparent
    // 2. Grandparent becomes the new node to check for violations

    // Case 2:
    // 1. Uncle is Black
    // 2a. Node is a Left Child of a Right Child
    // 2b. Node is a Right Child of a Left Child

    // Solution for Case 2:
    // 1a. Right rotate around Parent for 2a = Case 3
    // 1b. Left rotate around Parent for 2b = Case 3
    // 2. Parent becomes the new node to check for violations

    // Case 3:
    // 1. Uncle is Black
    // 2a. Node is a Right Child of a Right Child
    // 2b. Node is a Left Child of a Left Child

    // Solution for Case 3:
    // 1a. Left rotate around Grandparent for 2a
    // 1b. Right rotate around Grandparent for 2b
    // 2. Swap colors of Parent and Grandparent
    // 3. Grandparent becomes the new node to check for violations
    self.Insert = function(item) {
        var node = TreeInsert(item);
        while (node != rootNode) {
            if (node.Uncle() && node.Uncle().Color == node.ValidColors.Red) { //Uncle is Red
                node.Parent().SwapColors();
                node.Grandparent().SwapColors();
                node = node.Grandparent();
            } else if (node.Uncle() &&
                node.Uncle().Color == node.ValidColors.Black) { //If the uncle is black
                if (node.IsLeftChild() && node.Parent().IsRightChild()) {
                    break;
                } else if (node.IsRightChild() && node.Parent().IsLeftChild()) {
                    break;
                } else if (node.IsLeftChild() && node.Parent().IsLeftChild()) {
                    break;
                } else if (node.IsRightChild() && node.Parent().IsRightChild()) {
                    break;
                }
            } else { //No rules voilated
                break;
            }
        }

        if (node == rootNode) {
            node.Color = node.ValidColors.Black;
        }
    }

    self.Delete = function(item) {

    }

    self.Contains = function(item) {

    }

    self.PrintTree = function() {
        var queue = [];

        var currentDepth = self.Depth();
        var currDistance = 0;
        queue.push([rootNode, 0]);

        console.log("Current Tree");
        console.log("----");
        process.stdout.write("Level " + currDistance + ":");
        while (queue.length > 0) {
            var obj = queue.shift();
            if (obj) {
                var node = obj[0];
                var distance = obj[1];

                if (!node.Value) {
                    process.stdout.write(" ");
                    continue;
                }

                if (currDistance < distance) {
                    console.log("");
                    currDistance = distance;
                    process.stdout.write("Level " + currDistance + ":");
                }

                if (node) {
                    queue.push([node.Left(), currDistance + 1]);
                    queue.push([node.Right(), currDistance + 1]);

                    var leftNode = ((node.Left().Value == undefined) ? chalk.grey("NaN") : chalk[node.Left().Color](node.Left().Value));
                    var rightNode = ((node.Right().Value == undefined) ? chalk.grey("NaN") : chalk[node.Right().Color](node.Right().Value));
                    var line = " {0}({1},{2}) ".format(chalk[node.Color](node.Value), leftNode, rightNode)

                    process.stdout.write(line);
                }
            }
        }
        console.log("");
        console.log("----");
    }

    return self;
}

if (require.main === module) {
    var foo = new exports.RedBlackTree();
    foo.Insert(1);
    foo.Insert(2);
    foo.Insert(3);
    foo.Insert(4);
    // foo.Insert(-1);
    // foo.Insert(-2);
    // foo.Insert(0);
    // foo.Insert(2);
    // foo.Insert(10);
    foo.PrintTree();
    //console.log(foo.Depth());
}<commit_msg>We are in beta.  Added the rotate commands and can now get up to the height of 2 on the tree<commit_after>var chalk = require('chalk');

//Let's override some functionality to make my life easier.
//From http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format/4673436#4673436
// First, checks if it isn't implemented yet.
if (!String.prototype.format) {
    String.prototype.format = function() {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function(match, number) {
            return typeof args[number] != 'undefined' ? args[number] : match;
        });
    };
}

exports.RedBlackTree = function() {
    //Init
    var self = this;
    var rootNode;

    //////////////////
    //Private
    //////////////////

    function Node(value) {
        var self = this;
        var left = undefined;
        var right = undefined;
        var parent = undefined;

        self.ValidColors = {
            Red: "red",
            Black: "grey"
        };

        self.Color = self.ValidColors.Red;
        self.Value = value;
        self.NilNode = false;

        self.IsLeftChild = function() {
            var result = false;
            if (parent != undefined && parent.Left() == self) {
                result = true;
            }
            return result;
        }

        self.IsRightChild = function() {
            var result = false;
            if (parent != undefined && parent.Right() == self) {
                result = true;
            }
            return result;
        }

        self.Grandparent = function() {
            var result = undefined;
            if (parent != undefined) {
                result = parent.Parent();
            }
            return result;
        }

        self.Uncle = function() {
            var result = undefined;
            if (self.IsRightChild()) {
                if (self.Grandparent() != undefined) {
                    result = self.Grandparent().Left();
                    if (result == undefined) {
                        result = new Node();
                    }
                }
            } else if (self.IsLeftChild()) {
                if (self.Grandparent() != undefined) {
                    result = self.Grandparent().Right();
                }
            }
            return result;
        }

        self.SwapColors = function() {
            if (self.Color == self.ValidColors.Red) {
                self.Color = self.ValidColors.Black;
            } else {
                self.Color = self.ValidColors.Red;
            }
        }

        //Insert as left node and have node refer to self as parent
        self.Left = function(node) {
            if (node && !node.NilNode) {
                left = node;
                node.Parent(self);
            }

            var result = undefined;
            if (left != undefined) {
                result = left;
            } else {
                result = new Node();
                result.Value = undefined;
                result.Color = self.ValidColors.Black;
                result.NilNode = true;
            }

            return result;
        }

        //Insert as right node and have node refer to self as parent
        self.Right = function(node) {
            if (node && !node.NilNode) {
                right = node;
                node.Parent(self);
            }

            var result = undefined;
            if (right != undefined) {
                result = right;
            } else {
                result = new Node();
                result.Value = undefined;
                result.Color = self.ValidColors.Black;
                result.NilNode = true;
            }

            return result;
        }

        self.Parent = function(node) {
            if (node) {
                parent = node;
            }
            return parent;
        };

        self.RemoveParent = function(){
        	parent = undefined;
        }

        self.RemoveLeft = function(){
        	left = undefined;
        }

        self.RemoveRight = function(){
        	right = undefined;
        }

        return self;
    }

    function RotateLeft(node) {
    	var rightChild = node.Right();
    	var rightChildsLeft = rightChild.Left();

    	//Rotate
    	rightChild.Left(node);

    	if(!rightChildsLeft.NilNode){
    		node.Right(rightChildsLeft);
    	} else {
    		node.RemoveRight();
    	}

    	if(node == rootNode){
    		rootNode = rightChild;
    		rootNode.RemoveParent();
    	}
    }

    function RotateRight(node) {
    	var leftChild = node.Left();
    	var leftChildsRight = leftChild.Right();

    	//Rotate
    	leftChild.Right(node);
    	if(!leftChildsRight.NilNode){
    		node.Right(rightChildsLeft);
    	} else {
    		node.RemoveLeft();
    	}

    	if(node == rootNode){
    		rootNode = leftChild;
    		rootNode.RemoveParent();
    	}
    }

    function Compare(val1, val2) {
        return val1 - val2;
    }

    function TreeInsert(item) {
        var newNode = undefined;
        if (rootNode == undefined) {
            rootNode = new Node(item);
            newNode = rootNode;
        } else {
            var currentNode = rootNode;
            var nextNode = undefined;
            while (true) {
                if (Compare(item, currentNode.Value) <= 0) {
                    nextNode = currentNode.Left();
                    if (nextNode.NilNode) {
                        newNode = currentNode.Left(new Node(item));
                        break;
                    }
                } else {
                    nextNode = currentNode.Right();
                    if (nextNode.NilNode) {
                        newNode = currentNode.Right(new Node(item));
                        break;
                    }
                }
                currentNode = nextNode;
            }
        }

        return newNode;
    }

    //////////////////
    //Public Methods
    //////////////////

    self.Depth = function(starterNode) {
        function DepthHelper(node) {
            if (node.NilNode) {
                return 0;
            } else {
                return Math.max(DepthHelper(node.Left()), DepthHelper(node.Right())) + 1;
            }
        }
        if (!starterNode) {
            starterNode = rootNode;
        }

        return DepthHelper(starterNode);
    }

    //    Case 1:
    // 1. Uncle is Red

    // Solution for Case 1:
    // 1. Swap colors of Parent, Uncle, and Grandparent
    // 2. Grandparent becomes the new node to check for violations

    // Case 2:
    // 1. Uncle is Black
    // 2a. Node is a Left Child of a Right Child
    // 2b. Node is a Right Child of a Left Child

    // Solution for Case 2:
    // 1a. Right rotate around Parent for 2a = Case 3
    // 1b. Left rotate around Parent for 2b = Case 3
    // 2. Parent becomes the new node to check for violations

    // Case 3:
    // 1. Uncle is Black
    // 2a. Node is a Right Child of a Right Child
    // 2b. Node is a Left Child of a Left Child

    // Solution for Case 3:
    // 1a. Left rotate around Grandparent for 2a
    // 1b. Right rotate around Grandparent for 2b
    // 2. Swap colors of Parent and Grandparent
    // 3. Grandparent becomes the new node to check for violations
    self.Insert = function(item) {
        var node = TreeInsert(item);
        while (node != rootNode) {
        	if(node.Value == 4){
        		debugger;
        	}
            if (node.Uncle() && node.Uncle().Color == node.ValidColors.Red) { //Uncle is Red
                node.Parent().SwapColors();
                node.Grandparent().SwapColors();
                node.Uncle().SwapColors();
                node = node.Grandparent();
            } else if (node.Uncle() && node.Uncle().Color == node.ValidColors.Black) { //If the uncle is black
                if (node.IsLeftChild() && node.Parent().IsRightChild()) {
                    var parent = node.Parent();
                    RotateRight(parent);
                    node = parent;
                } else if (node.IsRightChild() && node.Parent().IsLeftChild()) {
                    var parent = node.Parent();
                    RotateLeft(parent);
                    node = parent;
                } else if (node.IsLeftChild() && node.Parent().IsLeftChild()) {
                    var grandparent = node.Grandparent();
                    var parent = node.Parent();
                    RotateRight(grandparent);

                    grandparent.SwapColors();
                    parent.SwapColors();
                    node = grandparent;
                } else if (node.IsRightChild() && node.Parent().IsRightChild()) {
                    var grandparent = node.Grandparent();
                    var parent = node.Parent();
                    RotateLeft(grandparent);

                    grandparent.SwapColors();
                    parent.SwapColors();
                    node = grandparent;
                }
            } else { //No rules voilated
                node = node.Parent();
            }
        }

        if (node == rootNode) {
            node.Color = node.ValidColors.Black;
        }
    }

    self.Delete = function(item) {

    }

    self.Contains = function(item) {

    }

    self.PrintTree = function() {
        var queue = [];

        var currentDepth = self.Depth();
        var currDistance = 0;
        queue.push([rootNode, 0]);

        console.log("Current Tree");
        console.log("----");
        process.stdout.write("Level " + currDistance + ":");
        while (queue.length > 0) {
            var obj = queue.shift();
            if (obj) {
                var node = obj[0];
                var distance = obj[1];

                if (node.NilNode) {
                    process.stdout.write(" ");
                    continue;
                }

                if (currDistance < distance) {
                    console.log("");
                    currDistance = distance;
                    process.stdout.write("Level " + currDistance + ":");
                }

                if (node) {
                    queue.push([node.Left(), currDistance + 1]);
                    queue.push([node.Right(), currDistance + 1]);

                    var leftNode = ((node.Left().NilNode) ? chalk.grey("NaN") : chalk[node.Left().Color](node.Left().Value));
                    var rightNode = ((node.Right().NilNode) ? chalk.grey("NaN") : chalk[node.Right().Color](node.Right().Value));
                    var line = " {0}({1},{2}) ".format(chalk[node.Color](node.Value), leftNode, rightNode)

                    process.stdout.write(line);
                }
            }
        }
        console.log("");
        console.log("----");
    }

    return self;
}

if (require.main === module) {
    var foo = new exports.RedBlackTree();
    foo.Insert(1);
    foo.Insert(2);
    foo.Insert(3);
    foo.Insert(4);
    //foo.Insert(5);
    //foo.Insert(6);
    // foo.Insert(-1);
    // foo.Insert(-2);
    // foo.Insert(0);
    // foo.Insert(2);
    // foo.Insert(10);
    foo.PrintTree();
    //console.log(foo.Depth());
}<|endoftext|>