<commit_before>L.Util.extend(L.DomEvent, {

	_msTouches: [],

	// Provides a touch events wrapper for msPointer events.
	// Based on changes by veproza https://github.com/CloudMade/Leaflet/pull/1019

	addMsTouchListener: function (obj, type, handler, id) {

		switch (type) {
		case 'touchstart':
			return this.addMsTouchListenerStart(obj, type, handler, id);
		case 'touchend':
			return this.addMsTouchListenerEnd(obj, type, handler, id);
		case 'touchmove':
			return this.addMsTouchListenerMove(obj, type, handler, id);
		default:
			throw 'Unknown touch event type';
		}
	},

	addMsTouchListenerStart: function (obj, type, handler, id) {
		var pre = '_leaflet_',
			touches = this._msTouches;

		var cb = function (e) {

			var alreadyInArray = false;
			for (var i = 0; i < touches.length; i++) {
				if (touches[i].pointerId === e.pointerId) {
					alreadyInArray = true;
					break;
				}
			}
			if (!alreadyInArray) {
				touches.push(e);
			}

			e.touches = touches.slice();
			e.changedTouches = [e];

			handler(e);
		};

		obj[pre + 'touchstart' + id] = cb;
		obj.addEventListener('MSPointerDown', cb, this);

		//Need to also listen for end events to keep the _msTouches list accurate
		var internalCb = function (e) {
			for (var i = 0; i < touches.length; i++) {
				if (touches[i].pointerId === e.pointerId) {
					touches.splice(i, 1);
					break;
				}
			}
		};
		obj.addEventListener('MSPointerUp', internalCb, this);
		obj.addEventListener('MSPointerCancel', internalCb, this);
		obj[pre + 'touchstartend' + id] = cb;

		return this;
	},

	addMsTouchListenerMove: function (obj, type, handler, id) {
		var pre = '_leaflet_';

		var touches = this._msTouches;
		var cb = function (e) {

			//Don't fire touch moves when mouse isn't down
			if (e.pointerType === e.MSPOINTER_TYPE_MOUSE && e.buttons === 0) {
				return;
			}

			for (var i = 0; i < touches.length; i++) {
				if (touches[i].pointerId === e.pointerId) {
					touches[i] = e;
					break;
				}
			}

			e.touches = touches.slice();
			e.changedTouches = [e];

			handler(e);
		};

		obj[pre + 'touchmove' + id] = cb;
		obj.addEventListener('MSPointerMove', cb, this);

		return this;
	},

	addMsTouchListenerEnd: function (obj, type, handler, id) {
		var pre = '_leaflet_',
			touches = this._msTouches;

		var cb = function (e) {

			for (var i = 0; i < touches.length; i++) {
				if (touches[i].pointerId === e.pointerId) {
					touches.splice(i, 1);
					break;
				}
			}

			e.touches = touches.slice();
			e.changedTouches = [e];

			handler(e);
		};

		obj[pre + 'touchend' + id] = cb;
		obj.addEventListener('MSPointerUp', cb, this);
		obj.addEventListener('MSPointerCancel', cb, this);

		return this;
	},

	removeMsTouchListener: function (obj, type, id) {
		var pre = '_leaflet_',
		    cb = obj[pre + type + id];

		switch (type) {
		case 'touchstart':
			obj.removeEventListener('MSPointerDown', cb, this);
			obj.removeEventListener('MSPointerUp', obj[pre + 'touchstartend' + id], this);
			obj.removeEventListener('MSPointerCancel', obj[pre + 'touchstartend' + id], this);
			break;
		case 'touchmove':
			obj.removeEventListener('MSPointerMove', cb, this);
			break;
		case 'touchend':
			obj.removeEventListener('MSPointerUp', cb, this);
			obj.removeEventListener('MSPointerCancel', cb, this);
			break;
		}

		return this;
	}
});
<commit_msg>Attempt a fix at the screen edge bug<commit_after>L.Util.extend(L.DomEvent, {

	_msTouches: [],

	// Provides a touch events wrapper for msPointer events.
	// Based on changes by veproza https://github.com/CloudMade/Leaflet/pull/1019

	addMsTouchListener: function (obj, type, handler, id) {

		switch (type) {
		case 'touchstart':
			return this.addMsTouchListenerStart(obj, type, handler, id);
		case 'touchend':
			return this.addMsTouchListenerEnd(obj, type, handler, id);
		case 'touchmove':
			return this.addMsTouchListenerMove(obj, type, handler, id);
		default:
			throw 'Unknown touch event type';
		}
	},

	addMsTouchListenerStart: function (obj, type, handler, id) {
		var pre = '_leaflet_',
			touches = this._msTouches;

		var cb = function (e) {

			var alreadyInArray = false;
			for (var i = 0; i < touches.length; i++) {
				if (touches[i].pointerId === e.pointerId) {
					alreadyInArray = true;
					break;
				}
			}
			if (!alreadyInArray) {
				//console.log(e.type + ' ' + touches.length + ' id: ' + e.pointerId);
				touches.push(e);
			}

			e.touches = touches.slice();
			e.changedTouches = [e];

			handler(e);
		};

		obj[pre + 'touchstart' + id] = cb;
		obj.addEventListener('MSPointerDown', cb, this);

		//Need to also listen for end events to keep the _msTouches list accurate
		var internalCb = function (e) {
			for (var i = 0; i < touches.length; i++) {
				if (touches[i].pointerId === e.pointerId) {
					touches.splice(i, 1);
					break;
				}
			}
		};
		obj.addEventListener('MSPointerUp', internalCb, this);
		obj.addEventListener('MSPointerCancel', internalCb, this);
		obj[pre + 'touchstartend' + id] = cb;

		return this;
	},

	addMsTouchListenerMove: function (obj, type, handler, id) {
		var pre = '_leaflet_';

		var touches = this._msTouches;
		var cb = function (e) {

			//Don't fire touch moves when mouse isn't down
			if (e.pointerType === e.MSPOINTER_TYPE_MOUSE && e.buttons === 0) {
				return;
			}

			for (var i = 0; i < touches.length; i++) {
				if (touches[i].pointerId === e.pointerId) {
					touches[i] = e;
					break;
				}
			}

			e.touches = touches.slice();
			e.changedTouches = [e];

			handler(e);
		};

		obj[pre + 'touchmove' + id] = cb;
		obj.addEventListener('MSPointerMove', cb, this);

		return this;
	},

	addMsTouchListenerEnd: function (obj, type, handler, id) {
		var pre = '_leaflet_',
			touches = this._msTouches;

		var cb = function (e) {
			//console.log(e.type + ' ' + touches.length + ' id: ' + e.pointerId);
			var found = false;
			for (var i = 0; i < touches.length; i++) {
				if (touches[i].pointerId === e.pointerId) {
					touches.splice(i, 1);
					found = true;
					break;
				}
			}

			if (!found) { //Crappy work around for pointerIDs breaking when leaving screen edge https://github.com/CloudMade/Leaflet/issues/871#issuecomment-9125445
				touches.splice(0, touches.length);
			}

			e.touches = touches.slice();
			e.changedTouches = [e];

			handler(e);
		};

		obj[pre + 'touchend' + id] = cb;
		obj.addEventListener('MSPointerUp', cb, this);
		obj.addEventListener('MSPointerCancel', cb, this);

		return this;
	},

	removeMsTouchListener: function (obj, type, id) {
		var pre = '_leaflet_',
		    cb = obj[pre + type + id];

		switch (type) {
		case 'touchstart':
			obj.removeEventListener('MSPointerDown', cb, this);
			obj.removeEventListener('MSPointerUp', obj[pre + 'touchstartend' + id], this);
			obj.removeEventListener('MSPointerCancel', obj[pre + 'touchstartend' + id], this);
			break;
		case 'touchmove':
			obj.removeEventListener('MSPointerMove', cb, this);
			break;
		case 'touchend':
			obj.removeEventListener('MSPointerUp', cb, this);
			obj.removeEventListener('MSPointerCancel', cb, this);
			break;
		}

		return this;
	}
});
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qbs.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

var File = require("qbs.File");
var FileInfo = require("qbs.FileInfo");
var ModUtils = require("qbs.ModUtils");
var WindowsUtils = require("qbs.WindowsUtils");

function compilerVersionDefine(cpp) {
    var result = '_MSC_VER=' + cpp.compilerVersionMajor;
    var s = cpp.compilerVersionMinor.toString();
    while (s.length < 2)
        s = '0' + s;
    result += s;
    return result;
}

function prepareCompiler(project, product, inputs, outputs, input, output) {
    var i;
    var debugInformation = input.cpp.debugInformation;
    var args = ['/nologo', '/c']

    // Determine which C-language we're compiling
    var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(Object.keys(outputs)));
    if (!["c", "cpp"].contains(tag))
        throw ("unsupported source language");

    // Whether we're compiling a precompiled header or normal source file
    var pchOutput = outputs[tag + "_pch"] ? outputs[tag + "_pch"][0] : undefined;

    var enableExceptions = input.cpp.enableExceptions;
    if (enableExceptions) {
        var ehModel = input.cpp.exceptionHandlingModel;
        switch (ehModel) {
        case "default":
            args.push("/EHsc"); // "Yes" in VS
            break;
        case "seh":
            args.push("/EHa"); // "Yes with SEH exceptions" in VS
            break;
        case "externc":
            args.push("/EHs"); // "Yes with Extern C functions" in VS
            break;
        }
    }

    var enableRtti = input.cpp.enableRtti;
    if (enableRtti !== undefined) {
        args.push(enableRtti ? "/GR" : "/GR-");
    }

    switch (input.cpp.optimization) {
    case "small":
        args.push('/Os')
        break;
    case "fast":
        args.push('/O2')
        break;
    case "none":
        args.push("/Od");
        break;
    }

    if (debugInformation) {
        if (product.cpp.separateDebugInformation)
            args.push('/Zi');
        else
            args.push('/Z7');
    }

    var rtl = product.cpp.runtimeLibrary;
    if (rtl) {
        rtl = (rtl === "static" ? "/MT" : "/MD");
        if (product.qbs.enableDebugCode)
            rtl += "d";
        args.push(rtl);
    }

    // warnings:
    var warningLevel = input.cpp.warningLevel;
    if (warningLevel === 'none')
        args.push('/w')
    if (warningLevel === 'all')
        args.push('/Wall')
    if (input.cpp.treatWarningsAsErrors)
        args.push('/WX')
    var allIncludePaths = [];
    var includePaths = input.cpp.includePaths;
    if (includePaths)
        allIncludePaths = allIncludePaths.uniqueConcat(includePaths);
    var systemIncludePaths = input.cpp.systemIncludePaths;
    if (systemIncludePaths)
        allIncludePaths = allIncludePaths.uniqueConcat(systemIncludePaths);
    for (i in allIncludePaths)
        args.push('/I' + FileInfo.toWindowsSeparators(allIncludePaths[i]))
    var allDefines = [];
    var platformDefines = input.cpp.platformDefines;
    if (platformDefines)
        allDefines = allDefines.uniqueConcat(platformDefines);
    var defines = input.cpp.defines;
    if (defines)
        allDefines = allDefines.uniqueConcat(defines);
    for (i in allDefines)
        args.push('/D' + allDefines[i].replace(/%/g, "%%"));

    var minimumWindowsVersion = product.cpp.minimumWindowsVersion;
    if (minimumWindowsVersion) {
        var hexVersion = WindowsUtils.getWindowsVersionInFormat(minimumWindowsVersion, 'hex');
        if (hexVersion) {
            var versionDefs = [ 'WINVER', '_WIN32_WINNT', '_WIN32_WINDOWS' ];
            for (i in versionDefs) {
                args.push('/D' + versionDefs[i] + '=' + hexVersion);
            }
        }
    }

    var objOutput = outputs.obj ? outputs.obj[0] : undefined
    args.push('/Fo' + FileInfo.toWindowsSeparators(objOutput.filePath))
    args.push(FileInfo.toWindowsSeparators(input.filePath))

    var prefixHeaders = product.cpp.prefixHeaders;
    for (i in prefixHeaders)
        args.push("/FI" + FileInfo.toWindowsSeparators(prefixHeaders[i]));

    // Language
    if (tag === "cpp")
        args.push("/TP");
    else if (tag === "c")
        args.push("/TC");

    var commands = [];
    var usePch = ModUtils.moduleProperty(input, "usePrecompiledHeader", tag);
    if (usePch) {
        if (pchOutput) {
            // create PCH
            args.push("/Yc");
            args.push("/Fp" + FileInfo.toWindowsSeparators(pchOutput.filePath));
            args.push("/Fo" + FileInfo.toWindowsSeparators(objOutput.filePath));
            args.push(FileInfo.toWindowsSeparators(input.filePath));
            var copyCmd = new JavaScriptCommand();
            copyCmd.tag = tag;
            copyCmd.silent = true;
            copyCmd.sourceCode = function() {
                File.copy(input.filePath, outputs[tag + "_pch_copy"][0].filePath);
            };
            commands.push(copyCmd);
        } else {
            // use PCH
            var pchHeaderFilePath = ".obj/" + product.name + '_' + tag + '.pch_copy';
            var pchFilePath = FileInfo.toWindowsSeparators(product.buildDirectory
                + "\\.obj\\" + product.name + "_" + tag + ".pch");
            args.push("/FI" + pchHeaderFilePath);
            args.push("/Yu" + pchHeaderFilePath);
            args.push("/Fp" + pchFilePath);
        }
    }

    args = args.concat(ModUtils.moduleProperty(input, 'platformFlags'),
                       ModUtils.moduleProperty(input, 'flags'),
                       ModUtils.moduleProperty(input, 'platformFlags', tag),
                       ModUtils.moduleProperty(input, 'flags', tag));

    var compilerPath = product.cpp.compilerPath;
    var wrapperArgs = product.cpp.compilerWrapper;
    if (wrapperArgs && wrapperArgs.length > 0) {
        args.unshift(compilerPath);
        compilerPath = wrapperArgs.shift();
        args = wrapperArgs.concat(args);
    }
    var cmd = new Command(compilerPath, args)
    cmd.description = (pchOutput ? 'pre' : '') + 'compiling ' + input.fileName;
    if (pchOutput)
        cmd.description += ' (' + tag + ')';
    cmd.highlight = "compiler";
    cmd.workingDirectory = product.buildDirectory + "/.obj";
    cmd.responseFileUsagePrefix = '@';
    // cl.exe outputs the cpp file name. We filter that out.
    cmd.inputFileName = input.fileName;
    cmd.stdoutFilterFunction = function(output) {
        return output.split(inputFileName + "\r\n").join("");
    };
    commands.push(cmd);
    return commands;
}

function collectLibraryDependencies(product) {
    var seen = {};
    var result = [];

    function addFilePath(filePath) {
        result.push(filePath);
    }

    function addArtifactFilePaths(dep, artifacts) {
        if (!artifacts)
            return;
        var artifactFilePaths = artifacts.map(function(a) { return a.filePath; });
        artifactFilePaths.forEach(addFilePath);
    }

    function addExternalLibs(obj) {
        var externalLibs = [].concat(
                    ModUtils.sanitizedModuleProperty(obj, "cpp", "staticLibraries"),
                    ModUtils.sanitizedModuleProperty(obj, "cpp", "dynamicLibraries"));
        externalLibs.forEach(function (libName) {
            if (!libName.match(/\.lib$/i))
                libName += ".lib";
            addFilePath(libName);
        });
    }

    function traverse(dep) {
        if (seen.hasOwnProperty(dep.name))
            return;
        seen[dep.name] = true;
        var staticLibraryArtifacts = dep.artifacts["staticlibrary"];
        var dynamicLibraryArtifacts = staticLibraryArtifacts
                ? null : dep.artifacts["dynamiclibrary_import"];
        if (staticLibraryArtifacts) {
            dep.dependencies.forEach(traverse);
            addArtifactFilePaths(dep, staticLibraryArtifacts);
            addExternalLibs(dep);
        } else if (dynamicLibraryArtifacts) {
            addArtifactFilePaths(dep, dynamicLibraryArtifacts);
        }
    }

    product.dependencies.forEach(traverse);
    addExternalLibs(product);
    return result;
}

function prepareLinker(project, product, inputs, outputs, input, output) {
    var i;
    var linkDLL = (outputs.dynamiclibrary ? true : false)
    var primaryOutput = (linkDLL ? outputs.dynamiclibrary[0] : outputs.application[0])
    var debugInformation = product.cpp.debugInformation;
    var generateManifestFiles = !linkDLL && product.cpp.generateManifestFile;

    var args = ['/nologo']
    if (linkDLL) {
        args.push('/DLL');
        args.push('/IMPLIB:' + FileInfo.toWindowsSeparators(outputs.dynamiclibrary_import[0].filePath));
    }

    if (debugInformation) {
        args.push("/DEBUG");
        var debugInfo = outputs.debuginfo_app || outputs.debuginfo_dll;
        if (debugInfo)
            args.push("/PDB:" + debugInfo[0].fileName);
    } else {
        args.push('/INCREMENTAL:NO')
    }

    switch (product.qbs.architecture) {
    case "x86":
        args.push("/MACHINE:X86");
        break;
    case "x86_64":
        args.push("/MACHINE:X64");
        break;
    case "ia64":
        args.push("/MACHINE:IA64");
        break;
    case "armv7":
        args.push("/MACHINE:ARM");
        break;
    }

    var minimumWindowsVersion = product.cpp.minimumWindowsVersion;
    var subsystemSwitch = undefined;
    if (minimumWindowsVersion || product.consoleApplication !== undefined) {
        // Ensure that we default to console if product.consoleApplication is undefined
        // since that could still be the case if only minimumWindowsVersion had been defined
        subsystemSwitch = product.consoleApplication === false ? '/SUBSYSTEM:WINDOWS' : '/SUBSYSTEM:CONSOLE';
    }

    if (minimumWindowsVersion) {
        var subsystemVersion = WindowsUtils.getWindowsVersionInFormat(minimumWindowsVersion,
                                                                      'subsystem');
        if (subsystemVersion) {
            subsystemSwitch += ',' + subsystemVersion;
            args.push('/OSVERSION:' + subsystemVersion);
        }
    }

    if (subsystemSwitch)
        args.push(subsystemSwitch);

    var linkerOutputNativeFilePath;
    var manifestFileName;
    if (generateManifestFiles) {
        linkerOutputNativeFilePath
                = FileInfo.toWindowsSeparators(
                    FileInfo.path(primaryOutput.filePath) + "/intermediate."
                        + primaryOutput.fileName);
        manifestFileName = linkerOutputNativeFilePath + ".manifest";
        args.push('/MANIFEST', '/MANIFESTFILE:' + manifestFileName)
    } else {
        linkerOutputNativeFilePath = FileInfo.toWindowsSeparators(primaryOutput.filePath);
    }

    var allInputs = inputs.obj || [];
    for (i in allInputs) {
        var fileName = FileInfo.toWindowsSeparators(allInputs[i].filePath)
        args.push(fileName)
    }

    function toWindowsSeparator(filePath) { return FileInfo.toWindowsSeparators(filePath); }
    args = args.concat(collectLibraryDependencies(product).map(toWindowsSeparator));

    if (product.cpp.entryPoint)
        args.push("/ENTRY:" + product.cpp.entryPoint);

    args.push('/OUT:' + linkerOutputNativeFilePath)
    var libraryPaths = product.cpp.libraryPaths;
    if (libraryPaths)
        libraryPaths = [].uniqueConcat(libraryPaths);
    for (i in libraryPaths) {
        args.push('/LIBPATH:' + FileInfo.toWindowsSeparators(libraryPaths[i]))
    }
    var linkerFlags = product.cpp.platformLinkerFlags.concat(product.cpp.linkerFlags);
    args = args.concat(linkerFlags);
    if (product.cpp.allowUnresolvedSymbols)
        args.push("/FORCE:UNRESOLVED");

    var linkerPath = product.cpp.linkerPath;
    var wrapperArgs = product.cpp.linkerWrapper;
    if (wrapperArgs && wrapperArgs.length > 0) {
        args.unshift(linkerPath);
        linkerPath = wrapperArgs.shift();
        args = wrapperArgs.concat(args);
    }
    var commands = [];
    var cmd = new Command(linkerPath, args)
    cmd.description = 'linking ' + primaryOutput.fileName;
    cmd.highlight = 'linker';
    cmd.workingDirectory = FileInfo.path(primaryOutput.filePath)
    cmd.responseFileUsagePrefix = '@';
    cmd.stdoutFilterFunction = function(output) {
        return output.replace(/^ +Creating library.*\r\n$/, "");
    };
    commands.push(cmd);

    if (generateManifestFiles) {
        var outputNativeFilePath = FileInfo.toWindowsSeparators(primaryOutput.filePath);
        cmd = new JavaScriptCommand();
        cmd.src = linkerOutputNativeFilePath;
        cmd.dst = outputNativeFilePath;
        cmd.sourceCode = function() {
            File.copy(src, dst);
        }
        cmd.silent = true
        commands.push(cmd);
        args = [
            '/nologo', '/manifest', manifestFileName,
            "/outputresource:" + outputNativeFilePath + ";#" + (linkDLL ? "2" : "1")
        ]
        cmd = new Command("mt.exe", args)
        cmd.description = 'embedding manifest into ' + primaryOutput.fileName;
        cmd.highlight = 'linker';
        cmd.workingDirectory = FileInfo.path(primaryOutput.filePath)
        commands.push(cmd);
    }

    return commands;
}

<commit_msg>MSVC: let the linker embed manifests<commit_after>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qbs.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

var File = require("qbs.File");
var FileInfo = require("qbs.FileInfo");
var ModUtils = require("qbs.ModUtils");
var WindowsUtils = require("qbs.WindowsUtils");

function compilerVersionDefine(cpp) {
    var result = '_MSC_VER=' + cpp.compilerVersionMajor;
    var s = cpp.compilerVersionMinor.toString();
    while (s.length < 2)
        s = '0' + s;
    result += s;
    return result;
}

function prepareCompiler(project, product, inputs, outputs, input, output) {
    var i;
    var debugInformation = input.cpp.debugInformation;
    var args = ['/nologo', '/c']

    // Determine which C-language we're compiling
    var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(Object.keys(outputs)));
    if (!["c", "cpp"].contains(tag))
        throw ("unsupported source language");

    // Whether we're compiling a precompiled header or normal source file
    var pchOutput = outputs[tag + "_pch"] ? outputs[tag + "_pch"][0] : undefined;

    var enableExceptions = input.cpp.enableExceptions;
    if (enableExceptions) {
        var ehModel = input.cpp.exceptionHandlingModel;
        switch (ehModel) {
        case "default":
            args.push("/EHsc"); // "Yes" in VS
            break;
        case "seh":
            args.push("/EHa"); // "Yes with SEH exceptions" in VS
            break;
        case "externc":
            args.push("/EHs"); // "Yes with Extern C functions" in VS
            break;
        }
    }

    var enableRtti = input.cpp.enableRtti;
    if (enableRtti !== undefined) {
        args.push(enableRtti ? "/GR" : "/GR-");
    }

    switch (input.cpp.optimization) {
    case "small":
        args.push('/Os')
        break;
    case "fast":
        args.push('/O2')
        break;
    case "none":
        args.push("/Od");
        break;
    }

    if (debugInformation) {
        if (product.cpp.separateDebugInformation)
            args.push('/Zi');
        else
            args.push('/Z7');
    }

    var rtl = product.cpp.runtimeLibrary;
    if (rtl) {
        rtl = (rtl === "static" ? "/MT" : "/MD");
        if (product.qbs.enableDebugCode)
            rtl += "d";
        args.push(rtl);
    }

    // warnings:
    var warningLevel = input.cpp.warningLevel;
    if (warningLevel === 'none')
        args.push('/w')
    if (warningLevel === 'all')
        args.push('/Wall')
    if (input.cpp.treatWarningsAsErrors)
        args.push('/WX')
    var allIncludePaths = [];
    var includePaths = input.cpp.includePaths;
    if (includePaths)
        allIncludePaths = allIncludePaths.uniqueConcat(includePaths);
    var systemIncludePaths = input.cpp.systemIncludePaths;
    if (systemIncludePaths)
        allIncludePaths = allIncludePaths.uniqueConcat(systemIncludePaths);
    for (i in allIncludePaths)
        args.push('/I' + FileInfo.toWindowsSeparators(allIncludePaths[i]))
    var allDefines = [];
    var platformDefines = input.cpp.platformDefines;
    if (platformDefines)
        allDefines = allDefines.uniqueConcat(platformDefines);
    var defines = input.cpp.defines;
    if (defines)
        allDefines = allDefines.uniqueConcat(defines);
    for (i in allDefines)
        args.push('/D' + allDefines[i].replace(/%/g, "%%"));

    var minimumWindowsVersion = product.cpp.minimumWindowsVersion;
    if (minimumWindowsVersion) {
        var hexVersion = WindowsUtils.getWindowsVersionInFormat(minimumWindowsVersion, 'hex');
        if (hexVersion) {
            var versionDefs = [ 'WINVER', '_WIN32_WINNT', '_WIN32_WINDOWS' ];
            for (i in versionDefs) {
                args.push('/D' + versionDefs[i] + '=' + hexVersion);
            }
        }
    }

    var objOutput = outputs.obj ? outputs.obj[0] : undefined
    args.push('/Fo' + FileInfo.toWindowsSeparators(objOutput.filePath))
    args.push(FileInfo.toWindowsSeparators(input.filePath))

    var prefixHeaders = product.cpp.prefixHeaders;
    for (i in prefixHeaders)
        args.push("/FI" + FileInfo.toWindowsSeparators(prefixHeaders[i]));

    // Language
    if (tag === "cpp")
        args.push("/TP");
    else if (tag === "c")
        args.push("/TC");

    var commands = [];
    var usePch = ModUtils.moduleProperty(input, "usePrecompiledHeader", tag);
    if (usePch) {
        if (pchOutput) {
            // create PCH
            args.push("/Yc");
            args.push("/Fp" + FileInfo.toWindowsSeparators(pchOutput.filePath));
            args.push("/Fo" + FileInfo.toWindowsSeparators(objOutput.filePath));
            args.push(FileInfo.toWindowsSeparators(input.filePath));
            var copyCmd = new JavaScriptCommand();
            copyCmd.tag = tag;
            copyCmd.silent = true;
            copyCmd.sourceCode = function() {
                File.copy(input.filePath, outputs[tag + "_pch_copy"][0].filePath);
            };
            commands.push(copyCmd);
        } else {
            // use PCH
            var pchHeaderFilePath = ".obj/" + product.name + '_' + tag + '.pch_copy';
            var pchFilePath = FileInfo.toWindowsSeparators(product.buildDirectory
                + "\\.obj\\" + product.name + "_" + tag + ".pch");
            args.push("/FI" + pchHeaderFilePath);
            args.push("/Yu" + pchHeaderFilePath);
            args.push("/Fp" + pchFilePath);
        }
    }

    args = args.concat(ModUtils.moduleProperty(input, 'platformFlags'),
                       ModUtils.moduleProperty(input, 'flags'),
                       ModUtils.moduleProperty(input, 'platformFlags', tag),
                       ModUtils.moduleProperty(input, 'flags', tag));

    var compilerPath = product.cpp.compilerPath;
    var wrapperArgs = product.cpp.compilerWrapper;
    if (wrapperArgs && wrapperArgs.length > 0) {
        args.unshift(compilerPath);
        compilerPath = wrapperArgs.shift();
        args = wrapperArgs.concat(args);
    }
    var cmd = new Command(compilerPath, args)
    cmd.description = (pchOutput ? 'pre' : '') + 'compiling ' + input.fileName;
    if (pchOutput)
        cmd.description += ' (' + tag + ')';
    cmd.highlight = "compiler";
    cmd.workingDirectory = product.buildDirectory + "/.obj";
    cmd.responseFileUsagePrefix = '@';
    // cl.exe outputs the cpp file name. We filter that out.
    cmd.inputFileName = input.fileName;
    cmd.stdoutFilterFunction = function(output) {
        return output.split(inputFileName + "\r\n").join("");
    };
    commands.push(cmd);
    return commands;
}

function collectLibraryDependencies(product) {
    var seen = {};
    var result = [];

    function addFilePath(filePath) {
        result.push(filePath);
    }

    function addArtifactFilePaths(dep, artifacts) {
        if (!artifacts)
            return;
        var artifactFilePaths = artifacts.map(function(a) { return a.filePath; });
        artifactFilePaths.forEach(addFilePath);
    }

    function addExternalLibs(obj) {
        var externalLibs = [].concat(
                    ModUtils.sanitizedModuleProperty(obj, "cpp", "staticLibraries"),
                    ModUtils.sanitizedModuleProperty(obj, "cpp", "dynamicLibraries"));
        externalLibs.forEach(function (libName) {
            if (!libName.match(/\.lib$/i))
                libName += ".lib";
            addFilePath(libName);
        });
    }

    function traverse(dep) {
        if (seen.hasOwnProperty(dep.name))
            return;
        seen[dep.name] = true;
        var staticLibraryArtifacts = dep.artifacts["staticlibrary"];
        var dynamicLibraryArtifacts = staticLibraryArtifacts
                ? null : dep.artifacts["dynamiclibrary_import"];
        if (staticLibraryArtifacts) {
            dep.dependencies.forEach(traverse);
            addArtifactFilePaths(dep, staticLibraryArtifacts);
            addExternalLibs(dep);
        } else if (dynamicLibraryArtifacts) {
            addArtifactFilePaths(dep, dynamicLibraryArtifacts);
        }
    }

    product.dependencies.forEach(traverse);
    addExternalLibs(product);
    return result;
}

function prepareLinker(project, product, inputs, outputs, input, output) {
    var i;
    var linkDLL = (outputs.dynamiclibrary ? true : false)
    var primaryOutput = (linkDLL ? outputs.dynamiclibrary[0] : outputs.application[0])
    var debugInformation = product.cpp.debugInformation;
    var generateManifestFiles = !linkDLL && product.cpp.generateManifestFile;
    var canEmbedManifest = (product.cpp.compilerVersionMajor >= 17);    // VS 2012

    var args = ['/nologo']
    if (linkDLL) {
        args.push('/DLL');
        args.push('/IMPLIB:' + FileInfo.toWindowsSeparators(outputs.dynamiclibrary_import[0].filePath));
    }

    if (debugInformation) {
        args.push("/DEBUG");
        var debugInfo = outputs.debuginfo_app || outputs.debuginfo_dll;
        if (debugInfo)
            args.push("/PDB:" + debugInfo[0].fileName);
    } else {
        args.push('/INCREMENTAL:NO')
    }

    switch (product.qbs.architecture) {
    case "x86":
        args.push("/MACHINE:X86");
        break;
    case "x86_64":
        args.push("/MACHINE:X64");
        break;
    case "ia64":
        args.push("/MACHINE:IA64");
        break;
    case "armv7":
        args.push("/MACHINE:ARM");
        break;
    }

    var minimumWindowsVersion = product.cpp.minimumWindowsVersion;
    var subsystemSwitch = undefined;
    if (minimumWindowsVersion || product.consoleApplication !== undefined) {
        // Ensure that we default to console if product.consoleApplication is undefined
        // since that could still be the case if only minimumWindowsVersion had been defined
        subsystemSwitch = product.consoleApplication === false ? '/SUBSYSTEM:WINDOWS' : '/SUBSYSTEM:CONSOLE';
    }

    if (minimumWindowsVersion) {
        var subsystemVersion = WindowsUtils.getWindowsVersionInFormat(minimumWindowsVersion,
                                                                      'subsystem');
        if (subsystemVersion) {
            subsystemSwitch += ',' + subsystemVersion;
            args.push('/OSVERSION:' + subsystemVersion);
        }
    }

    if (subsystemSwitch)
        args.push(subsystemSwitch);

    var linkerOutputNativeFilePath = FileInfo.toWindowsSeparators(primaryOutput.filePath);
    var manifestFileName;
    if (generateManifestFiles) {
        if (canEmbedManifest) {
            args.push("/MANIFEST:embed");
        } else {
            linkerOutputNativeFilePath
                    = FileInfo.toWindowsSeparators(
                        FileInfo.path(primaryOutput.filePath) + "/intermediate."
                            + primaryOutput.fileName);
            manifestFileName = linkerOutputNativeFilePath + ".manifest";
            args.push('/MANIFEST', '/MANIFESTFILE:' + manifestFileName)
        }
    }

    var allInputs = inputs.obj || [];
    for (i in allInputs) {
        var fileName = FileInfo.toWindowsSeparators(allInputs[i].filePath)
        args.push(fileName)
    }

    function toWindowsSeparator(filePath) { return FileInfo.toWindowsSeparators(filePath); }
    args = args.concat(collectLibraryDependencies(product).map(toWindowsSeparator));

    if (product.cpp.entryPoint)
        args.push("/ENTRY:" + product.cpp.entryPoint);

    args.push('/OUT:' + linkerOutputNativeFilePath)
    var libraryPaths = product.cpp.libraryPaths;
    if (libraryPaths)
        libraryPaths = [].uniqueConcat(libraryPaths);
    for (i in libraryPaths) {
        args.push('/LIBPATH:' + FileInfo.toWindowsSeparators(libraryPaths[i]))
    }
    var linkerFlags = product.cpp.platformLinkerFlags.concat(product.cpp.linkerFlags);
    args = args.concat(linkerFlags);
    if (product.cpp.allowUnresolvedSymbols)
        args.push("/FORCE:UNRESOLVED");

    var linkerPath = product.cpp.linkerPath;
    var wrapperArgs = product.cpp.linkerWrapper;
    if (wrapperArgs && wrapperArgs.length > 0) {
        args.unshift(linkerPath);
        linkerPath = wrapperArgs.shift();
        args = wrapperArgs.concat(args);
    }
    var commands = [];
    var cmd = new Command(linkerPath, args)
    cmd.description = 'linking ' + primaryOutput.fileName;
    cmd.highlight = 'linker';
    cmd.workingDirectory = FileInfo.path(primaryOutput.filePath)
    cmd.responseFileUsagePrefix = '@';
    cmd.stdoutFilterFunction = function(output) {
        return output.replace(/^ +Creating library.*\r\n$/, "");
    };
    commands.push(cmd);

    if (generateManifestFiles && !canEmbedManifest) {
        var outputNativeFilePath = FileInfo.toWindowsSeparators(primaryOutput.filePath);
        cmd = new JavaScriptCommand();
        cmd.src = linkerOutputNativeFilePath;
        cmd.dst = outputNativeFilePath;
        cmd.sourceCode = function() {
            File.copy(src, dst);
        }
        cmd.silent = true
        commands.push(cmd);
        args = [
            '/nologo', '/manifest', manifestFileName,
            "/outputresource:" + outputNativeFilePath + ";#" + (linkDLL ? "2" : "1")
        ]
        cmd = new Command("mt.exe", args)
        cmd.description = 'embedding manifest into ' + primaryOutput.fileName;
        cmd.highlight = 'linker';
        cmd.workingDirectory = FileInfo.path(primaryOutput.filePath)
        commands.push(cmd);
    }

    return commands;
}

<|endoftext|>


<commit_before>var INVALID_ESCAPES = /[^\\]\\[^.*+?^${}()|[\]\\bBcdDfnrsStvwWxu0-9]/;
var validators = require('./'),
	formats = {
		'date-time': /^\d{4}-(0[0-9]{1}|1[0-2]{1})-[0-9]{2}[t ]\d{2}:\d{2}:\d{2}(\.\d+)?([zZ]|[+-]\d{2}:\d{2})$/i,
		'date': /^\d{4}-(0[0-9]{1}|1[0-2]{1})-[0-9]{2}$/,
		'time': /^\d{2}:\d{2}:\d{2}$/,
		'color': /^(#[0-9a-f]{3}|#[0-9a-f]{6}|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow)$/i,
		'style': /^(?:\s*-?[_A-Z]+[_A-Z0-9-]*:[^\n\r\f;]+;)*\s*-?[_A-Z]+[_A-Z0-9-]*:[^\n\r\f;]+;?\s*$/i,
		'phone': /^(?:(?:\(?(?:00|\+)(?:[1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?(?:(?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(?:\d+))?$/i,
		'uri': /^(?:([a-z0-9+.-]+:\/\/)((?:(?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(:(?:\d*))?(\/(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?|([a-z0-9+.-]+:)(\/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?)(\?(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?(#(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?$/i,
		'email': /^[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,}$/i,
		'ipv4': /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/,
		'ipv6': /^\s*((([0-9A-F]{1,4}:){7}([0-9A-F]{1,4}|:))|(([0-9A-F]{1,4}:){6}(:[0-9A-F]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-F]{1,4}:){5}(((:[0-9A-F]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-F]{1,4}:){4}(((:[0-9A-F]{1,4}){1,3})|((:[0-9A-F]{1,4})((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-F]{1,4}:){3}(((:[0-9A-F]{1,4}){1,4})|((:[0-9A-F]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-F]{1,4}:){2}(((:[0-9A-F]{1,4}){1,5})|((:[0-9A-F]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-F]{1,4}:){1}(((:[0-9A-F]{1,4}){1,6})|((:[0-9A-F]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-F]{1,4}){1,7})|((:[0-9A-F]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/i,

		// hostname regex from: http://stackoverflow.com/a/1420225/5628
		'hostname': /^(?=.{1,255}$)[0-9A-Z](?:(?:[0-9A-Z]|-){0,61}[0-9A-Z])?(?:\.[0-9A-Z](?:(?:[0-9A-Z]|-){0,61}[0-9A-Z])?)*\.?$/i,

		'utc-millisec': function(subject) {
			var parsed = parseInt(subject, 10);
			return !isNaN(parsed) && parsed.toString() === subject.toString();
		},
		'regex': function (subject) {
			if(INVALID_ESCAPES.test(subject)) return false;
			try {
				new RegExp(subject);
				return true;
			}
			catch(e) {
				return false;
			}
		}
	};

// aliases
formats['host-name'] = formats.hostname;
formats['ip-address'] = formats.ipv4;

function getType(subject) {
	var type = typeof subject;

	if(type === 'object') {
		if(subject === null) return 'null';
		if(Array.isArray(subject)) return 'array';
	}

	if(type === 'number' && subject === Math.round(subject)) return 'integer';

	return type;
}

function format(context, subject, schema) {
	var fmt = schema.format,
		validator = formats[fmt];

	if(!validator)
		throw new Error('Invalid schema: unknown format (' + fmt + ')');

	var valid = validator.test ? validator.test(subject) : validator(subject);
	if(!valid) {
		context.addError('Failed "format" criteria (' + fmt + ')', subject, schema);
	}

	return valid;
}

function validateTypes(context, subject, type, validTypes) {
	var i = validTypes.length,
		validType, valid;
	while(i--) {
		validType = validTypes[i];

		if(validType === 'any') return true;

		if(typeof validType === 'object') {
			valid = context.silently(function() {
				return validateBase(context, subject, validType);
			}); // jshint ignore:line
			if(valid) return true;
			else continue;
		}

		if(!(validType in validators.types))
			throw new Error('Invalid schema: invalid type (' + validType + ')');

		if(validType === 'number' && type === 'integer') return true;

		if(type === validType) return true;
	}

	return false;
}

function allOf(context, subject, schema) {
	var schemas = schema.allOf;

	if(!Array.isArray(schemas))
		throw new Error('Invalid schema: "allOf" value must be an array');

	var i = schemas.length,
		invalidCount = 0;
	while(i--) {
		if(!validateBase(context, subject, schemas[i])) {
			invalidCount += 1;
		}
	}

	if(invalidCount === 0) return true;

	context.addError('Failed "allOf" criteria', subject, schemas);
	return false;
}

function anyOf(context, subject, schema) {
	var schemas = schema.anyOf;

	if(!Array.isArray(schemas))
		throw new Error('Invalid schema: "anyOf" value must be an array');

	var matched = context.silently(function() {
		var i = schemas.length;
		while(i--) {
			if(validateBase(context, subject, schemas[i])) return true;
		}
		return false;
	});

	if(matched) return true;

	context.addError('Failed "anyOf" criteria', subject, schemas);
	return false;
}

function oneOf(context, subject, schema) {
	var schemas = schema.oneOf;

	if(!Array.isArray(schemas))
		throw new Error('Invalid schema: "oneOf" value must be an array');

	var i = schemas.length,
		validCount = 0;
	context.silently(function() {
		while(i--) {
			if(validateBase(context, subject, schemas[i])) validCount += 1;
		}
	});

	if(validCount === 1) return true;

	context.addError('Failed "oneOf" criteria', subject, schemas);
	return false;
}

function not(context, subject, schema) {
	var badSchema = schema.not,
		valid = context.silently(function() {
			return !validateBase(context, subject, badSchema);
		});

	if(valid) return true;

	context.addError('Failed "not" criteria', subject, schema);
	return false;
}

function disallow(context, subject, schema, type) {
	var invalidTypes = Array.isArray(schema.disallow) ? schema.disallow : [ schema.disallow ],
		valid = !validateTypes(context, subject, type, invalidTypes);

	if(!valid) {
		context.addError('Failed "disallow" criteria: expecting ' + invalidTypes.join(' or ') + ', found ' + type, subject, schema);
	}

	return valid;
}

function validateExtends(context, subject, schema) {
	var schemas = Array.isArray(schema["extends"]) ? schema["extends"] : [ schema["extends"] ];

	var i = schemas.length,
		invalidCount = 0;
	while(i--) {
		if(!validateBase(context, subject, schemas[i])) {
			invalidCount += 1;
		}
	}

	return invalidCount === 0;
}

function validateEnum(context, subject, schema) {
	var values = schema['enum'];

	if(!Array.isArray(values))
		throw new Error('Invalid schema: "enum" value must be an array');

	var i = values.length;
	while(i--) {
		if(validators.deepEqual(subject, values[i])) return true;
	}

	context.addError('Failed "enum" criteria', subject, values);
	return false;
}

function validateType(context, subject, schema, type) {
	var validTypes = Array.isArray(schema.type) ? schema.type : [ schema.type ],
		valid = validateTypes(context, subject, type, validTypes);

	if(!valid) {
		context.addError('Failed "type" criteria: expecting ' + validTypes.join(' or ') + ', found ' + type, subject, schema);
	}

	return valid;
}

function typeValidations(context, subject, schema, type) {
	return validators.types[type](context, subject, schema);
}

function pathFromIds(ids) {
	return ids.map(function(id) {
		var lastSlash = id.lastIndexOf("/");
		if(lastSlash === -1) return id;
		return id.substr(0, lastSlash + 1);
	}).join('');
}

function $ref(context, subject, schema) {
	var absolute = /^(#|\/)/.test(schema.$ref),
		ref = absolute ? schema.$ref : pathFromIds(context.id) + schema.$ref,
		refSchema = context.refs.get(ref, context.schema),
		ctx = context;

	if(schema.$ref[0] !== '#') {
		ctx = context.subcontext(context.refs.get(ref, context.schema, true));
	}

	var valid = validateBase(ctx, subject, refSchema);

	context.cleanSubject = ctx.cleanSubject;

	return valid;
}

function validateBase(context, subject, schema) {
	if(schema.$ref) {
		return $ref(context, subject, schema);
	}

	if(schema.id) context.id.push(schema.id);

	var valid = context.runValidations([
		[ 'type' in schema, validateType ],
		[ 'disallow' in schema, disallow ],
		[ 'enum' in schema, validateEnum ],
		[ true, typeValidations ],
		[ 'format' in schema, format ],
		[ 'extends' in schema, validateExtends ],
		[ 'allOf' in schema, allOf ],
		[ 'anyOf' in schema, anyOf ],
		[ 'oneOf' in schema, oneOf ],
		[ 'not' in schema, not ]
	], subject, schema, getType(subject));

	if(schema.id) context.id.pop();

	return valid;
}

module.exports = validateBase;
<commit_msg>Resolved potential ReDoS issue with uri format regexp.<commit_after>var INVALID_ESCAPES = /[^\\]\\[^.*+?^${}()|[\]\\bBcdDfnrsStvwWxu0-9]/;
var validators = require('./'),
	formats = {
		'date-time': /^\d{4}-(0[0-9]{1}|1[0-2]{1})-[0-9]{2}[t ]\d{2}:\d{2}:\d{2}(\.\d+)?([zZ]|[+-]\d{2}:\d{2})$/i,
		'date': /^\d{4}-(0[0-9]{1}|1[0-2]{1})-[0-9]{2}$/,
		'time': /^\d{2}:\d{2}:\d{2}$/,
		'color': /^(#[0-9a-f]{3}|#[0-9a-f]{6}|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow)$/i,
		'style': /^(?:\s*-?[_A-Z]+[_A-Z0-9-]*:[^\n\r\f;]+;)*\s*-?[_A-Z]+[_A-Z0-9-]*:[^\n\r\f;]+;?\s*$/i,
		'phone': /^(?:(?:\(?(?:00|\+)(?:[1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?(?:(?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(?:\d+))?$/i,
		'uri': /^(?:([a-z0-9+.-]+:\/\/)((?:(?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(:(?:\d*))?(\/(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?|([a-z0-9+.-]+:)(\/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?)(\?(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?(#(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?$/i,
		'email': /^[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,}$/i,
		'ipv4': /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/,
		'ipv6': /^\s*((([0-9A-F]{1,4}:){7}([0-9A-F]{1,4}|:))|(([0-9A-F]{1,4}:){6}(:[0-9A-F]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-F]{1,4}:){5}(((:[0-9A-F]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-F]{1,4}:){4}(((:[0-9A-F]{1,4}){1,3})|((:[0-9A-F]{1,4})((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-F]{1,4}:){3}(((:[0-9A-F]{1,4}){1,4})|((:[0-9A-F]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-F]{1,4}:){2}(((:[0-9A-F]{1,4}){1,5})|((:[0-9A-F]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-F]{1,4}:){1}(((:[0-9A-F]{1,4}){1,6})|((:[0-9A-F]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-F]{1,4}){1,7})|((:[0-9A-F]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/i,

		// hostname regex from: http://stackoverflow.com/a/1420225/5628
		'hostname': /^(?=.{1,255}$)[0-9A-Z](?:(?:[0-9A-Z]|-){0,61}[0-9A-Z])?(?:\.[0-9A-Z](?:(?:[0-9A-Z]|-){0,61}[0-9A-Z])?)*\.?$/i,

		'utc-millisec': function(subject) {
			var parsed = parseInt(subject, 10);
			return !isNaN(parsed) && parsed.toString() === subject.toString();
		},
		'regex': function (subject) {
			if(INVALID_ESCAPES.test(subject)) return false;
			try {
				new RegExp(subject);
				return true;
			}
			catch(e) {
				return false;
			}
		}
	};

// aliases
formats['host-name'] = formats.hostname;
formats['ip-address'] = formats.ipv4;

function getType(subject) {
	var type = typeof subject;

	if(type === 'object') {
		if(subject === null) return 'null';
		if(Array.isArray(subject)) return 'array';
	}

	if(type === 'number' && subject === Math.round(subject)) return 'integer';

	return type;
}

function format(context, subject, schema) {
	var fmt = schema.format,
		validator = formats[fmt];

	if(!validator)
		throw new Error('Invalid schema: unknown format (' + fmt + ')');

	var valid = validator.test ? validator.test(subject) : validator(subject);
	if(!valid) {
		context.addError('Failed "format" criteria (' + fmt + ')', subject, schema);
	}

	return valid;
}

function validateTypes(context, subject, type, validTypes) {
	var i = validTypes.length,
		validType, valid;
	while(i--) {
		validType = validTypes[i];

		if(validType === 'any') return true;

		if(typeof validType === 'object') {
			valid = context.silently(function() {
				return validateBase(context, subject, validType);
			}); // jshint ignore:line
			if(valid) return true;
			else continue;
		}

		if(!(validType in validators.types))
			throw new Error('Invalid schema: invalid type (' + validType + ')');

		if(validType === 'number' && type === 'integer') return true;

		if(type === validType) return true;
	}

	return false;
}

function allOf(context, subject, schema) {
	var schemas = schema.allOf;

	if(!Array.isArray(schemas))
		throw new Error('Invalid schema: "allOf" value must be an array');

	var i = schemas.length,
		invalidCount = 0;
	while(i--) {
		if(!validateBase(context, subject, schemas[i])) {
			invalidCount += 1;
		}
	}

	if(invalidCount === 0) return true;

	context.addError('Failed "allOf" criteria', subject, schemas);
	return false;
}

function anyOf(context, subject, schema) {
	var schemas = schema.anyOf;

	if(!Array.isArray(schemas))
		throw new Error('Invalid schema: "anyOf" value must be an array');

	var matched = context.silently(function() {
		var i = schemas.length;
		while(i--) {
			if(validateBase(context, subject, schemas[i])) return true;
		}
		return false;
	});

	if(matched) return true;

	context.addError('Failed "anyOf" criteria', subject, schemas);
	return false;
}

function oneOf(context, subject, schema) {
	var schemas = schema.oneOf;

	if(!Array.isArray(schemas))
		throw new Error('Invalid schema: "oneOf" value must be an array');

	var i = schemas.length,
		validCount = 0;
	context.silently(function() {
		while(i--) {
			if(validateBase(context, subject, schemas[i])) validCount += 1;
		}
	});

	if(validCount === 1) return true;

	context.addError('Failed "oneOf" criteria', subject, schemas);
	return false;
}

function not(context, subject, schema) {
	var badSchema = schema.not,
		valid = context.silently(function() {
			return !validateBase(context, subject, badSchema);
		});

	if(valid) return true;

	context.addError('Failed "not" criteria', subject, schema);
	return false;
}

function disallow(context, subject, schema, type) {
	var invalidTypes = Array.isArray(schema.disallow) ? schema.disallow : [ schema.disallow ],
		valid = !validateTypes(context, subject, type, invalidTypes);

	if(!valid) {
		context.addError('Failed "disallow" criteria: expecting ' + invalidTypes.join(' or ') + ', found ' + type, subject, schema);
	}

	return valid;
}

function validateExtends(context, subject, schema) {
	var schemas = Array.isArray(schema["extends"]) ? schema["extends"] : [ schema["extends"] ];

	var i = schemas.length,
		invalidCount = 0;
	while(i--) {
		if(!validateBase(context, subject, schemas[i])) {
			invalidCount += 1;
		}
	}

	return invalidCount === 0;
}

function validateEnum(context, subject, schema) {
	var values = schema['enum'];

	if(!Array.isArray(values))
		throw new Error('Invalid schema: "enum" value must be an array');

	var i = values.length;
	while(i--) {
		if(validators.deepEqual(subject, values[i])) return true;
	}

	context.addError('Failed "enum" criteria', subject, values);
	return false;
}

function validateType(context, subject, schema, type) {
	var validTypes = Array.isArray(schema.type) ? schema.type : [ schema.type ],
		valid = validateTypes(context, subject, type, validTypes);

	if(!valid) {
		context.addError('Failed "type" criteria: expecting ' + validTypes.join(' or ') + ', found ' + type, subject, schema);
	}

	return valid;
}

function typeValidations(context, subject, schema, type) {
	return validators.types[type](context, subject, schema);
}

function pathFromIds(ids) {
	return ids.map(function(id) {
		var lastSlash = id.lastIndexOf("/");
		if(lastSlash === -1) return id;
		return id.substr(0, lastSlash + 1);
	}).join('');
}

function $ref(context, subject, schema) {
	var absolute = /^(#|\/)/.test(schema.$ref),
		ref = absolute ? schema.$ref : pathFromIds(context.id) + schema.$ref,
		refSchema = context.refs.get(ref, context.schema),
		ctx = context;

	if(schema.$ref[0] !== '#') {
		ctx = context.subcontext(context.refs.get(ref, context.schema, true));
	}

	var valid = validateBase(ctx, subject, refSchema);

	context.cleanSubject = ctx.cleanSubject;

	return valid;
}

function validateBase(context, subject, schema) {
	if(schema.$ref) {
		return $ref(context, subject, schema);
	}

	if(schema.id) context.id.push(schema.id);

	var valid = context.runValidations([
		[ 'type' in schema, validateType ],
		[ 'disallow' in schema, disallow ],
		[ 'enum' in schema, validateEnum ],
		[ true, typeValidations ],
		[ 'format' in schema, format ],
		[ 'extends' in schema, validateExtends ],
		[ 'allOf' in schema, allOf ],
		[ 'anyOf' in schema, anyOf ],
		[ 'oneOf' in schema, oneOf ],
		[ 'not' in schema, not ]
	], subject, schema, getType(subject));

	if(schema.id) context.id.pop();

	return valid;
}

module.exports = validateBase;
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

function registerPushwooshAndroid() {

 	var pushNotification = cordova.require("com.pushwoosh.plugins.pushwoosh.PushNotification");

	//set push notifications handler
	document.addEventListener('push-notification',
		function(event)
		{
            var title = event.notification.title;
            var userData = event.notification.userdata;

            //dump custom data to the console if it exists
            if(typeof(userData) != "undefined") {
				console.warn('user data: ' + JSON.stringify(userData));
			}

			//and show alert
			alert(title);

			//stopping geopushes
			//pushNotification.stopGeoPushes();
		}
	);

	//initialize Pushwoosh with projectid: "GOOGLE_PROJECT_ID", appid : "PUSHWOOSH_APP_ID". This will trigger all pending push notifications on start.
	pushNotification.onDeviceReady({ projectid: "60756016005", appid : "4FC89B6D14A655.46488481" });

	//register for push notifications
	pushNotification.registerDevice(
		function(token)
		{
			alert(token);
			//callback when pushwoosh is ready
			onPushwooshAndroidInitialized(token);
		},
		function(status)
		{
			alert("failed to register: " +  status);
		    console.warn(JSON.stringify(['failed to register ', status]));
		}
	);
}

function onPushwooshAndroidInitialized(pushToken)
{
	//output the token to the console
	console.warn('push token: ' + pushToken);

	var pushNotification = cordova.require("com.pushwoosh.plugins.pushwoosh.PushNotification");

	//if you need push token at a later time you can always get it from Pushwoosh plugin
	pushNotification.getPushToken(
		function(token)
		{
			console.warn('push token: ' + token);
		}
	);

	//and HWID if you want to communicate with Pushwoosh API
	pushNotification.getPushwooshHWID(
		function(token) {
			console.warn('Pushwoosh HWID: ' + token);
		}
	);

	pushNotification.getTags(
		function(tags)
		{
			console.warn('tags for the device: ' + JSON.stringify(tags));
		},
		function(error)
		{
			console.warn('get tags error: ' + JSON.stringify(error));
		}
	);

	//set multi notificaiton mode
	//pushNotification.setMultiNotificationMode();
	//pushNotification.setEnableLED(true);

	//set single notification mode
	//pushNotification.setSingleNotificationMode();

	//disable sound and vibration
	//pushNotification.setSoundType(1);
	//pushNotification.setVibrateType(1);

	pushNotification.setLightScreenOnNotification(false);

	//goal with count
	//pushNotification.sendGoalAchieved({goal:'purchase', count:3});

	//goal with no count
	//pushNotification.sendGoalAchieved({goal:'registration'});

	//setting list tags
	//pushNotification.setTags({"MyTag":["hello", "world"]});

	//settings tags
	pushNotification.setTags({deviceName:"hello", deviceId:10},
		function(status) {
			console.warn('setTags success');
		},
		function(status) {
			console.warn('setTags failed');
		}
	);

	//Pushwoosh Android specific method that cares for the battery
	//pushNotification.startGeoPushes();
}
<commit_msg>removed obsolete functions<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

function registerPushwooshAndroid() {

 	var pushNotification = cordova.require("com.pushwoosh.plugins.pushwoosh.PushNotification");

	//set push notifications handler
	document.addEventListener('push-notification',
		function(event)
		{
            var title = event.notification.title;
            var userData = event.notification.userdata;

            //dump custom data to the console if it exists
            if(typeof(userData) != "undefined") {
				console.warn('user data: ' + JSON.stringify(userData));
			}

			//and show alert
			alert(title);

			//stopping geopushes
			//pushNotification.stopGeoPushes();
		}
	);

	//initialize Pushwoosh with projectid: "GOOGLE_PROJECT_ID", appid : "PUSHWOOSH_APP_ID". This will trigger all pending push notifications on start.
	pushNotification.onDeviceReady({ projectid: "60756016005", appid : "4FC89B6D14A655.46488481" });

	//register for push notifications
	pushNotification.registerDevice(
		function(token)
		{
			alert(token);
			//callback when pushwoosh is ready
			onPushwooshAndroidInitialized(token);
		},
		function(status)
		{
			alert("failed to register: " +  status);
		    console.warn(JSON.stringify(['failed to register ', status]));
		}
	);
}

function onPushwooshAndroidInitialized(pushToken)
{
	//output the token to the console
	console.warn('push token: ' + pushToken);

	var pushNotification = cordova.require("com.pushwoosh.plugins.pushwoosh.PushNotification");

	//if you need push token at a later time you can always get it from Pushwoosh plugin
	pushNotification.getPushToken(
		function(token)
		{
			console.warn('push token: ' + token);
		}
	);

	//and HWID if you want to communicate with Pushwoosh API
	pushNotification.getPushwooshHWID(
		function(token) {
			console.warn('Pushwoosh HWID: ' + token);
		}
	);

	pushNotification.getTags(
		function(tags)
		{
			console.warn('tags for the device: ' + JSON.stringify(tags));
		},
		function(error)
		{
			console.warn('get tags error: ' + JSON.stringify(error));
		}
	);

	//set multi notificaiton mode
	//pushNotification.setMultiNotificationMode();
	//pushNotification.setEnableLED(true);

	//set single notification mode
	//pushNotification.setSingleNotificationMode();

	//disable sound and vibration
	//pushNotification.setSoundType(1);
	//pushNotification.setVibrateType(1);

	pushNotification.setLightScreenOnNotification(false);

	//setting list tags
	//pushNotification.setTags({"MyTag":["hello", "world"]});

	//settings tags
	pushNotification.setTags({deviceName:"hello", deviceId:10},
		function(status) {
			console.warn('setTags success');
		},
		function(status) {
			console.warn('setTags failed');
		}
	);

	//Pushwoosh Android specific method that cares for the battery
	//pushNotification.startGeoPushes();
}
<|endoftext|>


<commit_before>angular.module('weatherHistory.controllers')
.controller('ListCtrl', function($scope, $filter, settingsFactory, geocoder, forecastFactory) {
  $scope.loadData = loadData;
  $scope.reloadData = reloadData;
  $scope.models = {
    date: forecastFactory.date,
    place: {
      details: {},
      place: null
    }};
  $scope.list = [];
  var expectedLength = 3,
    LENGTH = 3;

  $scope.$on('list:reload', reloadData);
  $scope.$watch('list.length', orderList);
  $scope.$watch('models.place.details', getNewPlace);
  $scope.$watch('models.date', getNewDate);

  /**
   * Load data from forecast.io. Used in infinite scroll and called whenever
   * settings or place change.
   */
  function loadData() {
    settingsFactory.getDeferred()
      .then(function(settings) {
        $scope.city = settings.city;
        $scope.country = settings.country;
        $scope.formattedDate = moment(settings.date).format(settings.dateFormat);
        var interval = settings.interval,
          oldLength = $scope.list.length * interval;

        for (var i = 0; i < LENGTH; i++) {
          var time = moment(settings.date).subtract(oldLength + i * interval, 'years').unix();
          forecastFactory.getForecast(settings.latitude, settings.longitude, time, settings)
            .then(handleData);
        }
      });
  }

  /**
   * Handle data received from api calls in loadData for loop.
   *
   * @param {Object} forecast - Forecast data
   */
  function handleData(forecast) {
    forecast.data.year = parseInt(moment.unix(forecast.data.currently.time).format('YYYY'), 10);
    forecast.data.currently.icon = forecastFactory.renameIcons(forecast.data.currently.icon);
    $scope.list.push(forecast.data);
  }

  /**
   * Watch to see when api calls are done and list is full of new data. Orders only new data.
   *
   * @param {Number} newLength - New length
   * @param {Number} oldLength - Old length
   */
  function orderList(newLength, oldLength) {
    if (newLength !== oldLength) {
      if (newLength === expectedLength) {
        var recentlyAdded = $scope.list.splice(newLength - LENGTH, LENGTH);
        recentlyAdded = $filter('orderBy')(recentlyAdded, 'year', true);
        $scope.list = $scope.list.concat(recentlyAdded);
        expectedLength = expectedLength + LENGTH;
        $scope.$broadcast('scroll.infiniteScrollComplete');
      }
    }
  }

  /**
   * Reload data. Reset list and its expected length, clear cache, and then load data. Used when
   * setting, date, or place change.
   *
   * @param {Boolean} pulledToRefresh - True if using pull to refresh directive
   */
  function reloadData(pulledToRefresh) {
    $scope.list = [];
    expectedLength = LENGTH;
    forecastFactory.clearCache();
    loadData();

    // Make conditional since it uses javascript to scroll which triggers infinite scroll to
    // call its method (meaning data is duplicated).
    if (pulledToRefresh) {
      $scope.$broadcast('scroll.refreshComplete');
    }
  }

  /**
   * Watch function to handle user getting new location from google maps places search
   *
   * @param {Object} newPlace - New place from google search
   * @param {Object} oldPlace - Old place
   */
  function getNewPlace(newPlace, oldPlace) {
    if (newPlace !== oldPlace) {
      // Put city and country into $scope
      angular.extend($scope, geocoder.parseAddressComponents(newPlace.address_components));
      $scope.latitude = parseFloat(newPlace.geometry.location.A, 10);
      $scope.longitude = parseFloat(newPlace.geometry.location.F, 10);
      settingsFactory.set({
        city: $scope.city,
        country: $scope.country,
        latitude: $scope.latitude,
        longitude: $scope.longitude
      });
      reloadData();
      $scope.models.place.place = '';
    }
  }

  /**
   * Watch function to handle getting new date from datepicker, closing the modal, and
   * getting weather with new date.
   *
   * @param {Date} newDate - New date input
   * @param {Date} oldDate - Old date input
   */
  function getNewDate(newDate, oldDate) {
    if (newDate !== oldDate) {
      // TODO: Doesn't close when picking same day after changing months
      if (moment(newDate).isSame(oldDate, 'month')) {
        settingsFactory.set({date: newDate});
        reloadData();
        $scope.$broadcast('DatepickerModal:closeModal');
      }
    }
  }
});

<commit_msg>Added code to stop infinite scroll runinng when there's no more data to be retrieved.<commit_after>angular.module('weatherHistory.controllers')
.controller('ListCtrl', function($scope, $filter, settingsFactory, geocoder, forecastFactory) {
  $scope.loadData = loadData;
  $scope.reloadData = reloadData;
  $scope.canLoadData = canLoadData;
  $scope.models = {
    date: forecastFactory.date,
    place: {
      details: {},
      place: null
    }};
  $scope.list = [];
  var expectedLength = 3,
    canLoad = true,
    LENGTH = 3;

  $scope.$on('list:reload', reloadData);
  $scope.$watch('list.length', orderList);
  $scope.$watch('models.place.details', getNewPlace);
  $scope.$watch('models.date', getNewDate);

  /**
   * Load data from forecast.io. Used in infinite scroll and called whenever
   * settings or place change.
   */
  function loadData() {
    settingsFactory.getDeferred()
      .then(function(settings) {
        $scope.city = settings.city;
        $scope.country = settings.country;
        $scope.formattedDate = moment(settings.date).format(settings.dateFormat);
        var interval = settings.interval,
          oldLength = $scope.list.length * interval;

        for (var i = 0; i < LENGTH; i++) {
          var time = moment(settings.date).subtract(oldLength + i * interval, 'years').unix();
          forecastFactory.getForecast(settings.latitude, settings.longitude, time, settings)
            .then(handleData);
        }
      });
  }

  /**
   * Handle data received from api calls in loadData for loop.
   *
   * @param {Object} forecast - Forecast data
   */
  function handleData(forecast) {
    // Check we're still getting data otherwise stop infinite scroll
    if (forecast.data.currently.icon) {
      forecast.data.year = parseInt(moment.unix(forecast.data.currently.time).format('YYYY'), 10);
      forecast.data.currently.icon = forecastFactory.renameIcons(forecast.data.currently.icon);
      $scope.list.push(forecast.data);
    } else {
      canLoad = false;

      // Last two items end up switched so here's a hack
      var listLength = $scope.list,
        penUltimate, ultimate;
      angular.copy($scope.list[listLength-2], ultimate),
      angular.copy($scope.list[listLength-1], penUltimate);
      $scope.list[listLength-1] = penUltimate;
      $scope.list[listLength-2] = ultimate;
    }
  }

  /**
   * Handle error received from api calls in loadData for loop.
   *
   * @param {Object} forecast - Forecast data
   */
  function handleError() {
    console.log('error')
    canLoad = false;
  }

  /**
   * Watch to see when api calls are done and list is full of new data. Orders only new data.
   *
   * @param {Number} newLength - New length
   * @param {Number} oldLength - Old length
   */
  function orderList(newLength, oldLength) {
    if (newLength !== oldLength) {
      if (newLength === expectedLength) {
        var recentlyAdded = $scope.list.splice(newLength - LENGTH, LENGTH);
        recentlyAdded = $filter('orderBy')(recentlyAdded, 'year', true);
        $scope.list = $scope.list.concat(recentlyAdded);
        expectedLength = expectedLength + LENGTH;
        $scope.$broadcast('scroll.infiniteScrollComplete');
      }
    }
  }

  /**
   * Reload data. Reset list and its expected length, clear cache, and then load data. Used when
   * setting, date, or place change.
   *
   * @param {Boolean} pulledToRefresh - True if using pull to refresh directive
   */
  function reloadData(pulledToRefresh) {
    $scope.list = [];
    expectedLength = LENGTH;
    canLoad = true;
    forecastFactory.clearCache();
    loadData();

    // Make conditional since it uses javascript to scroll which triggers infinite scroll to
    // call its method (meaning data is duplicated).
    if (pulledToRefresh) {
      $scope.$broadcast('scroll.refreshComplete');
    }
  }

  /**
   * Used when ;lder forecasts can't be retrieved anymore.
   *
   * @return {Boolean} canLoad - Whether data can be loaded
   */
  function canLoadData() {
    return canLoad;
  }

  /**
   * Watch function to handle user getting new location from google maps places search
   *
   * @param {Object} newPlace - New place from google search
   * @param {Object} oldPlace - Old place
   */
  function getNewPlace(newPlace, oldPlace) {
    if (newPlace !== oldPlace) {
      // Put city and country into $scope
      angular.extend($scope, geocoder.parseAddressComponents(newPlace.address_components));
      $scope.latitude = parseFloat(newPlace.geometry.location.A, 10);
      $scope.longitude = parseFloat(newPlace.geometry.location.F, 10);
      settingsFactory.set({
        city: $scope.city,
        country: $scope.country,
        latitude: $scope.latitude,
        longitude: $scope.longitude
      });
      reloadData();
      $scope.models.place.place = '';
    }
  }

  /**
   * Watch function to handle getting new date from datepicker, closing the modal, and
   * getting weather with new date.
   *
   * @param {Date} newDate - New date input
   * @param {Date} oldDate - Old date input
   */
  function getNewDate(newDate, oldDate) {
    if (newDate !== oldDate) {
      // TODO: Doesn't close when picking same day after changing months
      if (moment(newDate).isSame(oldDate, 'month')) {
        settingsFactory.set({date: newDate});
        reloadData();
        $scope.$broadcast('DatepickerModal:closeModal');
      }
    }
  }
});

<|endoftext|>


<commit_before>/**
 * Created by Petr Marek on 3.7.2015.
 */

var DEFAULT_ADDRESS = "http://qa.ailao.eu/"; //default address of endpoint
var CONNECTION_ADDRESS; //address of endpoint
var DIRECTLY_SHOWED_QUESTIONS = 3; // Number of questions above drop down menu
var showFeedbackDefault = true;

var qidQueue = []; // queue of posed questions
var isShowingAnswer = false;
var gen_sources, gen_answers;  // when this number changes, re-render
var answers;
var endpoint;
var showFeedbackBool;

var numberOfShowedAnswers;

var questionText;

/* Ajax function for retrieving questions and answers */
$(function () {
    $("#ask").ajaxForm({
        success: function (response) {
            $('#verticalCenter').animate({marginTop: '0px'}, 'slow');
            saveUserID(JSON.parse(response).userID);
            putUserIDToForm();
            putDialogIDToForm(JSON.parse(response).dialogueID);
            window.location.href = createURL(JSON.parse(response).dialogueID,null);
            setTimeout(function () {
                loadQuestion(JSON.parse(response).id, true)
            }, 500);
        }
    });

    getToAnswerJson();
    setInterval(getToAnswerJson, 3100);

    getInProgressJson();
    setInterval(getInProgressJson, 3000);

    getDialogsJson();
    setInterval(getDialogsJson, 2900);
});

/* Handles back navigation */
$(function () {
    // Bind the event.
    $(window).hashchange(hashchanged);
    // Trigger the event (useful on page load).
    hashchanged();
});

/* Url changed, redraw page */
function hashchanged() {
    //load and change endpoint
    endpoint = getParameterByName("e", window.location.href);
    changeEndpoint(endpoint);
    reloadAnswered();

    var showFeedback = getParameterByName("feedback", window.location.href);
    if (showFeedback != null)
        showFeedbackBool = showFeedback.toLowerCase() === 'true';
    else
        showFeedbackBool = showFeedbackDefault;
    var dID = getParameterByName("dID", window.location.href);
    var qID = getParameterByName("qID", window.location.href);
    // If dID is present and we are on main page, show answer
    var arr = window.location.href.split('#');
    if (dID != null && (arr[1] == "mainPage" || arr[1] == null)) {
        loadDialog(dID, true);
        $('#verticalCenter').css('margin-top', 0);
        switchToSearchAfterAnswer();
        openQuestion(arr);
    }else if(qID!=null && (arr[1]=="mainPage" || arr[1] == null)){
        loadQuestion(qID);
    }
    //if there is no dID clear show search area to center and clear results
    else {
        //if page is not loaded, don't position anything (page is loaded only during back navigation)
        if ($('[data-role=header]').height() != null) {
            $('#verticalCenter').css('opacity', 0.0);
            $('#verticalCenter').animate({opacity: '1.0'}, 100);
            $('#verticalCenter').css('margin-top', ($(window).height() / 2 - ($('#verticalCenter').outerHeight()) / 1.5));
        }
        clearResult();
        qidQueue = [];
    }
}

function openQuestion(arr) {
    var qID = getParameterByName("qID", window.location.href);
    if (qID != null && (arr[1] == "mainPage" || arr[1] == null)) {
        setTimeout(function () {
            $("#" + qID).collapsible("expand")
        }, 500);
    }
}

function switchToSearchAfterAnswer() {
    $('.searchButtons').empty();
    $('#searchBlock').css("width", "83%");
    $('#askBlock').css("width", "10%");
    $('#askBlock').css("display", "inline");
    $('#blurb').css("display", "none");
    $('#mainPage .mainHeader').removeClass("mainHeaderLone");
}

/* Centers search area if there is no answers */
$(document).on('pageshow', '#mainPage', function (e, data) {
    if (!isShowingAnswer) {
        $('#verticalCenter').animate({opacity: '1.0'}, 100);
        $('#verticalCenter').css('margin-top', ($(window).height() / 2 - ($('#verticalCenter').outerHeight()) / 1.5));
    } else {
        $('#verticalCenter').css('opacity', 1.0);
    }
    $('input[name="text"]').val(questionText);
    putUserIDToForm();
});

/* Centers search area on page resize */
$(window).resize(function () {
    if (!isShowingAnswer) {
        $('#verticalCenter').css('margin-top', ($(window).height() / 2 - ($('#verticalCenter').outerHeight()) / 1.5));
    }
});

function reloadMainPage() {
    window.location.href=createURL(null,null);
}

/* Gets parameter by name */
function getParameterByName(name, url) {
    var arr = url.split('#');
    var match = RegExp('[?&]' + name + '=([^&]*)')
        .exec(arr[0]);
    return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}

/* Clears results of answer during back navigation */
function clearResult() {
    $("#answers_area").empty();
    $("#concept_area").empty();
    $("#answerType_area").empty();
    $("#sources_area").empty();
    $('input[name="text"]').val("");
}

/* Changes endpoint for JSON and form */
function changeEndpoint(endpoint) {
    if (endpoint == null) {
        CONNECTION_ADDRESS = DEFAULT_ADDRESS;
        $("#ask").attr("action", DEFAULT_ADDRESS + "q");
        setFeedbackEndpoint("live");
    } else {
        if (endpoint == "http://qa.ailao.eu:4000/") {
            // XXX: ugly hardcoded
            $(".mainHeaderLink").html("YodaQA Movies");
            $("#blurb").html("Ask question about movies and TV series.
We don't have the storylines, but know the metadata
(credits, dates, episodes, awards, ...).");
            setFeedbackEndpoint("movies");
        } else {
            $(".mainHeaderLink").html("YodaQA Custom");
            $("#blurb").html("This is an unofficial YodaQA version.");
        }
        CONNECTION_ADDRESS = endpoint;
        $("#ask").attr("action", endpoint + "q");
    }
}

function reloadAnswered() {
    getToAnswerJson();
    getInProgressJson();
    getDialogsJson();
}

/* Gets question information and shows it
 */
function loadQuestion(q) {
    isShowingAnswer = true;
    gen_sources = 0;
    gen_answers = 0;
    addNewCard(q);
    addQuestion(q, $('input[name="text"]').val());
    getQuestionJson(q);
}

function toggleFeedback() {
    showFeedbackBool = !showFeedbackBool;
    loadQuestion(getParameterByName("dID", window.location.href), true);
}

/* Creates URL with parameters */
function createURL(dID,qID) {
    var appersand = false;
    var url = "?";
    if (dID != null) {
        url += "dID=" + dID;
        appersand = true;
    }
    if (qID != null){
        if (appersand) {
            url += "&";
        }
        url += "qID=" + qID;
        appersand = true;
    }
    if (endpoint != null) {
        if (appersand) {
            url += "&";
        }
        url += "e=" + endpoint;
        appersand = true;
    }
    if (showFeedbackBool != showFeedbackDefault) {
        if (appersand) {
            url += "&";
        }
        url += "feedback=" + showFeedbackBool;
    }
    url += "#mainPage";
    return url;
}

/* Retrieve, process and display json question information. */
function getQuestionJson(qid) {
    if (CONNECTION_ADDRESS != null) {
        var parameters = "q/" + qid;
        var uID = getUserID();
        if (uID != "" && uID != "undefined") {
            parameters += "/" + uID;
        }else{
            parameters += "/" + "-1";
        }
        $.get(CONNECTION_ADDRESS + parameters, function (r) {
            saveUserID(r.userID);
            putUserIDToForm();
            showAnswerToQuestion(r)
        });
    }
}

function getDialogJson(id) {
    if (CONNECTION_ADDRESS != null) {
        var parameters = "q/" + id;
        $.get(CONNECTION_ADDRESS + parameters, function (r) {
            showDialog(r);
        });
    }
}

function showDialog(dialogJson) {
    for (var i = 0; i < dialogJson.length; i++) {
        loadQuestion(dialogJson[i], true);
    }
}

/* Capitalize first letter */
String.prototype.capitalizeFirstLetter = function () {
    return this.charAt(0).toUpperCase() + this.slice(1);
}

function saveUserID(userID) {
    var cookieName = "userID";
    if (!cookieExists(cookieName)) {
        setCookie(cookieName, userID, 365);
    }
}

function getUserID() {
    return getCookie("userID");
}

function putUserIDToForm() {
    var uID = getUserID();
    if (uID != "" && uID != "undefined") {
        $("#userID").val(uID);
    }
}

function putDialogIDToForm(id) {
    $("#dialogueID").val(id);
}<commit_msg>Changed default endpoints<commit_after>/**
 * Created by Petr Marek on 3.7.2015.
 */

var DEFAULT_ADDRESS = "http://qa.ailao.eu:4568/"; //default address of endpoint
var CONNECTION_ADDRESS; //address of endpoint
var DIRECTLY_SHOWED_QUESTIONS = 3; // Number of questions above drop down menu
var showFeedbackDefault = true;

var qidQueue = []; // queue of posed questions
var isShowingAnswer = false;
var gen_sources, gen_answers;  // when this number changes, re-render
var answers;
var endpoint;
var showFeedbackBool;

var numberOfShowedAnswers;

var questionText;

/* Ajax function for retrieving questions and answers */
$(function () {
    $("#ask").ajaxForm({
        success: function (response) {
            $('#verticalCenter').animate({marginTop: '0px'}, 'slow');
            saveUserID(JSON.parse(response).userID);
            putUserIDToForm();
            putDialogIDToForm(JSON.parse(response).dialogueID);
            window.location.href = createURL(JSON.parse(response).dialogueID,null);
            setTimeout(function () {
                loadQuestion(JSON.parse(response).id, true)
            }, 500);
        }
    });

    getToAnswerJson();
    setInterval(getToAnswerJson, 3100);

    getInProgressJson();
    setInterval(getInProgressJson, 3000);

    getDialogsJson();
    setInterval(getDialogsJson, 2900);
});

/* Handles back navigation */
$(function () {
    // Bind the event.
    $(window).hashchange(hashchanged);
    // Trigger the event (useful on page load).
    hashchanged();
});

/* Url changed, redraw page */
function hashchanged() {
    //load and change endpoint
    endpoint = getParameterByName("e", window.location.href);
    changeEndpoint(endpoint);
    reloadAnswered();

    var showFeedback = getParameterByName("feedback", window.location.href);
    if (showFeedback != null)
        showFeedbackBool = showFeedback.toLowerCase() === 'true';
    else
        showFeedbackBool = showFeedbackDefault;
    var dID = getParameterByName("dID", window.location.href);
    var qID = getParameterByName("qID", window.location.href);
    // If dID is present and we are on main page, show answer
    var arr = window.location.href.split('#');
    if (dID != null && (arr[1] == "mainPage" || arr[1] == null)) {
        loadDialog(dID, true);
        $('#verticalCenter').css('margin-top', 0);
        switchToSearchAfterAnswer();
        openQuestion(arr);
    }else if(qID!=null && (arr[1]=="mainPage" || arr[1] == null)){
        loadQuestion(qID);
    }
    //if there is no dID clear show search area to center and clear results
    else {
        //if page is not loaded, don't position anything (page is loaded only during back navigation)
        if ($('[data-role=header]').height() != null) {
            $('#verticalCenter').css('opacity', 0.0);
            $('#verticalCenter').animate({opacity: '1.0'}, 100);
            $('#verticalCenter').css('margin-top', ($(window).height() / 2 - ($('#verticalCenter').outerHeight()) / 1.5));
        }
        clearResult();
        qidQueue = [];
    }
}

function openQuestion(arr) {
    var qID = getParameterByName("qID", window.location.href);
    if (qID != null && (arr[1] == "mainPage" || arr[1] == null)) {
        setTimeout(function () {
            $("#" + qID).collapsible("expand")
        }, 500);
    }
}

function switchToSearchAfterAnswer() {
    $('.searchButtons').empty();
    $('#searchBlock').css("width", "83%");
    $('#askBlock').css("width", "10%");
    $('#askBlock').css("display", "inline");
    $('#blurb').css("display", "none");
    $('#mainPage .mainHeader').removeClass("mainHeaderLone");
}

/* Centers search area if there is no answers */
$(document).on('pageshow', '#mainPage', function (e, data) {
    if (!isShowingAnswer) {
        $('#verticalCenter').animate({opacity: '1.0'}, 100);
        $('#verticalCenter').css('margin-top', ($(window).height() / 2 - ($('#verticalCenter').outerHeight()) / 1.5));
    } else {
        $('#verticalCenter').css('opacity', 1.0);
    }
    $('input[name="text"]').val(questionText);
    putUserIDToForm();
});

/* Centers search area on page resize */
$(window).resize(function () {
    if (!isShowingAnswer) {
        $('#verticalCenter').css('margin-top', ($(window).height() / 2 - ($('#verticalCenter').outerHeight()) / 1.5));
    }
});

function reloadMainPage() {
    window.location.href=createURL(null,null);
}

/* Gets parameter by name */
function getParameterByName(name, url) {
    var arr = url.split('#');
    var match = RegExp('[?&]' + name + '=([^&]*)')
        .exec(arr[0]);
    return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}

/* Clears results of answer during back navigation */
function clearResult() {
    $("#answers_area").empty();
    $("#concept_area").empty();
    $("#answerType_area").empty();
    $("#sources_area").empty();
    $('input[name="text"]').val("");
}

/* Changes endpoint for JSON and form */
function changeEndpoint(endpoint) {
    if (endpoint == null) {
        CONNECTION_ADDRESS = DEFAULT_ADDRESS;
        $("#ask").attr("action", DEFAULT_ADDRESS + "q");
        setFeedbackEndpoint("live");
    } else {
        if (endpoint == "http://qa.ailao.eu:4001/") {
            // XXX: ugly hardcoded
            $(".mainHeaderLink").html("YodaQA Movies");
            $("#blurb").html("Ask question about movies and TV series.
We don't have the storylines, but know the metadata
(credits, dates, episodes, awards, ...).");
            setFeedbackEndpoint("movies");
        } else {
            $(".mainHeaderLink").html("YodaQA Custom");
            $("#blurb").html("This is an unofficial YodaQA version.");
        }
        CONNECTION_ADDRESS = endpoint;
        $("#ask").attr("action", endpoint + "q");
    }
}

function reloadAnswered() {
    getToAnswerJson();
    getInProgressJson();
    getDialogsJson();
}

/* Gets question information and shows it
 */
function loadQuestion(q) {
    isShowingAnswer = true;
    gen_sources = 0;
    gen_answers = 0;
    addNewCard(q);
    addQuestion(q, $('input[name="text"]').val());
    getQuestionJson(q);
}

function toggleFeedback() {
    showFeedbackBool = !showFeedbackBool;
    loadQuestion(getParameterByName("dID", window.location.href), true);
}

/* Creates URL with parameters */
function createURL(dID,qID) {
    var appersand = false;
    var url = "?";
    if (dID != null) {
        url += "dID=" + dID;
        appersand = true;
    }
    if (qID != null){
        if (appersand) {
            url += "&";
        }
        url += "qID=" + qID;
        appersand = true;
    }
    if (endpoint != null) {
        if (appersand) {
            url += "&";
        }
        url += "e=" + endpoint;
        appersand = true;
    }
    if (showFeedbackBool != showFeedbackDefault) {
        if (appersand) {
            url += "&";
        }
        url += "feedback=" + showFeedbackBool;
    }
    url += "#mainPage";
    return url;
}

/* Retrieve, process and display json question information. */
function getQuestionJson(qid) {
    if (CONNECTION_ADDRESS != null) {
        var parameters = "q/" + qid;
        var uID = getUserID();
        if (uID != "" && uID != "undefined") {
            parameters += "/" + uID;
        }else{
            parameters += "/" + "-1";
        }
        $.get(CONNECTION_ADDRESS + parameters, function (r) {
            saveUserID(r.userID);
            putUserIDToForm();
            showAnswerToQuestion(r)
        });
    }
}

function getDialogJson(id) {
    if (CONNECTION_ADDRESS != null) {
        var parameters = "q/" + id;
        $.get(CONNECTION_ADDRESS + parameters, function (r) {
            showDialog(r);
        });
    }
}

function showDialog(dialogJson) {
    for (var i = 0; i < dialogJson.length; i++) {
        loadQuestion(dialogJson[i], true);
    }
}

/* Capitalize first letter */
String.prototype.capitalizeFirstLetter = function () {
    return this.charAt(0).toUpperCase() + this.slice(1);
}

function saveUserID(userID) {
    var cookieName = "userID";
    if (!cookieExists(cookieName)) {
        setCookie(cookieName, userID, 365);
    }
}

function getUserID() {
    return getCookie("userID");
}

function putUserIDToForm() {
    var uID = getUserID();
    if (uID != "" && uID != "undefined") {
        $("#userID").val(uID);
    }
}

function putDialogIDToForm(id) {
    $("#dialogueID").val(id);
}<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Exponent
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Based on "tough-cookie-web-storage-store" v1.0.0
 * Thanks James Ide: https://github.com/exponentjs/tough-cookie-web-storage-store
 *
 * Modified by Sefa Ilkimen for cordova plugin integration
 *
 */

'use strict';

var pluginId = module.id.slice(0, module.id.indexOf('.'));
var ToughCookie = require(pluginId + '.tough-cookie');
var _ = require(pluginId + '.lodash');

function WebStorageCookieStore(storage, storeKey) {
    ToughCookie.Store.call(this);
    this._storage = storage || window.localStorage;
    this._storeKey = storeKey || '__cookieStore__';
    this.synchronous = true;
}

WebStorageCookieStore.prototype = Object.create(ToughCookie.Store);

WebStorageCookieStore.prototype.findCookie = function(domain, path, key, callback) {
    var store = this._readStore();
    var cookie = _.get(store, [domain, path, key], null);

    callback(null, ToughCookie.Cookie.fromJSON(cookie));
};

WebStorageCookieStore.prototype.findCookies = function(domain, path, callback) {
    if (!domain) {
        callback(null, []);
        return;
    }

    var that = this;
    var cookies = [];
    var store = this._readStore();
    var domains = ToughCookie.permuteDomain(domain) || [domain];

    domains.forEach(function(domain) {
        if (!store[domain]) {
            return;
        }

        var matchingPaths = Object.keys(store[domain]);

        if (path != null) {
            matchingPaths = matchingPaths.filter(function(cookiePath) {
                return that._isOnPath(cookiePath, path);
            });
        }

        matchingPaths.forEach(function(path) {
            Array.prototype.push.apply(cookies, _.values(store[domain][path]));
        });
    });

    cookies = cookies.map(function(cookie) {
        return ToughCookie.Cookie.fromJSON(cookie);
    });

    callback(null, cookies);
};

/**
 * Returns whether `cookiePath` is on the given `urlPath`
 */
WebStorageCookieStore.prototype._isOnPath = function(cookiePath, urlPath) {
    if (!cookiePath) {
        return false;
    }

    if (cookiePath === urlPath) {
        return true;
    }

    if (!urlPath.startsWith(cookiePath)) {
        return false;
    }

    if (cookiePath[cookiePath.length - 1] !== '/' && urlPath[cookiePath.length] !== '/') {
        return false;
    }

    return true;
};

WebStorageCookieStore.prototype.putCookie = function(cookie, callback) {
     var store = this._readStore();

     _.set(store, [cookie.domain, cookie.path, cookie.key], cookie);
     this._writeStore(store);
     callback(null);
};

WebStorageCookieStore.prototype.updateCookie = function(oldCookie, newCookie, callback) {
    this.putCookie(newCookie, callback);
};

WebStorageCookieStore.prototype.removeCookie = function(domain, path, key, callback) {
    var store = this._readStore();

    _.unset(store, [domain, path, key]);
    this._writeStore(store);
    callback(null);
};

WebStorageCookieStore.prototype.removeCookies = function(domain, path, callback) {
    var store = this._readStore();

    if (path == null) {
        _.unset(store, [domain]);
    } else {
        _.unset(store, [domain, path]);
    }

    this._writeStore(store);
    callback(null);
};

WebStorageCookieStore.prototype.getAllCookies = function(callback) {
    var cookies = [];
    var store = this._readStore();

    Object.keys(store).forEach(function(domain) {
        Object.keys(store[domain]).forEach(function(path) {
            Array.protype.push.apply(cookies, _.values(store[domain][path]));
        });
    });

    cookies = cookies.map(function(cookie) {
        return ToughCookie.Cookie.fromJSON(cookie);
    });

    cookies.sort(function(c1, c2) {
        return (c1.creationIndex || 0) - (c2.creationIndex || 0);
    });

    callback(null, cookies);
};

WebStorageCookieStore.prototype._readStore = function() {
    var json = this._storage.getItem(this._storeKey);

    if (json !== null) {
        try {
            return JSON.parse(json);
        } catch (e) { }
    }

    return {};
};

WebStorageCookieStore.prototype._writeStore = function(store) {
    this._storage.setItem(this._storeKey, JSON.stringify(store));
};

module.exports = WebStorageCookieStore;
<commit_msg>removed „String.prototype.startsWith“ call to be compatible with older web view versions<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Exponent
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Based on "tough-cookie-web-storage-store" v1.0.0
 * Thanks James Ide: https://github.com/exponentjs/tough-cookie-web-storage-store
 *
 * Modified by Sefa Ilkimen for cordova plugin integration
 *
 */

'use strict';

var pluginId = module.id.slice(0, module.id.indexOf('.'));
var ToughCookie = require(pluginId + '.tough-cookie');
var _ = require(pluginId + '.lodash');

function WebStorageCookieStore(storage, storeKey) {
    ToughCookie.Store.call(this);
    this._storage = storage || window.localStorage;
    this._storeKey = storeKey || '__cookieStore__';
    this.synchronous = true;
}

WebStorageCookieStore.prototype = Object.create(ToughCookie.Store);

WebStorageCookieStore.prototype.findCookie = function(domain, path, key, callback) {
    var store = this._readStore();
    var cookie = _.get(store, [domain, path, key], null);

    callback(null, ToughCookie.Cookie.fromJSON(cookie));
};

WebStorageCookieStore.prototype.findCookies = function(domain, path, callback) {
    if (!domain) {
        callback(null, []);
        return;
    }

    var that = this;
    var cookies = [];
    var store = this._readStore();
    var domains = ToughCookie.permuteDomain(domain) || [domain];

    domains.forEach(function(domain) {
        if (!store[domain]) {
            return;
        }

        var matchingPaths = Object.keys(store[domain]);

        if (path != null) {
            matchingPaths = matchingPaths.filter(function(cookiePath) {
                return that._isOnPath(cookiePath, path);
            });
        }

        matchingPaths.forEach(function(path) {
            Array.prototype.push.apply(cookies, _.values(store[domain][path]));
        });
    });

    cookies = cookies.map(function(cookie) {
        return ToughCookie.Cookie.fromJSON(cookie);
    });

    callback(null, cookies);
};

/**
 * Returns whether `cookiePath` is on the given `urlPath`
 */
WebStorageCookieStore.prototype._isOnPath = function(cookiePath, urlPath) {
    if (!cookiePath) {
        return false;
    }

    if (cookiePath === urlPath) {
        return true;
    }

    if (urlPath.indexOf(cookiePath) !== 0) {
        return false;
    }

    if (cookiePath[cookiePath.length - 1] !== '/' && urlPath[cookiePath.length] !== '/') {
        return false;
    }

    return true;
};

WebStorageCookieStore.prototype.putCookie = function(cookie, callback) {
     var store = this._readStore();

     _.set(store, [cookie.domain, cookie.path, cookie.key], cookie);
     this._writeStore(store);
     callback(null);
};

WebStorageCookieStore.prototype.updateCookie = function(oldCookie, newCookie, callback) {
    this.putCookie(newCookie, callback);
};

WebStorageCookieStore.prototype.removeCookie = function(domain, path, key, callback) {
    var store = this._readStore();

    _.unset(store, [domain, path, key]);
    this._writeStore(store);
    callback(null);
};

WebStorageCookieStore.prototype.removeCookies = function(domain, path, callback) {
    var store = this._readStore();

    if (path == null) {
        _.unset(store, [domain]);
    } else {
        _.unset(store, [domain, path]);
    }

    this._writeStore(store);
    callback(null);
};

WebStorageCookieStore.prototype.getAllCookies = function(callback) {
    var cookies = [];
    var store = this._readStore();

    Object.keys(store).forEach(function(domain) {
        Object.keys(store[domain]).forEach(function(path) {
            Array.protype.push.apply(cookies, _.values(store[domain][path]));
        });
    });

    cookies = cookies.map(function(cookie) {
        return ToughCookie.Cookie.fromJSON(cookie);
    });

    cookies.sort(function(c1, c2) {
        return (c1.creationIndex || 0) - (c2.creationIndex || 0);
    });

    callback(null, cookies);
};

WebStorageCookieStore.prototype._readStore = function() {
    var json = this._storage.getItem(this._storeKey);

    if (json !== null) {
        try {
            return JSON.parse(json);
        } catch (e) { }
    }

    return {};
};

WebStorageCookieStore.prototype._writeStore = function(store) {
    this._storage.setItem(this._storeKey, JSON.stringify(store));
};

module.exports = WebStorageCookieStore;
<|endoftext|>