41 changed files with 5711 additions and 4 deletions
-
6.gitignore
-
40restscrape/__init__.py
-
3restscrape/browser.py
-
2restscrape/proxy.py
-
11restscrape/scraper.py
-
57restscrape/uBlock/1p-filters.html
-
69restscrape/uBlock/3p-filters.html
-
47restscrape/uBlock/about.html
-
52restscrape/uBlock/asset-viewer.html
-
45restscrape/uBlock/background.html
-
23restscrape/uBlock/cloud-ui.html
-
36restscrape/uBlock/dashboard.html
-
66restscrape/uBlock/document-blocked.html
-
61restscrape/uBlock/dyna-rules.html
-
238restscrape/uBlock/epicker.html
-
9restscrape/uBlock/is-webrtc-supported.html
-
21restscrape/uBlock/lib/codemirror/LICENSE
-
49restscrape/uBlock/lib/codemirror/README.md
-
127restscrape/uBlock/lib/codemirror/addon/display/panel.js
-
119restscrape/uBlock/lib/codemirror/addon/merge/merge.css
-
1002restscrape/uBlock/lib/codemirror/addon/merge/merge.js
-
122restscrape/uBlock/lib/codemirror/addon/scroll/annotatescrollbar.js
-
8restscrape/uBlock/lib/codemirror/addon/search/matchesonscrollbar.css
-
97restscrape/uBlock/lib/codemirror/addon/search/matchesonscrollbar.js
-
293restscrape/uBlock/lib/codemirror/addon/search/searchcursor.js
-
72restscrape/uBlock/lib/codemirror/addon/selection/active-line.js
-
34restscrape/uBlock/lib/diff/README.md
-
243restscrape/uBlock/lib/diff/swatinem_diff.js
-
52restscrape/uBlock/lib/lz4/README.md
-
171restscrape/uBlock/lib/lz4/lz4-block-codec-any.js
-
297restscrape/uBlock/lib/lz4/lz4-block-codec-js.js
-
194restscrape/uBlock/lib/lz4/lz4-block-codec-wasm.js
-
BINrestscrape/uBlock/lib/lz4/lz4-block-codec.wasm
-
745restscrape/uBlock/lib/lz4/lz4-block-codec.wat
-
328restscrape/uBlock/lib/publicsuffixlist.js
-
530restscrape/uBlock/lib/punycode.js
-
204restscrape/uBlock/logger-ui.html
-
75restscrape/uBlock/popup.html
-
71restscrape/uBlock/settings.html
-
37restscrape/uBlock/shortcuts.html
-
59restscrape/uBlock/whitelist.html
@ -0,0 +1,40 @@ |
|||||
|
if __name__ == "__main__": |
||||
|
import sys |
||||
|
sys.path.insert(0,'..') |
||||
|
from restscrape.browser import browser as browser_class |
||||
|
from restscrape.scraper import scraper |
||||
|
from restscrape.proxy import create_proxy_iter |
||||
|
import time |
||||
|
US_PROXY_ITER = create_proxy_iter() |
||||
|
|
||||
|
def scrape(url,labels,max_tries=4,proxy_iter = None,wait_for = 0,raw_tags = True): |
||||
|
browser = browser_class(headless=False) |
||||
|
if proxy_iter is not None: |
||||
|
for trial in range(max_tries): |
||||
|
proxy_ip = next(proxy_iter) |
||||
|
try: |
||||
|
browser.restart_browser(start_page = url,proxy=proxy_ip) |
||||
|
if wait_for: |
||||
|
time.sleep(wait_for) |
||||
|
source = browser.get_source() |
||||
|
break |
||||
|
except Exception as e: |
||||
|
print(e) |
||||
|
print(proxy_ip) |
||||
|
proxy_iter.blacklist(proxy) |
||||
|
|
||||
|
else: |
||||
|
for trial in range(max_tries): |
||||
|
try: |
||||
|
if trial == 0: |
||||
|
browser.restart_browser(start_page = url) |
||||
|
else: |
||||
|
browser.open(url) |
||||
|
except Exception as e: |
||||
|
print(e) |
||||
|
|
||||
|
scraper = scraper(source) |
||||
|
return scraper.label_convert(raw_tags=True) |
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
ret = scrape('https://www.google.com',{'imgs':'//img'},wait_for = 10) |
||||
@ -0,0 +1,57 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
|
<title>uBlock — Your filters</title> |
||||
|
|
||||
|
<link rel="stylesheet" href="lib/codemirror/lib/codemirror.css"> |
||||
|
<link rel="stylesheet" href="lib/codemirror/addon/search/matchesonscrollbar.css"> |
||||
|
|
||||
|
<link rel="stylesheet" href="css/common.css"> |
||||
|
<link rel="stylesheet" href="css/dashboard-common.css"> |
||||
|
<link rel="stylesheet" href="css/cloud-ui.css"> |
||||
|
<link rel="stylesheet" href="css/1p-filters.css"> |
||||
|
<link rel="stylesheet" href="css/codemirror.css"> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
|
||||
|
<div class="body"> |
||||
|
<div id="cloudWidget" class="hide" data-cloud-entry="myFiltersPane"></div> |
||||
|
|
||||
|
<p class="vverbose"><span data-i18n="1pFormatHint"></span> <a class="fa info" href="https://github.com/gorhill/uBlock/wiki/Static-filter-syntax" target="_blank"></a></p> |
||||
|
<p> |
||||
|
<button id="userFiltersApply" class="custom important iconifiable" type="button" disabled><span class="fa"></span><span data-i18n="1pApplyChanges"></span></button> |
||||
|
<button id="userFiltersRevert" class="custom iconifiable" type="button" disabled><span class="fa"></span><span data-i18n="genericRevert"></span></button> |
||||
|
   |
||||
|
<button id="importUserFiltersFromFile" class="custom iconifiable" type="button"><span class="fa"></span><span data-i18n="1pImport"></span></button> |
||||
|
<button id="exportUserFiltersToFile" class="custom iconifiable" type="button"><span class="fa"></span><span data-i18n="1pExport"></span></button> |
||||
|
</p> |
||||
|
</div> |
||||
|
<div id="userFilters" class="codeMirrorContainer codeMirrorFillVertical" spellcheck="false"></div> |
||||
|
<div class="hidden"> |
||||
|
<input id="importFilePicker" type="file" accept="text/plain"> |
||||
|
</div> |
||||
|
|
||||
|
<script src="lib/codemirror/lib/codemirror.js"></script> |
||||
|
<script src="lib/codemirror/addon/display/panel.js"></script> |
||||
|
<script src="lib/codemirror/addon/scroll/annotatescrollbar.js"></script> |
||||
|
<script src="lib/codemirror/addon/search/matchesonscrollbar.js"></script> |
||||
|
<script src="lib/codemirror/addon/search/searchcursor.js"></script> |
||||
|
<script src="lib/codemirror/addon/selection/active-line.js"></script> |
||||
|
|
||||
|
<script src="js/codemirror/search.js"></script> |
||||
|
<script src="js/codemirror/ubo-static-filtering.js"></script> |
||||
|
|
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/dashboard-common.js"></script> |
||||
|
<script src="js/cloud-ui.js"></script> |
||||
|
<script src="js/1p-filters.js"></script> |
||||
|
|
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,69 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
|
<title>uBlock — Filter lists</title> |
||||
|
<link rel="stylesheet" type="text/css" href="css/common.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/dashboard-common.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/cloud-ui.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/3p-filters.css"> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
|
||||
|
<div class="body"> |
||||
|
|
||||
|
<div id="cloudWidget" class="hide" data-cloud-entry="tpFiltersPane"></div> |
||||
|
<ul id="options" class="root"> |
||||
|
<li><button id="buttonUpdate" class="custom important disabled" data-i18n="3pUpdateNow"></button> |
||||
|
<button id="buttonPurgeAll" class="custom disabled" data-i18n="3pPurgeAll"></button> |
||||
|
<button id="buttonApply" class="custom important disabled" data-i18n="3pApplyChanges"></button> |
||||
|
<li><input type="checkbox" id="autoUpdate"><label data-i18n="3pAutoUpdatePrompt1" for="autoUpdate"></label>  |
||||
|
<li><input type="checkbox" id="parseCosmeticFilters"><label data-i18n="3pParseAllABPHideFiltersPrompt1" for="parseCosmeticFilters"></label><button class="whatisthis"></button> |
||||
|
<div class="whatisthis-expandable para" data-i18n="3pParseAllABPHideFiltersInfo"></div> |
||||
|
<li><input type="checkbox" id="ignoreGenericCosmeticFilters"><label data-i18n="3pIgnoreGenericCosmeticFilters" for="ignoreGenericCosmeticFilters"></label><button class="whatisthis"></button> |
||||
|
<div class="whatisthis-expandable para" data-i18n="3pIgnoreGenericCosmeticFiltersInfo"></div> |
||||
|
</ul> |
||||
|
<ul class="root"> |
||||
|
<li><span id="listsOfBlockedHostsPrompt"></span> |
||||
|
<ul id="lists"></ul> |
||||
|
</ul> |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
<div id="templates" style="display: none;"> |
||||
|
<ul> |
||||
|
<li class="groupEntry"><span class="geDetails"><span class="geName"></span> <span class="geCount dim"></span></span> |
||||
|
<ul class="listEntries"></ul> |
||||
|
</li> |
||||
|
<li class="listEntry"> |
||||
|
<input type="checkbox"><!-- |
||||
|
--><a class="content" type="text/plain" target="_blank" href=""></a>​<!-- |
||||
|
--><a class="fa support" href="" target="_blank"></a>​<!-- |
||||
|
--><a class="fa remove" href=""></a>​<!-- |
||||
|
--><a class="fa mustread" href="" target="_blank"></a>​<!-- |
||||
|
--><span class="fa status unsecure" title="http"></span>​<!-- |
||||
|
--><span class="counts dim"></span>​<!-- |
||||
|
--><span class="fa status obsolete" data-i18n-title="3pExternalListObsolete"></span>​<!-- |
||||
|
--><span class="fa status cache"></span>​<!-- |
||||
|
--><span class="fa status updating" data-i18n-title="3pUpdating"></span>​<!-- |
||||
|
--><span class="fa status failed" data-i18n-title="3pNetworkError"></span> |
||||
|
</li> |
||||
|
<li class="listEntry toImport"><input type="checkbox" id="importLists"><label for="importLists" data-i18n="3pImport"></label><!-- |
||||
|
--><a class="fa info towiki" href="https://github.com/gorhill/uBlock/wiki/Filter-lists-from-around-the-web" target="_blank"></a><!-- |
||||
|
--><textarea id="externalLists" dir="ltr" spellcheck="false" placeholder="3pExternalListsHint"></textarea> |
||||
|
</ul> |
||||
|
</div> |
||||
|
|
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/dashboard-common.js"></script> |
||||
|
<script src="js/cloud-ui.js"></script> |
||||
|
<script src="js/3p-filters.js"></script> |
||||
|
|
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,47 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
|
<title>uBlock — About</title> |
||||
|
<link rel="stylesheet" type="text/css" href="css/common.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/dashboard-common.css"> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
|
||||
|
<div class="body"> |
||||
|
<p id="aboutNameVer"></p> |
||||
|
<p>Copyright (c) Raymond Hill 2014-present<br> |
||||
|
|
||||
|
</p> |
||||
|
<ul> |
||||
|
<li><a href="https://github.com/gorhill/uBlock/releases" data-i18n="aboutChangelog"></a> |
||||
|
<li><a href="https://github.com/gorhill/uBlock/wiki" data-i18n="aboutWiki"></a> |
||||
|
<li><a href="https://old.reddit.com/r/uBlockOrigin/" data-i18n="aboutSupport"></a> |
||||
|
<li><a href="https://github.com/uBlockOrigin/uBlock-issues/issues" data-i18n="aboutIssues"></a> |
||||
|
<li><a href="https://github.com/gorhill/uBlock" data-i18n="aboutCode"></a> |
||||
|
<li><span data-i18n="aboutContributors"></span> |
||||
|
<ul> |
||||
|
<li><a href="https://github.com/gorhill/uBlock/graphs/contributors">GitHub</a> |
||||
|
<li><a href="https://crowdin.net/project/ublock">Crowdin</a> |
||||
|
</ul> |
||||
|
<li><span data-i18n="aboutDependencies"></span><ul> |
||||
|
<li><a href="https://github.com/bestiejs/punycode.js" target="_blank">Punycode.js</a> by <a href="https://github.com/mathiasbynens">Mathias Bynens</a> |
||||
|
<li><a href="https://fontawesome.com/" target="_blank">Font Awesome</a> by <a href="https://github.com/davegandy">Dave Gandy</a> |
||||
|
<li><a href="https://codemirror.net/" target="_blank">CodeMirror</a> by <a href="https://github.com/marijnh">Marijn Haverbeke</a> |
||||
|
<li><a href="https://github.com/Swatinem/diff" target="_blank">An implementation of Myers' diff algorithm</a> by <a href="https://github.com/Swatinem">Arpad Borsos</a> |
||||
|
</ul> |
||||
|
</ul> |
||||
|
</div> |
||||
|
|
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/dashboard-common.js"></script> |
||||
|
<script src="js/about.js"></script> |
||||
|
|
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,52 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
|
<title data-i18n="assetViewerPageName"></title> |
||||
|
<link rel="stylesheet" href="lib/codemirror/lib/codemirror.css"> |
||||
|
<link rel="stylesheet" href="lib/codemirror/addon/search/matchesonscrollbar.css"> |
||||
|
<link rel="stylesheet" href="css/common.css"> |
||||
|
<link rel="stylesheet" href="css/codemirror.css"> |
||||
|
<link rel="shortcut icon" type="image/png" href="img/icon_32.png"/> |
||||
|
<style> |
||||
|
body { |
||||
|
border: 0; |
||||
|
margin: 0; |
||||
|
padding: 0; |
||||
|
} |
||||
|
#content { |
||||
|
height: 100vh; |
||||
|
width: 100vw; |
||||
|
} |
||||
|
|
||||
|
/* https://github.com/uBlockOrigin/uBlock-issues/issues/292 */ |
||||
|
.CodeMirror-wrap pre { |
||||
|
word-break: break-all; |
||||
|
} |
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
|
||||
|
<div id="content" class="codeMirrorContainer"></div> |
||||
|
|
||||
|
<script src="lib/codemirror/lib/codemirror.js"></script> |
||||
|
<script src="lib/codemirror/addon/display/panel.js"></script> |
||||
|
<script src="lib/codemirror/addon/scroll/annotatescrollbar.js"></script> |
||||
|
<script src="lib/codemirror/addon/search/matchesonscrollbar.js"></script> |
||||
|
<script src="lib/codemirror/addon/search/searchcursor.js"></script> |
||||
|
<script src="lib/codemirror/addon/selection/active-line.js"></script> |
||||
|
|
||||
|
<script src="js/codemirror/search.js"></script> |
||||
|
<script src="js/codemirror/ubo-static-filtering.js"></script> |
||||
|
|
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/dashboard-common.js"></script> |
||||
|
<script src="js/asset-viewer.js"></script> |
||||
|
|
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,45 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<title>uBlock Origin</title> |
||||
|
</head> |
||||
|
<body> |
||||
|
<script src="lib/lz4/lz4-block-codec-any.js"></script> |
||||
|
<script src="lib/punycode.js"></script> |
||||
|
<script src="lib/publicsuffixlist.js"></script> |
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-background.js"></script> |
||||
|
<script src="js/vapi-webrequest.js"></script><!-- Forks can pick the webext, chromium, or their own implementation --> |
||||
|
<script src="js/background.js"></script> |
||||
|
<script src="js/traffic.js"></script> |
||||
|
<script src="js/hntrie.js"></script> |
||||
|
<script src="js/utils.js"></script> |
||||
|
<script src="js/uritools.js"></script> |
||||
|
<script src="js/lz4.js"></script> |
||||
|
<script src="js/cachestorage.js"></script> |
||||
|
<script src="js/assets.js"></script> |
||||
|
<script src="js/filtering-context.js"></script> |
||||
|
<script src="js/redirect-engine.js"></script> |
||||
|
<script src="js/dynamic-net-filtering.js"></script> |
||||
|
<script src="js/static-net-filtering.js"></script> |
||||
|
<script src="js/url-net-filtering.js"></script> |
||||
|
<script src="js/static-ext-filtering.js"></script> |
||||
|
<script src="js/cosmetic-filtering.js"></script> |
||||
|
<script src="js/scriptlet-filtering.js"></script> |
||||
|
<script src="js/html-filtering.js"></script> |
||||
|
<script src="js/hnswitches.js"></script> |
||||
|
<script src="js/ublock.js"></script> |
||||
|
<script src="js/messaging.js"></script> |
||||
|
<script src="js/storage.js"></script> |
||||
|
<script src="js/logger.js"></script> |
||||
|
<script src="js/pagestore.js"></script> |
||||
|
<script src="js/tab.js"></script> |
||||
|
<script src="js/text-encode.js"></script> |
||||
|
<script src="js/contextmenu.js"></script> |
||||
|
<script src="js/reverselookup.js"></script> |
||||
|
<script src="js/start.js"></script> |
||||
|
<script src="js/commands.js"></script> |
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,23 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<title></title> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div class="cloudTools"> |
||||
|
<button id="cloudPush" type="button" class="custom" data-i18n-title="cloudPush"><span class="fa"></span></button> |
||||
|
<span id="cloudInfo" data-i18n="cloudNoData"></span> |
||||
|
<button id="cloudPull" type="button" class="custom" data-i18n-title="cloudPull" disabled><span class="fa"></span></button> |
||||
|
<button id="cloudPullAndMerge" type="button" class="custom" data-i18n-title="cloudPullAndMerge" disabled><span class="fa"><span></span></span></button> |
||||
|
</div> |
||||
|
<p id="cloudError"></p> |
||||
|
<span id="cloudCog" class="fa"></span> |
||||
|
<div id="cloudOptions"> |
||||
|
<div> |
||||
|
<p><label data-i18n="cloudDeviceNamePrompt"></label> <input id="cloudDeviceName" type="text" value=""> |
||||
|
<p><button id="cloudOptionsSubmit" type="button" data-i18n="genericSubmit"></button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,36 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
|
<title data-i18n="dashboardName"></title> |
||||
|
<link href="css/dashboard.css" rel="stylesheet" type="text/css"> |
||||
|
<link href="css/common.css" rel="stylesheet" type="text/css"> |
||||
|
<link rel="shortcut icon" type="image/png" href="img/icon_16.png"/> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
<div id="dashboard-nav"> |
||||
|
<div id="dashboard-nav-widgets"> |
||||
|
<span class="hverbose" data-i18n-title="extName"><img src="img/ublock.svg"></span><!-- |
||||
|
--><a class="tabButton" href="#settings.html" data-i18n="settingsPageName"></a><!-- |
||||
|
--><a class="tabButton" href="#3p-filters.html" data-i18n="3pPageName"></a><!-- |
||||
|
--><a class="tabButton" href="#1p-filters.html" data-i18n="1pPageName"></a><!-- |
||||
|
--><a class="tabButton" href="#dyna-rules.html" data-i18n="rulesPageName"></a><!-- |
||||
|
--><a class="tabButton" href="#whitelist.html" data-i18n="whitelistPageName"></a><!-- |
||||
|
--><a class="tabButton" href="#shortcuts.html" data-i18n="shortcutsPageName"></a><!-- |
||||
|
--><a class="tabButton" href="#about.html" data-i18n="aboutPageName"></a> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<iframe id="iframe" src=""></iframe> |
||||
|
|
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/dashboard.js"></script> |
||||
|
|
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,66 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1 user-scalable=yes"> |
||||
|
<title></title> |
||||
|
<link rel="stylesheet" href="css/common.css" type="text/css"> |
||||
|
<link rel="stylesheet" href="css/fa-icons.css" type="text/css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/document-blocked.css"> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div id="warningSign"><a class="fa-icon" href="https://github.com/gorhill/uBlock/wiki/Strict-blocking" target="_blank">exclamation-triangle</a></div> |
||||
|
|
||||
|
<div> |
||||
|
<p data-i18n="docblockedPrompt1"></p> |
||||
|
<div id="theURL" class="collapsed"> |
||||
|
<p class="code"></p> |
||||
|
<ul id="parsed"></ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div> |
||||
|
<p data-i18n="docblockedPrompt2"></p> |
||||
|
<p id="why" class="code"></p><!-- |
||||
|
--><p id="whyex" style="display: none;"><span data-i18n="docblockedFoundIn"></span> <span></span></p> |
||||
|
</div> |
||||
|
|
||||
|
<div> |
||||
|
<p><button id="back" data-i18n="docblockedBack" type="button"></button> |
||||
|
<button id="bye" data-i18n="docblockedClose" type="button"></button></p> |
||||
|
</div> |
||||
|
|
||||
|
<div> |
||||
|
<p id="proceed"></p> |
||||
|
<p><button id="proceedTemporary" data-i18n="docblockedDisableTemporary" type="button"></button> |
||||
|
<button id="proceedPermanent" data-i18n="docblockedDisablePermanent" type="button"></button></p> |
||||
|
</div> |
||||
|
|
||||
|
<div id="templates" style="display: none;"> |
||||
|
<span class="proceed"> |
||||
|
<span></span> |
||||
|
<span class="proceedChoice"> |
||||
|
<select> |
||||
|
<option class="hn" value="" selected> |
||||
|
<option class="dn" value=""> |
||||
|
</select> |
||||
|
</span> |
||||
|
<span class="proceedChoice code hn"></span> |
||||
|
<span></span> |
||||
|
</span> |
||||
|
<span class="filterList"> |
||||
|
<span class="filterListSeparator">•</span> |
||||
|
<a class="filterListSource" href="asset-viewer.html?url=" target="_blank"></a> <!-- |
||||
|
--><a class="fa filterListSupport" href="" target="_blank"></a> |
||||
|
</span> |
||||
|
</div> |
||||
|
|
||||
|
<script src="js/fa-icons.js"></script> |
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/document-blocked.js"></script> |
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,61 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
|
<title>uBlock — Dynamic filtering rules</title> |
||||
|
<link rel="stylesheet" type="text/css" href="lib/codemirror/lib/codemirror.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="lib/codemirror/addon/merge/merge.css"> |
||||
|
|
||||
|
<link rel="stylesheet" type="text/css" href="css/common.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/dashboard-common.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/cloud-ui.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/dyna-rules.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/codemirror.css"> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
|
||||
|
<div class="body"> |
||||
|
<div id="cloudWidget" class="hide" data-cloud-entry="myRulesPane"></div> |
||||
|
<p class="vverbose"><span data-i18n="rulesHint"></span> <a class="fa info" href="https://github.com/gorhill/uBlock/wiki/Dynamic-filtering:-rule-syntax" target="_blank"></a></p> |
||||
|
<div id="diff"> |
||||
|
<div class="tools"> |
||||
|
<div class="ruleActions"> |
||||
|
<h3 data-i18n="rulesPermanentHeader"></h3> |
||||
|
<button type="button" class="custom iconifiable" id="exportButton"><span class="fa"></span><span data-i18n="rulesExport"></span></button> |
||||
|
<button type="button" class="custom iconifiable" id="revertButton"><span class="fa"></span><span data-i18n="rulesRevert"></span></button> |
||||
|
</div> |
||||
|
<div class="ruleActions"> |
||||
|
<h3 data-i18n="rulesTemporaryHeader"></h3> |
||||
|
<button type="button" class="custom iconifiable" id="commitButton"><span class="fa"></span><span data-i18n="rulesCommit"></span></button> |
||||
|
<button type="button" class="custom iconifiable" id="importButton"><span class="fa"></span><span data-i18n="rulesImport"></span></button> |
||||
|
<button type="button" class="custom iconifiable important disabled" id="editSaveButton"><span class="fa"></span><span data-i18n="rulesEditSave"></span></button> |
||||
|
</div> |
||||
|
<div id="ruleFilter"><span class="fa"></span> <input type="text" size="20"></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="codeMirrorContainer codeMirrorMergeContainer codeMirrorFillVertical"></div> |
||||
|
|
||||
|
<div id="templates" style="display: none;"> |
||||
|
<input class="hidden" id="importFilePicker" type="file" accept="text/plain"> |
||||
|
<span class="hidden" data-i18n="rulesDefaultFileName"></span> |
||||
|
</div> |
||||
|
|
||||
|
<script src="lib/diff/swatinem_diff.js"></script> |
||||
|
<script src="lib/codemirror/lib/codemirror.js"></script> |
||||
|
<script src="lib/codemirror/addon/merge/merge.js"></script> |
||||
|
<script src="lib/codemirror/addon/selection/active-line.js"></script> |
||||
|
|
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/dashboard-common.js"></script> |
||||
|
<script src="js/cloud-ui.js"></script> |
||||
|
<script src="js/dyna-rules.js"></script> |
||||
|
|
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,238 @@ |
|||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<title>uBlock Origin Element Picker</title> |
||||
|
<style> |
||||
|
html#ublock0-epicker, |
||||
|
#ublock0-epicker body { |
||||
|
background: transparent !important; |
||||
|
color: black !important; |
||||
|
font: 12px sans-serif !important; |
||||
|
height: 100% !important; |
||||
|
margin: 0 !important; |
||||
|
overflow: hidden !important; |
||||
|
width: 100% !important; |
||||
|
} |
||||
|
#ublock0-epicker :focus { |
||||
|
outline: none !important; |
||||
|
} |
||||
|
#ublock0-epicker ul, |
||||
|
#ublock0-epicker li, |
||||
|
#ublock0-epicker div { |
||||
|
display: block !important; |
||||
|
} |
||||
|
#ublock0-epicker ul { |
||||
|
margin: 0.25em 0 0 0 !important; |
||||
|
} |
||||
|
#ublock0-epicker button { |
||||
|
background-color: #ccc !important; |
||||
|
border: 1px solid #aaa !important; |
||||
|
border-radius: 3px !important; |
||||
|
box-sizing: border-box !important; |
||||
|
box-shadow: none !important; |
||||
|
color: #000 !important; |
||||
|
cursor: pointer !important; |
||||
|
margin: 0 0 0 2px !important; |
||||
|
opacity: 0.7 !important; |
||||
|
padding: 4px 6px !important; |
||||
|
} |
||||
|
#ublock0-epicker button:first-of-type { |
||||
|
margin-left: 0 !important; |
||||
|
} |
||||
|
#ublock0-epicker button:disabled { |
||||
|
color: #999 !important; |
||||
|
background-color: #ccc !important; |
||||
|
} |
||||
|
#ublock0-epicker button:not(:disabled):hover { |
||||
|
opacity: 1 !important; |
||||
|
} |
||||
|
#ublock0-epicker #create:not(:disabled) { |
||||
|
background-color: hsl(36, 100%, 83%) !important; |
||||
|
border-color: hsl(36, 50%, 60%) !important; |
||||
|
} |
||||
|
#ublock0-epicker #preview { |
||||
|
float: left !important; |
||||
|
} |
||||
|
#ublock0-epicker body.preview #preview { |
||||
|
background-color: hsl(204, 100%, 83%) !important; |
||||
|
border-color: hsl(204, 50%, 60%) !important; |
||||
|
} |
||||
|
#ublock0-epicker section { |
||||
|
border: 0 !important; |
||||
|
box-sizing: border-box !important; |
||||
|
display: inline-block !important; |
||||
|
width: 100% !important; |
||||
|
} |
||||
|
#ublock0-epicker section > div:first-child { |
||||
|
border: 1px solid #aaa !important; |
||||
|
margin: 0 !important; |
||||
|
position: relative !important; |
||||
|
} |
||||
|
#ublock0-epicker section.invalidFilter > div:first-child { |
||||
|
border-color: red !important; |
||||
|
} |
||||
|
#ublock0-epicker section > div:first-child > textarea { |
||||
|
background-color: #fff !important; |
||||
|
border: none !important; |
||||
|
box-sizing: border-box !important; |
||||
|
color: #000 !important; |
||||
|
font: 11px monospace !important; |
||||
|
height: 8em !important; |
||||
|
margin: 0 !important; |
||||
|
overflow: hidden !important; |
||||
|
overflow-y: auto !important; |
||||
|
padding: 2px !important; |
||||
|
resize: none !important; |
||||
|
width: 100% !important; |
||||
|
word-break: break-all !important; |
||||
|
} |
||||
|
#ublock0-epicker #resultsetCount { |
||||
|
background-color: #aaa !important; |
||||
|
bottom: 0 !important; |
||||
|
color: white !important; |
||||
|
padding: 2px 4px !important; |
||||
|
position: absolute !important; |
||||
|
right: 0 !important; |
||||
|
} |
||||
|
#ublock0-epicker section.invalidFilter #resultsetCount { |
||||
|
background-color: red !important; |
||||
|
} |
||||
|
#ublock0-epicker section > div:first-child + div { |
||||
|
direction: ltr !important; |
||||
|
margin: 2px 0 !important; |
||||
|
text-align: right !important; |
||||
|
} |
||||
|
#ublock0-epicker ul { |
||||
|
padding: 0 !important; |
||||
|
list-style-type: none !important; |
||||
|
text-align: left !important; |
||||
|
overflow: hidden !important; |
||||
|
} |
||||
|
#ublock0-epicker aside > ul { |
||||
|
max-height: 16em !important; |
||||
|
overflow-y: auto !important; |
||||
|
} |
||||
|
#ublock0-epicker aside > ul > li:first-of-type { |
||||
|
margin-bottom: 0.5em !important; |
||||
|
} |
||||
|
#ublock0-epicker ul > li > span:nth-of-type(1) { |
||||
|
font-weight: bold !important; |
||||
|
} |
||||
|
#ublock0-epicker ul > li > span:nth-of-type(2) { |
||||
|
font-size: smaller !important; |
||||
|
color: gray !important; |
||||
|
} |
||||
|
#ublock0-epicker ul > li > ul { |
||||
|
list-style-type: none !important; |
||||
|
margin: 0 0 0 1em !important; |
||||
|
overflow: hidden !important; |
||||
|
text-align: left !important; |
||||
|
} |
||||
|
#ublock0-epicker ul > li > ul > li { |
||||
|
font: 11px monospace !important; |
||||
|
white-space: nowrap !important; |
||||
|
cursor: pointer !important; |
||||
|
direction: ltr !important; |
||||
|
} |
||||
|
#ublock0-epicker ul > li > ul > li:hover { |
||||
|
background-color: white !important; |
||||
|
} |
||||
|
#ublock0-epicker svg { |
||||
|
position: fixed !important; |
||||
|
top: 0 !important; |
||||
|
left: 0 !important; |
||||
|
cursor: crosshair !important; |
||||
|
width: 100% !important; |
||||
|
height: 100% !important; |
||||
|
} |
||||
|
#ublock0-epicker .paused > svg { |
||||
|
cursor: not-allowed !important; |
||||
|
} |
||||
|
#ublock0-epicker svg > path:first-child { |
||||
|
fill: rgba(0,0,0,0.5) !important; |
||||
|
fill-rule: evenodd !important; |
||||
|
} |
||||
|
#ublock0-epicker svg > path + path { |
||||
|
stroke: #F00 !important; |
||||
|
stroke-width: 0.5px !important; |
||||
|
fill: rgba(255,63,63,0.20) !important; |
||||
|
} |
||||
|
#ublock0-epicker body.zap svg > path + path { |
||||
|
stroke: #FF0 !important; |
||||
|
stroke-width: 0.5px !important; |
||||
|
fill: rgba(255,255,63,0.20) !important; |
||||
|
} |
||||
|
#ublock0-epicker body.preview svg > path { |
||||
|
fill: rgba(0,0,0,0.10) !important; |
||||
|
} |
||||
|
#ublock0-epicker body.preview svg > path + path { |
||||
|
stroke: none !important; |
||||
|
} |
||||
|
#ublock0-epicker aside { |
||||
|
background-color: #eee !important; |
||||
|
border: 1px solid #aaa !important; |
||||
|
bottom: 4px !important; |
||||
|
box-sizing: border-box !important; |
||||
|
min-width: 24em !important; |
||||
|
padding: 4px !important; |
||||
|
position: fixed !important; |
||||
|
right: 4px !important; |
||||
|
visibility: hidden !important; |
||||
|
width: calc(40% - 4px) !important; |
||||
|
} |
||||
|
#ublock0-epicker body.paused > aside { |
||||
|
opacity: 0.1; |
||||
|
visibility: visible !important; |
||||
|
z-index: 100 !important; |
||||
|
} |
||||
|
/** |
||||
|
https://github.com/gorhill/uBlock/issues/3449 |
||||
|
https://github.com/uBlockOrigin/uBlock-issues/issues/55 |
||||
|
**/ |
||||
|
@keyframes startDialog { |
||||
|
0% { opacity: 1.0; } |
||||
|
60% { opacity: 1.0; } |
||||
|
100% { opacity: 0.1; } |
||||
|
} |
||||
|
#ublock0-epicker body.paused > aside:not(:hover):not(.show) { |
||||
|
animation-duration: 1.6s !important; |
||||
|
animation-name: startDialog !important; |
||||
|
animation-timing-function: linear !important; |
||||
|
} |
||||
|
#ublock0-epicker body.paused > aside:hover { |
||||
|
opacity: 1 !important; |
||||
|
} |
||||
|
#ublock0-epicker body.paused > aside.show { |
||||
|
opacity: 1 !important; |
||||
|
} |
||||
|
#ublock0-epicker body.paused > aside.hide { |
||||
|
opacity: 0.1 !important; |
||||
|
} |
||||
|
</style> |
||||
|
</head> |
||||
|
|
||||
|
<body direction="{{bidi_dir}}"> |
||||
|
<svg><path d></path><path d></path></svg> |
||||
|
<aside> |
||||
|
<section> |
||||
|
<div> |
||||
|
<textarea lang="en" dir="ltr" spellcheck="false"></textarea> |
||||
|
<div id="resultsetCount"></div> |
||||
|
</div> |
||||
|
<div><!-- |
||||
|
--><button id="preview" type="button">{{preview}}</button><!-- |
||||
|
--><button id="create" type="button" disabled>{{create}}</button><!-- |
||||
|
--><button id="pick" type="button">{{pick}}</button><!-- |
||||
|
--><button id="quit" type="button">{{quit}}</button><!-- |
||||
|
--></div> |
||||
|
</section> |
||||
|
<ul> |
||||
|
<li id="netFilters"> |
||||
|
<span>{{netFilters}}</span><ul lang="en" class="changeFilter"></ul> |
||||
|
</li> |
||||
|
<li id="cosmeticFilters"> |
||||
|
<span>{{cosmeticFilters}}</span> <span>{{cosmeticFiltersHint}}</span> |
||||
|
<ul lang="en" class="changeFilter"></ul> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</aside> |
||||
|
</body> |
||||
@ -0,0 +1,9 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<title></title> |
||||
|
<script async src="js/is-webrtc-supported.js"></script> |
||||
|
</head> |
||||
|
<body></body> |
||||
|
</html> |
||||
@ -0,0 +1,21 @@ |
|||||
|
MIT License |
||||
|
|
||||
|
Copyright (C) 2017 by Marijn Haverbeke <marijnh@gmail.com> and others |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), to deal |
||||
|
in the Software without restriction, including without limitation the rights |
||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
|
copies of the Software, and to permit persons to whom the Software is |
||||
|
furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in |
||||
|
all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
|
THE SOFTWARE. |
||||
@ -0,0 +1,49 @@ |
|||||
|
# CodeMirror |
||||
|
|
||||
|
[](https://travis-ci.org/codemirror/CodeMirror) |
||||
|
[](https://www.npmjs.org/package/codemirror) |
||||
|
[](https://gitter.im/codemirror/CodeMirror) |
||||
|
[Funding status: ](https://marijnhaverbeke.nl/fund/) |
||||
|
|
||||
|
CodeMirror is a versatile text editor implemented in JavaScript for |
||||
|
the browser. It is specialized for editing code, and comes with over |
||||
|
100 language modes and various addons that implement more advanced |
||||
|
editing functionality. Every language comes with fully-featured code |
||||
|
and syntax highlighting to help with reading and editing complex code. |
||||
|
|
||||
|
A rich programming API and a CSS theming system are available for |
||||
|
customizing CodeMirror to fit your application, and extending it with |
||||
|
new functionality. |
||||
|
|
||||
|
You can find more information (and the |
||||
|
[manual](https://codemirror.net/doc/manual.html)) on the [project |
||||
|
page](https://codemirror.net). For questions and discussion, use the |
||||
|
[discussion forum](https://discuss.codemirror.net/). |
||||
|
|
||||
|
See |
||||
|
[CONTRIBUTING.md](https://github.com/codemirror/CodeMirror/blob/master/CONTRIBUTING.md) |
||||
|
for contributing guidelines. |
||||
|
|
||||
|
The CodeMirror community aims to be welcoming to everybody. We use the |
||||
|
[Contributor Covenant |
||||
|
(1.1)](http://contributor-covenant.org/version/1/1/0/) as our code of |
||||
|
conduct. |
||||
|
|
||||
|
### Installation |
||||
|
|
||||
|
Either get the [zip file](https://codemirror.net/codemirror.zip) with |
||||
|
the latest version, or make sure you have [Node](https://nodejs.org/) |
||||
|
installed and run: |
||||
|
|
||||
|
npm install codemirror |
||||
|
|
||||
|
**NOTE**: This is the source repository for the library, and not the |
||||
|
distribution channel. Cloning it is not the recommended way to install |
||||
|
the library, and will in fact not work unless you also run the build |
||||
|
step. |
||||
|
|
||||
|
### Quickstart |
||||
|
|
||||
|
To build the project, make sure you have Node.js installed (at least version 6) |
||||
|
and then `npm install`. To run, just open `index.html` in your |
||||
|
browser (you don't need to run a webserver). Run the tests with `npm test`. |
||||
@ -0,0 +1,127 @@ |
|||||
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
|
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
|
|
||||
|
(function(mod) { |
||||
|
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
|
mod(require("../../lib/codemirror")); |
||||
|
else if (typeof define == "function" && define.amd) // AMD
|
||||
|
define(["../../lib/codemirror"], mod); |
||||
|
else // Plain browser env
|
||||
|
mod(CodeMirror); |
||||
|
})(function(CodeMirror) { |
||||
|
CodeMirror.defineExtension("addPanel", function(node, options) { |
||||
|
options = options || {}; |
||||
|
|
||||
|
if (!this.state.panels) initPanels(this); |
||||
|
|
||||
|
var info = this.state.panels; |
||||
|
var wrapper = info.wrapper; |
||||
|
var cmWrapper = this.getWrapperElement(); |
||||
|
var replace = options.replace instanceof Panel && !options.replace.cleared; |
||||
|
|
||||
|
if (options.after instanceof Panel && !options.after.cleared) { |
||||
|
wrapper.insertBefore(node, options.before.node.nextSibling); |
||||
|
} else if (options.before instanceof Panel && !options.before.cleared) { |
||||
|
wrapper.insertBefore(node, options.before.node); |
||||
|
} else if (replace) { |
||||
|
wrapper.insertBefore(node, options.replace.node); |
||||
|
info.panels++; |
||||
|
options.replace.clear(); |
||||
|
} else if (options.position == "bottom") { |
||||
|
wrapper.appendChild(node); |
||||
|
} else if (options.position == "before-bottom") { |
||||
|
wrapper.insertBefore(node, cmWrapper.nextSibling); |
||||
|
} else if (options.position == "after-top") { |
||||
|
wrapper.insertBefore(node, cmWrapper); |
||||
|
} else { |
||||
|
wrapper.insertBefore(node, wrapper.firstChild); |
||||
|
} |
||||
|
|
||||
|
var height = (options && options.height) || node.offsetHeight; |
||||
|
this._setSize(null, info.heightLeft -= height); |
||||
|
if (!replace) { |
||||
|
info.panels++; |
||||
|
} |
||||
|
if (options.stable && isAtTop(this, node)) |
||||
|
this.scrollTo(null, this.getScrollInfo().top + height) |
||||
|
|
||||
|
return new Panel(this, node, options, height); |
||||
|
}); |
||||
|
|
||||
|
function Panel(cm, node, options, height) { |
||||
|
this.cm = cm; |
||||
|
this.node = node; |
||||
|
this.options = options; |
||||
|
this.height = height; |
||||
|
this.cleared = false; |
||||
|
} |
||||
|
|
||||
|
Panel.prototype.clear = function() { |
||||
|
if (this.cleared) return; |
||||
|
this.cleared = true; |
||||
|
var info = this.cm.state.panels; |
||||
|
this.cm._setSize(null, info.heightLeft += this.height); |
||||
|
if (this.options.stable && isAtTop(this.cm, this.node)) |
||||
|
this.cm.scrollTo(null, this.cm.getScrollInfo().top - this.height) |
||||
|
info.wrapper.removeChild(this.node); |
||||
|
if (--info.panels == 0) removePanels(this.cm); |
||||
|
}; |
||||
|
|
||||
|
Panel.prototype.changed = function(height) { |
||||
|
var newHeight = height == null ? this.node.offsetHeight : height; |
||||
|
var info = this.cm.state.panels; |
||||
|
this.cm._setSize(null, info.heightLeft -= (newHeight - this.height)); |
||||
|
this.height = newHeight; |
||||
|
}; |
||||
|
|
||||
|
function initPanels(cm) { |
||||
|
var wrap = cm.getWrapperElement(); |
||||
|
var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle; |
||||
|
var height = parseInt(style.height); |
||||
|
var info = cm.state.panels = { |
||||
|
setHeight: wrap.style.height, |
||||
|
heightLeft: height, |
||||
|
panels: 0, |
||||
|
wrapper: document.createElement("div") |
||||
|
}; |
||||
|
wrap.parentNode.insertBefore(info.wrapper, wrap); |
||||
|
var hasFocus = cm.hasFocus(); |
||||
|
info.wrapper.appendChild(wrap); |
||||
|
if (hasFocus) cm.focus(); |
||||
|
|
||||
|
cm._setSize = cm.setSize; |
||||
|
if (height != null) cm.setSize = function(width, newHeight) { |
||||
|
if (newHeight == null) return this._setSize(width, newHeight); |
||||
|
info.setHeight = newHeight; |
||||
|
if (typeof newHeight != "number") { |
||||
|
var px = /^(\d+\.?\d*)px$/.exec(newHeight); |
||||
|
if (px) { |
||||
|
newHeight = Number(px[1]); |
||||
|
} else { |
||||
|
info.wrapper.style.height = newHeight; |
||||
|
newHeight = info.wrapper.offsetHeight; |
||||
|
info.wrapper.style.height = ""; |
||||
|
} |
||||
|
} |
||||
|
cm._setSize(width, info.heightLeft += (newHeight - height)); |
||||
|
height = newHeight; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
function removePanels(cm) { |
||||
|
var info = cm.state.panels; |
||||
|
cm.state.panels = null; |
||||
|
|
||||
|
var wrap = cm.getWrapperElement(); |
||||
|
info.wrapper.parentNode.replaceChild(wrap, info.wrapper); |
||||
|
wrap.style.height = info.setHeight; |
||||
|
cm.setSize = cm._setSize; |
||||
|
cm.setSize(); |
||||
|
} |
||||
|
|
||||
|
function isAtTop(cm, dom) { |
||||
|
for (var sibling = dom.nextSibling; sibling; sibling = sibling.nextSibling) |
||||
|
if (sibling == cm.getWrapperElement()) return true |
||||
|
return false |
||||
|
} |
||||
|
}); |
||||
@ -0,0 +1,119 @@ |
|||||
|
.CodeMirror-merge { |
||||
|
position: relative; |
||||
|
border: 1px solid #ddd; |
||||
|
white-space: pre; |
||||
|
} |
||||
|
|
||||
|
.CodeMirror-merge, .CodeMirror-merge .CodeMirror { |
||||
|
height: 350px; |
||||
|
} |
||||
|
|
||||
|
.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; } |
||||
|
.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; } |
||||
|
.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; } |
||||
|
.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; } |
||||
|
|
||||
|
.CodeMirror-merge-pane { |
||||
|
display: inline-block; |
||||
|
white-space: normal; |
||||
|
vertical-align: top; |
||||
|
} |
||||
|
.CodeMirror-merge-pane-rightmost { |
||||
|
position: absolute; |
||||
|
right: 0px; |
||||
|
z-index: 1; |
||||
|
} |
||||
|
|
||||
|
.CodeMirror-merge-gap { |
||||
|
z-index: 2; |
||||
|
display: inline-block; |
||||
|
height: 100%; |
||||
|
-moz-box-sizing: border-box; |
||||
|
box-sizing: border-box; |
||||
|
overflow: hidden; |
||||
|
border-left: 1px solid #ddd; |
||||
|
border-right: 1px solid #ddd; |
||||
|
position: relative; |
||||
|
background: #f8f8f8; |
||||
|
} |
||||
|
|
||||
|
.CodeMirror-merge-scrolllock-wrap { |
||||
|
position: absolute; |
||||
|
bottom: 0; left: 50%; |
||||
|
} |
||||
|
.CodeMirror-merge-scrolllock { |
||||
|
position: relative; |
||||
|
left: -50%; |
||||
|
cursor: pointer; |
||||
|
color: #555; |
||||
|
line-height: 1; |
||||
|
} |
||||
|
.CodeMirror-merge-scrolllock:after { |
||||
|
content: "\21db\00a0\00a0\21da"; |
||||
|
} |
||||
|
.CodeMirror-merge-scrolllock.CodeMirror-merge-scrolllock-enabled:after { |
||||
|
content: "\21db\21da"; |
||||
|
} |
||||
|
|
||||
|
.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right { |
||||
|
position: absolute; |
||||
|
left: 0; top: 0; |
||||
|
right: 0; bottom: 0; |
||||
|
line-height: 1; |
||||
|
} |
||||
|
|
||||
|
.CodeMirror-merge-copy { |
||||
|
position: absolute; |
||||
|
cursor: pointer; |
||||
|
color: #44c; |
||||
|
z-index: 3; |
||||
|
} |
||||
|
|
||||
|
.CodeMirror-merge-copy-reverse { |
||||
|
position: absolute; |
||||
|
cursor: pointer; |
||||
|
color: #44c; |
||||
|
} |
||||
|
|
||||
|
.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; } |
||||
|
.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; } |
||||
|
|
||||
|
.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted { |
||||
|
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==); |
||||
|
background-position: bottom left; |
||||
|
background-repeat: repeat-x; |
||||
|
} |
||||
|
|
||||
|
.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted { |
||||
|
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==); |
||||
|
background-position: bottom left; |
||||
|
background-repeat: repeat-x; |
||||
|
} |
||||
|
|
||||
|
.CodeMirror-merge-r-chunk { background: #ffffe0; } |
||||
|
.CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; } |
||||
|
.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; } |
||||
|
.CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; } |
||||
|
|
||||
|
.CodeMirror-merge-l-chunk { background: #eef; } |
||||
|
.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; } |
||||
|
.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; } |
||||
|
.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; } |
||||
|
|
||||
|
.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; } |
||||
|
.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; } |
||||
|
.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; } |
||||
|
|
||||
|
.CodeMirror-merge-collapsed-widget:before { |
||||
|
content: "(...)"; |
||||
|
} |
||||
|
.CodeMirror-merge-collapsed-widget { |
||||
|
cursor: pointer; |
||||
|
color: #88b; |
||||
|
background: #eef; |
||||
|
border: 1px solid #ddf; |
||||
|
font-size: 90%; |
||||
|
padding: 0 3px; |
||||
|
border-radius: 4px; |
||||
|
} |
||||
|
.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; } |
||||
1002
restscrape/uBlock/lib/codemirror/addon/merge/merge.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,122 @@ |
|||||
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
|
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
|
|
||||
|
(function(mod) { |
||||
|
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
|
mod(require("../../lib/codemirror")); |
||||
|
else if (typeof define == "function" && define.amd) // AMD
|
||||
|
define(["../../lib/codemirror"], mod); |
||||
|
else // Plain browser env
|
||||
|
mod(CodeMirror); |
||||
|
})(function(CodeMirror) { |
||||
|
"use strict"; |
||||
|
|
||||
|
CodeMirror.defineExtension("annotateScrollbar", function(options) { |
||||
|
if (typeof options == "string") options = {className: options}; |
||||
|
return new Annotation(this, options); |
||||
|
}); |
||||
|
|
||||
|
CodeMirror.defineOption("scrollButtonHeight", 0); |
||||
|
|
||||
|
function Annotation(cm, options) { |
||||
|
this.cm = cm; |
||||
|
this.options = options; |
||||
|
this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight"); |
||||
|
this.annotations = []; |
||||
|
this.doRedraw = this.doUpdate = null; |
||||
|
this.div = cm.getWrapperElement().appendChild(document.createElement("div")); |
||||
|
this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none"; |
||||
|
this.computeScale(); |
||||
|
|
||||
|
function scheduleRedraw(delay) { |
||||
|
clearTimeout(self.doRedraw); |
||||
|
self.doRedraw = setTimeout(function() { self.redraw(); }, delay); |
||||
|
} |
||||
|
|
||||
|
var self = this; |
||||
|
cm.on("refresh", this.resizeHandler = function() { |
||||
|
clearTimeout(self.doUpdate); |
||||
|
self.doUpdate = setTimeout(function() { |
||||
|
if (self.computeScale()) scheduleRedraw(20); |
||||
|
}, 100); |
||||
|
}); |
||||
|
cm.on("markerAdded", this.resizeHandler); |
||||
|
cm.on("markerCleared", this.resizeHandler); |
||||
|
if (options.listenForChanges !== false) |
||||
|
cm.on("change", this.changeHandler = function() { |
||||
|
scheduleRedraw(250); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
Annotation.prototype.computeScale = function() { |
||||
|
var cm = this.cm; |
||||
|
var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) / |
||||
|
cm.getScrollerElement().scrollHeight |
||||
|
if (hScale != this.hScale) { |
||||
|
this.hScale = hScale; |
||||
|
return true; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
Annotation.prototype.update = function(annotations) { |
||||
|
this.annotations = annotations; |
||||
|
this.redraw(); |
||||
|
}; |
||||
|
|
||||
|
Annotation.prototype.redraw = function(compute) { |
||||
|
if (compute !== false) this.computeScale(); |
||||
|
var cm = this.cm, hScale = this.hScale; |
||||
|
|
||||
|
var frag = document.createDocumentFragment(), anns = this.annotations; |
||||
|
|
||||
|
var wrapping = cm.getOption("lineWrapping"); |
||||
|
var singleLineH = wrapping && cm.defaultTextHeight() * 1.5; |
||||
|
var curLine = null, curLineObj = null; |
||||
|
function getY(pos, top) { |
||||
|
if (curLine != pos.line) { |
||||
|
curLine = pos.line; |
||||
|
curLineObj = cm.getLineHandle(curLine); |
||||
|
} |
||||
|
if ((curLineObj.widgets && curLineObj.widgets.length) || |
||||
|
(wrapping && curLineObj.height > singleLineH)) |
||||
|
return cm.charCoords(pos, "local")[top ? "top" : "bottom"]; |
||||
|
var topY = cm.heightAtLine(curLineObj, "local"); |
||||
|
return topY + (top ? 0 : curLineObj.height); |
||||
|
} |
||||
|
|
||||
|
var lastLine = cm.lastLine() |
||||
|
if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) { |
||||
|
var ann = anns[i]; |
||||
|
if (ann.to.line > lastLine) continue; |
||||
|
var top = nextTop || getY(ann.from, true) * hScale; |
||||
|
var bottom = getY(ann.to, false) * hScale; |
||||
|
while (i < anns.length - 1) { |
||||
|
if (anns[i + 1].to.line > lastLine) break; |
||||
|
nextTop = getY(anns[i + 1].from, true) * hScale; |
||||
|
if (nextTop > bottom + .9) break; |
||||
|
ann = anns[++i]; |
||||
|
bottom = getY(ann.to, false) * hScale; |
||||
|
} |
||||
|
if (bottom == top) continue; |
||||
|
var height = Math.max(bottom - top, 3); |
||||
|
|
||||
|
var elt = frag.appendChild(document.createElement("div")); |
||||
|
elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: " |
||||
|
+ (top + this.buttonHeight) + "px; height: " + height + "px"; |
||||
|
elt.className = this.options.className; |
||||
|
if (ann.id) { |
||||
|
elt.setAttribute("annotation-id", ann.id); |
||||
|
} |
||||
|
} |
||||
|
this.div.textContent = ""; |
||||
|
this.div.appendChild(frag); |
||||
|
}; |
||||
|
|
||||
|
Annotation.prototype.clear = function() { |
||||
|
this.cm.off("refresh", this.resizeHandler); |
||||
|
this.cm.off("markerAdded", this.resizeHandler); |
||||
|
this.cm.off("markerCleared", this.resizeHandler); |
||||
|
if (this.changeHandler) this.cm.off("change", this.changeHandler); |
||||
|
this.div.parentNode.removeChild(this.div); |
||||
|
}; |
||||
|
}); |
||||
@ -0,0 +1,8 @@ |
|||||
|
.CodeMirror-search-match { |
||||
|
background: gold; |
||||
|
border-top: 1px solid orange; |
||||
|
border-bottom: 1px solid orange; |
||||
|
-moz-box-sizing: border-box; |
||||
|
box-sizing: border-box; |
||||
|
opacity: .5; |
||||
|
} |
||||
@ -0,0 +1,97 @@ |
|||||
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
|
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
|
|
||||
|
(function(mod) { |
||||
|
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
|
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar")); |
||||
|
else if (typeof define == "function" && define.amd) // AMD
|
||||
|
define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod); |
||||
|
else // Plain browser env
|
||||
|
mod(CodeMirror); |
||||
|
})(function(CodeMirror) { |
||||
|
"use strict"; |
||||
|
|
||||
|
CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) { |
||||
|
if (typeof options == "string") options = {className: options}; |
||||
|
if (!options) options = {}; |
||||
|
return new SearchAnnotation(this, query, caseFold, options); |
||||
|
}); |
||||
|
|
||||
|
function SearchAnnotation(cm, query, caseFold, options) { |
||||
|
this.cm = cm; |
||||
|
this.options = options; |
||||
|
var annotateOptions = {listenForChanges: false}; |
||||
|
for (var prop in options) annotateOptions[prop] = options[prop]; |
||||
|
if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match"; |
||||
|
this.annotation = cm.annotateScrollbar(annotateOptions); |
||||
|
this.query = query; |
||||
|
this.caseFold = caseFold; |
||||
|
this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1}; |
||||
|
this.matches = []; |
||||
|
this.update = null; |
||||
|
|
||||
|
this.findMatches(); |
||||
|
this.annotation.update(this.matches); |
||||
|
|
||||
|
var self = this; |
||||
|
cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); }); |
||||
|
} |
||||
|
|
||||
|
var MAX_MATCHES = 1000; |
||||
|
|
||||
|
SearchAnnotation.prototype.findMatches = function() { |
||||
|
if (!this.gap) return; |
||||
|
for (var i = 0; i < this.matches.length; i++) { |
||||
|
var match = this.matches[i]; |
||||
|
if (match.from.line >= this.gap.to) break; |
||||
|
if (match.to.line >= this.gap.from) this.matches.splice(i--, 1); |
||||
|
} |
||||
|
var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), this.caseFold); |
||||
|
var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES; |
||||
|
while (cursor.findNext()) { |
||||
|
var match = {from: cursor.from(), to: cursor.to()}; |
||||
|
if (match.from.line >= this.gap.to) break; |
||||
|
this.matches.splice(i++, 0, match); |
||||
|
if (this.matches.length > maxMatches) break; |
||||
|
} |
||||
|
this.gap = null; |
||||
|
}; |
||||
|
|
||||
|
function offsetLine(line, changeStart, sizeChange) { |
||||
|
if (line <= changeStart) return line; |
||||
|
return Math.max(changeStart, line + sizeChange); |
||||
|
} |
||||
|
|
||||
|
SearchAnnotation.prototype.onChange = function(change) { |
||||
|
var startLine = change.from.line; |
||||
|
var endLine = CodeMirror.changeEnd(change).line; |
||||
|
var sizeChange = endLine - change.to.line; |
||||
|
if (this.gap) { |
||||
|
this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line); |
||||
|
this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line); |
||||
|
} else { |
||||
|
this.gap = {from: change.from.line, to: endLine + 1}; |
||||
|
} |
||||
|
|
||||
|
if (sizeChange) for (var i = 0; i < this.matches.length; i++) { |
||||
|
var match = this.matches[i]; |
||||
|
var newFrom = offsetLine(match.from.line, startLine, sizeChange); |
||||
|
if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch); |
||||
|
var newTo = offsetLine(match.to.line, startLine, sizeChange); |
||||
|
if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch); |
||||
|
} |
||||
|
clearTimeout(this.update); |
||||
|
var self = this; |
||||
|
this.update = setTimeout(function() { self.updateAfterChange(); }, 250); |
||||
|
}; |
||||
|
|
||||
|
SearchAnnotation.prototype.updateAfterChange = function() { |
||||
|
this.findMatches(); |
||||
|
this.annotation.update(this.matches); |
||||
|
}; |
||||
|
|
||||
|
SearchAnnotation.prototype.clear = function() { |
||||
|
this.cm.off("change", this.changeHandler); |
||||
|
this.annotation.clear(); |
||||
|
}; |
||||
|
}); |
||||
@ -0,0 +1,293 @@ |
|||||
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
|
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
|
|
||||
|
(function(mod) { |
||||
|
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
|
mod(require("../../lib/codemirror")) |
||||
|
else if (typeof define == "function" && define.amd) // AMD
|
||||
|
define(["../../lib/codemirror"], mod) |
||||
|
else // Plain browser env
|
||||
|
mod(CodeMirror) |
||||
|
})(function(CodeMirror) { |
||||
|
"use strict" |
||||
|
var Pos = CodeMirror.Pos |
||||
|
|
||||
|
function regexpFlags(regexp) { |
||||
|
var flags = regexp.flags |
||||
|
return flags != null ? flags : (regexp.ignoreCase ? "i" : "") |
||||
|
+ (regexp.global ? "g" : "") |
||||
|
+ (regexp.multiline ? "m" : "") |
||||
|
} |
||||
|
|
||||
|
function ensureFlags(regexp, flags) { |
||||
|
var current = regexpFlags(regexp), target = current |
||||
|
for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1) |
||||
|
target += flags.charAt(i) |
||||
|
return current == target ? regexp : new RegExp(regexp.source, target) |
||||
|
} |
||||
|
|
||||
|
function maybeMultiline(regexp) { |
||||
|
return /\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source) |
||||
|
} |
||||
|
|
||||
|
function searchRegexpForward(doc, regexp, start) { |
||||
|
regexp = ensureFlags(regexp, "g") |
||||
|
for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) { |
||||
|
regexp.lastIndex = ch |
||||
|
var string = doc.getLine(line), match = regexp.exec(string) |
||||
|
if (match) |
||||
|
return {from: Pos(line, match.index), |
||||
|
to: Pos(line, match.index + match[0].length), |
||||
|
match: match} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function searchRegexpForwardMultiline(doc, regexp, start) { |
||||
|
if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start) |
||||
|
|
||||
|
regexp = ensureFlags(regexp, "gm") |
||||
|
var string, chunk = 1 |
||||
|
for (var line = start.line, last = doc.lastLine(); line <= last;) { |
||||
|
// This grows the search buffer in exponentially-sized chunks
|
||||
|
// between matches, so that nearby matches are fast and don't
|
||||
|
// require concatenating the whole document (in case we're
|
||||
|
// searching for something that has tons of matches), but at the
|
||||
|
// same time, the amount of retries is limited.
|
||||
|
for (var i = 0; i < chunk; i++) { |
||||
|
if (line > last) break |
||||
|
var curLine = doc.getLine(line++) |
||||
|
string = string == null ? curLine : string + "\n" + curLine |
||||
|
} |
||||
|
chunk = chunk * 2 |
||||
|
regexp.lastIndex = start.ch |
||||
|
var match = regexp.exec(string) |
||||
|
if (match) { |
||||
|
var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n") |
||||
|
var startLine = start.line + before.length - 1, startCh = before[before.length - 1].length |
||||
|
return {from: Pos(startLine, startCh), |
||||
|
to: Pos(startLine + inside.length - 1, |
||||
|
inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length), |
||||
|
match: match} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function lastMatchIn(string, regexp) { |
||||
|
var cutOff = 0, match |
||||
|
for (;;) { |
||||
|
regexp.lastIndex = cutOff |
||||
|
var newMatch = regexp.exec(string) |
||||
|
if (!newMatch) return match |
||||
|
match = newMatch |
||||
|
cutOff = match.index + (match[0].length || 1) |
||||
|
if (cutOff == string.length) return match |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function searchRegexpBackward(doc, regexp, start) { |
||||
|
regexp = ensureFlags(regexp, "g") |
||||
|
for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) { |
||||
|
var string = doc.getLine(line) |
||||
|
if (ch > -1) string = string.slice(0, ch) |
||||
|
var match = lastMatchIn(string, regexp) |
||||
|
if (match) |
||||
|
return {from: Pos(line, match.index), |
||||
|
to: Pos(line, match.index + match[0].length), |
||||
|
match: match} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function searchRegexpBackwardMultiline(doc, regexp, start) { |
||||
|
regexp = ensureFlags(regexp, "gm") |
||||
|
var string, chunk = 1 |
||||
|
for (var line = start.line, first = doc.firstLine(); line >= first;) { |
||||
|
for (var i = 0; i < chunk; i++) { |
||||
|
var curLine = doc.getLine(line--) |
||||
|
string = string == null ? curLine.slice(0, start.ch) : curLine + "\n" + string |
||||
|
} |
||||
|
chunk *= 2 |
||||
|
|
||||
|
var match = lastMatchIn(string, regexp) |
||||
|
if (match) { |
||||
|
var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n") |
||||
|
var startLine = line + before.length, startCh = before[before.length - 1].length |
||||
|
return {from: Pos(startLine, startCh), |
||||
|
to: Pos(startLine + inside.length - 1, |
||||
|
inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length), |
||||
|
match: match} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var doFold, noFold |
||||
|
if (String.prototype.normalize) { |
||||
|
doFold = function(str) { return str.normalize("NFD").toLowerCase() } |
||||
|
noFold = function(str) { return str.normalize("NFD") } |
||||
|
} else { |
||||
|
doFold = function(str) { return str.toLowerCase() } |
||||
|
noFold = function(str) { return str } |
||||
|
} |
||||
|
|
||||
|
// Maps a position in a case-folded line back to a position in the original line
|
||||
|
// (compensating for codepoints increasing in number during folding)
|
||||
|
function adjustPos(orig, folded, pos, foldFunc) { |
||||
|
if (orig.length == folded.length) return pos |
||||
|
for (var min = 0, max = pos + Math.max(0, orig.length - folded.length);;) { |
||||
|
if (min == max) return min |
||||
|
var mid = (min + max) >> 1 |
||||
|
var len = foldFunc(orig.slice(0, mid)).length |
||||
|
if (len == pos) return mid |
||||
|
else if (len > pos) max = mid |
||||
|
else min = mid + 1 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function searchStringForward(doc, query, start, caseFold) { |
||||
|
// Empty string would match anything and never progress, so we
|
||||
|
// define it to match nothing instead.
|
||||
|
if (!query.length) return null |
||||
|
var fold = caseFold ? doFold : noFold |
||||
|
var lines = fold(query).split(/\r|\n\r?/) |
||||
|
|
||||
|
search: for (var line = start.line, ch = start.ch, last = doc.lastLine() + 1 - lines.length; line <= last; line++, ch = 0) { |
||||
|
var orig = doc.getLine(line).slice(ch), string = fold(orig) |
||||
|
if (lines.length == 1) { |
||||
|
var found = string.indexOf(lines[0]) |
||||
|
if (found == -1) continue search |
||||
|
var start = adjustPos(orig, string, found, fold) + ch |
||||
|
return {from: Pos(line, adjustPos(orig, string, found, fold) + ch), |
||||
|
to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold) + ch)} |
||||
|
} else { |
||||
|
var cutFrom = string.length - lines[0].length |
||||
|
if (string.slice(cutFrom) != lines[0]) continue search |
||||
|
for (var i = 1; i < lines.length - 1; i++) |
||||
|
if (fold(doc.getLine(line + i)) != lines[i]) continue search |
||||
|
var end = doc.getLine(line + lines.length - 1), endString = fold(end), lastLine = lines[lines.length - 1] |
||||
|
if (endString.slice(0, lastLine.length) != lastLine) continue search |
||||
|
return {from: Pos(line, adjustPos(orig, string, cutFrom, fold) + ch), |
||||
|
to: Pos(line + lines.length - 1, adjustPos(end, endString, lastLine.length, fold))} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function searchStringBackward(doc, query, start, caseFold) { |
||||
|
if (!query.length) return null |
||||
|
var fold = caseFold ? doFold : noFold |
||||
|
var lines = fold(query).split(/\r|\n\r?/) |
||||
|
|
||||
|
search: for (var line = start.line, ch = start.ch, first = doc.firstLine() - 1 + lines.length; line >= first; line--, ch = -1) { |
||||
|
var orig = doc.getLine(line) |
||||
|
if (ch > -1) orig = orig.slice(0, ch) |
||||
|
var string = fold(orig) |
||||
|
if (lines.length == 1) { |
||||
|
var found = string.lastIndexOf(lines[0]) |
||||
|
if (found == -1) continue search |
||||
|
return {from: Pos(line, adjustPos(orig, string, found, fold)), |
||||
|
to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold))} |
||||
|
} else { |
||||
|
var lastLine = lines[lines.length - 1] |
||||
|
if (string.slice(0, lastLine.length) != lastLine) continue search |
||||
|
for (var i = 1, start = line - lines.length + 1; i < lines.length - 1; i++) |
||||
|
if (fold(doc.getLine(start + i)) != lines[i]) continue search |
||||
|
var top = doc.getLine(line + 1 - lines.length), topString = fold(top) |
||||
|
if (topString.slice(topString.length - lines[0].length) != lines[0]) continue search |
||||
|
return {from: Pos(line + 1 - lines.length, adjustPos(top, topString, top.length - lines[0].length, fold)), |
||||
|
to: Pos(line, adjustPos(orig, string, lastLine.length, fold))} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function SearchCursor(doc, query, pos, options) { |
||||
|
this.atOccurrence = false |
||||
|
this.doc = doc |
||||
|
pos = pos ? doc.clipPos(pos) : Pos(0, 0) |
||||
|
this.pos = {from: pos, to: pos} |
||||
|
|
||||
|
var caseFold |
||||
|
if (typeof options == "object") { |
||||
|
caseFold = options.caseFold |
||||
|
} else { // Backwards compat for when caseFold was the 4th argument
|
||||
|
caseFold = options |
||||
|
options = null |
||||
|
} |
||||
|
|
||||
|
if (typeof query == "string") { |
||||
|
if (caseFold == null) caseFold = false |
||||
|
this.matches = function(reverse, pos) { |
||||
|
return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold) |
||||
|
} |
||||
|
} else { |
||||
|
query = ensureFlags(query, "gm") |
||||
|
if (!options || options.multiline !== false) |
||||
|
this.matches = function(reverse, pos) { |
||||
|
return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos) |
||||
|
} |
||||
|
else |
||||
|
this.matches = function(reverse, pos) { |
||||
|
return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
SearchCursor.prototype = { |
||||
|
findNext: function() {return this.find(false)}, |
||||
|
findPrevious: function() {return this.find(true)}, |
||||
|
|
||||
|
find: function(reverse) { |
||||
|
var result = this.matches(reverse, this.doc.clipPos(reverse ? this.pos.from : this.pos.to)) |
||||
|
|
||||
|
// Implements weird auto-growing behavior on null-matches for
|
||||
|
// backwards-compatiblity with the vim code (unfortunately)
|
||||
|
while (result && CodeMirror.cmpPos(result.from, result.to) == 0) { |
||||
|
if (reverse) { |
||||
|
if (result.from.ch) result.from = Pos(result.from.line, result.from.ch - 1) |
||||
|
else if (result.from.line == this.doc.firstLine()) result = null |
||||
|
else result = this.matches(reverse, this.doc.clipPos(Pos(result.from.line - 1))) |
||||
|
} else { |
||||
|
if (result.to.ch < this.doc.getLine(result.to.line).length) result.to = Pos(result.to.line, result.to.ch + 1) |
||||
|
else if (result.to.line == this.doc.lastLine()) result = null |
||||
|
else result = this.matches(reverse, Pos(result.to.line + 1, 0)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (result) { |
||||
|
this.pos = result |
||||
|
this.atOccurrence = true |
||||
|
return this.pos.match || true |
||||
|
} else { |
||||
|
var end = Pos(reverse ? this.doc.firstLine() : this.doc.lastLine() + 1, 0) |
||||
|
this.pos = {from: end, to: end} |
||||
|
return this.atOccurrence = false |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
from: function() {if (this.atOccurrence) return this.pos.from}, |
||||
|
to: function() {if (this.atOccurrence) return this.pos.to}, |
||||
|
|
||||
|
replace: function(newText, origin) { |
||||
|
if (!this.atOccurrence) return |
||||
|
var lines = CodeMirror.splitLines(newText) |
||||
|
this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin) |
||||
|
this.pos.to = Pos(this.pos.from.line + lines.length - 1, |
||||
|
lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) { |
||||
|
return new SearchCursor(this.doc, query, pos, caseFold) |
||||
|
}) |
||||
|
CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) { |
||||
|
return new SearchCursor(this, query, pos, caseFold) |
||||
|
}) |
||||
|
|
||||
|
CodeMirror.defineExtension("selectMatches", function(query, caseFold) { |
||||
|
var ranges = [] |
||||
|
var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold) |
||||
|
while (cur.findNext()) { |
||||
|
if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break |
||||
|
ranges.push({anchor: cur.from(), head: cur.to()}) |
||||
|
} |
||||
|
if (ranges.length) |
||||
|
this.setSelections(ranges, 0) |
||||
|
}) |
||||
|
}); |
||||
@ -0,0 +1,72 @@ |
|||||
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
|
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
|
|
||||
|
(function(mod) { |
||||
|
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
|
mod(require("../../lib/codemirror")); |
||||
|
else if (typeof define == "function" && define.amd) // AMD
|
||||
|
define(["../../lib/codemirror"], mod); |
||||
|
else // Plain browser env
|
||||
|
mod(CodeMirror); |
||||
|
})(function(CodeMirror) { |
||||
|
"use strict"; |
||||
|
var WRAP_CLASS = "CodeMirror-activeline"; |
||||
|
var BACK_CLASS = "CodeMirror-activeline-background"; |
||||
|
var GUTT_CLASS = "CodeMirror-activeline-gutter"; |
||||
|
|
||||
|
CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { |
||||
|
var prev = old == CodeMirror.Init ? false : old; |
||||
|
if (val == prev) return |
||||
|
if (prev) { |
||||
|
cm.off("beforeSelectionChange", selectionChange); |
||||
|
clearActiveLines(cm); |
||||
|
delete cm.state.activeLines; |
||||
|
} |
||||
|
if (val) { |
||||
|
cm.state.activeLines = []; |
||||
|
updateActiveLines(cm, cm.listSelections()); |
||||
|
cm.on("beforeSelectionChange", selectionChange); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
function clearActiveLines(cm) { |
||||
|
for (var i = 0; i < cm.state.activeLines.length; i++) { |
||||
|
cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS); |
||||
|
cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS); |
||||
|
cm.removeLineClass(cm.state.activeLines[i], "gutter", GUTT_CLASS); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function sameArray(a, b) { |
||||
|
if (a.length != b.length) return false; |
||||
|
for (var i = 0; i < a.length; i++) |
||||
|
if (a[i] != b[i]) return false; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
function updateActiveLines(cm, ranges) { |
||||
|
var active = []; |
||||
|
for (var i = 0; i < ranges.length; i++) { |
||||
|
var range = ranges[i]; |
||||
|
var option = cm.getOption("styleActiveLine"); |
||||
|
if (typeof option == "object" && option.nonEmpty ? range.anchor.line != range.head.line : !range.empty()) |
||||
|
continue |
||||
|
var line = cm.getLineHandleVisualStart(range.head.line); |
||||
|
if (active[active.length - 1] != line) active.push(line); |
||||
|
} |
||||
|
if (sameArray(cm.state.activeLines, active)) return; |
||||
|
cm.operation(function() { |
||||
|
clearActiveLines(cm); |
||||
|
for (var i = 0; i < active.length; i++) { |
||||
|
cm.addLineClass(active[i], "wrap", WRAP_CLASS); |
||||
|
cm.addLineClass(active[i], "background", BACK_CLASS); |
||||
|
cm.addLineClass(active[i], "gutter", GUTT_CLASS); |
||||
|
} |
||||
|
cm.state.activeLines = active; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function selectionChange(cm, sel) { |
||||
|
updateActiveLines(cm, sel.ranges); |
||||
|
} |
||||
|
}); |
||||
@ -0,0 +1,34 @@ |
|||||
|
# diff |
||||
|
|
||||
|
implementation of myers diff algorithm |
||||
|
|
||||
|
[](https://travis-ci.org/Swatinem/diff) |
||||
|
[](https://coveralls.io/r/Swatinem/diff) |
||||
|
[](https://gemnasium.com/Swatinem/diff) |
||||
|
|
||||
|
|
||||
|
This uses the [*An O(ND) Difference Algorithm and Its Variations*](http://www.xmailserver.org/diff2.pdf) |
||||
|
Also see http://simplygenius.net/Article/DiffTutorial2 and |
||||
|
http://www.mathertel.de/Diff/ViewSrc.aspx for more inspiration |
||||
|
|
||||
|
## Installation |
||||
|
|
||||
|
$ npm install diff |
||||
|
$ component install Swatinem/diff |
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
### diff(a, b, [eql(a, b)]) |
||||
|
|
||||
|
Given two arrays (or array-likes, such as strings) `a` and `b` and an optional |
||||
|
equal function `eql`, this will return an array with the following operations: |
||||
|
* *nop* the element is in both arrays |
||||
|
* *ins* the element is only in array `b` and will be inserted |
||||
|
* *del* the element in only in array `a` and will be removed |
||||
|
* *rep* the element from `a` will be replaced by the element from `b`. |
||||
|
This is essentially the same as a del+ins |
||||
|
|
||||
|
## License |
||||
|
|
||||
|
LGPLv3 |
||||
|
|
||||
@ -0,0 +1,243 @@ |
|||||
|
/******************************************************************************* |
||||
|
|
||||
|
Key portions of code below was borrowed from: |
||||
|
https://github.com/Swatinem/diff
|
||||
|
|
||||
|
License is LGPL3 (thanks!) as per: |
||||
|
https://github.com/Swatinem/diff/blob/b58391504759/README.md
|
||||
|
|
||||
|
I chose to pick this implementation over |
||||
|
https://github.com/google/diff-match-patch as suggested by CodeMirror
|
||||
|
because: |
||||
|
|
||||
|
- Code is clean and simple to read -- useful when unfamiliar with the diff |
||||
|
algorithm, this makes changing the code easier if/when needed. |
||||
|
|
||||
|
- Smaller -- diff_match_patch comes with an extended API most of which is |
||||
|
of no use to the current project. |
||||
|
- diff_match_patch uncompressed: 74.7 KB |
||||
|
- Swatinem's diff uncompressed: 3.66 KB |
||||
|
|
||||
|
- I can easily adapt Swatinem's diff to deal with arrays of strings, which |
||||
|
is best suited for the current project -- it natively work with arrays. |
||||
|
|
||||
|
I removed portions of code which are of no use for the current project. |
||||
|
|
||||
|
I modified the diff script generator (Diff.prototype.editscript) since I |
||||
|
need to generate a script which is compatible with the output of the |
||||
|
diff_match_patch, as expected by CodeMirror. |
||||
|
|
||||
|
2018-12-20 gorhill: |
||||
|
There was an issue causing the wrong diff data to be issued, for instance |
||||
|
when diff-ing these two URLs on a character granularity basis (failure |
||||
|
point is marked): |
||||
|
| |
||||
|
/articles/5c1a7aae1854f30006cb26f7/lede/1545239527833-shutterstock_726 01757 2-copy.jpeg?crop=0.8889xw%3A0.9988xh%3B0.1089xw%2C0xh&resize=650%3A*&output-quality=55 |
||||
|
/articles/5c1a* 1854f30006cb2* /lede/15452* -shutterstock_* 017* 2-copy.jpeg?crop=0.* xw%3A* h%3B0.0* xw%2C0xh&resize=650%3A*&output-quality=55 |
||||
|
/articles/5c1aaea91854f30006cb2f1e/lede/1545253629235-shutterstock_106399017 2-copy.jpeg?crop=0.7749xw%3A1 xh%3B0.0391xw%2C0xh&resize=650%3A*&output-quality=55 |
||||
|
| |
||||
|
|
||||
|
Investigating, I found what appears to be the original source on which the |
||||
|
code below is based: |
||||
|
- "An O(ND) Difference Algorithm for C#" by Matthias Hertel |
||||
|
- http://www.mathertel.de/Diff/ViewSrc.aspx
|
||||
|
- https://github.com/mathertel
|
||||
|
|
||||
|
There was a difference; code had been commented out in the original source: |
||||
|
http://www.mathertel.de/Diff/DiffTest.aspx?oldfile=Diff.cs.v1&newfile=Diff.cs.v2
|
||||
|
|
||||
|
The developer noted: |
||||
|
> There have been overlapping boxes; that where analyzed partial differently. |
||||
|
> One return-point is enough. |
||||
|
|
||||
|
After applying the changes to the code below, the problematic diff-ing went |
||||
|
away: |
||||
|
| |
||||
|
/articles/5c1a7aae1854f30006cb26f7/lede/1545239527833-shutterstock_726 01757 2-copy.jpeg?crop=0.8889xw%3A0.9988xh%3B0.1089xw%2C0xh&resize=650%3A*&output-quality=55 |
||||
|
/articles/5c1a* 1854f30006cb2* /lede/15452* -shutterstock_* 017* 2-copy.jpeg?crop=0.* 9xw%3A* xh%3B0.* xw%2C0xh&resize=650%3A*&output-quality=55 |
||||
|
/articles/5c1aaea91854f30006cb2f1e/lede/1545253629235-shutterstock_106399017 2-copy.jpeg?crop=0.7749xw%3A1 xh%3B0.0391xw%2C0xh&resize=650%3A*&output-quality=55 |
||||
|
| |
||||
|
|
||||
|
So I will assume this was the issue. |
||||
|
|
||||
|
TODO: |
||||
|
- Apply other changes which were applied to the original code |
||||
|
|
||||
|
**/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
(function(context) { |
||||
|
|
||||
|
// CodeMirror expect these globals:
|
||||
|
context.DIFF_INSERT = 1; |
||||
|
context.DIFF_DELETE = -1; |
||||
|
context.DIFF_EQUAL = 0; |
||||
|
context.diff_match_patch = function(){}; |
||||
|
|
||||
|
context.diff_match_patch.prototype.diff_main = function(a, b) { |
||||
|
if ( a === b ) { return [ [ 0, a ] ]; } |
||||
|
var aa = a.match(/\n|[^\n]+\n?/g) || []; |
||||
|
var bb = b.match(/\n|[^\n]+\n?/g) || []; |
||||
|
var d = new Diff(aa, bb, eqlDefault); |
||||
|
return d.editscript(); |
||||
|
}; |
||||
|
|
||||
|
function eqlDefault(a, b) { return a === b; } |
||||
|
|
||||
|
function Diff(a, b, eql) { |
||||
|
this.a = a; |
||||
|
this.b = b; |
||||
|
this.eql = eql; |
||||
|
|
||||
|
this.moda = Array.apply(null, new Array(a.length)).map(true.valueOf, false); |
||||
|
this.modb = Array.apply(null, new Array(b.length)).map(true.valueOf, false); |
||||
|
|
||||
|
// just to save some allocations:
|
||||
|
this.down = {}; |
||||
|
this.up = {}; |
||||
|
|
||||
|
this.lcs(0, a.length, 0, b.length); |
||||
|
} |
||||
|
|
||||
|
Diff.prototype.editscript = function Diff_editscript() { |
||||
|
var moda = this.moda, modb = this.modb; |
||||
|
var astart = 0, aend = moda.length; |
||||
|
var bstart = 0, bend = modb.length; |
||||
|
var result = []; |
||||
|
while (astart < aend || bstart < bend) { |
||||
|
if (astart < aend && bstart < bend) { |
||||
|
if (!moda[astart] && !modb[bstart]) { |
||||
|
result.push([ 0, this.a[astart] ]); |
||||
|
astart++; bstart++; |
||||
|
continue; |
||||
|
} else if (moda[astart] && modb[bstart]) { |
||||
|
result.push([ -1, this.a[astart] ]); |
||||
|
result.push([ 1, this.b[bstart] ]); |
||||
|
astart++; bstart++; |
||||
|
continue; |
||||
|
} |
||||
|
} |
||||
|
if (astart < aend && (bstart >= bend || moda[astart])) { |
||||
|
result.push([ -1, this.a[astart] ]); |
||||
|
astart++; |
||||
|
} |
||||
|
if (bstart < bend && (astart >= aend || modb[bstart])) { |
||||
|
result.push([ 1, this.b[bstart] ]); |
||||
|
bstart++; |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
}; |
||||
|
|
||||
|
Diff.prototype.lcs = function Diff_lcs(astart, aend, bstart, bend) { |
||||
|
var a = this.a, b = this.b, eql = this.eql; |
||||
|
// separate common head
|
||||
|
while (astart < aend && bstart < bend && eql(a[astart], b[bstart])) { |
||||
|
astart++; bstart++; |
||||
|
} |
||||
|
// separate common tail
|
||||
|
while (astart < aend && bstart < bend && eql(a[aend - 1], b[bend - 1])) { |
||||
|
aend--; bend--; |
||||
|
} |
||||
|
|
||||
|
if (astart === aend) { |
||||
|
// only insertions
|
||||
|
while (bstart < bend) { |
||||
|
this.modb[bstart] = true; |
||||
|
bstart++; |
||||
|
} |
||||
|
} else if (bend === bstart) { |
||||
|
// only deletions
|
||||
|
while (astart < aend) { |
||||
|
this.moda[astart] = true; |
||||
|
astart++; |
||||
|
} |
||||
|
} else { |
||||
|
var snake = this.snake(astart, aend, bstart, bend); |
||||
|
|
||||
|
this.lcs(astart, snake.x, bstart, snake.y); |
||||
|
this.lcs(snake.x, aend, snake.y, bend); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
Diff.prototype.snake = function Diff_snake(astart, aend, bstart, bend) { |
||||
|
var a = this.a, b = this.b, eql = this.eql; |
||||
|
|
||||
|
var N = aend - astart, |
||||
|
M = bend - bstart; |
||||
|
|
||||
|
var kdown = astart - bstart; |
||||
|
var kup = aend - bend; |
||||
|
|
||||
|
var delta = N - M; |
||||
|
var deltaOdd = delta & 1; |
||||
|
|
||||
|
var down = this.down; |
||||
|
down[kdown + 1] = astart; |
||||
|
var up = this.up; |
||||
|
up[kup - 1] = aend; |
||||
|
|
||||
|
var Dmax = (N + M + 1) / 2; |
||||
|
for (var D = 0; D <= Dmax; D++) { |
||||
|
var k, x, y; |
||||
|
// forward path
|
||||
|
for (k = kdown - D; k <= kdown + D; k += 2) { |
||||
|
if (k === kdown - D) { |
||||
|
x = down[k + 1]; // down
|
||||
|
} else { |
||||
|
x = down[k - 1] + 1; // right
|
||||
|
if ((k < kdown + D) && (down[k + 1] >= x)) { |
||||
|
x = down[k + 1]; // down
|
||||
|
} |
||||
|
} |
||||
|
y = x - k; |
||||
|
|
||||
|
while (x < aend && y < bend && eql(a[x], b[y])) { |
||||
|
x++; y++; // diagonal
|
||||
|
} |
||||
|
down[k] = x; |
||||
|
|
||||
|
if (deltaOdd && (kup - D < k) && (k < kup + D) && |
||||
|
up[k] <= down[k]) { |
||||
|
return { |
||||
|
x: down[k], |
||||
|
y: down[k] - k, |
||||
|
// u: up[k],
|
||||
|
// v: up[k] - k,
|
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// reverse path
|
||||
|
for (k = kup - D; k <= kup + D; k += 2) { |
||||
|
if (k === kup + D) { |
||||
|
x = up[k - 1]; // up
|
||||
|
} else { |
||||
|
x = up[k + 1] - 1; // left
|
||||
|
if ((k > kup - D) && (up[k - 1] < x)) { |
||||
|
x = up[k - 1]; // up
|
||||
|
} |
||||
|
} |
||||
|
y = x - k; |
||||
|
|
||||
|
while (x > astart && y > bstart && eql(a[x - 1], b[y - 1])) { |
||||
|
x--; y--; // diagonal
|
||||
|
} |
||||
|
up[k] = x; |
||||
|
|
||||
|
if (!deltaOdd && (kdown - D <= k) && (k <= kdown + D) && |
||||
|
up[k] <= down[k]) { |
||||
|
return { |
||||
|
x: down[k], |
||||
|
y: down[k] - k, |
||||
|
// u: up[k],
|
||||
|
// v: up[k] - k,
|
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
return Diff; |
||||
|
})(self); |
||||
@ -0,0 +1,52 @@ |
|||||
|
## Purpose |
||||
|
|
||||
|
The purpose of this library is to implement LZ4 compression/decompression, |
||||
|
as documented at the official LZ4 repository: |
||||
|
|
||||
|
https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md |
||||
|
|
||||
|
The files in this directory are developed as a separate project at: |
||||
|
|
||||
|
https://github.com/gorhill/lz4-wasm |
||||
|
|
||||
|
## Files |
||||
|
|
||||
|
### `lz4-block-codec-any.js` |
||||
|
|
||||
|
The purpose is to instanciate a WebAssembly- or pure javascript-based |
||||
|
LZ4 block codec. |
||||
|
|
||||
|
If the choosen implementation is not specified, there will be an attempt to |
||||
|
create a WebAssembly-based instance. If for whatever reason this fails, a |
||||
|
pure javascript-based instance will be created. |
||||
|
|
||||
|
The script for either instance are dynamically loaded and only when needed, |
||||
|
such that no resources are wasted by keeping in memory code which won't be |
||||
|
used. |
||||
|
|
||||
|
### `lz4-block-codec-wasm.js` |
||||
|
|
||||
|
This contains the code to instanciate WebAssembly-based LZ4 block codec. Note |
||||
|
that the WebAssembly module is loaded using a `same-origin` fetch, hence |
||||
|
ensuring that no code outside the package is loaded. |
||||
|
|
||||
|
### `lz4-block-codec-js.js` |
||||
|
|
||||
|
This contains the code to instanciate pure javascript-based LZ4 block codec. |
||||
|
|
||||
|
This is used as a fallback implementation should WebAssembly not be available |
||||
|
for whatever reason. |
||||
|
|
||||
|
### `lz4-block-codec.wasm` |
||||
|
|
||||
|
This is the WebAssembly module, loaded by `lz4-block-codec-wasm.js` using a |
||||
|
`same-origin` fetch. |
||||
|
|
||||
|
### `lz4-block-codec.wat` |
||||
|
|
||||
|
The WebAssembly source code used to generate the WebAssembly module `lz4-block-codec.wasm`. |
||||
|
|
||||
|
wat2wasm ./lz4-block-codec.wat -o ./lz4-block-codec.wasm |
||||
|
wasm-opt ./lz4-block-codec.wasm -O4 -o ./lz4-block-codec.wasm |
||||
|
|
||||
|
You can get `wat2wasm` at <https://github.com/WebAssembly/wabt>, and `wasm-opt` at <https://github.com/WebAssembly/binaryen>. |
||||
@ -0,0 +1,171 @@ |
|||||
|
/******************************************************************************* |
||||
|
|
||||
|
lz4-block-codec-any.js |
||||
|
A wrapper to instanciate a wasm- and/or js-based LZ4 block |
||||
|
encoder/decoder. |
||||
|
Copyright (C) 2018 Raymond Hill |
||||
|
|
||||
|
BSD-2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are |
||||
|
met: |
||||
|
|
||||
|
1. Redistributions of source code must retain the above copyright |
||||
|
notice, this list of conditions and the following disclaimer. |
||||
|
|
||||
|
2. Redistributions in binary form must reproduce the above |
||||
|
copyright notice, this list of conditions and the following disclaimer |
||||
|
in the documentation and/or other materials provided with the |
||||
|
distribution. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
|
||||
|
Home: https://github.com/gorhill/lz4-wasm
|
||||
|
|
||||
|
I used the same license as the one picked by creator of LZ4 out of respect |
||||
|
for his creation, see https://lz4.github.io/lz4/
|
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
(function(context) { // >>>> Start of private namespace
|
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
let wd = (function() { |
||||
|
let url = document.currentScript.src; |
||||
|
let match = /[^\/]+$/.exec(url); |
||||
|
return match !== null ? |
||||
|
url.slice(0, match.index) : |
||||
|
''; |
||||
|
})(); |
||||
|
|
||||
|
let removeScript = function(script) { |
||||
|
if ( !script ) { return; } |
||||
|
if ( script.parentNode === null ) { return; } |
||||
|
script.parentNode.removeChild(script); |
||||
|
}; |
||||
|
|
||||
|
let createInstanceWASM = function() { |
||||
|
if ( context.LZ4BlockWASM instanceof Function ) { |
||||
|
let instance = new context.LZ4BlockWASM(); |
||||
|
return instance.init().then(( ) => { return instance; }); |
||||
|
} |
||||
|
if ( context.LZ4BlockWASM === null ) { |
||||
|
return Promise.resolve(null); |
||||
|
} |
||||
|
return new Promise((resolve, reject) => { |
||||
|
let script = document.createElement('script'); |
||||
|
script.src = wd + 'lz4-block-codec-wasm.js'; |
||||
|
script.addEventListener('load', ( ) => { |
||||
|
if ( context.LZ4BlockWASM instanceof Function === false ) { |
||||
|
context.LZ4BlockWASM = null; |
||||
|
context.LZ4BlockWASM = undefined; |
||||
|
resolve(null); |
||||
|
} else { |
||||
|
let instance = new context.LZ4BlockWASM(); |
||||
|
instance.init() |
||||
|
.then(( ) => { |
||||
|
resolve(instance); |
||||
|
}) |
||||
|
.catch(error => { |
||||
|
reject(error); |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
script.addEventListener('error', ( ) => { |
||||
|
context.LZ4BlockWASM = null; |
||||
|
resolve(null); |
||||
|
}); |
||||
|
document.head.appendChild(script); |
||||
|
removeScript(script); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
let createInstanceJS = function() { |
||||
|
if ( context.LZ4BlockJS instanceof Function ) { |
||||
|
let instance = new context.LZ4BlockJS(); |
||||
|
return instance.init().then(( ) => { return instance; }); |
||||
|
} |
||||
|
if ( context.LZ4BlockJS === null ) { |
||||
|
return Promise.resolve(null); |
||||
|
} |
||||
|
return new Promise((resolve, reject) => { |
||||
|
let script = document.createElement('script'); |
||||
|
script.src = wd + 'lz4-block-codec-js.js'; |
||||
|
script.addEventListener('load', ( ) => { |
||||
|
if ( context.LZ4BlockJS instanceof Function === false ) { |
||||
|
context.LZ4BlockJS = null; |
||||
|
resolve(null); |
||||
|
} else { |
||||
|
let instance = new context.LZ4BlockJS(); |
||||
|
instance.init() |
||||
|
.then(( ) => { |
||||
|
resolve(instance); |
||||
|
}) |
||||
|
.catch(error => { |
||||
|
reject(error); |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
script.addEventListener('error', ( ) => { |
||||
|
context.LZ4BlockJS = null; |
||||
|
resolve(null); |
||||
|
}); |
||||
|
document.head.appendChild(script); |
||||
|
removeScript(script); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
context.lz4BlockCodec = { |
||||
|
createInstance: function(flavor) { |
||||
|
let instantiator; |
||||
|
if ( flavor === 'wasm' ) { |
||||
|
instantiator = createInstanceWASM; |
||||
|
} else if ( flavor === 'js' ) { |
||||
|
instantiator = createInstanceJS; |
||||
|
} else { |
||||
|
instantiator = createInstanceWASM || createInstanceJS; |
||||
|
} |
||||
|
return (instantiator)() |
||||
|
.then(instance => { |
||||
|
if ( instance ) { return instance; } |
||||
|
if ( flavor === undefined ) { |
||||
|
return createInstanceJS(); |
||||
|
} |
||||
|
return null; |
||||
|
}) |
||||
|
.catch(( ) => { |
||||
|
if ( flavor === undefined ) { |
||||
|
return createInstanceJS(); |
||||
|
} |
||||
|
return null; |
||||
|
}); |
||||
|
}, |
||||
|
reset: function() { |
||||
|
context.LZ4BlockWASM = undefined; |
||||
|
context.LZ4BlockJS = undefined; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
})(this || self); // <<<< End of private namespace
|
||||
|
|
||||
|
/******************************************************************************/ |
||||
@ -0,0 +1,297 @@ |
|||||
|
/******************************************************************************* |
||||
|
|
||||
|
lz4-block-codec-js.js |
||||
|
A javascript wrapper around a pure javascript implementation of |
||||
|
LZ4 block format codec. |
||||
|
Copyright (C) 2018 Raymond Hill |
||||
|
|
||||
|
BSD-2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are |
||||
|
met: |
||||
|
|
||||
|
1. Redistributions of source code must retain the above copyright |
||||
|
notice, this list of conditions and the following disclaimer. |
||||
|
|
||||
|
2. Redistributions in binary form must reproduce the above |
||||
|
copyright notice, this list of conditions and the following disclaimer |
||||
|
in the documentation and/or other materials provided with the |
||||
|
distribution. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
|
||||
|
Home: https://github.com/gorhill/lz4-wasm
|
||||
|
|
||||
|
I used the same license as the one picked by creator of LZ4 out of respect |
||||
|
for his creation, see https://lz4.github.io/lz4/
|
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
(function(context) { // >>>> Start of private namespace
|
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
let growOutputBuffer = function(instance, size) { |
||||
|
if ( |
||||
|
instance.outputBuffer === undefined || |
||||
|
instance.outputBuffer.byteLength < size |
||||
|
) { |
||||
|
instance.outputBuffer = new ArrayBuffer(size + 0xFFFF & 0x7FFF0000); |
||||
|
} |
||||
|
return instance.outputBuffer; |
||||
|
}; |
||||
|
|
||||
|
let encodeBound = function(size) { |
||||
|
return size > 0x7E000000 ? |
||||
|
0 : |
||||
|
size + (size / 255 | 0) + 16; |
||||
|
}; |
||||
|
|
||||
|
let encodeBlock = function(instance, iBuf, oOffset) { |
||||
|
let iLen = iBuf.byteLength; |
||||
|
if ( iLen >= 0x7E000000 ) { throw new RangeError(); } |
||||
|
|
||||
|
// "The last match must start at least 12 bytes before end of block"
|
||||
|
let lastMatchPos = iLen - 12; |
||||
|
|
||||
|
// "The last 5 bytes are always literals"
|
||||
|
let lastLiteralPos = iLen - 5; |
||||
|
|
||||
|
if ( instance.hashTable === undefined ) { |
||||
|
instance.hashTable = new Int32Array(65536); |
||||
|
} |
||||
|
instance.hashTable.fill(-65536); |
||||
|
|
||||
|
if ( iBuf instanceof ArrayBuffer ) { |
||||
|
iBuf = new Uint8Array(iBuf); |
||||
|
} |
||||
|
|
||||
|
let oLen = oOffset + encodeBound(iLen); |
||||
|
let oBuf = new Uint8Array(growOutputBuffer(instance, oLen), 0, oLen); |
||||
|
let iPos = 0; |
||||
|
let oPos = oOffset; |
||||
|
let anchorPos = 0; |
||||
|
|
||||
|
// sequence-finding loop
|
||||
|
for (;;) { |
||||
|
let refPos; |
||||
|
let mOffset; |
||||
|
let sequence = iBuf[iPos] << 8 | iBuf[iPos+1] << 16 | iBuf[iPos+2] << 24; |
||||
|
|
||||
|
// match-finding loop
|
||||
|
while ( iPos <= lastMatchPos ) { |
||||
|
sequence = sequence >>> 8 | iBuf[iPos+3] << 24; |
||||
|
let hash = (sequence * 0x9E37 & 0xFFFF) + (sequence * 0x79B1 >>> 16) & 0xFFFF; |
||||
|
refPos = instance.hashTable[hash]; |
||||
|
instance.hashTable[hash] = iPos; |
||||
|
mOffset = iPos - refPos; |
||||
|
if ( |
||||
|
mOffset < 65536 && |
||||
|
iBuf[refPos+0] === ((sequence ) & 0xFF) && |
||||
|
iBuf[refPos+1] === ((sequence >>> 8) & 0xFF) && |
||||
|
iBuf[refPos+2] === ((sequence >>> 16) & 0xFF) && |
||||
|
iBuf[refPos+3] === ((sequence >>> 24) & 0xFF) |
||||
|
) { |
||||
|
break; |
||||
|
} |
||||
|
iPos += 1; |
||||
|
} |
||||
|
|
||||
|
// no match found
|
||||
|
if ( iPos > lastMatchPos ) { break; } |
||||
|
|
||||
|
// match found
|
||||
|
let lLen = iPos - anchorPos; |
||||
|
let mLen = iPos; |
||||
|
iPos += 4; refPos += 4; |
||||
|
while ( iPos < lastLiteralPos && iBuf[iPos] === iBuf[refPos] ) { |
||||
|
iPos += 1; refPos += 1; |
||||
|
} |
||||
|
mLen = iPos - mLen; |
||||
|
let token = mLen < 19 ? mLen - 4 : 15; |
||||
|
|
||||
|
// write token, length of literals if needed
|
||||
|
if ( lLen >= 15 ) { |
||||
|
oBuf[oPos++] = 0xF0 | token; |
||||
|
let l = lLen - 15; |
||||
|
while ( l >= 255 ) { |
||||
|
oBuf[oPos++] = 255; |
||||
|
l -= 255; |
||||
|
} |
||||
|
oBuf[oPos++] = l; |
||||
|
} else { |
||||
|
oBuf[oPos++] = (lLen << 4) | token; |
||||
|
} |
||||
|
|
||||
|
// write literals
|
||||
|
while ( lLen-- ) { |
||||
|
oBuf[oPos++] = iBuf[anchorPos++]; |
||||
|
} |
||||
|
|
||||
|
if ( mLen === 0 ) { break; } |
||||
|
|
||||
|
// write offset of match
|
||||
|
oBuf[oPos+0] = mOffset; |
||||
|
oBuf[oPos+1] = mOffset >>> 8; |
||||
|
oPos += 2; |
||||
|
|
||||
|
// write length of match if needed
|
||||
|
if ( mLen >= 19 ) { |
||||
|
let l = mLen - 19; |
||||
|
while ( l >= 255 ) { |
||||
|
oBuf[oPos++] = 255; |
||||
|
l -= 255; |
||||
|
} |
||||
|
oBuf[oPos++] = l; |
||||
|
} |
||||
|
|
||||
|
anchorPos = iPos; |
||||
|
} |
||||
|
|
||||
|
// last sequence is literals only
|
||||
|
let lLen = iLen - anchorPos; |
||||
|
if ( lLen >= 15 ) { |
||||
|
oBuf[oPos++] = 0xF0; |
||||
|
let l = lLen - 15; |
||||
|
while ( l >= 255 ) { |
||||
|
oBuf[oPos++] = 255; |
||||
|
l -= 255; |
||||
|
} |
||||
|
oBuf[oPos++] = l; |
||||
|
} else { |
||||
|
oBuf[oPos++] = lLen << 4; |
||||
|
} |
||||
|
while ( lLen-- ) { |
||||
|
oBuf[oPos++] = iBuf[anchorPos++]; |
||||
|
} |
||||
|
|
||||
|
return new Uint8Array(oBuf.buffer, 0, oPos); |
||||
|
}; |
||||
|
|
||||
|
let decodeBlock = function(instance, iBuf, iOffset, oLen) { |
||||
|
let iLen = iBuf.byteLength; |
||||
|
let oBuf = new Uint8Array(growOutputBuffer(instance, oLen), 0, oLen); |
||||
|
let iPos = iOffset, oPos = 0; |
||||
|
|
||||
|
while ( iPos < iLen ) { |
||||
|
let token = iBuf[iPos++]; |
||||
|
|
||||
|
// literals
|
||||
|
let clen = token >>> 4; |
||||
|
|
||||
|
// length of literals
|
||||
|
if ( clen !== 0 ) { |
||||
|
if ( clen === 15 ) { |
||||
|
let l; |
||||
|
for (;;) { |
||||
|
l = iBuf[iPos++]; |
||||
|
if ( l !== 255 ) { break; } |
||||
|
clen += 255; |
||||
|
} |
||||
|
clen += l; |
||||
|
} |
||||
|
|
||||
|
// copy literals
|
||||
|
let end = iPos + clen; |
||||
|
while ( iPos < end ) { |
||||
|
oBuf[oPos++] = iBuf[iPos++]; |
||||
|
} |
||||
|
if ( iPos === iLen ) { break; } |
||||
|
} |
||||
|
|
||||
|
// match
|
||||
|
let mOffset = iBuf[iPos+0] | (iBuf[iPos+1] << 8); |
||||
|
if ( mOffset === 0 || mOffset > oPos ) { return; } |
||||
|
iPos += 2; |
||||
|
|
||||
|
// length of match
|
||||
|
clen = (token & 0x0F) + 4; |
||||
|
if ( clen === 19 ) { |
||||
|
let l; |
||||
|
for (;;) { |
||||
|
l = iBuf[iPos++]; |
||||
|
if ( l !== 255 ) { break; } |
||||
|
clen += 255; |
||||
|
} |
||||
|
clen += l; |
||||
|
} |
||||
|
|
||||
|
// copy match
|
||||
|
let mPos = oPos - mOffset; |
||||
|
let end = oPos + clen; |
||||
|
while ( oPos < end ) { |
||||
|
oBuf[oPos++] = oBuf[mPos++]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return oBuf; |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
context.LZ4BlockJS = function() { |
||||
|
this.hashTable = undefined; |
||||
|
this.outputBuffer = undefined; |
||||
|
}; |
||||
|
|
||||
|
context.LZ4BlockJS.prototype = { |
||||
|
flavor: 'js', |
||||
|
init: function() { |
||||
|
return Promise.resolve(); |
||||
|
}, |
||||
|
|
||||
|
reset: function() { |
||||
|
this.hashTable = undefined; |
||||
|
this.outputBuffer = undefined; |
||||
|
}, |
||||
|
|
||||
|
bytesInUse: function() { |
||||
|
let bytesInUse = 0; |
||||
|
if ( this.hashTable !== undefined ) { |
||||
|
bytesInUse += this.hashTable.byteLength; |
||||
|
} |
||||
|
if ( this.outputBuffer !== undefined ) { |
||||
|
bytesInUse += this.outputBuffer.byteLength; |
||||
|
} |
||||
|
return bytesInUse; |
||||
|
}, |
||||
|
|
||||
|
encodeBlock: function(input, outputOffset) { |
||||
|
if ( input instanceof ArrayBuffer ) { |
||||
|
input = new Uint8Array(input); |
||||
|
} else if ( input instanceof Uint8Array === false ) { |
||||
|
throw new TypeError(); |
||||
|
} |
||||
|
return encodeBlock(this, input, outputOffset); |
||||
|
}, |
||||
|
|
||||
|
decodeBlock: function(input, inputOffset, outputSize) { |
||||
|
if ( input instanceof ArrayBuffer ) { |
||||
|
input = new Uint8Array(input); |
||||
|
} else if ( input instanceof Uint8Array === false ) { |
||||
|
throw new TypeError(); |
||||
|
} |
||||
|
return decodeBlock(this, input, inputOffset, outputSize); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
})(this || self); // <<<< End of private namespace
|
||||
|
|
||||
|
/******************************************************************************/ |
||||
@ -0,0 +1,194 @@ |
|||||
|
/******************************************************************************* |
||||
|
|
||||
|
lz4-block-codec-wasm.js |
||||
|
A javascript wrapper around a WebAssembly implementation of |
||||
|
LZ4 block format codec. |
||||
|
Copyright (C) 2018 Raymond Hill |
||||
|
|
||||
|
BSD-2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are |
||||
|
met: |
||||
|
|
||||
|
1. Redistributions of source code must retain the above copyright |
||||
|
notice, this list of conditions and the following disclaimer. |
||||
|
|
||||
|
2. Redistributions in binary form must reproduce the above |
||||
|
copyright notice, this list of conditions and the following disclaimer |
||||
|
in the documentation and/or other materials provided with the |
||||
|
distribution. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
|
||||
|
Home: https://github.com/gorhill/lz4-wasm
|
||||
|
|
||||
|
I used the same license as the one picked by creator of LZ4 out of respect |
||||
|
for his creation, see https://lz4.github.io/lz4/
|
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
/* global WebAssembly */ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
(function(context) { // >>>> Start of private namespace
|
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
let wd = (function() { |
||||
|
let url = document.currentScript.src; |
||||
|
let match = /[^\/]+$/.exec(url); |
||||
|
return match !== null ? |
||||
|
url.slice(0, match.index) : |
||||
|
''; |
||||
|
})(); |
||||
|
|
||||
|
let growMemoryTo = function(wasmInstance, byteLength) { |
||||
|
let lz4api = wasmInstance.exports; |
||||
|
let neededByteLength = lz4api.getLinearMemoryOffset() + byteLength; |
||||
|
let pageCountBefore = lz4api.memory.buffer.byteLength >>> 16; |
||||
|
let pageCountAfter = (neededByteLength + 65535) >>> 16; |
||||
|
if ( pageCountAfter > pageCountBefore ) { |
||||
|
lz4api.memory.grow(pageCountAfter - pageCountBefore); |
||||
|
} |
||||
|
return lz4api.memory.buffer; |
||||
|
}; |
||||
|
|
||||
|
let encodeBlock = function(wasmInstance, inputArray, outputOffset) { |
||||
|
let lz4api = wasmInstance.exports; |
||||
|
let mem0 = lz4api.getLinearMemoryOffset(); |
||||
|
let hashTableSize = 65536 * 4; |
||||
|
let inputSize = inputArray.byteLength; |
||||
|
if ( inputSize >= 0x7E000000 ) { throw new RangeError(); } |
||||
|
let memSize = |
||||
|
hashTableSize + |
||||
|
inputSize + |
||||
|
outputOffset + lz4api.lz4BlockEncodeBound(inputSize); |
||||
|
let memBuffer = growMemoryTo(wasmInstance, memSize); |
||||
|
let hashTable = new Int32Array(memBuffer, mem0, 65536); |
||||
|
hashTable.fill(-65536, 0, 65536); |
||||
|
let inputMem = new Uint8Array(memBuffer, mem0 + hashTableSize, inputSize); |
||||
|
inputMem.set(inputArray); |
||||
|
let outputSize = lz4api.lz4BlockEncode( |
||||
|
mem0 + hashTableSize, |
||||
|
inputSize, |
||||
|
mem0 + hashTableSize + inputSize + outputOffset |
||||
|
); |
||||
|
if ( outputSize === 0 ) { return; } |
||||
|
let outputArray = new Uint8Array( |
||||
|
memBuffer, |
||||
|
mem0 + hashTableSize + inputSize, |
||||
|
outputOffset + outputSize |
||||
|
); |
||||
|
return outputArray; |
||||
|
}; |
||||
|
|
||||
|
let decodeBlock = function(wasmInstance, inputArray, inputOffset, outputSize) { |
||||
|
let inputSize = inputArray.byteLength; |
||||
|
let lz4api = wasmInstance.exports; |
||||
|
let mem0 = lz4api.getLinearMemoryOffset(); |
||||
|
let memSize = inputSize + outputSize; |
||||
|
let memBuffer = growMemoryTo(wasmInstance, memSize); |
||||
|
let inputArea = new Uint8Array(memBuffer, mem0, inputSize); |
||||
|
inputArea.set(inputArray); |
||||
|
outputSize = lz4api.lz4BlockDecode( |
||||
|
mem0 + inputOffset, |
||||
|
inputSize - inputOffset, |
||||
|
mem0 + inputSize |
||||
|
); |
||||
|
if ( outputSize === 0 ) { return; } |
||||
|
return new Uint8Array(memBuffer, mem0 + inputSize, outputSize); |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
context.LZ4BlockWASM = function() { |
||||
|
this.lz4wasmInstance = undefined; |
||||
|
}; |
||||
|
|
||||
|
context.LZ4BlockWASM.prototype = { |
||||
|
flavor: 'wasm', |
||||
|
|
||||
|
init: function() { |
||||
|
if ( |
||||
|
typeof WebAssembly !== 'object' || |
||||
|
typeof WebAssembly.instantiateStreaming !== 'function' |
||||
|
) { |
||||
|
this.lz4wasmInstance = null; |
||||
|
} |
||||
|
if ( this.lz4wasmInstance === null ) { |
||||
|
return Promise.reject(); |
||||
|
} |
||||
|
if ( this.lz4wasmInstance instanceof WebAssembly.Instance ) { |
||||
|
return Promise.resolve(this.lz4wasmInstance); |
||||
|
} |
||||
|
if ( this.lz4wasmInstance === undefined ) { |
||||
|
this.lz4wasmInstance = WebAssembly.instantiateStreaming( |
||||
|
fetch(wd + 'lz4-block-codec.wasm', { mode: 'same-origin' }) |
||||
|
).then(result => { |
||||
|
this.lz4wasmInstance = undefined; |
||||
|
this.lz4wasmInstance = result && result.instance || null; |
||||
|
if ( this.lz4wasmInstance !== null ) { return this; } |
||||
|
return null; |
||||
|
}); |
||||
|
this.lz4wasmInstance.catch(( ) => { |
||||
|
this.lz4wasmInstance = null; |
||||
|
return null; |
||||
|
}); |
||||
|
} |
||||
|
return this.lz4wasmInstance; |
||||
|
}, |
||||
|
|
||||
|
reset: function() { |
||||
|
this.lz4wasmInstance = undefined; |
||||
|
}, |
||||
|
|
||||
|
bytesInUse: function() { |
||||
|
return this.lz4wasmInstance instanceof WebAssembly.Instance ? |
||||
|
this.lz4wasmInstance.exports.memory.buffer.byteLength : |
||||
|
0; |
||||
|
}, |
||||
|
|
||||
|
encodeBlock: function(input, outputOffset) { |
||||
|
if ( this.lz4wasmInstance instanceof WebAssembly.Instance === false ) { |
||||
|
throw new Error('LZ4BlockWASM: not initialized'); |
||||
|
} |
||||
|
if ( input instanceof ArrayBuffer ) { |
||||
|
input = new Uint8Array(input); |
||||
|
} else if ( input instanceof Uint8Array === false ) { |
||||
|
throw new TypeError(); |
||||
|
} |
||||
|
return encodeBlock(this.lz4wasmInstance, input, outputOffset); |
||||
|
}, |
||||
|
|
||||
|
decodeBlock: function(input, inputOffset, outputSize) { |
||||
|
if ( this.lz4wasmInstance instanceof WebAssembly.Instance === false ) { |
||||
|
throw new Error('LZ4BlockWASM: not initialized'); |
||||
|
} |
||||
|
if ( input instanceof ArrayBuffer ) { |
||||
|
input = new Uint8Array(input); |
||||
|
} else if ( input instanceof Uint8Array === false ) { |
||||
|
throw new TypeError(); |
||||
|
} |
||||
|
return decodeBlock(this.lz4wasmInstance, input, inputOffset, outputSize); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
})(this || self); // <<<< End of private namespace
|
||||
|
|
||||
|
/******************************************************************************/ |
||||
@ -0,0 +1,745 @@ |
|||||
|
;; |
||||
|
;; lz4-block-codec.wat: a WebAssembly implementation of LZ4 block format codec |
||||
|
;; Copyright (C) 2018 Raymond Hill |
||||
|
;; |
||||
|
;; BSD-2-Clause License (http://www.opensource.org/licenses/bsd-license.php) |
||||
|
;; |
||||
|
;; Redistribution and use in source and binary forms, with or without |
||||
|
;; modification, are permitted provided that the following conditions are |
||||
|
;; met: |
||||
|
;; |
||||
|
;; 1. Redistributions of source code must retain the above copyright |
||||
|
;; notice, this list of conditions and the following disclaimer. |
||||
|
;; |
||||
|
;; 2. Redistributions in binary form must reproduce the above |
||||
|
;; copyright notice, this list of conditions and the following disclaimer |
||||
|
;; in the documentation and/or other materials provided with the |
||||
|
;; distribution. |
||||
|
;; |
||||
|
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
|
;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
|
;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
|
;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
|
;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
|
;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
|
;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
|
;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
|
;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
|
;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
|
;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
;; |
||||
|
;; Home: https://github.com/gorhill/lz4-wasm |
||||
|
;; |
||||
|
;; I used the same license as the one picked by creator of LZ4 out of respect |
||||
|
;; for his creation, see https://lz4.github.io/lz4/ |
||||
|
;; |
||||
|
|
||||
|
(module |
||||
|
;; |
||||
|
;; module start |
||||
|
;; |
||||
|
|
||||
|
;; (func $log (import "imports" "log") (param i32 i32 i32)) |
||||
|
|
||||
|
(memory (export "memory") 1) |
||||
|
|
||||
|
;; |
||||
|
;; Public functions |
||||
|
;; |
||||
|
|
||||
|
;; |
||||
|
;; Return an offset to the first byte of usable linear memory. |
||||
|
;; Might be useful in the future to reserve memory space for whatever purpose, |
||||
|
;; like config variables, etc. |
||||
|
;; |
||||
|
(func $getLinearMemoryOffset (export "getLinearMemoryOffset") |
||||
|
(result i32) |
||||
|
i32.const 0 |
||||
|
) |
||||
|
|
||||
|
;; |
||||
|
;; unsigned int lz4BlockEncodeBound() |
||||
|
;; |
||||
|
;; Return the maximum size of the output buffer holding the compressed data. |
||||
|
;; |
||||
|
;; Reference implementation: |
||||
|
;; https://github.com/lz4/lz4/blob/dev/lib/lz4.h#L156 |
||||
|
;; |
||||
|
(func (export "lz4BlockEncodeBound") |
||||
|
(param $ilen i32) |
||||
|
(result i32) |
||||
|
get_local $ilen |
||||
|
i32.const 0x7E000000 |
||||
|
i32.gt_u |
||||
|
if |
||||
|
i32.const 0 |
||||
|
return |
||||
|
end |
||||
|
get_local $ilen |
||||
|
get_local $ilen |
||||
|
i32.const 255 |
||||
|
i32.div_u |
||||
|
i32.add |
||||
|
i32.const 16 |
||||
|
i32.add |
||||
|
) |
||||
|
|
||||
|
;; |
||||
|
;; unsigned int lz4BlockEncode( |
||||
|
;; unsigned int inPtr, |
||||
|
;; unsigned int ilen, |
||||
|
;; unsigned int outPtr |
||||
|
;; ) |
||||
|
;; |
||||
|
;; https://github.com/lz4/lz4/blob/dev/lib/lz4.c#L651 |
||||
|
;; |
||||
|
;; The implementation below is modified from the reference one. |
||||
|
;; |
||||
|
;; - There is no skip adjustement for repeated failure to find a match. |
||||
|
;; |
||||
|
;; - All configurable values are hard-coded to match the generic version |
||||
|
;; of the compressor. |
||||
|
;; |
||||
|
;; Note the size of the input block is NOT encoded in the output buffer, it |
||||
|
;; is for the caller to figure how they will save that information on |
||||
|
;; their side. At this point it is probably a trivial amount of work to |
||||
|
;; implement the LZ4 frame format, which encode the content size, but this |
||||
|
;; is for another day. |
||||
|
;; |
||||
|
(func $lz4BlockEncode (export "lz4BlockEncode") |
||||
|
(param $inPtr i32) ;; pointer to start of input buffer |
||||
|
(param $ilen i32) ;; size of input buffer |
||||
|
(param $outPtr i32) ;; pointer to start of output buffer |
||||
|
(result i32) |
||||
|
(local $hashPtrBeg i32) ;; start of hash buffer |
||||
|
(local $hashPtr i32) ;; current hash entry |
||||
|
(local $anchorPtr i32) ;; anchor position in input |
||||
|
(local $inPtrEnd1 i32) ;; point in input at which match-finding must cease |
||||
|
(local $inPtrEnd2 i32) ;; point in input at which match-length finding must cease |
||||
|
(local $inPtrEnd i32) ;; point to end of input |
||||
|
(local $outPtrBeg i32) ;; start of output buffer |
||||
|
(local $refPtr i32) ;; start of match in input |
||||
|
(local $seq32 i32) ;; 4-byte value from current input position |
||||
|
(local $llen i32) ;; length of found literals |
||||
|
(local $moffset i32) ;; offset to found match from current input position |
||||
|
(local $mlen i32) ;; length of found match |
||||
|
get_local $ilen ;; empty input = empty output |
||||
|
i32.const 0x7E000000 ;; max input size: 0x7E000000 |
||||
|
i32.gt_u |
||||
|
if |
||||
|
i32.const 0 |
||||
|
return |
||||
|
end |
||||
|
get_local $ilen ;; "blocks < 13 bytes cannot be compressed" |
||||
|
i32.const 13 |
||||
|
i32.lt_u |
||||
|
if |
||||
|
i32.const 0 |
||||
|
return |
||||
|
end |
||||
|
call $getLinearMemoryOffset ;; hash table is at start of usable memory |
||||
|
set_local $hashPtrBeg |
||||
|
get_local $inPtr |
||||
|
tee_local $anchorPtr |
||||
|
get_local $ilen |
||||
|
i32.add |
||||
|
tee_local $inPtrEnd |
||||
|
i32.const -5 ;; "The last 5 bytes are always literals." |
||||
|
i32.add |
||||
|
tee_local $inPtrEnd2 |
||||
|
i32.const -7 ;; "The last match must start at least 12 bytes before end of block" |
||||
|
i32.add |
||||
|
set_local $inPtrEnd1 |
||||
|
get_local $outPtr |
||||
|
set_local $outPtrBeg |
||||
|
;; |
||||
|
;; sequence processing loop |
||||
|
;; |
||||
|
block $noMoreSequence loop $nextSequence |
||||
|
get_local $inPtr |
||||
|
get_local $inPtrEnd1 |
||||
|
i32.ge_u ;; 5 or less bytes left? |
||||
|
br_if $noMoreSequence |
||||
|
get_local $inPtr ;; first sequence of 3 bytes before match-finding loop |
||||
|
i32.load8_u |
||||
|
i32.const 8 |
||||
|
i32.shl |
||||
|
get_local $inPtr |
||||
|
i32.load8_u offset=1 |
||||
|
i32.const 16 |
||||
|
i32.shl |
||||
|
i32.or |
||||
|
get_local $inPtr |
||||
|
i32.load8_u offset=2 |
||||
|
i32.const 24 |
||||
|
i32.shl |
||||
|
i32.or |
||||
|
set_local $seq32 |
||||
|
;; |
||||
|
;; match-finding loop |
||||
|
;; |
||||
|
loop $findMatch block $noMatchFound |
||||
|
get_local $inPtr |
||||
|
get_local $inPtrEnd2 |
||||
|
i32.gt_u ;; less than 12 bytes left? |
||||
|
br_if $noMoreSequence |
||||
|
get_local $seq32 ;; update last byte of current sequence |
||||
|
i32.const 8 |
||||
|
i32.shr_u |
||||
|
get_local $inPtr |
||||
|
i32.load8_u offset=3 |
||||
|
i32.const 24 |
||||
|
i32.shl |
||||
|
i32.or |
||||
|
tee_local $seq32 |
||||
|
i32.const 0x9E3779B1 ;; compute 16-bit hash |
||||
|
i32.mul |
||||
|
i32.const 16 |
||||
|
i32.shr_u ;; hash value is at top of stack |
||||
|
i32.const 2 ;; lookup refPtr at hash entry |
||||
|
i32.shl |
||||
|
get_local $hashPtrBeg |
||||
|
i32.add |
||||
|
tee_local $hashPtr |
||||
|
i32.load |
||||
|
set_local $refPtr |
||||
|
get_local $hashPtr ;; update hash entry with inPtr |
||||
|
get_local $inPtr |
||||
|
i32.store |
||||
|
get_local $inPtr |
||||
|
get_local $refPtr |
||||
|
i32.sub |
||||
|
tee_local $moffset ;; remember match offset, we will need it in case of match |
||||
|
i32.const 0xFFFF |
||||
|
i32.gt_s ;; match offset > 65535 = unusable match |
||||
|
br_if $noMatchFound |
||||
|
;; |
||||
|
;; confirm match: different sequences can yield same hash |
||||
|
;; compare-branch each byte to potentially save memory read ops |
||||
|
;; |
||||
|
get_local $seq32 ;; byte 0 |
||||
|
i32.const 0xFF |
||||
|
i32.and |
||||
|
get_local $refPtr |
||||
|
i32.load8_u |
||||
|
i32.ne ;; refPtr[0] !== inPtr[0] |
||||
|
br_if $noMatchFound |
||||
|
get_local $seq32 ;; byte 1 |
||||
|
i32.const 8 |
||||
|
i32.shr_u |
||||
|
i32.const 0xFF |
||||
|
i32.and |
||||
|
get_local $refPtr |
||||
|
i32.load8_u offset=1 |
||||
|
i32.ne |
||||
|
br_if $noMatchFound ;; refPtr[1] !== inPtr[1] |
||||
|
get_local $seq32 ;; byte 2 |
||||
|
i32.const 16 |
||||
|
i32.shr_u |
||||
|
i32.const 0xFF |
||||
|
i32.and |
||||
|
get_local $refPtr |
||||
|
i32.load8_u offset=2 |
||||
|
i32.ne ;; refPtr[2] !== inPtr[2] |
||||
|
br_if $noMatchFound |
||||
|
get_local $seq32 ;; byte 3 |
||||
|
i32.const 24 |
||||
|
i32.shr_u |
||||
|
i32.const 0xFF |
||||
|
i32.and |
||||
|
get_local $refPtr |
||||
|
i32.load8_u offset=3 |
||||
|
i32.ne ;; refPtr[3] !== inPtr[3] |
||||
|
br_if $noMatchFound |
||||
|
;; |
||||
|
;; a valid match has been found at this point |
||||
|
;; |
||||
|
get_local $inPtr ;; compute length of literals |
||||
|
get_local $anchorPtr |
||||
|
i32.sub |
||||
|
set_local $llen |
||||
|
get_local $inPtr ;; find match length |
||||
|
i32.const 4 ;; skip over confirmed 4-byte match |
||||
|
i32.add |
||||
|
set_local $inPtr |
||||
|
get_local $refPtr |
||||
|
i32.const 4 |
||||
|
i32.add |
||||
|
tee_local $mlen ;; remember refPtr to later compute match length |
||||
|
set_local $refPtr |
||||
|
block $endOfMatch loop ;; scan input buffer until match ends |
||||
|
get_local $inPtr |
||||
|
get_local $inPtrEnd2 |
||||
|
i32.ge_u |
||||
|
br_if $endOfMatch |
||||
|
get_local $inPtr |
||||
|
i32.load8_u |
||||
|
get_local $refPtr |
||||
|
i32.load8_u |
||||
|
i32.ne |
||||
|
br_if $endOfMatch |
||||
|
get_local $inPtr |
||||
|
i32.const 1 |
||||
|
i32.add |
||||
|
set_local $inPtr |
||||
|
get_local $refPtr |
||||
|
i32.const 1 |
||||
|
i32.add |
||||
|
set_local $refPtr |
||||
|
br 0 |
||||
|
end end $endOfMatch |
||||
|
;; encode token |
||||
|
get_local $outPtr ;; output token |
||||
|
get_local $llen |
||||
|
get_local $refPtr |
||||
|
get_local $mlen |
||||
|
i32.sub |
||||
|
tee_local $mlen |
||||
|
call $writeToken |
||||
|
get_local $outPtr |
||||
|
i32.const 1 |
||||
|
i32.add |
||||
|
set_local $outPtr |
||||
|
get_local $llen ;; encode/write length of literals if needed |
||||
|
i32.const 15 |
||||
|
i32.ge_s |
||||
|
if |
||||
|
get_local $outPtr |
||||
|
get_local $llen |
||||
|
call $writeLength |
||||
|
set_local $outPtr |
||||
|
end |
||||
|
;; copy literals |
||||
|
get_local $outPtr |
||||
|
get_local $anchorPtr |
||||
|
get_local $llen |
||||
|
call $copy |
||||
|
get_local $outPtr |
||||
|
get_local $llen |
||||
|
i32.add |
||||
|
set_local $outPtr |
||||
|
;; encode match offset |
||||
|
get_local $outPtr |
||||
|
get_local $moffset |
||||
|
i32.store8 |
||||
|
get_local $outPtr |
||||
|
get_local $moffset |
||||
|
i32.const 8 |
||||
|
i32.shr_u |
||||
|
i32.store8 offset=1 |
||||
|
get_local $outPtr |
||||
|
i32.const 2 |
||||
|
i32.add |
||||
|
set_local $outPtr |
||||
|
get_local $mlen ;; encode/write length of match if needed |
||||
|
i32.const 15 |
||||
|
i32.ge_s |
||||
|
if |
||||
|
get_local $outPtr |
||||
|
get_local $mlen |
||||
|
call $writeLength |
||||
|
set_local $outPtr |
||||
|
end |
||||
|
get_local $inPtr ;; advance anchor to current position |
||||
|
set_local $anchorPtr |
||||
|
br $nextSequence |
||||
|
end $noMatchFound |
||||
|
get_local $inPtr ;; no match found: advance to next byte |
||||
|
i32.const 1 |
||||
|
i32.add |
||||
|
set_local $inPtr |
||||
|
br $findMatch end ;; match offset > 65535 = unusable match |
||||
|
end end $noMoreSequence |
||||
|
;; |
||||
|
;; generate last (match-less) sequence if compression succeeded |
||||
|
;; |
||||
|
get_local $outPtr |
||||
|
get_local $outPtrBeg |
||||
|
i32.eq |
||||
|
if |
||||
|
i32.const 0 |
||||
|
return |
||||
|
end |
||||
|
get_local $outPtr |
||||
|
get_local $inPtrEnd |
||||
|
get_local $anchorPtr |
||||
|
i32.sub |
||||
|
tee_local $llen |
||||
|
i32.const 0 |
||||
|
call $writeToken |
||||
|
get_local $outPtr |
||||
|
i32.const 1 |
||||
|
i32.add |
||||
|
set_local $outPtr |
||||
|
get_local $llen |
||||
|
i32.const 15 |
||||
|
i32.ge_u |
||||
|
if |
||||
|
get_local $outPtr |
||||
|
get_local $llen |
||||
|
call $writeLength |
||||
|
set_local $outPtr |
||||
|
end |
||||
|
get_local $outPtr |
||||
|
get_local $anchorPtr |
||||
|
get_local $llen |
||||
|
call $copy |
||||
|
get_local $outPtr ;; return number of written bytes |
||||
|
get_local $llen |
||||
|
i32.add |
||||
|
get_local $outPtrBeg |
||||
|
i32.sub |
||||
|
) |
||||
|
|
||||
|
;; |
||||
|
;; unsigned int lz4BlockDecode( |
||||
|
;; unsigned int inPtr, |
||||
|
;; unsigned int ilen |
||||
|
;; unsigned int outPtr |
||||
|
;; ) |
||||
|
;; |
||||
|
;; Reference: |
||||
|
;; https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md |
||||
|
;; |
||||
|
(func (export "lz4BlockDecode") |
||||
|
(param $inPtr0 i32) ;; start of input buffer |
||||
|
(param $ilen i32) ;; length of input buffer |
||||
|
(param $outPtr0 i32) ;; start of output buffer |
||||
|
(result i32) |
||||
|
(local $inPtr i32) ;; current position in input buffer |
||||
|
(local $inPtrEnd i32) ;; end of input buffer |
||||
|
(local $outPtr i32) ;; current position in output buffer |
||||
|
(local $matchPtr i32) ;; position of current match |
||||
|
(local $token i32) ;; sequence token |
||||
|
(local $clen i32) ;; number of bytes to copy |
||||
|
(local $_ i32) ;; general purpose variable |
||||
|
get_local $ilen ;; if ( ilen == 0 ) { return 0; } |
||||
|
i32.eqz |
||||
|
if |
||||
|
i32.const 0 |
||||
|
return |
||||
|
end |
||||
|
get_local $inPtr0 |
||||
|
tee_local $inPtr ;; current position in input buffer |
||||
|
get_local $ilen |
||||
|
i32.add |
||||
|
set_local $inPtrEnd |
||||
|
get_local $outPtr0 ;; start of output buffer |
||||
|
set_local $outPtr ;; current position in output buffer |
||||
|
block $noMoreSequence loop ;; iterate through all sequences |
||||
|
get_local $inPtr |
||||
|
get_local $inPtrEnd |
||||
|
i32.ge_u |
||||
|
br_if $noMoreSequence ;; break when nothing left to read in input buffer |
||||
|
get_local $inPtr ;; read token -- consume one byte |
||||
|
i32.load8_u |
||||
|
get_local $inPtr |
||||
|
i32.const 1 |
||||
|
i32.add |
||||
|
set_local $inPtr |
||||
|
tee_local $token ;; extract length of literals from token |
||||
|
i32.const 4 |
||||
|
i32.shr_u |
||||
|
tee_local $clen ;; consume extra length bytes if present |
||||
|
i32.eqz |
||||
|
if else |
||||
|
get_local $clen |
||||
|
i32.const 15 |
||||
|
i32.eq |
||||
|
if loop |
||||
|
get_local $inPtr |
||||
|
i32.load8_u |
||||
|
get_local $inPtr |
||||
|
i32.const 1 |
||||
|
i32.add |
||||
|
set_local $inPtr |
||||
|
tee_local $_ |
||||
|
get_local $clen |
||||
|
i32.add |
||||
|
set_local $clen |
||||
|
get_local $_ |
||||
|
i32.const 255 |
||||
|
i32.eq |
||||
|
br_if 0 |
||||
|
end end |
||||
|
get_local $outPtr ;; copy literals to ouput buffer |
||||
|
get_local $inPtr |
||||
|
get_local $clen |
||||
|
call $copy |
||||
|
get_local $outPtr ;; advance output buffer pointer past copy |
||||
|
get_local $clen |
||||
|
i32.add |
||||
|
set_local $outPtr |
||||
|
get_local $clen ;; advance input buffer pointer past literals |
||||
|
get_local $inPtr |
||||
|
i32.add |
||||
|
tee_local $inPtr |
||||
|
get_local $inPtrEnd ;; exit if this is the last sequence |
||||
|
i32.eq |
||||
|
br_if $noMoreSequence |
||||
|
end |
||||
|
get_local $outPtr ;; read match offset |
||||
|
get_local $inPtr |
||||
|
i32.load8_u |
||||
|
get_local $inPtr |
||||
|
i32.load8_u offset=1 |
||||
|
i32.const 8 |
||||
|
i32.shl |
||||
|
i32.or |
||||
|
i32.sub |
||||
|
tee_local $matchPtr |
||||
|
get_local $outPtr ;; match position can't be outside input buffer bounds |
||||
|
i32.eq |
||||
|
br_if $noMoreSequence |
||||
|
get_local $matchPtr |
||||
|
get_local $inPtrEnd |
||||
|
i32.lt_u |
||||
|
br_if $noMoreSequence |
||||
|
get_local $inPtr ;; advance input pointer past match offset bytes |
||||
|
i32.const 2 |
||||
|
i32.add |
||||
|
set_local $inPtr |
||||
|
get_local $token ;; extract length of match from token |
||||
|
i32.const 15 |
||||
|
i32.and |
||||
|
i32.const 4 |
||||
|
i32.add |
||||
|
tee_local $clen |
||||
|
i32.const 19 ;; consume extra length bytes if present |
||||
|
i32.eq |
||||
|
if loop |
||||
|
get_local $inPtr |
||||
|
i32.load8_u |
||||
|
get_local $inPtr |
||||
|
i32.const 1 |
||||
|
i32.add |
||||
|
set_local $inPtr |
||||
|
tee_local $_ |
||||
|
get_local $clen |
||||
|
i32.add |
||||
|
set_local $clen |
||||
|
get_local $_ |
||||
|
i32.const 255 |
||||
|
i32.eq |
||||
|
br_if 0 |
||||
|
end end |
||||
|
get_local $outPtr ;; copy match to ouput buffer |
||||
|
get_local $matchPtr |
||||
|
get_local $clen |
||||
|
call $copy |
||||
|
get_local $clen ;; advance output buffer pointer past copy |
||||
|
get_local $outPtr |
||||
|
i32.add |
||||
|
set_local $outPtr |
||||
|
br 0 |
||||
|
end end $noMoreSequence |
||||
|
get_local $outPtr ;; return number of written bytes |
||||
|
get_local $outPtr0 |
||||
|
i32.sub |
||||
|
) |
||||
|
|
||||
|
;; |
||||
|
;; Private functions |
||||
|
;; |
||||
|
|
||||
|
;; |
||||
|
;; Encode a sequence token |
||||
|
;; |
||||
|
;; Reference documentation: |
||||
|
;; https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md |
||||
|
;; |
||||
|
(func $writeToken |
||||
|
(param $outPtr i32) |
||||
|
(param $llen i32) |
||||
|
(param $mlen i32) |
||||
|
get_local $outPtr |
||||
|
get_local $llen |
||||
|
i32.const 15 |
||||
|
get_local $llen |
||||
|
i32.const 15 |
||||
|
i32.lt_u |
||||
|
select |
||||
|
i32.const 4 |
||||
|
i32.shl |
||||
|
get_local $mlen |
||||
|
i32.const 15 |
||||
|
get_local $mlen |
||||
|
i32.const 15 |
||||
|
i32.lt_u |
||||
|
select |
||||
|
i32.or |
||||
|
i32.store8 |
||||
|
) |
||||
|
|
||||
|
;; |
||||
|
;; Encode and output length bytes. The return value is the pointer following |
||||
|
;; the last byte written. |
||||
|
;; |
||||
|
;; Reference documentation: |
||||
|
;; https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md |
||||
|
;; |
||||
|
(func $writeLength |
||||
|
(param $outPtr i32) |
||||
|
(param $len i32) |
||||
|
(result i32) |
||||
|
get_local $len |
||||
|
i32.const 15 |
||||
|
i32.sub |
||||
|
set_local $len |
||||
|
loop |
||||
|
get_local $outPtr |
||||
|
get_local $len |
||||
|
i32.const 255 |
||||
|
get_local $len |
||||
|
i32.const 255 |
||||
|
i32.lt_u |
||||
|
select |
||||
|
i32.store8 |
||||
|
get_local $outPtr |
||||
|
i32.const 1 |
||||
|
i32.add |
||||
|
set_local $outPtr |
||||
|
get_local $len |
||||
|
i32.const 255 |
||||
|
i32.sub |
||||
|
tee_local $len |
||||
|
i32.const 0 |
||||
|
i32.ge_s |
||||
|
br_if 0 |
||||
|
end |
||||
|
get_local $outPtr |
||||
|
) |
||||
|
|
||||
|
;; |
||||
|
;; Copy n bytes from source to destination. |
||||
|
;; |
||||
|
;; It is overlap-safe only from left-to-right -- which is only what is |
||||
|
;; required in the current module. |
||||
|
;; |
||||
|
(func $copy |
||||
|
(param $dst i32) |
||||
|
(param $src i32) |
||||
|
(param $len i32) |
||||
|
block $lessThan8 loop |
||||
|
get_local $len |
||||
|
i32.const 8 |
||||
|
i32.lt_u |
||||
|
br_if $lessThan8 |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u |
||||
|
i32.store8 |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u offset=1 |
||||
|
i32.store8 offset=1 |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u offset=2 |
||||
|
i32.store8 offset=2 |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u offset=3 |
||||
|
i32.store8 offset=3 |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u offset=4 |
||||
|
i32.store8 offset=4 |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u offset=5 |
||||
|
i32.store8 offset=5 |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u offset=6 |
||||
|
i32.store8 offset=6 |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u offset=7 |
||||
|
i32.store8 offset=7 |
||||
|
get_local $dst |
||||
|
i32.const 8 |
||||
|
i32.add |
||||
|
set_local $dst |
||||
|
get_local $src |
||||
|
i32.const 8 |
||||
|
i32.add |
||||
|
set_local $src |
||||
|
get_local $len |
||||
|
i32.const -8 |
||||
|
i32.add |
||||
|
set_local $len |
||||
|
br 0 |
||||
|
end end $lessThan8 |
||||
|
get_local $len |
||||
|
i32.const 4 |
||||
|
i32.ge_u |
||||
|
if |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u |
||||
|
i32.store8 |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u offset=1 |
||||
|
i32.store8 offset=1 |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u offset=2 |
||||
|
i32.store8 offset=2 |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u offset=3 |
||||
|
i32.store8 offset=3 |
||||
|
get_local $dst |
||||
|
i32.const 4 |
||||
|
i32.add |
||||
|
set_local $dst |
||||
|
get_local $src |
||||
|
i32.const 4 |
||||
|
i32.add |
||||
|
set_local $src |
||||
|
get_local $len |
||||
|
i32.const -4 |
||||
|
i32.add |
||||
|
set_local $len |
||||
|
end |
||||
|
get_local $len |
||||
|
i32.const 2 |
||||
|
i32.ge_u |
||||
|
if |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u |
||||
|
i32.store8 |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u offset=1 |
||||
|
i32.store8 offset=1 |
||||
|
get_local $dst |
||||
|
i32.const 2 |
||||
|
i32.add |
||||
|
set_local $dst |
||||
|
get_local $src |
||||
|
i32.const 2 |
||||
|
i32.add |
||||
|
set_local $src |
||||
|
get_local $len |
||||
|
i32.const -2 |
||||
|
i32.add |
||||
|
set_local $len |
||||
|
end |
||||
|
get_local $len |
||||
|
i32.eqz |
||||
|
if else |
||||
|
get_local $dst |
||||
|
get_local $src |
||||
|
i32.load8_u |
||||
|
i32.store8 |
||||
|
end |
||||
|
) |
||||
|
|
||||
|
;; |
||||
|
;; module end |
||||
|
;; |
||||
|
) |
||||
@ -0,0 +1,328 @@ |
|||||
|
/******************************************************************************* |
||||
|
|
||||
|
publicsuffixlist.js - an efficient javascript implementation to deal with |
||||
|
Mozilla Foundation's Public Suffix List <http://publicsuffix.org/list/>
|
||||
|
Copyright (C) 2013-2018 Raymond Hill |
||||
|
|
||||
|
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 |
||||
|
the Free Software Foundation, either version 3 of the License, or |
||||
|
(at your option) any later version. |
||||
|
|
||||
|
This program is distributed in the hope that it will be useful, |
||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
GNU General Public License for more details. |
||||
|
|
||||
|
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://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. |
||||
|
*/ |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
// A single instance of PublicSuffixList is enough.
|
||||
|
|
||||
|
;(function(root) { |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
let exceptions = new Map(); |
||||
|
let rules = new Map(); |
||||
|
|
||||
|
// This value dictate how the search will be performed:
|
||||
|
// < this.cutoffLength = indexOf()
|
||||
|
// >= this.cutoffLength = binary search
|
||||
|
const cutoffLength = 256; |
||||
|
const mustPunycode = /[^a-z0-9.-]/; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
// 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); |
||||
|
} |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
// 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
|
||||
|
} |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
// 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.get(tld); |
||||
|
if ( substore === undefined ) { 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; |
||||
|
if ( l >= substore.length ) { return false; } |
||||
|
var haystack = substore[l]; |
||||
|
if ( haystack.length === 0 ) { 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; |
||||
|
} |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
// 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 = new Map(); |
||||
|
rules = new Map(); |
||||
|
|
||||
|
// http://publicsuffix.org/list/:
|
||||
|
// "... all rules must be canonicalized in the normal way
|
||||
|
// for hostnames - lower-case, Punycode ..."
|
||||
|
text = text.toLowerCase(); |
||||
|
|
||||
|
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 = textEnd; |
||||
|
} |
||||
|
} |
||||
|
line = text.slice(lineBeg, lineEnd).trim(); |
||||
|
lineBeg = lineEnd + 1; |
||||
|
|
||||
|
if ( line.length === 0 ) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// Ignore comments
|
||||
|
pos = line.indexOf('//'); |
||||
|
if ( pos >= 0 ) { |
||||
|
line = line.slice(0, pos); |
||||
|
} |
||||
|
|
||||
|
// Ignore surrounding whitespaces
|
||||
|
line = line.trim(); |
||||
|
if ( !line ) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if ( mustPunycode.test(line) ) { |
||||
|
line = toAscii(line); |
||||
|
} |
||||
|
|
||||
|
// Is this an exception rule?
|
||||
|
if ( line.charAt(0) === '!' ) { |
||||
|
store = exceptions; |
||||
|
line = line.slice(1); |
||||
|
} else { |
||||
|
store = rules; |
||||
|
} |
||||
|
|
||||
|
// Extract TLD
|
||||
|
pos = line.lastIndexOf('.'); |
||||
|
if ( pos < 0 ) { |
||||
|
tld = line; |
||||
|
} else { |
||||
|
tld = line.slice(pos + 1); |
||||
|
line = line.slice(0, pos); |
||||
|
} |
||||
|
|
||||
|
// Store suffix using tld as key
|
||||
|
var substore = store.get(tld); |
||||
|
if ( substore === undefined ) { |
||||
|
store.set(tld, (substore = [])); |
||||
|
} |
||||
|
if ( line ) { |
||||
|
substore.push(line); |
||||
|
} |
||||
|
} |
||||
|
crystallize(exceptions); |
||||
|
crystallize(rules); |
||||
|
|
||||
|
window.dispatchEvent(new CustomEvent('publicSuffixList')); |
||||
|
} |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
// Cristallize the storage of suffixes using optimal internal representation
|
||||
|
// for future look up.
|
||||
|
|
||||
|
function crystallize(store) { |
||||
|
for ( var entry of store ) { |
||||
|
var tld = entry[0]; |
||||
|
var suffixes = entry[1]; |
||||
|
// No suffix
|
||||
|
if ( suffixes.length === 0 ) { |
||||
|
store.set(tld, ''); |
||||
|
continue; |
||||
|
} |
||||
|
// Concatenated list of suffixes less than cutoff length:
|
||||
|
// Store as string, lookup using indexOf()
|
||||
|
var s = suffixes.join(' '); |
||||
|
if ( s.length < cutoffLength ) { |
||||
|
store.set(tld, ' ' + s + ' '); |
||||
|
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
|
||||
|
var i = suffixes.length, l; |
||||
|
var aa = []; |
||||
|
while ( i-- ) { |
||||
|
var suffix = suffixes[i]; |
||||
|
var j = aa.length; |
||||
|
l = suffix.length; |
||||
|
while ( j <= l ) { |
||||
|
aa[j] = []; j += 1; |
||||
|
} |
||||
|
aa[l].push(suffix); |
||||
|
} |
||||
|
l = aa.length; |
||||
|
while ( l-- ) { |
||||
|
aa[l] = aa[l].sort().join(''); |
||||
|
} |
||||
|
store.set(tld, aa); |
||||
|
} |
||||
|
return store; |
||||
|
} |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
const selfieMagic = 1; |
||||
|
|
||||
|
function toSelfie() { |
||||
|
return { |
||||
|
magic: selfieMagic, |
||||
|
rules: Array.from(rules), |
||||
|
exceptions: Array.from(exceptions) |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
function fromSelfie(selfie) { |
||||
|
if ( typeof selfie !== 'object' || selfie.magic !== selfieMagic ) { |
||||
|
return false; |
||||
|
} |
||||
|
rules = new Map(selfie.rules); |
||||
|
exceptions = new Map(selfie.exceptions); |
||||
|
window.dispatchEvent(new CustomEvent('publicSuffixList')); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
// Public API
|
||||
|
|
||||
|
root = root || window; |
||||
|
|
||||
|
root.publicSuffixList = { |
||||
|
version: '1.0', |
||||
|
parse: parse, |
||||
|
getDomain: getDomain, |
||||
|
getPublicSuffix: getPublicSuffix, |
||||
|
toSelfie: toSelfie, |
||||
|
fromSelfie: fromSelfie, |
||||
|
get empty() { |
||||
|
return rules.size === 0; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
})(this); |
||||
|
|
||||
@ -0,0 +1,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 new 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)); |
||||
@ -0,0 +1,204 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=560, initial-scale=1"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/common.css"> |
||||
|
<link rel="stylesheet" href="css/fa-icons.css" type="text/css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/logger-ui.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/logger-ui-inspector.css"> |
||||
|
<link rel="shortcut icon" type="image/png" href="img/icon_16.png"> |
||||
|
<title data-i18n="statsPageName"></title> |
||||
|
<style id="vwRendererRuntimeStyles"></style> |
||||
|
</head> |
||||
|
<body> |
||||
|
|
||||
|
<div class="permatoolbar"> |
||||
|
<div> |
||||
|
<select id="pageSelector"> |
||||
|
<option value="0" data-i18n="logAll"> |
||||
|
<option value="-1" data-i18n="logBehindTheScene"> |
||||
|
<option value="_" data-i18n="loggerCurrentTab"> |
||||
|
</select> |
||||
|
<span id="refresh" class="button fa-icon disabled needdom" data-i18n-title="loggerReloadTip">refresh</span> |
||||
|
<span id="showdom" class="button fa-icon disabled needdom" data-i18n-title="loggerDomInspectorTip">code</span> |
||||
|
<span id="showpopup" class="button ubo-icon disabled needdom" data-i18n-title="loggerPopupPanelTip"><svg><use href="/img/ublock-defs.svg#ubo-solid"></use></svg></span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<a id="info" class="button fa-icon" href="https://github.com/gorhill/uBlock/wiki/The-logger" target="_blank" data-i18n-title="loggerInfoTip">info-circle</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div id="inspectors"> |
||||
|
<div id="domInspector" class="inspector hCompact"> |
||||
|
<div class="permatoolbar"> |
||||
|
<div> |
||||
|
<span class="button fa-icon vCompactToggler">double-angle-up</span> |
||||
|
<span class="button fa-icon hCompactToggler">double-angle-left</span> |
||||
|
<!-- <span class="button fa highlightMode" style="display: none"></span> --> |
||||
|
<span class="button fa-icon revert disabled">eraser</span> |
||||
|
<span class="button fa-icon commit disabled">floppy-o</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="vscrollable"> |
||||
|
<ul id="domTree"></ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div id="netInspector" class="inspector f"> |
||||
|
<div class="permatoolbar"> |
||||
|
<div> |
||||
|
<span class="button fa-icon vCompactToggler">double-angle-up</span> |
||||
|
<span id="clean" class="button fa-icon disabled">times</span> |
||||
|
<span id="clear" class="button fa-icon disabled" data-i18n-title="loggerClearTip">eraser</span> |
||||
|
<span id="pause"><span class="button fa-icon" data-i18n-title="loggerPauseTip">pause-circle-o</span><span class="button fa-icon" data-i18n-title="loggerUnpauseTip">play-circle-o</span></span> |
||||
|
<span id="filterExprGroup"> |
||||
|
<span id="filterButton" class="button fa-icon" data-i18n-title="loggerRowFiltererButtonTip">filter</span> |
||||
|
<span id="filterInput"> |
||||
|
<input type="text" placeholder="logFilterPrompt"> |
||||
|
<span id="filterExprButton" class="button fa-icon expanded" data-i18n-title="loggerRowFiltererBuiltinTip">angle-up</span> |
||||
|
<div id="filterExprPicker"> |
||||
|
<div><span data-filtex="!" data-i18n="loggerRowFiltererBuiltinNot"></span><span data-filtex="\t--\t|\t<<\t|\t##" data-i18n="loggerRowFiltererBuiltinBlocked"></span><span data-filtex="\t\+\+\t|\t\*\*\t|\t#@#" data-i18n="loggerRowFiltererBuiltinAllowed"></span></div> |
||||
|
<div><span data-filtex="!" data-i18n="loggerRowFiltererBuiltinNot"></span><span data-filtex="\t(?:css|font)\t">css/font</span><span data-filtex="\timage\t">image</span><span data-filtex="\t(?:inline-)?script(?:ing)?\t">script</span><span data-filtex="\t(?:websocket|xhr)\t">xhr</span><span data-filtex="\tframe\t">frame</span><span data-filtex="\tdom\t">dom</span></div> |
||||
|
<div><span data-filtex="!" data-i18n="loggerRowFiltererBuiltinNot"></span><span data-filtex="\t(?:0,)?1\t" data-i18n="loggerRowFiltererBuiltin1p"></span><span data-filtex="\t(?:3(?:,\d)?|0,3)\t" data-i18n="loggerRowFiltererBuiltin3p"></span></div> |
||||
|
</div> |
||||
|
</span> |
||||
|
</span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<span id="loggerExport" class="button fa-icon">clipboard</span> |
||||
|
<span id="settings" class="button fa-icon">cog</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="vscrollable"> |
||||
|
<div id="vwRenderer"> |
||||
|
<div id="vwScroller"> |
||||
|
<div id="vwVirtualContent"> |
||||
|
<div id="vwContent"></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div id="vwLineSizer"> |
||||
|
<div class="logEntry oneLine"><div><span>00:00:00</span><span> </span><span>**</span><span> </span><span>3,3</span><span>inline-script</span><span> </span></div></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<iframe id="popupContainer"></iframe> |
||||
|
</div> |
||||
|
|
||||
|
<div id="modalOverlay"> |
||||
|
<div> |
||||
|
<div id="modalOverlayContainer"></div> |
||||
|
<div id="modalOverlayClose"><svg viewBox="0 0 64 64"><path d="M 16 16 L 48 48 M 16 48 L 48 16" /></svg></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div id="templates" style="display: none;"> |
||||
|
<div id="logEntryTemplate"><div><span></span>​<span></span>​<span></span>​<span></span>​<span></span>​<span></span>​<span></span></div></div> |
||||
|
<div id="renderedURLTemplate"><span><span></span><b></b><span></span></span></div> |
||||
|
|
||||
|
<div id="netFilteringDialog" data-pane="details"> |
||||
|
<div class="hide preview"><span>click to preview</span></div> |
||||
|
<div class="headers"> |
||||
|
  |
||||
|
<span class="header details" data-pane="details" data-i18n="loggerEntryDetailsHeader"></span> |
||||
|
<span class="header dynamic" data-pane="dynamic" data-i18n="loggerURLFilteringHeader"></span> |
||||
|
<span class="header static" data-pane="static" data-i18n="loggerStaticFilteringHeader"></span> |
||||
|
<span class="tools"><span class="fa-icon reload">refresh</span> <span class="fa-icon picker">eye-dropper</span></span> |
||||
|
</div> |
||||
|
<div class="panes"> |
||||
|
<div class="pane details" data-pane="details"> |
||||
|
<div><span data-i18n="loggerEntryDetailsFilter"></span><span></span></div> |
||||
|
<div><span data-i18n="loggerEntryDetailsFilterList"></span><span class="prose"></span></div> |
||||
|
<div><span data-i18n="loggerEntryDetailsRule"></span><span></span></div> |
||||
|
<div><span data-i18n="loggerEntryDetailsRootContext"></span><span></span></div> |
||||
|
<div><span data-i18n="loggerEntryDetailsContext"></span><span></span></div> |
||||
|
<div><span data-i18n="loggerEntryDetailsPartyness"></span><span class="prose"></span></div> |
||||
|
<div><span data-i18n="loggerEntryDetailsType"></span><span></span></div> |
||||
|
<div><span data-i18n="loggerEntryDetailsURL"></span><span></span></div> |
||||
|
</div> |
||||
|
<div class="pane dynamic" data-pane="dynamic"> |
||||
|
<div class="toolbar row"> |
||||
|
<span><span id="saveRules" class="fa-icon">lock</span></span> |
||||
|
<span> |
||||
|
<label><span data-i18n="loggerURLFilteringContextLabel"></span> <select class="dynamic origin"></select></label>  |
||||
|
<label><span data-i18n="loggerURLFilteringTypeLabel"></span> <select class="dynamic type"><option><option value="*">*</select></label> |
||||
|
</span> |
||||
|
<div class="entry row"> |
||||
|
<span class="action"><span class="allow"> </span><span class="noop"> </span><span class="block"> </span></span> |
||||
|
<span class="url"></span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="entries"></div> |
||||
|
</div> |
||||
|
<div class="pane static" data-pane="static"> |
||||
|
<div></div> |
||||
|
<div><textarea class="staticFilter" spellcheck="false" value=""></textarea> |
||||
|
<button id="createStaticFilter" class="custom important" type="button" data-i18n="pickerCreate"></button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div id="filterFinderDialog"> |
||||
|
</div> |
||||
|
|
||||
|
<div id="filterFinderListEntry"> |
||||
|
<span><!-- |
||||
|
--><a href="asset-viewer.html?url=" target="_blank"></a> <!-- |
||||
|
--><a href="" class="fa-icon" target="_blank">home</a><!-- |
||||
|
--></span> |
||||
|
</div> |
||||
|
|
||||
|
<div id="cosmeticFilteringDialog" class="modalDialog"> |
||||
|
<textarea class="cosmeticFilters" value=""></textarea> |
||||
|
<button id="createCosmeticFilters" class="custom important" type="button" data-i18n="pickerCreate"></button> |
||||
|
</div> |
||||
|
|
||||
|
<div id="loggerSettingsDialog"> |
||||
|
<div><span data-i18n="loggerSettingDiscardPrompt"></span> |
||||
|
<ul> |
||||
|
<li><label data-i18n="loggerSettingPerEntryMaxAge"><input type="number" min="0" max="50000" /></label> |
||||
|
<li><label data-i18n="loggerSettingPerTabMaxLoads"><input type="number" min="0" max="1000000" /></label> |
||||
|
<li><label data-i18n="loggerSettingPerTabMaxEntries"><input type="number" min="0" max="1000000" /></label> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div><span data-i18n="loggerSettingHideColumnsPrompt"></span> |
||||
|
<ul> |
||||
|
<li><label data-i18n="loggerSettingHideColumnTime"><input type="checkbox" data-column="0" /></label> |
||||
|
<li><label data-i18n="loggerSettingHideColumnFilter"><input type="checkbox" data-column="1" /></label> |
||||
|
<li><label data-i18n="loggerSettingHideColumnContext"><input type="checkbox" data-column="3" /></label> |
||||
|
<li><label data-i18n="loggerSettingHideColumnPartyness"><input type="checkbox" data-column="4" /></label> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div><label data-i18n="loggerSettingPerEntryLineCount"><input type="number" min="2" max="6"></label></div> |
||||
|
</div> |
||||
|
|
||||
|
<div id="loggerExportDialog"> |
||||
|
<div class="options"> |
||||
|
<div data-radio="format"> |
||||
|
<span data-i18n="loggerExportFormatList" data-radio-item="list"></span> |
||||
|
<span data-i18n="loggerExportFormatTable" data-radio-item="table"></span> |
||||
|
</div> |
||||
|
<div data-radio="encoding"> |
||||
|
<span data-i18n="loggerExportEncodePlain" data-radio-item="plain"></span> |
||||
|
<span data-i18n="loggerExportEncodeMarkdown" data-radio-item="markdown"></span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<span data-i18n="genericCopyToClipboard" class="pushbutton"></span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<textarea class="output" readonly spellcheck="false"></textarea> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<script src="js/fa-icons.js"></script> |
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/logger-ui.js"></script> |
||||
|
<script src="js/logger-ui-inspector.js"></script> |
||||
|
|
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,75 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html id="uBO-popup-panel"> |
||||
|
|
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
|
<link rel="stylesheet" href="css/common.css" type="text/css"> |
||||
|
<link rel="stylesheet" href="css/fa-icons.css" type="text/css"> |
||||
|
<link rel="stylesheet" href="css/popup.css" type="text/css"> |
||||
|
<link rel="stylesheet" href="css/vapi-popup.css" type="text/css"><!-- Optional platform-specific CSS rules --> |
||||
|
<title>uBlock Origin</title> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
<div id="appinfo"><span id="appname"> </span> <span id="version"> </span></div> |
||||
|
<div id="panes"> |
||||
|
<div class="tooltipContainer"> |
||||
|
<p id="switch" role="button" aria-label data-tip-position="under" tabindex="0"><span class="fa-icon">power-off</span></p> |
||||
|
<p id="basicTools"> |
||||
|
<span id="gotoZap" class="fa-icon tool" data-i18n-tip="popupTipZapper" data-tip-position="under">bolt</span> |
||||
|
<span id="gotoPick" class="fa-icon tool" data-i18n-tip="popupTipPicker" data-tip-position="under">eye-dropper</span> |
||||
|
<a href="logger-ui.html#_" class="fa-icon tool enabled" aria-label="data-tip" data-i18n-tip="popupTipLog" data-tip-position="under" target="uBOLogger" tabindex="0">list-alt</a> |
||||
|
<a href="dashboard.html" class="fa-icon tool enabled" aria-label="data-tip" data-i18n-tip="popupTipDashboard" data-tip-position="under" target="uBODashboard" tabindex="0">sliders</a> |
||||
|
</p> |
||||
|
<h2 id="dfToggler" data-i18n="popupBlockedRequestPrompt"> </h2> |
||||
|
<p class="statName"> |
||||
|
<span data-i18n="popupBlockedOnThisPagePrompt"> </span> |
||||
|
</p> |
||||
|
<p class="statValue" id="page-blocked">?</p> |
||||
|
<div id="refresh" class="fa-icon">refresh</div> |
||||
|
<p class="statName"> |
||||
|
<span data-i18n="popupBlockedSinceInstallPrompt"> </span> |
||||
|
</p> |
||||
|
<p class="statValue" id="total-blocked">?</p> |
||||
|
<h2 data-i18n="popupHitDomainCountPrompt"> </h2> |
||||
|
<p class="statValue" id="popupHitDomainCount"> </p> |
||||
|
<div id="extraTools"> |
||||
|
<span id="no-popups" class="hnSwitch fa-icon fa-icon-badged" role="button" aria-label tabindex="0">files-o<svg class="nope" viewBox="0 0 20 20"><path d="M1,1 19,19M1,19 19,1" /></svg></span> |
||||
|
<span id="no-large-media" class="hnSwitch fa-icon fa-icon-badged" role="button" aria-label tabindex="0">film<svg class="nope" viewBox="0 0 20 20"><path d="M1,1 19,19M1,19 19,1" /></svg></span> |
||||
|
<span id="no-cosmetic-filtering" class="hnSwitch fa-icon fa-icon-badged" role="button" aria-label tabindex="0">eye-slash<svg class="nope" viewBox="0 0 20 20"><path d="M1,1 19,19M1,19 19,1" /></svg></span> |
||||
|
<span id="no-remote-fonts" class="hnSwitch fa-icon fa-icon-badged" role="button" aria-label tabindex="0">font<svg class="nope" viewBox="0 0 20 20"><path d="M1,1 19,19M1,19 19,1" /></svg></span> |
||||
|
<span id="no-scripting" class="hnSwitch fa-icon fa-icon-badged" role="button" aria-label tabindex="0">code<svg class="nope" viewBox="0 0 20 20"><path d="M1,1 19,19M1,19 19,1" /></svg></span> |
||||
|
</div> |
||||
|
</div><!-- DO NOT REMOVE --><div class="tooltipContainer"> |
||||
|
<div id="firewallContainer" class="minimized"> |
||||
|
<div data-des="*" data-type="*"><span data-i18n="popupAnyRulePrompt"></span><span data-src="/" data-i18n-tip="popupTipGlobalRules" data-tip-position="under"> </span><span data-src="." data-i18n-tip="popupTipLocalRules" data-tip-position="under"> </span></div> |
||||
|
<div data-des="*" data-type="image"><span data-i18n="popupImageRulePrompt"></span><span data-src="/"> </span><span data-src="."> </span></div> |
||||
|
<div data-des="*" data-type="3p"><span data-i18n="popup3pAnyRulePrompt"></span><span data-src="/"> </span><span data-src="."> </span></div> |
||||
|
<div data-des="*" data-type="inline-script"><span data-i18n="popupInlineScriptRulePrompt"></span><span data-src="/"> </span><span data-src="."> </span></div> |
||||
|
<div data-des="*" data-type="1p-script"><span data-i18n="popup1pScriptRulePrompt"></span><span data-src="/"> </span><span data-src="."> </span></div> |
||||
|
<div data-des="*" data-type="3p-script"><span data-i18n="popup3pScriptRulePrompt"></span><span data-src="/"> </span><span data-src="."> </span></div> |
||||
|
<div data-des="*" data-type="3p-frame"><span data-i18n="popup3pFrameRulePrompt"></span><span data-src="/"> </span><span data-src="."> </span></div> |
||||
|
</div><div id="rulesetTools"><span id="saveRules" class="fa-icon" data-i18n-tip="popupTipSaveRules" data-tip-position="under">lock</span><span id="revertRules" class="fa-icon" data-i18n-tip="popupTipRevertRules" data-tip-position="under">eraser</span></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div id="templates" style="display: none"> |
||||
|
<div data-des="" data-type="*"><span><sup></sup><span></span></span><span data-src="/"></span><span data-src="."></span><span data-src="."></span></div> |
||||
|
<div id="actionSelector"><span id="dynaAllow"></span><span id="dynaNoop"></span><span id="dynaBlock"></span></div> |
||||
|
<div id="hotspotTip"></div> |
||||
|
<div id="tooltip"></div> |
||||
|
</div> |
||||
|
|
||||
|
<script src="js/fa-icons.js"></script> |
||||
|
<script src="lib/punycode.js"></script> |
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/popup.js"></script> |
||||
|
|
||||
|
</body> |
||||
|
|
||||
|
</html> |
||||
@ -0,0 +1,71 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
|
<title>uBlock — Settings</title> |
||||
|
<link rel="stylesheet" type="text/css" href="css/common.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/dashboard-common.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/settings.css"> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
<div class="body"> |
||||
|
<ul id="userSettings"> |
||||
|
<li><input id="collapse-blocked" type="checkbox" data-setting-name="collapseBlocked" data-setting-type="bool"><label data-i18n="settingsCollapseBlockedPrompt" for="collapse-blocked"></label> |
||||
|
<li><input id="icon-badge" type="checkbox" data-setting-name="showIconBadge" data-setting-type="bool"><label data-i18n="settingsIconBadgePrompt" for="icon-badge"></label> |
||||
|
<li><input id="context-menu-enabled" type="checkbox" data-setting-name="contextMenuEnabled" data-setting-type="bool"><label data-i18n="settingsContextMenuPrompt" for="context-menu-enabled"></label> |
||||
|
<li><input id="tooltips-disabled" type="checkbox" data-setting-name="tooltipsDisabled" data-setting-type="bool"><label data-i18n="settingsTooltipsPrompt" for="tooltips-disabled"></label> |
||||
|
<li><input id="color-blind-friendly" type="checkbox" data-setting-name="colorBlindFriendly" data-setting-type="bool"><label data-i18n="settingsColorBlindPrompt" for="color-blind-friendly"></label> |
||||
|
<li><input id="cloud-storage-enabled" type="checkbox" data-setting-name="cloudStorageEnabled" data-setting-type="bool"><label data-i18n="settingsCloudStorageEnabledPrompt" for="cloud-storage-enabled"></label> <a class="fa info" href="https://github.com/gorhill/uBlock/wiki/Cloud-storage" target="_blank"></a> |
||||
|
<li><input id="advanced-user-enabled" type="checkbox" data-setting-name="advancedUserEnabled" data-setting-type="bool"><label data-i18n="settingsAdvancedUserPrompt" for="advanced-user-enabled"></label> <a class="fa info" href="advanced-settings.html" data-i18n-title="settingsAdvancedUserSettings"></a> |
||||
|
<li class="subgroup"><span data-i18n="3pGroupPrivacy"></span><ul> |
||||
|
<li><input id="prefetching-disabled" type="checkbox" data-setting-name="prefetchingDisabled" data-setting-type="bool"><label data-i18n="settingsPrefetchingDisabledPrompt" for="prefetching-disabled"></label> <a class="fa info" href="https://github.com/gorhill/uBlock/wiki/Dashboard:-Settings#disable-pre-fetching" target="_blank"></a> |
||||
|
<li><input id="hyperlink-auditing-disabled" type="checkbox" data-setting-name="hyperlinkAuditingDisabled" data-setting-type="bool"><label data-i18n="settingsHyperlinkAuditingDisabledPrompt" for="hyperlink-auditing-disabled"></label> <a class="fa info important" href="https://github.com/gorhill/uBlock/wiki/Dashboard:-Settings#disable-hyperlink-auditing" target="_blank"></a> |
||||
|
<li><input id="webrtc-ipaddress-hidden" type="checkbox" data-setting-name="webrtcIPAddressHidden" data-setting-type="bool"><label data-i18n="settingsWebRTCIPAddressHiddenPrompt" for="webrtc-ipaddress-hidden"></label> <a class="fa info important" href="https://github.com/gorhill/uBlock/wiki/Prevent-WebRTC-from-leaking-local-IP-address" target="_blank"></a> |
||||
|
<li><input id="no-csp-reports" type="checkbox" data-setting-name="noCSPReports" data-setting-type="bool"><label data-i18n="settingsNoCSPReportsPrompt" for="no-csp-reports"></label> <a class="fa info" href="https://github.com/gorhill/uBlock/wiki/Dashboard:-Settings#block-csp-reports" target="_blank"></a> |
||||
|
</ul> |
||||
|
<li class="subgroup"><span data-i18n="settingPerSiteSwitchGroup"></span><ul> |
||||
|
<li><label class="synopsis"><span data-i18n="settingPerSiteSwitchGroupSynopsis"></span> <a class="fa info" href="https://github.com/gorhill/uBlock/wiki/Per-site-switches" target="_blank"></a></label> |
||||
|
<li><input id="no-cosmetic-filtering" type="checkbox" data-setting-name="noCosmeticFiltering" data-setting-type="bool"><label data-i18n="settingsNoCosmeticFilteringPrompt" for="no-cosmetic-filtering"></label> <a class="fa info" href="https://github.com/gorhill/uBlock/wiki/Per-site-switches#no-cosmetic-filtering" target="_blank"></a> |
||||
|
<li><input id="no-large-media" type="checkbox" data-setting-name="noLargeMedia" data-setting-type="bool"><label data-i18n="settingsNoLargeMediaPrompt" for="no-large-media"><input type="number" min="0"></label> <a class="fa info" href="https://github.com/gorhill/uBlock/wiki/Per-site-switches#no-large-media-elements" target="_blank"></a> |
||||
|
<li><input id="no-remote-fonts" type="checkbox" data-setting-name="noRemoteFonts" data-setting-type="bool"><label data-i18n="settingsNoRemoteFontsPrompt" for="no-remote-fonts"></label> <a class="fa info" href="https://github.com/gorhill/uBlock/wiki/Per-site-switches#no-remote-fonts" target="_blank"></a> |
||||
|
<li><input id="no-scripting" type="checkbox" data-setting-name="noScripting" data-setting-type="bool"><label data-i18n="settingsNoScriptingPrompt" for="no-scripting"></label> <a class="fa info" href="https://github.com/gorhill/uBlock/wiki/Per-site-switches#no-scripting" target="_blank"></a> |
||||
|
</ul> |
||||
|
</ul> |
||||
|
|
||||
|
<div id="localData" style="margin: 0 1em;"> |
||||
|
<div style="margin: 2.5em 0; border-top: 1px solid #ccc;"></div> |
||||
|
<ul> |
||||
|
<li> |
||||
|
<li style="display: none;"><span data-i18n="settingsLastBackupPrompt"></span><ul> |
||||
|
<li> |
||||
|
</ul> |
||||
|
<li style="display: none;"><span data-i18n="settingsLastRestorePrompt"></span><ul> |
||||
|
<li> |
||||
|
<li> |
||||
|
</ul> |
||||
|
</ul> |
||||
|
</div> |
||||
|
|
||||
|
<div style="margin: 2.5em 1em;"> |
||||
|
<p><button class="custom" type="button" id="export" data-i18n="aboutBackupDataButton"></button>  |
||||
|
<button class="custom" type="button" id="import" data-i18n="aboutRestoreDataButton"></button> |
||||
|
<p><button class="custom" type="button" id="reset" data-i18n="aboutResetDataButton"></button> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="hidden"> |
||||
|
<input id="restoreFilePicker" type="file" accept="text/plain"> |
||||
|
</div> |
||||
|
|
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/dashboard-common.js"></script> |
||||
|
<script src="js/settings.js"></script> |
||||
|
|
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,37 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
|
<title>uBlock Origin — Keyboard shortcuts</title> |
||||
|
<link rel="stylesheet" type="text/css" href="css/common.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/dashboard-common.css"> |
||||
|
<link rel="stylesheet" type="text/css" href="css/shortcuts.css"> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
|
||||
|
<div class="body"> |
||||
|
<table class="commandEntries"><tbody></tbody></table> |
||||
|
</div> |
||||
|
|
||||
|
<div id="templates" style="display: none;"> |
||||
|
<table> |
||||
|
<tr class="commandEntry"> |
||||
|
<td class="commandDesc"> |
||||
|
<td class="commandShortcut"> |
||||
|
<input type="text" placeholder="shortcutCapturePlaceholder"> |
||||
|
<span class="commandReset">×</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/dashboard-common.js"></script> |
||||
|
<script src="js/shortcuts.js"></script> |
||||
|
|
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,59 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
|
<title>uBlock — Whitelist</title> |
||||
|
|
||||
|
<link rel="stylesheet" href="lib/codemirror/lib/codemirror.css"> |
||||
|
<link rel="stylesheet" href="lib/codemirror/addon/search/matchesonscrollbar.css"> |
||||
|
|
||||
|
<link rel="stylesheet" href="css/common.css"> |
||||
|
<link rel="stylesheet" href="css/dashboard-common.css"> |
||||
|
<link rel="stylesheet" href="css/cloud-ui.css"> |
||||
|
<link rel="stylesheet" href="css/whitelist.css"> |
||||
|
<link rel="stylesheet" href="css/codemirror.css"> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
|
||||
|
<div class="body"> |
||||
|
<div id="cloudWidget" class="hide" data-cloud-entry="whitelistPane"></div> |
||||
|
|
||||
|
<p class="vverbose"><span data-i18n="whitelistPrompt"></span> <a class="fa info important" href="https://github.com/gorhill/uBlock/wiki/Dashboard:-Whitelist"></a> |
||||
|
</p> |
||||
|
<p> |
||||
|
<button id="whitelistApply" class="custom important iconifiable" type="button" disabled><span class="fa"></span><span data-i18n="whitelistApply"></span></button> |
||||
|
<button id="whitelistRevert" class="custom iconifiable" type="button" disabled><span class="fa"></span><span data-i18n="genericRevert"></span></button> |
||||
|
   |
||||
|
<button id="importWhitelistFromFile" class="custom iconifiable" type="button"><span class="fa"></span><span data-i18n="whitelistImport"></span></button> |
||||
|
<button id="exportWhitelistToFile" class="custom iconifiable" type="button"><span class="fa"></span><span data-i18n="whitelistExport"></span></button> |
||||
|
</p> |
||||
|
</div> |
||||
|
<div id="whitelist" class="codeMirrorContainer codeMirrorFillVertical"></div> |
||||
|
|
||||
|
<div class="hidden"> |
||||
|
<input id="importFilePicker" type="file" accept="text/plain"> |
||||
|
</div> |
||||
|
|
||||
|
<script src="lib/codemirror/lib/codemirror.js"></script> |
||||
|
<script src="lib/codemirror/addon/display/panel.js"></script> |
||||
|
<script src="lib/codemirror/addon/scroll/annotatescrollbar.js"></script> |
||||
|
<script src="lib/codemirror/addon/search/matchesonscrollbar.js"></script> |
||||
|
<script src="lib/codemirror/addon/search/searchcursor.js"></script> |
||||
|
<script src="lib/codemirror/addon/selection/active-line.js"></script> |
||||
|
<script src="lib/punycode.js"></script> |
||||
|
|
||||
|
<script src="js/codemirror/search.js"></script> |
||||
|
|
||||
|
<script src="js/vapi.js"></script> |
||||
|
<script src="js/vapi-common.js"></script> |
||||
|
<script src="js/vapi-client.js"></script> |
||||
|
<script src="js/udom.js"></script> |
||||
|
<script src="js/i18n.js"></script> |
||||
|
<script src="js/dashboard-common.js"></script> |
||||
|
<script src="js/cloud-ui.js"></script> |
||||
|
<script src="js/whitelist.js"></script> |
||||
|
|
||||
|
</body> |
||||
|
</html> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue