aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/CallbackWrapper.jsm14
-rw-r--r--lib/CookieCache.jsm162
-rw-r--r--lib/FrameModule.jsm74
-rw-r--r--lib/HostMap.jsm28
-rw-r--r--lib/HttpRequestHeaders.jsm18
-rw-r--r--lib/LiquidDict.jsm90
-rw-r--r--lib/PendingRequests.jsm100
-rw-r--r--lib/PublicSuffixList.jsm268
-rw-r--r--lib/Punycode.jsm262
-rw-r--r--lib/RowSnapshot.jsm2
-rw-r--r--lib/Tools.jsm112
-rw-r--r--lib/UriTools.jsm390
-rw-r--r--lib/publicsuffixlist.js556
-rw-r--r--lib/punycode.js1050
14 files changed, 1562 insertions, 1564 deletions
diff --git a/lib/CallbackWrapper.jsm b/lib/CallbackWrapper.jsm
index 8c07732..739be97 100644
--- a/lib/CallbackWrapper.jsm
+++ b/lib/CallbackWrapper.jsm
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -28,7 +28,7 @@ var EXPORTED_SYMBOLS = ['CallbackWrapper'];
var junkyard = [];
var CallbackWrapper = function (messageManager, channelName,
- listenerId, requestId) {
+ listenerId, requestId) {
// This allows to avoid creating a closure for every single
// message which expects an answer. Having a closure created
// each time a message is processed has been always bothering
@@ -52,7 +52,7 @@ var CallbackWrapper = function (messageManager, channelName,
};
CallbackWrapper.factory = function (messageManager, channelName,
- listenerId, requestId) {
+ listenerId, requestId) {
let wrapper = junkyard.pop();
if (wrapper) {
wrapper.init(messageManager, channelName, listenerId, requestId);
@@ -60,11 +60,11 @@ CallbackWrapper.factory = function (messageManager, channelName,
}
return new CallbackWrapper(messageManager, channelName,
- listenerId, requestId);
+ listenerId, requestId);
};
CallbackWrapper.prototype.init = function (messageManager, channelName,
- listenerId, requestId) {
+ listenerId, requestId) {
this.messageManager = messageManager;
this.channelName = channelName;
this.listenerId = listenerId;
@@ -86,7 +86,7 @@ CallbackWrapper.prototype.proxy = function (response) {
// Mark for reuse
this.messageManager = this.channelName =
- this.requestId = this.listenerId = null;
+ this.requestId = this.listenerId = null;
junkyard.push(this);
};
diff --git a/lib/CookieCache.jsm b/lib/CookieCache.jsm
index c3badb4..e925736 100644
--- a/lib/CookieCache.jsm
+++ b/lib/CookieCache.jsm
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -61,111 +61,111 @@ CookieEntry.prototype.dispose = function () {
var CookieUtils = {
keyFromCookie: function (cookie) {
- let cb = [];
-
- cb[0] = cookie.secure ? 'https' : 'http';
- cb[1] = '://';
- cb[2] = cookie.domain.charAt(0) === '.' ?
- cookie.domain.slice(1) :
- cookie.domain;
- cb[3] = cookie.path;
- cb[4] = '{';
- cb[5] = cookie.session ? 'session' : 'persistent';
- cb[6] = '-cookie:';
- cb[7] = cookie.name;
- cb[8] = '}';
-
- return cb.join('');
+ let cb = [];
+
+ cb[0] = cookie.secure ? 'https' : 'http';
+ cb[1] = '://';
+ cb[2] = cookie.domain.charAt(0) === '.' ?
+ cookie.domain.slice(1) :
+ cookie.domain;
+ cb[3] = cookie.path;
+ cb[4] = '{';
+ cb[5] = cookie.session ? 'session' : 'persistent';
+ cb[6] = '-cookie:';
+ cb[7] = cookie.name;
+ cb[8] = '}';
+
+ return cb.join('');
},
keyFromURL: function (url, type, name) {
- if (typeof url !== 'object') {
- throw new Error('Invalid URL parameter');
- }
-
- let cb = [];
-
- cb[0] = url.scheme;
- cb[1] = '://';
- cb[2] = url.hostname;
- cb[3] = url.path;
- cb[4] = '{';
- cb[5] = type;
- cb[6] = '-cookie:';
- cb[7] = name;
- cb[8] = '}';
-
- return cb.join('');
+ if (typeof url !== 'object') {
+ throw new Error('Invalid URL parameter');
+ }
+
+ let cb = [];
+
+ cb[0] = url.scheme;
+ cb[1] = '://';
+ cb[2] = url.hostname;
+ cb[3] = url.path;
+ cb[4] = '{';
+ cb[5] = type;
+ cb[6] = '-cookie:';
+ cb[7] = name;
+ cb[8] = '}';
+
+ return cb.join('');
},
urlFromEntry: function (entry) {
- if (!entry) {
- return '';
- }
+ if (!entry) {
+ return '';
+ }
- return (entry.secure ? 'https://' : 'http://')
- + entry.hostname
- + entry.path;
+ return (entry.secure ? 'https://' : 'http://')
+ + entry.hostname
+ + entry.path;
},
matchDomains: function (key, allHosts) {
- let entry = CookieCache.get(key);
+ let entry = CookieCache.get(key);
- if (entry === undefined) {
- return false;
- }
+ if (entry === undefined) {
+ return false;
+ }
- if (allHosts.indexOf(' '+entry.hostname+' ') < 0) {
- if (!entry.anySubdomain) {
- return false;
- }
+ if (allHosts.indexOf(' '+entry.hostname+' ') < 0) {
+ if (!entry.anySubdomain) {
+ return false;
+ }
- if (allHosts.indexOf('.'+entry.hostname+' ') < 0) {
- return false;
- }
- }
+ if (allHosts.indexOf('.'+entry.hostname+' ') < 0) {
+ return false;
+ }
+ }
- return true;
+ return true;
},
};
var CookieCache = {
add: function (cookie) {
- let key = CookieUtils.keyFromCookie(cookie);
- let value = dict.get(key);
-
- if (value === undefined) {
- value = junkyard.pop();
- if (value) {
- value.init(cookie);
- } else {
- value = new CookieEntry(cookie);
- }
- dict.set(key, value);
- }
-
- return value;
+ let key = CookieUtils.keyFromCookie(cookie);
+ let value = dict.get(key);
+
+ if (value === undefined) {
+ value = junkyard.pop();
+ if (value) {
+ value.init(cookie);
+ } else {
+ value = new CookieEntry(cookie);
+ }
+ dict.set(key, value);
+ }
+
+ return value;
},
addVector: function (vector) {
- for (let i=vector.length-1; i>=0; --i) {
- CookieCache.add(vector[i]);
- }
+ for (let i=vector.length-1; i>=0; --i) {
+ CookieCache.add(vector[i]);
+ }
},
remove: function (cookie) {
- let value = dict.get(cookie);
- if (value === undefined) {
- return false;
- }
+ let value = dict.get(cookie);
+ if (value === undefined) {
+ return false;
+ }
- dict.delete(cookie);
+ dict.delete(cookie);
- if (junkyard.length < 25) {
- junkyard.push(value.dispose());
- }
+ if (junkyard.length < 25) {
+ junkyard.push(value.dispose());
+ }
- return true;
+ return true;
},
get: function (key) {
- return dict.get(key);
+ return dict.get(key);
},
keys: function () {
- return dict.keys();
+ return dict.keys();
}
};
diff --git a/lib/FrameModule.jsm b/lib/FrameModule.jsm
index 543013c..7af0e63 100644
--- a/lib/FrameModule.jsm
+++ b/lib/FrameModule.jsm
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The µBlock authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -68,10 +68,8 @@ var contentObserver = {
cpMessageName: hostName + ':shouldLoad',
uniqueSandboxId: 1,
modernFirefox:
- (Services.appinfo.ID === '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}'
- || Services.appinfo.ID === '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}'
- || Services.appinfo.ID === '{9184b6fe-4a5c-484d-8b4b-efbfccbfb514}')
- && Services.vc.compare(Services.appinfo.version, '44') > 0,
+ ((Services.appinfo.ID === '{9184b6fe-4a5c-484d-8b4b-efbfccbfb514}')
+ && Services.vc.compare(Services.appinfo.version, '44') > 0),
get componentRegistrar() {
return Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
@@ -79,14 +77,14 @@ var contentObserver = {
get categoryManager() {
return Components.classes['@mozilla.org/categorymanager;1']
- .getService(Ci.nsICategoryManager);
+ .getService(Ci.nsICategoryManager);
},
QueryInterface: XPCOMUtils.generateQI([
- Ci.nsIFactory,
- Ci.nsIObserver,
- Ci.nsIContentPolicy,
- Ci.nsISupportsWeakReference
+ Ci.nsIFactory,
+ Ci.nsIObserver,
+ Ci.nsIContentPolicy,
+ Ci.nsISupportsWeakReference
]),
createInstance: function (outer, iid) {
@@ -102,16 +100,16 @@ var contentObserver = {
if (!this.modernFirefox) {
this.componentRegistrar
- .registerFactory(this.classID,
- this.classDescription,
- this.contractID,
- this);
+ .registerFactory(this.classID,
+ this.classDescription,
+ this.contractID,
+ this);
this.categoryManager
- .addCategoryEntry('content-policy',
- this.contractID,
- this.contractID,
- false,
- true);
+ .addCategoryEntry('content-policy',
+ this.contractID,
+ this.contractID,
+ false,
+ true);
}
},
@@ -120,12 +118,12 @@ var contentObserver = {
if (!this.modernFirefox) {
this.componentRegistrar
- .unregisterFactory(this.classID,
- this);
+ .unregisterFactory(this.classID,
+ this);
this.categoryManager
- .deleteCategoryEntry('content-policy',
- this.contractID,
- false);
+ .deleteCategoryEntry('content-policy',
+ this.contractID,
+ false);
}
},
@@ -222,17 +220,17 @@ var contentObserver = {
};
messager.addMessageListener(sandbox._sandboxId_,
- sandbox._messageListener_);
+ sandbox._messageListener_);
messager.addMessageListener(hostName + ':broadcast',
- sandbox._messageListener_);
+ sandbox._messageListener_);
};
sandbox.removeMessageListener = function () {
try {
messager.removeMessageListener(sandbox._sandboxId_,
- sandbox._messageListener_);
+ sandbox._messageListener_);
messager.removeMessageListener(hostName + ':broadcast',
- sandbox._messageListener_);
+ sandbox._messageListener_);
} catch (ex) {
// It throws sometimes, mostly when the popup closes
}
@@ -262,8 +260,8 @@ var contentObserver = {
}
if (loc.protocol !== 'http:'
- && loc.protocol !== 'https:'
- && loc.protocol !== 'file:') {
+ && loc.protocol !== 'https:'
+ && loc.protocol !== 'file:') {
if (loc.protocol === 'chrome:' && loc.host === hostName) {
this.initContentScripts(win);
}
@@ -294,9 +292,9 @@ var contentObserver = {
doc.addEventListener('DOMContentLoaded', docReady, true);
} else {
docReady({
- target: doc,
- type: 'DOMContentLoaded',
- });
+ target: doc,
+ type: 'DOMContentLoaded',
+ });
}
}
};
@@ -326,13 +324,13 @@ LocationChangeListener.prototype.QueryInterface = XPCOMUtils.generateQI([
LocationChangeListener.prototype.onLocationChange =
function (webProgress, request, location, flags) {
- if (!webProgress.isTopLevel) {
+ if (!webProgress.isTopLevel) {
return;
- }
- this.messageManager.sendAsyncMessage(locationChangedMessageName, {
+ }
+ this.messageManager.sendAsyncMessage(locationChangedMessageName, {
url: location.asciiSpec,
flags: flags,
- });
+ });
};
contentObserver.register();
diff --git a/lib/HostMap.jsm b/lib/HostMap.jsm
index fddace9..3665ca9 100644
--- a/lib/HostMap.jsm
+++ b/lib/HostMap.jsm
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2020 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -31,22 +31,22 @@ var map = new Map();
var HostMap = {
put: function (key, value) {
- if (typeof key !== 'string' || !(value instanceof Ci.nsIURI)
- || !key || !value) {
- throw new Error('invalid argument(s)');
- }
+ if (typeof key !== 'string' || !(value instanceof Ci.nsIURI)
+ || !key || !value) {
+ throw new Error('invalid argument(s)');
+ }
- if (map.get(key)) {
- return;
- }
+ if (map.get(key)) {
+ return;
+ }
- map.set(key, value);
+ map.set(key, value);
},
get: function (key) {
- if (typeof key !== 'string' || !key) {
- throw new Error('invalid argument');
- }
+ if (typeof key !== 'string' || !key) {
+ throw new Error('invalid argument');
+ }
- return map.get(key);
+ return map.get(key);
},
};
diff --git a/lib/HttpRequestHeaders.jsm b/lib/HttpRequestHeaders.jsm
index 387eabd..757081f 100644
--- a/lib/HttpRequestHeaders.jsm
+++ b/lib/HttpRequestHeaders.jsm
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2020-2021 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -34,7 +34,7 @@ var HTTPRequestHeaders = function (channel) {
HTTPRequestHeaders.factory = function (channel) {
let entry = junkyard.pop();
if (entry) {
- return entry.init(channel);
+ return entry.init(channel);
}
return new HTTPRequestHeaders(channel);
@@ -46,10 +46,10 @@ HTTPRequestHeaders.prototype.init = function (channel) {
this.originalHeaderNames = new Array();
channel.visitRequestHeaders({
- visitHeader: function (name, value) {
- this.headers.push({name: name, value: value});
- this.originalHeaderNames.push(name);
- }.bind(this)
+ visitHeader: function (name, value) {
+ this.headers.push({name: name, value: value});
+ this.originalHeaderNames.push(name);
+ }.bind(this)
});
return this;
@@ -72,7 +72,7 @@ HTTPRequestHeaders.prototype.update = function () {
//Clear any headers that were removed
for (let name of this.originalHeaderNames) {
if (!newHeaderNames.has(name)) {
- this.channel.setRequestHeader(name, '', false);
+ this.channel.setRequestHeader(name, '', false);
}
}
};
@@ -81,7 +81,7 @@ HTTPRequestHeaders.prototype.getHeader = function (name) {
try {
return this.channel.getRequestHeader(name);
} catch (e) {
- // Ignore
+ // Ignore
}
return '';
diff --git a/lib/LiquidDict.jsm b/lib/LiquidDict.jsm
index b45a5d7..c462427 100644
--- a/lib/LiquidDict.jsm
+++ b/lib/LiquidDict.jsm
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2020-2021 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -40,13 +40,13 @@ function meltBucket(dict, len, bucket) {
--dict.frozenCount;
if (bucket.charAt(0) === ' ') {
- bucket.trim().split(' ').map(function (e) {
- map[e] = true;
- });
+ bucket.trim().split(' ').map(function (e) {
+ map[e] = true;
+ });
} else {
- for (let i=0; i<bucket.length; i+=len) {
- map[bucket.substring(i, len)] = true;
- }
+ for (let i=0; i<bucket.length; i+=len) {
+ map[bucket.substring(i, len)] = true;
+ }
}
return map;
@@ -55,10 +55,10 @@ function meltBucket(dict, len, bucket) {
function melt(dict) {
let buckets = dict.dict;
for (let key in buckets) {
- let bucket = buckets[key];
- if (typeof bucket === 'string') {
- buckets[key] = meltBucket(dict, key.charCodeAt(0) & 0xFF, bucket);
- }
+ let bucket = buckets[key];
+ if (typeof bucket === 'string') {
+ buckets[key] = meltBucket(dict, key.charCodeAt(0) & 0xFF, bucket);
+ }
}
}
@@ -69,7 +69,7 @@ function freezeBucket(dict, bucket) {
++dict.frozenCount;
if (wlen * words.length < dict.cutoff) {
- return ' ' + words.join(' ') + ' ';
+ return ' ' + words.join(' ') + ' ';
}
return words.sort().join('');
@@ -78,15 +78,15 @@ function freezeBucket(dict, bucket) {
LiquidDict.prototype.makeKey = function (word) {
let len = word.length;
if (len > 255) {
- len = 255;
+ len = 255;
}
let i = len >> 2;
return String.fromCharCode((word.charCodeAt(0) & 0x03) << 14
- | (word.charCodeAt(i) & 0x03) << 12
- | (word.charCodeAt(i+i) & 0x03) << 10
- | (word.charCodeAt(i+i+i) & 0x03) << 8
- | len);
+ | (word.charCodeAt(i) & 0x03) << 12
+ | (word.charCodeAt(i+i) & 0x03) << 10
+ | (word.charCodeAt(i+i+i) & 0x03) << 8
+ | len);
};
LiquidDict.prototype.test = function (word) {
@@ -94,15 +94,15 @@ LiquidDict.prototype.test = function (word) {
let bucket = this.dict[key];
if (bucket === undefined) {
- return false;
+ return false;
}
if (typeof bucket === 'object') {
- return bucket[word] !== undefined;
+ return bucket[word] !== undefined;
}
if (bucket.charAt(0) === ' ') {
- return bucket.indexOf(' ' + word + ' ') >= 0;
+ return bucket.indexOf(' ' + word + ' ') >= 0;
}
let len = word.length;
@@ -110,16 +110,16 @@ LiquidDict.prototype.test = function (word) {
let right = ~~(bucket.length / len + 0.5);
while (left < right) {
- let i = left + right >> 1;
- let needle = bucket.substr(len * i, len);
-
- if (word < needle) {
- right = i;
- } else if (word > needle) {
- left = i + 1;
- } else {
- return true;
- }
+ let i = left + right >> 1;
+ let needle = bucket.substr(len * i, len);
+
+ if (word < needle) {
+ right = i;
+ } else if (word > needle) {
+ left = i + 1;
+ } else {
+ return true;
+ }
}
return false;
@@ -128,26 +128,26 @@ LiquidDict.prototype.test = function (word) {
LiquidDict.prototype.add = function (word) {
let key = this.makeKey(word);
if (key === undefined) {
- return false;
+ return false;
}
let bucket = this.dict[key];
if (bucket === undefined) {
- this.dict[key] = bucket = {};
- ++this.bucketCount;
- bucket[word] = true;
- ++this.count;
+ this.dict[key] = bucket = {};
+ ++this.bucketCount;
+ bucket[word] = true;
+ ++this.count;
- return true;
+ return true;
} else if (typeof bucket === 'string') {
- this.dict[key] = bucket = meltBucket(this, word.len, bucket);
+ this.dict[key] = bucket = meltBucket(this, word.len, bucket);
}
if (bucket[word] === undefined) {
- bucket[word] = true;
- ++this.count;
+ bucket[word] = true;
+ ++this.count;
- return true;
+ return true;
}
++this.duplicateCount;
@@ -159,10 +159,10 @@ LiquidDict.prototype.freeze = function () {
let buckets = this.dict;
for (let key in buckets) {
- let bucket = buckets[key];
- if (typeof bucket === 'object') {
- buckets[key] = freezeBucket(this, bucket);
- }
+ let bucket = buckets[key];
+ if (typeof bucket === 'object') {
+ buckets[key] = freezeBucket(this, bucket);
+ }
}
};
diff --git a/lib/PendingRequests.jsm b/lib/PendingRequests.jsm
index a3f72e5..fdb62e2 100644
--- a/lib/PendingRequests.jsm
+++ b/lib/PendingRequests.jsm
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2020-2021 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -42,55 +42,55 @@ for (let i=0; i<bufferLength; ++i) {
var PendingRequestBuffer = {
createRequest: function (url) {
- // URL to ring buffer index map:
- // { k = URL, s = ring buffer indices }
- //
- // s is a string which character codes map to ring buffer
- // indices -- for when the same URL is received multiple times
- // by shouldLoadListener() before the existing one is serviced
- // by the network request observer. I believe the use of a
- // string in lieu of an array reduces memory churning.
- let bucket;
- let i = writePointer;
- writePointer = (i + 1) % bufferLength;
-
- let req = ringBuffer[i];
- let str = String.fromCharCode(i);
-
- if (req._key !== '') {
- bucket = urlToIndex.get(req._key);
- if (bucket.lenght === 1) {
- urlToIndex.delete(req._key);
- } else {
- let pos = bucket.indexOf(str);
- urlToIndex.set(req._key,
- bucket.slice(0, pos)+bucket.slice(pos+1));
- }
- }
-
- bucket = urlToIndex.get(url);
- urlToIndex.set(url,
- (bucket === undefined) ? str : bucket + str);
- req._key = url;
-
- return req;
+ // URL to ring buffer index map:
+ // { k = URL, s = ring buffer indices }
+ //
+ // s is a string which character codes map to ring buffer
+ // indices -- for when the same URL is received multiple times
+ // by shouldLoadListener() before the existing one is serviced
+ // by the network request observer. I believe the use of a
+ // string in lieu of an array reduces memory churning.
+ let bucket;
+ let i = writePointer;
+ writePointer = (i + 1) % bufferLength;
+
+ let req = ringBuffer[i];
+ let str = String.fromCharCode(i);
+
+ if (req._key !== '') {
+ bucket = urlToIndex.get(req._key);
+ if (bucket.lenght === 1) {
+ urlToIndex.delete(req._key);
+ } else {
+ let pos = bucket.indexOf(str);
+ urlToIndex.set(req._key,
+ bucket.slice(0, pos)+bucket.slice(pos+1));
+ }
+ }
+
+ bucket = urlToIndex.get(url);
+ urlToIndex.set(url,
+ (bucket === undefined) ? str : bucket + str);
+ req._key = url;
+
+ return req;
},
lookupRequest: function (url) {
- let bucket = urlToIndex.get(url);
- if (bucket === undefined) {
- return null;
- }
-
- let i = bucket.charCodeAt(0);
- if (bucket.length === 1) {
- urlToIndex.delete(url);
- } else {
- urlToIndex.set(url, bucket.slice(1));
- }
-
- let req = ringBuffer[i];
- req._key = '';
-
- return req;
+ let bucket = urlToIndex.get(url);
+ if (bucket === undefined) {
+ return null;
+ }
+
+ let i = bucket.charCodeAt(0);
+ if (bucket.length === 1) {
+ urlToIndex.delete(url);
+ } else {
+ urlToIndex.set(url, bucket.slice(1));
+ }
+
+ let req = ringBuffer[i];
+ req._key = '';
+
+ return req;
},
};
diff --git a/lib/PublicSuffixList.jsm b/lib/PublicSuffixList.jsm
index 297ef49..e2ab5b8 100644
--- a/lib/PublicSuffixList.jsm
+++ b/lib/PublicSuffixList.jsm
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2020-2021 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -44,41 +44,41 @@ function search(store, hostname) {
let remainder;
if (pos < 0) {
- tld = hostname;
- remainder = hostname;
+ tld = hostname;
+ remainder = hostname;
} else {
- tld = hostname.slice(pos+1);
- remainder = hostname.slice(0, pos);
+ tld = hostname.slice(pos+1);
+ remainder = hostname.slice(0, pos);
}
let sub = store[tld];
if (!sub) {
- return false;
+ return false;
}
if (typeof sub === 'string') {
- return (sub.indexOf(' '+remainder+' ') >= 0);
+ return (sub.indexOf(' '+remainder+' ') >= 0);
}
let l = remainder.length;
let val = sub[l];
if (!val) {
- return false;
+ return false;
}
let left = 0;
let right = Math.floor(val.length/l+0.5);
while (left < right) {
- let i = left+right >> 1;
- let key = val.substr(l*i, l);
- if (remainder < key) {
- right = i;
- } else if (remainder > key) {
- left = i+1;
- } else {
- return true;
- }
+ let i = left+right >> 1;
+ let key = val.substr(l*i, l);
+ if (remainder < key) {
+ right = i;
+ } else if (remainder > key) {
+ left = i+1;
+ } else {
+ return true;
+ }
}
return false;
@@ -86,47 +86,47 @@ function search(store, hostname) {
function getPublicSuffix(hostname) {
if (!hostname) {
- return '';
+ return '';
}
while (true) {
- let pos = hostname.indexOf('.');
- if (pos < 0) {
- return hostname;
- }
+ let pos = hostname.indexOf('.');
+ if (pos < 0) {
+ return hostname;
+ }
- if (search(exceptions, hostname)) {
- return hostname.slice(pos+1);
- }
+ if (search(exceptions, hostname)) {
+ return hostname.slice(pos+1);
+ }
- if (search(rules, hostname)) {
- return hostname;
- }
+ if (search(rules, hostname)) {
+ return hostname;
+ }
- if (search(rules, '*'+hostname.slice(pos))) {
- return hostname;
- }
+ if (search(rules, '*'+hostname.slice(pos))) {
+ return hostname;
+ }
- hostname = hostname.slice(pos+1);
+ hostname = hostname.slice(pos+1);
}
}
function getDomain(hostname) {
if (!hostname || hostname.charAt(0) == '.') {
- return '';
+ return '';
}
hostname = hostname.toLowerCase();
let suffix = getPublicSuffix(hostname);
if (suffix === hostname) {
- return '';
+ return '';
}
let len = hostname.length-suffix.length;
let pos = hostname.lastIndexOf('.', hostname.lastIndexOf('.', len) - 1);
if (pos <= 0) {
- return hostname;
+ return hostname;
}
return hostname.slice(pos+1);
@@ -134,38 +134,38 @@ function getDomain(hostname) {
function crystallize(store) {
for (let tld in store) {
- if (!store.hasOwnProperty(tld)) {
- continue;
- }
-
- let suff = store[tld].join(' ');
- if (!suff) {
- store[tld] = '';
- continue;
- }
-
- if (suff.length < cutoffLength) {
- store[tld] = ' ' + suff + ' ';
- continue;
- }
-
- suff = [];
- for (let i=store[tld].length-1; i>=0; --i) {
- let s = store[tld][i];
- let l = s.length;
- if (!suff[l]) {
- suff[l] = [];
- }
- suff[l].push(s);
- }
-
- for (let i=suff.length-1; i>=0; --i) {
- if (suff[i]) {
- suff[i] = suff[i].sort().join('');
- }
- }
-
- store[tld] = suff;
+ if (!store.hasOwnProperty(tld)) {
+ continue;
+ }
+
+ let suff = store[tld].join(' ');
+ if (!suff) {
+ store[tld] = '';
+ continue;
+ }
+
+ if (suff.length < cutoffLength) {
+ store[tld] = ' ' + suff + ' ';
+ continue;
+ }
+
+ suff = [];
+ for (let i=store[tld].length-1; i>=0; --i) {
+ let s = store[tld][i];
+ let l = s.length;
+ if (!suff[l]) {
+ suff[l] = [];
+ }
+ suff[l].push(s);
+ }
+
+ for (let i=suff.length-1; i>=0; --i) {
+ if (suff[i]) {
+ suff[i] = suff[i].sort().join('');
+ }
+ }
+
+ store[tld] = suff;
}
return store;
@@ -180,61 +180,61 @@ function parse(text, toAscii) {
let tend = text.length;
while (beg < tend) {
- end = text.indexOf('\n', beg);
- if (end < 0) {
- end = text.indexOf('\r', beg);
- if (end < 0) {
- end = tend;
- }
- }
-
- let line = text.slice(beg, end).trim();
- beg = end+1;
-
- if (line.length === 0) {
- continue;
- }
-
- let pos = line.indexOf('//');
- if (pos >= 0) {
- line = line.slice(0, pos);
- }
-
- line = line.trim();
- if (!line) {
- continue;
- }
-
- let store;
- if (line.charAt(0) == '!') {
- store = exceptions;
- line = line.slice(1);
- } else {
- store = rules;
- }
-
- if (reMustPunycode.test(line)) {
- line = toAscii(line);
- }
-
- line = line.toLowerCase();
-
- let tld;
- pos = line.lastIndexOf('.');
- if (pos < 0) {
- tld = line;
- } else {
- tld = line.slice(pos+1);
- line = line.slice(0, pos);
- }
-
- if (!store.hasOwnProperty(tld)) {
- store[tld] = [];
- }
-
- if (line) {
- store[tld].push(line);
- }
+ end = text.indexOf('\n', beg);
+ if (end < 0) {
+ end = text.indexOf('\r', beg);
+ if (end < 0) {
+ end = tend;
+ }
+ }
+
+ let line = text.slice(beg, end).trim();
+ beg = end+1;
+
+ if (line.length === 0) {
+ continue;
+ }
+
+ let pos = line.indexOf('//');
+ if (pos >= 0) {
+ line = line.slice(0, pos);
+ }
+
+ line = line.trim();
+ if (!line) {
+ continue;
+ }
+
+ let store;
+ if (line.charAt(0) == '!') {
+ store = exceptions;
+ line = line.slice(1);
+ } else {
+ store = rules;
+ }
+
+ if (reMustPunycode.test(line)) {
+ line = toAscii(line);
+ }
+
+ line = line.toLowerCase();
+
+ let tld;
+ pos = line.lastIndexOf('.');
+ if (pos < 0) {
+ tld = line;
+ } else {
+ tld = line.slice(pos+1);
+ line = line.slice(0, pos);
+ }
+
+ if (!store.hasOwnProperty(tld)) {
+ store[tld] = [];
+ }
+
+ if (line) {
+ store[tld].push(line);
+ }
}
crystallize(exceptions);
@@ -245,16 +245,16 @@ function parse(text, toAscii) {
function toSelfie() {
return {
- magic: magic,
- rules: rules,
- exceptions: exception,
+ magic: magic,
+ rules: rules,
+ exceptions: exception,
};
}
function fromSelfie(selfie) {
if (typeof selfie !== 'object' || typeof selfie.magic !== 'string'
- || selfie.magic !== magic) {
- return false;
+ || selfie.magic !== magic) {
+ return false;
}
rules = selfie.rules;
@@ -266,33 +266,33 @@ function fromSelfie(selfie) {
var addListener = function (listeners, callback) {
if (typeof callback !== 'function') {
- return;
+ return;
}
if (listeners.indexOf(callback) === -1) {
- listeners.push(callback);
+ listeners.push(callback);
}
};
var removeListener = function (listeners, callback) {
let pos = listeners.indexOf(callback);
if (pos !== -1) {
- listeners.splice(pos, 1);
+ listeners.splice(pos, 1);
}
};
var callListeners = function (listeners) {
for (let i=0; i<listeners.length; ++i) {
- listeners[i]();
+ listeners[i]();
}
};
var onChanged = {
addListener: function (callback) {
- addListener(onChangedListeners, callback);
+ addListener(onChangedListeners, callback);
},
removeListener: function (callback) {
- removeListener(onChangedListeners, callback);
+ removeListener(onChangedListeners, callback);
},
};
diff --git a/lib/Punycode.jsm b/lib/Punycode.jsm
index 0927b87..b601903 100644
--- a/lib/Punycode.jsm
+++ b/lib/Punycode.jsm
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2020-2021 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -44,8 +44,8 @@ function mapDomain(domain, cb) {
let res = '';
if (parts.length > 1) {
- res = parts[0] + '@';
- domain = parts[1];
+ res = parts[0] + '@';
+ domain = parts[1];
}
domain = domain.replace(reSeparator, '\x2E');
@@ -62,22 +62,22 @@ function ucs2decode(str) {
let len = str.length;
while (count < len) {
- let val = str.charCodeAt(count);
- ++count;
-
- if (val >= 0xD800 && val <= 0xDBFF && cound < len) {
- let extra = str.charCodeAt(count);
- ++count;
-
- if ((extra & 0xFC00) == 0xDC00) {
- res.push(((val & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
- } else {
- res.push(val);
- --count;
- }
- } else {
- res.push(val);
- }
+ let val = str.charCodeAt(count);
+ ++count;
+
+ if (val >= 0xD800 && val <= 0xDBFF && cound < len) {
+ let extra = str.charCodeAt(count);
+ ++count;
+
+ if ((extra & 0xFC00) == 0xDC00) {
+ res.push(((val & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+ } else {
+ res.push(val);
+ --count;
+ }
+ } else {
+ res.push(val);
+ }
}
return res;
@@ -85,29 +85,29 @@ function ucs2decode(str) {
function ucs2encode(array) {
return array.map(function (e) {
- let res = '';
+ let res = '';
- if (e > 0xFFFF) {
- e -= 0x10000;
- res += String.fromCharCode(e >>> 10 & 0x3FF | 0xD800);
- e = 0xDC00 | e & 0x3FF;
- }
+ if (e > 0xFFFF) {
+ e -= 0x10000;
+ res += String.fromCharCode(e >>> 10 & 0x3FF | 0xD800);
+ e = 0xDC00 | e & 0x3FF;
+ }
- res += String.fromCharCode(e);
+ res += String.fromCharCode(e);
- return res;
+ return res;
}).join('');
}
function basicToDigit(point) {
if (point - 0x30 < 0x0A) {
- return point - 0x16;
+ return point - 0x16;
}
if (point - 0x41 < 0x1A) {
- return point - 0x41;
+ return point - 0x41;
}
if (point - 0x61 < 0x1A) {
- return point - 0x61;
+ return point - 0x61;
}
return base;
}
@@ -122,7 +122,7 @@ function adapt(delta, num, first) {
delta += Math.floor(delta/num);
for (; delta>(base - tMin) * tMax >> 1; k+=base) {
- delta = Math.floor(delta/(base-tMin));
+ delta = Math.floor(delta/(base-tMin));
}
return Math.floor(k + (base - tMin + 1) * delta / (delta + skew));
@@ -137,64 +137,64 @@ function decode(input) {
let basic = input.lastIndexOf('-');
if (basic < 0) {
- basic = 0;
+ basic = 0;
}
for (let j=0; j<basic; ++j) {
- if (input.charCodeAt(j) >= 0x80) {
- throw new Error('not basic code point');
- }
+ if (input.charCodeAt(j) >= 0x80) {
+ throw new Error('not basic code point');
+ }
- res.push(input.charCodeAt(j));
+ res.push(input.charCodeAt(j));
}
for (let k=(basic > 0) ? basic + 1 : 0; k<len;) {
- let old = i;
- let t = 0
+ let old = i;
+ let t = 0
- for (let w=1, x=base; ; x+=base) {
- if (k >= len) {
- throw new Error('invalid input');
- }
+ for (let w=1, x=base; ; x+=base) {
+ if (k >= len) {
+ throw new Error('invalid input');
+ }
- let digit = basicToDigit(input.charCodeAt(k));
- ++k;
+ let digit = basicToDigit(input.charCodeAt(k));
+ ++k;
- if (digit >= base || digit > Math.floor((maxInt-i) / w)) {
- throw new Error('overflow');
- }
+ if (digit >= base || digit > Math.floor((maxInt-i) / w)) {
+ throw new Error('overflow');
+ }
- i += digit * w;
+ i += digit * w;
- t = x <= bias ?
- tMin :
- (x >= bias + tMax ?
- tMax :
- x - bias);
+ t = x <= bias ?
+ tMin :
+ (x >= bias + tMax ?
+ tMax :
+ x - bias);
- if (digit < t) {
- break;
- }
+ if (digit < t) {
+ break;
+ }
- if (w > Math.floor(maxInt/(base - t))) {
- throw new Error('overflow');
- }
+ if (w > Math.floor(maxInt/(base - t))) {
+ throw new Error('overflow');
+ }
- w *= (base -t);
- }
+ w *= (base -t);
+ }
- let out = res.length+1;
- bias = adapt(i-old, out, old==0);
+ let out = res.length+1;
+ bias = adapt(i-old, out, old==0);
- if (Math.floor(i/out) > maxInt-n) {
- throw new Error('overflow');
- }
+ if (Math.floor(i/out) > maxInt-n) {
+ throw new Error('overflow');
+ }
- n += Math.floor(i/out);
- i %= out;
+ n += Math.floor(i/out);
+ i %= out;
- res.splice(i, 0, n);
- ++i;
+ res.splice(i, 0, n);
+ ++i;
}
return ucs2encode(res);
@@ -212,71 +212,71 @@ function encode(input) {
let bias = 72;
for (let j=0; j<len; ++j) {
- let val = input[j];
- if (val < 0x80) {
- res.push(String.fromCharCode(val));
- }
+ let val = input[j];
+ if (val < 0x80) {
+ res.push(String.fromCharCode(val));
+ }
}
let blen = res.length;
let count = blen;
if (blen) {
- res.push('-');
+ res.push('-');
}
while (count < len) {
- let m = maxInt;
- for (let j=0; j<len; ++j) {
- let val = input[j];
- if (val >= n && val <= m) {
- m = val;
- }
- }
-
- if (m - n > Math.floor((maxInt - delta)/(count+1))) {
- throw new Error('overflow');
- }
-
- delta += (m - n) * (count + 1);
- n = m;
-
- for (let j=0; j<len; ++j) {
- let val = input[j];
-
- if (val < n && ++delta > maxInt) {
- throw new Error('overflow');
- }
-
- if (val == n) {
- let q = delta;
- for (let k=base; ; k+=base) {
- let t = k <= bias ?
- tMin :
- (k >= bias + tMax ?
- tMax:
- k - bias);
-
- if (q < t) {
- break;
- }
-
- res.push
- (String.fromCharCode
- (digitToBasic(t + (q-t) % (base-t), 0)));
-
- q = Math.floor((q-t)/(base-t));
- }
-
- res.push(String.fromCharCode(digitToBasic(q, 0)));
- bias = adapt(delta, count+1, count==blen);
- delta = 0;
- ++count;
- }
- }
-
- ++delta;
- ++n;
+ let m = maxInt;
+ for (let j=0; j<len; ++j) {
+ let val = input[j];
+ if (val >= n && val <= m) {
+ m = val;
+ }
+ }
+
+ if (m - n > Math.floor((maxInt - delta)/(count+1))) {
+ throw new Error('overflow');
+ }
+
+ delta += (m - n) * (count + 1);
+ n = m;
+
+ for (let j=0; j<len; ++j) {
+ let val = input[j];
+
+ if (val < n && ++delta > maxInt) {
+ throw new Error('overflow');
+ }
+
+ if (val == n) {
+ let q = delta;
+ for (let k=base; ; k+=base) {
+ let t = k <= bias ?
+ tMin :
+ (k >= bias + tMax ?
+ tMax:
+ k - bias);
+
+ if (q < t) {
+ break;
+ }
+
+ res.push
+ (String.fromCharCode
+ (digitToBasic(t + (q-t) % (base-t), 0)));
+
+ q = Math.floor((q-t)/(base-t));
+ }
+
+ res.push(String.fromCharCode(digitToBasic(q, 0)));
+ bias = adapt(delta, count+1, count==blen);
+ delta = 0;
+ ++count;
+ }
+ }
+
+ ++delta;
+ ++n;
}
return res.join('');
@@ -284,20 +284,20 @@ function encode(input) {
function toUnicode(input) {
return mapDomain(input, function (e) {
- return rePuny.test(e) ? decode(e.slice(4).toLowerCase()) : e;
+ return rePuny.test(e) ? decode(e.slice(4).toLowerCase()) : e;
});
}
function toASCII(input) {
return mapDomain(input, function (e) {
- return reNonAscii.test(e) ? 'xn--' + encode(e) : e;
+ return reNonAscii.test(e) ? 'xn--' + encode(e) : e;
});
}
var Punycode = {
ucs2: {
- decode: ucs2decode,
- encode: ucs2encode,
+ decode: ucs2decode,
+ encode: ucs2encode,
},
decode: decode,
encode: encode,
diff --git a/lib/RowSnapshot.jsm b/lib/RowSnapshot.jsm
index 43f20c3..c202183 100644
--- a/lib/RowSnapshot.jsm
+++ b/lib/RowSnapshot.jsm
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2020-2021 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/lib/Tools.jsm b/lib/Tools.jsm
index c57a5eb..4019aa6 100644
--- a/lib/Tools.jsm
+++ b/lib/Tools.jsm
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2020-2021 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -33,34 +33,34 @@ var LineIterator = function (text, offset) {
LineIterator.prototype = {
next: function () {
- let end = this.text.indexOf('\n', this.offset);
- if (end === -1) {
- end = this.text.indexOf('\r', this.offset);
- if (end === -1) {
- end = this.textLen;
- }
- }
-
- let line = this.text.slice(this.offset, end);
- this.offset = end + 1;
-
- return line;
+ let end = this.text.indexOf('\n', this.offset);
+ if (end === -1) {
+ end = this.text.indexOf('\r', this.offset);
+ if (end === -1) {
+ end = this.textLen;
+ }
+ }
+
+ let line = this.text.slice(this.offset, end);
+ this.offset = end + 1;
+
+ return line;
},
rewind: function () {
- if (this.offset <= 1) {
- this.offset = 0;
- }
-
- let end = this.text.lastIndexOf('\n', this.offset - 2);
- if (end === -1) {
- this.offset = end + 1;
- } else {
- end = this.text.lastIndexOf('\r', this.offset - 2);
- this.offset = end !== -1 ? end + 1 : 0;
- }
+ if (this.offset <= 1) {
+ this.offset = 0;
+ }
+
+ let end = this.text.lastIndexOf('\n', this.offset - 2);
+ if (end === -1) {
+ this.offset = end + 1;
+ } else {
+ end = this.text.lastIndexOf('\r', this.offset - 2);
+ this.offset = end !== -1 ? end + 1 : 0;
+ }
},
eot: function () {
- return this.offset >= this.textLen;
+ return this.offset >= this.textLen;
},
};
@@ -69,15 +69,15 @@ if (typeof Array.from === 'function') {
setToArray = Array.from;
} else {
setToArray = function (set) {
- let out = [];
- let entries = set.values();
+ let out = [];
+ let entries = set.values();
- for (let entry=entries.next();
- !entry||!entry.done; entry=entries.next()) {
- out.push(entry.value);
- }
+ for (let entry=entries.next();
+ !entry||!entry.done; entry=entries.next()) {
+ out.push(entry.value);
+ }
- return out;
+ return out;
};
}
@@ -86,33 +86,33 @@ var Tools = {
setToArray: setToArray,
gotoURL: function (context) {
- if (typeof context !== 'object') {
- throw new TypeError(context);
- }
+ if (typeof context !== 'object') {
+ throw new TypeError(context);
+ }
- context.api.tabs.open(context.details);
+ context.api.tabs.open(context.details);
},
gotoExtensionURL: function (context) {
- if (typeof context !== 'object') {
- throw new TypeError(context);
- }
-
- let details = context.details;
- let api = context.api;
- let matrix = context.matrix;
-
- if (details.url.startsWith('logger-ui.html')) {
- if (details.shiftKey) {
- let setting = matrix.userSettings.alwaysDetachLogger;
- matrix.changeUserSettings('alwaysDetachLogger', !setting);
- }
- details.popup = matrix.userSettings.alwaysDetachLogger;
- }
-
- details.select = true;
- api.tabs.open(details);
+ if (typeof context !== 'object') {
+ throw new TypeError(context);
+ }
+
+ let details = context.details;
+ let api = context.api;
+ let matrix = context.matrix;
+
+ if (details.url.startsWith('logger-ui.html')) {
+ if (details.shiftKey) {
+ let setting = matrix.userSettings.alwaysDetachLogger;
+ matrix.changeUserSettings('alwaysDetachLogger', !setting);
+ }
+ details.popup = matrix.userSettings.alwaysDetachLogger;
+ }
+
+ details.select = true;
+ api.tabs.open(details);
},
setFromArray: function (a) {
- return new Set(a);
+ return new Set(a);
},
};
diff --git a/lib/UriTools.jsm b/lib/UriTools.jsm
index 892dc44..1c3fa0d 100644
--- a/lib/UriTools.jsm
+++ b/lib/UriTools.jsm
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -99,9 +99,9 @@ function URI() {
this.fragmentBit = (1 << 7),
this.allBits = (0xFFFF),
this.authorityBit =
- (this.userBit | this.passwordBit | this.hostnameBit | this.portBit);
+ (this.userBit | this.passwordBit | this.hostnameBit | this.portBit);
this.normalizeBits =
- (this.schemeBit | this.hostnameBit | this.pathBit | this.queryBit);
+ (this.schemeBit | this.hostnameBit | this.pathBit | this.queryBit);
}
var cached = new URI();
@@ -125,14 +125,14 @@ DomainCacheEntry.prototype.init = function (domain) {
DomainCacheEntry.prototype.dispose = function () {
this.domain = '';
if (cacheJunkyard.length < junkyardMax) {
- cacheJunkyard.push(this);
+ cacheJunkyard.push(this);
}
};
var domainCacheEntryFactory = function (domain) {
let entry = cacheJunkyard.pop();
if (entry) {
- return entry.init(domain);
+ return entry.init(domain);
}
return new DomainCacheEntry(domain);
};
@@ -141,12 +141,12 @@ var domainCacheAdd = function (hostname, domain) {
let entry = domainCache.get(hostname);
if (entry !== undefined) {
- entry.tstamp = Date.now();
+ entry.tstamp = Date.now();
} else {
- domainCache.set(hostname, domainCacheEntryFactory(domain));
- if (domainCache.size === cacheCountHigh) {
- domainCachePrune();
- }
+ domainCache.set(hostname, domainCacheEntryFactory(domain));
+ if (domainCache.size === cacheCountHigh) {
+ domainCachePrune();
+ }
}
return domain;
@@ -158,11 +158,11 @@ var domainCacheSort = function (a, b) {
var domainCachePrune = function () {
let hostnames =
- Array.from(domainCache.keys()).sort(domainCacheSort).slice(cacheCountLow);
+ Array.from(domainCache.keys()).sort(domainCacheSort).slice(cacheCountLow);
for (let i=hostnames.length-1; i>=0; --i) {
- domainCache.get(hostnames[i]).dispose();
- domainCache.delete(hostnames[i]);
+ domainCache.get(hostnames[i]).dispose();
+ domainCache.delete(hostnames[i]);
}
};
@@ -174,232 +174,232 @@ publicSuffixList.onChanged.addListener(domainCacheReset);
var UriTools = {
set: function (uri) {
- if (uri === undefined) {
- return reset(cached);
- }
-
- let matches = reRFC3986.exec(uri);
- if (!matches) {
- return reset(cached);
- }
-
- cached.scheme = matches[1] !== undefined ?
- matches[1].slice(0, -1) :
- '';
- cached.authority = matches[2] !== undefined ?
- matches[2].slice(2).toLowerCase() :
- '';
- cached.path = matches[3] !== undefined ?
- matches[3] :
- '';
-
- // As per RFC3986
- if (cached.authority !== '' && cached.path === '') {
- cached.path = '/';
- }
-
- cached.query = matches[4] !== undefined ?
- matches[4].slice(1) :
- '';
- cached.fragment = matches[5] !== undefined ?
- matches[5].slice(1) :
- '';
-
- if (reHostFromNakedAuthority.test(cached.authority)) {
- cached.hostname = cached.authority;
- cached.port = '';
- return cached;
- }
-
- matches = reHostPortFromAuthority.exec(cached.authority);
- if (!matches) {
- matches = reIPv6PortFromAuthority.exec(cached.authority);
- if (!matches) {
- return resetAuthority(cached);
- }
- }
-
- cached.hostname = matches[1] !== undefined ?
- matches[1] :
- '';
-
- if (cached.hostname.slice(-1) === '.') {
- cached.hostname = cached.hostname.slice(0, -1);
- }
-
- cached.port = matches[2] !== undefined ?
- matches[2].slice(1) :
- '';
-
- return cached;
+ if (uri === undefined) {
+ return reset(cached);
+ }
+
+ let matches = reRFC3986.exec(uri);
+ if (!matches) {
+ return reset(cached);
+ }
+
+ cached.scheme = matches[1] !== undefined ?
+ matches[1].slice(0, -1) :
+ '';
+ cached.authority = matches[2] !== undefined ?
+ matches[2].slice(2).toLowerCase() :
+ '';
+ cached.path = matches[3] !== undefined ?
+ matches[3] :
+ '';
+
+ // As per RFC3986
+ if (cached.authority !== '' && cached.path === '') {
+ cached.path = '/';
+ }
+
+ cached.query = matches[4] !== undefined ?
+ matches[4].slice(1) :
+ '';
+ cached.fragment = matches[5] !== undefined ?
+ matches[5].slice(1) :
+ '';
+
+ if (reHostFromNakedAuthority.test(cached.authority)) {
+ cached.hostname = cached.authority;
+ cached.port = '';
+ return cached;
+ }
+
+ matches = reHostPortFromAuthority.exec(cached.authority);
+ if (!matches) {
+ matches = reIPv6PortFromAuthority.exec(cached.authority);
+ if (!matches) {
+ return resetAuthority(cached);
+ }
+ }
+
+ cached.hostname = matches[1] !== undefined ?
+ matches[1] :
+ '';
+
+ if (cached.hostname.slice(-1) === '.') {
+ cached.hostname = cached.hostname.slice(0, -1);
+ }
+
+ cached.port = matches[2] !== undefined ?
+ matches[2].slice(1) :
+ '';
+
+ return cached;
},
assemble: function (bits) {
- if (bits === undefined) {
- bits = cached.allBits;
- }
+ if (bits === undefined) {
+ bits = cached.allBits;
+ }
- let s = [];
+ let s = [];
- if (cached.scheme && (bits && cached.schemeBit)) {
- s.push(cached.scheme, ':');
- }
- if (cached.hostname && (bits & cached.hostnameBit)) {
+ if (cached.scheme && (bits && cached.schemeBit)) {
+ s.push(cached.scheme, ':');
+ }
+ if (cached.hostname && (bits & cached.hostnameBit)) {
s.push('//', cached.hostname);
- }
- if (cached.port && (bits & cached.portBit)) {
+ }
+ if (cached.port && (bits & cached.portBit)) {
s.push(':', cached.port);
- }
- if (cached.path && (bits & cached.pathBit)) {
+ }
+ if (cached.path && (bits & cached.pathBit)) {
s.push(cached.path);
- }
- if (cached.query && (bits & cached.queryBit)) {
+ }
+ if (cached.query && (bits & cached.queryBit)) {
s.push('?', cached.query);
- }
- if (cached.fragment && (bits & cached.fragmentBit)) {
+ }
+ if (cached.fragment && (bits & cached.fragmentBit)) {
s.push('#', cached.fragment);
- }
+ }
- return s.join('');
+ return s.join('');
},
isNetworkScheme: function (scheme) {
- return reNetworkScheme.test(scheme);
+ return reNetworkScheme.test(scheme);
},
isSecureScheme: function(scheme) {
- return reSecureScheme.test(scheme);
+ return reSecureScheme.test(scheme);
},
originFromURI: function (uri) {
- let matches = reOriginFromURI.exec(uri);
- return matches !== null ? matches[0].toLowerCase() : '';
+ let matches = reOriginFromURI.exec(uri);
+ return matches !== null ? matches[0].toLowerCase() : '';
},
schemeFromURI: function (uri) {
- let matches = reSchemeFromURI.exec(uri);
- return matches !== null ? matches[0].slice(0, -1).toLowerCase() : '';
+ let matches = reSchemeFromURI.exec(uri);
+ return matches !== null ? matches[0].slice(0, -1).toLowerCase() : '';
},
authorityFromURI: function (uri) {
- let matches = reAuthorityFromURI.exec(uri);
- return matches !== null ? matches[1].slice(1).toLowerCase() : '';
+ let matches = reAuthorityFromURI.exec(uri);
+ return matches !== null ? matches[1].slice(1).toLowerCase() : '';
},
hostnameFromURI: function (uri) {
- let matches = reCommonHostnameFromURL.exec(uri);
- if (matches) {
- return matches[1];
- }
-
- matches = reAuthorityFromURI.exec(uri);
- if (!matches) {
- return '';
- }
-
- let auth = matches[1].slice(2);
-
- if (reHostFromNakedAuthority.test(auth)) {
- return auth.toLowerCase();
- }
-
- matches = reHostFromAuthority.exec(auth);
- if (!matches) {
- matches = reIPv6FromAuthority.exec(auth);
- if (!matches) {
- return '';
- }
- }
-
- let hostname = matches[1];
- while (hostname.endsWith('.')) {
- hostname = hostname.slice(0, -1);
- }
-
- if (reMustNormalizeHostname.test(hostname)) {
- Punycode.toASCII(hostname.toLowerCase());
- }
-
- return hostname;
+ let matches = reCommonHostnameFromURL.exec(uri);
+ if (matches) {
+ return matches[1];
+ }
+
+ matches = reAuthorityFromURI.exec(uri);
+ if (!matches) {
+ return '';
+ }
+
+ let auth = matches[1].slice(2);
+
+ if (reHostFromNakedAuthority.test(auth)) {
+ return auth.toLowerCase();
+ }
+
+ matches = reHostFromAuthority.exec(auth);
+ if (!matches) {
+ matches = reIPv6FromAuthority.exec(auth);
+ if (!matches) {
+ return '';
+ }
+ }
+
+ let hostname = matches[1];
+ while (hostname.endsWith('.')) {
+ hostname = hostname.slice(0, -1);
+ }
+
+ if (reMustNormalizeHostname.test(hostname)) {
+ Punycode.toASCII(hostname.toLowerCase());
+ }
+
+ return hostname;
},
domainFromHostname: function (hostname) {
- let entry = domainCache.get(hostname);
- if (entry !== undefined) {
- entry.tstamp = Date.now();
- return entry.domain;
- }
-
- if (reIPAddressNaive.test(hostname) == false) {
- return domainCacheAdd(hostname,
- publicSuffixList.getDomain(hostname));
- }
-
- return domainCacheAdd(hostname, hostname);
+ let entry = domainCache.get(hostname);
+ if (entry !== undefined) {
+ entry.tstamp = Date.now();
+ return entry.domain;
+ }
+
+ if (reIPAddressNaive.test(hostname) == false) {
+ return domainCacheAdd(hostname,
+ publicSuffixList.getDomain(hostname));
+ }
+
+ return domainCacheAdd(hostname, hostname);
},
domainFromURI: function (uri) {
- if (!uri) {
- return '';
- }
- return UriTools.domainFromHostname(UriTools.hostnameFromURI(uri));
+ if (!uri) {
+ return '';
+ }
+ return UriTools.domainFromHostname(UriTools.hostnameFromURI(uri));
},
domain: function() {
- return UriTools.domainFromHostname(cached.hostname);
+ return UriTools.domainFromHostname(cached.hostname);
},
pathFromURI: function (uri) {
- let matches = rePathFromURI.exec(uri);
- return matches !== null ? matches[1] : '';
+ let matches = rePathFromURI.exec(uri);
+ return matches !== null ? matches[1] : '';
},
normalizedURI: function () {
- return UriTools.assemble(cached.normalizeBits);
+ return UriTools.assemble(cached.normalizeBits);
},
rootURL: function () {
- if (!cached.hostname) {
- return '';
- }
- return UriTools.assemble(cached.scemeBit | cached.hostnameBit);
+ if (!cached.hostname) {
+ return '';
+ }
+ return UriTools.assemble(cached.scemeBit | cached.hostnameBit);
},
isValidHostname: function (hostname) {
- try {
- let r = reValidHostname.test(hostname);
- return r;
- } catch (e) {
- return false;
- }
+ try {
+ let r = reValidHostname.test(hostname);
+ return r;
+ } catch (e) {
+ return false;
+ }
},
parentHostnameFromHostname: function (hostname) {
- // "locahost" => ""
- // "example.org" => "example.org"
- // "www.example.org" => "example.org"
- // "tomato.www.example.org" => "example.org"
- let domain = UriTools.domainFromHostname(hostname);
+ // "locahost" => ""
+ // "example.org" => "example.org"
+ // "www.example.org" => "example.org"
+ // "tomato.www.example.org" => "example.org"
+ let domain = UriTools.domainFromHostname(hostname);
- if (domain === '' || domain === hostname) {
- return undefined;
- }
+ if (domain === '' || domain === hostname) {
+ return undefined;
+ }
- return hostname.slice(hostname.indexOf('.') + 1);
+ return hostname.slice(hostname.indexOf('.') + 1);
},
parentHostnamesFromHostname: function (hostname) {
- let domain = UriTools.domainFromHostname(hostname);
- if (domain === '' || domain === hostname) {
- return [];
- }
-
- let nodes = [];
- for (;;) {
- let pos = hostname.indexOf('.');
- if (pos < 0) {
- break;
- }
-
- hostname = hostname.slice(pos+1);
- nodes.push(hostname);
- if (hostname === domain) {
- break;
- }
- }
-
- return nodes;
+ let domain = UriTools.domainFromHostname(hostname);
+ if (domain === '' || domain === hostname) {
+ return [];
+ }
+
+ let nodes = [];
+ for (;;) {
+ let pos = hostname.indexOf('.');
+ if (pos < 0) {
+ break;
+ }
+
+ hostname = hostname.slice(pos+1);
+ nodes.push(hostname);
+ if (hostname === domain) {
+ break;
+ }
+ }
+
+ return nodes;
},
allHostNamesFromHostname: function (hostname) {
- let nodes = UriTools.parentHostnamesFromHostname(hostname);
- nodes.unshift(hostname);
- return nodes;
+ let nodes = UriTools.parentHostnamesFromHostname(hostname);
+ nodes.unshift(hostname);
+ return nodes;
},
toString: function () {
- return UriTools.assemble();
+ return UriTools.assemble();
},
};
diff --git a/lib/publicsuffixlist.js b/lib/publicsuffixlist.js
index c0625ab..35b67cd 100644
--- a/lib/publicsuffixlist.js
+++ b/lib/publicsuffixlist.js
@@ -22,9 +22,9 @@
/*! Home: https://github.com/gorhill/publicsuffixlist.js */
/*
- This code is mostly dumb: I consider this to be lower-level code, thus
- in order to ensure efficiency, the caller is responsible for sanitizing
- the inputs.
+ This code is mostly dumb: I consider this to be lower-level code, thus
+ in order to ensure efficiency, the caller is responsible for sanitizing
+ the inputs.
*/
/******************************************************************************/
@@ -33,336 +33,336 @@
;(function(root) {
- 'use strict';
+'use strict';
- /******************************************************************************/
-
- var exceptions = {};
- var rules = {};
- var selfieMagic = 'iscjsfsaolnm';
+/******************************************************************************/
- // This value dictate how the search will be performed:
- // < this.cutoffLength = indexOf()
- // >= this.cutoffLength = binary search
- var cutoffLength = 256;
- var mustPunycode = /[^\w.*-]/;
+var exceptions = {};
+var rules = {};
+var selfieMagic = 'iscjsfsaolnm';
- var onChangedListeners = [];
+// This value dictate how the search will be performed:
+// < this.cutoffLength = indexOf()
+// >= this.cutoffLength = binary search
+var cutoffLength = 256;
+var mustPunycode = /[^\w.*-]/;
- /******************************************************************************/
+var onChangedListeners = [];
- // In the context of this code, a domain is defined as:
- // "{label}.{public suffix}".
- // A single standalone label is a public suffix as per
- // http://publicsuffix.org/list/:
- // "If no rules match, the prevailing rule is '*' "
- // This means 'localhost' is not deemed a domain by this
- // code, since according to the definition above, it would be
- // evaluated as a public suffix. The caller is therefore responsible to
- // decide how to further interpret such public suffix.
- //
- // `hostname` must be a valid ascii-based hostname.
+/******************************************************************************/
- function getDomain(hostname) {
- // A hostname starting with a dot is not a valid hostname.
- if ( !hostname || hostname.charAt(0) === '.' ) {
- return '';
- }
- hostname = hostname.toLowerCase();
- var suffix = getPublicSuffix(hostname);
- if ( suffix === hostname ) {
- return '';
- }
- var pos = hostname.lastIndexOf('.', hostname.lastIndexOf('.', hostname.length - suffix.length) - 1);
- if ( pos <= 0 ) {
- return hostname;
- }
- return hostname.slice(pos + 1);
+// In the context of this code, a domain is defined as:
+// "{label}.{public suffix}".
+// A single standalone label is a public suffix as per
+// http://publicsuffix.org/list/:
+// "If no rules match, the prevailing rule is '*' "
+// This means 'localhost' is not deemed a domain by this
+// code, since according to the definition above, it would be
+// evaluated as a public suffix. The caller is therefore responsible to
+// decide how to further interpret such public suffix.
+//
+// `hostname` must be a valid ascii-based hostname.
+
+function getDomain(hostname) {
+ // A hostname starting with a dot is not a valid hostname.
+ if ( !hostname || hostname.charAt(0) === '.' ) {
+ return '';
}
-
- /******************************************************************************/
-
- // Return longest public suffix.
- //
- // `hostname` must be a valid ascii-based string which respect hostname naming.
-
- function getPublicSuffix(hostname) {
- if ( !hostname ) {
- return '';
- }
- // Since we slice down the hostname with each pass, the first match
- // is the longest, so no need to find all the matching rules.
- var pos;
- while ( true ) {
- pos = hostname.indexOf('.');
- if ( pos < 0 ) {
- return hostname;
- }
- if ( search(exceptions, hostname) ) {
- return hostname.slice(pos + 1);
- }
- if ( search(rules, hostname) ) {
- return hostname;
- }
- if ( search(rules, '*' + hostname.slice(pos)) ) {
- return hostname;
- }
- hostname = hostname.slice(pos + 1);
- }
- // unreachable
+ hostname = hostname.toLowerCase();
+ var suffix = getPublicSuffix(hostname);
+ if ( suffix === hostname ) {
+ return '';
+ }
+ var pos = hostname.lastIndexOf('.', hostname.lastIndexOf('.', hostname.length - suffix.length) - 1);
+ if ( pos <= 0 ) {
+ return hostname;
}
+ return hostname.slice(pos + 1);
+}
- /******************************************************************************/
+/******************************************************************************/
- // Look up a specific hostname.
+// Return longest public suffix.
+//
+// `hostname` must be a valid ascii-based string which respect hostname naming.
- function search(store, hostname) {
- // Extract TLD
- var pos = hostname.lastIndexOf('.');
- var tld, remainder;
+function getPublicSuffix(hostname) {
+ if ( !hostname ) {
+ return '';
+ }
+ // Since we slice down the hostname with each pass, the first match
+ // is the longest, so no need to find all the matching rules.
+ var pos;
+ while ( true ) {
+ pos = hostname.indexOf('.');
if ( pos < 0 ) {
- tld = hostname;
- remainder = hostname;
- } else {
- tld = hostname.slice(pos + 1);
- remainder = hostname.slice(0, pos);
- }
- var substore = store[tld];
- if ( !substore ) {
- return false;
+ return hostname;
}
- // If substore is a string, use indexOf()
- if ( typeof substore === 'string' ) {
- return substore.indexOf(' ' + remainder + ' ') >= 0;
+ if ( search(exceptions, hostname) ) {
+ return hostname.slice(pos + 1);
}
- // It is an array: use binary search.
- var l = remainder.length;
- var haystack = substore[l];
- if ( !haystack ) {
- return false;
+ if ( search(rules, hostname) ) {
+ return hostname;
}
- var left = 0;
- var right = Math.floor(haystack.length / l + 0.5);
- var i, needle;
- while ( left < right ) {
- i = left + right >> 1;
- needle = haystack.substr( l * i, l );
- if ( remainder < needle ) {
- right = i;
- } else if ( remainder > needle ) {
- left = i + 1;
- } else {
- return true;
- }
+ if ( search(rules, '*' + hostname.slice(pos)) ) {
+ return hostname;
}
- return false;
+ hostname = hostname.slice(pos + 1);
}
+ // unreachable
+}
- /******************************************************************************/
-
- // Parse and set a UTF-8 text-based suffix list. Format is same as found at:
- // http://publicsuffix.org/list/
- //
- // `toAscii` is a converter from unicode to punycode. Required since the
- // Public Suffix List contains unicode characters.
- // Suggestion: use <https://github.com/bestiejs/punycode.js> it's quite good.
+/******************************************************************************/
- function parse(text, toAscii) {
- exceptions = {};
- rules = {};
+// Look up a specific hostname.
+
+function search(store, hostname) {
+ // Extract TLD
+ var pos = hostname.lastIndexOf('.');
+ var tld, remainder;
+ if ( pos < 0 ) {
+ tld = hostname;
+ remainder = hostname;
+ } else {
+ tld = hostname.slice(pos + 1);
+ remainder = hostname.slice(0, pos);
+ }
+ var substore = store[tld];
+ if ( !substore ) {
+ return false;
+ }
+ // If substore is a string, use indexOf()
+ if ( typeof substore === 'string' ) {
+ return substore.indexOf(' ' + remainder + ' ') >= 0;
+ }
+ // It is an array: use binary search.
+ var l = remainder.length;
+ var haystack = substore[l];
+ if ( !haystack ) {
+ return false;
+ }
+ var left = 0;
+ var right = Math.floor(haystack.length / l + 0.5);
+ var i, needle;
+ while ( left < right ) {
+ i = left + right >> 1;
+ needle = haystack.substr( l * i, l );
+ if ( remainder < needle ) {
+ right = i;
+ } else if ( remainder > needle ) {
+ left = i + 1;
+ } else {
+ return true;
+ }
+ }
+ return false;
+}
- var lineBeg = 0, lineEnd;
- var textEnd = text.length;
- var line, store, pos, tld;
+/******************************************************************************/
- while ( lineBeg < textEnd ) {
- lineEnd = text.indexOf('\n', lineBeg);
+// Parse and set a UTF-8 text-based suffix list. Format is same as found at:
+// http://publicsuffix.org/list/
+//
+// `toAscii` is a converter from unicode to punycode. Required since the
+// Public Suffix List contains unicode characters.
+// Suggestion: use <https://github.com/bestiejs/punycode.js> it's quite good.
+
+function parse(text, toAscii) {
+ exceptions = {};
+ rules = {};
+
+ var lineBeg = 0, lineEnd;
+ var textEnd = text.length;
+ var line, store, pos, tld;
+
+ while ( lineBeg < textEnd ) {
+ lineEnd = text.indexOf('\n', lineBeg);
+ if ( lineEnd < 0 ) {
+ lineEnd = text.indexOf('\r', lineBeg);
if ( lineEnd < 0 ) {
- lineEnd = text.indexOf('\r', lineBeg);
- if ( lineEnd < 0 ) {
- lineEnd = textEnd;
- }
+ lineEnd = textEnd;
}
- line = text.slice(lineBeg, lineEnd).trim();
- lineBeg = lineEnd + 1;
+ }
+ line = text.slice(lineBeg, lineEnd).trim();
+ lineBeg = lineEnd + 1;
- if ( line.length === 0 ) {
- continue;
- }
+ if ( line.length === 0 ) {
+ continue;
+ }
- // Ignore comments
- pos = line.indexOf('//');
- if ( pos >= 0 ) {
- line = line.slice(0, pos);
- }
+ // Ignore comments
+ pos = line.indexOf('//');
+ if ( pos >= 0 ) {
+ line = line.slice(0, pos);
+ }
- // Ignore surrounding whitespaces
- line = line.trim();
- if ( !line ) {
- continue;
- }
+ // Ignore surrounding whitespaces
+ line = line.trim();
+ if ( !line ) {
+ continue;
+ }
- // Is this an exception rule?
- if ( line.charAt(0) === '!' ) {
- store = exceptions;
- line = line.slice(1);
- } else {
- store = rules;
- }
+ // Is this an exception rule?
+ if ( line.charAt(0) === '!' ) {
+ store = exceptions;
+ line = line.slice(1);
+ } else {
+ store = rules;
+ }
- if ( mustPunycode.test(line) ) {
- line = toAscii(line);
- }
+ if ( mustPunycode.test(line) ) {
+ line = toAscii(line);
+ }
- // http://publicsuffix.org/list/:
- // "... all rules must be canonicalized in the normal way
- // for hostnames - lower-case, Punycode ..."
- line = line.toLowerCase();
-
- // Extract TLD
- pos = line.lastIndexOf('.');
- if ( pos < 0 ) {
- tld = line;
- } else {
- tld = line.slice(pos + 1);
- line = line.slice(0, pos);
- }
+ // http://publicsuffix.org/list/:
+ // "... all rules must be canonicalized in the normal way
+ // for hostnames - lower-case, Punycode ..."
+ line = line.toLowerCase();
- // Store suffix using tld as key
- if ( !store.hasOwnProperty(tld) ) {
- store[tld] = [];
- }
- if ( line ) {
- store[tld].push(line);
- }
+ // Extract TLD
+ pos = line.lastIndexOf('.');
+ if ( pos < 0 ) {
+ tld = line;
+ } else {
+ tld = line.slice(pos + 1);
+ line = line.slice(0, pos);
}
- crystallize(exceptions);
- crystallize(rules);
- callListeners(onChangedListeners);
+ // Store suffix using tld as key
+ if ( !store.hasOwnProperty(tld) ) {
+ store[tld] = [];
+ }
+ if ( line ) {
+ store[tld].push(line);
+ }
}
+ crystallize(exceptions);
+ crystallize(rules);
- /******************************************************************************/
+ callListeners(onChangedListeners);
+}
- // Cristallize the storage of suffixes using optimal internal representation
- // for future look up.
+/******************************************************************************/
- function crystallize(store) {
- var suffixes, suffix, i, l;
+// Cristallize the storage of suffixes using optimal internal representation
+// for future look up.
- for ( var tld in store ) {
- if ( !store.hasOwnProperty(tld) ) {
- continue;
- }
- suffixes = store[tld].join(' ');
- // No suffix
- if ( !suffixes ) {
- store[tld] = '';
- continue;
- }
- // Concatenated list of suffixes less than cutoff length:
- // Store as string, lookup using indexOf()
- if ( suffixes.length < cutoffLength ) {
- store[tld] = ' ' + suffixes + ' ';
- continue;
- }
- // Concatenated list of suffixes greater or equal to cutoff length
- // Store as array keyed on suffix length, lookup using binary search.
- // I borrowed the idea to key on string length here:
- // http://ejohn.org/blog/dictionary-lookups-in-javascript/#comment-392072
-
- i = store[tld].length;
- suffixes = [];
- while ( i-- ) {
- suffix = store[tld][i];
- l = suffix.length;
- if ( !suffixes[l] ) {
- suffixes[l] = [];
- }
- suffixes[l].push(suffix);
+function crystallize(store) {
+ var suffixes, suffix, i, l;
+
+ for ( var tld in store ) {
+ if ( !store.hasOwnProperty(tld) ) {
+ continue;
+ }
+ suffixes = store[tld].join(' ');
+ // No suffix
+ if ( !suffixes ) {
+ store[tld] = '';
+ continue;
+ }
+ // Concatenated list of suffixes less than cutoff length:
+ // Store as string, lookup using indexOf()
+ if ( suffixes.length < cutoffLength ) {
+ store[tld] = ' ' + suffixes + ' ';
+ continue;
+ }
+ // Concatenated list of suffixes greater or equal to cutoff length
+ // Store as array keyed on suffix length, lookup using binary search.
+ // I borrowed the idea to key on string length here:
+ // http://ejohn.org/blog/dictionary-lookups-in-javascript/#comment-392072
+
+ i = store[tld].length;
+ suffixes = [];
+ while ( i-- ) {
+ suffix = store[tld][i];
+ l = suffix.length;
+ if ( !suffixes[l] ) {
+ suffixes[l] = [];
}
- l = suffixes.length;
- while ( l-- ) {
- if ( suffixes[l] ) {
- suffixes[l] = suffixes[l].sort().join('');
- }
+ suffixes[l].push(suffix);
+ }
+ l = suffixes.length;
+ while ( l-- ) {
+ if ( suffixes[l] ) {
+ suffixes[l] = suffixes[l].sort().join('');
}
- store[tld] = suffixes;
}
- return store;
+ store[tld] = suffixes;
}
+ return store;
+}
- /******************************************************************************/
+/******************************************************************************/
- function toSelfie() {
- return {
- magic: selfieMagic,
- rules: rules,
- exceptions: exceptions
- };
- }
+function toSelfie() {
+ return {
+ magic: selfieMagic,
+ rules: rules,
+ exceptions: exceptions
+ };
+}
- function fromSelfie(selfie) {
- if ( typeof selfie !== 'object' || typeof selfie.magic !== 'string' || selfie.magic !== selfieMagic ) {
- return false;
- }
- rules = selfie.rules;
- exceptions = selfie.exceptions;
- callListeners(onChangedListeners);
- return true;
+function fromSelfie(selfie) {
+ if ( typeof selfie !== 'object' || typeof selfie.magic !== 'string' || selfie.magic !== selfieMagic ) {
+ return false;
}
+ rules = selfie.rules;
+ exceptions = selfie.exceptions;
+ callListeners(onChangedListeners);
+ return true;
+}
- /******************************************************************************/
+/******************************************************************************/
- var addListener = function(listeners, callback) {
- if ( typeof callback !== 'function' ) {
- return;
- }
- if ( listeners.indexOf(callback) === -1 ) {
- listeners.push(callback);
- }
- };
+var addListener = function(listeners, callback) {
+ if ( typeof callback !== 'function' ) {
+ return;
+ }
+ if ( listeners.indexOf(callback) === -1 ) {
+ listeners.push(callback);
+ }
+};
- var removeListener = function(listeners, callback) {
- var pos = listeners.indexOf(callback);
- if ( pos !== -1 ) {
- listeners.splice(pos, 1);
- }
- };
+var removeListener = function(listeners, callback) {
+ var pos = listeners.indexOf(callback);
+ if ( pos !== -1 ) {
+ listeners.splice(pos, 1);
+ }
+};
- var callListeners = function(listeners) {
- for ( var i = 0; i < listeners.length; i++ ) {
- listeners[i]();
- }
- };
+var callListeners = function(listeners) {
+ for ( var i = 0; i < listeners.length; i++ ) {
+ listeners[i]();
+ }
+};
- /******************************************************************************/
+/******************************************************************************/
- var onChanged = {
- addListener: function(callback) {
- addListener(onChangedListeners, callback);
- },
- removeListener: function(callback) {
- removeListener(onChangedListeners, callback);
- }
- };
+var onChanged = {
+ addListener: function(callback) {
+ addListener(onChangedListeners, callback);
+ },
+ removeListener: function(callback) {
+ removeListener(onChangedListeners, callback);
+ }
+};
- /******************************************************************************/
+/******************************************************************************/
- // Public API
+// Public API
- root = root || window;
+root = root || window;
- root.publicSuffixList = {
- 'version': '1.0',
- 'parse': parse,
- 'getDomain': getDomain,
- 'getPublicSuffix': getPublicSuffix,
- 'toSelfie': toSelfie,
- 'fromSelfie': fromSelfie,
- 'onChanged': onChanged
- };
+root.publicSuffixList = {
+ 'version': '1.0',
+ 'parse': parse,
+ 'getDomain': getDomain,
+ 'getPublicSuffix': getPublicSuffix,
+ 'toSelfie': toSelfie,
+ 'fromSelfie': fromSelfie,
+ 'onChanged': onChanged
+};
- /******************************************************************************/
+/******************************************************************************/
})(this);
diff --git a/lib/punycode.js b/lib/punycode.js
index b66096e..c965f8b 100644
--- a/lib/punycode.js
+++ b/lib/punycode.js
@@ -23,530 +23,530 @@
/*! https://mths.be/punycode v1.3.2 by @mathias */
;(function(root) {
- /** Detect free variables */
- var freeExports = typeof exports == 'object' && exports &&
- !exports.nodeType && exports;
- var freeModule = typeof module == 'object' && module &&
- !module.nodeType && module;
- var freeGlobal = typeof global == 'object' && global;
- if (
- freeGlobal.global === freeGlobal ||
- freeGlobal.window === freeGlobal ||
- freeGlobal.self === freeGlobal
- ) {
- root = freeGlobal;
- }
-
- /**
- * The `punycode` object.
- * @name punycode
- * @type Object
- */
- var punycode,
-
- /** Highest positive signed 32-bit float value */
- maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
-
- /** Bootstring parameters */
- base = 36,
- tMin = 1,
- tMax = 26,
- skew = 38,
- damp = 700,
- initialBias = 72,
- initialN = 128, // 0x80
- delimiter = '-', // '\x2D'
-
- /** Regular expressions */
- regexPunycode = /^xn--/,
- regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
- regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
-
- /** Error messages */
- errors = {
- 'overflow': 'Overflow: input needs wider integers to process',
- 'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
- 'invalid-input': 'Invalid input'
- },
-
- /** Convenience shortcuts */
- baseMinusTMin = base - tMin,
- floor = Math.floor,
- stringFromCharCode = String.fromCharCode,
-
- /** Temporary variable */
- key;
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * A generic error utility function.
- * @private
- * @param {String} type The error type.
- * @returns {Error} Throws a `RangeError` with the applicable error message.
- */
- function error(type) {
- throw RangeError(errors[type]);
- }
-
- /**
- * A generic `Array#map` utility function.
- * @private
- * @param {Array} array The array to iterate over.
- * @param {Function} callback The function that gets called for every array
- * item.
- * @returns {Array} A new array of values returned by the callback function.
- */
- function map(array, fn) {
- var length = array.length;
- var result = [];
- while (length--) {
- result[length] = fn(array[length]);
- }
- return result;
- }
-
- /**
- * A simple `Array#map`-like wrapper to work with domain name strings or email
- * addresses.
- * @private
- * @param {String} domain The domain name or email address.
- * @param {Function} callback The function that gets called for every
- * character.
- * @returns {Array} A new string of characters returned by the callback
- * function.
- */
- function mapDomain(string, fn) {
- var parts = string.split('@');
- var result = '';
- if (parts.length > 1) {
- // In email addresses, only the domain name should be punycoded. Leave
- // the local part (i.e. everything up to `@`) intact.
- result = parts[0] + '@';
- string = parts[1];
- }
- // Avoid `split(regex)` for IE8 compatibility. See #17.
- string = string.replace(regexSeparators, '\x2E');
- var labels = string.split('.');
- var encoded = map(labels, fn).join('.');
- return result + encoded;
- }
-
- /**
- * Creates an array containing the numeric code points of each Unicode
- * character in the string. While JavaScript uses UCS-2 internally,
- * this function will convert a pair of surrogate halves (each of which
- * UCS-2 exposes as separate characters) into a single code point,
- * matching UTF-16.
- * @see `punycode.ucs2.encode`
- * @see <https://mathiasbynens.be/notes/javascript-encoding>
- * @memberOf punycode.ucs2
- * @name decode
- * @param {String} string The Unicode input string (UCS-2).
- * @returns {Array} The new array of code points.
- */
- function ucs2decode(string) {
- var output = [],
- counter = 0,
- length = string.length,
- value,
- extra;
- while (counter < length) {
- value = string.charCodeAt(counter++);
- if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
- // high surrogate, and there is a next character
- extra = string.charCodeAt(counter++);
- if ((extra & 0xFC00) == 0xDC00) { // low surrogate
- output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
- } else {
- // unmatched surrogate; only append this code unit, in case the next
- // code unit is the high surrogate of a surrogate pair
- output.push(value);
- counter--;
- }
- } else {
- output.push(value);
- }
- }
- return output;
- }
-
- /**
- * Creates a string based on an array of numeric code points.
- * @see `punycode.ucs2.decode`
- * @memberOf punycode.ucs2
- * @name encode
- * @param {Array} codePoints The array of numeric code points.
- * @returns {String} The new Unicode string (UCS-2).
- */
- function ucs2encode(array) {
- return map(array, function(value) {
- var output = '';
- if (value > 0xFFFF) {
- value -= 0x10000;
- output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
- value = 0xDC00 | value & 0x3FF;
- }
- output += stringFromCharCode(value);
- return output;
- }).join('');
- }
-
- /**
- * Converts a basic code point into a digit/integer.
- * @see `digitToBasic()`
- * @private
- * @param {Number} codePoint The basic numeric code point value.
- * @returns {Number} The numeric value of a basic code point (for use in
- * representing integers) in the range `0` to `base - 1`, or `base` if
- * the code point does not represent a value.
- */
- function basicToDigit(codePoint) {
- if (codePoint - 48 < 10) {
- return codePoint - 22;
- }
- if (codePoint - 65 < 26) {
- return codePoint - 65;
- }
- if (codePoint - 97 < 26) {
- return codePoint - 97;
- }
- return base;
- }
-
- /**
- * Converts a digit/integer into a basic code point.
- * @see `basicToDigit()`
- * @private
- * @param {Number} digit The numeric value of a basic code point.
- * @returns {Number} The basic code point whose value (when used for
- * representing integers) is `digit`, which needs to be in the range
- * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
- * used; else, the lowercase form is used. The behavior is undefined
- * if `flag` is non-zero and `digit` has no uppercase form.
- */
- function digitToBasic(digit, flag) {
- // 0..25 map to ASCII a..z or A..Z
- // 26..35 map to ASCII 0..9
- return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
- }
-
- /**
- * Bias adaptation function as per section 3.4 of RFC 3492.
- * http://tools.ietf.org/html/rfc3492#section-3.4
- * @private
- */
- function adapt(delta, numPoints, firstTime) {
- var k = 0;
- delta = firstTime ? floor(delta / damp) : delta >> 1;
- delta += floor(delta / numPoints);
- for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
- delta = floor(delta / baseMinusTMin);
- }
- return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
- }
-
- /**
- * Converts a Punycode string of ASCII-only symbols to a string of Unicode
- * symbols.
- * @memberOf punycode
- * @param {String} input The Punycode string of ASCII-only symbols.
- * @returns {String} The resulting string of Unicode symbols.
- */
- function decode(input) {
- // Don't use UCS-2
- var output = [],
- inputLength = input.length,
- out,
- i = 0,
- n = initialN,
- bias = initialBias,
- basic,
- j,
- index,
- oldi,
- w,
- k,
- digit,
- t,
- /** Cached calculation results */
- baseMinusT;
-
- // Handle the basic code points: let `basic` be the number of input code
- // points before the last delimiter, or `0` if there is none, then copy
- // the first basic code points to the output.
-
- basic = input.lastIndexOf(delimiter);
- if (basic < 0) {
- basic = 0;
- }
-
- for (j = 0; j < basic; ++j) {
- // if it's not a basic code point
- if (input.charCodeAt(j) >= 0x80) {
- error('not-basic');
- }
- output.push(input.charCodeAt(j));
- }
-
- // Main decoding loop: start just after the last delimiter if any basic code
- // points were copied; start at the beginning otherwise.
-
- for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
-
- // `index` is the index of the next character to be consumed.
- // Decode a generalized variable-length integer into `delta`,
- // which gets added to `i`. The overflow checking is easier
- // if we increase `i` as we go, then subtract off its starting
- // value at the end to obtain `delta`.
- for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
-
- if (index >= inputLength) {
- error('invalid-input');
- }
-
- digit = basicToDigit(input.charCodeAt(index++));
-
- if (digit >= base || digit > floor((maxInt - i) / w)) {
- error('overflow');
- }
-
- i += digit * w;
- t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
-
- if (digit < t) {
- break;
- }
-
- baseMinusT = base - t;
- if (w > floor(maxInt / baseMinusT)) {
- error('overflow');
- }
-
- w *= baseMinusT;
-
- }
-
- out = output.length + 1;
- bias = adapt(i - oldi, out, oldi == 0);
-
- // `i` was supposed to wrap around from `out` to `0`,
- // incrementing `n` each time, so we'll fix that now:
- if (floor(i / out) > maxInt - n) {
- error('overflow');
- }
-
- n += floor(i / out);
- i %= out;
-
- // Insert `n` at position `i` of the output
- output.splice(i++, 0, n);
-
- }
-
- return ucs2encode(output);
- }
-
- /**
- * Converts a string of Unicode symbols (e.g. a domain name label) to a
- * Punycode string of ASCII-only symbols.
- * @memberOf punycode
- * @param {String} input The string of Unicode symbols.
- * @returns {String} The resulting Punycode string of ASCII-only symbols.
- */
- function encode(input) {
- var n,
- delta,
- handledCPCount,
- basicLength,
- bias,
- j,
- m,
- q,
- k,
- t,
- currentValue,
- output = [],
- /** `inputLength` will hold the number of code points in `input`. */
- inputLength,
- /** Cached calculation results */
- handledCPCountPlusOne,
- baseMinusT,
- qMinusT;
-
- // Convert the input in UCS-2 to Unicode
- input = ucs2decode(input);
-
- // Cache the length
- inputLength = input.length;
-
- // Initialize the state
- n = initialN;
- delta = 0;
- bias = initialBias;
-
- // Handle the basic code points
- for (j = 0; j < inputLength; ++j) {
- currentValue = input[j];
- if (currentValue < 0x80) {
- output.push(stringFromCharCode(currentValue));
- }
- }
-
- handledCPCount = basicLength = output.length;
-
- // `handledCPCount` is the number of code points that have been handled;
- // `basicLength` is the number of basic code points.
-
- // Finish the basic string - if it is not empty - with a delimiter
- if (basicLength) {
- output.push(delimiter);
- }
-
- // Main encoding loop:
- while (handledCPCount < inputLength) {
-
- // All non-basic code points < n have been handled already. Find the next
- // larger one:
- for (m = maxInt, j = 0; j < inputLength; ++j) {
- currentValue = input[j];
- if (currentValue >= n && currentValue < m) {
- m = currentValue;
- }
- }
-
- // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
- // but guard against overflow
- handledCPCountPlusOne = handledCPCount + 1;
- if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
- error('overflow');
- }
-
- delta += (m - n) * handledCPCountPlusOne;
- n = m;
-
- for (j = 0; j < inputLength; ++j) {
- currentValue = input[j];
-
- if (currentValue < n && ++delta > maxInt) {
- error('overflow');
- }
-
- if (currentValue == n) {
- // Represent delta as a generalized variable-length integer
- for (q = delta, k = base; /* no condition */; k += base) {
- t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
- if (q < t) {
- break;
- }
- qMinusT = q - t;
- baseMinusT = base - t;
- output.push(
- stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
- );
- q = floor(qMinusT / baseMinusT);
- }
-
- output.push(stringFromCharCode(digitToBasic(q, 0)));
- bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
- delta = 0;
- ++handledCPCount;
- }
- }
-
- ++delta;
- ++n;
-
- }
- return output.join('');
- }
-
- /**
- * Converts a Punycode string representing a domain name or an email address
- * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
- * it doesn't matter if you call it on a string that has already been
- * converted to Unicode.
- * @memberOf punycode
- * @param {String} input The Punycoded domain name or email address to
- * convert to Unicode.
- * @returns {String} The Unicode representation of the given Punycode
- * string.
- */
- function toUnicode(input) {
- return mapDomain(input, function(string) {
- return regexPunycode.test(string)
- ? decode(string.slice(4).toLowerCase())
- : string;
- });
- }
-
- /**
- * Converts a Unicode string representing a domain name or an email address to
- * Punycode. Only the non-ASCII parts of the domain name will be converted,
- * i.e. it doesn't matter if you call it with a domain that's already in
- * ASCII.
- * @memberOf punycode
- * @param {String} input The domain name or email address to convert, as a
- * Unicode string.
- * @returns {String} The Punycode representation of the given domain name or
- * email address.
- */
- function toASCII(input) {
- return mapDomain(input, function(string) {
- return regexNonASCII.test(string)
- ? 'xn--' + encode(string)
- : string;
- });
- }
-
- /*--------------------------------------------------------------------------*/
-
- /** Define the public API */
- punycode = {
- /**
- * A string representing the current Punycode.js version number.
- * @memberOf punycode
- * @type String
- */
- 'version': '1.3.2',
- /**
- * An object of methods to convert from JavaScript's internal character
- * representation (UCS-2) to Unicode code points, and back.
- * @see <https://mathiasbynens.be/notes/javascript-encoding>
- * @memberOf punycode
- * @type Object
- */
- 'ucs2': {
- 'decode': ucs2decode,
- 'encode': ucs2encode
- },
- 'decode': decode,
- 'encode': encode,
- 'toASCII': toASCII,
- 'toUnicode': toUnicode
- };
-
- /** Expose `punycode` */
- // Some AMD build optimizers, like r.js, check for specific condition patterns
- // like the following:
- if (
- typeof define == 'function' &&
- typeof define.amd == 'object' &&
- define.amd
- ) {
- define('punycode', function() {
- return punycode;
- });
- } else if (freeExports && freeModule) {
- if (module.exports == freeExports) { // in Node.js or RingoJS v0.8.0+
- freeModule.exports = punycode;
- } else { // in Narwhal or RingoJS v0.7.0-
- for (key in punycode) {
- punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
- }
- }
- } else { // in Rhino or a web browser
- root.punycode = punycode;
- }
+ /** Detect free variables */
+ var freeExports = typeof exports == 'object' && exports &&
+ !exports.nodeType && exports;
+ var freeModule = typeof module == 'object' && module &&
+ !module.nodeType && module;
+ var freeGlobal = typeof global == 'object' && global;
+ if (
+ freeGlobal.global === freeGlobal ||
+ freeGlobal.window === freeGlobal ||
+ freeGlobal.self === freeGlobal
+ ) {
+ root = freeGlobal;
+ }
+
+ /**
+ * The `punycode` object.
+ * @name punycode
+ * @type Object
+ */
+ var punycode,
+
+ /** Highest positive signed 32-bit float value */
+ maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
+
+ /** Bootstring parameters */
+ base = 36,
+ tMin = 1,
+ tMax = 26,
+ skew = 38,
+ damp = 700,
+ initialBias = 72,
+ initialN = 128, // 0x80
+ delimiter = '-', // '\x2D'
+
+ /** Regular expressions */
+ regexPunycode = /^xn--/,
+ regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
+ regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
+
+ /** Error messages */
+ errors = {
+ 'overflow': 'Overflow: input needs wider integers to process',
+ 'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+ 'invalid-input': 'Invalid input'
+ },
+
+ /** Convenience shortcuts */
+ baseMinusTMin = base - tMin,
+ floor = Math.floor,
+ stringFromCharCode = String.fromCharCode,
+
+ /** Temporary variable */
+ key;
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * A generic error utility function.
+ * @private
+ * @param {String} type The error type.
+ * @returns {Error} Throws a `RangeError` with the applicable error message.
+ */
+ function error(type) {
+ throw RangeError(errors[type]);
+ }
+
+ /**
+ * A generic `Array#map` utility function.
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} callback The function that gets called for every array
+ * item.
+ * @returns {Array} A new array of values returned by the callback function.
+ */
+ function map(array, fn) {
+ var length = array.length;
+ var result = [];
+ while (length--) {
+ result[length] = fn(array[length]);
+ }
+ return result;
+ }
+
+ /**
+ * A simple `Array#map`-like wrapper to work with domain name strings or email
+ * addresses.
+ * @private
+ * @param {String} domain The domain name or email address.
+ * @param {Function} callback The function that gets called for every
+ * character.
+ * @returns {Array} A new string of characters returned by the callback
+ * function.
+ */
+ function mapDomain(string, fn) {
+ var parts = string.split('@');
+ var result = '';
+ if (parts.length > 1) {
+ // In email addresses, only the domain name should be punycoded. Leave
+ // the local part (i.e. everything up to `@`) intact.
+ result = parts[0] + '@';
+ string = parts[1];
+ }
+ // Avoid `split(regex)` for IE8 compatibility. See #17.
+ string = string.replace(regexSeparators, '\x2E');
+ var labels = string.split('.');
+ var encoded = map(labels, fn).join('.');
+ return result + encoded;
+ }
+
+ /**
+ * Creates an array containing the numeric code points of each Unicode
+ * character in the string. While JavaScript uses UCS-2 internally,
+ * this function will convert a pair of surrogate halves (each of which
+ * UCS-2 exposes as separate characters) into a single code point,
+ * matching UTF-16.
+ * @see `punycode.ucs2.encode`
+ * @see <https://mathiasbynens.be/notes/javascript-encoding>
+ * @memberOf punycode.ucs2
+ * @name decode
+ * @param {String} string The Unicode input string (UCS-2).
+ * @returns {Array} The new array of code points.
+ */
+ function ucs2decode(string) {
+ var output = [],
+ counter = 0,
+ length = string.length,
+ value,
+ extra;
+ while (counter < length) {
+ value = string.charCodeAt(counter++);
+ if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+ // high surrogate, and there is a next character
+ extra = string.charCodeAt(counter++);
+ if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+ output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+ } else {
+ // unmatched surrogate; only append this code unit, in case the next
+ // code unit is the high surrogate of a surrogate pair
+ output.push(value);
+ counter--;
+ }
+ } else {
+ output.push(value);
+ }
+ }
+ return output;
+ }
+
+ /**
+ * Creates a string based on an array of numeric code points.
+ * @see `punycode.ucs2.decode`
+ * @memberOf punycode.ucs2
+ * @name encode
+ * @param {Array} codePoints The array of numeric code points.
+ * @returns {String} The new Unicode string (UCS-2).
+ */
+ function ucs2encode(array) {
+ return map(array, function(value) {
+ var output = '';
+ if (value > 0xFFFF) {
+ value -= 0x10000;
+ output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+ value = 0xDC00 | value & 0x3FF;
+ }
+ output += stringFromCharCode(value);
+ return output;
+ }).join('');
+ }
+
+ /**
+ * Converts a basic code point into a digit/integer.
+ * @see `digitToBasic()`
+ * @private
+ * @param {Number} codePoint The basic numeric code point value.
+ * @returns {Number} The numeric value of a basic code point (for use in
+ * representing integers) in the range `0` to `base - 1`, or `base` if
+ * the code point does not represent a value.
+ */
+ function basicToDigit(codePoint) {
+ if (codePoint - 48 < 10) {
+ return codePoint - 22;
+ }
+ if (codePoint - 65 < 26) {
+ return codePoint - 65;
+ }
+ if (codePoint - 97 < 26) {
+ return codePoint - 97;
+ }
+ return base;
+ }
+
+ /**
+ * Converts a digit/integer into a basic code point.
+ * @see `basicToDigit()`
+ * @private
+ * @param {Number} digit The numeric value of a basic code point.
+ * @returns {Number} The basic code point whose value (when used for
+ * representing integers) is `digit`, which needs to be in the range
+ * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+ * used; else, the lowercase form is used. The behavior is undefined
+ * if `flag` is non-zero and `digit` has no uppercase form.
+ */
+ function digitToBasic(digit, flag) {
+ // 0..25 map to ASCII a..z or A..Z
+ // 26..35 map to ASCII 0..9
+ return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+ }
+
+ /**
+ * Bias adaptation function as per section 3.4 of RFC 3492.
+ * http://tools.ietf.org/html/rfc3492#section-3.4
+ * @private
+ */
+ function adapt(delta, numPoints, firstTime) {
+ var k = 0;
+ delta = firstTime ? floor(delta / damp) : delta >> 1;
+ delta += floor(delta / numPoints);
+ for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
+ delta = floor(delta / baseMinusTMin);
+ }
+ return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+ }
+
+ /**
+ * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+ * symbols.
+ * @memberOf punycode
+ * @param {String} input The Punycode string of ASCII-only symbols.
+ * @returns {String} The resulting string of Unicode symbols.
+ */
+ function decode(input) {
+ // Don't use UCS-2
+ var output = [],
+ inputLength = input.length,
+ out,
+ i = 0,
+ n = initialN,
+ bias = initialBias,
+ basic,
+ j,
+ index,
+ oldi,
+ w,
+ k,
+ digit,
+ t,
+ /** Cached calculation results */
+ baseMinusT;
+
+ // Handle the basic code points: let `basic` be the number of input code
+ // points before the last delimiter, or `0` if there is none, then copy
+ // the first basic code points to the output.
+
+ basic = input.lastIndexOf(delimiter);
+ if (basic < 0) {
+ basic = 0;
+ }
+
+ for (j = 0; j < basic; ++j) {
+ // if it's not a basic code point
+ if (input.charCodeAt(j) >= 0x80) {
+ error('not-basic');
+ }
+ output.push(input.charCodeAt(j));
+ }
+
+ // Main decoding loop: start just after the last delimiter if any basic code
+ // points were copied; start at the beginning otherwise.
+
+ for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
+
+ // `index` is the index of the next character to be consumed.
+ // Decode a generalized variable-length integer into `delta`,
+ // which gets added to `i`. The overflow checking is easier
+ // if we increase `i` as we go, then subtract off its starting
+ // value at the end to obtain `delta`.
+ for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
+
+ if (index >= inputLength) {
+ error('invalid-input');
+ }
+
+ digit = basicToDigit(input.charCodeAt(index++));
+
+ if (digit >= base || digit > floor((maxInt - i) / w)) {
+ error('overflow');
+ }
+
+ i += digit * w;
+ t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+ if (digit < t) {
+ break;
+ }
+
+ baseMinusT = base - t;
+ if (w > floor(maxInt / baseMinusT)) {
+ error('overflow');
+ }
+
+ w *= baseMinusT;
+
+ }
+
+ out = output.length + 1;
+ bias = adapt(i - oldi, out, oldi == 0);
+
+ // `i` was supposed to wrap around from `out` to `0`,
+ // incrementing `n` each time, so we'll fix that now:
+ if (floor(i / out) > maxInt - n) {
+ error('overflow');
+ }
+
+ n += floor(i / out);
+ i %= out;
+
+ // Insert `n` at position `i` of the output
+ output.splice(i++, 0, n);
+
+ }
+
+ return ucs2encode(output);
+ }
+
+ /**
+ * Converts a string of Unicode symbols (e.g. a domain name label) to a
+ * Punycode string of ASCII-only symbols.
+ * @memberOf punycode
+ * @param {String} input The string of Unicode symbols.
+ * @returns {String} The resulting Punycode string of ASCII-only symbols.
+ */
+ function encode(input) {
+ var n,
+ delta,
+ handledCPCount,
+ basicLength,
+ bias,
+ j,
+ m,
+ q,
+ k,
+ t,
+ currentValue,
+ output = [],
+ /** `inputLength` will hold the number of code points in `input`. */
+ inputLength,
+ /** Cached calculation results */
+ handledCPCountPlusOne,
+ baseMinusT,
+ qMinusT;
+
+ // Convert the input in UCS-2 to Unicode
+ input = ucs2decode(input);
+
+ // Cache the length
+ inputLength = input.length;
+
+ // Initialize the state
+ n = initialN;
+ delta = 0;
+ bias = initialBias;
+
+ // Handle the basic code points
+ for (j = 0; j < inputLength; ++j) {
+ currentValue = input[j];
+ if (currentValue < 0x80) {
+ output.push(stringFromCharCode(currentValue));
+ }
+ }
+
+ handledCPCount = basicLength = output.length;
+
+ // `handledCPCount` is the number of code points that have been handled;
+ // `basicLength` is the number of basic code points.
+
+ // Finish the basic string - if it is not empty - with a delimiter
+ if (basicLength) {
+ output.push(delimiter);
+ }
+
+ // Main encoding loop:
+ while (handledCPCount < inputLength) {
+
+ // All non-basic code points < n have been handled already. Find the next
+ // larger one:
+ for (m = maxInt, j = 0; j < inputLength; ++j) {
+ currentValue = input[j];
+ if (currentValue >= n && currentValue < m) {
+ m = currentValue;
+ }
+ }
+
+ // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+ // but guard against overflow
+ handledCPCountPlusOne = handledCPCount + 1;
+ if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+ error('overflow');
+ }
+
+ delta += (m - n) * handledCPCountPlusOne;
+ n = m;
+
+ for (j = 0; j < inputLength; ++j) {
+ currentValue = input[j];
+
+ if (currentValue < n && ++delta > maxInt) {
+ error('overflow');
+ }
+
+ if (currentValue == n) {
+ // Represent delta as a generalized variable-length integer
+ for (q = delta, k = base; /* no condition */; k += base) {
+ t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+ if (q < t) {
+ break;
+ }
+ qMinusT = q - t;
+ baseMinusT = base - t;
+ output.push(
+ stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+ );
+ q = floor(qMinusT / baseMinusT);
+ }
+
+ output.push(stringFromCharCode(digitToBasic(q, 0)));
+ bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+ delta = 0;
+ ++handledCPCount;
+ }
+ }
+
+ ++delta;
+ ++n;
+
+ }
+ return output.join('');
+ }
+
+ /**
+ * Converts a Punycode string representing a domain name or an email address
+ * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
+ * it doesn't matter if you call it on a string that has already been
+ * converted to Unicode.
+ * @memberOf punycode
+ * @param {String} input The Punycoded domain name or email address to
+ * convert to Unicode.
+ * @returns {String} The Unicode representation of the given Punycode
+ * string.
+ */
+ function toUnicode(input) {
+ return mapDomain(input, function(string) {
+ return regexPunycode.test(string)
+ ? decode(string.slice(4).toLowerCase())
+ : string;
+ });
+ }
+
+ /**
+ * Converts a Unicode string representing a domain name or an email address to
+ * Punycode. Only the non-ASCII parts of the domain name will be converted,
+ * i.e. it doesn't matter if you call it with a domain that's already in
+ * ASCII.
+ * @memberOf punycode
+ * @param {String} input The domain name or email address to convert, as a
+ * Unicode string.
+ * @returns {String} The Punycode representation of the given domain name or
+ * email address.
+ */
+ function toASCII(input) {
+ return mapDomain(input, function(string) {
+ return regexNonASCII.test(string)
+ ? 'xn--' + encode(string)
+ : string;
+ });
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /** Define the public API */
+ punycode = {
+ /**
+ * A string representing the current Punycode.js version number.
+ * @memberOf punycode
+ * @type String
+ */
+ 'version': '1.3.2',
+ /**
+ * An object of methods to convert from JavaScript's internal character
+ * representation (UCS-2) to Unicode code points, and back.
+ * @see <https://mathiasbynens.be/notes/javascript-encoding>
+ * @memberOf punycode
+ * @type Object
+ */
+ 'ucs2': {
+ 'decode': ucs2decode,
+ 'encode': ucs2encode
+ },
+ 'decode': decode,
+ 'encode': encode,
+ 'toASCII': toASCII,
+ 'toUnicode': toUnicode
+ };
+
+ /** Expose `punycode` */
+ // Some AMD build optimizers, like r.js, check for specific condition patterns
+ // like the following:
+ if (
+ typeof define == 'function' &&
+ typeof define.amd == 'object' &&
+ define.amd
+ ) {
+ define('punycode', function() {
+ return punycode;
+ });
+ } else if (freeExports && freeModule) {
+ if (module.exports == freeExports) { // in Node.js or RingoJS v0.8.0+
+ freeModule.exports = punycode;
+ } else { // in Narwhal or RingoJS v0.7.0-
+ for (key in punycode) {
+ punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+ }
+ }
+ } else { // in Rhino or a web browser
+ root.punycode = punycode;
+ }
}(this));