15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2007 Apple Inc.  All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2012 Google Inc. All rights reserved.
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met:
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1.  Redistributions of source code must retain the above copyright
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     notice, this list of conditions and the following disclaimer.
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2.  Redistributions in binary form must reproduce the above copyright
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     notice, this list of conditions and the following disclaimer in the
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     documentation and/or other materials provided with the distribution.
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     its contributors may be used to endorse or promote products derived
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     from this software without specific prior written permission.
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
30e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
31a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {!Object} obj
32e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {boolean}
33e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.isEmpty = function(obj)
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var i in obj)
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
41e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
42a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {!Object.<string,!T>} obj
43a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @return {!Array.<!T>}
447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * @template T
45e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.values = function(obj)
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
48591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    var result = Object.keys(obj);
49591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    var length = result.length;
50591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    for (var i = 0; i < length; ++i)
51591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch        result[i] = obj[result[i]];
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return result;
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
55e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
56a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch * @param {number} m
57f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu * @param {number} n
58a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch * @return {number}
59a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch */
60a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdochfunction mod(m, n)
61a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch{
62a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    return ((m % n) + n) % n;
63a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch}
64a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch
65a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch/**
66e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @param {string} string
67e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {!Array.<number>}
68e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.prototype.findAll = function(string)
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var matches = [];
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var i = this.indexOf(string);
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    while (i !== -1) {
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        matches.push(i);
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        i = this.indexOf(string, i + string.length);
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return matches;
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
80e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
81e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {!Array.<number>}
82e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.prototype.lineEndings = function()
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!this._lineEndings) {
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._lineEndings = this.findAll("\n");
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._lineEndings.push(this.length);
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return this._lineEndings;
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
92e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
9309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) * @return {number}
9409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) */
9509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)String.prototype.lineCount = function()
9609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
9709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    var lineEndings = this.lineEndings();
9809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return lineEndings.length;
9909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
10009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
10109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)/**
10209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) * @return {string}
10309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) */
10409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)String.prototype.lineAt = function(lineNumber)
10509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
10609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    var lineEndings = this.lineEndings();
10709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    var lineStart = lineNumber > 0 ? lineEndings[lineNumber - 1] + 1 : 0;
10809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    var lineEnd = lineEndings[lineNumber];
10909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    var lineContent = this.substring(lineStart, lineEnd);
11009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (lineContent.length > 0 && lineContent.charAt(lineContent.length - 1) === "\r")
11109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        lineContent = lineContent.substring(0, lineContent.length - 1);
11209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return lineContent;
11309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
11409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
11509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)/**
116e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @param {string} chars
117e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
118e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.prototype.escapeCharacters = function(chars)
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var foundChar = false;
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var i = 0; i < chars.length; ++i) {
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (this.indexOf(chars.charAt(i)) !== -1) {
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            foundChar = true;
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!foundChar)
130926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return String(this);
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var result = "";
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var i = 0; i < this.length; ++i) {
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (chars.indexOf(this.charAt(i)) !== -1)
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result += "\\";
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result += this.charAt(i);
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return result;
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
142e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
143e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
144e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
145926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)String.regexSpecialCharacters = function()
146926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
14707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    return "^[]{}()\\.^$*+?|-,";
148926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
149926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
150e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
151e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
152e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.prototype.escapeForRegExp = function()
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
155e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    return this.escapeCharacters(String.regexSpecialCharacters());
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
158e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
159e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
160e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.prototype.escapeHTML = function()
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return this.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;"); //" doublequotes just for editor
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
166e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
167e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
168e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.prototype.collapseWhitespace = function()
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return this.replace(/[\s\xA0]+/g, " ");
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
174e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
175e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @param {number} maxLength
176e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
177e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.prototype.trimMiddle = function(maxLength)
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (this.length <= maxLength)
181926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return String(this);
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var leftHalf = maxLength >> 1;
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var rightHalf = maxLength - leftHalf - 1;
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return this.substr(0, leftHalf) + "\u2026" + this.substr(this.length - rightHalf, rightHalf);
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
187e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
188e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @param {number} maxLength
189e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
190e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.prototype.trimEnd = function(maxLength)
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (this.length <= maxLength)
194926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return String(this);
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return this.substr(0, maxLength - 1) + "\u2026";
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
198e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
199e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @param {?string=} baseURLDomain
200e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
201e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.prototype.trimURL = function(baseURLDomain)
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var result = this.replace(/^(https|http|file):\/\//i, "");
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (baseURLDomain)
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result = result.replace(new RegExp("^" + baseURLDomain.escapeForRegExp(), "i"), "");
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return result;
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
210e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
211e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
212e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
213926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)String.prototype.toTitleCase = function()
214926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
215926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return this.substring(0, 1).toUpperCase() + this.substring(1);
216926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
217926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
218926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)/**
219926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * @param {string} other
220926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * @return {number}
221926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) */
222926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)String.prototype.compareTo = function(other)
223926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
224926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (this > other)
225926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return 1;
226926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (this < other)
227926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return -1;
228926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return 0;
229926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
230926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {string} href
2338abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) * @return {?string}
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function sanitizeHref(href)
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2378abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    return href && href.trim().toLowerCase().startsWith("javascript:") ? null : href;
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
240e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
241e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
242e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.prototype.removeURLFragment = function()
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var fragmentIndex = this.indexOf("#");
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (fragmentIndex == -1)
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        fragmentIndex = this.length;
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return this.substring(0, fragmentIndex);
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
251e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
252e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {boolean}
253e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.prototype.startsWith = function(substring)
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return !this.lastIndexOf(substring, 0);
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
259e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
260e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {boolean}
261e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.prototype.endsWith = function(substring)
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return this.indexOf(substring, this.length - substring.length) !== -1;
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
267e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
26809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) * @return {number}
26909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) */
27009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)String.prototype.hashCode = function()
27109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
27209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    var result = 0;
27309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    for (var i = 0; i < this.length; ++i)
27409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        result = result * 3 + this.charCodeAt(i);
27509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return result;
27609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
27709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
27809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)/**
2797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * @param {string} a
2807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * @param {string} b
2817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * @return {number}
2827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch */
2837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochString.naturalOrderComparator = function(a, b)
2847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
2857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    var chunk = /^\d+|^\D+/;
2867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    var chunka, chunkb, anum, bnum;
2877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    while (1) {
2887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (a) {
2897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if (!b)
2907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                return 1;
2917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        } else {
2927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if (b)
2937757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                return -1;
2947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            else
2957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                return 0;
2967757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
2977757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        chunka = a.match(chunk)[0];
2987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        chunkb = b.match(chunk)[0];
2997757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        anum = !isNaN(chunka);
3007757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        bnum = !isNaN(chunkb);
3017757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (anum && !bnum)
3027757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            return -1;
3037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (bnum && !anum)
3047757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            return 1;
3057757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (anum && bnum) {
3067757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            var diff = chunka - chunkb;
3077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if (diff)
3087757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                return diff;
3097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if (chunka.length !== chunkb.length) {
3107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                if (!+chunka && !+chunkb) // chunks are strings of all 0s (special case)
3117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    return chunka.length - chunkb.length;
3127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                else
3137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    return chunkb.length - chunka.length;
3147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            }
3157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        } else if (chunka !== chunkb)
3167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            return (chunka < chunkb) ? -1 : 1;
3177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        a = a.substring(chunka.length);
3187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        b = b.substring(chunkb.length);
3197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
3207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
3217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
3227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch/**
323e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @param {number} num
324e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @param {number} min
325e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @param {number} max
326e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {number}
327e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Number.constrain = function(num, min, max)
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (num < min)
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        num = min;
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else if (num > max)
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        num = max;
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return num;
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3375267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)/**
338e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @param {number} a
339e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @param {number} b
340e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {number}
341e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
342e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben MurdochNumber.gcd = function(a, b)
343e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch{
344e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    if (b === 0)
345e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        return a;
346e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    else
347e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        return Number.gcd(b, a % b);
348e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch}
349e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
350e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
3515267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * @param {string} value
3525267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * @return {string}
3535267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) */
3545267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)Number.toFixedIfFloating = function(value)
3555267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles){
3565267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    if (!value || isNaN(value))
3575267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        return value;
3585267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    var number = Number(value);
3595267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    return number % 1 ? number.toFixed(3) : String(number);
3605267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)}
3615267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
362e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
363e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
364e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Date.prototype.toISO8601Compact = function()
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
367e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    /**
368e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @param {number} x
369e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @return {string}
370e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     */
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function leadZero(x)
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
373e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        return (x > 9 ? "" : "0") + x;
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return this.getFullYear() +
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)           leadZero(this.getMonth() + 1) +
377e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch           leadZero(this.getDate()) + "T" +
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)           leadZero(this.getHours()) +
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)           leadZero(this.getMinutes()) +
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)           leadZero(this.getSeconds());
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
38307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch/**
38407a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch * @return {string}
38507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch */
38607a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch Date.prototype.toConsoleTime = function()
38707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch{
38807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    /**
38907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch     * @param {number} x
39007a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch     * @return {string}
39107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch     */
39207a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    function leadZero2(x)
39307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    {
39407a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        return (x > 9 ? "" : "0") + x;
39507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    }
39607a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch
39707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    /**
39807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch     * @param {number} x
39907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch     * @return {string}
40007a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch     */
40107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    function leadZero3(x)
40207a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    {
40307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        return (Array(4 - x.toString().length)).join('0') + x;
40407a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    }
40507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch
40607a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    return this.getFullYear() + "-" +
40707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch           leadZero2(this.getMonth() + 1) + "-" +
40807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch           leadZero2(this.getDate()) + " " +
40907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch           leadZero2(this.getHours()) + ":" +
41007a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch           leadZero2(this.getMinutes()) + ":" +
41107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch           leadZero2(this.getSeconds()) + "." +
41207a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch           leadZero3(this.getMilliseconds());
41307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch}
41407a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.defineProperty(Array.prototype, "remove",
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
418a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!T} value
41907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch     * @param {boolean=} firstOnly
420a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @this {Array.<!T>}
4217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @template T
4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
42307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    value: function(value, firstOnly)
4245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
42507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        var index = this.indexOf(value);
42607a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        if (index === -1)
42707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch            return;
42807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        if (firstOnly) {
42907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch            this.splice(index, 1);
4305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
43207a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        for (var i = index + 1, n = this.length; i < n; ++i) {
43307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch            if (this[i] !== value)
43407a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch                this[index++] = this[i];
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
43607a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        this.length = index;
4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)});
4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.defineProperty(Array.prototype, "keySet",
4415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
443e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @return {!Object.<string, boolean>}
4445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @this {Array.<*>}
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
4465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    value: function()
4475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var keys = {};
4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < this.length; ++i)
4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            keys[this[i]] = true;
4515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return keys;
4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)});
4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
455f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)Object.defineProperty(Array.prototype, "pushAll",
456f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles){
457f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    /**
458f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     * @param {!Array.<!T>} array
459f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     * @this {Array.<!T>}
460f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     * @template T
461f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     */
462f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    value: function(array)
463f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    {
464f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        Array.prototype.push.apply(this, array);
465f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    }
466f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)});
467f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.defineProperty(Array.prototype, "rotate",
4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {number} index
472a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Array.<!T>}
473a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @this {Array.<!T>}
4747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @template T
4755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    value: function(index)
4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var result = [];
4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = index; i < index + this.length; ++i)
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.push(this[i % this.length]);
4815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return result;
4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)});
4845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
48576c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)Object.defineProperty(Array.prototype, "sortNumbers",
48676c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles){
48776c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)    /**
48876c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)     * @this {Array.<number>}
48976c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)     */
49076c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)    value: function()
49176c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)    {
49276c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)        /**
49376c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)         * @param {number} a
49476c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)         * @param {number} b
49576c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)         * @return {number}
49676c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)         */
49776c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)        function numericComparator(a, b)
49876c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)        {
49976c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)            return a - b;
50076c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)        }
50176c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)
50276c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)        this.sort(numericComparator);
50376c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)    }
50476c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)});
50576c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)
5065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.defineProperty(Uint32Array.prototype, "sort", {
50710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    value: Array.prototype.sort
5085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)});
5095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)(function() {
5115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)var partition = {
5125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
5135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @this {Array.<number>}
514e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @param {function(number, number): number} comparator
5155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {number} left
5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {number} right
5175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {number} pivotIndex
5185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
5195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    value: function(comparator, left, right, pivotIndex)
5205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
5215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function swap(array, i1, i2)
5225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
5235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var temp = array[i1];
5245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            array[i1] = array[i2];
5255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            array[i2] = temp;
5265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
5275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var pivotValue = this[pivotIndex];
5295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        swap(this, right, pivotIndex);
5305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var storeIndex = left;
5315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = left; i < right; ++i) {
5325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (comparator(this[i], pivotValue) < 0) {
5335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                swap(this, storeIndex, i);
5345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ++storeIndex;
5355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
5365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
5375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        swap(this, right, storeIndex);
5385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return storeIndex;
5395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
5405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
5415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.defineProperty(Array.prototype, "partition", partition);
5425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.defineProperty(Uint32Array.prototype, "partition", partition);
5435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)var sortRange = {
5455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
546e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @param {function(number, number): number} comparator
5475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {number} leftBound
5485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {number} rightBound
5498abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)     * @param {number} sortWindowLeft
5508abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)     * @param {number} sortWindowRight
551e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @return {!Array.<number>}
552e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @this {Array.<number>}
5535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
5548abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    value: function(comparator, leftBound, rightBound, sortWindowLeft, sortWindowRight)
5555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
5568abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)        function quickSortRange(array, comparator, left, right, sortWindowLeft, sortWindowRight)
5575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
5585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (right <= left)
5595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
5605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var pivotIndex = Math.floor(Math.random() * (right - left)) + left;
5615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var pivotNewIndex = array.partition(comparator, left, right, pivotIndex);
5628abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)            if (sortWindowLeft < pivotNewIndex)
5638abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)                quickSortRange(array, comparator, left, pivotNewIndex - 1, sortWindowLeft, sortWindowRight);
5648abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)            if (pivotNewIndex < sortWindowRight)
5658abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)                quickSortRange(array, comparator, pivotNewIndex + 1, right, sortWindowLeft, sortWindowRight);
5665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
5678abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)        if (leftBound === 0 && rightBound === (this.length - 1) && sortWindowLeft === 0 && sortWindowRight >= rightBound)
5685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this.sort(comparator);
5695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else
5708abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)            quickSortRange(this, comparator, leftBound, rightBound, sortWindowLeft, sortWindowRight);
5715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return this;
5725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
5735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.defineProperty(Array.prototype, "sortRange", sortRange);
5755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.defineProperty(Uint32Array.prototype, "sortRange", sortRange);
5765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)})();
5775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
578a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)Object.defineProperty(Array.prototype, "stableSort",
579a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles){
580a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    /**
581a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(?T, ?T): number=} comparator
582a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Array.<?T>}
583a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @this {Array.<?T>}
584a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @template T
585a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     */
586a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    value: function(comparator)
587a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    {
588a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        function defaultComparator(a, b)
589a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        {
590a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            return a < b ? -1 : (a > b ? 1 : 0);
591a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        }
592a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        comparator = comparator || defaultComparator;
593a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
594a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        var indices = new Array(this.length);
595a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        for (var i = 0; i < this.length; ++i)
596a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            indices[i] = i;
597a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        var self = this;
598a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        /**
599a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         * @param {number} a
600a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         * @param {number} b
601a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         * @return {number}
602a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         */
603a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        function indexComparator(a, b)
604a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        {
605a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            var result = comparator(self[a], self[b]);
606a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            return result ? result : a - b;
607a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        }
608a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        indices.sort(indexComparator);
609a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
610a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        for (var i = 0; i < this.length; ++i) {
611a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            if (indices[i] < 0 || i === indices[i])
612a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)                continue;
613a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            var cyclical = i;
614a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            var saved = this[i];
615a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            while (true) {
616a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)                var next = indices[cyclical];
617a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)                indices[cyclical] = -1;
618a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)                if (next === i) {
619a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)                    this[cyclical] = saved;
620a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)                    break;
621a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)                } else {
622a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)                    this[cyclical] = this[next];
623a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)                    cyclical = next;
624a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)                }
625a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            }
626a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        }
627a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        return this;
628a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    }
629a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)});
630a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
6315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.defineProperty(Array.prototype, "qselect",
6325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
6335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
6345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {number} k
635e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @param {function(number, number): number=} comparator
636e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @return {number|undefined}
637e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @this {Array.<number>}
6385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
6395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    value: function(k, comparator)
6405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
6415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (k < 0 || k >= this.length)
6425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
6435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!comparator)
6445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            comparator = function(a, b) { return a - b; }
6455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var low = 0;
6475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var high = this.length - 1;
6485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (;;) {
6495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var pivotPosition = this.partition(comparator, low, high, Math.floor((high + low) / 2));
6505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (pivotPosition === k)
6515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return this[k];
6525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else if (pivotPosition > k)
6535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                high = pivotPosition - 1;
6545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else
6555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                low = pivotPosition + 1;
6565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
6575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
6585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)});
6595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
660e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben MurdochObject.defineProperty(Array.prototype, "lowerBound",
6615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
662e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    /**
663e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * Return index of the leftmost element that is equal or greater
664e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * than the specimen object. If there's no such element (i.e. all
66509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * elements are smaller than the specimen) returns right bound.
666e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * The function works for sorted array.
66709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * When specified, |left| (inclusive) and |right| (exclusive) indices
66809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * define the search window.
669e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     *
670a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!T} object
671a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(!T,!S):number=} comparator
67209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {number=} left
67309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {number=} right
674e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @return {number}
675a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @this {Array.<!S>}
6767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @template T,S
677e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     */
67809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    value: function(object, comparator, left, right)
679e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    {
680e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        function defaultComparator(a, b)
681e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        {
6827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            return a < b ? -1 : (a > b ? 1 : 0);
683e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        }
684e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        comparator = comparator || defaultComparator;
68509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        var l = left || 0;
68609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        var r = right !== undefined ? right : this.length;
687e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        while (l < r) {
688e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch            var m = (l + r) >> 1;
689e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch            if (comparator(object, this[m]) > 0)
690e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch                l = m + 1;
691e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch            else
692e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch                r = m;
693e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        }
694e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        return r;
6955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
696e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch});
6975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
698e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben MurdochObject.defineProperty(Array.prototype, "upperBound",
699e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch{
700e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    /**
701e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * Return index of the leftmost element that is greater
702e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * than the specimen object. If there's no such element (i.e. all
70309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * elements are smaller or equal to the specimen) returns right bound.
704e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * The function works for sorted array.
70509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * When specified, |left| (inclusive) and |right| (exclusive) indices
70609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * define the search window.
707e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     *
708a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!T} object
709a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(!T,!S):number=} comparator
71009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {number=} left
71109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {number=} right
712e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @return {number}
713a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @this {Array.<!S>}
7147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @template T,S
715e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     */
71609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    value: function(object, comparator, left, right)
717e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    {
718e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        function defaultComparator(a, b)
719e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        {
7207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            return a < b ? -1 : (a > b ? 1 : 0);
721e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        }
722e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        comparator = comparator || defaultComparator;
72309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        var l = left || 0;
72409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        var r = right !== undefined ? right : this.length;
725e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        while (l < r) {
726e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch            var m = (l + r) >> 1;
727e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch            if (comparator(object, this[m]) >= 0)
728e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch                l = m + 1;
729e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch            else
730e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch                r = m;
731e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        }
732e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        return r;
733e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    }
734e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch});
7355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
73610f88d5669dbd969c059d61ba09fa37dd72ac559Ben MurdochObject.defineProperty(Uint32Array.prototype, "lowerBound", {
73710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    value: Array.prototype.lowerBound
73810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch});
73910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
74010f88d5669dbd969c059d61ba09fa37dd72ac559Ben MurdochObject.defineProperty(Uint32Array.prototype, "upperBound", {
74110f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    value: Array.prototype.upperBound
74210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch});
74310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
744f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuObject.defineProperty(Float64Array.prototype, "lowerBound", {
745f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    value: Array.prototype.lowerBound
746f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu});
747f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu
7485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.defineProperty(Array.prototype, "binaryIndexOf",
7495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
7505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
751a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!T} value
752a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(!T,!S):number} comparator
753e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     * @return {number}
754a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @this {Array.<!S>}
7557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @template T,S
7565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
7575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    value: function(value, comparator)
7585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
759e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        var index = this.lowerBound(value, comparator);
760e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        return index < this.length && comparator(value, this[index]) === 0 ? index : -1;
7615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)});
7635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Object.defineProperty(Array.prototype, "select",
7655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
7665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
7675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {string} field
768a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Array.<!T>}
769a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @this {Array.<!Object.<string,!T>>}
7707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @template T
7715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
7725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    value: function(field)
7735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
7745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var result = new Array(this.length);
7755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < this.length; ++i)
7765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result[i] = this[i][field];
7775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return result;
7785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)});
7805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
781926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)Object.defineProperty(Array.prototype, "peekLast",
782926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
783926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    /**
784a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!T|undefined}
785a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @this {Array.<!T>}
7867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @template T
787926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)     */
788926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    value: function()
789926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    {
790926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return this[this.length - 1];
791926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    }
792926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)});
793926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
794a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)(function(){
795a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
796a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)/**
797a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {!Array.<T>} array1
798a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {!Array.<T>} array2
799a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {function(T,T):number} comparator
800f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) * @param {boolean} mergeNotIntersect
801a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @return {!Array.<T>}
802a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @template T
803a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) */
804a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)function mergeOrIntersect(array1, array2, comparator, mergeNotIntersect)
805a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles){
806a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    var result = [];
807a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    var i = 0;
808a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    var j = 0;
80909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    while (i < array1.length && j < array2.length) {
81009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        var compareValue = comparator(array1[i], array2[j]);
81109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (mergeNotIntersect || !compareValue)
81209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            result.push(compareValue <= 0 ? array1[i] : array2[j]);
81309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (compareValue <= 0)
81409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            i++;
81509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (compareValue >= 0)
81609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            j++;
81709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
81809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (mergeNotIntersect) {
81909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        while (i < array1.length)
82009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            result.push(array1[i++]);
82109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        while (j < array2.length)
82209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            result.push(array2[j++]);
823a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    }
824a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    return result;
825a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)}
826a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
827a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)Object.defineProperty(Array.prototype, "intersectOrdered",
828a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles){
829a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    /**
830a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!Array.<T>} array
831a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(T,T):number} comparator
832a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Array.<T>}
833a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @this {!Array.<T>}
834a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @template T
835a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     */
836a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    value: function(array, comparator)
837a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    {
838a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        return mergeOrIntersect(this, array, comparator, false);
839a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    }
840a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)});
841a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
842a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)Object.defineProperty(Array.prototype, "mergeOrdered",
843a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles){
844a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    /**
845a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!Array.<T>} array
846a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(T,T):number} comparator
847a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Array.<T>}
848a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @this {!Array.<T>}
849a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @template T
850a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     */
851a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    value: function(array, comparator)
852a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    {
853a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        return mergeOrIntersect(this, array, comparator, true);
854a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    }
855a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)});
856a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
857a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)}());
858a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
859a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
8605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
861a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {!T} object
862a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {!Array.<!S>} list
863a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {function(!T,!S):number=} comparator
864591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch * @param {boolean=} insertionIndexAfter
865e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {number}
8667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * @template T,S
8675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
868e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdochfunction insertionIndexForObjectInListSortedByFunction(object, list, comparator, insertionIndexAfter)
8695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
870e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    if (insertionIndexAfter)
871e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        return list.upperBound(object, comparator);
872e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    else
873e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        return list.lowerBound(object, comparator);
8745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
8755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
8775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {string} format
8785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {...*} var_arg
879e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
8805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
8815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.sprintf = function(format, var_arg)
8825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
8835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return String.vsprintf(format, Array.prototype.slice.call(arguments, 1));
8845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
8855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8865d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)/**
8875d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) * @param {string} format
8885d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) * @param {!Object.<string, function(string, ...):*>} formatters
8895d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) * @return {!Array.<!Object>}
8905d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) */
8915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.tokenizeFormatString = function(format, formatters)
8925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
8935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var tokens = [];
8945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var substitutionIndex = 0;
8955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function addStringToken(str)
8975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
8985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        tokens.push({ type: "string", value: str });
8995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
9005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function addSpecifierToken(specifier, precision, substitutionIndex)
9025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
9035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        tokens.push({ type: "specifier", specifier: specifier, precision: precision, substitutionIndex: substitutionIndex });
9045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
9055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function isDigit(c)
9075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
9085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return !!/[0-9]/.exec(c);
9095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
9105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var index = 0;
9125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var precentIndex = format.indexOf("%", index); precentIndex !== -1; precentIndex = format.indexOf("%", index)) {
9135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        addStringToken(format.substring(index, precentIndex));
9145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        index = precentIndex + 1;
9155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9166f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        if (format[index] === "%") {
9176f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch            // %% escape sequence.
9186f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch            addStringToken("%");
9196f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch            ++index;
9206f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch            continue;
9216f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        }
9226f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch
9235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (isDigit(format[index])) {
9245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // The first character is a number, it might be a substitution index.
9255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var number = parseInt(format.substring(index), 10);
9265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            while (isDigit(format[index]))
9275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ++index;
9285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // If the number is greater than zero and ends with a "$",
9305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // then this is a substitution index.
9315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (number > 0 && format[index] === "$") {
9325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                substitutionIndex = (number - 1);
9335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ++index;
9345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
9355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
9365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var precision = -1;
9385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (format[index] === ".") {
9395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // This is a precision specifier. If no digit follows the ".",
9405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // then the precision should be zero.
9415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ++index;
9425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            precision = parseInt(format.substring(index), 10);
9435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (isNaN(precision))
9445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                precision = 0;
9455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            while (isDigit(format[index]))
9475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ++index;
9485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
9495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!(format[index] in formatters)) {
9515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            addStringToken(format.substring(precentIndex, index + 1));
9525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ++index;
9535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
9545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
9555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        addSpecifierToken(format[index], precision, substitutionIndex);
9575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ++substitutionIndex;
9595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ++index;
9605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
9615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    addStringToken(format.substring(index));
9635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return tokens;
9655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.standardFormatters = {
96809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    /**
96909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {number}
97009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     */
9715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    d: function(substitution)
9725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
9735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return !isNaN(substitution) ? substitution : 0;
9745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
9755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
97609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    /**
97709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {number}
97809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     */
9795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    f: function(substitution, token)
9805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
9815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (substitution && token.precision > -1)
9825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            substitution = substitution.toFixed(token.precision);
9835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return !isNaN(substitution) ? substitution : (token.precision > -1 ? Number(0).toFixed(token.precision) : 0);
9845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
9855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
98609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    /**
98709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {string}
98809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     */
9895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    s: function(substitution)
9905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
9915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return substitution;
9925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
9935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
995e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch/**
996e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @param {string} format
997a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {!Array.<*>} substitutions
998e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
999e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
10005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.vsprintf = function(format, substitutions)
10015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
10025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return String.format(format, substitutions, String.standardFormatters, "", function(a, b) { return a + b; }).formattedResult;
10035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
10045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10055d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)/**
10065d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) * @param {string} format
10075d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) * @param {?Array.<string>} substitutions
10085d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) * @param {!Object.<string, function(string, ...):string>} formatters
10095d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) * @param {!T} initialValue
10105d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) * @param {function(T, string): T|undefined} append
10115d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) * @return {!{formattedResult: T, unusedSubstitutions: ?Array.<string>}};
10125d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) * @template T
10135d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) */
10145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String.format = function(format, substitutions, formatters, initialValue, append)
10155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
10165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!format || !substitutions || !substitutions.length)
10175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return { formattedResult: append(initialValue, format), unusedSubstitutions: substitutions };
10185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function prettyFunctionName()
10205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
10215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return "String.format(\"" + format + "\", \"" + substitutions.join("\", \"") + "\")";
10225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
10235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function warn(msg)
10255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
10265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        console.warn(prettyFunctionName() + ": " + msg);
10275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
10285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    function error(msg)
10305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
10315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        console.error(prettyFunctionName() + ": " + msg);
10325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
10335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var result = initialValue;
10355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var tokens = String.tokenizeFormatString(format, formatters);
10365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var usedSubstitutionIndexes = {};
10375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var i = 0; i < tokens.length; ++i) {
10395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var token = tokens[i];
10405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (token.type === "string") {
10425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result = append(result, token.value);
10435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
10445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
10455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (token.type !== "specifier") {
10475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            error("Unknown token type \"" + token.type + "\" found.");
10485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
10495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
10505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (token.substitutionIndex >= substitutions.length) {
10525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // If there are not enough substitutions for the current substitutionIndex
10535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // just output the format specifier literally and move on.
10545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            error("not enough substitution arguments. Had " + substitutions.length + " but needed " + (token.substitutionIndex + 1) + ", so substitution was skipped.");
10555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result = append(result, "%" + (token.precision > -1 ? token.precision : "") + token.specifier);
10565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
10575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
10585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        usedSubstitutionIndexes[token.substitutionIndex] = true;
10605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!(token.specifier in formatters)) {
10625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Encountered an unsupported format character, treat as a string.
10635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            warn("unsupported format character \u201C" + token.specifier + "\u201D. Treating as a string.");
10645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result = append(result, substitutions[token.substitutionIndex]);
10655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
10665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
10675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result = append(result, formatters[token.specifier](substitutions[token.substitutionIndex], token));
10695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
10705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var unusedSubstitutions = [];
10725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var i = 0; i < substitutions.length; ++i) {
10735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (i in usedSubstitutionIndexes)
10745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
10755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        unusedSubstitutions.push(substitutions[i]);
10765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
10775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return { formattedResult: result, unusedSubstitutions: unusedSubstitutions };
10795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
10805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
10825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {string} query
10835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {boolean} caseSensitive
10845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {boolean} isRegex
1085a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @return {!RegExp}
10865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
10875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function createSearchRegex(query, caseSensitive, isRegex)
10885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
10895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var regexFlags = caseSensitive ? "g" : "gi";
10905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var regexObject;
10915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isRegex) {
10935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        try {
10945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            regexObject = new RegExp(query, regexFlags);
10955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } catch (e) {
10965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Silent catch.
10975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
10985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
10995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!regexObject)
11015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        regexObject = createPlainTextSearchRegex(query, regexFlags);
11025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return regexObject;
11045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
11055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
11075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {string} query
11085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {string=} flags
11095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @return {!RegExp}
11105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
11115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function createPlainTextSearchRegex(query, flags)
11125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
11135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // This should be kept the same as the one in ContentSearchUtils.cpp.
1114926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    var regexSpecialCharacters = String.regexSpecialCharacters();
11155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var regex = "";
11165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var i = 0; i < query.length; ++i) {
11175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var c = query.charAt(i);
11185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (regexSpecialCharacters.indexOf(c) != -1)
11195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            regex += "\\";
11205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        regex += c;
11215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
11225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return new RegExp(regex, flags || "");
11235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
11245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
1126a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {!RegExp} regex
11275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {string} content
11285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @return {number}
11295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
11305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function countRegexMatches(regex, content)
11315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
11325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var text = content;
11335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var result = 0;
11345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var match;
11355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    while (text && (match = regex.exec(text))) {
11365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (match[0].length > 0)
11375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ++result;
11385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        text = text.substring(match.index + 1);
11395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
11405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return result;
11415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
11425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
11445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {number} value
11455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {number} symbolsCount
11465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @return {string}
11475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
11485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function numberToStringWithSpacesPadding(value, symbolsCount)
11495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
11505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var numberString = value.toString();
11515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var paddingLength = Math.max(0, symbolsCount - numberString.length);
11525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var paddingString = Array(paddingLength + 1).join("\u00a0");
11535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return paddingString + numberString;
11545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
11555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
1157e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch * @return {string}
1158e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch */
1159926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)var createObjectIdentifier = function()
1160926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
1161926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // It has to be string for better performance.
1162e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    return "_" + ++createObjectIdentifier._last;
1163926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
1164926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1165926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)createObjectIdentifier._last = 0;
1166926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1167926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)/**
1168926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * @constructor
11697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * @template T
1170926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) */
1171926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)var Set = function()
1172926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
11737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /** @type {!Object.<string, !T>} */
1174926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    this._set = {};
1175926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    this._size = 0;
1176926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
1177926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
117810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch/**
117910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch * @param {!Array.<!T>} array
118010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch * @return {!Set.<T>}
118110f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch * @template T
118210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch */
118310f88d5669dbd969c059d61ba09fa37dd72ac559Ben MurdochSet.fromArray = function(array)
118410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch{
118510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    var result = new Set();
118610f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    array.forEach(function(item) { result.add(item); });
118710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    return result;
118810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch}
118910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
1190926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)Set.prototype = {
1191926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    /**
11927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @param {!T} item
1193926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)     */
1194926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    add: function(item)
1195926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    {
1196926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        var objectIdentifier = item.__identifier;
1197926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (!objectIdentifier) {
1198926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            objectIdentifier = createObjectIdentifier();
1199926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            item.__identifier = objectIdentifier;
1200926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        }
1201926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (!this._set[objectIdentifier])
1202926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            ++this._size;
1203926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        this._set[objectIdentifier] = item;
1204926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    },
1205e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
1206926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    /**
12077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @param {!T} item
1208e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     * @return {boolean}
1209926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)     */
1210926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    remove: function(item)
1211926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    {
1212926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (this._set[item.__identifier]) {
1213926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            --this._size;
1214926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            delete this._set[item.__identifier];
1215e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            return true;
1216926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        }
1217e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        return false;
1218926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    },
1219926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1220926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    /**
12217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @return {!Array.<!T>}
1222926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)     */
1223d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    values: function()
1224926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    {
1225926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        var result = new Array(this._size);
1226926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        var i = 0;
1227926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        for (var objectIdentifier in this._set)
1228926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            result[i++] = this._set[objectIdentifier];
1229926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return result;
1230926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    },
1231926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1232926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    /**
12337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @param {!T} item
1234e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     * @return {boolean}
1235926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)     */
123610f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    contains: function(item)
1237926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    {
1238e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        return !!this._set[item.__identifier];
1239926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    },
1240926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1241926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    /**
1242926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)     * @return {number}
1243926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)     */
1244926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    size: function()
1245926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    {
1246926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return this._size;
1247926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    },
1248926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1249926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    clear: function()
1250926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    {
1251926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        this._set = {};
1252926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        this._size = 0;
1253926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    }
1254926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
1255926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1256926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)/**
12575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
12587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * @template K,V
12595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
12605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)var Map = function()
12615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
12627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /** @type {!Object.<string, !Array.<K|V>>} */
12635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._map = {};
12645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._size = 0;
12655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
12665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Map.prototype = {
12685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
1269a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {K} key
1270a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {V} value
12715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
12725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    put: function(key, value)
12735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
12745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var objectIdentifier = key.__identifier;
12755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!objectIdentifier) {
1276926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            objectIdentifier = createObjectIdentifier();
12775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            key.__identifier = objectIdentifier;
12785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
12795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!this._map[objectIdentifier])
12805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ++this._size;
12815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._map[objectIdentifier] = [key, value];
12825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
1283e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
12845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
1285a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {K} key
1286a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {V}
12875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
12885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    remove: function(key)
12895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
12905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var result = this._map[key.__identifier];
1291926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (!result)
1292926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            return undefined;
12935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        --this._size;
1294926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        delete this._map[key.__identifier];
1295926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return result[1];
12965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
12975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
1299a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Array.<K>}
13005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
13015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    keys: function()
13025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
13035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return this._list(0);
13045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
13055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1306e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    /**
13077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @return {!Array.<V>}
1308e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     */
13095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    values: function()
13105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
13115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return this._list(1);
13125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
13135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
13155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {number} index
13167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @return {!Array.<K|V>}
13175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
13185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _list: function(index)
13195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
13205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var result = new Array(this._size);
13215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var i = 0;
13225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var objectIdentifier in this._map)
13235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result[i++] = this._map[objectIdentifier][index];
13245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return result;
13255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
13265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
1328a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {K} key
13297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @return {V|undefined}
13305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
13315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    get: function(key)
13325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
13335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var entry = this._map[key.__identifier];
13345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return entry ? entry[1] : undefined;
13355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
13365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1337926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    /**
1338a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {K} key
1339e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     * @return {boolean}
1340926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)     */
1341926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    contains: function(key)
1342926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    {
1343926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        var entry = this._map[key.__identifier];
1344926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return !!entry;
1345926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    },
1346926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1347e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    /**
1348e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     * @return {number}
1349e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     */
13505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    size: function()
13515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
13525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return this._size;
13535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
13545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    clear: function()
13565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
13575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._map = {};
13585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._size = 0;
13595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
13605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1361e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1362e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)/**
1363e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles) * @constructor
13647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * @template T
1365e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles) */
1366e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)var StringMap = function()
1367e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles){
13687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /** @type {!Object.<string, T>} */
1369e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    this._map = {};
1370e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    this._size = 0;
1371e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)}
1372e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1373e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)StringMap.prototype = {
1374e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    /**
1375e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     * @param {string} key
13767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @param {T} value
1377e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     */
1378e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    put: function(key, value)
1379e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    {
1380e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (key === "__proto__") {
1381e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            if (!this._hasProtoKey) {
1382e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)                ++this._size;
1383e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)                this._hasProtoKey = true;
1384e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            }
13857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            /** @type {T} */
1386e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            this._protoValue = value;
1387e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            return;
1388e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        }
1389e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (!Object.prototype.hasOwnProperty.call(this._map, key))
1390e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            ++this._size;
1391e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        this._map[key] = value;
1392e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    },
1393e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1394e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    /**
1395e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     * @param {string} key
139609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {T|undefined}
1397e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     */
1398e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    remove: function(key)
1399e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    {
1400e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        var result;
1401e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (key === "__proto__") {
1402e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            if (!this._hasProtoKey)
1403e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)                return undefined;
1404e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            --this._size;
1405e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            delete this._hasProtoKey;
1406e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            result = this._protoValue;
1407e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            delete this._protoValue;
1408e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            return result;
1409e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        }
1410e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (!Object.prototype.hasOwnProperty.call(this._map, key))
1411e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            return undefined;
1412e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        --this._size;
1413e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        result = this._map[key];
1414e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        delete this._map[key];
1415e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        return result;
1416e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    },
1417e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1418e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    /**
14197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @return {!Array.<string>}
1420e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     */
1421e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    keys: function()
1422e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    {
14237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        var result = Object.keys(this._map) || [];
1424e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (this._hasProtoKey)
1425e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            result.push("__proto__");
1426e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        return result;
1427e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    },
1428e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1429e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    /**
14307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch     * @return {!Array.<T>}
1431e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     */
1432e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    values: function()
1433e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    {
1434e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        var result = Object.values(this._map);
1435e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (this._hasProtoKey)
1436e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            result.push(this._protoValue);
1437e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        return result;
1438e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    },
1439e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1440e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    /**
1441e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     * @param {string} key
144209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {T|undefined}
1443e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     */
1444e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    get: function(key)
1445e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    {
1446e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (key === "__proto__")
1447e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            return this._protoValue;
1448e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (!Object.prototype.hasOwnProperty.call(this._map, key))
1449e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            return undefined;
1450e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        return this._map[key];
1451e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    },
1452e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1453e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    /**
1454e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     * @param {string} key
1455e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     * @return {boolean}
1456e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     */
1457e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    contains: function(key)
1458e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    {
1459e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        var result;
1460e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (key === "__proto__")
1461e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            return this._hasProtoKey;
1462e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        return Object.prototype.hasOwnProperty.call(this._map, key);
1463e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    },
1464e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1465e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    /**
1466e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     * @return {number}
1467e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     */
1468e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    size: function()
1469e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    {
1470e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        return this._size;
1471e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    },
1472e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1473e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    clear: function()
1474e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    {
1475e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        this._map = {};
1476e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        this._size = 0;
1477e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        delete this._hasProtoKey;
1478e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        delete this._protoValue;
1479e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    }
1480e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)}
1481e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
14825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
1483d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) * @constructor
1484aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch * @extends {StringMap.<Set.<!T>>}
1485aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch * @template T
1486aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch */
1487aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdochvar StringMultimap = function()
1488aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch{
1489aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    StringMap.call(this);
1490aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch}
1491aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch
1492aafa69cb17c9d6606c07663ade5f81388a2c5986Ben MurdochStringMultimap.prototype = {
1493aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    /**
1494aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {string} key
1495aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {T} value
1496aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     */
1497aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    put: function(key, value)
1498aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    {
1499aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch        if (key === "__proto__") {
1500aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            if (!this._hasProtoKey) {
1501aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch                ++this._size;
1502aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch                this._hasProtoKey = true;
1503aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch                /** @type {!Set.<T>} */
1504aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch                this._protoValue = new Set();
1505aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            }
1506aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            this._protoValue.add(value);
1507aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            return;
1508aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch        }
1509aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch        if (!Object.prototype.hasOwnProperty.call(this._map, key)) {
1510aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            ++this._size;
1511aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            this._map[key] = new Set();
1512aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch        }
1513aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch        this._map[key].add(value);
1514aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    },
1515aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch
1516f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    /**
1517f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     * @param {string} key
1518f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     * @return {!Set.<!T>}
1519f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     */
1520f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    get: function(key)
1521f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    {
1522f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        var result = StringMap.prototype.get.call(this, key);
1523f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        if (!result)
1524f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            result = new Set();
1525f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        return result;
1526f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    },
1527f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
1528f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    /**
1529f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     * @param {string} key
1530f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     * @param {T} value
1531f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     */
1532f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    remove: function(key, value)
1533f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    {
1534f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        var values = this.get(key);
1535f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        values.remove(value);
1536f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        if (!values.size())
1537f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            StringMap.prototype.remove.call(this, key)
1538f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    },
1539f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
1540f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    /**
1541f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     * @param {string} key
1542f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     */
1543f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    removeAll: function(key)
1544f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    {
1545f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        StringMap.prototype.remove.call(this, key);
1546f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    },
1547f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
1548f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    /**
1549f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     * @return {!Array.<!T>}
1550f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)     */
1551f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    values: function()
1552f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    {
1553f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        var result = [];
1554f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        var keys = this.keys();
1555f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        for (var i = 0; i < keys.length; ++i)
1556f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            result.pushAll(this.get(keys[i]).values());
1557f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        return result;
1558f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    },
1559f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
1560aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    __proto__: StringMap.prototype
1561aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch}
1562aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch
1563aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch/**
1564aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch * @constructor
1565d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) */
1566d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)var StringSet = function()
1567d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles){
1568d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /** @type {!StringMap.<boolean>} */
1569d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    this._map = new StringMap();
1570d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}
1571d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1572aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch/**
1573aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch * @param {!Array.<string>} array
157410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch * @return {!StringSet}
1575aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch */
1576aafa69cb17c9d6606c07663ade5f81388a2c5986Ben MurdochStringSet.fromArray = function(array)
1577aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch{
1578aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    var result = new StringSet();
1579aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    array.forEach(function(item) { result.add(item); });
1580aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    return result;
1581aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch}
1582aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch
1583d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)StringSet.prototype = {
1584d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1585d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {string} value
1586d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
1587aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    add: function(value)
1588d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    {
1589d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        this._map.put(value, true);
1590d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    },
1591d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1592d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1593d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {string} value
1594d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @return {boolean}
1595d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
1596d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    remove: function(value)
1597d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    {
1598d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        return !!this._map.remove(value);
1599d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    },
1600d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1601d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1602d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @return {!Array.<string>}
1603d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
1604d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    values: function()
1605d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    {
1606d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        return this._map.keys();
1607d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    },
1608d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1609d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1610d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {string} value
1611d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @return {boolean}
1612d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
1613d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    contains: function(value)
1614d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    {
1615d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        return this._map.contains(value);
1616d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    },
1617d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1618d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1619d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @return {number}
1620d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
1621d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    size: function()
1622d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    {
1623d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        return this._map.size();
1624d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    },
1625d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1626d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    clear: function()
1627d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    {
1628d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        this._map.clear();
1629d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    }
1630d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}
1631d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1632d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)/**
16335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {string} url
16345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {boolean=} async
16355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {function(?string)=} callback
16365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @return {?string}
16375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
163809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)function loadXHR(url, async, callback)
16395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
164009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    function onReadyStateChanged()
16415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
16425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (xhr.readyState !== XMLHttpRequest.DONE)
16435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
16445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
16455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (xhr.status === 200) {
16465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            callback(xhr.responseText);
16475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
16485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
16495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
165009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        callback(null);
16515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   }
16525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
16535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var xhr = new XMLHttpRequest();
16545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    xhr.open("GET", url, async);
16555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (async)
1656e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        xhr.onreadystatechange = onReadyStateChanged;
16575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    xhr.send(null);
16585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
16595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!async) {
166009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (xhr.status === 200)
16615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return xhr.responseText;
16625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return null;
16635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
16645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return null;
16655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
16665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
16675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)var _importedScripts = {};
16685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
16695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
1670323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles) * @param {string} url
1671323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles) * @return {string}
1672323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles) */
1673323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)function loadResource(url)
1674323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles){
1675323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    var xhr = new XMLHttpRequest();
1676323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    xhr.open("GET", url, false);
1677323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    var stack = new Error().stack;
1678323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    try {
1679323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)        xhr.send(null);
1680323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    } catch (e) {
1681323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)        console.error(url + " -> " + stack);
1682323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)        throw e;
1683323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    }
1684323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    return xhr.responseText;
1685323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)}
1686323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)
1687323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)/**
1688926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * This function behavior depends on the "debug_devtools" flag value.
1689926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * - In debug mode it loads scripts synchronously via xhr request.
1690926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * - In release mode every occurrence of "importScript" in the js files
1691323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles) *   that have been whitelisted in the build system gets replaced with
1692926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) *   the script source code on the compilation phase.
1693323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles) *   The build system will throw an exception if it finds an importScript() call
1694926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) *   in other files.
1695926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) *
1696926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * To load scripts lazily in release mode call "loadScript" function.
16975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {string} scriptName
16985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
16995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function importScript(scriptName)
17005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1701f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    var sourceURL = self._importScriptPathPrefix + scriptName;
1702f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    if (_importedScripts[sourceURL])
17035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
1704f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    _importedScripts[sourceURL] = true;
1705323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    var scriptSource = loadResource(sourceURL);
1706323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    if (!scriptSource)
1707f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu        throw "empty response arrived for script '" + sourceURL + "'";
1708f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    var oldPrefix = self._importScriptPathPrefix;
1709f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    self._importScriptPathPrefix += scriptName.substring(0, scriptName.lastIndexOf("/") + 1);
1710f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    try {
1711323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)        self.eval(scriptSource + "\n//# sourceURL=" + sourceURL);
1712f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    } finally {
1713f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu        self._importScriptPathPrefix = oldPrefix;
1714f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    }
17155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1716926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1717f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu(function() {
1718f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    var baseUrl = location.origin + location.pathname;
1719f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    self._importScriptPathPrefix = baseUrl.substring(0, baseUrl.lastIndexOf("/") + 1);
1720f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu})();
1721f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu
1722926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)var loadScript = importScript;
1723e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1724e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)/**
1725e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles) * @constructor
1726e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles) */
1727e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)function CallbackBarrier()
1728e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles){
1729e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    this._pendingIncomingCallbacksCount = 0;
1730e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)}
1731e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1732e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)CallbackBarrier.prototype = {
1733e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    /**
173410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch     * @param {function(...)=} userCallback
173510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch     * @return {function(...)}
1736e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     */
1737e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    createCallback: function(userCallback)
1738e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    {
1739e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        console.assert(!this._outgoingCallback, "CallbackBarrier.createCallback() is called after CallbackBarrier.callWhenDone()");
1740e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        ++this._pendingIncomingCallbacksCount;
1741e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        return this._incomingCallback.bind(this, userCallback);
1742e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    },
1743e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1744e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    /**
1745e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     * @param {function()} callback
1746e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)     */
1747e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    callWhenDone: function(callback)
1748e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    {
1749e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        console.assert(!this._outgoingCallback, "CallbackBarrier.callWhenDone() is called multiple times");
1750e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        this._outgoingCallback = callback;
1751e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (!this._pendingIncomingCallbacksCount)
1752e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            this._outgoingCallback();
1753e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    },
1754e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
1755e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    /**
1756f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)     * @param {function(...)=} userCallback
1757e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch     */
1758e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    _incomingCallback: function(userCallback)
1759e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    {
1760e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        console.assert(this._pendingIncomingCallbacksCount > 0);
1761e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (userCallback) {
1762e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            var args = Array.prototype.slice.call(arguments, 1);
1763e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            userCallback.apply(null, args);
1764e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        }
1765e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (!--this._pendingIncomingCallbacksCount && this._outgoingCallback)
1766e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)            this._outgoingCallback();
1767e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    }
1768e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)}
176909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
177009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)/**
177109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) * @param {*} value
177209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) */
177309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)function suppressUnused(value)
177409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
177509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
1776