Showing preview only (5,663K chars total). Download the full file or copy to clipboard to get everything.
Repository: HelloZeroNet/ZeroNet
Branch: py3
Commit: 454c0b2e7e00
Files: 537
Total size: 5.3 MB
Directory structure:
gitextract__wvjr9ao/
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.md
│ │ └── feature_request.md
│ └── workflows/
│ └── tests.yml
├── .gitignore
├── .gitlab-ci.yml
├── .travis.yml
├── CHANGELOG.md
├── COPYING
├── Dockerfile
├── Dockerfile.arm64v8
├── LICENSE
├── README-ru.md
├── README-zh-cn.md
├── README.md
├── Vagrantfile
├── plugins/
│ ├── AnnounceBitTorrent/
│ │ ├── AnnounceBitTorrentPlugin.py
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── AnnounceLocal/
│ │ ├── AnnounceLocalPlugin.py
│ │ ├── BroadcastServer.py
│ │ ├── Test/
│ │ │ ├── TestAnnounce.py
│ │ │ ├── conftest.py
│ │ │ └── pytest.ini
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── AnnounceShare/
│ │ ├── AnnounceSharePlugin.py
│ │ ├── Test/
│ │ │ ├── TestAnnounceShare.py
│ │ │ ├── conftest.py
│ │ │ └── pytest.ini
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── AnnounceZero/
│ │ ├── AnnounceZeroPlugin.py
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── Benchmark/
│ │ ├── BenchmarkDb.py
│ │ ├── BenchmarkPack.py
│ │ ├── BenchmarkPlugin.py
│ │ ├── __init__.py
│ │ ├── media/
│ │ │ └── benchmark.html
│ │ └── plugin_info.json
│ ├── Bigfile/
│ │ ├── BigfilePiecefield.py
│ │ ├── BigfilePlugin.py
│ │ ├── Test/
│ │ │ ├── TestBigfile.py
│ │ │ ├── conftest.py
│ │ │ └── pytest.ini
│ │ └── __init__.py
│ ├── Chart/
│ │ ├── ChartCollector.py
│ │ ├── ChartDb.py
│ │ ├── ChartPlugin.py
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── ContentFilter/
│ │ ├── ContentFilterPlugin.py
│ │ ├── ContentFilterStorage.py
│ │ ├── Test/
│ │ │ ├── TestContentFilter.py
│ │ │ ├── conftest.py
│ │ │ └── pytest.ini
│ │ ├── __init__.py
│ │ ├── languages/
│ │ │ ├── hu.json
│ │ │ ├── it.json
│ │ │ ├── jp.json
│ │ │ ├── pt-br.json
│ │ │ ├── zh-tw.json
│ │ │ └── zh.json
│ │ ├── media/
│ │ │ ├── blocklisted.html
│ │ │ └── js/
│ │ │ └── ZeroFrame.js
│ │ └── plugin_info.json
│ ├── Cors/
│ │ ├── CorsPlugin.py
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── CryptMessage/
│ │ ├── CryptMessage.py
│ │ ├── CryptMessagePlugin.py
│ │ ├── Test/
│ │ │ ├── TestCrypt.py
│ │ │ ├── conftest.py
│ │ │ └── pytest.ini
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── FilePack/
│ │ ├── FilePackPlugin.py
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── MergerSite/
│ │ ├── MergerSitePlugin.py
│ │ ├── __init__.py
│ │ └── languages/
│ │ ├── es.json
│ │ ├── fr.json
│ │ ├── hu.json
│ │ ├── it.json
│ │ ├── jp.json
│ │ ├── pt-br.json
│ │ ├── tr.json
│ │ ├── zh-tw.json
│ │ └── zh.json
│ ├── Newsfeed/
│ │ ├── NewsfeedPlugin.py
│ │ └── __init__.py
│ ├── OptionalManager/
│ │ ├── ContentDbPlugin.py
│ │ ├── OptionalManagerPlugin.py
│ │ ├── Test/
│ │ │ ├── TestOptionalManager.py
│ │ │ ├── conftest.py
│ │ │ └── pytest.ini
│ │ ├── UiWebsocketPlugin.py
│ │ ├── __init__.py
│ │ └── languages/
│ │ ├── es.json
│ │ ├── fr.json
│ │ ├── hu.json
│ │ ├── jp.json
│ │ ├── pt-br.json
│ │ ├── zh-tw.json
│ │ └── zh.json
│ ├── PeerDb/
│ │ ├── PeerDbPlugin.py
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── Sidebar/
│ │ ├── ConsolePlugin.py
│ │ ├── SidebarPlugin.py
│ │ ├── ZipStream.py
│ │ ├── __init__.py
│ │ ├── languages/
│ │ │ ├── da.json
│ │ │ ├── de.json
│ │ │ ├── es.json
│ │ │ ├── fr.json
│ │ │ ├── hu.json
│ │ │ ├── it.json
│ │ │ ├── jp.json
│ │ │ ├── pl.json
│ │ │ ├── pt-br.json
│ │ │ ├── ru.json
│ │ │ ├── tr.json
│ │ │ ├── zh-tw.json
│ │ │ └── zh.json
│ │ ├── media/
│ │ │ ├── Class.coffee
│ │ │ ├── Console.coffee
│ │ │ ├── Console.css
│ │ │ ├── Menu.coffee
│ │ │ ├── Menu.css
│ │ │ ├── Prototypes.coffee
│ │ │ ├── RateLimit.coffee
│ │ │ ├── Scrollable.js
│ │ │ ├── Scrollbable.css
│ │ │ ├── Sidebar.coffee
│ │ │ ├── Sidebar.css
│ │ │ ├── all.css
│ │ │ ├── all.js
│ │ │ └── morphdom.js
│ │ ├── media_globe/
│ │ │ ├── Detector.js
│ │ │ ├── Tween.js
│ │ │ ├── all.js
│ │ │ └── globe.js
│ │ └── plugin_info.json
│ ├── Stats/
│ │ ├── StatsPlugin.py
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── TranslateSite/
│ │ ├── TranslateSitePlugin.py
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── Trayicon/
│ │ ├── TrayiconPlugin.py
│ │ ├── __init__.py
│ │ ├── languages/
│ │ │ ├── es.json
│ │ │ ├── fr.json
│ │ │ ├── hu.json
│ │ │ ├── it.json
│ │ │ ├── jp.json
│ │ │ ├── pl.json
│ │ │ ├── pt-br.json
│ │ │ ├── tr.json
│ │ │ ├── zh-tw.json
│ │ │ └── zh.json
│ │ ├── lib/
│ │ │ ├── __init__.py
│ │ │ ├── notificationicon.py
│ │ │ └── winfolders.py
│ │ └── plugin_info.json
│ ├── UiConfig/
│ │ ├── UiConfigPlugin.py
│ │ ├── __init__.py
│ │ ├── languages/
│ │ │ ├── hu.json
│ │ │ ├── jp.json
│ │ │ ├── pl.json
│ │ │ ├── pt-br.json
│ │ │ └── zh.json
│ │ ├── media/
│ │ │ ├── config.html
│ │ │ ├── css/
│ │ │ │ ├── Config.css
│ │ │ │ ├── all.css
│ │ │ │ ├── button.css
│ │ │ │ └── fonts.css
│ │ │ └── js/
│ │ │ ├── ConfigStorage.coffee
│ │ │ ├── ConfigView.coffee
│ │ │ ├── UiConfig.coffee
│ │ │ ├── all.js
│ │ │ ├── lib/
│ │ │ │ ├── Class.coffee
│ │ │ │ ├── Promise.coffee
│ │ │ │ ├── Prototypes.coffee
│ │ │ │ └── maquette.js
│ │ │ └── utils/
│ │ │ ├── Animation.coffee
│ │ │ ├── Dollar.coffee
│ │ │ └── ZeroFrame.coffee
│ │ └── plugin_info.json
│ ├── UiFileManager/
│ │ ├── UiFileManagerPlugin.py
│ │ ├── __init__.py
│ │ ├── languages/
│ │ │ ├── hu.json
│ │ │ └── jp.json
│ │ └── media/
│ │ ├── codemirror/
│ │ │ ├── LICENSE
│ │ │ ├── all.css
│ │ │ ├── all.js
│ │ │ ├── base/
│ │ │ │ ├── codemirror.css
│ │ │ │ └── codemirror.js
│ │ │ ├── extension/
│ │ │ │ ├── dialog/
│ │ │ │ │ ├── dialog.css
│ │ │ │ │ └── dialog.js
│ │ │ │ ├── edit/
│ │ │ │ │ ├── closebrackets.js
│ │ │ │ │ ├── closetag.js
│ │ │ │ │ ├── continuelist.js
│ │ │ │ │ ├── matchbrackets.js
│ │ │ │ │ ├── matchtags.js
│ │ │ │ │ └── trailingspace.js
│ │ │ │ ├── fold/
│ │ │ │ │ ├── brace-fold.js
│ │ │ │ │ ├── comment-fold.js
│ │ │ │ │ ├── foldcode.js
│ │ │ │ │ ├── foldgutter.css
│ │ │ │ │ ├── foldgutter.js
│ │ │ │ │ ├── indent-fold.js
│ │ │ │ │ ├── markdown-fold.js
│ │ │ │ │ └── xml-fold.js
│ │ │ │ ├── hint/
│ │ │ │ │ ├── anyword-hint.js
│ │ │ │ │ ├── html-hint.js
│ │ │ │ │ ├── show-hint.css
│ │ │ │ │ ├── show-hint.js
│ │ │ │ │ ├── sql-hint.js
│ │ │ │ │ └── xml-hint.js
│ │ │ │ ├── lint/
│ │ │ │ │ ├── json-lint.js
│ │ │ │ │ ├── jsonlint.js
│ │ │ │ │ ├── lint.css
│ │ │ │ │ └── lint.js
│ │ │ │ ├── mdn-like-custom.css
│ │ │ │ ├── scroll/
│ │ │ │ │ ├── annotatescrollbar.js
│ │ │ │ │ ├── scrollpastend.js
│ │ │ │ │ ├── simplescrollbars.css
│ │ │ │ │ └── simplescrollbars.js
│ │ │ │ ├── search/
│ │ │ │ │ ├── jump-to-line.js
│ │ │ │ │ ├── match-highlighter.js
│ │ │ │ │ ├── matchesonscrollbar.css
│ │ │ │ │ ├── matchesonscrollbar.js
│ │ │ │ │ ├── search.js
│ │ │ │ │ └── searchcursor.js
│ │ │ │ ├── selection/
│ │ │ │ │ ├── active-line.js
│ │ │ │ │ ├── mark-selection.js
│ │ │ │ │ └── selection-pointer.js
│ │ │ │ ├── simple.js
│ │ │ │ └── sublime.js
│ │ │ └── mode/
│ │ │ ├── coffeescript.js
│ │ │ ├── css.js
│ │ │ ├── go.js
│ │ │ ├── htmlembedded.js
│ │ │ ├── htmlmixed.js
│ │ │ ├── javascript.js
│ │ │ ├── markdown.js
│ │ │ ├── python.js
│ │ │ ├── rust.js
│ │ │ └── xml.js
│ │ ├── css/
│ │ │ ├── Menu.css
│ │ │ ├── Selectbar.css
│ │ │ ├── UiFileManager.css
│ │ │ └── all.css
│ │ ├── js/
│ │ │ ├── Config.coffee
│ │ │ ├── FileEditor.coffee
│ │ │ ├── FileItemList.coffee
│ │ │ ├── FileList.coffee
│ │ │ ├── UiFileManager.coffee
│ │ │ ├── all.js
│ │ │ └── lib/
│ │ │ ├── Animation.coffee
│ │ │ ├── Class.coffee
│ │ │ ├── Dollar.coffee
│ │ │ ├── ItemList.coffee
│ │ │ ├── Menu.coffee
│ │ │ ├── Promise.coffee
│ │ │ ├── Prototypes.coffee
│ │ │ ├── RateLimitCb.coffee
│ │ │ ├── Text.coffee
│ │ │ ├── Time.coffee
│ │ │ ├── ZeroFrame.coffee
│ │ │ └── maquette.js
│ │ └── list.html
│ ├── UiPluginManager/
│ │ ├── UiPluginManagerPlugin.py
│ │ ├── __init__.py
│ │ └── media/
│ │ ├── css/
│ │ │ ├── PluginManager.css
│ │ │ ├── all.css
│ │ │ ├── button.css
│ │ │ └── fonts.css
│ │ ├── js/
│ │ │ ├── PluginList.coffee
│ │ │ ├── UiPluginManager.coffee
│ │ │ ├── all.js
│ │ │ ├── lib/
│ │ │ │ ├── Class.coffee
│ │ │ │ ├── Promise.coffee
│ │ │ │ ├── Prototypes.coffee
│ │ │ │ └── maquette.js
│ │ │ └── utils/
│ │ │ ├── Animation.coffee
│ │ │ ├── Dollar.coffee
│ │ │ └── ZeroFrame.coffee
│ │ └── plugin_manager.html
│ ├── Zeroname/
│ │ ├── README.md
│ │ ├── SiteManagerPlugin.py
│ │ ├── __init__.py
│ │ └── updater/
│ │ └── zeroname_updater.py
│ ├── __init__.py
│ ├── disabled-Bootstrapper/
│ │ ├── BootstrapperDb.py
│ │ ├── BootstrapperPlugin.py
│ │ ├── Test/
│ │ │ ├── TestBootstrapper.py
│ │ │ ├── conftest.py
│ │ │ └── pytest.ini
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── disabled-Dnschain/
│ │ ├── SiteManagerPlugin.py
│ │ ├── UiRequestPlugin.py
│ │ └── __init__.py
│ ├── disabled-DonationMessage/
│ │ ├── DonationMessagePlugin.py
│ │ └── __init__.py
│ ├── disabled-Multiuser/
│ │ ├── MultiuserPlugin.py
│ │ ├── Test/
│ │ │ ├── TestMultiuser.py
│ │ │ ├── conftest.py
│ │ │ └── pytest.ini
│ │ ├── UserPlugin.py
│ │ ├── __init__.py
│ │ └── plugin_info.json
│ ├── disabled-StemPort/
│ │ ├── StemPortPlugin.py
│ │ └── __init__.py
│ ├── disabled-UiPassword/
│ │ ├── UiPasswordPlugin.py
│ │ ├── __init__.py
│ │ ├── login.html
│ │ └── plugin_info.json
│ └── disabled-ZeronameLocal/
│ ├── SiteManagerPlugin.py
│ ├── UiRequestPlugin.py
│ └── __init__.py
├── requirements.txt
├── src/
│ ├── Config.py
│ ├── Connection/
│ │ ├── Connection.py
│ │ ├── ConnectionServer.py
│ │ └── __init__.py
│ ├── Content/
│ │ ├── ContentDb.py
│ │ ├── ContentDbDict.py
│ │ ├── ContentManager.py
│ │ └── __init__.py
│ ├── Crypt/
│ │ ├── Crypt.py
│ │ ├── CryptBitcoin.py
│ │ ├── CryptConnection.py
│ │ ├── CryptHash.py
│ │ ├── CryptRsa.py
│ │ └── __init__.py
│ ├── Db/
│ │ ├── Db.py
│ │ ├── DbCursor.py
│ │ ├── DbQuery.py
│ │ └── __init__.py
│ ├── Debug/
│ │ ├── Debug.py
│ │ ├── DebugHook.py
│ │ ├── DebugLock.py
│ │ ├── DebugMedia.py
│ │ ├── DebugReloader.py
│ │ └── __init__.py
│ ├── File/
│ │ ├── FileRequest.py
│ │ ├── FileServer.py
│ │ └── __init__.py
│ ├── Peer/
│ │ ├── Peer.py
│ │ ├── PeerHashfield.py
│ │ ├── PeerPortchecker.py
│ │ └── __init__.py
│ ├── Plugin/
│ │ ├── PluginManager.py
│ │ └── __init__.py
│ ├── Site/
│ │ ├── Site.py
│ │ ├── SiteAnnouncer.py
│ │ ├── SiteManager.py
│ │ ├── SiteStorage.py
│ │ └── __init__.py
│ ├── Test/
│ │ ├── BenchmarkSsl.py
│ │ ├── Spy.py
│ │ ├── TestCached.py
│ │ ├── TestConfig.py
│ │ ├── TestConnectionServer.py
│ │ ├── TestContent.py
│ │ ├── TestContentUser.py
│ │ ├── TestCryptBitcoin.py
│ │ ├── TestCryptConnection.py
│ │ ├── TestCryptHash.py
│ │ ├── TestDb.py
│ │ ├── TestDbQuery.py
│ │ ├── TestDebug.py
│ │ ├── TestDiff.py
│ │ ├── TestEvent.py
│ │ ├── TestFileRequest.py
│ │ ├── TestFlag.py
│ │ ├── TestHelper.py
│ │ ├── TestMsgpack.py
│ │ ├── TestNoparallel.py
│ │ ├── TestPeer.py
│ │ ├── TestRateLimit.py
│ │ ├── TestSafeRe.py
│ │ ├── TestSite.py
│ │ ├── TestSiteDownload.py
│ │ ├── TestSiteStorage.py
│ │ ├── TestThreadPool.py
│ │ ├── TestTor.py
│ │ ├── TestTranslate.py
│ │ ├── TestUiWebsocket.py
│ │ ├── TestUpnpPunch.py
│ │ ├── TestUser.py
│ │ ├── TestWeb.py
│ │ ├── TestWorkerTaskManager.py
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── coverage.ini
│ │ ├── pytest.ini
│ │ └── testdata/
│ │ └── 1TeSTvb4w2PWE81S2rEELgmX2GCCExQGT-original/
│ │ ├── content.json
│ │ ├── css/
│ │ │ └── all.css
│ │ ├── data/
│ │ │ ├── data.json
│ │ │ ├── optional.txt
│ │ │ ├── test_include/
│ │ │ │ ├── content.json
│ │ │ │ └── data.json
│ │ │ └── users/
│ │ │ ├── 1C5sgvWaSgfaTpV5kjBCnCiKtENNMYo69q/
│ │ │ │ ├── content.json
│ │ │ │ └── data.json
│ │ │ ├── 1CjfbrbwtP8Y2QjPy12vpTATkUT7oSiPQ9/
│ │ │ │ ├── content.json
│ │ │ │ └── data.json
│ │ │ ├── 1J6UrZMkarjVg5ax9W4qThir3BFUikbW6C/
│ │ │ │ ├── content.json
│ │ │ │ └── data.json
│ │ │ └── content.json
│ │ ├── data-default/
│ │ │ ├── data.json
│ │ │ └── users/
│ │ │ └── content-default.json
│ │ ├── dbschema.json
│ │ ├── index.html
│ │ └── js/
│ │ └── all.js
│ ├── Tor/
│ │ ├── TorManager.py
│ │ └── __init__.py
│ ├── Translate/
│ │ ├── Translate.py
│ │ ├── __init__.py
│ │ └── languages/
│ │ ├── da.json
│ │ ├── de.json
│ │ ├── es.json
│ │ ├── fa.json
│ │ ├── fr.json
│ │ ├── hu.json
│ │ ├── it.json
│ │ ├── jp.json
│ │ ├── nl.json
│ │ ├── pl.json
│ │ ├── pt-br.json
│ │ ├── ru.json
│ │ ├── sk.json
│ │ ├── sl.json
│ │ ├── tr.json
│ │ ├── zh-tw.json
│ │ └── zh.json
│ ├── Ui/
│ │ ├── UiRequest.py
│ │ ├── UiServer.py
│ │ ├── UiWebsocket.py
│ │ ├── __init__.py
│ │ ├── media/
│ │ │ ├── Fixbutton.coffee
│ │ │ ├── Infopanel.coffee
│ │ │ ├── Loading.coffee
│ │ │ ├── Notifications.coffee
│ │ │ ├── Wrapper.coffee
│ │ │ ├── Wrapper.css
│ │ │ ├── WrapperZeroFrame.coffee
│ │ │ ├── ZeroSiteTheme.coffee
│ │ │ ├── all.css
│ │ │ ├── all.js
│ │ │ ├── img/
│ │ │ │ ├── favicon.psd
│ │ │ │ └── logo.psd
│ │ │ └── lib/
│ │ │ ├── RateLimit.coffee
│ │ │ ├── Translate.coffee
│ │ │ ├── ZeroWebsocket.coffee
│ │ │ ├── jquery.cssanim.js
│ │ │ ├── jquery.csslater.coffee
│ │ │ └── jquery.easing.js
│ │ └── template/
│ │ ├── site_add.html
│ │ └── wrapper.html
│ ├── User/
│ │ ├── User.py
│ │ ├── UserManager.py
│ │ └── __init__.py
│ ├── Worker/
│ │ ├── Worker.py
│ │ ├── WorkerManager.py
│ │ ├── WorkerTaskManager.py
│ │ └── __init__.py
│ ├── __init__.py
│ ├── lib/
│ │ ├── __init__.py
│ │ ├── bencode_open/
│ │ │ ├── LICENSE
│ │ │ └── __init__.py
│ │ ├── cssvendor/
│ │ │ ├── __init__.py
│ │ │ └── cssvendor.py
│ │ ├── gevent_ws/
│ │ │ └── __init__.py
│ │ ├── libsecp256k1message/
│ │ │ ├── __init__.py
│ │ │ └── libsecp256k1message.py
│ │ ├── openssl/
│ │ │ └── openssl.cnf
│ │ ├── pyaes/
│ │ │ ├── LICENSE.txt
│ │ │ ├── README.md
│ │ │ ├── __init__.py
│ │ │ ├── aes.py
│ │ │ ├── blockfeeder.py
│ │ │ └── util.py
│ │ ├── sslcrypto/
│ │ │ ├── LICENSE
│ │ │ ├── __init__.py
│ │ │ ├── _aes.py
│ │ │ ├── _ecc.py
│ │ │ ├── _ripemd.py
│ │ │ ├── fallback/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _jacobian.py
│ │ │ │ ├── _util.py
│ │ │ │ ├── aes.py
│ │ │ │ ├── ecc.py
│ │ │ │ └── rsa.py
│ │ │ └── openssl/
│ │ │ ├── __init__.py
│ │ │ ├── aes.py
│ │ │ ├── discovery.py
│ │ │ ├── ecc.py
│ │ │ ├── library.py
│ │ │ └── rsa.py
│ │ └── subtl/
│ │ ├── LICENCE
│ │ ├── README.md
│ │ ├── __init__.py
│ │ └── subtl.py
│ ├── main.py
│ └── util/
│ ├── Cached.py
│ ├── Diff.py
│ ├── Electrum.py
│ ├── Event.py
│ ├── Flag.py
│ ├── GreenletManager.py
│ ├── Msgpack.py
│ ├── Noparallel.py
│ ├── OpensslFindPatch.py
│ ├── Platform.py
│ ├── Pooled.py
│ ├── QueryJson.py
│ ├── RateLimit.py
│ ├── SafeRe.py
│ ├── SocksProxy.py
│ ├── ThreadPool.py
│ ├── UpnpPunch.py
│ ├── __init__.py
│ └── helper.py
├── start.py
├── tools/
│ └── coffee/
│ ├── README.md
│ ├── coffee-script.js
│ ├── coffee.cmd
│ └── coffee.wsf
├── update.py
└── zeronet.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
custom: https://zeronet.io/docs/help_zeronet/donate/
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.md
================================================
---
name: Bug report
about: Create a report to help us improve ZeroNet
title: ''
labels: ''
assignees: ''
---
### Step 1: Please describe your environment
* ZeroNet version: _____
* Operating system: _____
* Web browser: _____
* Tor status: not available/always/disabled
* Opened port: yes/no
* Special configuration: ____
### Step 2: Describe the problem:
#### Steps to reproduce:
1. _____
2. _____
3. _____
#### Observed Results:
* What happened? This could be a screenshot, a description, log output (you can send log/debug.log file to hello@zeronet.io if necessary), etc.
#### Expected Results:
* What did you expect to happen?
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for ZeroNet
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/workflows/tests.yml
================================================
name: tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-16.04
strategy:
max-parallel: 16
matrix:
python-version: [3.5, 3.6, 3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Prepare for installation
run: |
python3 -m pip install setuptools
python3 -m pip install --upgrade pip wheel
python3 -m pip install --upgrade codecov coveralls flake8 mock pytest==4.6.3 pytest-cov selenium
- name: Install
run: |
python3 -m pip install --upgrade -r requirements.txt
python3 -m pip list
- name: Prepare for tests
run: |
openssl version -a
echo 0 | sudo tee /proc/sys/net/ipv6/conf/all/disable_ipv6
- name: Test
run: |
catchsegv python3 -m pytest src/Test --cov=src --cov-config src/Test/coverage.ini
export ZERONET_LOG_DIR="log/CryptMessage"; catchsegv python3 -m pytest -x plugins/CryptMessage/Test
export ZERONET_LOG_DIR="log/Bigfile"; catchsegv python3 -m pytest -x plugins/Bigfile/Test
export ZERONET_LOG_DIR="log/AnnounceLocal"; catchsegv python3 -m pytest -x plugins/AnnounceLocal/Test
export ZERONET_LOG_DIR="log/OptionalManager"; catchsegv python3 -m pytest -x plugins/OptionalManager/Test
export ZERONET_LOG_DIR="log/Multiuser"; mv plugins/disabled-Multiuser plugins/Multiuser && catchsegv python -m pytest -x plugins/Multiuser/Test
export ZERONET_LOG_DIR="log/Bootstrapper"; mv plugins/disabled-Bootstrapper plugins/Bootstrapper && catchsegv python -m pytest -x plugins/Bootstrapper/Test
find src -name "*.json" | xargs -n 1 python3 -c "import json, sys; print(sys.argv[1], end=' '); json.load(open(sys.argv[1])); print('[OK]')"
find plugins -name "*.json" | xargs -n 1 python3 -c "import json, sys; print(sys.argv[1], end=' '); json.load(open(sys.argv[1])); print('[OK]')"
flake8 . --count --select=E9,F63,F72,F82 --show-source --statistics --exclude=src/lib/pyaes/
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# Log files
**/*.log
# Hidden files
.*
!/.github
!/.gitignore
!/.travis.yml
!/.gitlab-ci.yml
# Temporary files
*.bak
# Data dir
data/*
*.db
# Virtualenv
env/*
# Tor data
tools/tor/data
# PhantomJS, downloaded manually for unit tests
tools/phantomjs
# ZeroNet config file
zeronet.conf
# ZeroNet log files
log/*
================================================
FILE: .gitlab-ci.yml
================================================
stages:
- test
.test_template: &test_template
stage: test
before_script:
- pip install --upgrade pip wheel
# Selenium and requests can't be installed without a requests hint on Python 3.4
- pip install --upgrade requests>=2.22.0
- pip install --upgrade codecov coveralls flake8 mock pytest==4.6.3 pytest-cov selenium
- pip install --upgrade -r requirements.txt
script:
- pip list
- openssl version -a
- python -m pytest -x plugins/CryptMessage/Test --color=yes
- python -m pytest -x plugins/Bigfile/Test --color=yes
- python -m pytest -x plugins/AnnounceLocal/Test --color=yes
- python -m pytest -x plugins/OptionalManager/Test --color=yes
- python -m pytest src/Test --cov=src --cov-config src/Test/coverage.ini --color=yes
- mv plugins/disabled-Multiuser plugins/Multiuser
- python -m pytest -x plugins/Multiuser/Test --color=yes
- mv plugins/disabled-Bootstrapper plugins/Bootstrapper
- python -m pytest -x plugins/Bootstrapper/Test --color=yes
- flake8 . --count --select=E9,F63,F72,F82 --show-source --statistics --exclude=src/lib/pyaes/
test:py3.4:
image: python:3.4.3
<<: *test_template
test:py3.5:
image: python:3.5.7
<<: *test_template
test:py3.6:
image: python:3.6.9
<<: *test_template
test:py3.7-openssl1.1.0:
image: python:3.7.0b5
<<: *test_template
test:py3.7-openssl1.1.1:
image: python:3.7.4
<<: *test_template
test:py3.8:
image: python:3.8.0b3
<<: *test_template
================================================
FILE: .travis.yml
================================================
language: python
python:
- 3.4
- 3.5
- 3.6
- 3.7
- 3.8
services:
- docker
cache: pip
before_install:
- pip install --upgrade pip wheel
- pip install --upgrade codecov coveralls flake8 mock pytest==4.6.3 pytest-cov selenium
# - docker build -t zeronet .
# - docker run -d -v $PWD:/root/data -p 15441:15441 -p 127.0.0.1:43110:43110 zeronet
install:
- pip install --upgrade -r requirements.txt
- pip list
before_script:
- openssl version -a
# Add an IPv6 config - see the corresponding Travis issue
# https://github.com/travis-ci/travis-ci/issues/8361
- if [ "${TRAVIS_OS_NAME}" == "linux" ]; then
sudo sh -c 'echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6';
fi
script:
- catchsegv python -m pytest src/Test --cov=src --cov-config src/Test/coverage.ini
- export ZERONET_LOG_DIR="log/CryptMessage"; catchsegv python -m pytest -x plugins/CryptMessage/Test
- export ZERONET_LOG_DIR="log/Bigfile"; catchsegv python -m pytest -x plugins/Bigfile/Test
- export ZERONET_LOG_DIR="log/AnnounceLocal"; catchsegv python -m pytest -x plugins/AnnounceLocal/Test
- export ZERONET_LOG_DIR="log/OptionalManager"; catchsegv python -m pytest -x plugins/OptionalManager/Test
- export ZERONET_LOG_DIR="log/Multiuser"; mv plugins/disabled-Multiuser plugins/Multiuser && catchsegv python -m pytest -x plugins/Multiuser/Test
- export ZERONET_LOG_DIR="log/Bootstrapper"; mv plugins/disabled-Bootstrapper plugins/Bootstrapper && catchsegv python -m pytest -x plugins/Bootstrapper/Test
- find src -name "*.json" | xargs -n 1 python3 -c "import json, sys; print(sys.argv[1], end=' '); json.load(open(sys.argv[1])); print('[OK]')"
- find plugins -name "*.json" | xargs -n 1 python3 -c "import json, sys; print(sys.argv[1], end=' '); json.load(open(sys.argv[1])); print('[OK]')"
- flake8 . --count --select=E9,F63,F72,F82 --show-source --statistics --exclude=src/lib/pyaes/
after_failure:
- zip -r log.zip log/
- curl --upload-file ./log.zip https://transfer.sh/log.zip
after_success:
- codecov
- coveralls --rcfile=src/Test/coverage.ini
notifications:
email:
recipients:
hello@zeronet.io
on_success: change
================================================
FILE: CHANGELOG.md
================================================
### ZeroNet 0.7.2 (2020-09-?) Rev4206?
### ZeroNet 0.7.1 (2019-07-01) Rev4206
### Added
- Built-in logging console in the web UI to see what's happening in the background. (pull down top-right 0 button to see it)
- Display database rebuild errors [Thanks to Lola]
- New plugin system that allows to install and manage builtin/third party extensions to the ZeroNet client using the web interface.
- Support multiple trackers_file
- Add OpenSSL 1.1 support to CryptMessage plugin based on Bitmessage modifications [Thanks to radfish]
- Display visual error message on startup errors
- Fix max opened files changing on Windows platform
- Display TLS1.3 compatibility on /Stats page
- Add fake SNI and ALPN to peer connections to make it more like standard https connections
- Hide and ignore tracker_proxy setting in Tor: Always mode as it's going to use Tor anyway.
- Deny websocket connections from unknown origins
- Restrict open_browser values to avoid RCE on sandbox escape
- Offer access web interface by IP address in case of unknown host
- Link to site's sidebar with "#ZeroNet:OpenSidebar" hash
### Changed
- Allow .. in file names [Thanks to imachug]
- Change unstable trackers
- More clean errors on sites.json/users.json load error
- Various tweaks for tracker rating on unstable connections
- Use OpenSSL 1.1 dlls from default Python Windows distribution if possible
- Re-factor domain resolving for easier domain plugins
- Disable UDP connections if --proxy is used
- New, decorator-based Websocket API permission system to avoid future typo mistakes
### Fixed
- Fix parsing config lines that have no value
- Fix start.py [Thanks to imachug]
- Allow multiple values of the same key in the config file [Thanks ssdifnskdjfnsdjk for reporting]
- Fix parsing config file lines that has % in the value [Thanks slrslr for reporting]
- Fix bootstrapper plugin hash reloads [Thanks geekless for reporting]
- Fix CryptMessage plugin OpenSSL dll loading on Windows (ZeroMail errors) [Thanks cxgreat2014 for reporting]
- Fix startup error when using OpenSSL 1.1 [Thanks to imachug]
- Fix a bug that did not loaded merged site data for 5 sec after the merged site got added
- Fix typo that allowed to add new plugins in public proxy mode. [Thanks styromaniac for reporting]
- Fix loading non-big files with "|all" postfix [Thanks to krzotr]
- Fix OpenSSL cert generation error crash by change Windows console encoding to utf8
#### Wrapper html injection vulnerability [Reported by ivanq]
In ZeroNet before rev4188 the wrapper template variables was rendered incorrectly.
Result: The opened site was able to gain WebSocket connection with unrestricted ADMIN/NOSANDBOX access, change configuration values and possible RCE on client's machine.
Fix: Fixed the template rendering code, disallowed WebSocket connections from unknown locations, restricted open_browser configuration values to avoid possible RCE in case of sandbox escape.
Note: The fix is also back ported to ZeroNet Py 2.x version (Rev3870)
### ZeroNet 0.7.0 (2019-06-12) Rev4106 (First release targeting Python 3.4+)
### Added
- 5-10x faster signature verification by using libsecp256k1 (Thanks to ZeroMux)
- Generated SSL certificate randomization to avoid protocol filters (Thanks to ValdikSS)
- Offline mode
- P2P source code update using ZeroNet protocol
- ecdsaSign/Verify commands to CryptMessage plugin (Thanks to imachug)
- Efficient file rename: change file names instead of re-downloading the file.
- Make redirect optional on site cloning (Thanks to Lola)
- EccPrivToPub / EccPubToPriv functions (Thanks to imachug)
- Detect and change dark/light theme based on OS setting (Thanks to filips123)
### Changed
- Re-factored code to Python3 runtime (compatible with Python 3.4-3.8)
- More safe database sync mode
- Removed bundled third-party libraries where it's possible
- Use lang=en instead of lang={lang} in urls to avoid url encode problems
- Remove environment details from error page
- Don't push content.json updates larger than 10kb to significantly reduce bw usage for site with many files
### Fixed
- Fix sending files with \0 characters
- Security fix: Escape error detail to avoid XSS (reported by krzotr)
- Fix signature verification using libsecp256k1 for compressed addresses (mostly certificates generated in the browser)
- Fix newsfeed if you have more than 1000 followed topic/post on one site.
- Fix site download as zip file
- Fix displaying sites with utf8 title
- Error message if dbRebuild fails (Thanks to Lola)
- Fix browser reopen if executing start.py again. (Thanks to imachug)
### ZeroNet 0.6.5 (2019-02-16) Rev3851 (Last release targeting Python 2.7.x)
### Added
- IPv6 support in peer exchange, bigfiles, optional file finding, tracker sharing, socket listening and connecting (based on tangdou1 modifications)
- New tracker database format with IPv6 support
- Display notification if there is an unpublished modification for your site
- Listen and shut down normally for SIGTERM (Thanks to blurHY)
- Support tilde `~` in filenames (by d14na)
- Support map for Namecoin subdomain names (Thanks to lola)
- Add log level to config page
- Support `{data}` for data dir variable in trackers_file value
- Quick check content.db on startup and rebuild if necessary
- Don't show meek proxy option if the tor client does not supports it
### Changed
- Refactored port open checking with IPv6 support
- Consider non-local IPs as external even is the open port check fails (for CJDNS and Yggdrasil support)
- Add IPv6 tracker and change unstable tracker
- Don't correct sent local time with the calculated time correction
- Disable CSP for Edge
- Only support CREATE commands in dbschema indexes node and SELECT from storage.query
### Fixed
- Check the length of master seed when executing cryptGetPrivatekey CLI command
- Only reload source code on file modification / creation
- Detection and issue warning for latest no-script plugin
- Fix atomic write of a non-existent file
- Fix sql queries with lots of variables and sites with lots of content.json
- Fix multi-line parsing of zeronet.conf
- Fix site deletion from users.json
- Fix site cloning before site downloaded (Reported by unsystemizer)
- Fix queryJson for non-list nodes (Reported by MingchenZhang)
## ZeroNet 0.6.4 (2018-10-20) Rev3660
### Added
- New plugin: UiConfig. A web interface that allows changing ZeroNet settings.
- New plugin: AnnounceShare. Share trackers between users, automatically announce client's ip as tracker if Bootstrapper plugin is enabled.
- Global tracker stats on ZeroHello: Include statistics from all served sites instead of displaying request statistics only for one site.
- Support custom proxy for trackers. (Configurable with /Config)
- Adding peers to sites manually using zeronet_peers get parameter
- Copy site address with peers link on the sidebar.
- Zip file listing and streaming support for Bigfiles.
- Tracker statistics on /Stats page
- Peer reputation save/restore to speed up sync time after startup.
- Full support fileGet, fileList, dirList calls on tar.gz/zip files.
- Archived_before support to user content rules to allow deletion of all user files before the specified date
- Show and manage "Connecting" sites on ZeroHello
- Add theme support to ZeroNet sites
- Dark theme for ZeroHello, ZeroBlog, ZeroTalk
### Changed
- Dynamic big file allocation: More efficient storage usage by don't pre-allocate the whole file at the beginning, but expand the size as the content downloads.
- Reduce the request frequency to unreliable trackers.
- Only allow 5 concurrent checkSites to run in parallel to reduce load under Tor/slow connection.
- Stop site downloading if it reached 95% of site limit to avoid download loop for sites out of limit
- The pinned optional files won't be removed from download queue after 30 retries and won't be deleted even if the site owner removes it.
- Don't remove incomplete (downloading) sites on startup
- Remove --pin_bigfile argument as big files are automatically excluded from optional files limit.
### Fixed
- Trayicon compatibility with latest gevent
- Request number counting for zero:// trackers
- Peer reputation boost for zero:// trackers.
- Blocklist of peers loaded from peerdb (Thanks tangdou1 for report)
- Sidebar map loading on foreign languages (Thx tangdou1 for report)
- FileGet on non-existent files (Thanks mcdev for reporting)
- Peer connecting bug for sites with low amount of peers
#### "The Vacation" Sandbox escape bug [Reported by GitCenter / Krixano / ZeroLSTN]
In ZeroNet 0.6.3 Rev3615 and earlier as a result of invalid file type detection, a malicious site could escape the iframe sandbox.
Result: Browser iframe sandbox escape
Applied fix: Replaced the previous, file extension based file type identification with a proper one.
Affected versions: All versions before ZeroNet Rev3616
## ZeroNet 0.6.3 (2018-06-26)
### Added
- New plugin: ContentFilter that allows to have shared site and user block list.
- Support Tor meek proxies to avoid tracker blocking of GFW
- Detect network level tracker blocking and easy setting meek proxy for tracker connections.
- Support downloading 2GB+ sites as .zip (Thx to Radtoo)
- Support ZeroNet as a transparent proxy (Thx to JeremyRand)
- Allow fileQuery as CORS command (Thx to imachug)
- Windows distribution includes Tor and meek client by default
- Download sites as zip link to sidebar
- File server port randomization
- Implicit SSL for all connection
- fileList API command for zip files
- Auto download bigfiles size limit on sidebar
- Local peer number to the sidebar
- Open site directory button in sidebar
### Changed
- Switched to Azure Tor meek proxy as Amazon one became unavailable
- Refactored/rewritten tracker connection manager
- Improved peer discovery for optional files without opened port
- Also delete Bigfile's piecemap on deletion
### Fixed
- Important security issue: Iframe sandbox escape [Reported by Ivanq / gitcenter]
- Local peer discovery when running multiple clients on the same machine
- Uploading small files with Bigfile plugin
- Ctrl-c shutdown when running CLI commands
- High CPU/IO usage when Multiuser plugin enabled
- Firefox back button
- Peer discovery on older Linux kernels
- Optional file handling when multiple files have the same hash_id (first 4 chars of the hash)
- Msgpack 0.5.5 and 0.5.6 compatibility
## ZeroNet 0.6.2 (2018-02-18)
### Added
- New plugin: AnnounceLocal to make ZeroNet work without an internet connection on the local network.
- Allow dbQuey and userGetSettings using the `as` API command on different sites with Cors permission
- New config option: `--log_level` to reduce log verbosity and IO load
- Prefer to connect to recent peers from trackers first
- Mark peers with port 1 is also unconnectable for future fix for trackers that do not support port 0 announce
### Changed
- Don't keep connection for sites that have not been modified in the last week
- Change unreliable trackers to new ones
- Send maximum 10 findhash request in one find optional files round (15sec)
- Change "Unique to site" to "No certificate" for default option in cert selection dialog.
- Dont print warnings if not in debug mode
- Generalized tracker logging format
- Only recover sites from sites.json if they had peers
- Message from local peers does not means internet connection
- Removed `--debug_gevent` and turned on Gevent block logging by default
### Fixed
- Limit connections to 512 to avoid reaching 1024 limit on windows
- Exception when logging foreign operating system socket errors
- Don't send private (local) IPs on pex
- Don't connect to private IPs in tor always mode
- Properly recover data from msgpack unpacker on file stream start
- Symlinked data directory deletion when deleting site using Windows
- De-duplicate peers before publishing
- Bigfile info for non-existing files
## ZeroNet 0.6.1 (2018-01-25)
### Added
- New plugin: Chart
- Collect and display charts about your contribution to ZeroNet network
- Allow list as argument replacement in sql queries. (Thanks to imachug)
- Newsfeed query time statistics (Click on "From XX sites in X.Xs on ZeroHello)
- New UiWebsocket API command: As to run commands as other site
- Ranged ajax queries for big files
- Filter feed by type and site address
- FileNeed, Bigfile upload command compatibility with merger sites
- Send event on port open / tor status change
- More description on permission request
### Changed
- Reduce memory usage of sidebar geoip database cache
- Change unreliable tracker to new one
- Don't display Cors permission ask if it already granted
- Avoid UI blocking when rebuilding a merger site
- Skip listing ignored directories on signing
- In Multiuser mode show the seed welcome message when adding new certificate instead of first visit
- Faster async port opening on multiple network interfaces
- Allow javascript modals
- Only zoom sidebar globe if mouse button is pressed down
### Fixed
- Open port checking error reporting (Thanks to imachug)
- Out-of-range big file requests
- Don't output errors happened on gevent greenlets twice
- Newsfeed skip sites with no database
- Newsfeed queries with multiple params
- Newsfeed queries with UNION and UNION ALL
- Fix site clone with sites larger that 10MB
- Unreliable Websocket connection when requesting files from different sites at the same time
## ZeroNet 0.6.0 (2017-10-17)
### Added
- New plugin: Big file support
- Automatic pinning on Big file download
- Enable TCP_NODELAY for supporting sockets
- actionOptionalFileList API command arguments to list non-downloaded files or only big files
- serverShowdirectory API command arguments to allow to display site's directory in OS file browser
- fileNeed API command to initialize optional file downloading
- wrapperGetAjaxKey API command to request nonce for AJAX request
- Json.gz support for database files
- P2P port checking (Thanks for grez911)
- `--download_optional auto` argument to enable automatic optional file downloading for newly added site
- Statistics for big files and protocol command requests on /Stats
- Allow to set user limitation based on auth_address
### Changed
- More aggressive and frequent connection timeout checking
- Use out of msgpack context file streaming for files larger than 512KB
- Allow optional files workers over the worker limit
- Automatic redirection to wrapper on nonce_error
- Send websocket event on optional file deletion
- Optimize sites.json saving
- Enable faster C-based msgpack packer by default
- Major optimization on Bootstrapper plugin SQL queries
- Don't reset bad file counter on restart, to allow easier give up on unreachable files
- Incoming connection limit changed from 1000 to 500 to avoid reaching socket limit on Windows
- Changed tracker boot.zeronet.io domain, because zeronet.io got banned in some countries
#### Fixed
- Sub-directories in user directories
## ZeroNet 0.5.7 (2017-07-19)
### Added
- New plugin: CORS to request read permission to other site's content
- New API command: userSetSettings/userGetSettings to store site's settings in users.json
- Avoid file download if the file size does not match with the requested one
- JavaScript and wrapper less file access using /raw/ prefix ([Example](http://127.0.0.1:43110/raw/1AsRLpuRxr3pb9p3TKoMXPSWHzh6i7fMGi/en.tar.gz/index.html))
- --silent command line option to disable logging to stdout
### Changed
- Better error reporting on sign/verification errors
- More test for sign and verification process
- Update to OpenSSL v1.0.2l
- Limit compressed files to 6MB to avoid zip/tar.gz bomb
- Allow space, [], () characters in filenames
- Disable cross-site resource loading to improve privacy. [Reported by Beardog108]
- Download directly accessed Pdf/Svg/Swf files instead of displaying them to avoid wrapper escape using in JS in SVG file. [Reported by Beardog108]
- Disallow potentially unsafe regular expressions to avoid ReDoS [Reported by MuxZeroNet]
### Fixed
- Detecting data directory when running Windows distribution exe [Reported by Plasmmer]
- OpenSSL loading under Android 6+
- Error on exiting when no connection server started
## ZeroNet 0.5.6 (2017-06-15)
### Added
- Callback for certSelect API command
- More compact list formatting in json
### Changed
- Remove obsolete auth_key_sha512 and signature format
- Improved Spanish translation (Thanks to Pupiloho)
### Fixed
- Opened port checking (Thanks l5h5t7 & saber28 for reporting)
- Standalone update.py argument parsing (Thanks Zalex for reporting)
- uPnP crash on startup (Thanks Vertux for reporting)
- CoffeeScript 1.12.6 compatibility (Thanks kavamaken & imachug)
- Multi value argument parsing
- Database error when running from directory that contains special characters (Thanks Pupiloho for reporting)
- Site lock violation logging
#### Proxy bypass during source upgrade [Reported by ZeroMux]
In ZeroNet before 0.5.6 during the client's built-in source code upgrade mechanism,
ZeroNet did not respect Tor and/or proxy settings.
Result: ZeroNet downloaded the update without using the Tor network and potentially leaked the connections.
Fix: Removed the problematic code line from the updater that removed the proxy settings from the socket library.
Affected versions: ZeroNet 0.5.5 and earlier, Fixed in: ZeroNet 0.5.6
#### XSS vulnerability using DNS rebinding. [Reported by Beardog108]
In ZeroNet before 0.5.6 the web interface did not validate the request's Host parameter.
Result: An attacker using a specially crafted DNS entry could have bypassed the browser's cross-site-scripting protection
and potentially gained access to user's private data stored on site.
Fix: By default ZeroNet only accept connections from 127.0.0.1 and localhost hosts.
If you bind the ui server to an external interface, then it also adds the first http request's host to the allowed host list
or you can define it manually using --ui_host.
Affected versions: ZeroNet 0.5.5 and earlier, Fixed in: ZeroNet 0.5.6
## ZeroNet 0.5.5 (2017-05-18)
### Added
- Outgoing socket binding by --bind parameter
- Database rebuilding progress bar
- Protect low traffic site's peers from cleanup closing
- Local site blacklisting
- Cloned site source code upgrade from parent
- Input placeholder support for displayPrompt
- Alternative interaction for wrapperConfirm
### Changed
- New file priorities for faster site display on first visit
- Don't add ? to url if push/replaceState url starts with #
### Fixed
- PermissionAdd/Remove admin command requirement
- Multi-line confirmation dialog
## ZeroNet 0.5.4 (2017-04-14)
### Added
- Major speed and CPU usage enhancements in Tor always mode
- Send skipped modifications to outdated clients
### Changed
- Upgrade libs to latest version
- Faster port opening and closing
- Deny site limit modification in MultiUser mode
### Fixed
- Filling database from optional files
- OpenSSL detection on systems with OpenSSL 1.1
- Users.json corruption on systems with slow hdd
- Fix leaking files in data directory by webui
## ZeroNet 0.5.3 (2017-02-27)
### Added
- Tar.gz/zip packed site support
- Utf8 filenames in archive files
- Experimental --db_mode secure database mode to prevent data loss on systems with unreliable power source.
- Admin user support in MultiUser mode
- Optional deny adding new sites in MultiUser mode
### Changed
- Faster update and publish times by new socket sharing algorithm
### Fixed
- Fix missing json_row errors when using Mute plugin
## ZeroNet 0.5.2 (2017-02-09)
### Added
- User muting
- Win/Mac signed exe/.app
- Signed commits
### Changed
- Faster site updates after startup
- New macOS package for 10.10 compatibility
### Fixed
- Fix "New version just released" popup on page first visit
- Fix disappearing optional files bug (Thanks l5h5t7 for reporting)
- Fix skipped updates on unreliable connections (Thanks P2P for reporting)
- Sandbox escape security fix (Thanks Firebox for reporting)
- Fix error reporting on async websocket functions
## ZeroNet 0.5.1 (2016-11-18)
### Added
- Multi language interface
- New plugin: Translation helper for site html and js files
- Per-site favicon
### Fixed
- Parallel optional file downloading
## ZeroNet 0.5.0 (2016-11-08)
### Added
- New Plugin: Allow list/delete/pin/manage files on ZeroHello
- New API commands to follow user's optional files, and query stats for optional files
- Set total size limit on optional files.
- New Plugin: Save peers to database and keep them between restarts to allow more faster optional file search and make it work without trackers
- Rewritten uPnP port opener + close port on exit (Thanks to sirMackk!)
- Lower memory usage by lazy PeerHashfield creation
- Loaded json files statistics and database info at /Stats page
### Changed
- Separate lock file for better Windows compatibility
- When executing start.py open browser even if ZeroNet is already running
- Keep plugin order after reload to allow plugins to extends an another plug-in
- Only save sites.json if fully loaded to avoid data loss
- Change aletorrenty tracker to a more reliable one
- Much lower findhashid CPU usage
- Pooled downloading of large amount of optional files
- Lots of other optional file changes to make it better
- If we have 1000 peers for a site make cleanup more aggressive
- Use warning instead of error on verification errors
- Push updates to newer clients first
- Bad file reset improvements
### Fixed
- Fix site deletion errors on startup
- Delay websocket messages until it's connected
- Fix database import if data file contains extra data
- Fix big site download
- Fix diff sending bug (been chasing it for a long time)
- Fix random publish errors when json file contained [] characters
- Fix site delete and siteCreate bug
- Fix file write confirmation dialog
## ZeroNet 0.4.1 (2016-09-05)
### Added
- Major core changes to allow fast startup and lower memory usage
- Try to reconnect to Tor on lost connection
- Sidebar fade-in
- Try to avoid incomplete data files overwrite
- Faster database open
- Display user file sizes in sidebar
- Concurrent worker number depends on --connection_limit
### Changed
- Close databases after 5 min idle time
- Better site size calculation
- Allow "-" character in domains
- Always try to keep connections for sites
- Remove merger permission from merged sites
- Newsfeed scans only last 3 days to speed up database queries
- Updated ZeroBundle-win to Python 2.7.12
### Fixed
- Fix for important security problem, which is allowed anyone to publish new content without valid certificate from ID provider. Thanks Kaffie for pointing it out!
- Fix sidebar error when no certificate provider selected
- Skip invalid files on database rebuilding
- Fix random websocket connection error popups
- Fix new siteCreate command
- Fix site size calculation
- Fix port open checking after computer wake up
- Fix --size_limit parsing from command line
## ZeroNet 0.4.0 (2016-08-11)
### Added
- Merger site plugin
- Live source code reloading: Faster core development by allowing me to make changes in ZeroNet source code without restarting it.
- New json table format for merger sites
- Database rebuild from sidebar.
- Allow to store custom data directly in json table: Much simpler and faster SQL queries.
- User file archiving: Allows the site owner to archive inactive user's content into single file. (Reducing initial sync time/cpu/memory usage)
- Also trigger onUpdated/update database on file delete.
- Permission request from ZeroFrame API.
- Allow to store extra data in content.json using fileWrite API command.
- Faster optional files downloading
- Use alternative sources (Gogs, Gitlab) to download updates
- Track provided sites/connection and prefer to keep the ones with more sites to reduce connection number
### Changed
- Keep at least 5 connection per site
- Changed target connection for sites to 10 from 15
- ZeroHello search function stability/speed improvements
- Improvements for clients with slower HDD
### Fixed
- Fix IE11 wrapper nonce errors
- Fix sidebar on mobile devices
- Fix site size calculation
- Fix IE10 compatibility
- Windows XP ZeroBundle compatibility (THX to people of China)
## ZeroNet 0.3.7 (2016-05-27)
### Changed
- Patch command to reduce bandwidth usage by transfer only the changed lines
- Other cpu/memory optimizations
## ZeroNet 0.3.6 (2016-05-27)
### Added
- New ZeroHello
- Newsfeed function
### Fixed
- Security fixes
## ZeroNet 0.3.5 (2016-02-02)
### Added
- Full Tor support with .onion hidden services
- Bootstrap using ZeroNet protocol
### Fixed
- Fix Gevent 1.0.2 compatibility
## ZeroNet 0.3.4 (2015-12-28)
### Added
- AES, ECIES API function support
- PushState and ReplaceState url manipulation support in API
- Multiuser localstorage
================================================
FILE: COPYING
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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 <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
================================================
FILE: Dockerfile
================================================
FROM alpine:3.11
#Base settings
ENV HOME /root
COPY requirements.txt /root/requirements.txt
#Install ZeroNet
RUN apk --update --no-cache --no-progress add python3 python3-dev gcc libffi-dev musl-dev make tor openssl \
&& pip3 install -r /root/requirements.txt \
&& apk del python3-dev gcc libffi-dev musl-dev make \
&& echo "ControlPort 9051" >> /etc/tor/torrc \
&& echo "CookieAuthentication 1" >> /etc/tor/torrc
RUN python3 -V \
&& python3 -m pip list \
&& tor --version \
&& openssl version
#Add Zeronet source
COPY . /root
VOLUME /root/data
#Control if Tor proxy is started
ENV ENABLE_TOR false
WORKDIR /root
#Set upstart command
CMD (! ${ENABLE_TOR} || tor&) && python3 zeronet.py --ui_ip 0.0.0.0 --fileserver_port 26552
#Expose ports
EXPOSE 43110 26552
================================================
FILE: Dockerfile.arm64v8
================================================
FROM alpine:3.12
#Base settings
ENV HOME /root
COPY requirements.txt /root/requirements.txt
#Install ZeroNet
RUN apk --update --no-cache --no-progress add python3 python3-dev gcc libffi-dev musl-dev make tor openssl \
&& pip3 install -r /root/requirements.txt \
&& apk del python3-dev gcc libffi-dev musl-dev make \
&& echo "ControlPort 9051" >> /etc/tor/torrc \
&& echo "CookieAuthentication 1" >> /etc/tor/torrc
RUN python3 -V \
&& python3 -m pip list \
&& tor --version \
&& openssl version
#Add Zeronet source
COPY . /root
VOLUME /root/data
#Control if Tor proxy is started
ENV ENABLE_TOR false
WORKDIR /root
#Set upstart command
CMD (! ${ENABLE_TOR} || tor&) && python3 zeronet.py --ui_ip 0.0.0.0 --fileserver_port 26552
#Expose ports
EXPOSE 43110 26552
================================================
FILE: LICENSE
================================================
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, version 3.
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 <https://www.gnu.org/licenses/>.
Additional Conditions :
Contributing to this repo
This repo is governed by GPLv3, same is located at the root of the ZeroNet git repo,
unless specified separately all code is governed by that license, contributions to this repo
are divided into two key types, key contributions and non-key contributions, key contributions
are which, directly affects the code performance, quality and features of software,
non key contributions include things like translation datasets, image, graphic or video
contributions that does not affect the main usability of software but improves the existing
usability of certain thing or feature, these also include tests written with code, since their
purpose is to check, whether something is working or not as intended. All the non-key contributions
are governed by [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/), unless specified
above, a contribution is ruled by the type of contribution if there is a conflict between two
contributing parties of repo in any case.
================================================
FILE: README-ru.md
================================================
# ZeroNet [](https://travis-ci.org/HelloZeroNet/ZeroNet) [](https://zeronet.io/docs/faq/) [](https://zeronet.io/docs/help_zeronet/donate/)
[简体中文](./README-zh-cn.md)
[English](./README.md)
Децентрализованные вебсайты использующие Bitcoin криптографию и BitTorrent сеть - https://zeronet.io
## Зачем?
* Мы верим в открытую, свободную, и не отцензуренную сеть и коммуникацию.
* Нет единой точки отказа: Сайт онлайн пока по крайней мере 1 пир обслуживает его.
* Никаких затрат на хостинг: Сайты обслуживаются посетителями.
* Невозможно отключить: Он нигде, потому что он везде.
* Быстр и работает оффлайн: Вы можете получить доступ к сайту, даже если Интернет недоступен.
## Особенности
* Обновляемые в реальном времени сайты
* Поддержка Namecoin .bit доменов
* Лёгок в установке: распаковал & запустил
* Клонирование вебсайтов в один клик
* Password-less [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
based authorization: Ваша учетная запись защищена той же криптографией, что и ваш Bitcoin-кошелек
* Встроенный SQL-сервер с синхронизацией данных P2P: Позволяет упростить разработку сайта и ускорить загрузку страницы
* Анонимность: Полная поддержка сети Tor с помощью скрытых служб .onion вместо адресов IPv4
* TLS зашифрованные связи
* Автоматическое открытие uPnP порта
* Плагин для поддержки многопользовательской (openproxy)
* Работает с любыми браузерами и операционными системами
## Как это работает?
* После запуска `zeronet.py` вы сможете посетить зайты (zeronet сайты) используя адрес
`http://127.0.0.1:43110/{zeronet_address}`
(например. `http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D`).
* Когда вы посещаете новый сайт zeronet, он пытается найти пиров с помощью BitTorrent
чтобы загрузить файлы сайтов (html, css, js ...) из них.
* Каждый посещенный зайт также обслуживается вами. (Т.е хранится у вас на компьютере)
* Каждый сайт содержит файл `content.json`, который содержит все остальные файлы в хэше sha512
и подпись, созданную с использованием частного ключа сайта.
* Если владелец сайта (у которого есть закрытый ключ для адреса сайта) изменяет сайт, то он/она
подписывает новый `content.json` и публикует его для пиров. После этого пиры проверяют целостность `content.json`
(используя подпись), они загружают измененные файлы и публикуют новый контент для других пиров.
#### [Слайд-шоу о криптографии ZeroNet, обновлениях сайтов, многопользовательских сайтах »](https://docs.google.com/presentation/d/1_2qK1IuOKJ51pgBvllZ9Yu7Au2l551t3XBgyTSvilew/pub?start=false&loop=false&delayms=3000)
#### [Часто задаваемые вопросы »](https://zeronet.io/docs/faq/)
#### [Документация разработчика ZeroNet »](https://zeronet.io/docs/site_development/getting_started/)
## Скриншоты


#### [Больше скриншотов в ZeroNet документации »](https://zeronet.io/docs/using_zeronet/sample_sites/)
## Как вступить
* Скачайте ZeroBundle пакет:
* [Microsoft Windows](https://github.com/HelloZeroNet/ZeroNet-win/archive/dist/ZeroNet-win.zip)
* [Apple macOS](https://github.com/HelloZeroNet/ZeroNet-mac/archive/dist/ZeroNet-mac.zip)
* [Linux 64-bit](https://github.com/HelloZeroNet/ZeroBundle/raw/master/dist/ZeroBundle-linux64.tar.gz)
* [Linux 32-bit](https://github.com/HelloZeroNet/ZeroBundle/raw/master/dist/ZeroBundle-linux32.tar.gz)
* Распакуйте где угодно
* Запустите `ZeroNet.exe` (win), `ZeroNet(.app)` (osx), `ZeroNet.sh` (linux)
### Linux терминал
* `wget https://github.com/HelloZeroNet/ZeroBundle/raw/master/dist/ZeroBundle-linux64.tar.gz`
* `tar xvpfz ZeroBundle-linux64.tar.gz`
* `cd ZeroBundle`
* Запустите с помощью `./ZeroNet.sh`
Он загружает последнюю версию ZeroNet, затем запускает её автоматически.
#### Ручная установка для Debian Linux
* `sudo apt-get update`
* `sudo apt-get install msgpack-python python-gevent`
* `wget https://github.com/HelloZeroNet/ZeroNet/archive/master.tar.gz`
* `tar xvpfz master.tar.gz`
* `cd ZeroNet-master`
* Запустите с помощью `python2 zeronet.py`
* Откройте http://127.0.0.1:43110/ в вашем браузере.
### [Arch Linux](https://www.archlinux.org)
* `git clone https://aur.archlinux.org/zeronet.git`
* `cd zeronet`
* `makepkg -srci`
* `systemctl start zeronet`
* Откройте http://127.0.0.1:43110/ в вашем браузере.
Смотрите [ArchWiki](https://wiki.archlinux.org)'s [ZeroNet
article](https://wiki.archlinux.org/index.php/ZeroNet) для дальнейшей помощи.
### [Gentoo Linux](https://www.gentoo.org)
* [`layman -a raiagent`](https://github.com/leycec/raiagent)
* `echo '>=net-vpn/zeronet-0.5.4' >> /etc/portage/package.accept_keywords`
* *(Опционально)* Включить поддержку Tor: `echo 'net-vpn/zeronet tor' >>
/etc/portage/package.use`
* `emerge zeronet`
* `rc-service zeronet start`
* Откройте http://127.0.0.1:43110/ в вашем браузере.
Смотрите `/usr/share/doc/zeronet-*/README.gentoo.bz2` для дальнейшей помощи.
### [FreeBSD](https://www.freebsd.org/)
* `pkg install zeronet` or `cd /usr/ports/security/zeronet/ && make install clean`
* `sysrc zeronet_enable="YES"`
* `service zeronet start`
* Откройте http://127.0.0.1:43110/ в вашем браузере.
### [Vagrant](https://www.vagrantup.com/)
* `vagrant up`
* Подключитесь к VM с помощью `vagrant ssh`
* `cd /vagrant`
* Запустите `python2 zeronet.py --ui_ip 0.0.0.0`
* Откройте http://127.0.0.1:43110/ в вашем браузере.
### [Docker](https://www.docker.com/)
* `docker run -d -v <local_data_folder>:/root/data -p 15441:15441 -p 127.0.0.1:43110:43110 nofish/zeronet`
* Это изображение Docker включает в себя прокси-сервер Tor, который по умолчанию отключён.
Остерегайтесь что некоторые хостинг-провайдеры могут не позволить вам запускать Tor на своих серверах.
Если вы хотите включить его,установите переменную среды `ENABLE_TOR` в` true` (по умолчанию: `false`) Например:
`docker run -d -e "ENABLE_TOR=true" -v <local_data_folder>:/root/data -p 15441:15441 -p 127.0.0.1:43110:43110 nofish/zeronet`
* Откройте http://127.0.0.1:43110/ в вашем браузере.
### [Virtualenv](https://virtualenv.readthedocs.org/en/latest/)
* `virtualenv env`
* `source env/bin/activate`
* `pip install msgpack gevent`
* `python2 zeronet.py`
* Откройте http://127.0.0.1:43110/ в вашем браузере.
## Текущие ограничения
* ~~Нет torrent-похожего файла разделения для поддержки больших файлов~~ (поддержка больших файлов добавлена)
* ~~Не анонимнее чем Bittorrent~~ (добавлена встроенная поддержка Tor)
* Файловые транзакции не сжаты ~~ или незашифрованы еще ~~ (добавлено шифрование TLS)
* Нет приватных сайтов
## Как я могу создать сайт в Zeronet?
Завершите работу zeronet, если он запущен
```bash
$ zeronet.py siteCreate
...
- Site private key (Приватный ключ сайта): 23DKQpzxhbVBrAtvLEc2uvk7DZweh4qL3fn3jpM3LgHDczMK2TtYUq
- Site address (Адрес сайта): 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2
...
- Site created! (Сайт создан)
$ zeronet.py
...
```
Поздравляем, вы закончили! Теперь каждый может получить доступ к вашему зайту используя
`http://localhost:43110/13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2`
Следующие шаги: [ZeroNet Developer Documentation](https://zeronet.io/docs/site_development/getting_started/)
## Как я могу модифицировать Zeronet сайт?
* Измените файлы расположенные в data/13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2 директории.
Когда закончите с изменением:
```bash
$ zeronet.py siteSign 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2
- Signing site (Подпись сайта): 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2...
Private key (Приватный ключ) (input hidden):
```
* Введите секретный ключ, который вы получили при создании сайта, потом:
```bash
$ zeronet.py sitePublish 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2
...
Site:13DNDk..bhC2 Publishing to 3/10 peers...
Site:13DNDk..bhC2 Successfuly published to 3 peers
- Serving files....
```
* Вот и всё! Вы успешно подписали и опубликовали свои изменения.
## Поддержите проект
- Bitcoin: 1QDhxQ6PraUZa21ET5fYUCPgdrwBomnFgX
- Paypal: https://zeronet.io/docs/help_zeronet/donate/
### Спонсоры
* Улучшенная совместимость с MacOS / Safari стала возможной благодаря [BrowserStack.com](https://www.browserstack.com)
#### Спасибо!
* Больше информации, помощь, журнал изменений, zeronet сайты: https://www.reddit.com/r/zeronet/
* Приходите, пообщайтесь с нами: [#zeronet @ FreeNode](https://kiwiirc.com/client/irc.freenode.net/zeronet) или на [gitter](https://gitter.im/HelloZeroNet/ZeroNet)
* Email: hello@zeronet.io (PGP: CB9613AE)
================================================
FILE: README-zh-cn.md
================================================
# ZeroNet [](https://travis-ci.org/HelloZeroNet/ZeroNet) [](https://zeronet.io/docs/faq/) [](https://zeronet.io/docs/help_zeronet/donate/)
[English](./README.md)
使用 Bitcoin 加密和 BitTorrent 网络的去中心化网络 - https://zeronet.io
## 为什么?
* 我们相信开放,自由,无审查的网络和通讯
* 不会受单点故障影响:只要有在线的节点,站点就会保持在线
* 无托管费用:站点由访问者托管
* 无法关闭:因为节点无处不在
* 快速并可离线运行:即使没有互联网连接也可以使用
## 功能
* 实时站点更新
* 支持 Namecoin 的 .bit 域名
* 安装方便:只需解压并运行
* 一键克隆存在的站点
* 无需密码、基于 [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
的认证:您的账户被与比特币钱包相同的加密方法保护
* 内建 SQL 服务器和 P2P 数据同步:让开发更简单并提升加载速度
* 匿名性:完整的 Tor 网络支持,支持通过 .onion 隐藏服务相互连接而不是通过 IPv4 地址连接
* TLS 加密连接
* 自动打开 uPnP 端口
* 多用户(openproxy)支持的插件
* 适用于任何浏览器 / 操作系统
## 原理
* 在运行 `zeronet.py` 后,您将可以通过
`http://127.0.0.1:43110/{zeronet_address}`(例如:
`http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D`)访问 zeronet 中的站点
* 在您浏览 zeronet 站点时,客户端会尝试通过 BitTorrent 网络来寻找可用的节点,从而下载需要的文件(html,css,js...)
* 您将会储存每一个浏览过的站点
* 每个站点都包含一个名为 `content.json` 的文件,它储存了其他所有文件的 sha512 散列值以及一个通过站点私钥生成的签名
* 如果站点的所有者(拥有站点地址的私钥)修改了站点,并且他 / 她签名了新的 `content.json` 然后推送至其他节点,
那么这些节点将会在使用签名验证 `content.json` 的真实性后,下载修改后的文件并将新内容推送至另外的节点
#### [关于 ZeroNet 加密,站点更新,多用户站点的幻灯片 »](https://docs.google.com/presentation/d/1_2qK1IuOKJ51pgBvllZ9Yu7Au2l551t3XBgyTSvilew/pub?start=false&loop=false&delayms=3000)
#### [常见问题 »](https://zeronet.io/docs/faq/)
#### [ZeroNet 开发者文档 »](https://zeronet.io/docs/site_development/getting_started/)
## 屏幕截图


#### [ZeroNet 文档中的更多屏幕截图 »](https://zeronet.io/docs/using_zeronet/sample_sites/)
## 如何加入
### Windows
- 下载 [ZeroNet-py3-win64.zip](https://github.com/HelloZeroNet/ZeroNet-win/archive/dist-win64/ZeroNet-py3-win64.zip) (18MB)
- 在任意位置解压缩
- 运行 `ZeroNet.exe`
### macOS
- 下载 [ZeroNet-dist-mac.zip](https://github.com/HelloZeroNet/ZeroNet-dist/archive/mac/ZeroNet-dist-mac.zip) (13.2MB)
- 在任意位置解压缩
- 运行 `ZeroNet.app`
### Linux (x86-64bit)
- `wget https://github.com/HelloZeroNet/ZeroNet-linux/archive/dist-linux64/ZeroNet-py3-linux64.tar.gz`
- `tar xvpfz ZeroNet-py3-linux64.tar.gz`
- `cd ZeroNet-linux-dist-linux64/`
- 使用以下命令启动 `./ZeroNet.sh`
- 在浏览器打开 http://127.0.0.1:43110/ 即可访问 ZeroHello 页面
__提示:__ 若要允许在 Web 界面上的远程连接,使用以下命令启动 `./ZeroNet.sh --ui_ip '*' --ui_restrict your.ip.address`
### 从源代码安装
- `wget https://github.com/HelloZeroNet/ZeroNet/archive/py3/ZeroNet-py3.tar.gz`
- `tar xvpfz ZeroNet-py3.tar.gz`
- `cd ZeroNet-py3`
- `sudo apt-get update`
- `sudo apt-get install python3-pip`
- `sudo python3 -m pip install -r requirements.txt`
- 使用以下命令启动 `python3 zeronet.py`
- 在浏览器打开 http://127.0.0.1:43110/ 即可访问 ZeroHello 页面
## 现有限制
* ~~没有类似于 torrent 的文件拆分来支持大文件~~ (已添加大文件支持)
* ~~没有比 BitTorrent 更好的匿名性~~ (已添加内置的完整 Tor 支持)
* 传输文件时没有压缩~~和加密~~ (已添加 TLS 支持)
* 不支持私有站点
## 如何创建一个 ZeroNet 站点?
* 点击 [ZeroHello](http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D) 站点的 **⋮** > **「新建空站点」** 菜单项
* 您将被**重定向**到一个全新的站点,该站点只能由您修改
* 您可以在 **data/[您的站点地址]** 目录中找到并修改网站的内容
* 修改后打开您的网站,将右上角的「0」按钮拖到左侧,然后点击底部的**签名**并**发布**按钮
接下来的步骤:[ZeroNet 开发者文档](https://zeronet.io/docs/site_development/getting_started/)
## 帮助这个项目
- Bitcoin: 1QDhxQ6PraUZa21ET5fYUCPgdrwBomnFgX
- Paypal: https://zeronet.io/docs/help_zeronet/donate/
### 赞助商
* [BrowserStack.com](https://www.browserstack.com) 使更好的 macOS/Safari 兼容性成为可能
#### 感谢您!
* 更多信息,帮助,变更记录和 zeronet 站点:https://www.reddit.com/r/zeronet/
* 前往 [#zeronet @ FreeNode](https://kiwiirc.com/client/irc.freenode.net/zeronet) 或 [gitter](https://gitter.im/HelloZeroNet/ZeroNet) 和我们聊天
* [这里](https://gitter.im/ZeroNet-zh/Lobby)是一个 gitter 上的中文聊天室
* Email: hello@zeronet.io (PGP: [960F FF2D 6C14 5AA6 13E8 491B 5B63 BAE6 CB96 13AE](https://zeronet.io/files/tamas@zeronet.io_pub.asc))
================================================
FILE: README.md
================================================
# ZeroNet [](https://travis-ci.org/HelloZeroNet/ZeroNet) [](https://zeronet.io/docs/faq/) [](https://zeronet.io/docs/help_zeronet/donate/)  [](https://hub.docker.com/r/nofish/zeronet)
Decentralized websites using Bitcoin crypto and the BitTorrent network - https://zeronet.io / [onion](http://zeronet34m3r5ngdu54uj57dcafpgdjhxsgq5kla5con4qvcmfzpvhad.onion)
## Why?
* We believe in open, free, and uncensored network and communication.
* No single point of failure: Site remains online so long as at least 1 peer is
serving it.
* No hosting costs: Sites are served by visitors.
* Impossible to shut down: It's nowhere because it's everywhere.
* Fast and works offline: You can access the site even if Internet is
unavailable.
## Features
* Real-time updated sites
* Namecoin .bit domains support
* Easy to setup: unpack & run
* Clone websites in one click
* Password-less [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
based authorization: Your account is protected by the same cryptography as your Bitcoin wallet
* Built-in SQL server with P2P data synchronization: Allows easier site development and faster page load times
* Anonymity: Full Tor network support with .onion hidden services instead of IPv4 addresses
* TLS encrypted connections
* Automatic uPnP port opening
* Plugin for multiuser (openproxy) support
* Works with any browser/OS
## How does it work?
* After starting `zeronet.py` you will be able to visit zeronet sites using
`http://127.0.0.1:43110/{zeronet_address}` (eg.
`http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D`).
* When you visit a new zeronet site, it tries to find peers using the BitTorrent
network so it can download the site files (html, css, js...) from them.
* Each visited site is also served by you.
* Every site contains a `content.json` file which holds all other files in a sha512 hash
and a signature generated using the site's private key.
* If the site owner (who has the private key for the site address) modifies the
site, then he/she signs the new `content.json` and publishes it to the peers.
Afterwards, the peers verify the `content.json` integrity (using the
signature), they download the modified files and publish the new content to
other peers.
#### [Slideshow about ZeroNet cryptography, site updates, multi-user sites »](https://docs.google.com/presentation/d/1_2qK1IuOKJ51pgBvllZ9Yu7Au2l551t3XBgyTSvilew/pub?start=false&loop=false&delayms=3000)
#### [Frequently asked questions »](https://zeronet.io/docs/faq/)
#### [ZeroNet Developer Documentation »](https://zeronet.io/docs/site_development/getting_started/)
## Screenshots


#### [More screenshots in ZeroNet docs »](https://zeronet.io/docs/using_zeronet/sample_sites/)
## How to join
### Windows
- Download [ZeroNet-py3-win64.zip](https://github.com/HelloZeroNet/ZeroNet-win/archive/dist-win64/ZeroNet-py3-win64.zip) (18MB)
- Unpack anywhere
- Run `ZeroNet.exe`
### macOS
- Download [ZeroNet-dist-mac.zip](https://github.com/HelloZeroNet/ZeroNet-dist/archive/mac/ZeroNet-dist-mac.zip) (13.2MB)
- Unpack anywhere
- Run `ZeroNet.app`
### Linux (x86-64bit)
- `wget https://github.com/HelloZeroNet/ZeroNet-linux/archive/dist-linux64/ZeroNet-py3-linux64.tar.gz`
- `tar xvpfz ZeroNet-py3-linux64.tar.gz`
- `cd ZeroNet-linux-dist-linux64/`
- Start with: `./ZeroNet.sh`
- Open the ZeroHello landing page in your browser by navigating to: http://127.0.0.1:43110/
__Tip:__ Start with `./ZeroNet.sh --ui_ip '*' --ui_restrict your.ip.address` to allow remote connections on the web interface.
### Android (arm, arm64, x86)
- minimum Android version supported 16 (JellyBean)
- [<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Download from Google Play"
height="80">](https://play.google.com/store/apps/details?id=in.canews.zeronetmobile)
- APK download: https://github.com/canewsin/zeronet_mobile/releases
- XDA Labs: https://labs.xda-developers.com/store/app/in.canews.zeronet
#### Docker
There is an official image, built from source at: https://hub.docker.com/r/nofish/zeronet/
### Install from source
- `wget https://github.com/HelloZeroNet/ZeroNet/archive/py3/ZeroNet-py3.tar.gz`
- `tar xvpfz ZeroNet-py3.tar.gz`
- `cd ZeroNet-py3`
- `sudo apt-get update`
- `sudo apt-get install python3-pip`
- `sudo python3 -m pip install -r requirements.txt`
- Start with: `python3 zeronet.py`
- Open the ZeroHello landing page in your browser by navigating to: http://127.0.0.1:43110/
## Current limitations
* ~~No torrent-like file splitting for big file support~~ (big file support added)
* ~~No more anonymous than Bittorrent~~ (built-in full Tor support added)
* File transactions are not compressed ~~or encrypted yet~~ (TLS encryption added)
* No private sites
## How can I create a ZeroNet site?
* Click on **⋮** > **"Create new, empty site"** menu item on the site [ZeroHello](http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D).
* You will be **redirected** to a completely new site that is only modifiable by you!
* You can find and modify your site's content in **data/[yoursiteaddress]** directory
* After the modifications open your site, drag the topright "0" button to left, then press **sign** and **publish** buttons on the bottom
Next steps: [ZeroNet Developer Documentation](https://zeronet.io/docs/site_development/getting_started/)
## Help keep this project alive
- Bitcoin: 1QDhxQ6PraUZa21ET5fYUCPgdrwBomnFgX
- Paypal: https://zeronet.io/docs/help_zeronet/donate/
### Sponsors
* Better macOS/Safari compatibility made possible by [BrowserStack.com](https://www.browserstack.com)
#### Thank you!
* More info, help, changelog, zeronet sites: https://www.reddit.com/r/zeronet/
* Come, chat with us: [#zeronet @ FreeNode](https://kiwiirc.com/client/irc.freenode.net/zeronet) or on [gitter](https://gitter.im/HelloZeroNet/ZeroNet)
* Email: hello@zeronet.io (PGP: [960F FF2D 6C14 5AA6 13E8 491B 5B63 BAE6 CB96 13AE](https://zeronet.io/files/tamas@zeronet.io_pub.asc))
================================================
FILE: Vagrantfile
================================================
# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
#Set box
config.vm.box = "ubuntu/trusty64"
#Do not check fo updates
config.vm.box_check_update = false
#Add private network
config.vm.network "private_network", type: "dhcp"
#Redirect ports
config.vm.network "forwarded_port", guest: 43110, host: 43110
config.vm.network "forwarded_port", guest: 15441, host: 15441
#Sync folder using NFS if not windows
config.vm.synced_folder ".", "/vagrant",
:nfs => !Vagrant::Util::Platform.windows?
#Virtal Box settings
config.vm.provider "virtualbox" do |vb|
# Don't boot with headless mode
#vb.gui = true
# Set VM settings
vb.customize ["modifyvm", :id, "--memory", "512"]
vb.customize ["modifyvm", :id, "--cpus", 1]
end
#Update system
config.vm.provision "shell",
inline: "sudo apt-get update -y && sudo apt-get upgrade -y"
#Install deps
config.vm.provision "shell",
inline: "sudo apt-get install msgpack-python python-gevent python-pip python-dev -y"
config.vm.provision "shell",
inline: "sudo pip install msgpack --upgrade"
end
================================================
FILE: plugins/AnnounceBitTorrent/AnnounceBitTorrentPlugin.py
================================================
import time
import urllib.request
import struct
import socket
import lib.bencode_open as bencode_open
from lib.subtl.subtl import UdpTrackerClient
import socks
import sockshandler
import gevent
from Plugin import PluginManager
from Config import config
from Debug import Debug
from util import helper
# We can only import plugin host clases after the plugins are loaded
@PluginManager.afterLoad
def importHostClasses():
global Peer, AnnounceError
from Peer import Peer
from Site.SiteAnnouncer import AnnounceError
@PluginManager.registerTo("SiteAnnouncer")
class SiteAnnouncerPlugin(object):
def getSupportedTrackers(self):
trackers = super(SiteAnnouncerPlugin, self).getSupportedTrackers()
if config.disable_udp or config.trackers_proxy != "disable":
trackers = [tracker for tracker in trackers if not tracker.startswith("udp://")]
return trackers
def getTrackerHandler(self, protocol):
if protocol == "udp":
handler = self.announceTrackerUdp
elif protocol == "http":
handler = self.announceTrackerHttp
elif protocol == "https":
handler = self.announceTrackerHttps
else:
handler = super(SiteAnnouncerPlugin, self).getTrackerHandler(protocol)
return handler
def announceTrackerUdp(self, tracker_address, mode="start", num_want=10):
s = time.time()
if config.disable_udp:
raise AnnounceError("Udp disabled by config")
if config.trackers_proxy != "disable":
raise AnnounceError("Udp trackers not available with proxies")
ip, port = tracker_address.split("/")[0].split(":")
tracker = UdpTrackerClient(ip, int(port))
if helper.getIpType(ip) in self.getOpenedServiceTypes():
tracker.peer_port = self.fileserver_port
else:
tracker.peer_port = 0
tracker.connect()
if not tracker.poll_once():
raise AnnounceError("Could not connect")
tracker.announce(info_hash=self.site.address_sha1, num_want=num_want, left=431102370)
back = tracker.poll_once()
if not back:
raise AnnounceError("No response after %.0fs" % (time.time() - s))
elif type(back) is dict and "response" in back:
peers = back["response"]["peers"]
else:
raise AnnounceError("Invalid response: %r" % back)
return peers
def httpRequest(self, url):
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
'Accept-Encoding': 'none',
'Accept-Language': 'en-US,en;q=0.8',
'Connection': 'keep-alive'
}
req = urllib.request.Request(url, headers=headers)
if config.trackers_proxy == "tor":
tor_manager = self.site.connection_server.tor_manager
handler = sockshandler.SocksiPyHandler(socks.SOCKS5, tor_manager.proxy_ip, tor_manager.proxy_port)
opener = urllib.request.build_opener(handler)
return opener.open(req, timeout=50)
elif config.trackers_proxy == "disable":
return urllib.request.urlopen(req, timeout=25)
else:
proxy_ip, proxy_port = config.trackers_proxy.split(":")
handler = sockshandler.SocksiPyHandler(socks.SOCKS5, proxy_ip, int(proxy_port))
opener = urllib.request.build_opener(handler)
return opener.open(req, timeout=50)
def announceTrackerHttps(self, *args, **kwargs):
kwargs["protocol"] = "https"
return self.announceTrackerHttp(*args, **kwargs)
def announceTrackerHttp(self, tracker_address, mode="start", num_want=10, protocol="http"):
tracker_ip, tracker_port = tracker_address.rsplit(":", 1)
if helper.getIpType(tracker_ip) in self.getOpenedServiceTypes():
port = self.fileserver_port
else:
port = 1
params = {
'info_hash': self.site.address_sha1,
'peer_id': self.peer_id, 'port': port,
'uploaded': 0, 'downloaded': 0, 'left': 431102370, 'compact': 1, 'numwant': num_want,
'event': 'started'
}
url = protocol + "://" + tracker_address + "?" + urllib.parse.urlencode(params)
s = time.time()
response = None
# Load url
if config.tor == "always" or config.trackers_proxy != "disable":
timeout = 60
else:
timeout = 30
with gevent.Timeout(timeout, False): # Make sure of timeout
req = self.httpRequest(url)
response = req.read()
req.close()
req = None
if not response:
raise AnnounceError("No response after %.0fs" % (time.time() - s))
# Decode peers
try:
peer_data = bencode_open.loads(response)[b"peers"]
response = None
peer_count = int(len(peer_data) / 6)
peers = []
for peer_offset in range(peer_count):
off = 6 * peer_offset
peer = peer_data[off:off + 6]
addr, port = struct.unpack('!LH', peer)
peers.append({"addr": socket.inet_ntoa(struct.pack('!L', addr)), "port": port})
except Exception as err:
raise AnnounceError("Invalid response: %r (%s)" % (response, Debug.formatException(err)))
return peers
================================================
FILE: plugins/AnnounceBitTorrent/__init__.py
================================================
from . import AnnounceBitTorrentPlugin
================================================
FILE: plugins/AnnounceBitTorrent/plugin_info.json
================================================
{
"name": "AnnounceBitTorrent",
"description": "Discover new peers using BitTorrent trackers.",
"default": "enabled"
}
================================================
FILE: plugins/AnnounceLocal/AnnounceLocalPlugin.py
================================================
import time
import gevent
from Plugin import PluginManager
from Config import config
from . import BroadcastServer
@PluginManager.registerTo("SiteAnnouncer")
class SiteAnnouncerPlugin(object):
def announce(self, force=False, *args, **kwargs):
local_announcer = self.site.connection_server.local_announcer
thread = None
if local_announcer and (force or time.time() - local_announcer.last_discover > 5 * 60):
thread = gevent.spawn(local_announcer.discover, force=force)
back = super(SiteAnnouncerPlugin, self).announce(force=force, *args, **kwargs)
if thread:
thread.join()
return back
class LocalAnnouncer(BroadcastServer.BroadcastServer):
def __init__(self, server, listen_port):
super(LocalAnnouncer, self).__init__("zeronet", listen_port=listen_port)
self.server = server
self.sender_info["peer_id"] = self.server.peer_id
self.sender_info["port"] = self.server.port
self.sender_info["broadcast_port"] = listen_port
self.sender_info["rev"] = config.rev
self.known_peers = {}
self.last_discover = 0
def discover(self, force=False):
self.log.debug("Sending discover request (force: %s)" % force)
self.last_discover = time.time()
if force: # Probably new site added, clean cache
self.known_peers = {}
for peer_id, known_peer in list(self.known_peers.items()):
if time.time() - known_peer["found"] > 20 * 60:
del(self.known_peers[peer_id])
self.log.debug("Timeout, removing from known_peers: %s" % peer_id)
self.broadcast({"cmd": "discoverRequest", "params": {}}, port=self.listen_port)
def actionDiscoverRequest(self, sender, params):
back = {
"cmd": "discoverResponse",
"params": {
"sites_changed": self.server.site_manager.sites_changed
}
}
if sender["peer_id"] not in self.known_peers:
self.known_peers[sender["peer_id"]] = {"added": time.time(), "sites_changed": 0, "updated": 0, "found": time.time()}
self.log.debug("Got discover request from unknown peer %s (%s), time to refresh known peers" % (sender["ip"], sender["peer_id"]))
gevent.spawn_later(1.0, self.discover) # Let the response arrive first to the requester
return back
def actionDiscoverResponse(self, sender, params):
if sender["peer_id"] in self.known_peers:
self.known_peers[sender["peer_id"]]["found"] = time.time()
if params["sites_changed"] != self.known_peers.get(sender["peer_id"], {}).get("sites_changed"):
# Peer's site list changed, request the list of new sites
return {"cmd": "siteListRequest"}
else:
# Peer's site list is the same
for site in self.server.sites.values():
peer = site.peers.get("%s:%s" % (sender["ip"], sender["port"]))
if peer:
peer.found("local")
def actionSiteListRequest(self, sender, params):
back = []
sites = list(self.server.sites.values())
# Split adresses to group of 100 to avoid UDP size limit
site_groups = [sites[i:i + 100] for i in range(0, len(sites), 100)]
for site_group in site_groups:
res = {}
res["sites_changed"] = self.server.site_manager.sites_changed
res["sites"] = [site.address_hash for site in site_group]
back.append({"cmd": "siteListResponse", "params": res})
return back
def actionSiteListResponse(self, sender, params):
s = time.time()
peer_sites = set(params["sites"])
num_found = 0
added_sites = []
for site in self.server.sites.values():
if site.address_hash in peer_sites:
added = site.addPeer(sender["ip"], sender["port"], source="local")
num_found += 1
if added:
site.worker_manager.onPeers()
site.updateWebsocket(peers_added=1)
added_sites.append(site)
# Save sites changed value to avoid unnecessary site list download
if sender["peer_id"] not in self.known_peers:
self.known_peers[sender["peer_id"]] = {"added": time.time()}
self.known_peers[sender["peer_id"]]["sites_changed"] = params["sites_changed"]
self.known_peers[sender["peer_id"]]["updated"] = time.time()
self.known_peers[sender["peer_id"]]["found"] = time.time()
self.log.debug(
"Tracker result: Discover from %s response parsed in %.3fs, found: %s added: %s of %s" %
(sender["ip"], time.time() - s, num_found, added_sites, len(peer_sites))
)
@PluginManager.registerTo("FileServer")
class FileServerPlugin(object):
def __init__(self, *args, **kwargs):
super(FileServerPlugin, self).__init__(*args, **kwargs)
if config.broadcast_port and config.tor != "always" and not config.disable_udp:
self.local_announcer = LocalAnnouncer(self, config.broadcast_port)
else:
self.local_announcer = None
def start(self, *args, **kwargs):
if self.local_announcer:
gevent.spawn(self.local_announcer.start)
return super(FileServerPlugin, self).start(*args, **kwargs)
def stop(self):
if self.local_announcer:
self.local_announcer.stop()
res = super(FileServerPlugin, self).stop()
return res
@PluginManager.registerTo("ConfigPlugin")
class ConfigPlugin(object):
def createArguments(self):
group = self.parser.add_argument_group("AnnounceLocal plugin")
group.add_argument('--broadcast_port', help='UDP broadcasting port for local peer discovery', default=1544, type=int, metavar='port')
return super(ConfigPlugin, self).createArguments()
================================================
FILE: plugins/AnnounceLocal/BroadcastServer.py
================================================
import socket
import logging
import time
from contextlib import closing
from Debug import Debug
from util import UpnpPunch
from util import Msgpack
class BroadcastServer(object):
def __init__(self, service_name, listen_port=1544, listen_ip=''):
self.log = logging.getLogger("BroadcastServer")
self.listen_port = listen_port
self.listen_ip = listen_ip
self.running = False
self.sock = None
self.sender_info = {"service": service_name}
def createBroadcastSocket(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if hasattr(socket, 'SO_REUSEPORT'):
try:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
except Exception as err:
self.log.warning("Error setting SO_REUSEPORT: %s" % err)
binded = False
for retry in range(3):
try:
sock.bind((self.listen_ip, self.listen_port))
binded = True
break
except Exception as err:
self.log.error(
"Socket bind to %s:%s error: %s, retry #%s" %
(self.listen_ip, self.listen_port, Debug.formatException(err), retry)
)
time.sleep(retry)
if binded:
return sock
else:
return False
def start(self): # Listens for discover requests
self.sock = self.createBroadcastSocket()
if not self.sock:
self.log.error("Unable to listen on port %s" % self.listen_port)
return
self.log.debug("Started on port %s" % self.listen_port)
self.running = True
while self.running:
try:
data, addr = self.sock.recvfrom(8192)
except Exception as err:
if self.running:
self.log.error("Listener receive error: %s" % err)
continue
if not self.running:
break
try:
message = Msgpack.unpack(data)
response_addr, message = self.handleMessage(addr, message)
if message:
self.send(response_addr, message)
except Exception as err:
self.log.error("Handlemessage error: %s" % Debug.formatException(err))
self.log.debug("Stopped listening on port %s" % self.listen_port)
def stop(self):
self.log.debug("Stopping, socket: %s" % self.sock)
self.running = False
if self.sock:
self.sock.close()
def send(self, addr, message):
if type(message) is not list:
message = [message]
for message_part in message:
message_part["sender"] = self.sender_info
self.log.debug("Send to %s: %s" % (addr, message_part["cmd"]))
with closing(socket.socket(socket.AF_INET, socket.SOCK_DGRAM)) as sock:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(Msgpack.pack(message_part), addr)
def getMyIps(self):
return UpnpPunch._get_local_ips()
def broadcast(self, message, port=None):
if not port:
port = self.listen_port
my_ips = self.getMyIps()
addr = ("255.255.255.255", port)
message["sender"] = self.sender_info
self.log.debug("Broadcast using ips %s on port %s: %s" % (my_ips, port, message["cmd"]))
for my_ip in my_ips:
try:
with closing(socket.socket(socket.AF_INET, socket.SOCK_DGRAM)) as sock:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.bind((my_ip, 0))
sock.sendto(Msgpack.pack(message), addr)
except Exception as err:
self.log.warning("Error sending broadcast using ip %s: %s" % (my_ip, err))
def handleMessage(self, addr, message):
self.log.debug("Got from %s: %s" % (addr, message["cmd"]))
cmd = message["cmd"]
params = message.get("params", {})
sender = message["sender"]
sender["ip"] = addr[0]
func_name = "action" + cmd[0].upper() + cmd[1:]
func = getattr(self, func_name, None)
if sender["service"] != "zeronet" or sender["peer_id"] == self.sender_info["peer_id"]:
# Skip messages not for us or sent by us
message = None
elif func:
message = func(sender, params)
else:
self.log.debug("Unknown cmd: %s" % cmd)
message = None
return (sender["ip"], sender["broadcast_port"]), message
================================================
FILE: plugins/AnnounceLocal/Test/TestAnnounce.py
================================================
import time
import copy
import gevent
import pytest
import mock
from AnnounceLocal import AnnounceLocalPlugin
from File import FileServer
from Test import Spy
@pytest.fixture
def announcer(file_server, site):
file_server.sites[site.address] = site
announcer = AnnounceLocalPlugin.LocalAnnouncer(file_server, listen_port=1100)
file_server.local_announcer = announcer
announcer.listen_port = 1100
announcer.sender_info["broadcast_port"] = 1100
announcer.getMyIps = mock.MagicMock(return_value=["127.0.0.1"])
announcer.discover = mock.MagicMock(return_value=False) # Don't send discover requests automatically
gevent.spawn(announcer.start)
time.sleep(0.5)
assert file_server.local_announcer.running
return file_server.local_announcer
@pytest.fixture
def announcer_remote(request, site_temp):
file_server_remote = FileServer("127.0.0.1", 1545)
file_server_remote.sites[site_temp.address] = site_temp
announcer = AnnounceLocalPlugin.LocalAnnouncer(file_server_remote, listen_port=1101)
file_server_remote.local_announcer = announcer
announcer.listen_port = 1101
announcer.sender_info["broadcast_port"] = 1101
announcer.getMyIps = mock.MagicMock(return_value=["127.0.0.1"])
announcer.discover = mock.MagicMock(return_value=False) # Don't send discover requests automatically
gevent.spawn(announcer.start)
time.sleep(0.5)
assert file_server_remote.local_announcer.running
def cleanup():
file_server_remote.stop()
request.addfinalizer(cleanup)
return file_server_remote.local_announcer
@pytest.mark.usefixtures("resetSettings")
@pytest.mark.usefixtures("resetTempSettings")
class TestAnnounce:
def testSenderInfo(self, announcer):
sender_info = announcer.sender_info
assert sender_info["port"] > 0
assert len(sender_info["peer_id"]) == 20
assert sender_info["rev"] > 0
def testIgnoreSelfMessages(self, announcer):
# No response to messages that has same peer_id as server
assert not announcer.handleMessage(("0.0.0.0", 123), {"cmd": "discoverRequest", "sender": announcer.sender_info, "params": {}})[1]
# Response to messages with different peer id
sender_info = copy.copy(announcer.sender_info)
sender_info["peer_id"] += "-"
addr, res = announcer.handleMessage(("0.0.0.0", 123), {"cmd": "discoverRequest", "sender": sender_info, "params": {}})
assert res["params"]["sites_changed"] > 0
def testDiscoverRequest(self, announcer, announcer_remote):
assert len(announcer_remote.known_peers) == 0
with Spy.Spy(announcer_remote, "handleMessage") as responses:
announcer_remote.broadcast({"cmd": "discoverRequest", "params": {}}, port=announcer.listen_port)
time.sleep(0.1)
response_cmds = [response[1]["cmd"] for response in responses]
assert response_cmds == ["discoverResponse", "siteListResponse"]
assert len(responses[-1][1]["params"]["sites"]) == 1
# It should only request siteList if sites_changed value is different from last response
with Spy.Spy(announcer_remote, "handleMessage") as responses:
announcer_remote.broadcast({"cmd": "discoverRequest", "params": {}}, port=announcer.listen_port)
time.sleep(0.1)
response_cmds = [response[1]["cmd"] for response in responses]
assert response_cmds == ["discoverResponse"]
def testPeerDiscover(self, announcer, announcer_remote, site):
assert announcer.server.peer_id != announcer_remote.server.peer_id
assert len(list(announcer.server.sites.values())[0].peers) == 0
announcer.broadcast({"cmd": "discoverRequest"}, port=announcer_remote.listen_port)
time.sleep(0.1)
assert len(list(announcer.server.sites.values())[0].peers) == 1
def testRecentPeerList(self, announcer, announcer_remote, site):
assert len(site.peers_recent) == 0
assert len(site.peers) == 0
with Spy.Spy(announcer, "handleMessage") as responses:
announcer.broadcast({"cmd": "discoverRequest", "params": {}}, port=announcer_remote.listen_port)
time.sleep(0.1)
assert [response[1]["cmd"] for response in responses] == ["discoverResponse", "siteListResponse"]
assert len(site.peers_recent) == 1
assert len(site.peers) == 1
# It should update peer without siteListResponse
last_time_found = list(site.peers.values())[0].time_found
site.peers_recent.clear()
with Spy.Spy(announcer, "handleMessage") as responses:
announcer.broadcast({"cmd": "discoverRequest", "params": {}}, port=announcer_remote.listen_port)
time.sleep(0.1)
assert [response[1]["cmd"] for response in responses] == ["discoverResponse"]
assert len(site.peers_recent) == 1
assert list(site.peers.values())[0].time_found > last_time_found
================================================
FILE: plugins/AnnounceLocal/Test/conftest.py
================================================
from src.Test.conftest import *
from Config import config
config.broadcast_port = 0
================================================
FILE: plugins/AnnounceLocal/Test/pytest.ini
================================================
[pytest]
python_files = Test*.py
addopts = -rsxX -v --durations=6
markers =
webtest: mark a test as a webtest.
================================================
FILE: plugins/AnnounceLocal/__init__.py
================================================
from . import AnnounceLocalPlugin
================================================
FILE: plugins/AnnounceLocal/plugin_info.json
================================================
{
"name": "AnnounceLocal",
"description": "Discover LAN clients using UDP broadcasting.",
"default": "enabled"
}
================================================
FILE: plugins/AnnounceShare/AnnounceSharePlugin.py
================================================
import time
import os
import logging
import json
import atexit
import gevent
from Config import config
from Plugin import PluginManager
from util import helper
class TrackerStorage(object):
def __init__(self):
self.log = logging.getLogger("TrackerStorage")
self.file_path = "%s/trackers.json" % config.data_dir
self.load()
self.time_discover = 0.0
atexit.register(self.save)
def getDefaultFile(self):
return {"shared": {}}
def onTrackerFound(self, tracker_address, type="shared", my=False):
if not tracker_address.startswith("zero://"):
return False
trackers = self.getTrackers()
added = False
if tracker_address not in trackers:
trackers[tracker_address] = {
"time_added": time.time(),
"time_success": 0,
"latency": 99.0,
"num_error": 0,
"my": False
}
self.log.debug("New tracker found: %s" % tracker_address)
added = True
trackers[tracker_address]["time_found"] = time.time()
trackers[tracker_address]["my"] = my
return added
def onTrackerSuccess(self, tracker_address, latency):
trackers = self.getTrackers()
if tracker_address not in trackers:
return False
trackers[tracker_address]["latency"] = latency
trackers[tracker_address]["time_success"] = time.time()
trackers[tracker_address]["num_error"] = 0
def onTrackerError(self, tracker_address):
trackers = self.getTrackers()
if tracker_address not in trackers:
return False
trackers[tracker_address]["time_error"] = time.time()
trackers[tracker_address]["num_error"] += 1
if len(self.getWorkingTrackers()) >= config.working_shared_trackers_limit:
error_limit = 5
else:
error_limit = 30
error_limit
if trackers[tracker_address]["num_error"] > error_limit and trackers[tracker_address]["time_success"] < time.time() - 60 * 60:
self.log.debug("Tracker %s looks down, removing." % tracker_address)
del trackers[tracker_address]
def getTrackers(self, type="shared"):
return self.file_content.setdefault(type, {})
def getWorkingTrackers(self, type="shared"):
trackers = {
key: tracker for key, tracker in self.getTrackers(type).items()
if tracker["time_success"] > time.time() - 60 * 60
}
return trackers
def getFileContent(self):
if not os.path.isfile(self.file_path):
open(self.file_path, "w").write("{}")
return self.getDefaultFile()
try:
return json.load(open(self.file_path))
except Exception as err:
self.log.error("Error loading trackers list: %s" % err)
return self.getDefaultFile()
def load(self):
self.file_content = self.getFileContent()
trackers = self.getTrackers()
self.log.debug("Loaded %s shared trackers" % len(trackers))
for address, tracker in list(trackers.items()):
tracker["num_error"] = 0
if not address.startswith("zero://"):
del trackers[address]
def save(self):
s = time.time()
helper.atomicWrite(self.file_path, json.dumps(self.file_content, indent=2, sort_keys=True).encode("utf8"))
self.log.debug("Saved in %.3fs" % (time.time() - s))
def discoverTrackers(self, peers):
if len(self.getWorkingTrackers()) > config.working_shared_trackers_limit:
return False
s = time.time()
num_success = 0
for peer in peers:
if peer.connection and peer.connection.handshake.get("rev", 0) < 3560:
continue # Not supported
res = peer.request("getTrackers")
if not res or "error" in res:
continue
num_success += 1
for tracker_address in res["trackers"]:
if type(tracker_address) is bytes: # Backward compatibilitys
tracker_address = tracker_address.decode("utf8")
added = self.onTrackerFound(tracker_address)
if added: # Only add one tracker from one source
break
if not num_success and len(peers) < 20:
self.time_discover = 0.0
if num_success:
self.save()
self.log.debug("Trackers discovered from %s/%s peers in %.3fs" % (num_success, len(peers), time.time() - s))
if "tracker_storage" not in locals():
tracker_storage = TrackerStorage()
@PluginManager.registerTo("SiteAnnouncer")
class SiteAnnouncerPlugin(object):
def getTrackers(self):
if tracker_storage.time_discover < time.time() - 5 * 60:
tracker_storage.time_discover = time.time()
gevent.spawn(tracker_storage.discoverTrackers, self.site.getConnectedPeers())
trackers = super(SiteAnnouncerPlugin, self).getTrackers()
shared_trackers = list(tracker_storage.getTrackers("shared").keys())
if shared_trackers:
return trackers + shared_trackers
else:
return trackers
def announceTracker(self, tracker, *args, **kwargs):
res = super(SiteAnnouncerPlugin, self).announceTracker(tracker, *args, **kwargs)
if res:
latency = res
tracker_storage.onTrackerSuccess(tracker, latency)
elif res is False:
tracker_storage.onTrackerError(tracker)
return res
@PluginManager.registerTo("FileRequest")
class FileRequestPlugin(object):
def actionGetTrackers(self, params):
shared_trackers = list(tracker_storage.getWorkingTrackers("shared").keys())
self.response({"trackers": shared_trackers})
@PluginManager.registerTo("FileServer")
class FileServerPlugin(object):
def portCheck(self, *args, **kwargs):
res = super(FileServerPlugin, self).portCheck(*args, **kwargs)
if res and not config.tor == "always" and "Bootstrapper" in PluginManager.plugin_manager.plugin_names:
for ip in self.ip_external_list:
my_tracker_address = "zero://%s:%s" % (ip, config.fileserver_port)
tracker_storage.onTrackerFound(my_tracker_address, my=True)
return res
@PluginManager.registerTo("ConfigPlugin")
class ConfigPlugin(object):
def createArguments(self):
group = self.parser.add_argument_group("AnnounceShare plugin")
group.add_argument('--working_shared_trackers_limit', help='Stop discovering new shared trackers after this number of shared trackers reached', default=5, type=int, metavar='limit')
return super(ConfigPlugin, self).createArguments()
================================================
FILE: plugins/AnnounceShare/Test/TestAnnounceShare.py
================================================
import pytest
from AnnounceShare import AnnounceSharePlugin
from Peer import Peer
from Config import config
@pytest.mark.usefixtures("resetSettings")
@pytest.mark.usefixtures("resetTempSettings")
class TestAnnounceShare:
def testAnnounceList(self, file_server):
open("%s/trackers.json" % config.data_dir, "w").write("{}")
tracker_storage = AnnounceSharePlugin.tracker_storage
tracker_storage.load()
peer = Peer(file_server.ip, 1544, connection_server=file_server)
assert peer.request("getTrackers")["trackers"] == []
tracker_storage.onTrackerFound("zero://%s:15441" % file_server.ip)
assert peer.request("getTrackers")["trackers"] == []
# It needs to have at least one successfull announce to be shared to other peers
tracker_storage.onTrackerSuccess("zero://%s:15441" % file_server.ip, 1.0)
assert peer.request("getTrackers")["trackers"] == ["zero://%s:15441" % file_server.ip]
================================================
FILE: plugins/AnnounceShare/Test/conftest.py
================================================
from src.Test.conftest import *
from Config import config
================================================
FILE: plugins/AnnounceShare/Test/pytest.ini
================================================
[pytest]
python_files = Test*.py
addopts = -rsxX -v --durations=6
markers =
webtest: mark a test as a webtest.
================================================
FILE: plugins/AnnounceShare/__init__.py
================================================
from . import AnnounceSharePlugin
================================================
FILE: plugins/AnnounceShare/plugin_info.json
================================================
{
"name": "AnnounceShare",
"description": "Share possible trackers between clients.",
"default": "enabled"
}
================================================
FILE: plugins/AnnounceZero/AnnounceZeroPlugin.py
================================================
import time
import itertools
from Plugin import PluginManager
from util import helper
from Crypt import CryptRsa
allow_reload = False # No source reload supported in this plugin
time_full_announced = {} # Tracker address: Last announced all site to tracker
connection_pool = {} # Tracker address: Peer object
# We can only import plugin host clases after the plugins are loaded
@PluginManager.afterLoad
def importHostClasses():
global Peer, AnnounceError
from Peer import Peer
from Site.SiteAnnouncer import AnnounceError
# Process result got back from tracker
def processPeerRes(tracker_address, site, peers):
added = 0
# Onion
found_onion = 0
for packed_address in peers["onion"]:
found_onion += 1
peer_onion, peer_port = helper.unpackOnionAddress(packed_address)
if site.addPeer(peer_onion, peer_port, source="tracker"):
added += 1
# Ip4
found_ipv4 = 0
peers_normal = itertools.chain(peers.get("ip4", []), peers.get("ipv4", []), peers.get("ipv6", []))
for packed_address in peers_normal:
found_ipv4 += 1
peer_ip, peer_port = helper.unpackAddress(packed_address)
if site.addPeer(peer_ip, peer_port, source="tracker"):
added += 1
if added:
site.worker_manager.onPeers()
site.updateWebsocket(peers_added=added)
return added
@PluginManager.registerTo("SiteAnnouncer")
class SiteAnnouncerPlugin(object):
def getTrackerHandler(self, protocol):
if protocol == "zero":
return self.announceTrackerZero
else:
return super(SiteAnnouncerPlugin, self).getTrackerHandler(protocol)
def announceTrackerZero(self, tracker_address, mode="start", num_want=10):
global time_full_announced
s = time.time()
need_types = ["ip4"] # ip4 for backward compatibility reasons
need_types += self.site.connection_server.supported_ip_types
if self.site.connection_server.tor_manager.enabled:
need_types.append("onion")
if mode == "start" or mode == "more": # Single: Announce only this site
sites = [self.site]
full_announce = False
else: # Multi: Announce all currently serving site
full_announce = True
if time.time() - time_full_announced.get(tracker_address, 0) < 60 * 15: # No reannounce all sites within short time
return None
time_full_announced[tracker_address] = time.time()
from Site import SiteManager
sites = [site for site in SiteManager.site_manager.sites.values() if site.isServing()]
# Create request
add_types = self.getOpenedServiceTypes()
request = {
"hashes": [], "onions": [], "port": self.fileserver_port, "need_types": need_types, "need_num": 20, "add": add_types
}
for site in sites:
if "onion" in add_types:
onion = self.site.connection_server.tor_manager.getOnion(site.address)
request["onions"].append(onion)
request["hashes"].append(site.address_hash)
# Tracker can remove sites that we don't announce
if full_announce:
request["delete"] = True
# Sent request to tracker
tracker_peer = connection_pool.get(tracker_address) # Re-use tracker connection if possible
if not tracker_peer:
tracker_ip, tracker_port = tracker_address.rsplit(":", 1)
tracker_peer = Peer(str(tracker_ip), int(tracker_port), connection_server=self.site.connection_server)
tracker_peer.is_tracker_connection = True
connection_pool[tracker_address] = tracker_peer
res = tracker_peer.request("announce", request)
if not res or "peers" not in res:
if full_announce:
time_full_announced[tracker_address] = 0
raise AnnounceError("Invalid response: %s" % res)
# Add peers from response to site
site_index = 0
peers_added = 0
for site_res in res["peers"]:
site = sites[site_index]
peers_added += processPeerRes(tracker_address, site, site_res)
site_index += 1
# Check if we need to sign prove the onion addresses
if "onion_sign_this" in res:
self.site.log.debug("Signing %s for %s to add %s onions" % (res["onion_sign_this"], tracker_address, len(sites)))
request["onion_signs"] = {}
request["onion_sign_this"] = res["onion_sign_this"]
request["need_num"] = 0
for site in sites:
onion = self.site.connection_server.tor_manager.getOnion(site.address)
publickey = self.site.connection_server.tor_manager.getPublickey(onion)
if publickey not in request["onion_signs"]:
sign = CryptRsa.sign(res["onion_sign_this"].encode("utf8"), self.site.connection_server.tor_manager.getPrivatekey(onion))
request["onion_signs"][publickey] = sign
res = tracker_peer.request("announce", request)
if not res or "onion_sign_this" in res:
if full_announce:
time_full_announced[tracker_address] = 0
raise AnnounceError("Announce onion address to failed: %s" % res)
if full_announce:
tracker_peer.remove() # Close connection, we don't need it in next 5 minute
self.site.log.debug(
"Tracker announce result: zero://%s (sites: %s, new peers: %s, add: %s, mode: %s) in %.3fs" %
(tracker_address, site_index, peers_added, add_types, mode, time.time() - s)
)
return True
================================================
FILE: plugins/AnnounceZero/__init__.py
================================================
from . import AnnounceZeroPlugin
================================================
FILE: plugins/AnnounceZero/plugin_info.json
================================================
{
"name": "AnnounceZero",
"description": "Announce using ZeroNet protocol.",
"default": "enabled"
}
================================================
FILE: plugins/Benchmark/BenchmarkDb.py
================================================
import os
import json
import contextlib
import time
from Plugin import PluginManager
from Config import config
@PluginManager.registerTo("Actions")
class ActionsPlugin:
def getBenchmarkTests(self, online=False):
tests = super().getBenchmarkTests(online)
tests.extend([
{"func": self.testDbConnect, "num": 10, "time_standard": 0.27},
{"func": self.testDbInsert, "num": 10, "time_standard": 0.91},
{"func": self.testDbInsertMultiuser, "num": 1, "time_standard": 0.57},
{"func": self.testDbQueryIndexed, "num": 1000, "time_standard": 0.84},
{"func": self.testDbQueryNotIndexed, "num": 1000, "time_standard": 1.30}
])
return tests
@contextlib.contextmanager
def getTestDb(self):
from Db import Db
path = "%s/benchmark.db" % config.data_dir
if os.path.isfile(path):
os.unlink(path)
schema = {
"db_name": "TestDb",
"db_file": path,
"maps": {
".*": {
"to_table": {
"test": "test"
}
}
},
"tables": {
"test": {
"cols": [
["test_id", "INTEGER"],
["title", "TEXT"],
["json_id", "INTEGER REFERENCES json (json_id)"]
],
"indexes": ["CREATE UNIQUE INDEX test_key ON test(test_id, json_id)"],
"schema_changed": 1426195822
}
}
}
db = Db.Db(schema, path)
yield db
db.close()
if os.path.isfile(path):
os.unlink(path)
def testDbConnect(self, num_run=1):
import sqlite3
for i in range(num_run):
with self.getTestDb() as db:
db.checkTables()
yield "."
yield "(SQLite version: %s, API: %s)" % (sqlite3.sqlite_version, sqlite3.version)
def testDbInsert(self, num_run=1):
yield "x 1000 lines "
for u in range(num_run):
with self.getTestDb() as db:
db.checkTables()
data = {"test": []}
for i in range(1000): # 1000 line of data
data["test"].append({"test_id": i, "title": "Testdata for %s message %s" % (u, i)})
json.dump(data, open("%s/test_%s.json" % (config.data_dir, u), "w"))
db.updateJson("%s/test_%s.json" % (config.data_dir, u))
os.unlink("%s/test_%s.json" % (config.data_dir, u))
assert db.execute("SELECT COUNT(*) FROM test").fetchone()[0] == 1000
yield "."
def fillTestDb(self, db):
db.checkTables()
cur = db.getCursor()
cur.logging = False
for u in range(100, 200): # 100 user
data = {"test": []}
for i in range(100): # 1000 line of data
data["test"].append({"test_id": i, "title": "Testdata for %s message %s" % (u, i)})
json.dump(data, open("%s/test_%s.json" % (config.data_dir, u), "w"))
db.updateJson("%s/test_%s.json" % (config.data_dir, u), cur=cur)
os.unlink("%s/test_%s.json" % (config.data_dir, u))
if u % 10 == 0:
yield "."
def testDbInsertMultiuser(self, num_run=1):
yield "x 100 users x 100 lines "
for u in range(num_run):
with self.getTestDb() as db:
for progress in self.fillTestDb(db):
yield progress
num_rows = db.execute("SELECT COUNT(*) FROM test").fetchone()[0]
assert num_rows == 10000, "%s != 10000" % num_rows
def testDbQueryIndexed(self, num_run=1):
s = time.time()
with self.getTestDb() as db:
for progress in self.fillTestDb(db):
pass
yield " (Db warmup done in %.3fs) " % (time.time() - s)
found_total = 0
for i in range(num_run): # 1000x by test_id
found = 0
res = db.execute("SELECT * FROM test WHERE test_id = %s" % (i % 100))
for row in res:
found_total += 1
found += 1
del(res)
yield "."
assert found == 100, "%s != 100 (i: %s)" % (found, i)
yield "Found: %s" % found_total
def testDbQueryNotIndexed(self, num_run=1):
s = time.time()
with self.getTestDb() as db:
for progress in self.fillTestDb(db):
pass
yield " (Db warmup done in %.3fs) " % (time.time() - s)
found_total = 0
for i in range(num_run): # 1000x by test_id
found = 0
res = db.execute("SELECT * FROM test WHERE json_id = %s" % i)
for row in res:
found_total += 1
found += 1
yield "."
del(res)
if i == 0 or i > 100:
assert found == 0, "%s != 0 (i: %s)" % (found, i)
else:
assert found == 100, "%s != 100 (i: %s)" % (found, i)
yield "Found: %s" % found_total
================================================
FILE: plugins/Benchmark/BenchmarkPack.py
================================================
import os
import io
from collections import OrderedDict
from Plugin import PluginManager
from Config import config
from util import Msgpack
@PluginManager.registerTo("Actions")
class ActionsPlugin:
def createZipFile(self, path):
import zipfile
test_data = b"Test" * 1024
file_name = b"\xc3\x81rv\xc3\xadzt\xc5\xb1r\xc5\x91%s.txt".decode("utf8")
with zipfile.ZipFile(path, 'w') as archive:
for y in range(100):
zip_info = zipfile.ZipInfo(file_name % y, (1980, 1, 1, 0, 0, 0))
zip_info.compress_type = zipfile.ZIP_DEFLATED
zip_info.create_system = 3
zip_info.flag_bits = 0
zip_info.external_attr = 25165824
archive.writestr(zip_info, test_data)
def testPackZip(self, num_run=1):
"""
Test zip file creating
"""
yield "x 100 x 5KB "
from Crypt import CryptHash
zip_path = '%s/test.zip' % config.data_dir
for i in range(num_run):
self.createZipFile(zip_path)
yield "."
archive_size = os.path.getsize(zip_path) / 1024
yield "(Generated file size: %.2fkB)" % archive_size
hash = CryptHash.sha512sum(open(zip_path, "rb"))
valid = "cb32fb43783a1c06a2170a6bc5bb228a032b67ff7a1fd7a5efb9b467b400f553"
assert hash == valid, "Invalid hash: %s != %s<br>" % (hash, valid)
os.unlink(zip_path)
def testUnpackZip(self, num_run=1):
"""
Test zip file reading
"""
yield "x 100 x 5KB "
import zipfile
zip_path = '%s/test.zip' % config.data_dir
test_data = b"Test" * 1024
file_name = b"\xc3\x81rv\xc3\xadzt\xc5\xb1r\xc5\x91".decode("utf8")
self.createZipFile(zip_path)
for i in range(num_run):
with zipfile.ZipFile(zip_path) as archive:
for f in archive.filelist:
assert f.filename.startswith(file_name), "Invalid filename: %s != %s" % (f.filename, file_name)
data = archive.open(f.filename).read()
assert archive.open(f.filename).read() == test_data, "Invalid data: %s..." % data[0:30]
yield "."
os.unlink(zip_path)
def createArchiveFile(self, path, archive_type="gz"):
import tarfile
import gzip
# Monkey patch _init_write_gz to use fixed date in order to keep the hash independent from datetime
def nodate_write_gzip_header(self):
self._write_mtime = 0
original_write_gzip_header(self)
test_data_io = io.BytesIO(b"Test" * 1024)
file_name = b"\xc3\x81rv\xc3\xadzt\xc5\xb1r\xc5\x91%s.txt".decode("utf8")
original_write_gzip_header = gzip.GzipFile._write_gzip_header
gzip.GzipFile._write_gzip_header = nodate_write_gzip_header
with tarfile.open(path, 'w:%s' % archive_type) as archive:
for y in range(100):
test_data_io.seek(0)
tar_info = tarfile.TarInfo(file_name % y)
tar_info.size = 4 * 1024
archive.addfile(tar_info, test_data_io)
def testPackArchive(self, num_run=1, archive_type="gz"):
"""
Test creating tar archive files
"""
yield "x 100 x 5KB "
from Crypt import CryptHash
hash_valid_db = {
"gz": "92caec5121a31709cbbc8c11b0939758e670b055bbbe84f9beb3e781dfde710f",
"bz2": "b613f41e6ee947c8b9b589d3e8fa66f3e28f63be23f4faf015e2f01b5c0b032d",
"xz": "ae43892581d770959c8d993daffab25fd74490b7cf9fafc7aaee746f69895bcb",
}
archive_path = '%s/test.tar.%s' % (config.data_dir, archive_type)
for i in range(num_run):
self.createArchiveFile(archive_path, archive_type=archive_type)
yield "."
archive_size = os.path.getsize(archive_path) / 1024
yield "(Generated file size: %.2fkB)" % archive_size
hash = CryptHash.sha512sum(open("%s/test.tar.%s" % (config.data_dir, archive_type), "rb"))
valid = hash_valid_db[archive_type]
assert hash == valid, "Invalid hash: %s != %s<br>" % (hash, valid)
if os.path.isfile(archive_path):
os.unlink(archive_path)
def testUnpackArchive(self, num_run=1, archive_type="gz"):
"""
Test reading tar archive files
"""
yield "x 100 x 5KB "
import tarfile
test_data = b"Test" * 1024
file_name = b"\xc3\x81rv\xc3\xadzt\xc5\xb1r\xc5\x91%s.txt".decode("utf8")
archive_path = '%s/test.tar.%s' % (config.data_dir, archive_type)
self.createArchiveFile(archive_path, archive_type=archive_type)
for i in range(num_run):
with tarfile.open(archive_path, 'r:%s' % archive_type) as archive:
for y in range(100):
assert archive.extractfile(file_name % y).read() == test_data
yield "."
if os.path.isfile(archive_path):
os.unlink(archive_path)
def testPackMsgpack(self, num_run=1):
"""
Test msgpack encoding
"""
yield "x 100 x 5KB "
binary = b'fqv\xf0\x1a"e\x10,\xbe\x9cT\x9e(\xa5]u\x072C\x8c\x15\xa2\xa8\x93Sw)\x19\x02\xdd\t\xfb\xf67\x88\xd9\xee\x86\xa1\xe4\xb6,\xc6\x14\xbb\xd7$z\x1d\xb2\xda\x85\xf5\xa0\x97^\x01*\xaf\xd3\xb0!\xb7\x9d\xea\x89\xbbh8\xa1"\xa7]e(@\xa2\xa5g\xb7[\xae\x8eE\xc2\x9fL\xb6s\x19\x19\r\xc8\x04S\xd0N\xe4]?/\x01\xea\xf6\xec\xd1\xb3\xc2\x91\x86\xd7\xf4K\xdf\xc2lV\xf4\xe8\x80\xfc\x8ep\xbb\x82\xb3\x86\x98F\x1c\xecS\xc8\x15\xcf\xdc\xf1\xed\xfc\xd8\x18r\xf9\x80\x0f\xfa\x8cO\x97(\x0b]\xf1\xdd\r\xe7\xbf\xed\x06\xbd\x1b?\xc5\xa0\xd7a\x82\xf3\xa8\xe6@\xf3\ri\xa1\xb10\xf6\xd4W\xbc\x86\x1a\xbb\xfd\x94!bS\xdb\xaeM\x92\x00#\x0b\xf7\xad\xe9\xc2\x8e\x86\xbfi![%\xd31]\xc6\xfc2\xc9\xda\xc6v\x82P\xcc\xa9\xea\xb9\xff\xf6\xc8\x17iD\xcf\xf3\xeeI\x04\xe9\xa1\x19\xbb\x01\x92\xf5nn4K\xf8\xbb\xc6\x17e>\xa7 \xbbv'
data = OrderedDict(
sorted({"int": 1024 * 1024 * 1024, "float": 12345.67890, "text": "hello" * 1024, "binary": binary}.items())
)
data_packed_valid = b'\x84\xa6binary\xc5\x01\x00fqv\xf0\x1a"e\x10,\xbe\x9cT\x9e(\xa5]u\x072C\x8c\x15\xa2\xa8\x93Sw)\x19\x02\xdd\t\xfb\xf67\x88\xd9\xee\x86\xa1\xe4\xb6,\xc6\x14\xbb\xd7$z\x1d\xb2\xda\x85\xf5\xa0\x97^\x01*\xaf\xd3\xb0!\xb7\x9d\xea\x89\xbbh8\xa1"\xa7]e(@\xa2\xa5g\xb7[\xae\x8eE\xc2\x9fL\xb6s\x19\x19\r\xc8\x04S\xd0N\xe4]?/\x01\xea\xf6\xec\xd1\xb3\xc2\x91\x86\xd7\xf4K\xdf\xc2lV\xf4\xe8\x80\xfc\x8ep\xbb\x82\xb3\x86\x98F\x1c\xecS\xc8\x15\xcf\xdc\xf1\xed\xfc\xd8\x18r\xf9\x80\x0f\xfa\x8cO\x97(\x0b]\xf1\xdd\r\xe7\xbf\xed\x06\xbd\x1b?\xc5\xa0\xd7a\x82\xf3\xa8\xe6@\xf3\ri\xa1\xb10\xf6\xd4W\xbc\x86\x1a\xbb\xfd\x94!bS\xdb\xaeM\x92\x00#\x0b\xf7\xad\xe9\xc2\x8e\x86\xbfi![%\xd31]\xc6\xfc2\xc9\xda\xc6v\x82P\xcc\xa9\xea\xb9\xff\xf6\xc8\x17iD\xcf\xf3\xeeI\x04\xe9\xa1\x19\xbb\x01\x92\xf5nn4K\xf8\xbb\xc6\x17e>\xa7 \xbbv\xa5float\xcb@\xc8\x1c\xd6\xe61\xf8\xa1\xa3int\xce@\x00\x00\x00\xa4text\xda\x14\x00'
data_packed_valid += b'hello' * 1024
for y in range(num_run):
for i in range(100):
data_packed = Msgpack.pack(data)
yield "."
assert data_packed == data_packed_valid, "%s<br>!=<br>%s" % (repr(data_packed), repr(data_packed_valid))
def testUnpackMsgpack(self, num_run=1):
"""
Test msgpack decoding
"""
yield "x 5KB "
binary = b'fqv\xf0\x1a"e\x10,\xbe\x9cT\x9e(\xa5]u\x072C\x8c\x15\xa2\xa8\x93Sw)\x19\x02\xdd\t\xfb\xf67\x88\xd9\xee\x86\xa1\xe4\xb6,\xc6\x14\xbb\xd7$z\x1d\xb2\xda\x85\xf5\xa0\x97^\x01*\xaf\xd3\xb0!\xb7\x9d\xea\x89\xbbh8\xa1"\xa7]e(@\xa2\xa5g\xb7[\xae\x8eE\xc2\x9fL\xb6s\x19\x19\r\xc8\x04S\xd0N\xe4]?/\x01\xea\xf6\xec\xd1\xb3\xc2\x91\x86\xd7\xf4K\xdf\xc2lV\xf4\xe8\x80\xfc\x8ep\xbb\x82\xb3\x86\x98F\x1c\xecS\xc8\x15\xcf\xdc\xf1\xed\xfc\xd8\x18r\xf9\x80\x0f\xfa\x8cO\x97(\x0b]\xf1\xdd\r\xe7\xbf\xed\x06\xbd\x1b?\xc5\xa0\xd7a\x82\xf3\xa8\xe6@\xf3\ri\xa1\xb10\xf6\xd4W\xbc\x86\x1a\xbb\xfd\x94!bS\xdb\xaeM\x92\x00#\x0b\xf7\xad\xe9\xc2\x8e\x86\xbfi![%\xd31]\xc6\xfc2\xc9\xda\xc6v\x82P\xcc\xa9\xea\xb9\xff\xf6\xc8\x17iD\xcf\xf3\xeeI\x04\xe9\xa1\x19\xbb\x01\x92\xf5nn4K\xf8\xbb\xc6\x17e>\xa7 \xbbv'
data = OrderedDict(
sorted({"int": 1024 * 1024 * 1024, "float": 12345.67890, "text": "hello" * 1024, "binary": binary}.items())
)
data_packed = b'\x84\xa6binary\xc5\x01\x00fqv\xf0\x1a"e\x10,\xbe\x9cT\x9e(\xa5]u\x072C\x8c\x15\xa2\xa8\x93Sw)\x19\x02\xdd\t\xfb\xf67\x88\xd9\xee\x86\xa1\xe4\xb6,\xc6\x14\xbb\xd7$z\x1d\xb2\xda\x85\xf5\xa0\x97^\x01*\xaf\xd3\xb0!\xb7\x9d\xea\x89\xbbh8\xa1"\xa7]e(@\xa2\xa5g\xb7[\xae\x8eE\xc2\x9fL\xb6s\x19\x19\r\xc8\x04S\xd0N\xe4]?/\x01\xea\xf6\xec\xd1\xb3\xc2\x91\x86\xd7\xf4K\xdf\xc2lV\xf4\xe8\x80\xfc\x8ep\xbb\x82\xb3\x86\x98F\x1c\xecS\xc8\x15\xcf\xdc\xf1\xed\xfc\xd8\x18r\xf9\x80\x0f\xfa\x8cO\x97(\x0b]\xf1\xdd\r\xe7\xbf\xed\x06\xbd\x1b?\xc5\xa0\xd7a\x82\xf3\xa8\xe6@\xf3\ri\xa1\xb10\xf6\xd4W\xbc\x86\x1a\xbb\xfd\x94!bS\xdb\xaeM\x92\x00#\x0b\xf7\xad\xe9\xc2\x8e\x86\xbfi![%\xd31]\xc6\xfc2\xc9\xda\xc6v\x82P\xcc\xa9\xea\xb9\xff\xf6\xc8\x17iD\xcf\xf3\xeeI\x04\xe9\xa1\x19\xbb\x01\x92\xf5nn4K\xf8\xbb\xc6\x17e>\xa7 \xbbv\xa5float\xcb@\xc8\x1c\xd6\xe61\xf8\xa1\xa3int\xce@\x00\x00\x00\xa4text\xda\x14\x00'
data_packed += b'hello' * 1024
for y in range(num_run):
data_unpacked = Msgpack.unpack(data_packed, decode=False)
yield "."
assert data_unpacked == data, "%s<br>!=<br>%s" % (data_unpacked, data)
def testUnpackMsgpackStreaming(self, num_run=1, fallback=False):
"""
Test streaming msgpack decoding
"""
yield "x 1000 x 5KB "
binary = b'fqv\xf0\x1a"e\x10,\xbe\x9cT\x9e(\xa5]u\x072C\x8c\x15\xa2\xa8\x93Sw)\x19\x02\xdd\t\xfb\xf67\x88\xd9\xee\x86\xa1\xe4\xb6,\xc6\x14\xbb\xd7$z\x1d\xb2\xda\x85\xf5\xa0\x97^\x01*\xaf\xd3\xb0!\xb7\x9d\xea\x89\xbbh8\xa1"\xa7]e(@\xa2\xa5g\xb7[\xae\x8eE\xc2\x9fL\xb6s\x19\x19\r\xc8\x04S\xd0N\xe4]?/\x01\xea\xf6\xec\xd1\xb3\xc2\x91\x86\xd7\xf4K\xdf\xc2lV\xf4\xe8\x80\xfc\x8ep\xbb\x82\xb3\x86\x98F\x1c\xecS\xc8\x15\xcf\xdc\xf1\xed\xfc\xd8\x18r\xf9\x80\x0f\xfa\x8cO\x97(\x0b]\xf1\xdd\r\xe7\xbf\xed\x06\xbd\x1b?\xc5\xa0\xd7a\x82\xf3\xa8\xe6@\xf3\ri\xa1\xb10\xf6\xd4W\xbc\x86\x1a\xbb\xfd\x94!bS\xdb\xaeM\x92\x00#\x0b\xf7\xad\xe9\xc2\x8e\x86\xbfi![%\xd31]\xc6\xfc2\xc9\xda\xc6v\x82P\xcc\xa9\xea\xb9\xff\xf6\xc8\x17iD\xcf\xf3\xeeI\x04\xe9\xa1\x19\xbb\x01\x92\xf5nn4K\xf8\xbb\xc6\x17e>\xa7 \xbbv'
data = OrderedDict(
sorted({"int": 1024 * 1024 * 1024, "float": 12345.67890, "text": "hello" * 1024, "binary": binary}.items())
)
data_packed = b'\x84\xa6binary\xc5\x01\x00fqv\xf0\x1a"e\x10,\xbe\x9cT\x9e(\xa5]u\x072C\x8c\x15\xa2\xa8\x93Sw)\x19\x02\xdd\t\xfb\xf67\x88\xd9\xee\x86\xa1\xe4\xb6,\xc6\x14\xbb\xd7$z\x1d\xb2\xda\x85\xf5\xa0\x97^\x01*\xaf\xd3\xb0!\xb7\x9d\xea\x89\xbbh8\xa1"\xa7]e(@\xa2\xa5g\xb7[\xae\x8eE\xc2\x9fL\xb6s\x19\x19\r\xc8\x04S\xd0N\xe4]?/\x01\xea\xf6\xec\xd1\xb3\xc2\x91\x86\xd7\xf4K\xdf\xc2lV\xf4\xe8\x80\xfc\x8ep\xbb\x82\xb3\x86\x98F\x1c\xecS\xc8\x15\xcf\xdc\xf1\xed\xfc\xd8\x18r\xf9\x80\x0f\xfa\x8cO\x97(\x0b]\xf1\xdd\r\xe7\xbf\xed\x06\xbd\x1b?\xc5\xa0\xd7a\x82\xf3\xa8\xe6@\xf3\ri\xa1\xb10\xf6\xd4W\xbc\x86\x1a\xbb\xfd\x94!bS\xdb\xaeM\x92\x00#\x0b\xf7\xad\xe9\xc2\x8e\x86\xbfi![%\xd31]\xc6\xfc2\xc9\xda\xc6v\x82P\xcc\xa9\xea\xb9\xff\xf6\xc8\x17iD\xcf\xf3\xeeI\x04\xe9\xa1\x19\xbb\x01\x92\xf5nn4K\xf8\xbb\xc6\x17e>\xa7 \xbbv\xa5float\xcb@\xc8\x1c\xd6\xe61\xf8\xa1\xa3int\xce@\x00\x00\x00\xa4text\xda\x14\x00'
data_packed += b'hello' * 1024
for i in range(num_run):
unpacker = Msgpack.getUnpacker(decode=False, fallback=fallback)
for y in range(1000):
unpacker.feed(data_packed)
for data_unpacked in unpacker:
pass
yield "."
assert data == data_unpacked, "%s != %s" % (data_unpacked, data)
================================================
FILE: plugins/Benchmark/BenchmarkPlugin.py
================================================
import os
import time
import io
import math
import hashlib
import re
import sys
from Config import config
from Crypt import CryptHash
from Plugin import PluginManager
from Debug import Debug
from util import helper
plugin_dir = os.path.dirname(__file__)
benchmark_key = None
@PluginManager.registerTo("UiRequest")
class UiRequestPlugin(object):
@helper.encodeResponse
def actionBenchmark(self):
global benchmark_key
script_nonce = self.getScriptNonce()
if not benchmark_key:
benchmark_key = CryptHash.random(encoding="base64")
self.sendHeader(script_nonce=script_nonce)
if "Multiuser" in PluginManager.plugin_manager.plugin_names and not config.multiuser_local:
yield "This function is disabled on this proxy"
return
data = self.render(
plugin_dir + "/media/benchmark.html",
script_nonce=script_nonce,
benchmark_key=benchmark_key,
filter=re.sub("[^A-Za-z0-9]", "", self.get.get("filter", ""))
)
yield data
@helper.encodeResponse
def actionBenchmarkResult(self):
global benchmark_key
if self.get.get("benchmark_key", "") != benchmark_key:
return self.error403("Invalid benchmark key")
self.sendHeader(content_type="text/plain", noscript=True)
if "Multiuser" in PluginManager.plugin_manager.plugin_names and not config.multiuser_local:
yield "This function is disabled on this proxy"
return
yield " " * 1024 # Head (required for streaming)
import main
s = time.time()
for part in main.actions.testBenchmark(filter=self.get.get("filter", "")):
yield part
yield "\n - Total time: %.3fs" % (time.time() - s)
@PluginManager.registerTo("Actions")
class ActionsPlugin:
def getMultiplerTitle(self, multipler):
if multipler < 0.3:
multipler_title = "Sloooow"
elif multipler < 0.6:
multipler_title = "Ehh"
elif multipler < 0.8:
multipler_title = "Goodish"
elif multipler < 1.2:
multipler_title = "OK"
elif multipler < 1.7:
multipler_title = "Fine"
elif multipler < 2.5:
multipler_title = "Fast"
elif multipler < 3.5:
multipler_title = "WOW"
else:
multipler_title = "Insane!!"
return multipler_title
def formatResult(self, taken, standard):
if not standard:
return " Done in %.3fs" % taken
if taken > 0:
multipler = standard / taken
else:
multipler = 99
multipler_title = self.getMultiplerTitle(multipler)
return " Done in %.3fs = %s (%.2fx)" % (taken, multipler_title, multipler)
def getBenchmarkTests(self, online=False):
if hasattr(super(), "getBenchmarkTests"):
tests = super().getBenchmarkTests(online)
else:
tests = []
tests.extend([
{"func": self.testHdPrivatekey, "num": 50, "time_standard": 0.57},
{"func": self.testSign, "num": 20, "time_standard": 0.46},
{"func": self.testVerify, "kwargs": {"lib_verify": "sslcrypto_fallback"}, "num": 20, "time_standard": 0.38},
{"func": self.testVerify, "kwargs": {"lib_verify": "sslcrypto"}, "num": 200, "time_standard": 0.30},
{"func": self.testVerify, "kwargs": {"lib_verify": "libsecp256k1"}, "num": 200, "time_standard": 0.10},
{"func": self.testPackMsgpack, "num": 100, "time_standard": 0.35},
{"func": self.testUnpackMsgpackStreaming, "kwargs": {"fallback": False}, "num": 100, "time_standard": 0.35},
{"func": self.testUnpackMsgpackStreaming, "kwargs": {"fallback": True}, "num": 10, "time_standard": 0.5},
{"func": self.testPackZip, "num": 5, "time_standard": 0.065},
{"func": self.testPackArchive, "kwargs": {"archive_type": "gz"}, "num": 5, "time_standard": 0.08},
{"func": self.testPackArchive, "kwargs": {"archive_type": "bz2"}, "num": 5, "time_standard": 0.68},
{"func": self.testPackArchive, "kwargs": {"archive_type": "xz"}, "num": 5, "time_standard": 0.47},
{"func": self.testUnpackZip, "num": 20, "time_standard": 0.25},
{"func": self.testUnpackArchive, "kwargs": {"archive_type": "gz"}, "num": 20, "time_standard": 0.28},
{"func": self.testUnpackArchive, "kwargs": {"archive_type": "bz2"}, "num": 20, "time_standard": 0.83},
{"func": self.testUnpackArchive, "kwargs": {"archive_type": "xz"}, "num": 20, "time_standard": 0.38},
{"func": self.testCryptHash, "kwargs": {"hash_type": "sha256"}, "num": 10, "time_standard": 0.50},
{"func": self.testCryptHash, "kwargs": {"hash_type": "sha512"}, "num": 10, "time_standard": 0.33},
{"func": self.testCryptHashlib, "kwargs": {"hash_type": "sha3_256"}, "num": 10, "time_standard": 0.33},
{"func": self.testCryptHashlib, "kwargs": {"hash_type": "sha3_512"}, "num": 10, "time_standard": 0.65},
{"func": self.testRandom, "num": 100, "time_standard": 0.08},
])
if online:
tests += [
{"func": self.testHttps, "num": 1, "time_standard": 2.1}
]
return tests
def testBenchmark(self, num_multipler=1, online=False, num_run=None, filter=None):
"""
Run benchmark on client functions
"""
tests = self.getBenchmarkTests(online=online)
if filter:
tests = [test for test in tests[:] if filter.lower() in test["func"].__name__.lower()]
yield "\n"
res = {}
res_time_taken = {}
multiplers = []
for test in tests:
s = time.time()
if num_run:
num_run_test = num_run
else:
num_run_test = math.ceil(test["num"] * num_multipler)
func = test["func"]
func_name = func.__name__
kwargs = test.get("kwargs", {})
key = "%s %s" % (func_name, kwargs)
if kwargs:
yield "* Running %s (%s) x %s " % (func_name, kwargs, num_run_test)
else:
yield "* Running %s x %s " % (func_name, num_run_test)
i = 0
try:
for progress in func(num_run_test, **kwargs):
i += 1
if num_run_test > 10:
should_print = i % (num_run_test / 10) == 0 or progress != "."
else:
should_print = True
if should_print:
if num_run_test == 1 and progress == ".":
progress = "..."
yield progress
time_taken = time.time() - s
if num_run:
time_standard = 0
else:
time_standard = test["time_standard"] * num_multipler
yield self.formatResult(time_taken, time_standard)
yield "\n"
res[key] = "ok"
res_time_taken[key] = time_taken
multiplers.append(time_standard / max(time_taken, 0.001))
except Exception as err:
res[key] = err
yield "Failed!\n! Error: %s\n\n" % Debug.formatException(err)
yield "\n== Result ==\n"
# Check verification speed
if "testVerify {'lib_verify': 'sslcrypto'}" in res_time_taken:
speed_order = ["sslcrypto_fallback", "sslcrypto", "libsecp256k1"]
time_taken = {}
for lib_verify in speed_order:
time_taken[lib_verify] = res_time_taken["testVerify {'lib_verify': '%s'}" % lib_verify]
time_taken["sslcrypto_fallback"] *= 10 # fallback benchmark only run 20 times instead of 200
speedup_sslcrypto = time_taken["sslcrypto_fallback"] / time_taken["sslcrypto"]
speedup_libsecp256k1 = time_taken["sslcrypto_fallback"] / time_taken["libsecp256k1"]
yield "\n* Verification speedup:\n"
yield " - OpenSSL: %.1fx (reference: 7.0x)\n" % speedup_sslcrypto
yield " - libsecp256k1: %.1fx (reference: 23.8x)\n" % speedup_libsecp256k1
if speedup_sslcrypto < 2:
res["Verification speed"] = "error: OpenSSL speedup low: %.1fx" % speedup_sslcrypto
if speedup_libsecp256k1 < speedup_sslcrypto:
res["Verification speed"] = "error: libsecp256k1 speedup low: %.1fx" % speedup_libsecp256k1
if not res:
yield "! No tests found"
if config.action == "test":
sys.exit(1)
else:
num_failed = len([res_key for res_key, res_val in res.items() if res_val != "ok"])
num_success = len([res_key for res_key, res_val in res.items() if res_val == "ok"])
yield "\n* Tests:\n"
yield " - Total: %s tests\n" % len(res)
yield " - Success: %s tests\n" % num_success
yield " - Failed: %s tests\n" % num_failed
if any(multiplers):
multipler_avg = sum(multiplers) / len(multiplers)
multipler_title = self.getMultiplerTitle(multipler_avg)
yield " - Average speed factor: %.2fx (%s)\n" % (multipler_avg, multipler_title)
# Display errors
for res_key, res_val in res.items():
if res_val != "ok":
yield " ! %s %s\n" % (res_key, res_val)
if num_failed != 0 and config.action == "test":
sys.exit(1)
def testHttps(self, num_run=1):
"""
Test https connection with valid and invalid certs
"""
import urllib.request
import urllib.error
body = urllib.request.urlopen("https://google.com").read()
assert len(body) > 100
yield "."
badssl_urls = [
"https://expired.badssl.com/",
"https://wrong.host.badssl.com/",
"https://self-signed.badssl.com/",
"https://untrusted-root.badssl.com/"
]
for badssl_url in badssl_urls:
try:
body = urllib.request.urlopen(badssl_url).read()
https_err = None
except urllib.error.URLError as err:
https_err = err
assert https_err
yield "."
def testCryptHash(self, num_run=1, hash_type="sha256"):
"""
Test hashing functions
"""
yield "(5MB) "
from Crypt import CryptHash
hash_types = {
"sha256": {"func": CryptHash.sha256sum, "hash_valid": "8cd629d9d6aff6590da8b80782a5046d2673d5917b99d5603c3dcb4005c45ffa"},
"sha512": {"func": CryptHash.sha512sum, "hash_valid": "9ca7e855d430964d5b55b114e95c6bbb114a6d478f6485df93044d87b108904d"}
}
hash_func = hash_types[hash_type]["func"]
hash_valid = hash_types[hash_type]["hash_valid"]
data = io.BytesIO(b"Hello" * 1024 * 1024) # 5MB
for i in range(num_run):
data.seek(0)
hash = hash_func(data)
yield "."
assert hash == hash_valid, "%s != %s" % (hash, hash_valid)
def testCryptHashlib(self, num_run=1, hash_type="sha3_256"):
"""
Test SHA3 hashing functions
"""
yield "x 5MB "
hash_types = {
"sha3_256": {"func": hashlib.sha3_256, "hash_valid": "c8aeb3ef9fe5d6404871c0d2a4410a4d4e23268e06735648c9596f436c495f7e"},
"sha3_512": {"func": hashlib.sha3_512, "hash_valid": "b75dba9472d8af3cc945ce49073f3f8214d7ac12086c0453fb08944823dee1ae83b3ffbc87a53a57cc454521d6a26fe73ff0f3be38dddf3f7de5d7692ebc7f95"},
}
hash_func = hash_types[hash_type]["func"]
hash_valid = hash_types[hash_type]["hash_valid"]
data = io.BytesIO(b"Hello" * 1024 * 1024) # 5MB
for i in range(num_run):
data.seek(0)
h = hash_func()
while 1:
buff = data.read(1024 * 64)
if not buff:
break
h.update(buff)
hash = h.hexdigest()
yield "."
assert hash == hash_valid, "%s != %s" % (hash, hash_valid)
def testRandom(self, num_run=1):
"""
Test generating random data
"""
yield "x 1000 x 256 bytes "
for i in range(num_run):
data_last = None
for y in range(1000):
data = os.urandom(256)
assert data != data_last
assert len(data) == 256
data_last = data
yield "."
def testHdPrivatekey(self, num_run=2):
"""
Test generating deterministic private keys from a master seed
"""
from Crypt import CryptBitcoin
seed = "e180efa477c63b0f2757eac7b1cce781877177fe0966be62754ffd4c8592ce38"
privatekeys = []
for i in range(num_run):
privatekeys.append(CryptBitcoin.hdPrivatekey(seed, i * 10))
yield "."
valid = "5JSbeF5PevdrsYjunqpg7kAGbnCVYa1T4APSL3QRu8EoAmXRc7Y"
assert privatekeys[0] == valid, "%s != %s" % (privatekeys[0], valid)
if len(privatekeys) > 1:
assert privatekeys[0] != privatekeys[-1]
def testSign(self, num_run=1):
"""
Test signing data using a private key
"""
from Crypt import CryptBitcoin
data = "Hello" * 1024
privatekey = "5JsunC55XGVqFQj5kPGK4MWgTL26jKbnPhjnmchSNPo75XXCwtk"
for i in range(num_run):
yield "."
sign = CryptBitcoin.sign(data, privatekey)
valid = "G1GXaDauZ8vX/N9Jn+MRiGm9h+I94zUhDnNYFaqMGuOiBHB+kp4cRPZOL7l1yqK5BHa6J+W97bMjvTXtxzljp6w="
assert sign == valid, "%s != %s" % (sign, valid)
def testVerify(self, num_run=1, lib_verify="sslcrypto"):
"""
Test verification of generated signatures
"""
from Crypt import CryptBitcoin
CryptBitcoin.loadLib(lib_verify, silent=True)
data = "Hello" * 1024
privatekey = "5JsunC55XGVqFQj5kPGK4MWgTL26jKbnPhjnmchSNPo75XXCwtk"
address = CryptBitcoin.privatekeyToAddress(privatekey)
sign = "G1GXaDauZ8vX/N9Jn+MRiGm9h+I94zUhDnNYFaqMGuOiBHB+kp4cRPZOL7l1yqK5BHa6J+W97bMjvTXtxzljp6w="
for i in range(num_run):
ok = CryptBitcoin.verify(data, address, sign, lib_verify=lib_verify)
yield "."
assert ok, "does not verify from %s" % address
if lib_verify == "sslcrypto":
yield("(%s)" % CryptBitcoin.sslcrypto.ecc.get_backend())
def testPortCheckers(self):
"""
Test all active open port checker
"""
from Peer import PeerPortchecker
for ip_type, func_names in PeerPortchecker.PeerPortchecker.checker_functions.items():
yield "\n- %s:" % ip_type
for func_name in func_names:
yield "\n - Tracker %s: " % func_name
try:
for res in self.testPortChecker(func_name):
yield res
except Exception as err:
yield Debug.formatException(err)
def testPortChecker(self, func_name):
"""
Test single open port checker
"""
from Peer import PeerPortchecker
peer_portchecker = PeerPortchecker.PeerPortchecker(None)
announce_func = getattr(peer_portchecker, func_name)
res = announce_func(3894)
yield res
def testAll(self):
"""
Run all tests to check system compatibility with ZeroNet functions
"""
for progress in self.testBenchmark(online=not config.offline, num_run=1):
yield progress
@PluginManager.registerTo("ConfigPlugin")
class ConfigPlugin(object):
def createArguments(self):
back = super(ConfigPlugin, self).createArguments()
if self.getCmdlineValue("test") == "benchmark":
self.test_parser.add_argument(
'--num_multipler', help='Benchmark run time multipler',
default=1.0, type=float, metavar='num'
)
self.test_parser.add_argument(
'--filter', help='Filter running benchmark',
default=None, metavar='test name'
)
elif self.getCmdlineValue("test") == "portChecker":
self.test_parser.add_argument(
'--func_name', help='Name of open port checker function',
default=None, metavar='func_name'
)
return back
================================================
FILE: plugins/Benchmark/__init__.py
================================================
from . import BenchmarkPlugin
from . import BenchmarkDb
from . import BenchmarkPack
================================================
FILE: plugins/Benchmark/media/benchmark.html
================================================
<html>
<script nonce="{script_nonce}">
window.benchmark_key = "{benchmark_key}";
function setState(elem, text) {
var formatted = text
var parts = text.match(/\* Running (.*?)(\n|$)/g)
if (parts) {
for (var i=0; i < parts.length; i++) {
part = parts[i];
var details = part.match(/\* Running (.*?) (\.+|$)(.*)/);
if (details) {
var title = details[1]
var progress = details[2]
var result = details[3]
result_parts = result.match(/(.*) Done in ([0-9\.]+)s = (.*?) \(([0-9\.]+)x\)/)
var percent = Math.min(100, progress.length * 10)
if (result_parts) percent = 100
var style = "background-image: linear-gradient(90deg, #FFF " + percent + "%, #FFF 0%, #d9d5de 0%);"
var part_formatted = "<div class='test' style='" + style + "'>"
part_formatted += "<span class='title'>" + title + "</span><span class='percent percent-" + percent + "'>" + percent + "%</span> "
if (result_parts) {
var result_extra = result_parts[1]
var taken = result_parts[2]
var multipler_title = result_parts[3]
var multipler = result_parts[4]
part_formatted += "<div class='result result-" + multipler_title.replace(/[^A-Za-z]/g, "") + "'>"
part_formatted += " <span class='taken'>" + taken + "s</span>"
part_formatted += " <span class='multipler'>" + multipler + "x</span>"
part_formatted += " <span class='multipler-title'>" + multipler_title + "</span>"
part_formatted += "</div>"
} else {
part_formatted += "<div class='result'>" + result + "</div>"
}
part_formatted += "</div>"
formatted = formatted.replace(part, part_formatted);
}
}
}
formatted = formatted.replace(/(\! Error:.*)/, "<div class='test error'>$1</div>");
formatted = formatted.replace(/(\== Result ==[^]*)/, "<div class='test summary'>$1</div>");
var is_bottom = document.body.scrollTop + document.body.clientHeight >= document.body.scrollHeight - 5;
elem.innerHTML = formatted.trim();
if (is_bottom)
document.body.scrollTop = document.body.scrollHeight;
}
function stream(url, elem) {
document.getElementById("h1").innerText = "Benchmark: Starting..."
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.setRequestHeader('Accept', 'text/html');
xhr.send(null);
xhr.onreadystatechange = function(state) {
document.getElementById("h1").innerText = "Benchmark: Running..."
setState(elem, xhr.responseText);
if (xhr.readyState == 4) {
document.getElementById("h1").innerText = "Benchmark: Done."
}
}
}
</script>
<body>
<style>
body {
background-color: #3c3546;
background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23cfcfcf' fill-opacity='0.09'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");}
h1 {
font-family: monospace; color: white; font-weight: normal; text-transform: uppercase;
max-width: 690px; margin: 30px auto; margin-bottom: 10px;
}
#out {
white-space: pre-line; background-color: #ffffff1a; padding: 20px; font-family: Consolas, monospace;
font-size: 11px; width: 90%; margin: auto; max-width: 650px; box-shadow: 0px 10px 30px -10px #5c5c5c6b;
}
.test { padding: 12px; box-shadow: 0px 5px 13px -5px #5c5c5c6b; margin-bottom: -2px; background-color: white; border: 1px solid #dbdbdb; }
.test .percent { float: right; }
.test .percent-100 { display: none; }
.test .result { float: right; }
.test .title { max-width: calc(100% - 150px); display: inline-block; }
.test .multipler-title { display: inline-block; width: 50px; text-align: right; }
.test:last-child { margin-bottom: 15px; border-color: #c1c1c1; }
.test .result-Sloooow { color: red; }
.test .result-Ehh { color: #ad1457; }
.test .result-Goodish { color: #ef6c00; }
.test .result-Ok { color: #00cf03; }
.test .result-Fine { color: #00bcd4; }
.test .result-Fast { color: #4b78ff; }
.test .result-WOW { color: #9c27b0; }
.test .result-Insane { color: #d603f4; }
.test.summary { margin-top: 20px; text-transform: uppercase; border-left: 10px solid #00ff63; border-color: #00ff63; }
.test.error { background-color: #ff2259; color: white; border-color: red; }
#start { text-align: center }
.button {
background-color: white; padding: 10px 20px; display: inline-block; border-radius: 5px;
text-decoration: none; color: #673AB7; text-transform: uppercase; margin-bottom: 11px; border-bottom: 2px solid #c1bff8;
}
.button:hover { border-bottom-color: #673AB7; }
.button:active { transform: translateY(1px) }
small { text-transform: uppercase; opacity: 0.7; color: white; letter-spacing: 1px; }
</style>
<h1 id="h1">Benchmark</h1>
<div id="out">
<div id="start">
<a href="#Start" class="button" id="start_button">Start benchmark</a>
<small>(It will take around 20 sec)</small>
</div>
</div>
<script nonce="{script_nonce}">
function start() {
stream("/BenchmarkResult?benchmark_key={benchmark_key}&filter={filter}", document.getElementById("out"));
return false;
}
document.getElementById("start_button").onclick = start
</script>
</body>
</html>
================================================
FILE: plugins/Benchmark/plugin_info.json
================================================
{
"name": "Benchmark",
"description": "Test and benchmark database and cryptographic functions related to ZeroNet.",
"default": "enabled"
}
================================================
FILE: plugins/Bigfile/BigfilePiecefield.py
================================================
import array
def packPiecefield(data):
if not isinstance(data, bytes) and not isinstance(data, bytearray):
raise Exception("Invalid data type: %s" % type(data))
res = []
if not data:
return array.array("H", b"")
if data[0] == b"\x00":
res.append(0)
find = b"\x01"
else:
find = b"\x00"
last_pos = 0
pos = 0
while 1:
pos = data.find(find, pos)
if find == b"\x00":
find = b"\x01"
else:
find = b"\x00"
if pos == -1:
res.append(len(data) - last_pos)
break
res.append(pos - last_pos)
last_pos = pos
return array.array("H", res)
def unpackPiecefield(data):
if not data:
return b""
res = []
char = b"\x01"
for times in data:
if times > 10000:
return b""
res.append(char * times)
if char == b"\x01":
char = b"\x00"
else:
char = b"\x01"
return b"".join(res)
def spliceBit(data, idx, bit):
if bit != b"\x00" and bit != b"\x01":
raise Exception("Invalid bit: %s" % bit)
if len(data) < idx:
data = data.ljust(idx + 1, b"\x00")
return data[:idx] + bit + data[idx+ 1:]
class Piecefield(object):
def tostring(self):
return "".join(["1" if b else "0" for b in self.tobytes()])
class BigfilePiecefield(Piecefield):
__slots__ = ["data"]
def __init__(self):
self.data = b""
def frombytes(self, s):
if not isinstance(s, bytes) and not isinstance(s, bytearray):
raise Exception("Invalid type: %s" % type(s))
self.data = s
def tobytes(self):
return self.data
def pack(self):
return packPiecefield(self.data).tobytes()
def unpack(self, s):
self.data = unpackPiecefield(array.array("H", s))
def __getitem__(self, key):
try:
return self.data[key]
except IndexError:
return False
def __setitem__(self, key, value):
self.data = spliceBit(self.data, key, value)
class BigfilePiecefieldPacked(Piecefield):
__slots__ = ["data"]
def __init__(self):
self.data = b""
def frombytes(self, data):
if not isinstance(data, bytes) and not isinstance(data, bytearray):
raise Exception("Invalid type: %s" % type(data))
self.data = packPiecefield(data).tobytes()
def tobytes(self):
return unpackPiecefield(array.array("H", self.data))
def pack(self):
return array.array("H", self.data).tobytes()
def unpack(self, data):
self.data = data
def __getitem__(self, key):
try:
return self.tobytes()[key]
except IndexError:
return False
def __setitem__(self, key, value):
data = spliceBit(self.tobytes(), key, value)
self.frombytes(data)
if __name__ == "__main__":
import os
import psutil
import time
testdata = b"\x01" * 100 + b"\x00" * 900 + b"\x01" * 4000 + b"\x00" * 4999 + b"\x01"
meminfo = psutil.Process(os.getpid()).memory_info
for storage in [BigfilePiecefieldPacked, BigfilePiecefield]:
print("-- Testing storage: %s --" % storage)
m = meminfo()[0]
s = time.time()
piecefields = {}
for i in range(10000):
piecefield = storage()
piecefield.frombytes(testdata[:i] + b"\x00" + testdata[i + 1:])
piecefields[i] = piecefield
print("Create x10000: +%sKB in %.3fs (len: %s)" % ((meminfo()[0] - m) / 1024, time.time() - s, len(piecefields[0].data)))
m = meminfo()[0]
s = time.time()
for piecefield in list(piecefields.values()):
val = piecefield[1000]
print("Query one x10000: +%sKB in %.3fs" % ((meminfo()[0] - m) / 1024, time.time() - s))
m = meminfo()[0]
s = time.time()
for piecefield in list(piecefields.values()):
piecefield[1000] = b"\x01"
print("Change one x10000: +%sKB in %.3fs" % ((meminfo()[0] - m) / 1024, time.time() - s))
m = meminfo()[0]
s = time.time()
for piecefield in list(piecefields.values()):
packed = piecefield.pack()
print("Pack x10000: +%sKB in %.3fs (len: %s)" % ((meminfo()[0] - m) / 1024, time.time() - s, len(packed)))
m = meminfo()[0]
s = time.time()
for piecefield in list(piecefields.values()):
piecefield.unpack(packed)
print("Unpack x10000: +%sKB in %.3fs (len: %s)" % ((meminfo()[0] - m) / 1024, time.time() - s, len(piecefields[0].data)))
piecefields = {}
================================================
FILE: plugins/Bigfile/BigfilePlugin.py
================================================
import time
import os
import subprocess
import shutil
import collections
import math
import warnings
import base64
import binascii
import json
import gevent
import gevent.lock
from Plugin import PluginManager
from Debug import Debug
from Crypt import CryptHash
with warnings.catch_warnings():
warnings.filterwarnings("ignore") # Ignore missing sha3 warning
import merkletools
from util import helper
from util import Msgpack
from util.Flag import flag
import util
from .BigfilePiecefield import BigfilePiecefield, BigfilePiecefieldPacked
# We can only import plugin host clases after the plugins are loaded
@PluginManager.afterLoad
def importPluginnedClasses():
global VerifyError, config
from Content.ContentManager import VerifyError
from Config import config
if "upload_nonces" not in locals():
upload_nonces = {}
@PluginManager.registerTo("UiRequest")
class UiRequestPlugin(object):
def isCorsAllowed(self, path):
if path == "/ZeroNet-Internal/BigfileUpload":
return True
else:
return super(UiRequestPlugin, self).isCorsAllowed(path)
@helper.encodeResponse
def actionBigfileUpload(self):
nonce = self.get.get("upload_nonce")
if nonce not in upload_nonces:
return self.error403("Upload nonce error.")
upload_info = upload_nonces[nonce]
del upload_nonces[nonce]
self.sendHeader(200, "text/html", noscript=True, extra_headers={
"Access-Control-Allow-Origin": "null",
"Access-Control-Allow-Credentials": "true"
})
self.readMultipartHeaders(self.env['wsgi.input']) # Skip http headers
result = self.handleBigfileUpload(upload_info, self.env['wsgi.input'].read)
return json.dumps(result)
def actionBigfileUploadWebsocket(self):
ws = self.env.get("wsgi.websocket")
if not ws:
self.start_response("400 Bad Request", [])
return [b"Not a websocket request!"]
nonce = self.get.get("upload_nonce")
if nonce not in upload_nonces:
return self.error403("Upload nonce error.")
upload_info = upload_nonces[nonce]
del upload_nonces[nonce]
ws.send("poll")
buffer = b""
def read(size):
nonlocal buffer
while len(buffer) < size:
buffer += ws.receive()
ws.send("poll")
part, buffer = buffer[:size], buffer[size:]
return part
result = self.handleBigfileUpload(upload_info, read)
ws.send(json.dumps(result))
def handleBigfileUpload(self, upload_info, read):
site = upload_info["site"]
inner_path = upload_info["inner_path"]
with site.storage.open(inner_path, "wb", create_dirs=True) as out_file:
merkle_root, piece_size, piecemap_info = site.content_manager.hashBigfile(
read, upload_info["size"], upload_info["piece_size"], out_file
)
if len(piecemap_info["sha512_pieces"]) == 1: # Small file, don't split
hash = binascii.hexlify(piecemap_info["sha512_pieces"][0])
hash_id = site.content_manager.hashfield.getHashId(hash)
site.content_manager.optionalDownloaded(inner_path, hash_id, upload_info["size"], own=True)
else: # Big file
file_name = helper.getFilename(inner_path)
site.storage.open(upload_info["piecemap"], "wb").write(Msgpack.pack({file_name: piecemap_info}))
# Find piecemap and file relative path to content.json
file_info = site.content_manager.getFileInfo(inner_path, new_file=True)
content_inner_path_dir = helper.getDirname(file_info["content_inner_path"])
piecemap_relative_path = upload_info["piecemap"][len(content_inner_path_dir):]
file_relative_path = inner_path[len(content_inner_path_dir):]
# Add file to content.json
if site.storage.isFile(file_info["content_inner_path"]):
content = site.storage.loadJson(file_info["content_inner_path"])
else:
content = {}
if "files_optional" not in content:
content["files_optional"] = {}
content["files_optional"][file_relative_path] = {
"sha512": merkle_root,
"size": upload_info["size"],
"piecemap": piecemap_relative_path,
"piece_size": piece_size
}
merkle_root_hash_id = site.content_manager.hashfield.getHashId(merkle_root)
site.content_manager.optionalDownloaded(inner_path, merkle_root_hash_id, upload_info["size"], own=True)
site.storage.writeJson(file_info["content_inner_path"], content)
site.content_manager.contents.loadItem(file_info["content_inner_path"]) # reload cache
return {
"merkle_root": merkle_root,
"piece_num": len(piecemap_info["sha512_pieces"]),
"piece_size": piece_size,
"inner_path": inner_path
}
def readMultipartHeaders(self, wsgi_input):
found = False
for i in range(100):
line = wsgi_input.readline()
if line == b"\r\n":
found = True
break
if not found:
raise Exception("No multipart header found")
return i
def actionFile(self, file_path, *args, **kwargs):
if kwargs.get("file_size", 0) > 1024 * 1024 and kwargs.get("path_parts"): # Only check files larger than 1MB
path_parts = kwargs["path_parts"]
site = self.server.site_manager.get(path_parts["address"])
big_file = site.storage.openBigfile(path_parts["inner_path"], prebuffer=2 * 1024 * 1024)
if big_file:
kwargs["file_obj"] = big_file
kwargs["file_size"] = big_file.size
return super(UiRequestPlugin, self).actionFile(file_path, *args, **kwargs)
@PluginManager.registerTo("UiWebsocket")
class UiWebsocketPlugin(object):
def actionBigfileUploadInit(self, to, inner_path, size, protocol="xhr"):
valid_signers = self.site.content_manager.getValidSigners(inner_path)
auth_address = self.user.getAuthAddress(self.site.address)
if not self.site.settings["own"] and auth_address not in valid_signers:
self.log.error("FileWrite forbidden %s not in valid_signers %s" % (auth_address, valid_signers))
return self.response(to, {"error": "Forbidden, you can only modify your own files"})
nonce = CryptHash.random()
piece_size = 1024 * 1024
inner_path = self.site.content_manager.sanitizePath(inner_path)
file_info = self.site.content_manager.getFileInfo(inner_path, new_file=True)
content_inner_path_dir = helper.getDirname(file_info["content_inner_path"])
file_relative_path = inner_path[len(content_inner_path_dir):]
upload_nonces[nonce] = {
"added": time.time(),
"site": self.site,
"inner_path": inner_path,
"websocket_client": self,
"size": size,
"piece_size": piece_size,
"piecemap": inner_path + ".piecemap.msgpack"
}
if protocol == "xhr":
return {
"url": "/ZeroNet-Internal/BigfileUpload?upload_nonce=" + nonce,
"piece_size": piece_size,
"inner_path": inner_path,
"file_relative_path": file_relative_path
}
elif protocol == "websocket":
server_url = self.request.getWsServerUrl()
if server_url:
proto, host = server_url.split("://")
origin = proto.replace("http", "ws") + "://" + host
else:
origin = "{origin}"
return {
"url": origin + "/ZeroNet-Internal/BigfileUploadWebsocket?upload_nonce=" + nonce,
"piece_size": piece_size,
"inner_path": inner_path,
"file_relative_path": file_relative_path
}
else:
return {"error": "Unknown protocol"}
@flag.no_multiuser
def actionSiteSetAutodownloadBigfileLimit(self, to, limit):
permissions = self.getPermissions(to)
if "ADMIN" not in permissions:
return self.response(to, "You don't have permission to run this command")
self.site.settings["autodownload_bigfile_size_limit"] = int(limit)
self.response(to, "ok")
def actionFileDelete(self, to, inner_path):
piecemap_inner_path = inner_path + ".piecemap.msgpack"
if self.hasFilePermission(inner_path) and self.site.storage.isFile(piecemap_inner_path):
# Also delete .piecemap.msgpack file if exists
self.log.debug("Deleting piecemap: %s" % piecemap_inner_path)
file_info = self.site.content_manager.getFileInfo(piecemap_inner_path)
if file_info:
content_json = self.site.storage.loadJson(file_info["content_inner_path"])
relative_path = file_info["relative_path"]
if relative_path in content_json.get("files_optional", {}):
del content_json["files_optional"][relative_path]
self.site.storage.writeJson(file_info["content_inner_path"], content_json)
self.site.content_manager.loadContent(file_info["content_inner_path"], add_bad_files=False, force=True)
try:
self.site.storage.delete(piecemap_inner_path)
except Exception as err:
self.log.error("File %s delete error: %s" % (piecemap_inner_path, err))
return super(UiWebsocketPlugin, self).actionFileDelete(to, inner_path)
@PluginManager.registerTo("ContentManager")
class ContentManagerPlugin(object):
def getFileInfo(self, inner_path, *args, **kwargs):
if "|" not in inner_path:
return super(ContentManagerPlugin, self).getFileInfo(inner_path, *args, **kwargs)
inner_path, file_range = inner_path.split("|")
pos_from, pos_to = map(int, file_range.split("-"))
file_info = super(ContentManagerPlugin, self).getFileInfo(inner_path, *args, **kwargs)
return file_info
def readFile(self, read_func, size, buff_size=1024 * 64):
part_num = 0
recv_left = size
while 1:
part_num += 1
read_size = min(buff_size, recv_left)
part = read_func(read_size)
if not part:
break
yield part
if part_num % 100 == 0: # Avoid blocking ZeroNet execution during upload
time.sleep(0.001)
recv_left -= read_size
if recv_left <= 0:
break
def hashBigfile(self, read_func, size, piece_size=1024 * 1024, file_out=None):
self.site.settings["has_bigfile"] = True
recv = 0
try:
piece_hash = CryptHash.sha512t()
piece_hashes = []
piece_recv = 0
mt = merkletools.MerkleTools()
mt.hash_function = CryptHash.sha512t
part = ""
for part in self.readFile(read_func, size):
if file_out:
file_out.write(part)
recv += len(part)
piece_recv += len(part)
piece_hash.update(part)
if piece_recv >= piece_size:
piece_digest = piece_hash.digest()
piece_hashes.append(piece_digest)
mt.leaves.append(piece_digest)
piece_hash = CryptHash.sha512t()
piece_recv = 0
if len(piece_hashes) % 100 == 0 or recv == size:
self.log.info("- [HASHING:%.0f%%] Pieces: %s, %.1fMB/%.1fMB" % (
float(recv) / size * 100, len(piece_hashes), recv / 1024 / 1024, size / 1024 / 1024
))
part = ""
if len(part) > 0:
piece_digest = piece_hash.digest()
piece_hashes.append(piece_digest)
mt.leaves.append(piece_digest)
except Exception as err:
raise err
finally:
if file_out:
file_out.close()
mt.make_tree()
merkle_root = mt.get_merkle_root()
if type(merkle_root) is bytes: # Python <3.5
merkle_root = merkle_root.decode()
return merkle_root, piece_size, {
"sha512_pieces": piece_hashes
}
def hashFile(self, dir_inner_path, file_relative_path, optional=False):
inner_path = dir_inner_path + file_relative_path
file_size = self.site.storage.getSize(inner_path)
# Only care about optional files >1MB
if not optional or file_size < 1 * 1024 * 1024:
return super(ContentManagerPlugin, self).hashFile(dir_inner_path, file_relative_path, optional)
back = {}
content = self.contents.get(dir_inner_path + "content.json")
hash = None
piecemap_relative_path = None
piece_size = None
# Don't re-hash if it's already in content.json
if content and file_relative_path in content.get("files_optional", {}):
file_node = content["files_optional"][file_relative_path]
if file_node["size"] == file_size:
self.log.info("- [SAME SIZE] %s" % file_relative_path)
hash = file_node.get("sha512")
piecemap_relative_path = file_node.get("piecemap")
piece_size = file_node.get("piece_size")
if not hash or not piecemap_relative_path: # Not in content.json yet
if file_size < 5 * 1024 * 1024: # Don't create piecemap automatically for files smaller than 5MB
return super(ContentManagerPlugin, self).hashFile(dir_inner_path, file_relative_path, optional)
self.log.info("- [HASHING] %s" % file_relative_path)
merkle_root, piece_size, piecemap_info = self.hashBigfile(self.site.storage.open(inner_path, "rb").read, file_size)
if not hash:
hash = merkle_root
if not piecemap_relative_path:
file_name = helper.getFilename(file_relative_path)
piecemap_relative_path = file_relative_path + ".piecemap.msgpack"
piecemap_inner_path = inner_path + ".piecemap.msgpack"
self.site.storage.open(piecemap_inner_path, "wb").write(Msgpack.pack({file_name: piecemap_info}))
back.update(super(ContentManagerPlugin, self).hashFile(dir_inner_path, piecemap_relative_path, optional=True))
piece_num = int(math.ceil(float(file_size) / piece_size))
# Add the merkle root to hashfield
hash_id = self.site.content_manager.hashfield.getHashId(hash)
self.optionalDownloaded(inner_path, hash_id, file_size, own=True)
self.site.storage.piecefields[hash].frombytes(b"\x01" * piece_num)
back[file_relative_path] = {"sha512": hash, "size": file_size, "piecemap": piecemap_relative_path, "piece_size": piece_size}
return back
def getPiecemap(self, inner_path):
file_info = self.site.content_manager.getFileInfo(inner_path)
piecemap_inner_path = helper.getDirname(file_info["content_inner_path"]) + file_info["piecemap"]
self.site.needFile(piecemap_inner_path, priority=20)
piecemap = Msgpack.unpack(self.site.storage.open(piecemap_inner_path, "rb").read())[helper.getFilename(inner_path)]
piecemap["piece_size"] = file_info["piece_size"]
return piecemap
def verifyPiece(self, inner_path, pos, piece):
try:
piecemap = self.getPiecemap(inner_path)
except Exception as err:
raise VerifyError("Unable to download piecemap: %s" % Debug.formatException(err))
piece_i = int(pos / piecemap["piece_size"])
if CryptHash.sha512sum(piece, format="digest") != piecemap["sha512_pieces"][piece_i]:
raise VerifyError("Invalid hash")
return True
def verifyFile(self, inner_path, file, ignore_same=True):
if "|" not in inner_path:
return super(ContentManagerPlugin, self).verifyFile(inner_path, file, ignore_same)
inner_path, file_range = inner_path.split("|")
pos_from, pos_to = map(int, file_range.split("-"))
return self.verifyPiece(inner_path, pos_from, file)
def optionalDownloaded(self, inner_path, hash_id, size=None, own=False):
if "|" in inner_path:
inner_path, file_range = inner_path.split("|")
pos_from, pos_to = map(int, file_range.split("-"))
file_info = self.getFileInfo(inner_path)
# Mark piece downloaded
piece_i = int(pos_from / file_info["piece_size"])
self.site.storage.piecefields[file_info["sha512"]][piece_i] = b"\x01"
# Only add to site size on first request
if hash_id in self.hashfield:
size = 0
elif size > 1024 * 1024:
file_info = self.getFileInfo(inner_path)
if file_info and "sha512" in file_info: # We already have the file, but not in piecefield
sha512 = file_info["sha512"]
if sha512 not in self.site.storage.piecefields:
self.site.storage.checkBigfile(inner_path)
return super(ContentManagerPlugin, self).optionalDownloaded(inner_path, hash_id, size, own)
def optionalRemoved(self, inner_path, hash_id, size=None):
if size and size > 1024 * 1024:
file_info = self.getFileInfo(inner_path)
sha512 = file_info["sha512"]
if sha512 in self.site.storage.piecefields:
del self.site.storage.piecefields[sha512]
# Also remove other pieces of the file from download queue
for key in list(self.site.bad_files.keys()):
if key.startswith(inner_path + "|"):
del self.site.bad_files[key]
self.site.worker_manager.removeSolvedFileTasks()
return super(ContentManagerPlugin, self).optionalRemoved(inner_path, hash_id, size)
@PluginManager.registerTo("SiteStorage")
class SiteStoragePlugin(object):
def __init__(self, *args, **kwargs):
super(SiteStoragePlugin, self).__init__(*args, **kwargs)
self.piecefields = collections.defaultdict(BigfilePiecefield)
if "piecefields" in self.site.settings.get("cache", {}):
for sha512, piecefield_packed in self.site.settings["cache"].get("piecefields").items():
if piecefield_packed:
self.piecefields[sha512].unpack(base64.b64decode(piecefield_packed))
self.site.settings["cache"]["piecefields"] = {}
def createSparseFile(self, inner_path, size, sha512=None):
file_path = self.getPath(inner_path)
self.ensureDir(os.path.dirname(inner_path))
f = open(file_path, 'wb')
f.truncate(min(1024 * 1024 * 5, size)) # Only pre-allocate up to 5MB
f.close()
if os.name == "nt":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.call(["fsutil", "sparse", "setflag", file_path], close_fds=True, startupinfo=startupinfo)
if sha512 and sha512 in self.piecefields:
self.log.debug("%s: File not exists, but has piecefield. Deleting piecefield." % inner_path)
del self.piecefields[sha512]
def write(self, inner_path, content):
if "|" not in inner_path:
return super(SiteStoragePlugin, self).write(inner_path, content)
# Write to specific position by passing |{pos} after the filename
inner_path, file_range = inner_path.split("|")
pos_from, pos_to = map(int, file_range.split("-"))
file_path = self.getPath(inner_path)
# Create dir if not exist
self.ensureDir(os.path.dirname(inner_path))
if not os.path.isfile(file_path):
file_info = self.site.content_manager.getFileInfo(inner_path)
self.createSparseFile(inner_path, file_info["size"])
# Write file
with open(file_path, "rb+") as file:
file.seek(pos_from)
if hasattr(content, 'read'): # File-like object
shutil.copyfileobj(content, file) # Write buff to disk
else: # Simple string
file.write(content)
del content
self.onUpdated(inner_path)
def checkBigfile(self, inner_path):
file_info = self.site.content_manager.getFileInfo(inner_path)
if not file_info or (file_info and "piecemap" not in file_info): # It's not a big file
return False
self.site.settings["has_bigfile"] = True
file_path = self.getPath(inner_path)
sha512 = file_info["sha512"]
piece_num = int(math.ceil(float(file_info["size"]) / file_info["piece_size"]))
if os.path.isfile(file_path):
if sha512 not in self.piecefields:
if open(file_path, "rb").read(128) == b"\0" * 128:
piece_data = b"\x00"
else:
piece_data = b"\x01"
self.log.debug("%s: File exists, but not in piecefield. Filling piecefiled with %s * %s." % (inner_path, piece_num, piece_data))
self.piecefields[sha512].frombytes(piece_data * piece_num)
else:
self.log.debug("Creating bigfile: %s" % inner_path)
self.createSparseFile(inner_path, file_info["size"], sha512)
self.piecefields[sha512].frombytes(b"\x00" * piece_num)
self.log.debug("Created bigfile: %s" % inner_path)
return True
def openBigfile(self, inner_path, prebuffer=0):
if not self.checkBigfile(inner_path):
return False
self.site.needFile(inner_path, blocking=False) # Download piecemap
return BigFile(self.site, inner_path, prebuffer=prebuffer)
class BigFile(object):
def __init__(self,
gitextract__wvjr9ao/ ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug-report.md │ │ └── feature_request.md │ └── workflows/ │ └── tests.yml ├── .gitignore ├── .gitlab-ci.yml ├── .travis.yml ├── CHANGELOG.md ├── COPYING ├── Dockerfile ├── Dockerfile.arm64v8 ├── LICENSE ├── README-ru.md ├── README-zh-cn.md ├── README.md ├── Vagrantfile ├── plugins/ │ ├── AnnounceBitTorrent/ │ │ ├── AnnounceBitTorrentPlugin.py │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── AnnounceLocal/ │ │ ├── AnnounceLocalPlugin.py │ │ ├── BroadcastServer.py │ │ ├── Test/ │ │ │ ├── TestAnnounce.py │ │ │ ├── conftest.py │ │ │ └── pytest.ini │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── AnnounceShare/ │ │ ├── AnnounceSharePlugin.py │ │ ├── Test/ │ │ │ ├── TestAnnounceShare.py │ │ │ ├── conftest.py │ │ │ └── pytest.ini │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── AnnounceZero/ │ │ ├── AnnounceZeroPlugin.py │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── Benchmark/ │ │ ├── BenchmarkDb.py │ │ ├── BenchmarkPack.py │ │ ├── BenchmarkPlugin.py │ │ ├── __init__.py │ │ ├── media/ │ │ │ └── benchmark.html │ │ └── plugin_info.json │ ├── Bigfile/ │ │ ├── BigfilePiecefield.py │ │ ├── BigfilePlugin.py │ │ ├── Test/ │ │ │ ├── TestBigfile.py │ │ │ ├── conftest.py │ │ │ └── pytest.ini │ │ └── __init__.py │ ├── Chart/ │ │ ├── ChartCollector.py │ │ ├── ChartDb.py │ │ ├── ChartPlugin.py │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── ContentFilter/ │ │ ├── ContentFilterPlugin.py │ │ ├── ContentFilterStorage.py │ │ ├── Test/ │ │ │ ├── TestContentFilter.py │ │ │ ├── conftest.py │ │ │ └── pytest.ini │ │ ├── __init__.py │ │ ├── languages/ │ │ │ ├── hu.json │ │ │ ├── it.json │ │ │ ├── jp.json │ │ │ ├── pt-br.json │ │ │ ├── zh-tw.json │ │ │ └── zh.json │ │ ├── media/ │ │ │ ├── blocklisted.html │ │ │ └── js/ │ │ │ └── ZeroFrame.js │ │ └── plugin_info.json │ ├── Cors/ │ │ ├── CorsPlugin.py │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── CryptMessage/ │ │ ├── CryptMessage.py │ │ ├── CryptMessagePlugin.py │ │ ├── Test/ │ │ │ ├── TestCrypt.py │ │ │ ├── conftest.py │ │ │ └── pytest.ini │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── FilePack/ │ │ ├── FilePackPlugin.py │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── MergerSite/ │ │ ├── MergerSitePlugin.py │ │ ├── __init__.py │ │ └── languages/ │ │ ├── es.json │ │ ├── fr.json │ │ ├── hu.json │ │ ├── it.json │ │ ├── jp.json │ │ ├── pt-br.json │ │ ├── tr.json │ │ ├── zh-tw.json │ │ └── zh.json │ ├── Newsfeed/ │ │ ├── NewsfeedPlugin.py │ │ └── __init__.py │ ├── OptionalManager/ │ │ ├── ContentDbPlugin.py │ │ ├── OptionalManagerPlugin.py │ │ ├── Test/ │ │ │ ├── TestOptionalManager.py │ │ │ ├── conftest.py │ │ │ └── pytest.ini │ │ ├── UiWebsocketPlugin.py │ │ ├── __init__.py │ │ └── languages/ │ │ ├── es.json │ │ ├── fr.json │ │ ├── hu.json │ │ ├── jp.json │ │ ├── pt-br.json │ │ ├── zh-tw.json │ │ └── zh.json │ ├── PeerDb/ │ │ ├── PeerDbPlugin.py │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── Sidebar/ │ │ ├── ConsolePlugin.py │ │ ├── SidebarPlugin.py │ │ ├── ZipStream.py │ │ ├── __init__.py │ │ ├── languages/ │ │ │ ├── da.json │ │ │ ├── de.json │ │ │ ├── es.json │ │ │ ├── fr.json │ │ │ ├── hu.json │ │ │ ├── it.json │ │ │ ├── jp.json │ │ │ ├── pl.json │ │ │ ├── pt-br.json │ │ │ ├── ru.json │ │ │ ├── tr.json │ │ │ ├── zh-tw.json │ │ │ └── zh.json │ │ ├── media/ │ │ │ ├── Class.coffee │ │ │ ├── Console.coffee │ │ │ ├── Console.css │ │ │ ├── Menu.coffee │ │ │ ├── Menu.css │ │ │ ├── Prototypes.coffee │ │ │ ├── RateLimit.coffee │ │ │ ├── Scrollable.js │ │ │ ├── Scrollbable.css │ │ │ ├── Sidebar.coffee │ │ │ ├── Sidebar.css │ │ │ ├── all.css │ │ │ ├── all.js │ │ │ └── morphdom.js │ │ ├── media_globe/ │ │ │ ├── Detector.js │ │ │ ├── Tween.js │ │ │ ├── all.js │ │ │ └── globe.js │ │ └── plugin_info.json │ ├── Stats/ │ │ ├── StatsPlugin.py │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── TranslateSite/ │ │ ├── TranslateSitePlugin.py │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── Trayicon/ │ │ ├── TrayiconPlugin.py │ │ ├── __init__.py │ │ ├── languages/ │ │ │ ├── es.json │ │ │ ├── fr.json │ │ │ ├── hu.json │ │ │ ├── it.json │ │ │ ├── jp.json │ │ │ ├── pl.json │ │ │ ├── pt-br.json │ │ │ ├── tr.json │ │ │ ├── zh-tw.json │ │ │ └── zh.json │ │ ├── lib/ │ │ │ ├── __init__.py │ │ │ ├── notificationicon.py │ │ │ └── winfolders.py │ │ └── plugin_info.json │ ├── UiConfig/ │ │ ├── UiConfigPlugin.py │ │ ├── __init__.py │ │ ├── languages/ │ │ │ ├── hu.json │ │ │ ├── jp.json │ │ │ ├── pl.json │ │ │ ├── pt-br.json │ │ │ └── zh.json │ │ ├── media/ │ │ │ ├── config.html │ │ │ ├── css/ │ │ │ │ ├── Config.css │ │ │ │ ├── all.css │ │ │ │ ├── button.css │ │ │ │ └── fonts.css │ │ │ └── js/ │ │ │ ├── ConfigStorage.coffee │ │ │ ├── ConfigView.coffee │ │ │ ├── UiConfig.coffee │ │ │ ├── all.js │ │ │ ├── lib/ │ │ │ │ ├── Class.coffee │ │ │ │ ├── Promise.coffee │ │ │ │ ├── Prototypes.coffee │ │ │ │ └── maquette.js │ │ │ └── utils/ │ │ │ ├── Animation.coffee │ │ │ ├── Dollar.coffee │ │ │ └── ZeroFrame.coffee │ │ └── plugin_info.json │ ├── UiFileManager/ │ │ ├── UiFileManagerPlugin.py │ │ ├── __init__.py │ │ ├── languages/ │ │ │ ├── hu.json │ │ │ └── jp.json │ │ └── media/ │ │ ├── codemirror/ │ │ │ ├── LICENSE │ │ │ ├── all.css │ │ │ ├── all.js │ │ │ ├── base/ │ │ │ │ ├── codemirror.css │ │ │ │ └── codemirror.js │ │ │ ├── extension/ │ │ │ │ ├── dialog/ │ │ │ │ │ ├── dialog.css │ │ │ │ │ └── dialog.js │ │ │ │ ├── edit/ │ │ │ │ │ ├── closebrackets.js │ │ │ │ │ ├── closetag.js │ │ │ │ │ ├── continuelist.js │ │ │ │ │ ├── matchbrackets.js │ │ │ │ │ ├── matchtags.js │ │ │ │ │ └── trailingspace.js │ │ │ │ ├── fold/ │ │ │ │ │ ├── brace-fold.js │ │ │ │ │ ├── comment-fold.js │ │ │ │ │ ├── foldcode.js │ │ │ │ │ ├── foldgutter.css │ │ │ │ │ ├── foldgutter.js │ │ │ │ │ ├── indent-fold.js │ │ │ │ │ ├── markdown-fold.js │ │ │ │ │ └── xml-fold.js │ │ │ │ ├── hint/ │ │ │ │ │ ├── anyword-hint.js │ │ │ │ │ ├── html-hint.js │ │ │ │ │ ├── show-hint.css │ │ │ │ │ ├── show-hint.js │ │ │ │ │ ├── sql-hint.js │ │ │ │ │ └── xml-hint.js │ │ │ │ ├── lint/ │ │ │ │ │ ├── json-lint.js │ │ │ │ │ ├── jsonlint.js │ │ │ │ │ ├── lint.css │ │ │ │ │ └── lint.js │ │ │ │ ├── mdn-like-custom.css │ │ │ │ ├── scroll/ │ │ │ │ │ ├── annotatescrollbar.js │ │ │ │ │ ├── scrollpastend.js │ │ │ │ │ ├── simplescrollbars.css │ │ │ │ │ └── simplescrollbars.js │ │ │ │ ├── search/ │ │ │ │ │ ├── jump-to-line.js │ │ │ │ │ ├── match-highlighter.js │ │ │ │ │ ├── matchesonscrollbar.css │ │ │ │ │ ├── matchesonscrollbar.js │ │ │ │ │ ├── search.js │ │ │ │ │ └── searchcursor.js │ │ │ │ ├── selection/ │ │ │ │ │ ├── active-line.js │ │ │ │ │ ├── mark-selection.js │ │ │ │ │ └── selection-pointer.js │ │ │ │ ├── simple.js │ │ │ │ └── sublime.js │ │ │ └── mode/ │ │ │ ├── coffeescript.js │ │ │ ├── css.js │ │ │ ├── go.js │ │ │ ├── htmlembedded.js │ │ │ ├── htmlmixed.js │ │ │ ├── javascript.js │ │ │ ├── markdown.js │ │ │ ├── python.js │ │ │ ├── rust.js │ │ │ └── xml.js │ │ ├── css/ │ │ │ ├── Menu.css │ │ │ ├── Selectbar.css │ │ │ ├── UiFileManager.css │ │ │ └── all.css │ │ ├── js/ │ │ │ ├── Config.coffee │ │ │ ├── FileEditor.coffee │ │ │ ├── FileItemList.coffee │ │ │ ├── FileList.coffee │ │ │ ├── UiFileManager.coffee │ │ │ ├── all.js │ │ │ └── lib/ │ │ │ ├── Animation.coffee │ │ │ ├── Class.coffee │ │ │ ├── Dollar.coffee │ │ │ ├── ItemList.coffee │ │ │ ├── Menu.coffee │ │ │ ├── Promise.coffee │ │ │ ├── Prototypes.coffee │ │ │ ├── RateLimitCb.coffee │ │ │ ├── Text.coffee │ │ │ ├── Time.coffee │ │ │ ├── ZeroFrame.coffee │ │ │ └── maquette.js │ │ └── list.html │ ├── UiPluginManager/ │ │ ├── UiPluginManagerPlugin.py │ │ ├── __init__.py │ │ └── media/ │ │ ├── css/ │ │ │ ├── PluginManager.css │ │ │ ├── all.css │ │ │ ├── button.css │ │ │ └── fonts.css │ │ ├── js/ │ │ │ ├── PluginList.coffee │ │ │ ├── UiPluginManager.coffee │ │ │ ├── all.js │ │ │ ├── lib/ │ │ │ │ ├── Class.coffee │ │ │ │ ├── Promise.coffee │ │ │ │ ├── Prototypes.coffee │ │ │ │ └── maquette.js │ │ │ └── utils/ │ │ │ ├── Animation.coffee │ │ │ ├── Dollar.coffee │ │ │ └── ZeroFrame.coffee │ │ └── plugin_manager.html │ ├── Zeroname/ │ │ ├── README.md │ │ ├── SiteManagerPlugin.py │ │ ├── __init__.py │ │ └── updater/ │ │ └── zeroname_updater.py │ ├── __init__.py │ ├── disabled-Bootstrapper/ │ │ ├── BootstrapperDb.py │ │ ├── BootstrapperPlugin.py │ │ ├── Test/ │ │ │ ├── TestBootstrapper.py │ │ │ ├── conftest.py │ │ │ └── pytest.ini │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── disabled-Dnschain/ │ │ ├── SiteManagerPlugin.py │ │ ├── UiRequestPlugin.py │ │ └── __init__.py │ ├── disabled-DonationMessage/ │ │ ├── DonationMessagePlugin.py │ │ └── __init__.py │ ├── disabled-Multiuser/ │ │ ├── MultiuserPlugin.py │ │ ├── Test/ │ │ │ ├── TestMultiuser.py │ │ │ ├── conftest.py │ │ │ └── pytest.ini │ │ ├── UserPlugin.py │ │ ├── __init__.py │ │ └── plugin_info.json │ ├── disabled-StemPort/ │ │ ├── StemPortPlugin.py │ │ └── __init__.py │ ├── disabled-UiPassword/ │ │ ├── UiPasswordPlugin.py │ │ ├── __init__.py │ │ ├── login.html │ │ └── plugin_info.json │ └── disabled-ZeronameLocal/ │ ├── SiteManagerPlugin.py │ ├── UiRequestPlugin.py │ └── __init__.py ├── requirements.txt ├── src/ │ ├── Config.py │ ├── Connection/ │ │ ├── Connection.py │ │ ├── ConnectionServer.py │ │ └── __init__.py │ ├── Content/ │ │ ├── ContentDb.py │ │ ├── ContentDbDict.py │ │ ├── ContentManager.py │ │ └── __init__.py │ ├── Crypt/ │ │ ├── Crypt.py │ │ ├── CryptBitcoin.py │ │ ├── CryptConnection.py │ │ ├── CryptHash.py │ │ ├── CryptRsa.py │ │ └── __init__.py │ ├── Db/ │ │ ├── Db.py │ │ ├── DbCursor.py │ │ ├── DbQuery.py │ │ └── __init__.py │ ├── Debug/ │ │ ├── Debug.py │ │ ├── DebugHook.py │ │ ├── DebugLock.py │ │ ├── DebugMedia.py │ │ ├── DebugReloader.py │ │ └── __init__.py │ ├── File/ │ │ ├── FileRequest.py │ │ ├── FileServer.py │ │ └── __init__.py │ ├── Peer/ │ │ ├── Peer.py │ │ ├── PeerHashfield.py │ │ ├── PeerPortchecker.py │ │ └── __init__.py │ ├── Plugin/ │ │ ├── PluginManager.py │ │ └── __init__.py │ ├── Site/ │ │ ├── Site.py │ │ ├── SiteAnnouncer.py │ │ ├── SiteManager.py │ │ ├── SiteStorage.py │ │ └── __init__.py │ ├── Test/ │ │ ├── BenchmarkSsl.py │ │ ├── Spy.py │ │ ├── TestCached.py │ │ ├── TestConfig.py │ │ ├── TestConnectionServer.py │ │ ├── TestContent.py │ │ ├── TestContentUser.py │ │ ├── TestCryptBitcoin.py │ │ ├── TestCryptConnection.py │ │ ├── TestCryptHash.py │ │ ├── TestDb.py │ │ ├── TestDbQuery.py │ │ ├── TestDebug.py │ │ ├── TestDiff.py │ │ ├── TestEvent.py │ │ ├── TestFileRequest.py │ │ ├── TestFlag.py │ │ ├── TestHelper.py │ │ ├── TestMsgpack.py │ │ ├── TestNoparallel.py │ │ ├── TestPeer.py │ │ ├── TestRateLimit.py │ │ ├── TestSafeRe.py │ │ ├── TestSite.py │ │ ├── TestSiteDownload.py │ │ ├── TestSiteStorage.py │ │ ├── TestThreadPool.py │ │ ├── TestTor.py │ │ ├── TestTranslate.py │ │ ├── TestUiWebsocket.py │ │ ├── TestUpnpPunch.py │ │ ├── TestUser.py │ │ ├── TestWeb.py │ │ ├── TestWorkerTaskManager.py │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── coverage.ini │ │ ├── pytest.ini │ │ └── testdata/ │ │ └── 1TeSTvb4w2PWE81S2rEELgmX2GCCExQGT-original/ │ │ ├── content.json │ │ ├── css/ │ │ │ └── all.css │ │ ├── data/ │ │ │ ├── data.json │ │ │ ├── optional.txt │ │ │ ├── test_include/ │ │ │ │ ├── content.json │ │ │ │ └── data.json │ │ │ └── users/ │ │ │ ├── 1C5sgvWaSgfaTpV5kjBCnCiKtENNMYo69q/ │ │ │ │ ├── content.json │ │ │ │ └── data.json │ │ │ ├── 1CjfbrbwtP8Y2QjPy12vpTATkUT7oSiPQ9/ │ │ │ │ ├── content.json │ │ │ │ └── data.json │ │ │ ├── 1J6UrZMkarjVg5ax9W4qThir3BFUikbW6C/ │ │ │ │ ├── content.json │ │ │ │ └── data.json │ │ │ └── content.json │ │ ├── data-default/ │ │ │ ├── data.json │ │ │ └── users/ │ │ │ └── content-default.json │ │ ├── dbschema.json │ │ ├── index.html │ │ └── js/ │ │ └── all.js │ ├── Tor/ │ │ ├── TorManager.py │ │ └── __init__.py │ ├── Translate/ │ │ ├── Translate.py │ │ ├── __init__.py │ │ └── languages/ │ │ ├── da.json │ │ ├── de.json │ │ ├── es.json │ │ ├── fa.json │ │ ├── fr.json │ │ ├── hu.json │ │ ├── it.json │ │ ├── jp.json │ │ ├── nl.json │ │ ├── pl.json │ │ ├── pt-br.json │ │ ├── ru.json │ │ ├── sk.json │ │ ├── sl.json │ │ ├── tr.json │ │ ├── zh-tw.json │ │ └── zh.json │ ├── Ui/ │ │ ├── UiRequest.py │ │ ├── UiServer.py │ │ ├── UiWebsocket.py │ │ ├── __init__.py │ │ ├── media/ │ │ │ ├── Fixbutton.coffee │ │ │ ├── Infopanel.coffee │ │ │ ├── Loading.coffee │ │ │ ├── Notifications.coffee │ │ │ ├── Wrapper.coffee │ │ │ ├── Wrapper.css │ │ │ ├── WrapperZeroFrame.coffee │ │ │ ├── ZeroSiteTheme.coffee │ │ │ ├── all.css │ │ │ ├── all.js │ │ │ ├── img/ │ │ │ │ ├── favicon.psd │ │ │ │ └── logo.psd │ │ │ └── lib/ │ │ │ ├── RateLimit.coffee │ │ │ ├── Translate.coffee │ │ │ ├── ZeroWebsocket.coffee │ │ │ ├── jquery.cssanim.js │ │ │ ├── jquery.csslater.coffee │ │ │ └── jquery.easing.js │ │ └── template/ │ │ ├── site_add.html │ │ └── wrapper.html │ ├── User/ │ │ ├── User.py │ │ ├── UserManager.py │ │ └── __init__.py │ ├── Worker/ │ │ ├── Worker.py │ │ ├── WorkerManager.py │ │ ├── WorkerTaskManager.py │ │ └── __init__.py │ ├── __init__.py │ ├── lib/ │ │ ├── __init__.py │ │ ├── bencode_open/ │ │ │ ├── LICENSE │ │ │ └── __init__.py │ │ ├── cssvendor/ │ │ │ ├── __init__.py │ │ │ └── cssvendor.py │ │ ├── gevent_ws/ │ │ │ └── __init__.py │ │ ├── libsecp256k1message/ │ │ │ ├── __init__.py │ │ │ └── libsecp256k1message.py │ │ ├── openssl/ │ │ │ └── openssl.cnf │ │ ├── pyaes/ │ │ │ ├── LICENSE.txt │ │ │ ├── README.md │ │ │ ├── __init__.py │ │ │ ├── aes.py │ │ │ ├── blockfeeder.py │ │ │ └── util.py │ │ ├── sslcrypto/ │ │ │ ├── LICENSE │ │ │ ├── __init__.py │ │ │ ├── _aes.py │ │ │ ├── _ecc.py │ │ │ ├── _ripemd.py │ │ │ ├── fallback/ │ │ │ │ ├── __init__.py │ │ │ │ ├── _jacobian.py │ │ │ │ ├── _util.py │ │ │ │ ├── aes.py │ │ │ │ ├── ecc.py │ │ │ │ └── rsa.py │ │ │ └── openssl/ │ │ │ ├── __init__.py │ │ │ ├── aes.py │ │ │ ├── discovery.py │ │ │ ├── ecc.py │ │ │ ├── library.py │ │ │ └── rsa.py │ │ └── subtl/ │ │ ├── LICENCE │ │ ├── README.md │ │ ├── __init__.py │ │ └── subtl.py │ ├── main.py │ └── util/ │ ├── Cached.py │ ├── Diff.py │ ├── Electrum.py │ ├── Event.py │ ├── Flag.py │ ├── GreenletManager.py │ ├── Msgpack.py │ ├── Noparallel.py │ ├── OpensslFindPatch.py │ ├── Platform.py │ ├── Pooled.py │ ├── QueryJson.py │ ├── RateLimit.py │ ├── SafeRe.py │ ├── SocksProxy.py │ ├── ThreadPool.py │ ├── UpnpPunch.py │ ├── __init__.py │ └── helper.py ├── start.py ├── tools/ │ └── coffee/ │ ├── README.md │ ├── coffee-script.js │ ├── coffee.cmd │ └── coffee.wsf ├── update.py └── zeronet.py
Showing preview only (323K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (4145 symbols across 227 files)
FILE: plugins/AnnounceBitTorrent/AnnounceBitTorrentPlugin.py
function importHostClasses (line 20) | def importHostClasses():
class SiteAnnouncerPlugin (line 27) | class SiteAnnouncerPlugin(object):
method getSupportedTrackers (line 28) | def getSupportedTrackers(self):
method getTrackerHandler (line 35) | def getTrackerHandler(self, protocol):
method announceTrackerUdp (line 46) | def announceTrackerUdp(self, tracker_address, mode="start", num_want=10):
method httpRequest (line 73) | def httpRequest(self, url):
method announceTrackerHttps (line 98) | def announceTrackerHttps(self, *args, **kwargs):
method announceTrackerHttp (line 102) | def announceTrackerHttp(self, tracker_address, mode="start", num_want=...
FILE: plugins/AnnounceLocal/AnnounceLocalPlugin.py
class SiteAnnouncerPlugin (line 11) | class SiteAnnouncerPlugin(object):
method announce (line 12) | def announce(self, force=False, *args, **kwargs):
class LocalAnnouncer (line 26) | class LocalAnnouncer(BroadcastServer.BroadcastServer):
method __init__ (line 27) | def __init__(self, server, listen_port):
method discover (line 39) | def discover(self, force=False):
method actionDiscoverRequest (line 51) | def actionDiscoverRequest(self, sender, params):
method actionDiscoverResponse (line 66) | def actionDiscoverResponse(self, sender, params):
method actionSiteListRequest (line 79) | def actionSiteListRequest(self, sender, params):
method actionSiteListResponse (line 92) | def actionSiteListResponse(self, sender, params):
class FileServerPlugin (line 121) | class FileServerPlugin(object):
method __init__ (line 122) | def __init__(self, *args, **kwargs):
method start (line 129) | def start(self, *args, **kwargs):
method stop (line 134) | def stop(self):
class ConfigPlugin (line 142) | class ConfigPlugin(object):
method createArguments (line 143) | def createArguments(self):
FILE: plugins/AnnounceLocal/BroadcastServer.py
class BroadcastServer (line 11) | class BroadcastServer(object):
method __init__ (line 12) | def __init__(self, service_name, listen_port=1544, listen_ip=''):
method createBroadcastSocket (line 21) | def createBroadcastSocket(self):
method start (line 49) | def start(self): # Listens for discover requests
method stop (line 79) | def stop(self):
method send (line 85) | def send(self, addr, message):
method getMyIps (line 97) | def getMyIps(self):
method broadcast (line 100) | def broadcast(self, message, port=None):
method handleMessage (line 120) | def handleMessage(self, addr, message):
FILE: plugins/AnnounceLocal/Test/TestAnnounce.py
function announcer (line 13) | def announcer(file_server, site):
function announcer_remote (line 28) | def announcer_remote(request, site_temp):
class TestAnnounce (line 51) | class TestAnnounce:
method testSenderInfo (line 52) | def testSenderInfo(self, announcer):
method testIgnoreSelfMessages (line 58) | def testIgnoreSelfMessages(self, announcer):
method testDiscoverRequest (line 68) | def testDiscoverRequest(self, announcer, announcer_remote):
method testPeerDiscover (line 86) | def testPeerDiscover(self, announcer, announcer_remote, site):
method testRecentPeerList (line 93) | def testRecentPeerList(self, announcer, announcer_remote, site):
FILE: plugins/AnnounceShare/AnnounceSharePlugin.py
class TrackerStorage (line 14) | class TrackerStorage(object):
method __init__ (line 15) | def __init__(self):
method getDefaultFile (line 22) | def getDefaultFile(self):
method onTrackerFound (line 25) | def onTrackerFound(self, tracker_address, type="shared", my=False):
method onTrackerSuccess (line 46) | def onTrackerSuccess(self, tracker_address, latency):
method onTrackerError (line 55) | def onTrackerError(self, tracker_address):
method getTrackers (line 73) | def getTrackers(self, type="shared"):
method getWorkingTrackers (line 76) | def getWorkingTrackers(self, type="shared"):
method getFileContent (line 83) | def getFileContent(self):
method load (line 93) | def load(self):
method save (line 103) | def save(self):
method discoverTrackers (line 108) | def discoverTrackers(self, peers):
class SiteAnnouncerPlugin (line 143) | class SiteAnnouncerPlugin(object):
method getTrackers (line 144) | def getTrackers(self):
method announceTracker (line 155) | def announceTracker(self, tracker, *args, **kwargs):
class FileRequestPlugin (line 167) | class FileRequestPlugin(object):
method actionGetTrackers (line 168) | def actionGetTrackers(self, params):
class FileServerPlugin (line 174) | class FileServerPlugin(object):
method portCheck (line 175) | def portCheck(self, *args, **kwargs):
class ConfigPlugin (line 185) | class ConfigPlugin(object):
method createArguments (line 186) | def createArguments(self):
FILE: plugins/AnnounceShare/Test/TestAnnounceShare.py
class TestAnnounceShare (line 10) | class TestAnnounceShare:
method testAnnounceList (line 11) | def testAnnounceList(self, file_server):
FILE: plugins/AnnounceZero/AnnounceZeroPlugin.py
function importHostClasses (line 15) | def importHostClasses():
function processPeerRes (line 22) | def processPeerRes(tracker_address, site, peers):
class SiteAnnouncerPlugin (line 49) | class SiteAnnouncerPlugin(object):
method getTrackerHandler (line 50) | def getTrackerHandler(self, protocol):
method announceTrackerZero (line 56) | def announceTrackerZero(self, tracker_address, mode="start", num_want=...
FILE: plugins/Benchmark/BenchmarkDb.py
class ActionsPlugin (line 11) | class ActionsPlugin:
method getBenchmarkTests (line 12) | def getBenchmarkTests(self, online=False):
method getTestDb (line 25) | def getTestDb(self):
method testDbConnect (line 61) | def testDbConnect(self, num_run=1):
method testDbInsert (line 69) | def testDbInsert(self, num_run=1):
method fillTestDb (line 83) | def fillTestDb(self, db):
method testDbInsertMultiuser (line 97) | def testDbInsertMultiuser(self, num_run=1):
method testDbQueryIndexed (line 106) | def testDbQueryIndexed(self, num_run=1):
method testDbQueryNotIndexed (line 124) | def testDbQueryNotIndexed(self, num_run=1):
FILE: plugins/Benchmark/BenchmarkPack.py
class ActionsPlugin (line 11) | class ActionsPlugin:
method createZipFile (line 12) | def createZipFile(self, path):
method testPackZip (line 25) | def testPackZip(self, num_run=1):
method testUnpackZip (line 44) | def testUnpackZip(self, num_run=1):
method createArchiveFile (line 65) | def createArchiveFile(self, path, archive_type="gz"):
method testPackArchive (line 86) | def testPackArchive(self, num_run=1, archive_type="gz"):
method testUnpackArchive (line 113) | def testUnpackArchive(self, num_run=1, archive_type="gz"):
method testPackMsgpack (line 132) | def testPackMsgpack(self, num_run=1):
method testUnpackMsgpack (line 149) | def testUnpackMsgpack(self, num_run=1):
method testUnpackMsgpackStreaming (line 165) | def testUnpackMsgpackStreaming(self, num_run=1, fallback=False):
FILE: plugins/Benchmark/BenchmarkPlugin.py
class UiRequestPlugin (line 21) | class UiRequestPlugin(object):
method actionBenchmark (line 23) | def actionBenchmark(self):
method actionBenchmarkResult (line 43) | def actionBenchmarkResult(self):
class ActionsPlugin (line 66) | class ActionsPlugin:
method getMultiplerTitle (line 67) | def getMultiplerTitle(self, multipler):
method formatResult (line 86) | def formatResult(self, taken, standard):
method getBenchmarkTests (line 98) | def getBenchmarkTests(self, online=False):
method testBenchmark (line 138) | def testBenchmark(self, num_multipler=1, online=False, num_run=None, f...
method testHttps (line 239) | def testHttps(self, num_run=1):
method testCryptHash (line 265) | def testCryptHash(self, num_run=1, hash_type="sha256"):
method testCryptHashlib (line 287) | def testCryptHashlib(self, num_run=1, hash_type="sha3_256"):
method testRandom (line 314) | def testRandom(self, num_run=1):
method testHdPrivatekey (line 328) | def testHdPrivatekey(self, num_run=2):
method testSign (line 343) | def testSign(self, num_run=1):
method testVerify (line 356) | def testVerify(self, num_run=1, lib_verify="sslcrypto"):
method testPortCheckers (line 377) | def testPortCheckers(self):
method testPortChecker (line 392) | def testPortChecker(self, func_name):
method testAll (line 402) | def testAll(self):
class ConfigPlugin (line 411) | class ConfigPlugin(object):
method createArguments (line 412) | def createArguments(self):
FILE: plugins/Bigfile/BigfilePiecefield.py
function packPiecefield (line 4) | def packPiecefield(data):
function unpackPiecefield (line 33) | def unpackPiecefield(data):
function spliceBit (line 50) | def spliceBit(data, idx, bit):
class Piecefield (line 58) | class Piecefield(object):
method tostring (line 59) | def tostring(self):
class BigfilePiecefield (line 63) | class BigfilePiecefield(Piecefield):
method __init__ (line 66) | def __init__(self):
method frombytes (line 69) | def frombytes(self, s):
method tobytes (line 74) | def tobytes(self):
method pack (line 77) | def pack(self):
method unpack (line 80) | def unpack(self, s):
method __getitem__ (line 83) | def __getitem__(self, key):
method __setitem__ (line 89) | def __setitem__(self, key, value):
class BigfilePiecefieldPacked (line 92) | class BigfilePiecefieldPacked(Piecefield):
method __init__ (line 95) | def __init__(self):
method frombytes (line 98) | def frombytes(self, data):
method tobytes (line 103) | def tobytes(self):
method pack (line 106) | def pack(self):
method unpack (line 109) | def unpack(self, data):
method __getitem__ (line 112) | def __getitem__(self, key):
method __setitem__ (line 118) | def __setitem__(self, key, value):
FILE: plugins/Bigfile/BigfilePlugin.py
function importPluginnedClasses (line 31) | def importPluginnedClasses():
class UiRequestPlugin (line 42) | class UiRequestPlugin(object):
method isCorsAllowed (line 43) | def isCorsAllowed(self, path):
method actionBigfileUpload (line 50) | def actionBigfileUpload(self):
method actionBigfileUploadWebsocket (line 67) | def actionBigfileUploadWebsocket(self):
method handleBigfileUpload (line 95) | def handleBigfileUpload(self, upload_info, read):
method readMultipartHeaders (line 147) | def readMultipartHeaders(self, wsgi_input):
method actionFile (line 158) | def actionFile(self, file_path, *args, **kwargs):
class UiWebsocketPlugin (line 171) | class UiWebsocketPlugin(object):
method actionBigfileUploadInit (line 172) | def actionBigfileUploadInit(self, to, inner_path, size, protocol="xhr"):
method actionSiteSetAutodownloadBigfileLimit (line 221) | def actionSiteSetAutodownloadBigfileLimit(self, to, limit):
method actionFileDelete (line 229) | def actionFileDelete(self, to, inner_path):
class ContentManagerPlugin (line 251) | class ContentManagerPlugin(object):
method getFileInfo (line 252) | def getFileInfo(self, inner_path, *args, **kwargs):
method readFile (line 261) | def readFile(self, read_func, size, buff_size=1024 * 64):
method hashBigfile (line 281) | def hashBigfile(self, read_func, size, piece_size=1024 * 1024, file_ou...
method hashFile (line 331) | def hashFile(self, dir_inner_path, file_relative_path, optional=False):
method getPiecemap (line 383) | def getPiecemap(self, inner_path):
method verifyPiece (line 391) | def verifyPiece(self, inner_path, pos, piece):
method verifyFile (line 402) | def verifyFile(self, inner_path, file, ignore_same=True):
method optionalDownloaded (line 411) | def optionalDownloaded(self, inner_path, hash_id, size=None, own=False):
method optionalRemoved (line 433) | def optionalRemoved(self, inner_path, hash_id, size=None):
class SiteStoragePlugin (line 449) | class SiteStoragePlugin(object):
method __init__ (line 450) | def __init__(self, *args, **kwargs):
method createSparseFile (line 459) | def createSparseFile(self, inner_path, size, sha512=None):
method write (line 476) | def write(self, inner_path, content):
method checkBigfile (line 502) | def checkBigfile(self, inner_path):
method openBigfile (line 526) | def openBigfile(self, inner_path, prebuffer=0):
class BigFile (line 533) | class BigFile(object):
method __init__ (line 534) | def __init__(self, site, inner_path, prebuffer=0):
method read (line 549) | def read(self, buff=64 * 1024):
method seek (line 593) | def seek(self, pos, whence=0):
method seekable (line 600) | def seekable(self):
method tell (line 603) | def tell(self):
method close (line 606) | def close(self):
method __enter__ (line 609) | def __enter__(self):
method __exit__ (line 612) | def __exit__(self, exc_type, exc_val, exc_tb):
class WorkerManagerPlugin (line 617) | class WorkerManagerPlugin(object):
method addTask (line 618) | def addTask(self, inner_path, *args, **kwargs):
method taskAddPeer (line 658) | def taskAddPeer(self, task, peer):
class FileRequestPlugin (line 671) | class FileRequestPlugin(object):
method isReadable (line 672) | def isReadable(self, site, inner_path, file, pos):
method actionGetPiecefields (line 685) | def actionGetPiecefields(self, params):
method actionSetPiecefields (line 699) | def actionSetPiecefields(self, params):
class PeerPlugin (line 720) | class PeerPlugin(object):
method __getattr__ (line 721) | def __getattr__(self, key):
method updatePiecefields (line 732) | def updatePiecefields(self, force=False):
method sendMyHashfield (line 754) | def sendMyHashfield(self, *args, **kwargs):
method updateHashfield (line 757) | def updateHashfield(self, *args, **kwargs):
method getFile (line 766) | def getFile(self, site, inner_path, *args, **kwargs):
class SitePlugin (line 776) | class SitePlugin(object):
method isFileDownloadAllowed (line 777) | def isFileDownloadAllowed(self, inner_path, file_info):
method getSettingsCache (line 791) | def getSettingsCache(self):
method needFile (line 797) | def needFile(self, inner_path, *args, **kwargs):
class ConfigPlugin (line 837) | class ConfigPlugin(object):
method createArguments (line 838) | def createArguments(self):
FILE: plugins/Bigfile/Test/TestBigfile.py
class TestBigfile (line 21) | class TestBigfile:
method createBigfile (line 25) | def createBigfile(self, site, inner_path="data/optional.any.iso", piec...
method testPiecemapCreate (line 33) | def testPiecemapCreate(self, site):
method testVerifyPiece (line 47) | def testVerifyPiece(self, site):
method testSparseFile (line 67) | def testSparseFile(self, site):
method testRangedFileRequest (line 95) | def testRangedFileRequest(self, file_server, site, site_temp):
method testRangedFileDownload (line 117) | def testRangedFileDownload(self, file_server, site, site_temp):
method testOpenBigfile (line 162) | def testOpenBigfile(self, file_server, site, site_temp):
method testPiecefield (line 222) | def testPiecefield(self, piecefield_obj, site):
method testFileGet (line 245) | def testFileGet(self, file_server, site, site_temp):
method benchmarkPeerMemory (line 277) | def benchmarkPeerMemory(self, site, file_server):
method testUpdatePiecefield (line 292) | def testUpdatePiecefield(self, file_server, site, site_temp):
method testWorkerManagerPiecefieldDeny (line 309) | def testWorkerManagerPiecefieldDeny(self, file_server, site, site_temp):
method testWorkerManagerPiecefieldDownload (line 337) | def testWorkerManagerPiecefieldDownload(self, file_server, site, site_...
method testDownloadStats (line 370) | def testDownloadStats(self, file_server, site, site_temp):
method testPrebuffer (line 407) | def testPrebuffer(self, file_server, site, site_temp):
method testDownloadAllPieces (line 443) | def testDownloadAllPieces(self, file_server, site, site_temp):
method testFileSize (line 472) | def testFileSize(self, file_server, site, site_temp):
method testFileRename (line 497) | def testFileRename(self, file_server, site, site_temp):
method testNullFileRead (line 548) | def testNullFileRead(self, file_server, site, site_temp, size):
FILE: plugins/Chart/ChartCollector.py
class ChartCollector (line 12) | class ChartCollector(object):
method __init__ (line 13) | def __init__(self, db):
method setInitialLastValues (line 20) | def setInitialLastValues(self, sites):
method getCollectors (line 26) | def getCollectors(self):
method getSiteCollectors (line 81) | def getSiteCollectors(self):
method getUniquePeers (line 103) | def getUniquePeers(self):
method collectDatas (line 110) | def collectDatas(self, collectors, last_values, site=None):
method collectGlobal (line 140) | def collectGlobal(self, collectors, last_values):
method collectSites (line 154) | def collectSites(self, sites, collectors, last_values):
method collector (line 170) | def collector(self):
FILE: plugins/Chart/ChartDb.py
class ChartDb (line 6) | class ChartDb(Db):
method __init__ (line 7) | def __init__(self):
method getSchema (line 15) | def getSchema(self):
method getTypeId (line 49) | def getTypeId(self, name):
method getSiteId (line 56) | def getSiteId(self, address):
method loadSites (line 63) | def loadSites(self):
method loadTypes (line 69) | def loadTypes(self):
method deleteSite (line 75) | def deleteSite(self, address):
method archive (line 82) | def archive(self):
FILE: plugins/Chart/ChartPlugin.py
class SiteManagerPlugin (line 20) | class SiteManagerPlugin(object):
method load (line 21) | def load(self, *args, **kwargs):
method delete (line 26) | def delete(self, address, *args, **kwargs):
class UiWebsocketPlugin (line 31) | class UiWebsocketPlugin(object):
method actionChartDbQuery (line 33) | def actionChartDbQuery(self, to, query, params=None):
method actionChartGetPeerLocations (line 52) | def actionChartGetPeerLocations(self, to):
FILE: plugins/ContentFilter/ContentFilterPlugin.py
class SiteManagerPlugin (line 21) | class SiteManagerPlugin(object):
method load (line 22) | def load(self, *args, **kwargs):
method add (line 27) | def add(self, address, *args, **kwargs):
class UiWebsocketPlugin (line 47) | class UiWebsocketPlugin(object):
method cbMuteAdd (line 49) | def cbMuteAdd(self, to, auth_address, cert_user_id, reason):
method actionMuteAdd (line 58) | def actionMuteAdd(self, to, auth_address, cert_user_id, reason):
method cbMuteRemove (line 69) | def cbMuteRemove(self, to, auth_address):
method actionMuteRemove (line 76) | def actionMuteRemove(self, to, auth_address):
method actionMuteList (line 88) | def actionMuteList(self, to):
method actionSiteblockIgnoreAddSite (line 94) | def actionSiteblockIgnoreAddSite(self, to, site_address):
method actionSiteblockAdd (line 105) | def actionSiteblockAdd(self, to, site_address, reason=None):
method actionSiteblockRemove (line 112) | def actionSiteblockRemove(self, to, site_address):
method actionSiteblockList (line 118) | def actionSiteblockList(self, to):
method actionSiteblockGet (line 122) | def actionSiteblockGet(self, to, site_address):
method actionFilterIncludeAdd (line 135) | def actionFilterIncludeAdd(self, to, inner_path, description=None, add...
method cbFilterIncludeAdd (line 158) | def cbFilterIncludeAdd(self, to, res, address, inner_path, description):
method actionFilterIncludeRemove (line 167) | def actionFilterIncludeRemove(self, to, inner_path, address=None):
method actionFilterIncludeList (line 180) | def actionFilterIncludeList(self, to, all_sites=False, filters=False):
class SiteStoragePlugin (line 202) | class SiteStoragePlugin(object):
method updateDbFile (line 203) | def updateDbFile(self, inner_path, file=None, cur=None):
method onUpdated (line 215) | def onUpdated(self, inner_path, file=None):
class UiRequestPlugin (line 224) | class UiRequestPlugin(object):
method actionWrapper (line 225) | def actionWrapper(self, path, extra_headers=None):
method actionUiMedia (line 257) | def actionUiMedia(self, path, *args, **kwargs):
FILE: plugins/ContentFilter/ContentFilterStorage.py
class ContentFilterStorage (line 14) | class ContentFilterStorage(object):
method __init__ (line 15) | def __init__(self, site_manager):
method load (line 37) | def load(self):
method includeUpdateAll (line 51) | def includeUpdateAll(self, update_site_dbs=True):
method includeAdd (line 93) | def includeAdd(self, address, inner_path, description=None):
method includeRemove (line 103) | def includeRemove(self, address, inner_path):
method save (line 108) | def save(self):
method isMuted (line 113) | def isMuted(self, auth_address):
method getSiteAddressHashed (line 119) | def getSiteAddressHashed(self, address):
method isSiteblocked (line 122) | def isSiteblocked(self, address):
method getSiteblockDetails (line 127) | def getSiteblockDetails(self, address):
method changeDbs (line 148) | def changeDbs(self, auth_address, action):
FILE: plugins/ContentFilter/Test/TestContentFilter.py
function filter_storage (line 7) | def filter_storage():
class TestContentFilter (line 14) | class TestContentFilter:
method createInclude (line 15) | def createInclude(self, site):
method testIncludeLoad (line 21) | def testIncludeLoad(self, site, filter_storage):
method testIncludeAdd (line 35) | def testIncludeAdd(self, site, filter_storage):
method testIncludeChange (line 56) | def testIncludeChange(self, site, filter_storage):
FILE: plugins/ContentFilter/media/js/ZeroFrame.js
constant CMD_INNER_READY (line 5) | const CMD_INNER_READY = 'innerReady'
constant CMD_RESPONSE (line 6) | const CMD_RESPONSE = 'response'
constant CMD_WRAPPER_READY (line 7) | const CMD_WRAPPER_READY = 'wrapperReady'
constant CMD_PING (line 8) | const CMD_PING = 'ping'
constant CMD_PONG (line 9) | const CMD_PONG = 'pong'
constant CMD_WRAPPER_OPENED_WEBSOCKET (line 10) | const CMD_WRAPPER_OPENED_WEBSOCKET = 'wrapperOpenedWebsocket'
constant CMD_WRAPPER_CLOSE_WEBSOCKET (line 11) | const CMD_WRAPPER_CLOSE_WEBSOCKET = 'wrapperClosedWebsocket'
class ZeroFrame (line 13) | class ZeroFrame {
method constructor (line 14) | constructor(url) {
method init (line 23) | init() {
method connect (line 27) | connect() {
method onMessage (line 33) | onMessage(e) {
method onRequest (line 56) | onRequest(cmd, message) {
method response (line 60) | response(to, result) {
method cmd (line 68) | cmd(cmd, params={}, cb=null) {
method cmdp (line 75) | cmdp(cmd, params={}) {
method send (line 87) | send(message, cb=null) {
method log (line 97) | log(...args) {
method onOpenWebsocket (line 101) | onOpenWebsocket() {
method onCloseWebsocket (line 105) | onCloseWebsocket() {
method monkeyPatchAjax (line 109) | monkeyPatchAjax() {
FILE: plugins/Cors/CorsPlugin.py
function getCorsPath (line 17) | def getCorsPath(site, inner_path):
class UiWebsocketPlugin (line 31) | class UiWebsocketPlugin(object):
method hasSitePermission (line 32) | def hasSitePermission(self, address, cmd=None):
method corsFuncWrapper (line 46) | def corsFuncWrapper(self, func_name, to, inner_path, *args, **kwargs):
method actionFileGet (line 62) | def actionFileGet(self, to, inner_path, *args, **kwargs):
method actionFileList (line 65) | def actionFileList(self, to, inner_path, *args, **kwargs):
method actionDirList (line 68) | def actionDirList(self, to, inner_path, *args, **kwargs):
method actionFileRules (line 71) | def actionFileRules(self, to, inner_path, *args, **kwargs):
method actionOptionalFileInfo (line 74) | def actionOptionalFileInfo(self, to, inner_path, *args, **kwargs):
method actionCorsPermission (line 77) | def actionCorsPermission(self, to, address):
method cbCorsPermission (line 109) | def cbCorsPermission(self, to, addresses):
class UiRequestPlugin (line 128) | class UiRequestPlugin(object):
method parsePath (line 130) | def parsePath(self, path):
FILE: plugins/CryptMessage/CryptMessage.py
function eciesEncrypt (line 11) | def eciesEncrypt(data, pubkey, ciphername="aes-256-cbc"):
function eciesDecryptMulti (line 23) | def eciesDecryptMulti(encrypted_datas, privatekey):
function eciesDecrypt (line 34) | def eciesDecrypt(ciphertext, privatekey):
function decodePubkey (line 38) | def decodePubkey(pubkey):
function split (line 53) | def split(encrypted):
FILE: plugins/CryptMessage/CryptMessagePlugin.py
class UiWebsocketPlugin (line 17) | class UiWebsocketPlugin(object):
method actionUserPublickey (line 22) | def actionUserPublickey(self, to, index=0):
method actionEciesEncrypt (line 27) | def actionEciesEncrypt(self, to, text, publickey=0, return_aes_key=Fal...
method actionEciesDecrypt (line 38) | def actionEciesDecrypt(self, to, param, privatekey=0):
method actionAesEncrypt (line 56) | def actionAesEncrypt(self, to, text, key=None):
method actionAesDecrypt (line 72) | def actionAesDecrypt(self, to, *args):
method actionEcdsaSign (line 100) | def actionEcdsaSign(self, to, data, privatekey=None):
method actionEcdsaVerify (line 108) | def actionEcdsaVerify(self, to, data, address, signature):
method actionEccPrivToPub (line 112) | def actionEccPrivToPub(self, to, privatekey):
method actionEccPubToAddr (line 116) | def actionEccPubToAddr(self, to, publickey):
class UserPlugin (line 121) | class UserPlugin(object):
method getEncryptPrivatekey (line 122) | def getEncryptPrivatekey(self, address, param_index=0):
method getEncryptPublickey (line 140) | def getEncryptPublickey(self, address, param_index=0):
class ActionsPlugin (line 159) | class ActionsPlugin:
method getBenchmarkTests (line 164) | def getBenchmarkTests(self, online=False):
method testCryptEciesEncrypt (line 180) | def testCryptEciesEncrypt(self, num_run=1):
method testCryptEciesDecrypt (line 186) | def testCryptEciesDecrypt(self, num_run=1):
method testCryptEciesDecryptMulti (line 194) | def testCryptEciesDecryptMulti(self, num_run=1):
method testCryptAesEncrypt (line 212) | def testCryptAesEncrypt(self, num_run=1):
method testCryptAesDecrypt (line 218) | def testCryptAesDecrypt(self, num_run=1):
FILE: plugins/CryptMessage/Test/TestCrypt.py
class TestCrypt (line 7) | class TestCrypt:
method testEncryptEcies (line 15) | def testEncryptEcies(self, text, text_repeat):
method testDecryptEcies (line 23) | def testDecryptEcies(self, user):
method testPublickey (line 26) | def testPublickey(self, ui_websocket):
method testEcies (line 46) | def testEcies(self, ui_websocket):
method testEciesUtf8 (line 68) | def testEciesUtf8(self, ui_websocket):
method testEciesAes (line 76) | def testEciesAes(self, ui_websocket):
method testEciesAesLongpubkey (line 90) | def testEciesAesLongpubkey(self, ui_websocket):
method testAes (line 105) | def testAes(self, ui_websocket):
method testAesUtf8 (line 131) | def testAesUtf8(self, ui_websocket):
FILE: plugins/FilePack/FilePackPlugin.py
function closeArchive (line 14) | def closeArchive(archive_path):
function openArchive (line 19) | def openArchive(archive_path, file_obj=None):
function openArchiveFile (line 33) | def openArchiveFile(archive_path, path_within, file_obj=None):
class UiRequestPlugin (line 42) | class UiRequestPlugin(object):
method actionSiteMedia (line 43) | def actionSiteMedia(self, path, **kwargs):
method streamFile (line 85) | def streamFile(self, file):
class SiteStoragePlugin (line 99) | class SiteStoragePlugin(object):
method isFile (line 100) | def isFile(self, inner_path):
method openArchive (line 108) | def openArchive(self, inner_path):
method walk (line 128) | def walk(self, inner_path, *args, **kwags):
method list (line 152) | def list(self, inner_path, *args, **kwags):
method read (line 179) | def read(self, inner_path, mode="rb", **kwargs):
FILE: plugins/MergerSite/MergerSitePlugin.py
function checkMergerPath (line 31) | def checkMergerPath(address, inner_path):
class UiWebsocketPlugin (line 56) | class UiWebsocketPlugin(object):
method actionMergerSiteAdd (line 58) | def actionMergerSiteAdd(self, to, addresses):
method cbMergerSiteAdd (line 79) | def cbMergerSiteAdd(self, to, addresses):
method actionMergerSiteDelete (line 94) | def actionMergerSiteDelete(self, to, address):
method actionMergerSiteList (line 109) | def actionMergerSiteList(self, to, query_site_info=False):
method hasSitePermission (line 124) | def hasSitePermission(self, address, *args, **kwargs):
method mergerFuncWrapper (line 134) | def mergerFuncWrapper(self, func_name, to, inner_path, *args, **kwargs):
method actionFileList (line 152) | def actionFileList(self, to, inner_path, *args, **kwargs):
method actionDirList (line 155) | def actionDirList(self, to, inner_path, *args, **kwargs):
method actionFileGet (line 158) | def actionFileGet(self, to, inner_path, *args, **kwargs):
method actionFileWrite (line 161) | def actionFileWrite(self, to, inner_path, *args, **kwargs):
method actionFileDelete (line 164) | def actionFileDelete(self, to, inner_path, *args, **kwargs):
method actionFileRules (line 167) | def actionFileRules(self, to, inner_path, *args, **kwargs):
method actionFileNeed (line 170) | def actionFileNeed(self, to, inner_path, *args, **kwargs):
method actionOptionalFileInfo (line 173) | def actionOptionalFileInfo(self, to, inner_path, *args, **kwargs):
method actionOptionalFileDelete (line 176) | def actionOptionalFileDelete(self, to, inner_path, *args, **kwargs):
method actionBigfileUploadInit (line 179) | def actionBigfileUploadInit(self, to, inner_path, *args, **kwargs):
method mergerFuncWrapperWithPrivatekey (line 187) | def mergerFuncWrapperWithPrivatekey(self, func_name, to, privatekey, i...
method actionSiteSign (line 208) | def actionSiteSign(self, to, privatekey=None, inner_path="content.json...
method actionSitePublish (line 211) | def actionSitePublish(self, to, privatekey=None, inner_path="content.j...
method actionPermissionAdd (line 214) | def actionPermissionAdd(self, to, permission):
method actionPermissionDetails (line 219) | def actionPermissionDetails(self, to, permission):
class UiRequestPlugin (line 243) | class UiRequestPlugin(object):
method parsePath (line 245) | def parsePath(self, path):
class SiteStoragePlugin (line 254) | class SiteStoragePlugin(object):
method getDbFiles (line 256) | def getDbFiles(self):
method onUpdated (line 300) | def onUpdated(self, inner_path, file=None):
class SitePlugin (line 319) | class SitePlugin(object):
method fileDone (line 320) | def fileDone(self, inner_path):
method fileFailed (line 329) | def fileFailed(self, inner_path):
class SiteManagerPlugin (line 340) | class SiteManagerPlugin(object):
method updateMergerSites (line 342) | def updateMergerSites(self):
method load (line 393) | def load(self, *args, **kwags):
method saveDelayed (line 397) | def saveDelayed(self, *args, **kwags):
FILE: plugins/Newsfeed/NewsfeedPlugin.py
class UiWebsocketPlugin (line 12) | class UiWebsocketPlugin(object):
method formatSiteInfo (line 13) | def formatSiteInfo(self, site, create_user=True):
method actionFeedFollow (line 22) | def actionFeedFollow(self, to, feeds):
method actionFeedListFollow (line 27) | def actionFeedListFollow(self, to):
method actionFeedQuery (line 32) | def actionFeedQuery(self, to, limit=10, day_limit=3):
method parseSearch (line 96) | def parseSearch(self, search):
method actionFeedSearch (line 107) | def actionFeedSearch(self, to, search, limit=30, day_limit=30):
class UserPlugin (line 181) | class UserPlugin(object):
method setFeedFollow (line 183) | def setFeedFollow(self, address, feeds):
FILE: plugins/OptionalManager/ContentDbPlugin.py
class ContentDbPlugin (line 18) | class ContentDbPlugin(object):
method __init__ (line 19) | def __init__(self, *args, **kwargs):
method getSchema (line 31) | def getSchema(self):
method initSite (line 59) | def initSite(self, site):
method checkTables (line 64) | def checkTables(self):
method loadFilesOptional (line 71) | def loadFilesOptional(self):
method isOptionalFile (line 116) | def isOptionalFile(self, site_id, inner_path):
method fillTableFileOptional (line 120) | def fillTableFileOptional(self, site):
method setContentFilesOptional (line 153) | def setContentFilesOptional(self, site, content_inner_path, content, c...
method setContent (line 189) | def setContent(self, site, inner_path, content, size=0):
method deleteContent (line 204) | def deleteContent(self, site, inner_path):
method updatePeerNumbers (line 216) | def updatePeerNumbers(self):
method queryDeletableFiles (line 268) | def queryDeletableFiles(self):
method getOptionalLimitBytes (line 324) | def getOptionalLimitBytes(self):
method getOptionalUsedWhere (line 332) | def getOptionalUsedWhere(self):
method getOptionalUsedBytes (line 346) | def getOptionalUsedBytes(self):
method getOptionalNeedDelete (line 352) | def getOptionalNeedDelete(self, size):
method checkOptionalLimit (line 360) | def checkOptionalLimit(self, limit=None):
class SiteManagerPlugin (line 408) | class SiteManagerPlugin(object):
method load (line 409) | def load(self, *args, **kwargs):
FILE: plugins/OptionalManager/OptionalManagerPlugin.py
function importPluginnedClasses (line 14) | def importPluginnedClasses():
function processAccessLog (line 19) | def processAccessLog():
function processRequestLog (line 41) | def processRequestLog():
class ContentManagerPlugin (line 70) | class ContentManagerPlugin(object):
method __init__ (line 71) | def __init__(self, *args, **kwargs):
method optionalDownloaded (line 75) | def optionalDownloaded(self, inner_path, hash_id, size=None, own=False):
method optionalRemoved (line 88) | def optionalRemoved(self, inner_path, hash_id, size=None):
method optionalRenamed (line 104) | def optionalRenamed(self, inner_path_old, inner_path_new):
method isDownloaded (line 113) | def isDownloaded(self, inner_path=None, hash_id=None, force_check_db=F...
method isPinned (line 133) | def isPinned(self, inner_path):
method setPin (line 154) | def setPin(self, inner_path, is_pinned):
method optionalDelete (line 160) | def optionalDelete(self, inner_path):
class WorkerManagerPlugin (line 169) | class WorkerManagerPlugin(object):
method doneTask (line 170) | def doneTask(self, task):
class UiRequestPlugin (line 178) | class UiRequestPlugin(object):
method parsePath (line 179) | def parsePath(self, path):
class FileRequestPlugin (line 191) | class FileRequestPlugin(object):
method actionGetFile (line 192) | def actionGetFile(self, params):
method actionStreamFile (line 197) | def actionStreamFile(self, params):
method recordFileRequest (line 202) | def recordFileRequest(self, site_address, inner_path, stats):
class SitePlugin (line 212) | class SitePlugin(object):
method isDownloadable (line 213) | def isDownloadable(self, inner_path):
method fileForgot (line 224) | def fileForgot(self, inner_path):
method fileDone (line 231) | def fileDone(self, inner_path):
class ConfigPlugin (line 247) | class ConfigPlugin(object):
method createArguments (line 248) | def createArguments(self):
FILE: plugins/OptionalManager/Test/TestOptionalManager.py
class TestOptionalManager (line 7) | class TestOptionalManager:
method testDbFill (line 8) | def testDbFill(self, site):
method testSetContent (line 13) | def testSetContent(self, site):
method testDeleteContent (line 33) | def testDeleteContent(self, site):
method testVerifyFiles (line 39) | def testVerifyFiles(self, site):
method testVerifyFilesSameHashId (line 68) | def testVerifyFilesSameHashId(self, site):
method testIsPinned (line 104) | def testIsPinned(self, site):
method testBigfilePieceReset (line 113) | def testBigfilePieceReset(self, site):
method testOptionalDelete (line 123) | def testOptionalDelete(self, site):
method testOptionalRename (line 141) | def testOptionalRename(self, site):
FILE: plugins/OptionalManager/UiWebsocketPlugin.py
class UiWebsocketPlugin (line 24) | class UiWebsocketPlugin(object):
method __init__ (line 25) | def __init__(self, *args, **kwargs):
method actionSiteSign (line 29) | def actionSiteSign(self, to, privatekey=None, inner_path="content.json...
method updatePeerNumbers (line 43) | def updatePeerNumbers(self):
method addBigfileInfo (line 49) | def addBigfileInfo(self, row):
method actionOptionalFileList (line 113) | def actionOptionalFileList(self, to, address=None, orderby="time_downl...
method actionOptionalFileInfo (line 187) | def actionOptionalFileInfo(self, to, inner_path):
method setPin (line 209) | def setPin(self, inner_path, is_pinned, address=None):
method actionOptionalFilePin (line 222) | def actionOptionalFilePin(self, to, inner_path, address=None):
method actionOptionalFileUnpin (line 235) | def actionOptionalFileUnpin(self, to, inner_path, address=None):
method actionOptionalFileDelete (line 248) | def actionOptionalFileDelete(self, to, inner_path, address=None):
method actionOptionalLimitStats (line 286) | def actionOptionalLimitStats(self, to):
method actionOptionalLimitSet (line 296) | def actionOptionalLimitSet(self, to, limit):
method actionOptionalHelpList (line 303) | def actionOptionalHelpList(self, to, address=None):
method actionOptionalHelp (line 315) | def actionOptionalHelp(self, to, directory, title, address=None):
method actionOptionalHelpRemove (line 352) | def actionOptionalHelpRemove(self, to, directory, address=None):
method cbOptionalHelpAll (line 367) | def cbOptionalHelpAll(self, to, site, value):
method actionOptionalHelpAll (line 372) | def actionOptionalHelpAll(self, to, value, address=None):
FILE: plugins/PeerDb/PeerDbPlugin.py
class ContentDbPlugin (line 11) | class ContentDbPlugin(object):
method __init__ (line 12) | def __init__(self, *args, **kwargs):
method getSchema (line 16) | def getSchema(self):
method loadPeers (line 37) | def loadPeers(self, site):
method iteratePeers (line 60) | def iteratePeers(self, site):
method savePeers (line 70) | def savePeers(self, site, spawn=False):
method initSite (line 90) | def initSite(self, site):
method saveAllPeers (line 95) | def saveAllPeers(self):
FILE: plugins/Sidebar/ConsolePlugin.py
class WsLogStreamer (line 11) | class WsLogStreamer(logging.StreamHandler):
method __init__ (line 12) | def __init__(self, stream_id, ui_websocket, filter):
method emit (line 24) | def emit(self, record):
method stop (line 34) | def stop(self):
class UiWebsocketPlugin (line 39) | class UiWebsocketPlugin(object):
method __init__ (line 40) | def __init__(self, *args, **kwargs):
method actionConsoleLogRead (line 46) | def actionConsoleLogRead(self, to, filter=None, read_size=32 * 1024, l...
method addLogStreamer (line 78) | def addLogStreamer(self, stream_id, filter=None):
method actionConsoleLogStream (line 88) | def actionConsoleLogStream(self, to, filter=None):
method actionConsoleLogStreamRemove (line 95) | def actionConsoleLogStreamRemove(self, to, stream_id):
FILE: plugins/Sidebar/SidebarPlugin.py
class UiRequestPlugin (line 32) | class UiRequestPlugin(object):
method actionUiMedia (line 34) | def actionUiMedia(self, path):
method actionZip (line 66) | def actionZip(self):
method streamZip (line 79) | def streamZip(self, dir_path):
class UiWebsocketPlugin (line 89) | class UiWebsocketPlugin(object):
method sidebarRenderPeerStats (line 90) | def sidebarRenderPeerStats(self, body, site):
method sidebarRenderTransferStats (line 146) | def sidebarRenderTransferStats(self, body, site):
method sidebarRenderFileStats (line 171) | def sidebarRenderFileStats(self, body, site):
method sidebarRenderSizeLimit (line 270) | def sidebarRenderSizeLimit(self, body, site):
method sidebarRenderOptionalFileStats (line 284) | def sidebarRenderOptionalFileStats(self, body, site):
method sidebarRenderOptionalFileSettings (line 312) | def sidebarRenderOptionalFileSettings(self, body, site):
method sidebarRenderBadFiles (line 336) | def sidebarRenderBadFiles(self, body, site):
method sidebarRenderDbOptions (line 363) | def sidebarRenderDbOptions(self, body, site):
method sidebarRenderIdentity (line 384) | def sidebarRenderIdentity(self, body, site):
method sidebarRenderControls (line 408) | def sidebarRenderControls(self, body, site):
method sidebarRenderOwnedCheckbox (line 455) | def sidebarRenderOwnedCheckbox(self, body, site):
method sidebarRenderOwnSettings (line 466) | def sidebarRenderOwnSettings(self, body, site):
method sidebarRenderContents (line 486) | def sidebarRenderContents(self, body, site):
method actionSidebarGetHtmlTag (line 516) | def actionSidebarGetHtmlTag(self, to):
method downloadGeoLiteDb (line 556) | def downloadGeoLiteDb(self, db_path):
method getLoc (line 608) | def getLoc(self, geodb, ip):
method getGeoipDb (line 637) | def getGeoipDb(self):
method getPeerLocations (line 658) | def getPeerLocations(self, peers):
method actionSidebarGetPeers (line 709) | def actionSidebarGetPeers(self, to):
method actionSiteSetOwned (line 740) | def actionSiteSetOwned(self, to, owned):
method actionSiteRecoverPrivatekey (line 750) | def actionSiteRecoverPrivatekey(self, to):
method actionUserSetSitePrivatekey (line 774) | def actionUserSetSitePrivatekey(self, to, privatekey):
method actionSiteSetAutodownloadoptional (line 784) | def actionSiteSetAutodownloadoptional(self, to, owned):
method actionDbReload (line 790) | def actionDbReload(self, to):
method actionDbRebuild (line 798) | def actionDbRebuild(self, to):
FILE: plugins/Sidebar/ZipStream.py
class ZipStream (line 5) | class ZipStream(object):
method __init__ (line 6) | def __init__(self, dir_path):
method getFileList (line 14) | def getFileList(self):
method read (line 22) | def read(self, size=60 * 1024):
method write (line 34) | def write(self, data):
method tell (line 38) | def tell(self):
method seek (line 41) | def seek(self, pos, whence=0):
method flush (line 46) | def flush(self):
FILE: plugins/Sidebar/media/Scrollable.js
function calculateScrollerHeight (line 14) | function calculateScrollerHeight() {
function moveScroller (line 24) | function moveScroller(evt) {
function startDrag (line 31) | function startDrag(evt) {
function stopDrag (line 39) | function stopDrag(evt) {
function scrollBarScroll (line 44) | function scrollBarScroll(evt) {
function updateHeight (line 53) | function updateHeight() {
function createScroller (line 58) | function createScroller() {
FILE: plugins/Sidebar/media/all.js
function Class (line 10) | function Class() {}
function ctor (line 64) | function ctor() { this.constructor = child; }
function Console (line 70) | function Console(sidebar) {
function Menu (line 370) | function Menu(button) {
function calculateScrollerHeight (line 522) | function calculateScrollerHeight() {
function moveScroller (line 532) | function moveScroller(evt) {
function startDrag (line 539) | function startDrag(evt) {
function stopDrag (line 547) | function stopDrag(evt) {
function scrollBarScroll (line 552) | function scrollBarScroll(evt) {
function updateHeight (line 561) | function updateHeight() {
function createScroller (line 566) | function createScroller() {
function ctor (line 607) | function ctor() { this.constructor = child; }
function Sidebar (line 614) | function Sidebar(wrapper1) {
function s (line 1431) | function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&re...
function noop (line 1466) | function noop() {}
function morphAttrs (line 1476) | function morphAttrs(fromNode, toNode) {
function moveChildren (line 1515) | function moveChildren(from, to) {
function morphdom (line 1525) | function morphdom(fromNode, toNode, options) {
FILE: plugins/Sidebar/media/morphdom.js
function s (line 1) | function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&re...
function noop (line 36) | function noop() {}
function morphAttrs (line 46) | function morphAttrs(fromNode, toNode) {
function moveChildren (line 85) | function moveChildren(from, to) {
function morphdom (line 95) | function morphdom(fromNode, toNode, options) {
FILE: plugins/Sidebar/media_globe/all.js
function init (line 178) | function init() {
function addData (line 263) | function addData(data, opts) {
function createPoints (line 317) | function createPoints() {
function addPoint (line 345) | function addPoint(lat, lng, size, color, subgeo) {
function onMouseDown (line 370) | function onMouseDown(event) {
function onMouseMove (line 386) | function onMouseMove(event) {
function onMouseUp (line 399) | function onMouseUp(event) {
function onMouseOut (line 406) | function onMouseOut(event) {
function onMouseWheel (line 412) | function onMouseWheel(event) {
function onDocumentKeyDown (line 425) | function onDocumentKeyDown(event) {
function onWindowResize (line 438) | function onWindowResize( event ) {
function zoom (line 444) | function zoom(delta) {
function animate (line 450) | function animate() {
function render (line 456) | function render() {
function unload (line 472) | function unload() {
method x (line 552) | get x(){return this._x}
method x (line 552) | set x(a){this._x=a;this.onChangeCallback()}
method y (line 552) | get y(){return this._y}
method y (line 552) | set y(a){this._y=a;this.onChangeCallback()}
method z (line 552) | get z(){return this._z}
method z (line 552) | set z(a){this._z=a;this.onChangeCallback()}
method w (line 552) | get w(){return this._w}
method w (line 552) | set w(a){this._w=a;this.onChangeCallback()}
method x (line 596) | get x(){return this._x}
method x (line 596) | set x(a){this._x=a;this.onChangeCallback()}
method y (line 596) | get y(){return this._y}
method y (line 596) | set y(a){this._y=a;this.onChangeCallback()}
method z (line 596) | get z(){return this._z}
method z (line 596) | set z(a){this._z=a;this.onChangeCallback()}
method order (line 596) | get order(){return this._order}
method order (line 596) | set order(a){this._order=a;this.onChangeCallback()}
function b (line 672) | function b(a,b,c,d,e,f,g){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*g+(-...
method eulerOrder (line 689) | get eulerOrder(){console.warn("THREE.Object3D: .eulerOrder has been move...
method eulerOrder (line 689) | set eulerOrder(a){console.warn("THREE.Object3D: .eulerOrder has been mov...
method useQuaternion (line 689) | get useQuaternion(){console.warn("THREE.Object3D: .useQuaternion has bee...
method useQuaternion (line 689) | set useQuaternion(a){console.warn("THREE.Object3D: .useQuaternion has be...
method length (line 708) | get length(){return this.array.length}
function a (line 724) | function a(a,b,c){q.fromArray(d,3*a);m.fromArray(d,3*b);r.fromArray(d,3*...
function b (line 724) | function b(a){ya.fromArray(e,
function a (line 749) | function a(a,b,c){return c?a|1<<b:a&~(1<<b)}
function b (line 749) | function b(a){var b=a.x.toString()+a.y.toString()+a.z.toString();if(void...
function c (line 749) | function c(a){var b=a.r.toString()+a.g.toString()+a.b.toString();if(void...
function d (line 749) | function d(a){var b=a.x.toString()+a.y.toString();if(void 0!==r[b])retur...
function c (line 779) | function c(a){a=Math.log(a)/Math.LN2;return Math.pow(2,Math.round(a))}
function d (line 779) | function d(a,
function e (line 781) | function e(a){return(255*a[0]<<16)+(255*a[1]<<8)+255*a[2]}
method needsUpdate (line 856) | get needsUpdate(){return this._needsUpdate}
method needsUpdate (line 856) | set needsUpdate(a){!0===a&&this.update();this._needsUpdate=a}
function b (line 966) | function b(a){var b=a.geometry;a=a.material;var c=b.vertices.length;if(a...
function c (line 967) | function c(a,b){var c=b.geometry,e=a.faces3,f=3*e.length,g=1*e.length,h=...
function d (line 970) | function d(a,b){return a.material instanceof THREE.MeshFaceMaterial?a.ma...
function e (line 970) | function e(a,b,c,d){c=c.attributes;var e=b.attributes;b=b.attributesKeys...
function f (line 971) | function f(){for(var a=0,b=wb.length;a<b;a++)wb[a]=0}
function g (line 971) | function g(a){wb[a]=1;0===ib[a]&&(l.enableVertexAttribArray(a),ib[a]=1)}
function h (line 971) | function h(){for(var a=0,b=ib.length;a<b;a++)ib[a]!==wb[a]&&(l.disableVe...
function k (line 971) | function k(a,b){return a.material.id!==b.material.id?b.material.id-a.mat...
function n (line 971) | function n(a,b){return a.z!==b.z?a.z-b.z:a.id-b.id}
function p (line 971) | function p(a,b){return b[0]-
function q (line 972) | function q(a,e){if(!1!==e.visible){if(!(e instanceof THREE.Scene||e inst...
function m (line 1002) | function m(a,
function r (line 1003) | function r(a,b,c,d,e,f,g){for(var h,k=0,l=a.length;k<l;k++){h=a[k];
function t (line 1004) | function t(a){var b=a.object.material;b.transparent?(a.transparent=b,a.o...
function s (line 1004) | function s(a,b,d){var e=b.material,f=!1;if(void 0===xb[d.id]||!0===d.gro...
function u (line 1008) | function u(a,b,c){var d=c.id;a[d]=a[d]||[];a[d].push({id:d,buffer:b,obje...
function v (line 1008) | function v(a){for(var b in a.attributes)if(a.attributes[b].needsUpdate)r...
function y (line 1008) | function y(a){for(var b in a.attributes)a.attributes[b].needsUpdate=!1}
function G (line 1008) | function G(a,b,c,d,e){var f,g,h,k;dc=0;if(d.needsUpdate){d.program&&Cc(d...
function w (line 1038) | function w(a,b){a.ambientLightColor.needsUpdate=b;a.directionalLightColo...
function K (line 1039) | function K(){var a=dc;a>=Oc&&console.warn("WebGLRenderer: trying to use ...
function x (line 1040) | function x(a,b){a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse...
function D (line 1040) | function D(a,b,c,d){a[b]=c.r*c.r*d;a[b+1]=c.g*c.g*d;a[b+2]=c.b*c.b*d}
function E (line 1040) | function E(a,b,c,d){a[b]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}
function A (line 1040) | function A(a){a!==Pc&&(l.lineWidth(a),Pc=a)}
function B (line 1040) | function B(a,b,c){Qc!==a&&(a?l.enable(l.POLYGON_OFFSET_FILL):l.disable(l...
function F (line 1040) | function F(a,b,c){c?
function R (line 1042) | function R(a,b){if(a.width>b||a.height>b){var c=b/Math.max(a.width,a.hei...
function H (line 1043) | function H(a,b){l.bindRenderbuffer(l.RENDERBUFFER,a);b.depthBuffer&&!b.s...
function C (line 1044) | function C(a){a instanceof THREE.WebGLRenderTargetCube?(l.bindTexture(l....
function T (line 1044) | function T(a){return a===THREE.NearestFilter||a===THREE.NearestMipMapNea...
function Q (line 1044) | function Q(a){var b;if(a===THREE.RepeatWrapping)return l.REPEAT;
function e (line 1126) | function e(a,b,d){if(b.visible){var f=c[b.id];if(f&&b.castShadow&&(!1===...
function G (line 1138) | function G(a,b){return a.z!==b.z?b.z-a.z:b.id-a.id}
function c (line 1190) | function c(a){for(var b=[],c=0,d=a.length;c<d;c++){var e=a[c],f=new THRE...
function d (line 1190) | function d(a,b){for(var c=b.length,d=!1,e=c-1,f=0;f<c;e=f++){var g=b[e],...
function c (line 1196) | function c(a,b,c){return a.x!=b.x?a.x<b.x?a.x<=c.x&&c.x<=b.x:b.x<=c.x&&c...
function d (line 1196) | function d(a,b,d,e,f){var g=b.x-a.x,h=b.y-a.y,k=e.x-d.x,n=e.y-d.y,p=a.x-...
function e (line 1198) | function e(a,b,c,d){var e=b.x-a.x,f=b.y-a.y;b=c.x-a.x;c=c.y-a.y;var g=d....
function c (line 1198) | function c(a,b){var d=h.length-1,f=a-1;0>f&&(f=d);var g=a+1;g>d&&(g=0);d...
function f (line 1199) | function f(a,b){var c,e;for(c=0;c<h.length;c++)if(e=c+1,e%=h.length,e=d(...
function g (line 1199) | function g(a,c){var e,f,h,k;for(e=0;e<n.length;e++)for(f=b[n[e]],h=0;h<f...
function g (line 1238) | function g(a,b,c,d,e,f,g,s){var u,v=h.widthSegments,y=h.heightSegments,G...
function c (line 1248) | function c(a,b,c){b||console.log("die");return b.clone().multiplyScalar(...
function d (line 1248) | function d(a,b,c){var d=1,d=a.x-b.x,e=a.y-b.y,f=c.x-a.x,g=c.y-a.y,h=d*d+...
function e (line 1249) | function e(a,b){var c,d;for(P=a.length;0<=--P;){c=P;d=P-1;0>d&&(d=a.leng...
function f (line 1250) | function f(a,b,c){F.vertices.push(new THREE.Vector3(a,b,c))}
function g (line 1250) | function g(a,b,c){a+=R;b+=R;c+=R;F.faces.push(new THREE.Face3(a,b,c,null...
function h (line 1275) | function h(a,b,c,d,e){var f=Math.cos(a),g=Math.sin(a);a*=b/c;b=Math.cos(...
function e (line 1284) | function e(a){var b=a.normalize().clone();b.index=k.vertices.push(b)-1;v...
function f (line 1284) | function f(a,b,c){var d=new THREE.Face3(a.index,b.index,c.index,[a.clone...
function g (line 1284) | function g(a,b){var c=
function h (line 1285) | function h(a,b,c){0>c&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x...
function b (line 1303) | function b(a,b,d){c(a,d);c(b,d)}
function c (line 1303) | function c(a,b){d.vertices.push(new THREE.Vector3);d.colors.push(new THR...
FILE: plugins/Sidebar/media_globe/globe.js
function init (line 89) | function init() {
function addData (line 174) | function addData(data, opts) {
function createPoints (line 228) | function createPoints() {
function addPoint (line 256) | function addPoint(lat, lng, size, color, subgeo) {
function onMouseDown (line 281) | function onMouseDown(event) {
function onMouseMove (line 297) | function onMouseMove(event) {
function onMouseUp (line 310) | function onMouseUp(event) {
function onMouseOut (line 317) | function onMouseOut(event) {
function onMouseWheel (line 323) | function onMouseWheel(event) {
function onDocumentKeyDown (line 336) | function onDocumentKeyDown(event) {
function onWindowResize (line 349) | function onWindowResize( event ) {
function zoom (line 355) | function zoom(delta) {
function animate (line 361) | function animate() {
function render (line 367) | function render() {
function unload (line 383) | function unload() {
FILE: plugins/Stats/StatsPlugin.py
class UiRequestPlugin (line 16) | class UiRequestPlugin(object):
method formatTableRow (line 18) | def formatTableRow(self, row, class_name=""):
method getObjSize (line 33) | def getObjSize(self, obj, hpy=None):
method renderHead (line 39) | def renderHead(self):
method renderConnectionsTable (line 72) | def renderConnectionsTable(self):
method renderTrackers (line 117) | def renderTrackers(self):
method renderTor (line 146) | def renderTor(self):
method renderDbStats (line 152) | def renderDbStats(self):
method renderSites (line 164) | def renderSites(self):
method renderBigfiles (line 204) | def renderBigfiles(self):
method renderRequests (line 228) | def renderRequests(self):
method renderMemory (line 247) | def renderMemory(self):
method actionStats (line 361) | def actionStats(self):
method actionDumpobj (line 405) | def actionDumpobj(self):
method actionListobj (line 443) | def actionListobj(self):
method actionGcCollect (line 511) | def actionGcCollect(self):
method actionEnv (line 518) | def actionEnv(self):
class ActionsPlugin (line 541) | class ActionsPlugin:
method formatTable (line 542) | def formatTable(self, *rows, format="text"):
method formatHead (line 548) | def formatHead(self, title, format="text"):
method formatTableHtml (line 554) | def formatTableHtml(self, *rows):
method formatTableText (line 563) | def formatTableText(self, *rows):
method testEnv (line 570) | def testEnv(self, format="text"):
FILE: plugins/TranslateSite/TranslateSitePlugin.py
class UiRequestPlugin (line 8) | class UiRequestPlugin(object):
method actionSiteMedia (line 9) | def actionSiteMedia(self, path, **kwargs):
method actionUiMedia (line 37) | def actionUiMedia(self, path):
method actionPatchFile (line 48) | def actionPatchFile(self, site, inner_path, file_generator):
FILE: plugins/Trayicon/TrayiconPlugin.py
class ActionsPlugin (line 19) | class ActionsPlugin(object):
method main (line 21) | def main(self):
method quit (line 77) | def quit(self):
method quitServers (line 81) | def quitServers(self):
method opensite (line 85) | def opensite(self, url):
method titleIp (line 89) | def titleIp(self):
method titleConnections (line 97) | def titleConnections(self):
method titleTransfer (line 101) | def titleTransfer(self):
method titleConsole (line 108) | def titleConsole(self):
method toggleConsole (line 115) | def toggleConsole(self):
method getAutorunPath (line 123) | def getAutorunPath(self):
method formatAutorun (line 126) | def formatAutorun(self):
method isAutorunEnabled (line 156) | def isAutorunEnabled(self):
method titleAutorun (line 160) | def titleAutorun(self):
method toggleAutorun (line 167) | def toggleAutorun(self):
FILE: plugins/Trayicon/lib/notificationicon.py
class POINT (line 53) | class POINT(ctypes.Structure):
class TimeoutVersionUnion (line 99) | class TimeoutVersionUnion(ctypes.Union):
class NOTIFYICONDATA (line 106) | class NOTIFYICONDATA(ctypes.Structure):
method __init__ (line 107) | def __init__(self, *args, **kwargs):
class WNDCLASSEX (line 430) | class WNDCLASSEX(ctypes.Structure):
method __init__ (line 431) | def __init__(self, *args, **kwargs):
function GenerateDummyWindow (line 450) | def GenerateDummyWindow(callback, uid):
class MSG (line 478) | class MSG(ctypes.Structure):
function LoadIcon (line 498) | def LoadIcon(iconfilename, small=False):
class NotificationIcon (line 507) | class NotificationIcon(object):
method __init__ (line 508) | def __init__(self, iconfilename, tooltip=None):
method _bubble (line 524) | def _bubble(self, iconinfo):
method _run (line 537) | def _run(self):
method _menu (line 577) | def _menu(self):
method clicked (line 636) | def clicked(self):
method _callback (line 641) | def _callback(self, hWnd, msg, wParam, lParam):
method die (line 658) | def die(self):
method pump (line 670) | def pump(self):
method announce (line 679) | def announce(self, text):
function hideConsole (line 683) | def hideConsole():
function showConsole (line 686) | def showConsole():
function hasConsole (line 689) | def hasConsole():
function greet (line 695) | def greet():
function quit (line 699) | def quit():
function announce (line 702) | def announce():
function clicked (line 706) | def clicked():
function dynamicTitle (line 709) | def dynamicTitle():
function goodbye (line 727) | def goodbye():
FILE: plugins/Trayicon/lib/winfolders.py
function get (line 44) | def get(intFolder):
FILE: plugins/UiConfig/UiConfigPlugin.py
class UiRequestPlugin (line 17) | class UiRequestPlugin(object):
method actionWrapper (line 18) | def actionWrapper(self, path, extra_headers=None):
method actionUiMedia (line 34) | def actionUiMedia(self, path, *args, **kwargs):
class UiWebsocketPlugin (line 55) | class UiWebsocketPlugin(object):
method actionConfigList (line 57) | def actionConfigList(self, to):
FILE: plugins/UiConfig/media/js/all.js
function Class (line 10) | function Class() {}
function Promise (line 88) | function Promise() {
function Animation (line 969) | function Animation() {}
function ctor (line 1146) | function ctor() { this.constructor = child; }
function ZeroFrame (line 1152) | function ZeroFrame(url) {
function ctor (line 1277) | function ctor() { this.constructor = child; }
function ConfigStorage (line 1283) | function ConfigStorage(config) {
function ctor (line 1634) | function ctor() { this.constructor = child; }
function ConfigView (line 1640) | function ConfigView() {
function ctor (line 1837) | function ctor() { this.constructor = child; }
function UiConfig (line 1845) | function UiConfig() {
FILE: plugins/UiFileManager/UiFileManagerPlugin.py
class UiFileManagerPlugin (line 17) | class UiFileManagerPlugin(object):
method actionWrapper (line 18) | def actionWrapper(self, path, extra_headers=None):
method actionUiMedia (line 48) | def actionUiMedia(self, path, *args, **kwargs):
method error404 (line 71) | def error404(self, path=""):
FILE: plugins/UiFileManager/media/codemirror/all.js
function classTest (line 54) | function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)...
function removeChildren (line 65) | function removeChildren(e) {
function removeChildrenAndAdd (line 71) | function removeChildrenAndAdd(parent, e) {
function elt (line 75) | function elt(tag, content, className, style) {
function eltP (line 84) | function eltP(tag, content, className, style) {
function contains (line 107) | function contains(parent, child) {
function activeElt (line 118) | function activeElt() {
function addClass (line 133) | function addClass(node, cls) {
function joinClasses (line 137) | function joinClasses(a, b) {
function bind (line 150) | function bind(f) {
function copyObj (line 155) | function copyObj(obj, target, overwrite) {
function countColumn (line 165) | function countColumn(string, end, tabSize, startIndex, startValue) {
function indexOf (line 204) | function indexOf(array, elt) {
function findColumn (line 222) | function findColumn(string, goal, tabSize) {
function spaceStr (line 237) | function spaceStr(n) {
function lst (line 243) | function lst(arr) { return arr[arr.length-1] }
function map (line 245) | function map(array, f) {
function insertSorted (line 251) | function insertSorted(array, value, score) {
function nothing (line 257) | function nothing() {}
function createObj (line 259) | function createObj(base, props) {
function isWordCharBasic (line 272) | function isWordCharBasic(ch) {
function isWordChar (line 276) | function isWordChar(ch, helper) {
function isEmpty (line 282) | function isEmpty(obj) {
function isExtendingChar (line 293) | function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendi...
function skipExtendingChars (line 296) | function skipExtendingChars(str, pos, dir) {
function findFirst (line 304) | function findFirst(pred, from, to) {
function iterateBidiSections (line 319) | function iterateBidiSections(order, from, to, f) {
function getBidiPartAt (line 333) | function getBidiPartAt(order, ch, sticky) {
function charType (line 379) | function charType(code) {
function BidiSpan (line 392) | function BidiSpan(level, from, to) {
function getOrder (line 525) | function getOrder(line, direction) {
function getHandlers (line 549) | function getHandlers(emitter, type) {
function off (line 553) | function off(emitter, type, f) {
function signal (line 568) | function signal(emitter, type /*, values...*/) {
function signalDOMEvent (line 578) | function signalDOMEvent(cm, e, override) {
function signalCursorActivity (line 585) | function signalCursorActivity(cm) {
function hasHandler (line 593) | function hasHandler(emitter, type) {
function eventMixin (line 599) | function eventMixin(ctor) {
function e_preventDefault (line 607) | function e_preventDefault(e) {
function e_stopPropagation (line 611) | function e_stopPropagation(e) {
function e_defaultPrevented (line 615) | function e_defaultPrevented(e) {
function e_stop (line 618) | function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
function e_target (line 620) | function e_target(e) {return e.target || e.srcElement}
function e_button (line 621) | function e_button(e) {
function zeroWidthElement (line 642) | function zeroWidthElement(measure) {
function hasBadBidiRects (line 657) | function hasBadBidiRects(measure) {
function hasBadZoomedRects (line 706) | function hasBadZoomedRects(measure) {
function defineMode (line 720) | function defineMode(name, mode) {
function defineMIME (line 726) | function defineMIME(mime, spec) {
function resolveMode (line 732) | function resolveMode(spec) {
function getMode (line 751) | function getMode(options, spec) {
function extendMode (line 775) | function extendMode(mode, properties) {
function copyState (line 780) | function copyState(mode, state) {
function innerMode (line 794) | function innerMode(mode, state) {
function startState (line 805) | function startState(mode, a1, a2) {
function getLine (line 895) | function getLine(doc, n) {
function getBetween (line 911) | function getBetween(doc, start, end) {
function getLines (line 923) | function getLines(doc, from, to) {
function updateLineHeight (line 931) | function updateLineHeight(line, height) {
function lineNo (line 938) | function lineNo(line) {
function lineAtHeight (line 952) | function lineAtHeight(chunk, h) {
function isLine (line 972) | function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
function lineNumberFor (line 974) | function lineNumberFor(options, i) {
function Pos (line 979) | function Pos(line, ch, sticky) {
function cmp (line 990) | function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
function equalCursorPos (line 992) | function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b)...
function copyPos (line 994) | function copyPos(x) {return Pos(x.line, x.ch)}
function maxPos (line 995) | function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
function minPos (line 996) | function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
function clipLine (line 1000) | function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.fi...
function clipPos (line 1001) | function clipPos(doc, pos) {
function clipToLen (line 1007) | function clipToLen(pos, linelen) {
function clipPosArray (line 1013) | function clipPosArray(doc, array) {
function highlightLine (line 1070) | function highlightLine(cm, line, context, forceToEnd) {
function getLineStyles (line 1115) | function getLineStyles(cm, line, updateFrontier) {
function getContextBefore (line 1131) | function getContextBefore(cm, n, precise) {
function processLine (line 1151) | function processLine(cm, text, context, startAt) {
function callBlankLine (line 1162) | function callBlankLine(mode, state) {
function readToken (line 1169) | function readToken(mode, stream, state, inner) {
function takeToken (line 1186) | function takeToken(cm, pos, precise, asArray) {
function extractLineClasses (line 1200) | function extractLineClasses(type, output) {
function runMode (line 1215) | function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
function findStartLine (line 1259) | function findStartLine(cm, n, precise) {
function retreatFrontier (line 1276) | function retreatFrontier(doc, n) {
function seeReadOnlySpans (line 1296) | function seeReadOnlySpans() {
function seeCollapsedSpans (line 1300) | function seeCollapsedSpans() {
function MarkedSpan (line 1306) | function MarkedSpan(marker, from, to) {
function getMarkedSpanFor (line 1312) | function getMarkedSpanFor(spans, marker) {
function removeMarkedSpan (line 1320) | function removeMarkedSpan(spans, span) {
function addMarkedSpan (line 1327) | function addMarkedSpan(line, span) {
function markedSpansBefore (line 1336) | function markedSpansBefore(old, startCh, isInsert) {
function markedSpansAfter (line 1348) | function markedSpansAfter(old, endCh, isInsert) {
function stretchSpansOverChange (line 1368) | function stretchSpansOverChange(doc, change) {
function clearEmptySpans (line 1430) | function clearEmptySpans(spans) {
function removeReadOnlyRanges (line 1441) | function removeReadOnlyRanges(doc, from, to) {
function detachMarkedSpans (line 1470) | function detachMarkedSpans(line) {
function attachMarkedSpans (line 1477) | function attachMarkedSpans(line, spans) {
function extraLeft (line 1486) | function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
function extraRight (line 1487) | function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
function compareCollapsedMarkers (line 1492) | function compareCollapsedMarkers(a, b) {
function collapsedSpanAtSide (line 1505) | function collapsedSpanAtSide(line, start) {
function collapsedSpanAtStart (line 1515) | function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, t...
function collapsedSpanAtEnd (line 1516) | function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, fal...
function collapsedSpanAround (line 1518) | function collapsedSpanAround(line, ch) {
function conflictingCollapsedRange (line 1531) | function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
function visualLine (line 1551) | function visualLine(line) {
function visualLineEnd (line 1558) | function visualLineEnd(line) {
function visualLineContinued (line 1567) | function visualLineContinued(line) {
function visualLineNo (line 1578) | function visualLineNo(doc, lineN) {
function visualLineEndNo (line 1586) | function visualLineEndNo(doc, lineN) {
function lineIsHidden (line 1598) | function lineIsHidden(doc, line) {
function lineIsHiddenInner (line 1609) | function lineIsHiddenInner(doc, line, span) {
function heightAtLine (line 1626) | function heightAtLine(lineObj) {
function lineLength (line 1648) | function lineLength(line) {
function findMaxLine (line 1667) | function findMaxLine(cm) {
function updateLine (line 1697) | function updateLine(line, text, markedSpans, estimateHeight) {
function cleanUpLine (line 1709) | function cleanUpLine(line) {
function interpretTokenStyle (line 1718) | function interpretTokenStyle(style, options) {
function buildLineContent (line 1730) | function buildLineContent(cm, lineView) {
function defaultSpecialCharPlaceholder (line 1788) | function defaultSpecialCharPlaceholder(ch) {
function buildToken (line 1797) | function buildToken(builder, text, style, startStyle, endStyle, css, att...
function splitSpaces (line 1864) | function splitSpaces(text, trailingBefore) {
function buildTokenBadBidi (line 1879) | function buildTokenBadBidi(inner, order) {
function buildCollapsedSpan (line 1899) | function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
function insertLineContent (line 1917) | function insertLineContent(line, builder, styles) {
function LineView (line 1996) | function LineView(doc, line, lineN) {
function buildViewArray (line 2008) | function buildViewArray(cm, from, to) {
function pushOperation (line 2020) | function pushOperation(op) {
function fireCallbacksForOps (line 2031) | function fireCallbacksForOps(group) {
function finishOperation (line 2047) | function finishOperation(op, endCb) {
function signalLater (line 2067) | function signalLater(emitter, type /*, values...*/) {
function fireOrphanDelayed (line 2087) | function fireOrphanDelayed() {
function updateLineForChanges (line 2096) | function updateLineForChanges(cm, lineView, lineN, dims) {
function ensureLineWrapped (line 2109) | function ensureLineWrapped(lineView) {
function updateLineBackground (line 2120) | function updateLineBackground(cm, lineView) {
function getLineContent (line 2135) | function getLineContent(cm, lineView) {
function updateLineText (line 2148) | function updateLineText(cm, lineView) {
function updateLineClasses (line 2163) | function updateLineClasses(cm, lineView) {
function updateLineGutter (line 2173) | function updateLineGutter(cm, lineView, lineN, dims) {
function updateLineWidgets (line 2211) | function updateLineWidgets(cm, lineView, dims) {
function buildLineElement (line 2222) | function buildLineElement(cm, lineView, lineN, dims) {
function insertLineWidgets (line 2236) | function insertLineWidgets(cm, lineView, dims) {
function insertLineWidgetsFor (line 2242) | function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
function positionLineWidget (line 2258) | function positionLineWidget(widget, node, lineView, dims) {
function widgetHeight (line 2276) | function widgetHeight(widget) {
function eventInWidget (line 2292) | function eventInWidget(display, e) {
function paddingTop (line 2302) | function paddingTop(display) {return display.lineSpace.offsetTop}
function paddingVert (line 2303) | function paddingVert(display) {return display.mover.offsetHeight - displ...
function paddingH (line 2304) | function paddingH(display) {
function scrollGap (line 2313) | function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
function displayWidth (line 2314) | function displayWidth(cm) {
function displayHeight (line 2317) | function displayHeight(cm) {
function ensureLineHeights (line 2325) | function ensureLineHeights(cm, lineView, rect) {
function mapFromLineView (line 2346) | function mapFromLineView(lineView, line, lineN) {
function updateExternalMeasurement (line 2359) | function updateExternalMeasurement(cm, line) {
function measureChar (line 2372) | function measureChar(cm, line, ch, bias) {
function findViewForLine (line 2377) | function findViewForLine(cm, lineN) {
function prepareMeasureForLine (line 2390) | function prepareMeasureForLine(cm, line) {
function measureCharPrepared (line 2412) | function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
function nodeAndOffsetInLineMap (line 2434) | function nodeAndOffsetInLineMap(map, ch, bias) {
function getUsefulRect (line 2472) | function getUsefulRect(rects, bias) {
function measureCharInner (line 2482) | function measureCharInner(cm, prepared, ch, bias) {
function maybeUpdateRectForZooming (line 2535) | function maybeUpdateRectForZooming(measure, rect) {
function clearLineMeasurementCacheFor (line 2545) | function clearLineMeasurementCacheFor(lineView) {
function clearLineMeasurementCache (line 2554) | function clearLineMeasurementCache(cm) {
function clearCaches (line 2561) | function clearCaches(cm) {
function pageScrollX (line 2568) | function pageScrollX() {
function pageScrollY (line 2575) | function pageScrollY() {
function widgetTopHeight (line 2580) | function widgetTopHeight(lineObj) {
function intoCoordSystem (line 2591) | function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
function fromCoordSystem (line 2613) | function fromCoordSystem(cm, coords, context) {
function charCoords (line 2630) | function charCoords(cm, pos, context, lineObj, bias) {
function cursorCoords (line 2651) | function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHei...
function estimateCoords (line 2682) | function estimateCoords(cm, pos) {
function PosWithInfo (line 2697) | function PosWithInfo(line, ch, sticky, outside, xRel) {
function coordsChar (line 2706) | function coordsChar(cm, x, y) {
function wrappedLineExtent (line 2726) | function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
function wrappedLineExtentChar (line 2734) | function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
function boxIsAfter (line 2742) | function boxIsAfter(box, x, y, left) {
function coordsCharInner (line 2746) | function coordsCharInner(cm, lineObj, lineNo, x, y) {
function coordsBidiPart (line 2813) | function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, ...
function coordsBidiPartWrapped (line 2837) | function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, or...
function textHeight (line 2872) | function textHeight(display) {
function charWidth (line 2892) | function charWidth(display) {
function getDimensions (line 2904) | function getDimensions(cm) {
function compensateForHScroll (line 2922) | function compensateForHScroll(display) {
function estimateHeight (line 2929) | function estimateHeight(cm) {
function estimateLineHeights (line 2947) | function estimateLineHeights(cm) {
function posFromMouse (line 2960) | function posFromMouse(cm, e, liberal, forRect) {
function findViewIndex (line 2978) | function findViewIndex(cm, n) {
function regChange (line 2995) | function regChange(cm, from, to, lendiff) {
function regLineChange (line 3060) | function regLineChange(cm, line, type) {
function resetView (line 3074) | function resetView(cm) {
function viewCuttingPoint (line 3080) | function viewCuttingPoint(cm, oldN, newN, dir) {
function adjustView (line 3107) | function adjustView(cm, from, to) {
function countDirtyView (line 3128) | function countDirtyView(cm) {
function updateSelection (line 3137) | function updateSelection(cm) {
function prepareSelection (line 3141) | function prepareSelection(cm, primary) {
function drawSelectionCursor (line 3162) | function drawSelectionCursor(cm, head, output) {
function cmpCoords (line 3180) | function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
function drawSelectionRange (line 3183) | function drawSelectionRange(cm, range, output) {
function restartBlink (line 3276) | function restartBlink(cm) {
function ensureFocus (line 3289) | function ensureFocus(cm) {
function delayBlurEvent (line 3293) | function delayBlurEvent(cm) {
function onFocus (line 3301) | function onFocus(cm, e) {
function onBlur (line 3320) | function onBlur(cm, e) {
function updateHeightsInViewport (line 3334) | function updateHeightsInViewport(cm) {
function updateWidgetHeight (line 3373) | function updateWidgetHeight(line) {
function visibleLines (line 3383) | function visibleLines(display, doc, viewport) {
function maybeScrollWindow (line 3408) | function maybeScrollWindow(cm, rect) {
function scrollPosIntoView (line 3425) | function scrollPosIntoView(cm, pos, end, margin) {
function scrollIntoView (line 3459) | function scrollIntoView(cm, rect) {
function calculateScrollPos (line 3469) | function calculateScrollPos(cm, rect) {
function addToScrollTop (line 3499) | function addToScrollTop(cm, top) {
function ensureCursorVisible (line 3507) | function ensureCursorVisible(cm) {
function scrollToCoords (line 3513) | function scrollToCoords(cm, x, y) {
function scrollToRange (line 3519) | function scrollToRange(cm, range) {
function resolveScrollToPos (line 3528) | function resolveScrollToPos(cm) {
function scrollToCoordsRange (line 3537) | function scrollToCoordsRange(cm, from, to, margin) {
function updateScrollTop (line 3549) | function updateScrollTop(cm, val) {
function setScrollTop (line 3557) | function setScrollTop(cm, val, forceScroll) {
function setScrollLeft (line 3567) | function setScrollLeft(cm, val, isScroller, forceScroll) {
function measureForScrollbars (line 3580) | function measureForScrollbars(cm) {
function maybeDisable (line 3672) | function maybeDisable() {
function updateScrollbars (line 3701) | function updateScrollbars(cm, measure) {
function updateScrollbarsInner (line 3715) | function updateScrollbarsInner(cm, measure) {
function initScrollbars (line 3737) | function initScrollbars(cm) {
function startOperation (line 3767) | function startOperation(cm) {
function endOperation (line 3789) | function endOperation(cm) {
function endOperations (line 3800) | function endOperations(group) {
function endOperation_R1 (line 3814) | function endOperation_R1(op) {
function endOperation_W1 (line 3827) | function endOperation_W1(op) {
function endOperation_R2 (line 3831) | function endOperation_R2(op) {
function endOperation_W2 (line 3852) | function endOperation_W2(op) {
function endOperation_finish (line 3877) | function endOperation_finish(op) {
function runInOp (line 3916) | function runInOp(cm, f) {
function operation (line 3923) | function operation(cm, f) {
function methodOp (line 3933) | function methodOp(f) {
function docMethodOp (line 3941) | function docMethodOp(f) {
function startWorker (line 3953) | function startWorker(cm, time) {
function highlightWorker (line 3958) | function highlightWorker(cm) {
function maybeClipScrollbars (line 4026) | function maybeClipScrollbars(cm) {
function selectionSnapshot (line 4037) | function selectionSnapshot(cm) {
function restoreSelection (line 4054) | function restoreSelection(snapshot) {
function updateDisplayIfNeeded (line 4071) | function updateDisplayIfNeeded(cm, update) {
function postUpdateDisplay (line 4143) | function postUpdateDisplay(cm, update) {
function updateDisplaySimple (line 4175) | function updateDisplaySimple(cm, viewport) {
function patchDisplay (line 4192) | function patchDisplay(cm, updateNumbersFrom, dims) {
function updateGutterSpace (line 4233) | function updateGutterSpace(display) {
function setDocumentHeight (line 4238) | function setDocumentHeight(cm, measure) {
function alignHorizontally (line 4246) | function alignHorizontally(cm) {
function maybeUpdateLineNumberWidth (line 4269) | function maybeUpdateLineNumberWidth(cm) {
function getGutters (line 4287) | function getGutters(gutters, lineNumbers) {
function renderGutters (line 4304) | function renderGutters(display) {
function updateGutters (line 4323) | function updateGutters(cm) {
function Display (line 4333) | function Display(place, doc, input, options) {
function wheelEventDelta (line 4456) | function wheelEventDelta(e) {
function wheelEventPixels (line 4463) | function wheelEventPixels(e) {
function onScrollWheel (line 4470) | function onScrollWheel(cm, e) {
function normalizeSelection (line 4601) | function normalizeSelection(cm, ranges, primIndex) {
function simpleSelection (line 4619) | function simpleSelection(anchor, head) {
function changeEnd (line 4625) | function changeEnd(change) {
function adjustForChange (line 4633) | function adjustForChange(pos, change) {
function computeSelAfterChange (line 4642) | function computeSelAfterChange(doc, change) {
function offsetPos (line 4652) | function offsetPos(pos, old, nw) {
function computeReplacedSel (line 4661) | function computeReplacedSel(doc, changes, hint) {
function loadMode (line 4682) | function loadMode(cm) {
function resetModeState (line 4687) | function resetModeState(cm) {
function isWholeLineUpdate (line 4703) | function isWholeLineUpdate(doc, change) {
function updateDoc (line 4709) | function updateDoc(doc, change, markedSpans, estimateHeight) {
function linkedDocs (line 4761) | function linkedDocs(doc, f, sharedHistOnly) {
function attachDoc (line 4776) | function attachDoc(cm, doc) {
function setDirectionClass (line 4788) | function setDirectionClass(cm) {
function directionChanged (line 4792) | function directionChanged(cm) {
function History (line 4799) | function History(startGen) {
function historyChangeFromChange (line 4816) | function historyChangeFromChange(doc, change) {
function clearSelectionEvents (line 4825) | function clearSelectionEvents(array) {
function lastChangeEvent (line 4835) | function lastChangeEvent(hist, force) {
function addChangeToHistory (line 4850) | function addChangeToHistory(doc, change, selAfter, opId) {
function selectionEventCanBeMerged (line 4893) | function selectionEventCanBeMerged(doc, origin, prev, sel) {
function addSelectionToHistory (line 4906) | function addSelectionToHistory(doc, sel, opId, options) {
function pushSelectionToHistory (line 4928) | function pushSelectionToHistory(sel, dest) {
function attachLocalSpans (line 4935) | function attachLocalSpans(doc, change, from, to) {
function removeClearedSpans (line 4946) | function removeClearedSpans(spans) {
function getOldSpans (line 4957) | function getOldSpans(doc, change) {
function mergeOldSpans (line 4970) | function mergeOldSpans(doc, change) {
function copyHistoryArray (line 4994) | function copyHistoryArray(events, newGroup, instantiateSel) {
function extendRange (line 5026) | function extendRange(range, head, other, extend) {
function extendSelection (line 5045) | function extendSelection(doc, head, other, options, extend) {
function extendSelections (line 5052) | function extendSelections(doc, heads, options) {
function replaceOneSelection (line 5062) | function replaceOneSelection(doc, i, range, options) {
function setSimpleSelection (line 5069) | function setSimpleSelection(doc, anchor, head, options) {
function filterSelectionChange (line 5075) | function filterSelectionChange(doc, sel, options) {
function setSelectionReplaceHistory (line 5092) | function setSelectionReplaceHistory(doc, sel, options) {
function setSelection (line 5103) | function setSelection(doc, sel, options) {
function setSelectionNoUndo (line 5108) | function setSelectionNoUndo(doc, sel, options) {
function setSelectionInner (line 5120) | function setSelectionInner(doc, sel) {
function reCheckSelection (line 5135) | function reCheckSelection(doc) {
function skipAtomicInSelection (line 5141) | function skipAtomicInSelection(doc, sel, bias, mayClear) {
function skipAtomicInner (line 5156) | function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
function skipAtomic (line 5196) | function skipAtomic(doc, pos, oldPos, bias, mayClear) {
function movePos (line 5209) | function movePos(doc, pos, dir, line) {
function selectAll (line 5221) | function selectAll(cm) {
function filterChange (line 5228) | function filterChange(doc, change, update) {
function makeChange (line 5255) | function makeChange(doc, change, ignoreReadOnly) {
function makeChangeInner (line 5277) | function makeChangeInner(doc, change) {
function makeChangeFromHistory (line 5295) | function makeChangeFromHistory(doc, type, allowSelectionOnly) {
function shiftDoc (line 5371) | function shiftDoc(doc, distance) {
function makeChangeSingleDoc (line 5387) | function makeChangeSingleDoc(doc, change, selAfter, spans) {
function makeChangeSingleDocInEditor (line 5423) | function makeChangeSingleDocInEditor(cm, change, spans) {
function replaceRange (line 5481) | function replaceRange(doc, code, from, to, origin) {
function rebaseHistSelSingle (line 5492) | function rebaseHistSelSingle(pos, from, to, diff) {
function rebaseHistArray (line 5508) | function rebaseHistArray(array, from, to, diff) {
function rebaseHist (line 5536) | function rebaseHist(hist, change) {
function changeLine (line 5545) | function changeLine(doc, handle, changeType, op) {
function LeafChunk (line 5567) | function LeafChunk(lines) {
function BranchChunk (line 5612) | function BranchChunk(children) {
function adjustScrollWhenAboveVisible (line 5761) | function adjustScrollWhenAboveVisible(cm, line, diff) {
function addLineWidget (line 5766) | function addLineWidget(doc, handle, node, options) {
function markText (line 5922) | function markText(doc, from, to, options, type) {
function markTextShared (line 6017) | function markTextShared(doc, from, to, options, type) {
function findSharedMarkers (line 6032) | function findSharedMarkers(doc) {
function copySharedMarkers (line 6036) | function copySharedMarkers(doc, markers) {
function detachSharedMarkers (line 6048) | function detachSharedMarkers(markers) {
function onDrop (line 6485) | function onDrop(e) {
function onDragStart (line 6556) | function onDragStart(cm, e) {
function onDragOver (line 6579) | function onDragOver(cm, e) {
function clearDragCursor (line 6591) | function clearDragCursor(cm) {
function forEachCodeMirror (line 6602) | function forEachCodeMirror(f) {
function ensureGlobalHandlers (line 6615) | function ensureGlobalHandlers() {
function registerGlobalHandlers (line 6620) | function registerGlobalHandlers() {
function onResize (line 6633) | function onResize(cm) {
function normalizeKeyName (line 6704) | function normalizeKeyName(name) {
function normalizeKeyMap (line 6728) | function normalizeKeyMap(keymap) {
function lookupKey (line 6755) | function lookupKey(key, map, handle, context) {
function isModifierKey (line 6774) | function isModifierKey(value) {
function addModifierNames (line 6779) | function addModifierNames(name, event, noShift) {
function keyName (line 6789) | function keyName(event, noShift) {
function getKeyMap (line 6799) | function getKeyMap(val) {
function deleteNearSelection (line 6805) | function deleteNearSelection(cm, compute) {
function moveCharLogically (line 6828) | function moveCharLogically(line, ch, dir) {
function moveLogically (line 6833) | function moveLogically(line, start, dir) {
function endOfLine (line 6838) | function endOfLine(visually, cm, lineObj, lineNo, dir) {
function moveVisually (line 6866) | function moveVisually(cm, line, start, dir) {
function lineStart (line 7078) | function lineStart(cm, lineN) {
function lineEnd (line 7084) | function lineEnd(cm, lineN) {
function lineStartSmart (line 7090) | function lineStartSmart(cm, pos) {
function doHandleBinding (line 7103) | function doHandleBinding(cm, bound, dropShift) {
function lookupKeyForEditor (line 7123) | function lookupKeyForEditor(cm, name, handle) {
function dispatchKey (line 7137) | function dispatchKey(cm, name, e, handle) {
function dispatchKeyInner (line 7155) | function dispatchKeyInner(cm, name, e, handle) {
function handleKeyBinding (line 7172) | function handleKeyBinding(cm, e) {
function handleCharBinding (line 7191) | function handleCharBinding(cm, e, ch) {
function onKeyDown (line 7196) | function onKeyDown(e) {
function showCrossHair (line 7220) | function showCrossHair(cm) {
function onKeyUp (line 7235) | function onKeyUp(e) {
function onKeyPress (line 7240) | function onKeyPress(e) {
function clickRepeat (line 7268) | function clickRepeat(pos, button) {
function onMouseDown (line 7289) | function onMouseDown(e) {
function handleMappedButton (line 7326) | function handleMappedButton(cm, button, pos, repeat, event) {
function configureMouse (line 7346) | function configureMouse(cm, repeat, event) {
function leftButtonDown (line 7359) | function leftButtonDown(cm, pos, repeat, event) {
function leftButtonStartDrag (line 7377) | function leftButtonStartDrag(cm, event, pos, behavior) {
function rangeForUnit (line 7416) | function rangeForUnit(cm, pos, unit) {
function leftButtonSelect (line 7425) | function leftButtonSelect(cm, event, start, behavior) {
function bidiSimplify (line 7562) | function bidiSimplify(cm, range) {
function gutterEvent (line 7597) | function gutterEvent(cm, e, type, prevent) {
function clickInGutter (line 7626) | function clickInGutter(cm, e) {
function onContextMenu (line 7635) | function onContextMenu(cm, e) {
function contextMenuInGutter (line 7641) | function contextMenuInGutter(cm, e) {
function themeChanged (line 7646) | function themeChanged(cm) {
function defineOptions (line 7657) | function defineOptions(CodeMirror) {
function dragDropChanged (line 7801) | function dragDropChanged(cm, value, old) {
function wrappingChanged (line 7814) | function wrappingChanged(cm) {
function CodeMirror (line 7832) | function CodeMirror(place, options) {
function registerEventHandlers (line 7907) | function registerEventHandlers(cm) {
function indentLine (line 8025) | function indentLine(cm, n, how, aggressive) {
function setLastCopied (line 8089) | function setLastCopied(newLastCopied) {
function applyTextInput (line 8093) | function applyTextInput(cm, inserted, deleted, sel, origin) {
function handlePaste (line 8141) | function handlePaste(e, cm) {
function triggerElectric (line 8151) | function triggerElectric(cm, inserted) {
function copyableRanges (line 8175) | function copyableRanges(cm) {
function disableBrowserMagic (line 8186) | function disableBrowserMagic(field, spellcheck, autocorrect, autocapital...
function hiddenTextarea (line 8192) | function hiddenTextarea() {
function addEditorMethods (line 8215) | function addEditorMethods(CodeMirror) {
function findPosH (line 8655) | function findPosH(doc, pos, dir, unit, visually) {
function findPosV (line 8716) | function findPosV(cm, pos, dir, unit) {
function belongsToInput (line 8754) | function belongsToInput(e) {
function onCopyCut (line 8787) | function onCopyCut(e) {
function poll (line 8954) | function poll() {
function posToDOM (line 9120) | function posToDOM(cm, pos) {
function isInGutter (line 9136) | function isInGutter(node) {
function badPos (line 9142) | function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
function domTextBetween (line 9144) | function domTextBetween(cm, from, to, fromLine, toLine) {
function domToPos (line 9197) | function domToPos(cm, node, offset) {
function locateNodeInLineView (line 9216) | function locateNodeInLineView(lineView, node, offset) {
function prepareCopyCut (line 9313) | function prepareCopyCut(e) {
function p (line 9470) | function p() {
function prepareSelectAllHack (line 9574) | function prepareSelectAllHack() {
function rehide (line 9587) | function rehide() {
function fromTextArea (line 9634) | function fromTextArea(textarea, options) {
function addLegacyProps (line 9691) | function addLegacyProps(CodeMirror) {
function ensureState (line 9848) | function ensureState(states, name) {
function toRegex (line 9853) | function toRegex(val, caret) {
function asToken (line 9865) | function asToken(val) {
function Rule (line 9875) | function Rule(data, states) {
function tokenFunction (line 9882) | function tokenFunction(states, config) {
function cmp (line 9945) | function cmp(a, b) {
function enterLocalMode (line 9957) | function enterLocalMode(config, state, spec, token) {
function indexOf (line 9973) | function indexOf(val, arr) {
function indentFunction (line 9977) | function indentFunction(states, meta) {
function findPosSubword (line 10029) | function findPosSubword(doc, start, dir) {
function moveSubword (line 10055) | function moveSubword(cm, dir) {
function insertLine (line 10113) | function insertLine(cm, above) {
function wordAt (line 10135) | function wordAt(cm, pos) {
function addCursorToSelection (line 10177) | function addCursorToSelection(cm, dir) {
function isSelectedRange (line 10198) | function isSelectedRange(ranges, from, to) {
function selectBetweenBrackets (line 10206) | function selectBetweenBrackets(cm) {
function puncType (line 10239) | function puncType(type) {
function sortLines (line 10350) | function sortLines(cm, caseSensitive) {
function modifyWordOrSelection (line 10452) | function modifyWordOrSelection(cm, mod) {
function getTarget (line 10550) | function getTarget(cm) {
function findAndGoTo (line 10561) | function findAndGoTo(cm, forward) {
function dialogDiv (line 10741) | function dialogDiv(cm, template, bottom) {
function closeNotification (line 10759) | function closeNotification(cm, newVal) {
function close (line 10772) | function close(newVal) {
function close (line 10833) | function close() {
function close (line 10872) | function close() {
function getOption (line 10928) | function getOption(conf, name) {
function ensureBound (line 10935) | function ensureBound(chars) {
function handler (line 10943) | function handler(ch) {
function getConfig (line 10947) | function getConfig(cm) {
function handleBackspace (line 10954) | function handleBackspace(cm) {
function handleEnter (line 10971) | function handleEnter(cm) {
function contractSelection (line 10995) | function contractSelection(sel) {
function handleChar (line 11001) | function handleChar(cm, ch) {
function charsAround (line 11075) | function charsAround(cm, pos) {
function stringStartsAfter (line 11081) | function stringStartsAfter(cm, pos) {
function autoCloseGT (line 11146) | function autoCloseGT(cm) {
function autoCloseCurrent (line 11199) | function autoCloseCurrent(cm, typingSlash) {
function autoCloseSlash (line 11238) | function autoCloseSlash(cm) {
function indexOf (line 11245) | function indexOf(collection, elt) {
function closingTagExists (line 11254) | function closingTagExists(cm, context, tagName, pos, newTag) {
function incrementRemainingMarkdownListNumbers (line 11347) | function incrementRemainingMarkdownListNumbers(cm, pos) {
function bracketRegex (line 11405) | function bracketRegex(config) {
function findMatchingBracket (line 11409) | function findMatchingBracket(cm, where, config) {
function scanForBracket (line 11440) | function scanForBracket(cm, where, dir, style, config) {
function matchBrackets (line 11467) | function matchBrackets(cm, autoclear, config) {
function doMatchBrackets (line 11496) | function doMatchBrackets(cm) {
function clear (line 11507) | function clear(cm) {
function clear (line 11577) | function clear(cm) {
function doMatchTags (line 11583) | function doMatchTags(cm) {
function maybeUpdateMatch (line 11604) | function maybeUpdateMatch(cm) {
function findOpening (line 11670) | function findOpening(openCh) {
function hasImport (line 11715) | function hasImport(line) {
function hasInclude (line 11739) | function hasInclude(line) {
function doFold (line 11840) | function doFold(cm, pos, options, force) {
function makeWidget (line 11887) | function makeWidget(cm, options, range) {
function getOption (line 11971) | function getOption(cm, options, name) {
function State (line 12027) | function State(options) {
function parseOptions (line 12032) | function parseOptions(opts) {
function isFolded (line 12040) | function isFolded(cm, line) {
function marker (line 12051) | function marker(spec) {
function updateFoldInfo (line 12061) | function updateFoldInfo(cm, from, to) {
function classTest (line 12090) | function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)...
function updateInViewport (line 12092) | function updateInViewport(cm) {
function onGutterClick (line 12101) | function onGutterClick(cm, line, gutter) {
function onChange (line 12111) | function onChange(cm) {
function onViewportChange (line 12120) | function onViewportChange(cm) {
function onFold (line 12144) | function onFold(cm, from) {
function lineIndent (line 12170) | function lineIndent(cm, lineNo) {
function isHeader (line 12226) | function isHeader(lineNo) {
function headerLevel (line 12231) | function headerLevel(lineNo, line, nextLine) {
function cmp (line 12278) | function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
function Iter (line 12284) | function Iter(cm, line, ch, range) {
function tagAt (line 12291) | function tagAt(iter, ch) {
function nextLine (line 12296) | function nextLine(iter) {
function prevLine (line 12302) | function prevLine(iter) {
function toTagEnd (line 12309) | function toTagEnd(iter) {
function toTagStart (line 12320) | function toTagStart(iter) {
function toNextTag (line 12332) | function toNextTag(iter) {
function toPrevTag (line 12342) | function toPrevTag(iter) {
function findMatchingClose (line 12354) | function findMatchingClose(iter, tag) {
function findMatchingOpen (line 12375) | function findMatchingOpen(iter, tag) {
function populate (line 12832) | function populate(obj) {
function htmlHint (line 12842) | function htmlHint(cm, options) {
function Completion (line 12906) | function Completion(cm, options) {
function parseOptions (line 13004) | function parseOptions(cm, pos, options) {
function getText (line 13016) | function getText(completion) {
function buildKeyMap (line 13021) | function buildKeyMap(completion, handle) {
function getHintElement (line 13064) | function getHintElement(hintsElement, el) {
function Widget (line 13071) | function Widget(completion, data) {
function applicableHelpers (line 13250) | function applicableHelpers(cm, helpers) {
function fetchHints (line 13258) | function fetchHints(hint, cm, options, callback) {
function resolveAutoHints (line 13268) | function resolveAutoHints(cm, pos) {
function isArray (line 13361) | function isArray(val) { return Object.prototype.toString.call(val) == "[...
function getKeywords (line 13363) | function getKeywords(editor) {
function getIdentifierQuote (line 13369) | function getIdentifierQuote(editor) {
function getText (line 13375) | function getText(item) {
function wrapTable (line 13379) | function wrapTable(name, value) {
function parseTables (line 13385) | function parseTables(input) {
function getTable (line 13399) | function getTable(name) {
function shallowClone (line 13403) | function shallowClone(object) {
function match (line 13410) | function match(string, word) {
function addMatches (line 13416) | function addMatches(result, search, wordlist, formatter) {
function cleanName (line 13432) | function cleanName(name) {
function insertIdentifierQuotes (line 13445) | function insertIdentifierQuotes(name) {
function nameCompletion (line 13459) | function nameCompletion(cur, token, result, editor) {
function eachWord (line 13524) | function eachWord(lineText, f) {
function findTableByAlias (line 13530) | function findTableByAlias(alias, editor) {
function matches (line 13662) | function matches(hint, typed, matchInMiddle) {
function getHints (line 13667) | function getHints(cm, options) {
function o (line 13820) | function o(a){d.length=d.length-2*a,e.length=e.length-a,f.length=f.lengt...
function p (line 13820) | function p(){var a;return a=c.lexer.lex()||1,typeof a!="number"&&(a=c.sy...
function showTooltip (line 13839) | function showTooltip(cm, e, content) {
function rm (line 13858) | function rm(elt) {
function hideTooltip (line 13861) | function hideTooltip(tt) {
function showTooltipFor (line 13868) | function showTooltipFor(cm, e, content, node) {
function LintState (line 13885) | function LintState(cm, options, hasGutter) {
function parseOptions (line 13894) | function parseOptions(_cm, options) {
function clearMarks (line 13900) | function clearMarks(cm) {
function makeMarker (line 13908) | function makeMarker(cm, labels, severity, multiple, tooltips) {
function getMaxSeverity (line 13923) | function getMaxSeverity(a, b) {
function groupByLine (line 13928) | function groupByLine(annotations) {
function annotationTooltip (line 13937) | function annotationTooltip(ann) {
function lintAsync (line 13950) | function lintAsync(cm, getAnnotations, passOptions) {
function startLinting (line 13966) | function startLinting(cm) {
function updateLinting (line 13987) | function updateLinting(cm, annotationsNotSorted) {
function onChange (line 14022) | function onChange(cm) {
function popupTooltips (line 14029) | function popupTooltips(cm, annotations, e) {
function onMouseOver (line 14039) | function onMouseOver(cm, e) {
function Annotation (line 14105) | function Annotation(cm, options) {
function getY (line 14159) | function getY(pos, top) {
function onChange (line 14239) | function onChange(cm, change) {
function updateBottomMargin (line 14244) | function updateBottomMargin(cm) {
function Bar (line 14278) | function Bar(cls, orientation, scroll) {
function SimpleScrollbars (line 14360) | function SimpleScrollbars(cls, place, scroll) {
function dialog (line 14437) | function dialog(cm, text, shortText, deflt, f) {
function getJumpDialog (line 14442) | function getJumpDialog(cm) {
function interpretLine (line 14446) | function interpretLine(cm, string) {
function State (line 14518) | function State(options) {
function cursorActivity (line 14547) | function cursorActivity(cm) {
function onFocus (line 14552) | function onFocus(cm) {
function scheduleHighlight (line 14560) | function scheduleHighlight(cm, state) {
function addOverlay (line 14565) | function addOverlay(cm, query, hasBoundary, style) {
function removeOverlay (line 14577) | function removeOverlay(cm) {
function highlightMatches (line 14589) | function highlightMatches(cm) {
function isWord (line 14612) | function isWord(cm, from, to) {
function boundariesAround (line 14629) | function boundariesAround(stream, re) {
function makeOverlay (line 14634) | function makeOverlay(query, hasBoundary, style) {
function SearchAnnotation (line 14668) | function SearchAnnotation(cm, query, caseFold, options) {
function offsetLine (line 14708) | function offsetLine(line, changeStart, sizeChange) {
function searchOverlay (line 14772) | function searchOverlay(query, caseInsensitive) {
function SearchState (line 14792) | function SearchState() {
function getSearchState (line 14797) | function getSearchState(cm) {
function queryCaseInsensitive (line 14801) | function queryCaseInsensitive(query) {
function getSearchCursor (line 14805) | function getSearchCursor(cm, query, pos) {
function persistentDialog (line 14810) | function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
function dialog (line 14820) | function dialog(cm, text, shortText, deflt, f) {
function confirmDialog (line 14825) | function confirmDialog(cm, text, shortText, fs) {
function parseString (line 14830) | function parseString(string) {
function parseQuery (line 14840) | function parseQuery(query) {
function startSearch (line 14853) | function startSearch(cm, state, query) {
function doSearch (line 14865) | function doSearch(cm, rev, persistent, immediate) {
function findNext (line 14916) | function findNext(cm, rev, callback) {cm.operation(function() {
function clearSearch (line 14929) | function clearSearch(cm) {cm.operation(function() {
function getQueryDialog (line 14939) | function getQueryDialog(cm) {
function getReplaceQueryDialog (line 14942) | function getReplaceQueryDialog(cm) {
function getReplacementQueryDialog (line 14945) | function getReplacementQueryDialog(cm) {
function getDoReplaceConfirm (line 14948) | function getDoReplaceConfirm(cm) {
function replaceAll (line 14952) | function replaceAll(cm, query, text) {
function replace (line 14963) | function replace(cm, all) {
function regexpFlags (line 15030) | function regexpFlags(regexp) {
function ensureFlags (line 15037) | function ensureFlags(regexp, flags) {
function maybeMultiline (line 15044) | function maybeMultiline(regexp) {
function searchRegexpForward (line 15048) | function searchRegexpForward(doc, regexp, start) {
function searchRegexpForwardMultiline (line 15060) | function searchRegexpForwardMultiline(doc, regexp, start) {
function lastMatchIn (line 15090) | function lastMatchIn(string, regexp, endMargin) {
function searchRegexpBackward (line 15105) | function searchRegexpBackward(doc, regexp, start) {
function searchRegexpBackwardMultiline (line 15117) | function searchRegexpBackwardMultiline(doc, regexp, start) {
function adjustPos (line 15151) | function adjustPos(orig, folded, pos, foldFunc) {
function searchStringForward (line 15163) | function searchStringForward(doc, query, start, caseFold) {
function searchStringBackward (line 15191) | function searchStringBackward(doc, query, start, caseFold) {
function SearchCursor (line 15218) | function SearchCursor(doc, query, pos, options) {
function clearActiveLines (line 15348) | function clearActiveLines(cm) {
function sameArray (line 15356) | function sameArray(a, b) {
function updateActiveLines (line 15363) | function updateActiveLines(cm, ranges) {
function selectionChange (line 15385) | function selectionChange(cm, sel) {
function onCursorActivity (line 15429) | function onCursorActivity(cm) {
function onChange (line 15434) | function onChange(cm) {
function coverRange (line 15443) | function coverRange(cm, from, to, addAt) {
function clear (line 15459) | function clear(cm) {
function reset (line 15465) | function reset(cm) {
function update (line 15472) | function update(cm) {
function mousemove (line 15560) | function mousemove(cm, event) {
function mouseout (line 15571) | function mouseout(cm, event) {
function reset (line 15579) | function reset(cm) {
function scheduleUpdate (line 15584) | function scheduleUpdate(cm) {
function update (line 15594) | function update(cm) {
function wordRegexp (line 15641) | function wordRegexp(words) {
function tokenBase (line 15670) | function tokenBase(stream, state) {
function tokenFactory (line 15799) | function tokenFactory(delimiter, singleline, outclass) {
function longComment (line 15826) | function longComment(stream, state) {
function indent (line 15838) | function indent(stream, state, type) {
function dedent (line 15862) | function dedent(stream, state) {
function tokenLexer (line 15886) | function tokenLexer(stream, state) {
function ret (line 16019) | function ret(style, tp) { type = tp; return style; }
function tokenBase (line 16023) | function tokenBase(stream, state) {
function tokenString (line 16077) | function tokenString(quote) {
function tokenParenthesized (line 16092) | function tokenParenthesized(stream, state) {
function Context (line 16103) | function Context(type, indent, prev) {
function pushContext (line 16109) | function pushContext(state, stream, type, indent) {
function popContext (line 16114) | function popContext(state) {
function pass (line 16120) | function pass(type, stream, state) {
function popAndPass (line 16123) | function popAndPass(type, stream, state, n) {
function wordAsValue (line 16131) | function wordAsValue(stream) {
function keySet (line 16402) | function keySet(array) {
function tokenCComment (line 16707) | function tokenCComment(stream, state) {
function tokenBase (line 16890) | function tokenBase(stream, state) {
function tokenString (line 16934) | function tokenString(quote) {
function tokenComment (line 16947) | function tokenComment(stream, state) {
function Context (line 16959) | function Context(indented, column, type, align, prev) {
function pushContext (line 16966) | function pushContext(state, col, type) {
function popContext (line 16969) | function popContext(state) {
function maybeBackup (line 17112) | function maybeBackup(stream, pat, style) {
function getAttrRegexp (line 17124) | function getAttrRegexp(attr) {
function getAttrValue (line 17130) | function getAttrValue(text, attr) {
function getTagRegexp (line 17135) | function getTagRegexp(tagName, anchored) {
function addTags (line 17139) | function addTags(from, to) {
function findMatchingMode (line 17148) | function findMatchingMode(tagInfo, tagText) {
function html (line 17170) | function html(stream, state) {
function kw (line 17265) | function kw(type) {return {type: type, style: "keyword"};}
function readRegexp (line 17286) | function readRegexp(stream) {
function ret (line 17301) | function ret(tp, style, cont) {
function tokenBase (line 17305) | function tokenBase(stream, state) {
function tokenString (line 17376) | function tokenString(quote) {
function tokenComment (line 17392) | function tokenComment(stream, state) {
function tokenQuasi (line 17404) | function tokenQuasi(stream, state) {
function findFatArrow (line 17424) | function findFatArrow(stream, state) {
function JSLexical (line 17463) | function JSLexical(indented, column, type, align, prev, info) {
function inScope (line 17472) | function inScope(state, varname) {
function parseJS (line 17481) | function parseJS(state, style, type, content, stream) {
function pass (line 17505) | function pass() {
function cont (line 17508) | function cont() {
function inList (line 17512) | function inList(name, list) {
function register (line 17516) | function register(varname) {
function registerVarScoped (line 17536) | function registerVarScoped(varname, context) {
function isModifier (line 17551) | function isModifier(name) {
function Context (line 17557) | function Context(prev, vars, block) { this.prev = prev; this.vars = vars...
function Var (line 17558) | function Var(name, next) { this.name = name; this.next = next }
function pushcontext (line 17561) | function pushcontext() {
function pushblockcontext (line 17565) | function pushblockcontext() {
function popcontext (line 17569) | function popcontext() {
function pushlex (line 17574) | function pushlex(type, info) {
function poplex (line 17585) | function poplex() {
function expect (line 17595) | function expect(wanted) {
function statement (line 17604) | function statement(type, value) {
function maybeCatchBinding (line 17653) | function maybeCatchBinding(type) {
function expression (line 17656) | function expression(type, value) {
function expressionNoComma (line 17659) | function expressionNoComma(type, value) {
function parenExpr (line 17662) | function parenExpr(type) {
function expressionInner (line 17666) | function expressionInner(type, value, noComma) {
function maybeexpression (line 17687) | function maybeexpression(type) {
function maybeoperatorComma (line 17692) | function maybeoperatorComma(type, value) {
function maybeoperatorNoComma (line 17696) | function maybeoperatorNoComma(type, value, noComma) {
function quasi (line 17719) | function quasi(type, value) {
function continueQuasi (line 17724) | function continueQuasi(type) {
function arrowBody (line 17731) | function arrowBody(type) {
function arrowBodyNoComma (line 17735) | function arrowBodyNoComma(type) {
function maybeTarget (line 17739) | function maybeTarget(noComma) {
function target (line 17746) | function target(_, value) {
function targetNoComma (line 17749) | function targetNoComma(_, value) {
function maybelabel (line 17752) | function maybelabel(type) {
function property (line 17756) | function property(type) {
function objprop (line 17759) | function objprop(type, value) {
function getterSetter (line 17789) | function getterSetter(type) {
function afterprop (line 17794) | function afterprop(type) {
function commasep (line 17798) | function commasep(what, end, sep) {
function contCommasep (line 17817) | function contCommasep(what, end, info) {
function block (line 17822) | function block(type) {
function maybetype (line 17826) | function maybetype(type, value) {
function maybetypeOrIn (line 17832) | function maybetypeOrIn(type, value) {
function mayberettype (line 17835) | function mayberettype(type) {
function isKW (line 17841) | function isKW(_, value) {
function typeexpr (line 17847) | function typeexpr(type, value) {
function maybeReturnType (line 17863) | function maybeReturnType(type) {
function typeprop (line 17866) | function typeprop(type, value) {
function typearg (line 17880) | function typearg(type, value) {
function afterType (line 17886) | function afterType(type, value) {
function maybeTypeArgs (line 17893) | function maybeTypeArgs(_, value) {
function typeparam (line 17896) | function typeparam() {
function maybeTypeDefault (line 17899) | function maybeTypeDefault(_, value) {
function vardef (line 17902) | function vardef(_, value) {
function pattern (line 17906) | function pattern(type, value) {
function proppattern (line 17913) | function proppattern(type, value) {
function eltpattern (line 17924) | function eltpattern() {
function maybeAssign (line 17927) | function maybeAssign(_type, value) {
function vardefCont (line 17930) | function vardefCont(type) {
function maybeelse (line 17933) | function maybeelse(type, value) {
function forspec (line 17936) | function forspec(type, value) {
function forspec1 (line 17940) | function forspec1(type) {
function forspec2 (line 17945) | function forspec2(type, value) {
function functiondef (line 17951) | function functiondef(type, value) {
function functiondecl (line 17957) | function functiondecl(type, value) {
function typename (line 17963) | function typename(type, value) {
function funarg (line 17971) | function funarg(type, value) {
function classExpression (line 17978) | function classExpression(type, value) {
function className (line 17983) | function className(type, value) {
function classNameAfter (line 17986) | function classNameAfter(type, value) {
function classBody (line 17994) | function classBody(type, value) {
function classfield (line 18018) | function classfield(type, value) {
function afterExport (line 18025) | function afterExport(type, value) {
function exportField (line 18031) | function exportField(type, value) {
function afterImport (line 18035) | function afterImport(type) {
function importSpec (line 18040) | function importSpec(type, value) {
function maybeMoreImports (line 18046) | function maybeMoreImports(type) {
function maybeAs (line 18049) | function maybeAs(_type, value) {
function maybeFrom (line 18052) | function maybeFrom(_type, value) {
function arrayLiteral (line 18055) | function arrayLiteral(type) {
function enumdef (line 18059) | function enumdef() {
function enummember (line 18062) | function enummember() {
function isContinuedStatement (line 18066) | function isContinuedStatement(state, textAfter) {
function expressionAllowed (line 18072) | function expressionAllowed(stream, state, backUp) {
function getMode (line 18198) | function getMode(name) {
function switchInline (line 18279) | function switchInline(stream, state, f) {
function switchBlock (line 18284) | function switchBlock(stream, state, f) {
function lineIsEmpty (line 18289) | function lineIsEmpty(line) {
function blankLine (line 18295) | function blankLine(state) {
function blockNormal (line 18332) | function blockNormal(stream, state) {
function htmlBlock (line 18463) | function htmlBlock(stream, state) {
function local (line 18478) | function local(stream, state) {
function getType (line 18503) | function getType(state) {
function handleText (line 18586) | function handleText(stream, state) {
function inlineNormal (line 18593) | function inlineNormal(stream, state) {
function linkInline (line 18823) | function linkInline(stream, state) {
function linkHref (line 18843) | function linkHref(stream, state) {
function getLinkHrefInside (line 18863) | function getLinkHrefInside(endChar) {
function footnoteLink (line 18881) | function footnoteLink(stream, state) {
function footnoteLinkInside (line 18892) | function footnoteLinkInside(stream, state) {
function footnoteUrl (line 18906) | function footnoteUrl(stream, state) {
function wordRegexp (line 19084) | function wordRegexp(words) {
function top (line 19107) | function top(state) {
function tokenBase (line 19148) | function tokenBase(stream, state) {
function tokenBaseInner (line 19171) | function tokenBaseInner(stream, state, inFormat) {
function formatStringFactory (line 19253) | function formatStringFactory(delimiter, tokenOuter) {
function tokenStringFactory (line 19314) | function tokenStringFactory(delimiter, tokenOuter) {
function pushPyScope (line 19347) | function pushPyScope(state) {
function pushBracketScope (line 19354) | function pushBracketScope(stream, state, type) {
function dedent (line 19361) | function dedent(stream, state) {
function tokenLexer (line 19370) | function tokenLexer(stream, state) {
function inText (line 19620) | function inText(stream, state) {
function inTag (line 19668) | function inTag(stream, state) {
function inAttribute (line 19693) | function inAttribute(quote) {
function inBlock (line 19707) | function inBlock(style, terminator) {
function doctype (line 19720) | function doctype(depth) {
function Context (line 19741) | function Context(state, tagName, startOfLine) {
function popContext (line 19749) | function popContext(state) {
function maybePopContext (line 19752) | function maybePopContext(state, nextTagName) {
function baseState (line 19767) | function baseState(type, stream, state) {
function tagNameState (line 19777) | function tagNameState(type, stream, state) {
function closeTagNameState (line 19790) | function closeTagNameState(type, stream, state) {
function closeState (line 19812) | function closeState(type, _stream, state) {
function closeStateErr (line 19820) | function closeStateErr(type, stream, state) {
function attrState (line 19825) | function attrState(type, _stream, state) {
function attrEqState (line 19844) | function attrEqState(type, stream, state) {
function attrValueState (line 19849) | function attrValueState(type, stream, state) {
function attrContinuedState (line 19855) | function attrContinuedState(type, stream, state) {
FILE: plugins/UiFileManager/media/codemirror/base/codemirror.js
function classTest (line 50) | function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)...
function removeChildren (line 61) | function removeChildren(e) {
function removeChildrenAndAdd (line 67) | function removeChildrenAndAdd(parent, e) {
function elt (line 71) | function elt(tag, content, className, style) {
function eltP (line 80) | function eltP(tag, content, className, style) {
function contains (line 103) | function contains(parent, child) {
function activeElt (line 114) | function activeElt() {
function addClass (line 129) | function addClass(node, cls) {
function joinClasses (line 133) | function joinClasses(a, b) {
function bind (line 146) | function bind(f) {
function copyObj (line 151) | function copyObj(obj, target, overwrite) {
function countColumn (line 161) | function countColumn(string, end, tabSize, startIndex, startValue) {
function indexOf (line 200) | function indexOf(array, elt) {
function findColumn (line 218) | function findColumn(string, goal, tabSize) {
function spaceStr (line 233) | function spaceStr(n) {
function lst (line 239) | function lst(arr) { return arr[arr.length-1] }
function map (line 241) | function map(array, f) {
function insertSorted (line 247) | function insertSorted(array, value, score) {
function nothing (line 253) | function nothing() {}
function createObj (line 255) | function createObj(base, props) {
function isWordCharBasic (line 268) | function isWordCharBasic(ch) {
function isWordChar (line 272) | function isWordChar(ch, helper) {
function isEmpty (line 278) | function isEmpty(obj) {
function isExtendingChar (line 289) | function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendi...
function skipExtendingChars (line 292) | function skipExtendingChars(str, pos, dir) {
function findFirst (line 300) | function findFirst(pred, from, to) {
function iterateBidiSections (line 315) | function iterateBidiSections(order, from, to, f) {
function getBidiPartAt (line 329) | function getBidiPartAt(order, ch, sticky) {
function charType (line 375) | function charType(code) {
function BidiSpan (line 388) | function BidiSpan(level, from, to) {
function getOrder (line 521) | function getOrder(line, direction) {
function getHandlers (line 545) | function getHandlers(emitter, type) {
function off (line 549) | function off(emitter, type, f) {
function signal (line 564) | function signal(emitter, type /*, values...*/) {
function signalDOMEvent (line 574) | function signalDOMEvent(cm, e, override) {
function signalCursorActivity (line 581) | function signalCursorActivity(cm) {
function hasHandler (line 589) | function hasHandler(emitter, type) {
function eventMixin (line 595) | function eventMixin(ctor) {
function e_preventDefault (line 603) | function e_preventDefault(e) {
function e_stopPropagation (line 607) | function e_stopPropagation(e) {
function e_defaultPrevented (line 611) | function e_defaultPrevented(e) {
function e_stop (line 614) | function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
function e_target (line 616) | function e_target(e) {return e.target || e.srcElement}
function e_button (line 617) | function e_button(e) {
function zeroWidthElement (line 638) | function zeroWidthElement(measure) {
function hasBadBidiRects (line 653) | function hasBadBidiRects(measure) {
function hasBadZoomedRects (line 702) | function hasBadZoomedRects(measure) {
function defineMode (line 716) | function defineMode(name, mode) {
function defineMIME (line 722) | function defineMIME(mime, spec) {
function resolveMode (line 728) | function resolveMode(spec) {
function getMode (line 747) | function getMode(options, spec) {
function extendMode (line 771) | function extendMode(mode, properties) {
function copyState (line 776) | function copyState(mode, state) {
function innerMode (line 790) | function innerMode(mode, state) {
function startState (line 801) | function startState(mode, a1, a2) {
function getLine (line 891) | function getLine(doc, n) {
function getBetween (line 907) | function getBetween(doc, start, end) {
function getLines (line 919) | function getLines(doc, from, to) {
function updateLineHeight (line 927) | function updateLineHeight(line, height) {
function lineNo (line 934) | function lineNo(line) {
function lineAtHeight (line 948) | function lineAtHeight(chunk, h) {
function isLine (line 968) | function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
function lineNumberFor (line 970) | function lineNumberFor(options, i) {
function Pos (line 975) | function Pos(line, ch, sticky) {
function cmp (line 986) | function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
function equalCursorPos (line 988) | function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b)...
function copyPos (line 990) | function copyPos(x) {return Pos(x.line, x.ch)}
function maxPos (line 991) | function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
function minPos (line 992) | function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
function clipLine (line 996) | function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.fi...
function clipPos (line 997) | function clipPos(doc, pos) {
function clipToLen (line 1003) | function clipToLen(pos, linelen) {
function clipPosArray (line 1009) | function clipPosArray(doc, array) {
function highlightLine (line 1066) | function highlightLine(cm, line, context, forceToEnd) {
function getLineStyles (line 1111) | function getLineStyles(cm, line, updateFrontier) {
function getContextBefore (line 1127) | function getContextBefore(cm, n, precise) {
function processLine (line 1147) | function processLine(cm, text, context, startAt) {
function callBlankLine (line 1158) | function callBlankLine(mode, state) {
function readToken (line 1165) | function readToken(mode, stream, state, inner) {
function takeToken (line 1182) | function takeToken(cm, pos, precise, asArray) {
function extractLineClasses (line 1196) | function extractLineClasses(type, output) {
function runMode (line 1211) | function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
function findStartLine (line 1255) | function findStartLine(cm, n, precise) {
function retreatFrontier (line 1272) | function retreatFrontier(doc, n) {
function seeReadOnlySpans (line 1292) | function seeReadOnlySpans() {
function seeCollapsedSpans (line 1296) | function seeCollapsedSpans() {
function MarkedSpan (line 1302) | function MarkedSpan(marker, from, to) {
function getMarkedSpanFor (line 1308) | function getMarkedSpanFor(spans, marker) {
function removeMarkedSpan (line 1316) | function removeMarkedSpan(spans, span) {
function addMarkedSpan (line 1323) | function addMarkedSpan(line, span) {
function markedSpansBefore (line 1332) | function markedSpansBefore(old, startCh, isInsert) {
function markedSpansAfter (line 1344) | function markedSpansAfter(old, endCh, isInsert) {
function stretchSpansOverChange (line 1364) | function stretchSpansOverChange(doc, change) {
function clearEmptySpans (line 1426) | function clearEmptySpans(spans) {
function removeReadOnlyRanges (line 1437) | function removeReadOnlyRanges(doc, from, to) {
function detachMarkedSpans (line 1466) | function detachMarkedSpans(line) {
function attachMarkedSpans (line 1473) | function attachMarkedSpans(line, spans) {
function extraLeft (line 1482) | function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
function extraRight (line 1483) | function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
function compareCollapsedMarkers (line 1488) | function compareCollapsedMarkers(a, b) {
function collapsedSpanAtSide (line 1501) | function collapsedSpanAtSide(line, start) {
function collapsedSpanAtStart (line 1511) | function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, t...
function collapsedSpanAtEnd (line 1512) | function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, fal...
function collapsedSpanAround (line 1514) | function collapsedSpanAround(line, ch) {
function conflictingCollapsedRange (line 1527) | function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
function visualLine (line 1547) | function visualLine(line) {
function visualLineEnd (line 1554) | function visualLineEnd(line) {
function visualLineContinued (line 1563) | function visualLineContinued(line) {
function visualLineNo (line 1574) | function visualLineNo(doc, lineN) {
function visualLineEndNo (line 1582) | function visualLineEndNo(doc, lineN) {
function lineIsHidden (line 1594) | function lineIsHidden(doc, line) {
function lineIsHiddenInner (line 1605) | function lineIsHiddenInner(doc, line, span) {
function heightAtLine (line 1622) | function heightAtLine(lineObj) {
function lineLength (line 1644) | function lineLength(line) {
function findMaxLine (line 1663) | function findMaxLine(cm) {
function updateLine (line 1693) | function updateLine(line, text, markedSpans, estimateHeight) {
function cleanUpLine (line 1705) | function cleanUpLine(line) {
function interpretTokenStyle (line 1714) | function interpretTokenStyle(style, options) {
function buildLineContent (line 1726) | function buildLineContent(cm, lineView) {
function defaultSpecialCharPlaceholder (line 1784) | function defaultSpecialCharPlaceholder(ch) {
function buildToken (line 1793) | function buildToken(builder, text, style, startStyle, endStyle, css, att...
function splitSpaces (line 1860) | function splitSpaces(text, trailingBefore) {
function buildTokenBadBidi (line 1875) | function buildTokenBadBidi(inner, order) {
function buildCollapsedSpan (line 1895) | function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
function insertLineContent (line 1913) | function insertLineContent(line, builder, styles) {
function LineView (line 1992) | function LineView(doc, line, lineN) {
function buildViewArray (line 2004) | function buildViewArray(cm, from, to) {
function pushOperation (line 2016) | function pushOperation(op) {
function fireCallbacksForOps (line 2027) | function fireCallbacksForOps(group) {
function finishOperation (line 2043) | function finishOperation(op, endCb) {
function signalLater (line 2063) | function signalLater(emitter, type /*, values...*/) {
function fireOrphanDelayed (line 2083) | function fireOrphanDelayed() {
function updateLineForChanges (line 2092) | function updateLineForChanges(cm, lineView, lineN, dims) {
function ensureLineWrapped (line 2105) | function ensureLineWrapped(lineView) {
function updateLineBackground (line 2116) | function updateLineBackground(cm, lineView) {
function getLineContent (line 2131) | function getLineContent(cm, lineView) {
function updateLineText (line 2144) | function updateLineText(cm, lineView) {
function updateLineClasses (line 2159) | function updateLineClasses(cm, lineView) {
function updateLineGutter (line 2169) | function updateLineGutter(cm, lineView, lineN, dims) {
function updateLineWidgets (line 2207) | function updateLineWidgets(cm, lineView, dims) {
function buildLineElement (line 2218) | function buildLineElement(cm, lineView, lineN, dims) {
function insertLineWidgets (line 2232) | function insertLineWidgets(cm, lineView, dims) {
function insertLineWidgetsFor (line 2238) | function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
function positionLineWidget (line 2254) | function positionLineWidget(widget, node, lineView, dims) {
function widgetHeight (line 2272) | function widgetHeight(widget) {
function eventInWidget (line 2288) | function eventInWidget(display, e) {
function paddingTop (line 2298) | function paddingTop(display) {return display.lineSpace.offsetTop}
function paddingVert (line 2299) | function paddingVert(display) {return display.mover.offsetHeight - displ...
function paddingH (line 2300) | function paddingH(display) {
function scrollGap (line 2309) | function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
function displayWidth (line 2310) | function displayWidth(cm) {
function displayHeight (line 2313) | function displayHeight(cm) {
function ensureLineHeights (line 2321) | function ensureLineHeights(cm, lineView, rect) {
function mapFromLineView (line 2342) | function mapFromLineView(lineView, line, lineN) {
function updateExternalMeasurement (line 2355) | function updateExternalMeasurement(cm, line) {
function measureChar (line 2368) | function measureChar(cm, line, ch, bias) {
function findViewForLine (line 2373) | function findViewForLine(cm, lineN) {
function prepareMeasureForLine (line 2386) | function prepareMeasureForLine(cm, line) {
function measureCharPrepared (line 2408) | function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
function nodeAndOffsetInLineMap (line 2430) | function nodeAndOffsetInLineMap(map, ch, bias) {
function getUsefulRect (line 2468) | function getUsefulRect(rects, bias) {
function measureCharInner (line 2478) | function measureCharInner(cm, prepared, ch, bias) {
function maybeUpdateRectForZooming (line 2531) | function maybeUpdateRectForZooming(measure, rect) {
function clearLineMeasurementCacheFor (line 2541) | function clearLineMeasurementCacheFor(lineView) {
function clearLineMeasurementCache (line 2550) | function clearLineMeasurementCache(cm) {
function clearCaches (line 2557) | function clearCaches(cm) {
function pageScrollX (line 2564) | function pageScrollX() {
function pageScrollY (line 2571) | function pageScrollY() {
function widgetTopHeight (line 2576) | function widgetTopHeight(lineObj) {
function intoCoordSystem (line 2587) | function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
function fromCoordSystem (line 2609) | function fromCoordSystem(cm, coords, context) {
function charCoords (line 2626) | function charCoords(cm, pos, context, lineObj, bias) {
function cursorCoords (line 2647) | function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHei...
function estimateCoords (line 2678) | function estimateCoords(cm, pos) {
function PosWithInfo (line 2693) | function PosWithInfo(line, ch, sticky, outside, xRel) {
function coordsChar (line 2702) | function coordsChar(cm, x, y) {
function wrappedLineExtent (line 2722) | function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
function wrappedLineExtentChar (line 2730) | function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
function boxIsAfter (line 2738) | function boxIsAfter(box, x, y, left) {
function coordsCharInner (line 2742) | function coordsCharInner(cm, lineObj, lineNo, x, y) {
function coordsBidiPart (line 2809) | function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, ...
function coordsBidiPartWrapped (line 2833) | function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, or...
function textHeight (line 2868) | function textHeight(display) {
function charWidth (line 2888) | function charWidth(display) {
function getDimensions (line 2900) | function getDimensions(cm) {
function compensateForHScroll (line 2918) | function compensateForHScroll(display) {
function estimateHeight (line 2925) | function estimateHeight(cm) {
function estimateLineHeights (line 2943) | function estimateLineHeights(cm) {
function posFromMouse (line 2956) | function posFromMouse(cm, e, liberal, forRect) {
function findViewIndex (line 2974) | function findViewIndex(cm, n) {
function regChange (line 2991) | function regChange(cm, from, to, lendiff) {
function regLineChange (line 3056) | function regLineChange(cm, line, type) {
function resetView (line 3070) | function resetView(cm) {
function viewCuttingPoint (line 3076) | function viewCuttingPoint(cm, oldN, newN, dir) {
function adjustView (line 3103) | function adjustView(cm, from, to) {
function countDirtyView (line 3124) | function countDirtyView(cm) {
function updateSelection (line 3133) | function updateSelection(cm) {
function prepareSelection (line 3137) | function prepareSelection(cm, primary) {
function drawSelectionCursor (line 3158) | function drawSelectionCursor(cm, head, output) {
function cmpCoords (line 3176) | function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
function drawSelectionRange (line 3179) | function drawSelectionRange(cm, range, output) {
function restartBlink (line 3272) | function restartBlink(cm) {
function ensureFocus (line 3285) | function ensureFocus(cm) {
function delayBlurEvent (line 3289) | function delayBlurEvent(cm) {
function onFocus (line 3297) | function onFocus(cm, e) {
function onBlur (line 3316) | function onBlur(cm, e) {
function updateHeightsInViewport (line 3330) | function updateHeightsInViewport(cm) {
function updateWidgetHeight (line 3369) | function updateWidgetHeight(line) {
function visibleLines (line 3379) | function visibleLines(display, doc, viewport) {
function maybeScrollWindow (line 3404) | function maybeScrollWindow(cm, rect) {
function scrollPosIntoView (line 3421) | function scrollPosIntoView(cm, pos, end, margin) {
function scrollIntoView (line 3455) | function scrollIntoView(cm, rect) {
function calculateScrollPos (line 3465) | function calculateScrollPos(cm, rect) {
function addToScrollTop (line 3495) | function addToScrollTop(cm, top) {
function ensureCursorVisible (line 3503) | function ensureCursorVisible(cm) {
function scrollToCoords (line 3509) | function scrollToCoords(cm, x, y) {
function scrollToRange (line 3515) | function scrollToRange(cm, range) {
function resolveScrollToPos (line 3524) | function resolveScrollToPos(cm) {
function scrollToCoordsRange (line 3533) | function scrollToCoordsRange(cm, from, to, margin) {
function updateScrollTop (line 3545) | function updateScrollTop(cm, val) {
function setScrollTop (line 3553) | function setScrollTop(cm, val, forceScroll) {
function setScrollLeft (line 3563) | function setScrollLeft(cm, val, isScroller, forceScroll) {
function measureForScrollbars (line 3576) | function measureForScrollbars(cm) {
function maybeDisable (line 3668) | function maybeDisable() {
function updateScrollbars (line 3697) | function updateScrollbars(cm, measure) {
function updateScrollbarsInner (line 3711) | function updateScrollbarsInner(cm, measure) {
function initScrollbars (line 3733) | function initScrollbars(cm) {
function startOperation (line 3763) | function startOperation(cm) {
function endOperation (line 3785) | function endOperation(cm) {
function endOperations (line 3796) | function endOperations(group) {
function endOperation_R1 (line 3810) | function endOperation_R1(op) {
function endOperation_W1 (line 3823) | function endOperation_W1(op) {
function endOperation_R2 (line 3827) | function endOperation_R2(op) {
function endOperation_W2 (line 3848) | function endOperation_W2(op) {
function endOperation_finish (line 3873) | function endOperation_finish(op) {
function runInOp (line 3912) | function runInOp(cm, f) {
function operation (line 3919) | function operation(cm, f) {
function methodOp (line 3929) | function methodOp(f) {
function docMethodOp (line 3937) | function docMethodOp(f) {
function startWorker (line 3949) | function startWorker(cm, time) {
function highlightWorker (line 3954) | function highlightWorker(cm) {
function maybeClipScrollbars (line 4022) | function maybeClipScrollbars(cm) {
function selectionSnapshot (line 4033) | function selectionSnapshot(cm) {
function restoreSelection (line 4050) | function restoreSelection(snapshot) {
function updateDisplayIfNeeded (line 4067) | function updateDisplayIfNeeded(cm, update) {
function postUpdateDisplay (line 4139) | function postUpdateDisplay(cm, update) {
function updateDisplaySimple (line 4171) | function updateDisplaySimple(cm, viewport) {
function patchDisplay (line 4188) | function patchDisplay(cm, updateNumbersFrom, dims) {
function updateGutterSpace (line 4229) | function updateGutterSpace(display) {
function setDocumentHeight (line 4234) | function setDocumentHeight(cm, measure) {
function alignHorizontally (line 4242) | function alignHorizontally(cm) {
function maybeUpdateLineNumberWidth (line 4265) | function maybeUpdateLineNumberWidth(cm) {
function getGutters (line 4283) | function getGutters(gutters, lineNumbers) {
function renderGutters (line 4300) | function renderGutters(display) {
function updateGutters (line 4319) | function updateGutters(cm) {
function Display (line 4329) | function Display(place, doc, input, options) {
function wheelEventDelta (line 4452) | function wheelEventDelta(e) {
function wheelEventPixels (line 4459) | function wheelEventPixels(e) {
function onScrollWheel (line 4466) | function onScrollWheel(cm, e) {
function normalizeSelection (line 4597) | function normalizeSelection(cm, ranges, primIndex) {
function simpleSelection (line 4615) | function simpleSelection(anchor, head) {
function changeEnd (line 4621) | function changeEnd(change) {
function adjustForChange (line 4629) | function adjustForChange(pos, change) {
function computeSelAfterChange (line 4638) | function computeSelAfterChange(doc, change) {
function offsetPos (line 4648) | function offsetPos(pos, old, nw) {
function computeReplacedSel (line 4657) | function computeReplacedSel(doc, changes, hint) {
function loadMode (line 4678) | function loadMode(cm) {
function resetModeState (line 4683) | function resetModeState(cm) {
function isWholeLineUpdate (line 4699) | function isWholeLineUpdate(doc, change) {
function updateDoc (line 4705) | function updateDoc(doc, change, markedSpans, estimateHeight) {
function linkedDocs (line 4757) | function linkedDocs(doc, f, sharedHistOnly) {
function attachDoc (line 4772) | function attachDoc(cm, doc) {
function setDirectionClass (line 4784) | function setDirectionClass(cm) {
function directionChanged (line 4788) | function directionChanged(cm) {
function History (line 4795) | function History(startGen) {
function historyChangeFromChange (line 4812) | function historyChangeFromChange(doc, change) {
function clearSelectionEvents (line 4821) | function clearSelectionEvents(array) {
function lastChangeEvent (line 4831) | function lastChangeEvent(hist, force) {
function addChangeToHistory (line 4846) | function addChangeToHistory(doc, change, selAfter, opId) {
function selectionEventCanBeMerged (line 4889) | function selectionEventCanBeMerged(doc, origin, prev, sel) {
function addSelectionToHistory (line 4902) | function addSelectionToHistory(doc, sel, opId, options) {
function pushSelectionToHistory (line 4924) | function pushSelectionToHistory(sel, dest) {
function attachLocalSpans (line 4931) | function attachLocalSpans(doc, change, from, to) {
function removeClearedSpans (line 4942) | function removeClearedSpans(spans) {
function getOldSpans (line 4953) | function getOldSpans(doc, change) {
function mergeOldSpans (line 4966) | function mergeOldSpans(doc, change) {
function copyHistoryArray (line 4990) | function copyHistoryArray(events, newGroup, instantiateSel) {
function extendRange (line 5022) | function extendRange(range, head, other, extend) {
function extendSelection (line 5041) | function extendSelection(doc, head, other, options, extend) {
function extendSelections (line 5048) | function extendSelections(doc, heads, options) {
function replaceOneSelection (line 5058) | function replaceOneSelection(doc, i, range, options) {
function setSimpleSelection (line 5065) | function setSimpleSelection(doc, anchor, head, options) {
function filterSelectionChange (line 5071) | function filterSelectionChange(doc, sel, options) {
function setSelectionReplaceHistory (line 5088) | function setSelectionReplaceHistory(doc, sel, options) {
function setSelection (line 5099) | function setSelection(doc, sel, options) {
function setSelectionNoUndo (line 5104) | function setSelectionNoUndo(doc, sel, options) {
function setSelectionInner (line 5116) | function setSelectionInner(doc, sel) {
function reCheckSelection (line 5131) | function reCheckSelection(doc) {
function skipAtomicInSelection (line 5137) | function skipAtomicInSelection(doc, sel, bias, mayClear) {
function skipAtomicInner (line 5152) | function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
function skipAtomic (line 5192) | function skipAtomic(doc, pos, oldPos, bias, mayClear) {
function movePos (line 5205) | function movePos(doc, pos, dir, line) {
function selectAll (line 5217) | function selectAll(cm) {
function filterChange (line 5224) | function filterChange(doc, change, update) {
function makeChange (line 5251) | function makeChange(doc, change, ignoreReadOnly) {
function makeChangeInner (line 5273) | function makeChangeInner(doc, change) {
function makeChangeFromHistory (line 5291) | function makeChangeFromHistory(doc, type, allowSelectionOnly) {
function shiftDoc (line 5367) | function shiftDoc(doc, distance) {
function makeChangeSingleDoc (line 5383) | function makeChangeSingleDoc(doc, change, selAfter, spans) {
function makeChangeSingleDocInEditor (line 5419) | function makeChangeSingleDocInEditor(cm, change, spans) {
function replaceRange (line 5477) | function replaceRange(doc, code, from, to, origin) {
function rebaseHistSelSingle (line 5488) | function rebaseHistSelSingle(pos, from, to, diff) {
function rebaseHistArray (line 5504) | function rebaseHistArray(array, from, to, diff) {
function rebaseHist (line 5532) | function rebaseHist(hist, change) {
function changeLine (line 5541) | function changeLine(doc, handle, changeType, op) {
function LeafChunk (line 5563) | function LeafChunk(lines) {
function BranchChunk (line 5608) | function BranchChunk(children) {
function adjustScrollWhenAboveVisible (line 5757) | function adjustScrollWhenAboveVisible(cm, line, diff) {
function addLineWidget (line 5762) | function addLineWidget(doc, handle, node, options) {
function markText (line 5918) | function markText(doc, from, to, options, type) {
function markTextShared (line 6013) | function markTextShared(doc, from, to, options, type) {
function findSharedMarkers (line 6028) | function findSharedMarkers(doc) {
function copySharedMarkers (line 6032) | function copySharedMarkers(doc, markers) {
function detachSharedMarkers (line 6044) | function detachSharedMarkers(markers) {
function onDrop (line 6481) | function onDrop(e) {
function onDragStart (line 6552) | function onDragStart(cm, e) {
function onDragOver (line 6575) | function onDragOver(cm, e) {
function clearDragCursor (line 6587) | function clearDragCursor(cm) {
function forEachCodeMirror (line 6598) | function forEachCodeMirror(f) {
function ensureGlobalHandlers (line 6611) | function ensureGlobalHandlers() {
function registerGlobalHandlers (line 6616) | function registerGlobalHandlers() {
function onResize (line 6629) | function onResize(cm) {
function normalizeKeyName (line 6700) | function normalizeKeyName(name) {
function normalizeKeyMap (line 6724) | function normalizeKeyMap(keymap) {
function lookupKey (line 6751) | function lookupKey(key, map, handle, context) {
function isModifierKey (line 6770) | function isModifierKey(value) {
function addModifierNames (line 6775) | function addModifierNames(name, event, noShift) {
function keyName (line 6785) | function keyName(event, noShift) {
function getKeyMap (line 6795) | function getKeyMap(val) {
function deleteNearSelection (line 6801) | function deleteNearSelection(cm, compute) {
function moveCharLogically (line 6824) | function moveCharLogically(line, ch, dir) {
function moveLogically (line 6829) | function moveLogically(line, start, dir) {
function endOfLine (line 6834) | function endOfLine(visually, cm, lineObj, lineNo, dir) {
function moveVisually (line 6862) | function moveVisually(cm, line, start, dir) {
function lineStart (line 7074) | function lineStart(cm, lineN) {
function lineEnd (line 7080) | function lineEnd(cm, lineN) {
function lineStartSmart (line 7086) | function lineStartSmart(cm, pos) {
function doHandleBinding (line 7099) | function doHandleBinding(cm, bound, dropShift) {
function lookupKeyForEditor (line 7119) | function lookupKeyForEditor(cm, name, handle) {
function dispatchKey (line 7133) | function dispatchKey(cm, name, e, handle) {
function dispatchKeyInner (line 7151) | function dispatchKeyInner(cm, name, e, handle) {
function handleKeyBinding (line 7168) | function handleKeyBinding(cm, e) {
function handleCharBinding (line 7187) | function handleCharBinding(cm, e, ch) {
function onKeyDown (line 7192) | function onKeyDown(e) {
function showCrossHair (line 7216) | function showCrossHair(cm) {
function onKeyUp (line 7231) | function onKeyUp(e) {
function onKeyPress (line 7236) | function onKeyPress(e) {
function clickRepeat (line 7264) | function clickRepeat(pos, button) {
function onMouseDown (line 7285) | function onMouseDown(e) {
function handleMappedButton (line 7322) | function handleMappedButton(cm, button, pos, repeat, event) {
function configureMouse (line 7342) | function configureMouse(cm, repeat, event) {
function leftButtonDown (line 7355) | function leftButtonDown(cm, pos, repeat, event) {
function leftButtonStartDrag (line 7373) | function leftButtonStartDrag(cm, event, pos, behavior) {
function rangeForUnit (line 7412) | function rangeForUnit(cm, pos, unit) {
function leftButtonSelect (line 7421) | function leftButtonSelect(cm, event, start, behavior) {
function bidiSimplify (line 7558) | function bidiSimplify(cm, range) {
function gutterEvent (line 7593) | function gutterEvent(cm, e, type, prevent) {
function clickInGutter (line 7622) | function clickInGutter(cm, e) {
function onContextMenu (line 7631) | function onContextMenu(cm, e) {
function contextMenuInGutter (line 7637) | function contextMenuInGutter(cm, e) {
function themeChanged (line 7642) | function themeChanged(cm) {
function defineOptions (line 7653) | function defineOptions(CodeMirror) {
function dragDropChanged (line 7797) | function dragDropChanged(cm, value, old) {
function wrappingChanged (line 7810) | function wrappingChanged(cm) {
function CodeMirror (line 7828) | function CodeMirror(place, options) {
function registerEventHandlers (line 7903) | function registerEventHandlers(cm) {
function indentLine (line 8021) | function indentLine(cm, n, how, aggressive) {
function setLastCopied (line 8085) | function setLastCopied(newLastCopied) {
function applyTextInput (line 8089) | function applyTextInput(cm, inserted, deleted, sel, origin) {
function handlePaste (line 8137) | function handlePaste(e, cm) {
function triggerElectric (line 8147) | function triggerElectric(cm, inserted) {
function copyableRanges (line 8171) | function copyableRanges(cm) {
function disableBrowserMagic (line 8182) | function disableBrowserMagic(field, spellcheck, autocorrect, autocapital...
function hiddenTextarea (line 8188) | function hiddenTextarea() {
function addEditorMethods (line 8211) | function addEditorMethods(CodeMirror) {
function findPosH (line 8651) | function findPosH(doc, pos, dir, unit, visually) {
function findPosV (line 8712) | function findPosV(cm, pos, dir, unit) {
function belongsToInput (line 8750) | function belongsToInput(e) {
function onCopyCut (line 8783) | function onCopyCut(e) {
function poll (line 8950) | function poll() {
function posToDOM (line 9116) | function posToDOM(cm, pos) {
function isInGutter (line 9132) | function isInGutter(node) {
function badPos (line 9138) | function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
function domTextBetween (line 9140) | function domTextBetween(cm, from, to, fromLine, toLine) {
function domToPos (line 9193) | function domToPos(cm, node, offset) {
function locateNodeInLineView (line 9212) | function locateNodeInLineView(lineView, node, offset) {
function prepareCopyCut (line 9309) | function prepareCopyCut(e) {
function p (line 9466) | function p() {
function prepareSelectAllHack (line 9570) | function prepareSelectAllHack() {
function rehide (line 9583) | function rehide() {
function fromTextArea (line 9630) | function fromTextArea(textarea, options) {
function addLegacyProps (line 9687) | function addLegacyProps(CodeMirror) {
FILE: plugins/UiFileManager/media/codemirror/extension/dialog/dialog.js
function dialogDiv (line 14) | function dialogDiv(cm, template, bottom) {
function closeNotification (line 32) | function closeNotification(cm, newVal) {
function close (line 45) | function close(newVal) {
function close (line 106) | function close() {
function close (line 145) | function close() {
FILE: plugins/UiFileManager/media/codemirror/extension/edit/closebrackets.js
function getOption (line 33) | function getOption(conf, name) {
function ensureBound (line 40) | function ensureBound(chars) {
function handler (line 48) | function handler(ch) {
function getConfig (line 52) | function getConfig(cm) {
function handleBackspace (line 59) | function handleBackspace(cm) {
function handleEnter (line 76) | function handleEnter(cm) {
function contractSelection (line 100) | function contractSelection(sel) {
function handleChar (line 106) | function handleChar(cm, ch) {
function charsAround (line 180) | function charsAround(cm, pos) {
function stringStartsAfter (line 186) | function stringStartsAfter(cm, pos) {
FILE: plugins/UiFileManager/media/codemirror/extension/edit/closetag.js
function autoCloseGT (line 55) | function autoCloseGT(cm) {
function autoCloseCurrent (line 108) | function autoCloseCurrent(cm, typingSlash) {
function autoCloseSlash (line 147) | function autoCloseSlash(cm) {
function indexOf (line 154) | function indexOf(collection, elt) {
function closingTagExists (line 163) | function closingTagExists(cm, context, tagName, pos, newTag) {
FILE: plugins/UiFileManager/media/codemirror/extension/edit/continuelist.js
function incrementRemainingMarkdownListNumbers (line 67) | function incrementRemainingMarkdownListNumbers(cm, pos) {
FILE: plugins/UiFileManager/media/codemirror/extension/edit/matchbrackets.js
function bracketRegex (line 19) | function bracketRegex(config) {
function findMatchingBracket (line 23) | function findMatchingBracket(cm, where, config) {
function scanForBracket (line 54) | function scanForBracket(cm, where, dir, style, config) {
function matchBrackets (line 81) | function matchBrackets(cm, autoclear, config) {
function doMatchBrackets (line 110) | function doMatchBrackets(cm) {
function clear (line 121) | function clear(cm) {
FILE: plugins/UiFileManager/media/codemirror/extension/edit/matchtags.js
function clear (line 28) | function clear(cm) {
function doMatchTags (line 34) | function doMatchTags(cm) {
function maybeUpdateMatch (line 55) | function maybeUpdateMatch(cm) {
FILE: plugins/UiFileManager/media/codemirror/extension/fold/brace-fold.js
function findOpening (line 18) | function findOpening(openCh) {
function hasImport (line 63) | function hasImport(line) {
function hasInclude (line 87) | function hasInclude(line) {
FILE: plugins/UiFileManager/media/codemirror/extension/fold/foldcode.js
function doFold (line 14) | function doFold(cm, pos, options, force) {
function makeWidget (line 61) | function makeWidget(cm, options, range) {
function getOption (line 145) | function getOption(cm, options, name) {
FILE: plugins/UiFileManager/media/codemirror/extension/fold/foldgutter.js
function State (line 39) | function State(options) {
function parseOptions (line 44) | function parseOptions(opts) {
function isFolded (line 52) | function isFolded(cm, line) {
function marker (line 63) | function marker(spec) {
function updateFoldInfo (line 73) | function updateFoldInfo(cm, from, to) {
function classTest (line 102) | function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)...
function updateInViewport (line 104) | function updateInViewport(cm) {
function onGutterClick (line 113) | function onGutterClick(cm, line, gutter) {
function onChange (line 123) | function onChange(cm) {
function onViewportChange (line 132) | function onViewportChange(cm) {
function onFold (line 156) | function onFold(cm, from) {
FILE: plugins/UiFileManager/media/codemirror/extension/fold/indent-fold.js
function lineIndent (line 14) | function lineIndent(cm, lineNo) {
FILE: plugins/UiFileManager/media/codemirror/extension/fold/markdown-fold.js
function isHeader (line 17) | function isHeader(lineNo) {
function headerLevel (line 22) | function headerLevel(lineNo, line, nextLine) {
FILE: plugins/UiFileManager/media/codemirror/extension/fold/xml-fold.js
function cmp (line 15) | function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
function Iter (line 21) | function Iter(cm, line, ch, range) {
function tagAt (line 28) | function tagAt(iter, ch) {
function nextLine (line 33) | function nextLine(iter) {
function prevLine (line 39) | function prevLine(iter) {
function toTagEnd (line 46) | function toTagEnd(iter) {
function toTagStart (line 57) | function toTagStart(iter) {
function toNextTag (line 69) | function toNextTag(iter) {
function toPrevTag (line 79) | function toPrevTag(iter) {
function findMatchingClose (line 91) | function findMatchingClose(iter, tag) {
function findMatchingOpen (line 112) | function findMatchingOpen(iter, tag) {
FILE: plugins/UiFileManager/media/codemirror/extension/hint/html-hint.js
function populate (line 334) | function populate(obj) {
function htmlHint (line 344) | function htmlHint(cm, options) {
FILE: plugins/UiFileManager/media/codemirror/extension/hint/show-hint.js
function Completion (line 53) | function Completion(cm, options) {
function parseOptions (line 151) | function parseOptions(cm, pos, options) {
function getText (line 163) | function getText(completion) {
function buildKeyMap (line 168) | function buildKeyMap(completion, handle) {
function getHintElement (line 211) | function getHintElement(hintsElement, el) {
function Widget (line 218) | function Widget(completion, data) {
function applicableHelpers (line 397) | function applicableHelpers(cm, helpers) {
function fetchHints (line 405) | function fetchHints(hint, cm, options, callback) {
function resolveAutoHints (line 415) | function resolveAutoHints(cm, pos) {
FILE: plugins/UiFileManager/media/codemirror/extension/hint/sql-hint.js
function isArray (line 24) | function isArray(val) { return Object.prototype.toString.call(val) == "[...
function getKeywords (line 26) | function getKeywords(editor) {
function getIdentifierQuote (line 32) | function getIdentifierQuote(editor) {
function getText (line 38) | function getText(item) {
function wrapTable (line 42) | function wrapTable(name, value) {
function parseTables (line 48) | function parseTables(input) {
function getTable (line 62) | function getTable(name) {
function shallowClone (line 66) | function shallowClone(object) {
function match (line 73) | function match(string, word) {
function addMatches (line 79) | function addMatches(result, search, wordlist, formatter) {
function cleanName (line 95) | function cleanName(name) {
function insertIdentifierQuotes (line 108) | function insertIdentifierQuotes(name) {
function nameCompletion (line 122) | function nameCompletion(cur, token, result, editor) {
function eachWord (line 187) | function eachWord(lineText, f) {
function findTableByAlias (line 193) | function findTableByAlias(alias, editor) {
FILE: plugins/UiFileManager/media/codemirror/extension/hint/xml-hint.js
function matches (line 16) | function matches(hint, typed, matchInMiddle) {
function getHints (line 21) | function getHints(cm, options) {
FILE: plugins/UiFileManager/media/codemirror/extension/lint/jsonlint.js
function o (line 1) | function o(a){d.length=d.length-2*a,e.length=e.length-a,f.length=f.lengt...
function p (line 1) | function p(){var a;return a=c.lexer.lex()||1,typeof a!="number"&&(a=c.sy...
FILE: plugins/UiFileManager/media/codemirror/extension/lint/lint.js
function showTooltip (line 15) | function showTooltip(cm, e, content) {
function rm (line 34) | function rm(elt) {
function hideTooltip (line 37) | function hideTooltip(tt) {
function showTooltipFor (line 44) | function showTooltipFor(cm, e, content, node) {
function LintState (line 61) | function LintState(cm, options, hasGutter) {
function parseOptions (line 70) | function parseOptions(_cm, options) {
function clearMarks (line 76) | function clearMarks(cm) {
function makeMarker (line 84) | function makeMarker(cm, labels, severity, multiple, tooltips) {
function getMaxSeverity (line 99) | function getMaxSeverity(a, b) {
function groupByLine (line 104) | function groupByLine(annotations) {
function annotationTooltip (line 113) | function annotationTooltip(ann) {
function lintAsync (line 126) | function lintAsync(cm, getAnnotations, passOptions) {
function startLinting (line 142) | function startLinting(cm) {
function updateLinting (line 163) | function updateLinting(cm, annotationsNotSorted) {
function onChange (line 198) | function onChange(cm) {
function popupTooltips (line 205) | function popupTooltips(cm, annotations, e) {
function onMouseOver (line 215) | function onMouseOver(cm, e) {
FILE: plugins/UiFileManager/media/codemirror/extension/scroll/annotatescrollbar.js
function Annotation (line 21) | function Annotation(cm, options) {
function getY (line 75) | function getY(pos, top) {
FILE: plugins/UiFileManager/media/codemirror/extension/scroll/scrollpastend.js
function onChange (line 28) | function onChange(cm, change) {
function updateBottomMargin (line 33) | function updateBottomMargin(cm) {
FILE: plugins/UiFileManager/media/codemirror/extension/scroll/simplescrollbars.js
function Bar (line 14) | function Bar(cls, orientation, scroll) {
function SimpleScrollbars (line 96) | function SimpleScrollbars(cls, place, scroll) {
FILE: plugins/UiFileManager/media/codemirror/extension/search/jump-to-line.js
function dialog (line 16) | function dialog(cm, text, shortText, deflt, f) {
function getJumpDialog (line 21) | function getJumpDialog(cm) {
function interpretLine (line 25) | function interpretLine(cm, string) {
FILE: plugins/UiFileManager/media/codemirror/extension/search/match-highlighter.js
function State (line 42) | function State(options) {
function cursorActivity (line 71) | function cursorActivity(cm) {
function onFocus (line 76) | function onFocus(cm) {
function scheduleHighlight (line 84) | function scheduleHighlight(cm, state) {
function addOverlay (line 89) | function addOverlay(cm, query, hasBoundary, style) {
function removeOverlay (line 101) | function removeOverlay(cm) {
function highlightMatches (line 113) | function highlightMatches(cm) {
function isWord (line 136) | function isWord(cm, from, to) {
function boundariesAround (line 153) | function boundariesAround(stream, re) {
function makeOverlay (line 158) | function makeOverlay(query, hasBoundary, style) {
FILE: plugins/UiFileManager/media/codemirror/extension/search/matchesonscrollbar.js
function SearchAnnotation (line 20) | function SearchAnnotation(cm, query, caseFold, options) {
function offsetLine (line 60) | function offsetLine(line, changeStart, sizeChange) {
FILE: plugins/UiFileManager/media/codemirror/extension/search/search.js
function searchOverlay (line 22) | function searchOverlay(query, caseInsensitive) {
function SearchState (line 42) | function SearchState() {
function getSearchState (line 47) | function getSearchState(cm) {
function queryCaseInsensitive (line 51) | function queryCaseInsensitive(query) {
function getSearchCursor (line 55) | function getSearchCursor(cm, query, pos) {
function persistentDialog (line 60) | function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
function dialog (line 70) | function dialog(cm, text, shortText, deflt, f) {
function confirmDialog (line 75) | function confirmDialog(cm, text, shortText, fs) {
function parseString (line 80) | function parseString(string) {
function parseQuery (line 90) | function parseQuery(query) {
function startSearch (line 103) | function startSearch(cm, state, query) {
function doSearch (line 115) | function doSearch(cm, rev, persistent, immediate) {
function findNext (line 166) | function findNext(cm, rev, callback) {cm.operation(function() {
function clearSearch (line 179) | function clearSearch(cm) {cm.operation(function() {
function getQueryDialog (line 189) | function getQueryDialog(cm) {
function getReplaceQueryDialog (line 192) | function getReplaceQueryDialog(cm) {
function getReplacementQueryDialog (line 195) | function getReplacementQueryDialog(cm) {
function getDoReplaceConfirm (line 198) | function getDoReplaceConfirm(cm) {
function replaceAll (line 202) | function replaceAll(cm, query, text) {
function replace (line 213) | function replace(cm, all) {
FILE: plugins/UiFileManager/media/codemirror/extension/search/searchcursor.js
function regexpFlags (line 15) | function regexpFlags(regexp) {
function ensureFlags (line 22) | function ensureFlags(regexp, flags) {
function maybeMultiline (line 29) | function maybeMultiline(regexp) {
function searchRegexpForward (line 33) | function searchRegexpForward(doc, regexp, start) {
function searchRegexpForwardMultiline (line 45) | function searchRegexpForwardMultiline(doc, regexp, start) {
function lastMatchIn (line 75) | function lastMatchIn(string, regexp, endMargin) {
function searchRegexpBackward (line 90) | function searchRegexpBackward(doc, regexp, start) {
function searchRegexpBackwardMultiline (line 102) | function searchRegexpBackwardMultiline(doc, regexp, start) {
function adjustPos (line 136) | function adjustPos(orig, folded, pos, foldFunc) {
function searchStringForward (line 148) | function searchStringForward(doc, query, start, caseFold) {
function searchStringBackward (line 176) | function searchStringBackward(doc, query, start, caseFold) {
function SearchCursor (line 203) | function SearchCursor(doc, query, pos, options) {
FILE: plugins/UiFileManager/media/codemirror/extension/selection/active-line.js
function clearActiveLines (line 32) | function clearActiveLines(cm) {
function sameArray (line 40) | function sameArray(a, b) {
function updateActiveLines (line 47) | function updateActiveLines(cm, ranges) {
function selectionChange (line 69) | function selectionChange(cm, sel) {
FILE: plugins/UiFileManager/media/codemirror/extension/selection/mark-selection.js
function onCursorActivity (line 36) | function onCursorActivity(cm) {
function onChange (line 41) | function onChange(cm) {
function coverRange (line 50) | function coverRange(cm, from, to, addAt) {
function clear (line 66) | function clear(cm) {
function reset (line 72) | function reset(cm) {
function update (line 79) | function update(cm) {
FILE: plugins/UiFileManager/media/codemirror/extension/selection/selection-pointer.js
function mousemove (line 43) | function mousemove(cm, event) {
function mouseout (line 54) | function mouseout(cm, event) {
function reset (line 62) | function reset(cm) {
function scheduleUpdate (line 67) | function scheduleUpdate(cm) {
function update (line 77) | function update(cm) {
FILE: plugins/UiFileManager/media/codemirror/extension/simple.js
function ensureState (line 61) | function ensureState(states, name) {
function toRegex (line 66) | function toRegex(val, caret) {
function asToken (line 78) | function asToken(val) {
function Rule (line 88) | function Rule(data, states) {
function tokenFunction (line 95) | function tokenFunction(states, config) {
function cmp (line 158) | function cmp(a, b) {
function enterLocalMode (line 170) | function enterLocalMode(config, state, spec, token) {
function indexOf (line 186) | function indexOf(val, arr) {
function indentFunction (line 190) | function indentFunction(states, meta) {
FILE: plugins/UiFileManager/media/codemirror/extension/sublime.js
function findPosSubword (line 21) | function findPosSubword(doc, start, dir) {
function moveSubword (line 47) | function moveSubword(cm, dir) {
function insertLine (line 105) | function insertLine(cm, above) {
function wordAt (line 127) | function wordAt(cm, pos) {
function addCursorToSelection (line 169) | function addCursorToSelection(cm, dir) {
function isSelectedRange (line 190) | function isSelectedRange(ranges, from, to) {
function selectBetweenBrackets (line 198) | function selectBetweenBrackets(cm) {
function puncType (line 231) | function puncType(type) {
function sortLines (line 342) | function sortLines(cm, caseSensitive) {
function modifyWordOrSelection (line 444) | function modifyWordOrSelection(cm, mod) {
function getTarget (line 542) | function getTarget(cm) {
function findAndGoTo (line 553) | function findAndGoTo(cm, forward) {
FILE: plugins/UiFileManager/media/codemirror/mode/coffeescript.js
function wordRegexp (line 21) | function wordRegexp(words) {
function tokenBase (line 50) | function tokenBase(stream, state) {
function tokenFactory (line 179) | function tokenFactory(delimiter, singleline, outclass) {
function longComment (line 206) | function longComment(stream, state) {
function indent (line 218) | function indent(stream, state, type) {
function dedent (line 242) | function dedent(stream, state) {
function tokenLexer (line 266) | function tokenLexer(stream, state) {
FILE: plugins/UiFileManager/media/codemirror/mode/css.js
function ret (line 35) | function ret(style, tp) { type = tp; return style; }
function tokenBase (line 39) | function tokenBase(stream, state) {
function tokenString (line 93) | function tokenString(quote) {
function tokenParenthesized (line 108) | function tokenParenthesized(stream, state) {
function Context (line 119) | function Context(type, indent, prev) {
function pushContext (line 125) | function pushContext(state, stream, type, indent) {
function popContext (line 130) | function popContext(state) {
function pass (line 136) | function pass(type, stream, state) {
function popAndPass (line 139) | function popAndPass(type, stream, state, n) {
function wordAsValue (line 147) | function wordAsValue(stream) {
function keySet (line 418) | function keySet(array) {
function tokenCComment (line 723) | function tokenCComment(stream, state) {
FILE: plugins/UiFileManager/media/codemirror/mode/go.js
function tokenBase (line 41) | function tokenBase(stream, state) {
function tokenString (line 85) | function tokenString(quote) {
function tokenComment (line 98) | function tokenComment(stream, state) {
function Context (line 110) | function Context(indented, column, type, align, prev) {
function pushContext (line 117) | function pushContext(state, col, type) {
function popContext (line 120) | function popContext(state) {
FILE: plugins/UiFileManager/media/codemirror/mode/htmlmixed.js
function maybeBackup (line 29) | function maybeBackup(stream, pat, style) {
function getAttrRegexp (line 41) | function getAttrRegexp(attr) {
function getAttrValue (line 47) | function getAttrValue(text, attr) {
function getTagRegexp (line 52) | function getTagRegexp(tagName, anchored) {
function addTags (line 56) | function addTags(from, to) {
function findMatchingMode (line 65) | function findMatchingMode(tagInfo, tagText) {
function html (line 87) | function html(stream, state) {
FILE: plugins/UiFileManager/media/codemirror/mode/javascript.js
function kw (line 25) | function kw(type) {return {type: type, style: "keyword"};}
function readRegexp (line 46) | function readRegexp(stream) {
function ret (line 61) | function ret(tp, style, cont) {
function tokenBase (line 65) | function tokenBase(stream, state) {
function tokenString (line 136) | function tokenString(quote) {
function tokenComment (line 152) | function tokenComment(stream, state) {
function tokenQuasi (line 164) | function tokenQuasi(stream, state) {
function findFatArrow (line 184) | function findFatArrow(stream, state) {
function JSLexical (line 223) | function JSLexical(indented, column, type, align, prev, info) {
function inScope (line 232) | function inScope(state, varname) {
function parseJS (line 241) | function parseJS(state, style, type, content, stream) {
function pass (line 265) | function pass() {
function cont (line 268) | function cont() {
function inList (line 272) | function inList(name, list) {
function register (line 276) | function register(varname) {
function registerVarScoped (line 296) | function registerVarScoped(varname, context) {
function isModifier (line 311) | function isModifier(name) {
function Context (line 317) | function Context(prev, vars, block) { this.prev = prev; this.vars = vars...
function Var (line 318) | function Var(name, next) { this.name = name; this.next = next }
function pushcontext (line 321) | function pushcontext() {
function pushblockcontext (line 325) | function pushblockcontext() {
function popcontext (line 329) | function popcontext() {
function pushlex (line 334) | function pushlex(type, info) {
function poplex (line 345) | function poplex() {
function expect (line 355) | function expect(wanted) {
function statement (line 364) | function statement(type, value) {
function maybeCatchBinding (line 413) | function maybeCatchBinding(type) {
function expression (line 416) | function expression(type, value) {
function expressionNoComma (line 419) | function expressionNoComma(type, value) {
function parenExpr (line 422) | function parenExpr(type) {
function expressionInner (line 426) | function expressionInner(type, value, noComma) {
function maybeexpression (line 447) | function maybeexpression(type) {
function maybeoperatorComma (line 452) | function maybeoperatorComma(type, value) {
function maybeoperatorNoComma (line 456) | function maybeoperatorNoComma(type, value, noComma) {
function quasi (line 479) | function quasi(type, value) {
function continueQuasi (line 484) | function continueQuasi(type) {
function arrowBody (line 491) | function arrowBody(type) {
function arrowBodyNoComma (line 495) | function arrowBodyNoComma(type) {
function maybeTarget (line 499) | function maybeTarget(noComma) {
function target (line 506) | function target(_, value) {
function targetNoComma (line 509) | function targetNoComma(_, value) {
function maybelabel (line 512) | function maybelabel(type) {
function property (line 516) | function property(type) {
function objprop (line 519) | function objprop(type, value) {
function getterSetter (line 549) | function getterSetter(type) {
function afterprop (line 554) | function afterprop(type) {
function commasep (line 558) | function commasep(what, end, sep) {
function contCommasep (line 577) | function contCommasep(what, end, info) {
function block (line 582) | function block(type) {
function maybetype (line 586) | function maybetype(type, value) {
function maybetypeOrIn (line 592) | function maybetypeOrIn(type, value) {
function mayberettype (line 595) | function mayberettype(type) {
function isKW (line 601) | function isKW(_, value) {
function typeexpr (line 607) | function typeexpr(type, value) {
function maybeReturnType (line 623) | function maybeReturnType(type) {
function typeprop (line 626) | function typeprop(type, value) {
function typearg (line 640) | function typearg(type, value) {
function afterType (line 646) | function afterType(type, value) {
function maybeTypeArgs (line 653) | function maybeTypeArgs(_, value) {
function typeparam (line 656) | function typeparam() {
function maybeTypeDefault (line 659) | function maybeTypeDefault(_, value) {
function vardef (line 662) | function vardef(_, value) {
function pattern (line 666) | function pattern(type, value) {
function proppattern (line 673) | function proppattern(type, value) {
function eltpattern (line 684) | function eltpattern() {
function maybeAssign (line 687) | function maybeAssign(_type, value) {
function vardefCont (line 690) | function vardefCont(type) {
function maybeelse (line 693) | function maybeelse(type, value) {
function forspec (line 696) | function forspec(type, value) {
function forspec1 (line 700) | function forspec1(type) {
function forspec2 (line 705) | function forspec2(type, value) {
function functiondef (line 711) | function functiondef(type, value) {
function functiondecl (line 717) | function functiondecl(type, value) {
function typename (line 723) | function typename(type, value) {
function funarg (line 731) | function funarg(type, value) {
function classExpression (line 738) | function classExpression(type, value) {
function className (line 743) | function className(type, value) {
function classNameAfter (line 746) | function classNameAfter(type, value) {
function classBody (line 754) | function classBody(type, value) {
function classfield (line 778) | function classfield(type, value) {
function afterExport (line 785) | function afterExport(type, value) {
function exportField (line 791) | function exportField(type, value) {
function afterImport (line 795) | function afterImport(type) {
function importSpec (line 800) | function importSpec(type, value) {
function maybeMoreImports (line 806) | function maybeMoreImports(type) {
function maybeAs (line 809) | function maybeAs(_type, value) {
function maybeFrom (line 812) | function maybeFrom(_type, value) {
function arrayLiteral (line 815) | function arrayLiteral(type) {
function enumdef (line 819) | function enumdef() {
function enummember (line 822) | function enummember() {
function isContinuedStatement (line 826) | function isContinuedStatement(state, textAfter) {
function expressionAllowed (line 832) | function expressionAllowed(stream, state, backUp) {
FILE: plugins/UiFileManager/media/codemirror/mode/markdown.js
function getMode (line 19) | function getMode(name) {
function switchInline (line 100) | function switchInline(stream, state, f) {
function switchBlock (line 105) | function switchBlock(stream, state, f) {
function lineIsEmpty (line 110) | function lineIsEmpty(line) {
function blankLine (line 116) | function blankLine(state) {
function blockNormal (line 153) | function blockNormal(stream, state) {
function htmlBlock (line 284) | function htmlBlock(stream, state) {
function local (line 299) | function local(stream, state) {
function getType (line 324) | function getType(state) {
function handleText (line 407) | function handleText(stream, state) {
function inlineNormal (line 414) | function inlineNormal(stream, state) {
function linkInline (line 644) | function linkInline(stream, state) {
function linkHref (line 664) | function linkHref(stream, state) {
function getLinkHrefInside (line 684) | function getLinkHrefInside(endChar) {
function footnoteLink (line 702) | function footnoteLink(stream, state) {
function footnoteLinkInside (line 713) | function footnoteLinkInside(stream, state) {
function footnoteUrl (line 727) | function footnoteUrl(stream, state) {
FILE: plugins/UiFileManager/media/codemirror/mode/python.js
function wordRegexp (line 14) | function wordRegexp(words) {
function top (line 37) | function top(state) {
function tokenBase (line 78) | function tokenBase(stream, state) {
function tokenBaseInner (line 101) | function tokenBaseInner(stream, state, inFormat) {
function formatStringFactory (line 183) | function formatStringFactory(delimiter, tokenOuter) {
function tokenStringFactory (line 244) | function tokenStringFactory(delimiter, tokenOuter) {
function pushPyScope (line 277) | function pushPyScope(state) {
function pushBracketScope (line 284) | function pushBracketScope(stream, state, type) {
function dedent (line 291) | function dedent(stream, state) {
function tokenLexer (line 300) | function tokenLexer(stream, state) {
FILE: plugins/UiFileManager/media/codemirror/mode/xml.js
function inText (line 69) | function inText(stream, state) {
function inTag (line 117) | function inTag(stream, state) {
function inAttribute (line 142) | function inAttribute(quote) {
function inBlock (line 156) | function inBlock(style, terminator) {
function doctype (line 169) | function doctype(depth) {
function Context (line 190) | function Context(state, tagName, startOfLine) {
function popContext (line 198) | function popContext(state) {
function maybePopContext (line 201) | function maybePopContext(state, nextTagName) {
function baseState (line 216) | function baseState(type, stream, state) {
function tagNameState (line 226) | function tagNameState(type, stream, state) {
function closeTagNameState (line 239) | function closeTagNameState(type, stream, state) {
function closeState (line 261) | function closeState(type, _stream, state) {
function closeStateErr (line 269) | function closeStateErr(type, stream, state) {
function attrState (line 274) | function attrState(type, _stream, state) {
function attrEqState (line 293) | function attrEqState(type, stream, state) {
function attrValueState (line 298) | function attrValueState(type, stream, state) {
function attrContinuedState (line 304) | function attrContinuedState(type, stream, state) {
FILE: plugins/UiFileManager/media/js/all.js
function Animation (line 9) | function Animation() {}
function Class (line 176) | function Class() {}
function ItemList (line 243) | function ItemList(item_class1, key1) {
function Menu (line 297) | function Menu() {
function Promise (line 504) | function Promise() {
function Text (line 697) | function Text() {}
function Time (line 922) | function Time() {}
function ctor (line 1021) | function ctor() { this.constructor = child; }
function ZeroFrame (line 1027) | function ZeroFrame(url) {
function ctor (line 1936) | function ctor() { this.constructor = child; }
function FileEditor (line 1942) | function FileEditor(inner_path1) {
function ctor (line 2205) | function ctor() { this.constructor = child; }
function FileItemList (line 2211) | function FileItemList(inner_path1) {
function ctor (line 2490) | function ctor() { this.constructor = child; }
function FileList (line 2497) | function FileList(site, inner_path1, is_owner) {
function ctor (line 2921) | function ctor() { this.constructor = child; }
function UiFileManager (line 2929) | function UiFileManager() {
FILE: plugins/UiPluginManager/UiPluginManagerPlugin.py
function restrictDictValues (line 21) | def restrictDictValues(input_dict):
class UiRequestPlugin (line 30) | class UiRequestPlugin(object):
method actionWrapper (line 31) | def actionWrapper(self, path, extra_headers=None):
method actionUiMedia (line 47) | def actionUiMedia(self, path, *args, **kwargs):
class UiWebsocketPlugin (line 68) | class UiWebsocketPlugin(object):
method actionPluginList (line 70) | def actionPluginList(self, to):
method actionPluginConfigSet (line 106) | def actionPluginConfigSet(self, to, source, inner_path, key, value):
method pluginAction (line 130) | def pluginAction(self, action, address, inner_path):
method doPluginAdd (line 180) | def doPluginAdd(self, to, inner_path, res):
method actionPluginAddRequest (line 196) | def actionPluginAddRequest(self, to, inner_path):
method actionPluginRemove (line 210) | def actionPluginRemove(self, to, address, inner_path):
method actionPluginUpdate (line 217) | def actionPluginUpdate(self, to, address, inner_path):
FILE: plugins/UiPluginManager/media/js/all.js
function Class (line 10) | function Class() {}
function Promise (line 89) | function Promise() {
function Animation (line 972) | function Animation() {}
function ctor (line 1151) | function ctor() { this.constructor = child; }
function ZeroFrame (line 1157) | function ZeroFrame(url) {
function ctor (line 1283) | function ctor() { this.constructor = child; }
function PluginList (line 1289) | function PluginList(plugins) {
function ctor (line 1466) | function ctor() { this.constructor = child; }
function UiPluginManager (line 1474) | function UiPluginManager() {
FILE: plugins/Zeroname/SiteManagerPlugin.py
class SiteManagerPlugin (line 14) | class SiteManagerPlugin(object):
method load (line 19) | def load(self, *args, **kwargs):
method isBitDomain (line 25) | def isBitDomain(self, address):
method resolveBitDomain (line 30) | def resolveBitDomain(self, domain):
method resolveDomain (line 52) | def resolveDomain(self, domain):
method isDomain (line 56) | def isDomain(self, address):
class ConfigPlugin (line 61) | class ConfigPlugin(object):
method createArguments (line 62) | def createArguments(self):
FILE: plugins/Zeroname/updater/zeroname_updater.py
function publish (line 15) | def publish():
function processNameOp (line 20) | def processNameOp(domain, value, test=False):
function processBlock (line 94) | def processBlock(block_id, test=False):
function initRpc (line 115) | def initRpc(config):
FILE: plugins/disabled-Bootstrapper/BootstrapperDb.py
class BootstrapperDb (line 11) | class BootstrapperDb(Db.Db):
method __init__ (line 12) | def __init__(self):
method cleanup (line 21) | def cleanup(self):
method updateHashCache (line 27) | def updateHashCache(self):
method checkTables (line 32) | def checkTables(self):
method createTables (line 40) | def createTables(self):
method getHashId (line 79) | def getHashId(self, hash):
method peerAnnounce (line 86) | def peerAnnounce(self, ip_type, address, port=None, hashes=[], onion_s...
method peerList (line 122) | def peerList(self, hash, address=None, onions=[], port=None, limit=30,...
FILE: plugins/disabled-Bootstrapper/BootstrapperPlugin.py
class FileRequestPlugin (line 15) | class FileRequestPlugin(object):
method checkOnionSigns (line 16) | def checkOnionSigns(self, onions, onion_signs, onion_sign_this):
method actionAnnounce (line 37) | def actionAnnounce(self, params):
class UiRequestPlugin (line 132) | class UiRequestPlugin(object):
method actionStatsBootstrapper (line 134) | def actionStatsBootstrapper(self):
FILE: plugins/disabled-Bootstrapper/Test/TestBootstrapper.py
function bootstrapper_db (line 14) | def bootstrapper_db(request):
class TestBootstrapper (line 29) | class TestBootstrapper:
method testHashCache (line 30) | def testHashCache(self, file_server, bootstrapper_db):
method testBootstrapperDb (line 52) | def testBootstrapperDb(self, file_server, bootstrapper_db):
method testPassive (line 112) | def testPassive(self, file_server, bootstrapper_db):
method testAddOnion (line 124) | def testAddOnion(self, file_server, site, bootstrapper_db, tor_manager):
method testRequestPeers (line 193) | def testRequestPeers(self, file_server, site, bootstrapper_db, tor_man...
method testAnnounce (line 211) | def testAnnounce(self, file_server, tor_manager):
method testBackwardCompatibility (line 226) | def testBackwardCompatibility(self, file_server, bootstrapper_db):
FILE: plugins/disabled-Dnschain/SiteManagerPlugin.py
class SiteManagerPlugin (line 13) | class SiteManagerPlugin(object):
method isAddress (line 18) | def isAddress(self, address):
method isDomain (line 26) | def isDomain(self, address):
method loadDnsCache (line 31) | def loadDnsCache(self):
method saveDnsCache (line 40) | def saveDnsCache(self):
method resolveDomainDnschainNet (line 46) | def resolveDomainDnschainNet(self, domain):
method resolveDomainDnschainInfo (line 69) | def resolveDomainDnschainInfo(self, domain):
method resolveDomain (line 91) | def resolveDomain(self, domain):
method need (line 124) | def need(self, address, all_file=True):
method get (line 136) | def get(self, address):
FILE: plugins/disabled-Dnschain/UiRequestPlugin.py
class UiRequestPlugin (line 5) | class UiRequestPlugin(object):
method __init__ (line 6) | def __init__(self, server = None):
method actionSiteMedia (line 13) | def actionSiteMedia(self, path):
method isMediaRequestAllowed (line 24) | def isMediaRequestAllowed(self, site_address, referer):
FILE: plugins/disabled-DonationMessage/DonationMessagePlugin.py
class UiRequestPlugin (line 8) | class UiRequestPlugin(object):
method renderWrapper (line 10) | def renderWrapper(self, *args, **kwargs):
FILE: plugins/disabled-Multiuser/MultiuserPlugin.py
function importPluginnedClasses (line 14) | def importPluginnedClasses():
class UiRequestPlugin (line 25) | class UiRequestPlugin(object):
method __init__ (line 26) | def __init__(self, *args, **kwargs):
method actionWrapper (line 32) | def actionWrapper(self, path, extra_headers=None):
method getCurrentUser (line 94) | def getCurrentUser(self):
class UiWebsocketPlugin (line 104) | class UiWebsocketPlugin(object):
method __init__ (line 105) | def __init__(self, *args, **kwargs):
method formatServerInfo (line 112) | def formatServerInfo(self):
method actionUserShowMasterSeed (line 123) | def actionUserShowMasterSeed(self, to):
method actionUserLogout (line 131) | def actionUserLogout(self, to):
method actionUserSet (line 148) | def actionUserSet(self, to, master_address):
method actionUserSelectForm (line 162) | def actionUserSelectForm(self, to):
method actionUserLoginForm (line 194) | def actionUserLoginForm(self, to):
method responseUserLogin (line 198) | def responseUserLogin(self, master_seed):
method hasCmdPermission (line 212) | def hasCmdPermission(self, cmd):
method actionCertAdd (line 221) | def actionCertAdd(self, *args, **kwargs):
method actionPermissionAdd (line 258) | def actionPermissionAdd(self, to, permission):
class ConfigPlugin (line 269) | class ConfigPlugin(object):
method createArguments (line 270) | def createArguments(self):
FILE: plugins/disabled-Multiuser/Test/TestMultiuser.py
class TestMultiuser (line 8) | class TestMultiuser:
method testMemorySave (line 9) | def testMemorySave(self, user):
FILE: plugins/disabled-Multiuser/UserPlugin.py
class UserManagerPlugin (line 7) | class UserManagerPlugin(object):
method load (line 8) | def load(self):
method get (line 19) | def get(self, master_address=None):
class UserPlugin (line 29) | class UserPlugin(object):
method save (line 31) | def save(self):
FILE: plugins/disabled-StemPort/StemPortPlugin.py
class PatchedControlPort (line 24) | class PatchedControlPort(ControlPort):
method _make_socket (line 25) | def _make_socket(self):
function from_port (line 39) | def from_port(address = '127.0.0.1', port = 'default'):
class TorManagerPlugin (line 56) | class TorManagerPlugin(object):
method connectController (line 58) | def connectController(self):
method disconnect (line 82) | def disconnect(self):
method resetCircuits (line 87) | def resetCircuits(self):
method makeOnionAndKey (line 95) | def makeOnionAndKey(self):
method delOnion (line 114) | def delOnion(self, address):
method request (line 125) | def request(self, cmd):
method send (line 133) | def send(self, cmd, conn=None):
FILE: plugins/disabled-UiPassword/UiPasswordPlugin.py
function showPasswordAdvice (line 20) | def showPasswordAdvice(password):
class UiRequestPlugin (line 30) | class UiRequestPlugin(object):
method getClientId (line 35) | def getClientId(self):
method whitelistClientId (line 38) | def whitelistClientId(self, session_id=None):
method route (line 52) | def route(self, path):
method actionWrapper (line 69) | def actionWrapper(self, path, *args, **kwargs):
method actionLogin (line 82) | def actionLogin(self):
method randomString (line 109) | def randomString(self, nchars):
method sessionCheckPassword (line 112) | def sessionCheckPassword(self, password):
method sessionDelete (line 115) | def sessionDelete(self, session_id):
method sessionCleanup (line 122) | def sessionCleanup(self):
method actionSessions (line 132) | def actionSessions(self):
method actionLogout (line 141) | def actionLogout(self):
class ConfigPlugin (line 159) | class ConfigPlugin(object):
method createArguments (line 160) | def createArguments(self):
class UiWebsocketPlugin (line 169) | class UiWebsocketPlugin(object):
method actionUiLogout (line 170) | def actionUiLogout(self, to):
method addHomepageNotifications (line 178) | def addHomepageNotifications(self):
FILE: plugins/disabled-ZeronameLocal/SiteManagerPlugin.py
class SiteManagerPlugin (line 11) | class SiteManagerPlugin(object):
method load (line 12) | def load(self, *args, **kwargs):
method isAddress (line 49) | def isAddress(self, address):
method isDomain (line 53) | def isDomain(self, address):
method isBitDomain (line 57) | def isBitDomain(self, address):
method get (line 61) | def get(self, address):
method need (line 79) | def need(self, address, *args, **kwargs):
method resolveDomain (line 91) | def resolveDomain(self, domain):
class ConfigPlugin (line 172) | class ConfigPlugin(object):
method createArguments (line 173) | def createArguments(self):
FILE: plugins/disabled-ZeronameLocal/UiRequestPlugin.py
class UiRequestPlugin (line 5) | class UiRequestPlugin(object):
method __init__ (line 6) | def __init__(self, *args, **kwargs):
method actionSiteMedia (line 13) | def actionSiteMedia(self, path):
method isMediaRequestAllowed (line 24) | def isMediaRequestAllowed(self, site_address, referer):
FILE: src/Config.py
class Config (line 13) | class Config(object):
method __init__ (line 15) | def __init__(self, argv):
method createParser (line 43) | def createParser(self):
method __str__ (line 49) | def __str__(self):
method strToBool (line 53) | def strToBool(self, v):
method getStartDir (line 56) | def getStartDir(self):
method createArguments (line 81) | def createArguments(self):
method loadTrackersFile (line 320) | def loadTrackersFile(self):
method getActionArguments (line 343) | def getActionArguments(self):
method getAction (line 351) | def getAction(self, argv):
method moveUnknownToEnd (line 361) | def moveUnknownToEnd(self, argv, default_action):
method getParser (line 381) | def getParser(self, argv):
method parse (line 389) | def parse(self, silent=False, parse_config=True):
method parseCommandline (line 424) | def parseCommandline(self, argv, silent=False):
method parseConfig (line 442) | def parseConfig(self, argv):
method getCmdlineValue (line 473) | def getCmdlineValue(self, key):
method setAttributes (line 483) | def setAttributes(self):
method loadPlugins (line 495) | def loadPlugins(self):
method saveValue (line 513) | def saveValue(self, key, value):
method getServerInfo (line 557) | def getServerInfo(self):
method initConsoleLogger (line 587) | def initConsoleLogger(self):
method initFileLogger (line 608) | def initFileLogger(self):
method initLogging (line 630) | def initLogging(self, console_logging=None, file_logging=None):
class ErrorLogHandler (line 661) | class ErrorLogHandler(logging.StreamHandler):
method __init__ (line 662) | def __init__(self):
method emit (line 666) | def emit(self, record):
method onNewRecord (line 669) | def onNewRecord(self, record):
FILE: src/Connection/Connection.py
class Connection (line 17) | class Connection(object):
method __init__ (line 25) | def __init__(self, server, ip, port, sock=None, target_onion=None, is_...
method setIp (line 82) | def setIp(self, ip):
method createSocket (line 87) | def createSocket(self):
method updateName (line 94) | def updateName(self):
method __str__ (line 97) | def __str__(self):
method __repr__ (line 100) | def __repr__(self):
method log (line 103) | def log(self, text):
method getValidSites (line 106) | def getValidSites(self):
method badAction (line 109) | def badAction(self, weight=1):
method goodAction (line 116) | def goodAction(self):
method connect (line 120) | def connect(self):
method handleIncomingConnection (line 183) | def handleIncomingConnection(self, sock):
method getMsgpackUnpacker (line 202) | def getMsgpackUnpacker(self):
method messageLoop (line 209) | def messageLoop(self):
method getUnpackerUnprocessedBytesNum (line 284) | def getUnpackerUnprocessedBytesNum(self):
method handleStream (line 292) | def handleStream(self, message, buff):
method getHandshakeInfo (line 345) | def getHandshakeInfo(self):
method setHandshake (line 390) | def setHandshake(self, handshake):
method handleMessage (line 442) | def handleMessage(self, message):
method handleHandshake (line 483) | def handleHandshake(self, message):
method send (line 506) | def send(self, message, streaming=False):
method sendRawfile (line 553) | def sendRawfile(self, file, read_bytes):
method request (line 573) | def request(self, cmd, params={}, stream_to=None):
method ping (line 591) | def ping(self):
method close (line 606) | def close(self, reason="Unknown"):
FILE: src/Connection/ConnectionServer.py
class ConnectionServer (line 23) | class ConnectionServer(object):
method __init__ (line 24) | def __init__(self, ip=None, port=None, request_handler=None):
method start (line 80) | def start(self, check_connections=True):
method listen (line 104) | def listen(self):
method stop (line 117) | def stop(self):
method closeConnections (line 126) | def closeConnections(self):
method handleIncomingConnection (line 131) | def handleIncomingConnection(self, sock, addr):
method handleMessage (line 162) | def handleMessage(self, *args, **kwargs):
method getConnection (line 165) | def getConnection(self, ip=None, port=None, peer_id=None, create=True,...
method removeConnection (line 234) | def removeConnection(self, connection):
method checkConnections (line 249) | def checkConnections(self):
method checkMaxConnections (line 335) | def checkMaxConnections(self):
method onInternetOnline (line 356) | def onInternetOnline(self):
method onInternetOffline (line 359) | def onInternetOffline(self):
method getTimecorrection (line 363
Condensed preview — 537 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,820K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 53,
"preview": "custom: https://zeronet.io/docs/help_zeronet/donate/\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug-report.md",
"chars": 664,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve ZeroNet\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n### Step"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 590,
"preview": "---\nname: Feature request\nabout: Suggest an idea for ZeroNet\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature "
},
{
"path": ".github/workflows/tests.yml",
"chars": 2162,
"preview": "name: tests\n\non: [push, pull_request]\n\njobs:\n test:\n\n runs-on: ubuntu-16.04\n strategy:\n max-parallel: 16\n "
},
{
"path": ".gitignore",
"chars": 382,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n\n# Log files\n**/*.log\n\n# Hidden files\n.*\n!/.github\n!/.git"
},
{
"path": ".gitlab-ci.yml",
"chars": 1485,
"preview": "stages:\n - test\n\n.test_template: &test_template\n stage: test\n before_script:\n - pip install --upgrade pip wheel\n "
},
{
"path": ".travis.yml",
"chars": 2152,
"preview": "language: python\npython:\n - 3.4\n - 3.5\n - 3.6\n - 3.7\n - 3.8\nservices:\n - docker\ncache: pip\nbefore_install:\n - pip "
},
{
"path": "CHANGELOG.md",
"chars": 25053,
"preview": "### ZeroNet 0.7.2 (2020-09-?) Rev4206?\n\n\n\n### ZeroNet 0.7.1 (2019-07-01) Rev4206\n### Added\n - Built-in logging console i"
},
{
"path": "COPYING",
"chars": 35149,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
},
{
"path": "Dockerfile",
"chars": 777,
"preview": "FROM alpine:3.11 \n\n#Base settings\nENV HOME /root\n\nCOPY requirements.txt /root/requirements.txt\n\n#Install ZeroNet\nRUN apk"
},
{
"path": "Dockerfile.arm64v8",
"chars": 777,
"preview": "FROM alpine:3.12\n\n#Base settings\nENV HOME /root\n\nCOPY requirements.txt /root/requirements.txt\n\n#Install ZeroNet\nRUN apk "
},
{
"path": "LICENSE",
"chars": 1617,
"preview": "This program is free software: you can redistribute it and/or modify\r\nit under the terms of the GNU General Public Licen"
},
{
"path": "README-ru.md",
"chars": 8658,
"preview": "# ZeroNet [](https://travis-ci.org/HelloZer"
},
{
"path": "README-zh-cn.md",
"chars": 4013,
"preview": "# ZeroNet [](https://travis-ci.org/HelloZeroNe"
},
{
"path": "README.md",
"chars": 6555,
"preview": "# ZeroNet [](https://travis-ci.org/HelloZeroNe"
},
{
"path": "Vagrantfile",
"chars": 1189,
"preview": "# -*- mode: ruby -*-\n# vi: set ft=ruby :\n\nVAGRANTFILE_API_VERSION = \"2\"\n\nVagrant.configure(VAGRANTFILE_API_VERSION) do |"
},
{
"path": "plugins/AnnounceBitTorrent/AnnounceBitTorrentPlugin.py",
"chars": 5648,
"preview": "import time\nimport urllib.request\nimport struct\nimport socket\n\nimport lib.bencode_open as bencode_open\nfrom lib.subtl.su"
},
{
"path": "plugins/AnnounceBitTorrent/__init__.py",
"chars": 38,
"preview": "from . import AnnounceBitTorrentPlugin"
},
{
"path": "plugins/AnnounceBitTorrent/plugin_info.json",
"chars": 121,
"preview": "{\n\t\"name\": \"AnnounceBitTorrent\",\n\t\"description\": \"Discover new peers using BitTorrent trackers.\",\n\t\"default\": \"enabled\"\n"
},
{
"path": "plugins/AnnounceLocal/AnnounceLocalPlugin.py",
"chars": 5961,
"preview": "import time\n\nimport gevent\n\nfrom Plugin import PluginManager\nfrom Config import config\nfrom . import BroadcastServer\n\n\n@"
},
{
"path": "plugins/AnnounceLocal/BroadcastServer.py",
"chars": 4892,
"preview": "import socket\nimport logging\nimport time\nfrom contextlib import closing\n\nfrom Debug import Debug\nfrom util import UpnpPu"
},
{
"path": "plugins/AnnounceLocal/Test/TestAnnounce.py",
"chars": 4957,
"preview": "import time\nimport copy\n\nimport gevent\nimport pytest\nimport mock\n\nfrom AnnounceLocal import AnnounceLocalPlugin\nfrom Fil"
},
{
"path": "plugins/AnnounceLocal/Test/conftest.py",
"chars": 85,
"preview": "from src.Test.conftest import *\n\nfrom Config import config\nconfig.broadcast_port = 0\n"
},
{
"path": "plugins/AnnounceLocal/Test/pytest.ini",
"chars": 114,
"preview": "[pytest]\npython_files = Test*.py\naddopts = -rsxX -v --durations=6\nmarkers =\n webtest: mark a test as a webtest."
},
{
"path": "plugins/AnnounceLocal/__init__.py",
"chars": 33,
"preview": "from . import AnnounceLocalPlugin"
},
{
"path": "plugins/AnnounceLocal/plugin_info.json",
"chars": 115,
"preview": "{\n\t\"name\": \"AnnounceLocal\",\n\t\"description\": \"Discover LAN clients using UDP broadcasting.\",\n\t\"default\": \"enabled\"\n}"
},
{
"path": "plugins/AnnounceShare/AnnounceSharePlugin.py",
"chars": 6831,
"preview": "import time\nimport os\nimport logging\nimport json\nimport atexit\n\nimport gevent\n\nfrom Config import config\nfrom Plugin imp"
},
{
"path": "plugins/AnnounceShare/Test/TestAnnounceShare.py",
"chars": 969,
"preview": "import pytest\n\nfrom AnnounceShare import AnnounceSharePlugin\nfrom Peer import Peer\nfrom Config import config\n\n\n@pytest.m"
},
{
"path": "plugins/AnnounceShare/Test/conftest.py",
"chars": 59,
"preview": "from src.Test.conftest import *\n\nfrom Config import config\n"
},
{
"path": "plugins/AnnounceShare/Test/pytest.ini",
"chars": 114,
"preview": "[pytest]\npython_files = Test*.py\naddopts = -rsxX -v --durations=6\nmarkers =\n webtest: mark a test as a webtest."
},
{
"path": "plugins/AnnounceShare/__init__.py",
"chars": 34,
"preview": "from . import AnnounceSharePlugin\n"
},
{
"path": "plugins/AnnounceShare/plugin_info.json",
"chars": 111,
"preview": "{\n\t\"name\": \"AnnounceShare\",\n\t\"description\": \"Share possible trackers between clients.\",\n\t\"default\": \"enabled\"\n}"
},
{
"path": "plugins/AnnounceZero/AnnounceZeroPlugin.py",
"chars": 5736,
"preview": "import time\nimport itertools\n\nfrom Plugin import PluginManager\nfrom util import helper\nfrom Crypt import CryptRsa\n\nallow"
},
{
"path": "plugins/AnnounceZero/__init__.py",
"chars": 32,
"preview": "from . import AnnounceZeroPlugin"
},
{
"path": "plugins/AnnounceZero/plugin_info.json",
"chars": 102,
"preview": "{\n\t\"name\": \"AnnounceZero\",\n\t\"description\": \"Announce using ZeroNet protocol.\",\n\t\"default\": \"enabled\"\n}"
},
{
"path": "plugins/Benchmark/BenchmarkDb.py",
"chars": 5314,
"preview": "import os\nimport json\nimport contextlib\nimport time\n\nfrom Plugin import PluginManager\nfrom Config import config\n\n\n@Plugi"
},
{
"path": "plugins/Benchmark/BenchmarkPack.py",
"chars": 11998,
"preview": "import os\nimport io\nfrom collections import OrderedDict\n\nfrom Plugin import PluginManager\nfrom Config import config\nfrom"
},
{
"path": "plugins/Benchmark/BenchmarkPlugin.py",
"chars": 16761,
"preview": "import os\nimport time\nimport io\nimport math\nimport hashlib\nimport re\nimport sys\n\nfrom Config import config\nfrom Crypt im"
},
{
"path": "plugins/Benchmark/__init__.py",
"chars": 84,
"preview": "from . import BenchmarkPlugin\nfrom . import BenchmarkDb\nfrom . import BenchmarkPack\n"
},
{
"path": "plugins/Benchmark/media/benchmark.html",
"chars": 5640,
"preview": "<html>\n<script nonce=\"{script_nonce}\">\nwindow.benchmark_key = \"{benchmark_key}\";\n\nfunction setState(elem, text) {\n va"
},
{
"path": "plugins/Benchmark/plugin_info.json",
"chars": 142,
"preview": "{\n\t\"name\": \"Benchmark\",\n\t\"description\": \"Test and benchmark database and cryptographic functions related to ZeroNet.\",\n\t"
},
{
"path": "plugins/Bigfile/BigfilePiecefield.py",
"chars": 4674,
"preview": "import array\n\n\ndef packPiecefield(data):\n if not isinstance(data, bytes) and not isinstance(data, bytearray):\n "
},
{
"path": "plugins/Bigfile/BigfilePlugin.py",
"chars": 36039,
"preview": "import time\nimport os\nimport subprocess\nimport shutil\nimport collections\nimport math\nimport warnings\nimport base64\nimpor"
},
{
"path": "plugins/Bigfile/Test/TestBigfile.py",
"chars": 23500,
"preview": "import time\nimport io\nimport binascii\n\nimport pytest\nimport mock\n\nfrom Connection import ConnectionServer\nfrom Content.C"
},
{
"path": "plugins/Bigfile/Test/conftest.py",
"chars": 32,
"preview": "from src.Test.conftest import *\n"
},
{
"path": "plugins/Bigfile/Test/pytest.ini",
"chars": 114,
"preview": "[pytest]\npython_files = Test*.py\naddopts = -rsxX -v --durations=6\nmarkers =\n webtest: mark a test as a webtest."
},
{
"path": "plugins/Bigfile/__init__.py",
"chars": 101,
"preview": "from . import BigfilePlugin\nfrom .BigfilePiecefield import BigfilePiecefield, BigfilePiecefieldPacked"
},
{
"path": "plugins/Chart/ChartCollector.py",
"chars": 7496,
"preview": "import time\nimport sys\nimport collections\nimport itertools\nimport logging\n\nimport gevent\nfrom util import helper\nfrom Co"
},
{
"path": "plugins/Chart/ChartDb.py",
"chars": 4759,
"preview": "from Config import config\nfrom Db.Db import Db\nimport time\n\n\nclass ChartDb(Db):\n def __init__(self):\n self.ver"
},
{
"path": "plugins/Chart/ChartPlugin.py",
"chars": 1938,
"preview": "import time\nimport itertools\n\nimport gevent\n\nfrom Config import config\nfrom util import helper\nfrom util.Flag import fla"
},
{
"path": "plugins/Chart/__init__.py",
"chars": 25,
"preview": "from . import ChartPlugin"
},
{
"path": "plugins/Chart/plugin_info.json",
"chars": 111,
"preview": "{\n\t\"name\": \"Chart\",\n\t\"description\": \"Collect and provide stats of client information.\",\n\t\"default\": \"enabled\"\n}"
},
{
"path": "plugins/ContentFilter/ContentFilterPlugin.py",
"chars": 10565,
"preview": "import time\nimport re\nimport html\nimport os\n\nfrom Plugin import PluginManager\nfrom Translate import Translate\nfrom Confi"
},
{
"path": "plugins/ContentFilter/ContentFilterStorage.py",
"chars": 6435,
"preview": "import os\nimport json\nimport logging\nimport collections\nimport time\nimport hashlib\n\nfrom Debug import Debug\nfrom Plugin "
},
{
"path": "plugins/ContentFilter/Test/TestContentFilter.py",
"chars": 3528,
"preview": "import pytest\nfrom ContentFilter import ContentFilterPlugin\nfrom Site import SiteManager\n\n\n@pytest.fixture\ndef filter_st"
},
{
"path": "plugins/ContentFilter/Test/conftest.py",
"chars": 32,
"preview": "from src.Test.conftest import *\n"
},
{
"path": "plugins/ContentFilter/Test/pytest.ini",
"chars": 114,
"preview": "[pytest]\npython_files = Test*.py\naddopts = -rsxX -v --durations=6\nmarkers =\n webtest: mark a test as a webtest."
},
{
"path": "plugins/ContentFilter/__init__.py",
"chars": 34,
"preview": "from . import ContentFilterPlugin\n"
},
{
"path": "plugins/ContentFilter/languages/hu.json",
"chars": 203,
"preview": "{\r\n\t\"Hide all content from <b>%s</b>?\": \"<b>%s</b> tartalmaniak elrejtése?\",\r\n\t\"Mute\": \"Elnémítás\",\r\n\t\"Unmute <b>%s</b>?"
},
{
"path": "plugins/ContentFilter/languages/it.json",
"chars": 247,
"preview": "{\r\n\t\"Hide all content from <b>%s</b>?\": \"<b>%s</b> Vuoi nascondere i contenuti di questo utente ?\",\r\n\t\"Mute\": \"Attiva Si"
},
{
"path": "plugins/ContentFilter/languages/jp.json",
"chars": 157,
"preview": "{\n\t\"Hide all content from <b>%s</b>?\": \"<b>%s</b> のコンテンツをすべて隠しますか?\",\n\t\"Mute\": \"ミュート\",\n\t\"Unmute <b>%s</b>?\": \"<b>%s</b> の"
},
{
"path": "plugins/ContentFilter/languages/pt-br.json",
"chars": 226,
"preview": "{\n\t\"Hide all content from <b>%s</b>?\": \"<b>%s</b> Ocultar todo o conteúdo de ?\",\n\t\"Mute\": \"Ativar o Silêncio\",\n\t\"Unmute "
},
{
"path": "plugins/ContentFilter/languages/zh-tw.json",
"chars": 146,
"preview": "{\r\n\t\"Hide all content from <b>%s</b>?\": \"屏蔽 <b>%s</b> 的所有內容?\",\r\n\t\"Mute\": \"屏蔽\",\r\n\t\"Unmute <b>%s</b>?\": \"對 <b>%s</b> 解除屏蔽?"
},
{
"path": "plugins/ContentFilter/languages/zh.json",
"chars": 146,
"preview": "{\r\n\t\"Hide all content from <b>%s</b>?\": \"屏蔽 <b>%s</b> 的所有内容?\",\r\n\t\"Mute\": \"屏蔽\",\r\n\t\"Unmute <b>%s</b>?\": \"对 <b>%s</b> 解除屏蔽?"
},
{
"path": "plugins/ContentFilter/media/blocklisted.html",
"chars": 4046,
"preview": "<html>\n<body>\n\n<style>\n.content { line-height: 24px; font-family: monospace; font-size: 14px; color: #636363; text-trans"
},
{
"path": "plugins/ContentFilter/media/js/ZeroFrame.js",
"chars": 3371,
"preview": "// Version 1.0.0 - Initial release\n// Version 1.1.0 (2017-08-02) - Added cmdp function that returns promise instead of u"
},
{
"path": "plugins/ContentFilter/plugin_info.json",
"chars": 103,
"preview": "{\n\t\"name\": \"ContentFilter\",\n\t\"description\": \"Manage site and user block list.\",\n\t\"default\": \"enabled\"\n}"
},
{
"path": "plugins/Cors/CorsPlugin.py",
"chars": 5146,
"preview": "import re\nimport html\nimport copy\nimport os\nimport gevent\n\nfrom Plugin import PluginManager\nfrom Translate import Transl"
},
{
"path": "plugins/Cors/__init__.py",
"chars": 24,
"preview": "from . import CorsPlugin"
},
{
"path": "plugins/Cors/plugin_info.json",
"chars": 87,
"preview": "{\n\t\"name\": \"Cors\",\n\t\"description\": \"Cross site resource read.\",\n\t\"default\": \"enabled\"\n}"
},
{
"path": "plugins/CryptMessage/CryptMessage.py",
"chars": 1471,
"preview": "import hashlib\nimport base64\nimport struct\nfrom lib import sslcrypto\nfrom Crypt import Crypt\n\n\ncurve = sslcrypto.ecc.get"
},
{
"path": "plugins/CryptMessage/CryptMessagePlugin.py",
"chars": 9178,
"preview": "import base64\nimport os\n\nimport gevent\n\nfrom Plugin import PluginManager\nfrom Crypt import CryptBitcoin, CryptHash\nfrom "
},
{
"path": "plugins/CryptMessage/Test/TestCrypt.py",
"chars": 6010,
"preview": "import pytest\nimport base64\nfrom CryptMessage import CryptMessage\n\n\n@pytest.mark.usefixtures(\"resetSettings\")\nclass Test"
},
{
"path": "plugins/CryptMessage/Test/conftest.py",
"chars": 31,
"preview": "from src.Test.conftest import *"
},
{
"path": "plugins/CryptMessage/Test/pytest.ini",
"chars": 114,
"preview": "[pytest]\npython_files = Test*.py\naddopts = -rsxX -v --durations=6\nmarkers =\n webtest: mark a test as a webtest."
},
{
"path": "plugins/CryptMessage/__init__.py",
"chars": 32,
"preview": "from . import CryptMessagePlugin"
},
{
"path": "plugins/CryptMessage/plugin_info.json",
"chars": 138,
"preview": "{\n\t\"name\": \"CryptMessage\",\n\t\"description\": \"Cryptographic functions of ECIES and AES data encryption/decryption.\",\n\t\"def"
},
{
"path": "plugins/FilePack/FilePackPlugin.py",
"chars": 7786,
"preview": "import os\nimport re\n\nimport gevent\n\nfrom Plugin import PluginManager\nfrom Config import config\nfrom Debug import Debug\n\n"
},
{
"path": "plugins/FilePack/__init__.py",
"chars": 28,
"preview": "from . import FilePackPlugin"
},
{
"path": "plugins/FilePack/plugin_info.json",
"chars": 114,
"preview": "{\n\t\"name\": \"FilePack\",\n\t\"description\": \"Transparent web access for Zip and Tar.gz files.\",\n\t\"default\": \"enabled\"\n}"
},
{
"path": "plugins/MergerSite/MergerSitePlugin.py",
"chars": 18155,
"preview": "import re\nimport time\nimport copy\nimport os\n\nfrom Plugin import PluginManager\nfrom Translate import Translate\nfrom util "
},
{
"path": "plugins/MergerSite/__init__.py",
"chars": 30,
"preview": "from . import MergerSitePlugin"
},
{
"path": "plugins/MergerSite/languages/es.json",
"chars": 180,
"preview": "{\n\t\"Add <b>%s</b> new site?\": \"¿Agregar <b>%s</b> nuevo sitio?\",\n\t\"Added <b>%s</b> new site\": \"Sitio <b>%s</b> agregado\""
},
{
"path": "plugins/MergerSite/languages/fr.json",
"chars": 171,
"preview": "{\n\t\"Add <b>%s</b> new site?\": \"Ajouter le site <b>%s</b> ?\",\n\t\"Added <b>%s</b> new site\": \"Site <b>%s</b> ajouté\",\n\t\"Sit"
},
{
"path": "plugins/MergerSite/languages/hu.json",
"chars": 184,
"preview": "{\n\t\"Add <b>%s</b> new site?\": \"Új oldal hozzáadása: <b>%s</b>?\",\n\t\"Added <b>%s</b> new site\": \"Új oldal hozzáadva: <b>%s"
},
{
"path": "plugins/MergerSite/languages/it.json",
"chars": 180,
"preview": "{\n\t\"Add <b>%s</b> new site?\": \"Aggiungere <b>%s</b> nuovo sito ?\",\n\t\"Added <b>%s</b> new site\": \"Sito <b>%s</b> aggiunto"
},
{
"path": "plugins/MergerSite/languages/jp.json",
"chars": 167,
"preview": "{\n\t\"Add <b>%s</b> new site?\": \"サイト: <b>%s</b> を追加しますか?\",\n\t\"Added <b>%s</b> new site\": \"サイト: <b>%s</b> を追加しました\",\n\t\"Site d"
},
{
"path": "plugins/MergerSite/languages/pt-br.json",
"chars": 179,
"preview": "{\n\t\"Add <b>%s</b> new site?\": \"Adicionar <b>%s</b> novo site?\",\n\t\"Added <b>%s</b> new site\": \"Site <b>%s</b> adicionado\""
},
{
"path": "plugins/MergerSite/languages/tr.json",
"chars": 177,
"preview": "{\n\t\"Add <b>%s</b> new site?\": \"<b>%s</b> sitesi eklensin mi?\",\n\t\"Added <b>%s</b> new site\": \"<b>%s</b> sitesi eklendi\",\n"
},
{
"path": "plugins/MergerSite/languages/zh-tw.json",
"chars": 149,
"preview": "{\n\t\"Add <b>%s</b> new site?\": \"添加新網站: <b>%s</b>?\",\n\t\"Added <b>%s</b> new site\": \"已添加到新網站:<b>%s</b>\",\n\t\"Site deleted: <b>"
},
{
"path": "plugins/MergerSite/languages/zh.json",
"chars": 149,
"preview": "{\n\t\"Add <b>%s</b> new site?\": \"添加新站点: <b>%s</b>?\",\n\t\"Added <b>%s</b> new site\": \"已添加到新站点:<b>%s</b>\",\n\t\"Site deleted: <b>"
},
{
"path": "plugins/Newsfeed/NewsfeedPlugin.py",
"chars": 7987,
"preview": "import time\nimport re\n\nfrom Plugin import PluginManager\nfrom Db.DbQuery import DbQuery\nfrom Debug import Debug\nfrom util"
},
{
"path": "plugins/Newsfeed/__init__.py",
"chars": 28,
"preview": "from . import NewsfeedPlugin"
},
{
"path": "plugins/OptionalManager/ContentDbPlugin.py",
"chars": 17062,
"preview": "import time\nimport collections\nimport itertools\nimport re\n\nimport gevent\n\nfrom util import helper\nfrom Plugin import Plu"
},
{
"path": "plugins/OptionalManager/OptionalManagerPlugin.py",
"chars": 10486,
"preview": "import time\nimport re\nimport collections\n\nimport gevent\n\nfrom util import helper\nfrom Plugin import PluginManager\nfrom ."
},
{
"path": "plugins/OptionalManager/Test/TestOptionalManager.py",
"chars": 7313,
"preview": "import copy\n\nimport pytest\n\n\n@pytest.mark.usefixtures(\"resetSettings\")\nclass TestOptionalManager:\n def testDbFill(sel"
},
{
"path": "plugins/OptionalManager/Test/conftest.py",
"chars": 31,
"preview": "from src.Test.conftest import *"
},
{
"path": "plugins/OptionalManager/Test/pytest.ini",
"chars": 114,
"preview": "[pytest]\npython_files = Test*.py\naddopts = -rsxX -v --durations=6\nmarkers =\n webtest: mark a test as a webtest."
},
{
"path": "plugins/OptionalManager/UiWebsocketPlugin.py",
"chars": 14586,
"preview": "import re\nimport time\nimport html\nimport os\n\nimport gevent\n\nfrom Plugin import PluginManager\nfrom Config import config\nf"
},
{
"path": "plugins/OptionalManager/__init__.py",
"chars": 68,
"preview": "from . import OptionalManagerPlugin\nfrom . import UiWebsocketPlugin\n"
},
{
"path": "plugins/OptionalManager/languages/es.json",
"chars": 458,
"preview": "{\n\t\"Pinned %s files\": \"Archivos %s fijados\",\n\t\"Removed pin from %s files\": \"Archivos %s que no estan fijados\",\n\t\"You sta"
},
{
"path": "plugins/OptionalManager/languages/fr.json",
"chars": 456,
"preview": "{\n\t\"Pinned %s files\": \"Fichiers %s épinglés\",\n\t\"Removed pin from %s files\": \"Fichiers %s ne sont plus épinglés\",\n\t\"You s"
},
{
"path": "plugins/OptionalManager/languages/hu.json",
"chars": 446,
"preview": "{\n\t\"Pinned %s files\": \"%s fájl rögzítve\",\n\t\"Removed pin from %s files\": \"%s fájl rögzítés eltávolítva\",\n\t\"You started to"
},
{
"path": "plugins/OptionalManager/languages/jp.json",
"chars": 377,
"preview": "{\n\t\"Pinned %s files\": \"%s 件のファイルを固定\",\n\t\"Removed pin from %s files\": \"%s 件のファイルの固定を解除\",\n\t\"You started to help distribute "
},
{
"path": "plugins/OptionalManager/languages/pt-br.json",
"chars": 449,
"preview": "{\n\t\"Pinned %s files\": \"Arquivos %s fixados\",\n\t\"Removed pin from %s files\": \"Arquivos %s não estão fixados\",\n\t\"You starte"
},
{
"path": "plugins/OptionalManager/languages/zh-tw.json",
"chars": 336,
"preview": "{\n\t\"Pinned %s files\": \"已固定 %s 個檔\",\n\t\"Removed pin from %s files\": \"已解除固定 %s 個檔\",\n\t\"You started to help distribute <b>%s</"
},
{
"path": "plugins/OptionalManager/languages/zh.json",
"chars": 339,
"preview": "{\n\t\"Pinned %s files\": \"已固定 %s 个文件\",\n\t\"Removed pin from %s files\": \"已解除固定 %s 个文件\",\n\t\"You started to help distribute <b>%s"
},
{
"path": "plugins/PeerDb/PeerDbPlugin.py",
"chars": 3946,
"preview": "import time\nimport sqlite3\nimport random\nimport atexit\n\nimport gevent\nfrom Plugin import PluginManager\n\n\n@PluginManager."
},
{
"path": "plugins/PeerDb/__init__.py",
"chars": 28,
"preview": "from . import PeerDbPlugin\n\n"
},
{
"path": "plugins/PeerDb/plugin_info.json",
"chars": 105,
"preview": "{\n\t\"name\": \"PeerDb\",\n\t\"description\": \"Save/restore peer list on client restart.\",\n\t\"default\": \"enabled\"\n}"
},
{
"path": "plugins/Sidebar/ConsolePlugin.py",
"chars": 3329,
"preview": "import re\nimport logging\n\nfrom Plugin import PluginManager\nfrom Config import config\nfrom Debug import Debug\nfrom util i"
},
{
"path": "plugins/Sidebar/SidebarPlugin.py",
"chars": 31838,
"preview": "import re\nimport os\nimport html\nimport sys\nimport math\nimport time\nimport json\nimport io\nimport urllib\nimport urllib.par"
},
{
"path": "plugins/Sidebar/ZipStream.py",
"chars": 1595,
"preview": "import io\nimport os\nimport zipfile\n\nclass ZipStream(object):\n def __init__(self, dir_path):\n self.dir_path = d"
},
{
"path": "plugins/Sidebar/__init__.py",
"chars": 55,
"preview": "from . import SidebarPlugin\nfrom . import ConsolePlugin"
},
{
"path": "plugins/Sidebar/languages/da.json",
"chars": 2706,
"preview": "{\n\t\"Peers\": \"Klienter\",\n\t\"Connected\": \"Forbundet\",\n\t\"Connectable\": \"Mulige\",\n\t\"Connectable peers\": \"Mulige klienter\",\n\n\t"
},
{
"path": "plugins/Sidebar/languages/de.json",
"chars": 2840,
"preview": "{\n\t\"Peers\": \"Peers\",\n\t\"Connected\": \"Verbunden\",\n\t\"Connectable\": \"Verbindbar\",\n\t\"Connectable peers\": \"Verbindbare Peers\","
},
{
"path": "plugins/Sidebar/languages/es.json",
"chars": 2856,
"preview": "{\n\t\"Peers\": \"Pares\",\n\t\"Connected\": \"Conectados\",\n\t\"Connectable\": \"Conectables\",\n\t\"Connectable peers\": \"Pares conectables"
},
{
"path": "plugins/Sidebar/languages/fr.json",
"chars": 2836,
"preview": "{\n\t\"Peers\": \"Pairs\",\n\t\"Connected\": \"Connectés\",\n\t\"Connectable\": \"Accessibles\",\n\t\"Connectable peers\": \"Pairs accessibles\""
},
{
"path": "plugins/Sidebar/languages/hu.json",
"chars": 2756,
"preview": "{\n\t\"Peers\": \"Csatlakozási pontok\",\n\t\"Connected\": \"Csaltakozva\",\n\t\"Connectable\": \"Csatlakozható\",\n\t\"Connectable peers\": \""
},
{
"path": "plugins/Sidebar/languages/it.json",
"chars": 2747,
"preview": "{\n\t\"Peers\": \"Peer\",\n\t\"Connected\": \"Connessi\",\n\t\"Connectable\": \"Collegabili\",\n\t\"Connectable peers\": \"Peer collegabili\",\n\n"
},
{
"path": "plugins/Sidebar/languages/jp.json",
"chars": 3101,
"preview": "{\n\t\"Copy to clipboard\": \"クリップボードにコピー\",\n\t\"Peers\": \"ピア\",\n\t\"Connected\": \"接続済み\",\n\t\"Connectable\": \"利用可能\",\n\t\"Connectable peers"
},
{
"path": "plugins/Sidebar/languages/pl.json",
"chars": 2843,
"preview": "{\n\t\"Peers\": \"Użytkownicy równorzędni\",\n\t\"Connected\": \"Połączony\",\n\t\"Connectable\": \"Możliwy do podłączenia\",\n\t\"Connectabl"
},
{
"path": "plugins/Sidebar/languages/pt-br.json",
"chars": 3626,
"preview": "{\n\t\"Copy to clipboard\": \"Copiar para área de transferência (clipboard)\",\n\t\"Peers\": \"Peers\",\n\t\"Connected\": \"Ligados\",\n\t\"C"
},
{
"path": "plugins/Sidebar/languages/ru.json",
"chars": 2783,
"preview": "{\n\t\"Peers\": \"Пиры\",\n\t\"Connected\": \"Подключенные\",\n\t\"Connectable\": \"Доступные\",\n\t\"Connectable peers\": \"Пиры доступны для "
},
{
"path": "plugins/Sidebar/languages/tr.json",
"chars": 2710,
"preview": "{\n\t\"Peers\": \"Eşler\",\n\t\"Connected\": \"Bağlı\",\n\t\"Connectable\": \"Erişilebilir\",\n\t\"Connectable peers\": \"Bağlanılabilir eşler\""
},
{
"path": "plugins/Sidebar/languages/zh-tw.json",
"chars": 2090,
"preview": "{\n\t\"Peers\": \"節點數\",\n\t\"Connected\": \"已連線\",\n\t\"Connectable\": \"可連線\",\n\t\"Connectable peers\": \"可連線節點\",\n\n\t\"Data transfer\": \"數據傳輸\","
},
{
"path": "plugins/Sidebar/languages/zh.json",
"chars": 2672,
"preview": "{\n\t\"Copy to clipboard\": \"复制到剪切板\",\n\t\"Peers\": \"节点数\",\n\t\"Connected\": \"已连接\",\n\t\"Connectable\": \"可连接\",\n\t\"Onion\": \"洋葱点\",\n\t\"Local\""
},
{
"path": "plugins/Sidebar/media/Class.coffee",
"chars": 490,
"preview": "class Class\n\ttrace: true\n\n\tlog: (args...) ->\n\t\treturn unless @trace\n\t\treturn if typeof console is 'undefined'\n\t\targs.uns"
},
{
"path": "plugins/Sidebar/media/Console.coffee",
"chars": 6223,
"preview": "class Console extends Class\n\tconstructor: (@sidebar) ->\n\t\t@tag = null\n\t\t@opened = false\n\t\t@filter = null\n\t\t@tab_types = "
},
{
"path": "plugins/Sidebar/media/Console.css",
"chars": 2288,
"preview": ".console-container { width: 100%; z-index: 998; position: absolute; top: -100vh; padding-bottom: 100%; }\n.console-contai"
},
{
"path": "plugins/Sidebar/media/Menu.coffee",
"chars": 1360,
"preview": "class Menu\n\tconstructor: (@button) ->\n\t\t@elem = $(\".menu.template\").clone().removeClass(\"template\")\n\t\t@elem.appendTo(\"bo"
},
{
"path": "plugins/Sidebar/media/Menu.css",
"chars": 1302,
"preview": ".menu {\n\tbackground-color: white; padding: 10px 0px; position: absolute; top: 0px; left: 0px; max-height: 0px; overflow:"
},
{
"path": "plugins/Sidebar/media/Prototypes.coffee",
"chars": 317,
"preview": "String::startsWith = (s) -> @[...s.length] is s\nString::endsWith = (s) -> s is '' or @[-s.length..] is s\nString::capital"
},
{
"path": "plugins/Sidebar/media/RateLimit.coffee",
"chars": 379,
"preview": "limits = {}\ncall_after_interval = {}\nwindow.RateLimit = (interval, fn) ->\n\tif not limits[fn]\n\t\tcall_after_interval[fn] ="
},
{
"path": "plugins/Sidebar/media/Scrollable.js",
"chars": 3264,
"preview": "/* via http://jsfiddle.net/elGrecode/00dgurnn/ */\n\nwindow.initScrollable = function () {\n\n var scrollContainer = docu"
},
{
"path": "plugins/Sidebar/media/Scrollbable.css",
"chars": 862,
"preview": ".scrollable {\n overflow: hidden;\n}\n\n.scrollable.showScroll::after {\n position: absolute;\n content: '';\n top:"
},
{
"path": "plugins/Sidebar/media/Sidebar.coffee",
"chars": 22253,
"preview": "class Sidebar extends Class\n\tconstructor: (@wrapper) ->\n\t\t@tag = null\n\t\t@container = null\n\t\t@opened = false\n\t\t@width = 4"
},
{
"path": "plugins/Sidebar/media/Sidebar.css",
"chars": 8927,
"preview": ".menu {\n\tfont-family: Roboto, 'Segoe UI', 'Helvetica Neue'; z-index: 999;\n}\n\n.drag-bg { width: 100%; height: 100%; posit"
},
{
"path": "plugins/Sidebar/media/all.css",
"chars": 19710,
"preview": "\n/* ---- Console.css ---- */\n\n\n.console-container { width: 100%; z-index: 998; position: absolute; top: -100vh; padding-"
},
{
"path": "plugins/Sidebar/media/all.js",
"chars": 64705,
"preview": "\n/* ---- Class.coffee ---- */\n\n\n(function() {\n var Class,\n slice = [].slice;\n\n Class = (function() {\n function C"
},
{
"path": "plugins/Sidebar/media/morphdom.js",
"chars": 12591,
"preview": "(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"func"
},
{
"path": "plugins/Sidebar/media_globe/Detector.js",
"chars": 1952,
"preview": "/**\n * @author alteredq / http://alteredqualia.com/\n * @author mr.doob / http://mrdoob.com/\n */\n\nDetector = {\n\n canvas "
},
{
"path": "plugins/Sidebar/media_globe/Tween.js",
"chars": 4518,
"preview": "// Tween.js - http://github.com/sole/tween.js\nvar TWEEN=TWEEN||function(){var a,e,c,d,f=[];return{start:function(g){c=se"
},
{
"path": "plugins/Sidebar/media_globe/all.js",
"chars": 435287,
"preview": "\n\n/* ---- plugins/Sidebar/media_globe/Detector.js ---- */\n\n\n/**\n * @author alteredq / http://alteredqualia.com/\n * @auth"
},
{
"path": "plugins/Sidebar/media_globe/globe.js",
"chars": 12800,
"preview": "/**\n * dat.globe Javascript WebGL Globe Toolkit\n * http://dataarts.github.com/dat.globe\n *\n * Copyright 2011 Data Arts T"
},
{
"path": "plugins/Sidebar/plugin_info.json",
"chars": 155,
"preview": "{\n\t\"name\": \"Sidebar\",\n\t\"description\": \"Access site management sidebar and console by dragging top-right 0 button to left"
},
{
"path": "plugins/Stats/StatsPlugin.py",
"chars": 25746,
"preview": "import time\nimport html\nimport os\nimport json\nimport sys\nimport itertools\n\nfrom Plugin import PluginManager\nfrom Config "
},
{
"path": "plugins/Stats/__init__.py",
"chars": 25,
"preview": "from . import StatsPlugin"
},
{
"path": "plugins/Stats/plugin_info.json",
"chars": 91,
"preview": "{\n\t\"name\": \"Stats\",\n\t\"description\": \"/Stats and /Benchmark pages.\",\n\t\"default\": \"enabled\"\n}"
},
{
"path": "plugins/TranslateSite/TranslateSitePlugin.py",
"chars": 3683,
"preview": "import time\n\nfrom Plugin import PluginManager\nfrom Translate import translate\n\n\n@PluginManager.registerTo(\"UiRequest\")\nc"
},
{
"path": "plugins/TranslateSite/__init__.py",
"chars": 34,
"preview": "from . import TranslateSitePlugin\n"
},
{
"path": "plugins/TranslateSite/plugin_info.json",
"chars": 137,
"preview": "{\n\t\"name\": \"TranslateSite\",\n\t\"description\": \"Transparent support translation of site javascript and html files.\",\n\t\"defa"
},
{
"path": "plugins/Trayicon/TrayiconPlugin.py",
"chars": 5482,
"preview": "import os\nimport sys\nimport atexit\n\nfrom Plugin import PluginManager\nfrom Config import config\nfrom Translate import Tra"
},
{
"path": "plugins/Trayicon/__init__.py",
"chars": 69,
"preview": "import sys\n\nif sys.platform == 'win32':\n\tfrom . import TrayiconPlugin"
},
{
"path": "plugins/Trayicon/languages/es.json",
"chars": 531,
"preview": "{\n\t\"ZeroNet Twitter\": \"ZeroNet Twitter\",\n\t\"ZeroNet Reddit\": \"ZeroNet Reddit\",\n\t\"ZeroNet Github\": \"ZeroNet Github\",\n\t\"Rep"
},
{
"path": "plugins/Trayicon/languages/fr.json",
"chars": 540,
"preview": "{\n\t\"ZeroNet Twitter\": \"ZeroNet Twitter\",\n\t\"ZeroNet Reddit\": \"ZeroNet Reddit\",\n\t\"ZeroNet Github\": \"ZeroNet Github\",\n\t\"Rep"
},
{
"path": "plugins/Trayicon/languages/hu.json",
"chars": 528,
"preview": "{\n\t\"ZeroNet Twitter\": \"ZeroNet Twitter\",\n\t\"ZeroNet Reddit\": \"ZeroNet Reddit\",\n\t\"ZeroNet Github\": \"ZeroNet Github\",\n\t\"Rep"
},
{
"path": "plugins/Trayicon/languages/it.json",
"chars": 538,
"preview": "{\n\t\"ZeroNet Twitter\": \"ZeroNet Twitter\",\n\t\"ZeroNet Reddit\": \"ZeroNet Reddit\",\n\t\"ZeroNet Github\": \"ZeroNet Github\",\n\t\"Rep"
},
{
"path": "plugins/Trayicon/languages/jp.json",
"chars": 460,
"preview": " {\n\t\"ZeroNet Twitter\": \"ZeroNet Twitter\",\n\t\"ZeroNet Reddit\": \"ZeroNet Reddit\",\n\t\"ZeroNet Github\": \"ZeroNet Github\",\n\t\"Re"
},
{
"path": "plugins/Trayicon/languages/pl.json",
"chars": 526,
"preview": "{\n\t\"ZeroNet Twitter\": \"ZeroNet Twitter\",\n\t\"ZeroNet Reddit\": \"ZeroNet Reddit\",\n\t\"ZeroNet Github\": \"ZeroNet Github\",\n\t\"Rep"
},
{
"path": "plugins/Trayicon/languages/pt-br.json",
"chars": 529,
"preview": "{\n\t\"ZeroNet Twitter\": \"ZeroNet Twitter\",\n\t\"ZeroNet Reddit\": \"ZeroNet Reddit\",\n\t\"ZeroNet Github\": \"ZeroNet Github\",\n\t\"Rep"
},
{
"path": "plugins/Trayicon/languages/tr.json",
"chars": 519,
"preview": "{\n\t\"ZeroNet Twitter\": \"ZeroNet Twitter\",\n\t\"ZeroNet Reddit\": \"ZeroNet Reddit\",\n\t\"ZeroNet Github\": \"ZeroNet Github\",\n\t\"Rep"
},
{
"path": "plugins/Trayicon/languages/zh-tw.json",
"chars": 455,
"preview": "{\n\t\"ZeroNet Twitter\": \"ZeroNet Twitter\",\n\t\"ZeroNet Reddit\": \"ZeroNet Reddit\",\n\t\"ZeroNet Github\": \"ZeroNet Github\",\n\t\"Rep"
},
{
"path": "plugins/Trayicon/languages/zh.json",
"chars": 455,
"preview": "{\n\t\"ZeroNet Twitter\": \"ZeroNet Twitter\",\n\t\"ZeroNet Reddit\": \"ZeroNet Reddit\",\n\t\"ZeroNet Github\": \"ZeroNet Github\",\n\t\"Rep"
},
{
"path": "plugins/Trayicon/lib/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "plugins/Trayicon/lib/notificationicon.py",
"chars": 24297,
"preview": "# Pure ctypes windows taskbar notification icon\n# via https://gist.github.com/jasonbot/5759510\n# Modified for ZeroNet\n\ni"
},
{
"path": "plugins/Trayicon/lib/winfolders.py",
"chars": 1976,
"preview": "''' Get windows special folders without pythonwin\n Example:\n import specialfolders\n start_progr"
},
{
"path": "plugins/Trayicon/plugin_info.json",
"chars": 102,
"preview": "{\n\t\"name\": \"Trayicon\",\n\t\"description\": \"Icon for system tray. (Windows only)\",\n\t\"default\": \"enabled\"\n}"
},
{
"path": "plugins/UiConfig/UiConfigPlugin.py",
"chars": 2670,
"preview": "import io\nimport os\n\nfrom Plugin import PluginManager\nfrom Config import config\nfrom Translate import Translate\nfrom uti"
},
{
"path": "plugins/UiConfig/__init__.py",
"chars": 29,
"preview": "from . import UiConfigPlugin\n"
},
{
"path": "plugins/UiConfig/languages/hu.json",
"chars": 1757,
"preview": "{\n\t\"ZeroNet config\": \"ZeroNet beállítások\",\n\t\"Web Interface\": \"Web felület\",\n\t\"Open web browser on ZeroNet startup\": \"Bö"
},
{
"path": "plugins/UiConfig/languages/jp.json",
"chars": 2502,
"preview": "{\n\t\"ZeroNet config\": \"ZeroNetの設定\",\n\t\"Web Interface\": \"WEBインターフェース\",\n\t\"Open web browser on ZeroNet startup\": \"ZeroNet起動時に"
},
{
"path": "plugins/UiConfig/languages/pl.json",
"chars": 3323,
"preview": "{\n\t\"ZeroNet config\": \"Konfiguracja ZeroNet\",\n\t\"Web Interface\": \"Interfejs webowy\",\n\t\"Open web browser on ZeroNet startup"
},
{
"path": "plugins/UiConfig/languages/pt-br.json",
"chars": 3207,
"preview": "{\n\t\"ZeroNet config\": \"Configurações da ZeroNet\",\n\t\"Web Interface\": \"Interface Web\",\n\t\"Open web browser on ZeroNet startu"
},
{
"path": "plugins/UiConfig/languages/zh.json",
"chars": 2305,
"preview": "{\n\t\"ZeroNet config\": \"ZeroNet配置\",\n\t\"Web Interface\": \"网页界面\",\n\t\"Open web browser on ZeroNet startup\": \"ZeroNet启动时,打开浏览器\",\n"
},
{
"path": "plugins/UiConfig/media/config.html",
"chars": 482,
"preview": "<!DOCTYPE html>\n\n<html>\n<head>\n <title>Settings - ZeroNet</title>\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"content-t"
},
{
"path": "plugins/UiConfig/media/css/Config.css",
"chars": 4320,
"preview": "body { background-color: #EDF2F5; font-family: Roboto, 'Segoe UI', Arial, 'Helvetica Neue'; margin: 0px; padding: 0px; b"
},
{
"path": "plugins/UiConfig/media/css/all.css",
"chars": 92966,
"preview": "\n/* ---- Config.css ---- */\n\n\nbody { background-color: #EDF2F5; font-family: Roboto, 'Segoe UI', Arial, 'Helvetica Neue'"
},
{
"path": "plugins/UiConfig/media/css/button.css",
"chars": 725,
"preview": "/* Button */\n.button {\n\tbackground-color: #FFDC00; color: black; padding: 10px 20px; display: inline-block; background-p"
},
{
"path": "plugins/UiConfig/media/css/fonts.css",
"chars": 83825,
"preview": "/* Base64 encoder: http://www.motobit.com/util/base64-decoder-encoder.asp */\n/* Generated by Font Squirrel (http://www.f"
},
{
"path": "plugins/UiConfig/media/js/ConfigStorage.coffee",
"chars": 5824,
"preview": "class ConfigStorage extends Class\n\tconstructor: (@config) ->\n\t\t@items = []\n\t\t@createSections()\n\t\t@setValues(@config)\n\n\ts"
},
{
"path": "plugins/UiConfig/media/js/ConfigView.coffee",
"chars": 3919,
"preview": "class ConfigView extends Class\n\tconstructor: () ->\n\t\t@\n\n\trender: ->\n\t\t@config_storage.items.map @renderSection\n\n\trenderS"
},
{
"path": "plugins/UiConfig/media/js/UiConfig.coffee",
"chars": 4073,
"preview": "window.h = maquette.h\n\nclass UiConfig extends ZeroFrame\n\tinit: ->\n\t\t@save_visible = true\n\t\t@config = null # Setting cur"
},
{
"path": "plugins/UiConfig/media/js/all.js",
"chars": 75270,
"preview": "\n/* ---- lib/Class.coffee ---- */\n\n\n(function() {\n var Class,\n slice = [].slice;\n\n Class = (function() {\n functi"
},
{
"path": "plugins/UiConfig/media/js/lib/Class.coffee",
"chars": 490,
"preview": "class Class\n\ttrace: true\n\n\tlog: (args...) ->\n\t\treturn unless @trace\n\t\treturn if typeof console is 'undefined'\n\t\targs.uns"
},
{
"path": "plugins/UiConfig/media/js/lib/Promise.coffee",
"chars": 1410,
"preview": "# From: http://dev.bizo.com/2011/12/promises-in-javascriptcoffeescript.html\n\nclass Promise\n\t@when: (tasks...) ->\n\t\tnum_u"
},
{
"path": "plugins/UiConfig/media/js/lib/Prototypes.coffee",
"chars": 235,
"preview": "String::startsWith = (s) -> @[...s.length] is s\nString::endsWith = (s) -> s is '' or @[-s.length..] is s\nString::repeat "
},
{
"path": "plugins/UiConfig/media/js/lib/maquette.js",
"chars": 35517,
"preview": "(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymo"
},
{
"path": "plugins/UiConfig/media/js/utils/Animation.coffee",
"chars": 4263,
"preview": "class Animation\n\tslideDown: (elem, props) ->\n\t\tif elem.offsetTop > 2000\n\t\t\treturn\n\n\t\th = elem.offsetHeight\n\t\tcstyle = wi"
},
{
"path": "plugins/UiConfig/media/js/utils/Dollar.coffee",
"chars": 114,
"preview": "window.$ = (selector) ->\n\tif selector.startsWith(\"#\")\n\t\treturn document.getElementById(selector.replace(\"#\", \"\"))\n"
},
{
"path": "plugins/UiConfig/media/js/utils/ZeroFrame.coffee",
"chars": 1931,
"preview": "class ZeroFrame extends Class\n\tconstructor: (url) ->\n\t\t@url = url\n\t\t@waiting_cb = {}\n\t\t@wrapper_nonce = document.locatio"
},
{
"path": "plugins/UiConfig/plugin_info.json",
"chars": 113,
"preview": "{\n\t\"name\": \"UiConfig\",\n\t\"description\": \"Change client settings using the web interface.\",\n\t\"default\": \"enabled\"\n}"
},
{
"path": "plugins/UiFileManager/UiFileManagerPlugin.py",
"chars": 3454,
"preview": "import io\nimport os\nimport re\nimport urllib\n\nfrom Plugin import PluginManager\nfrom Config import config\nfrom Translate i"
},
{
"path": "plugins/UiFileManager/__init__.py",
"chars": 34,
"preview": "from . import UiFileManagerPlugin\n"
},
{
"path": "plugins/UiFileManager/languages/hu.json",
"chars": 592,
"preview": "{\n \"New file name:\": \"Új fájl neve:\",\n \"Delete\": \"Törlés\",\n \"Cancel\": \"Mégse\",\n \"Selected:\": \"Köjelölt:\",\n "
},
{
"path": "plugins/UiFileManager/languages/jp.json",
"chars": 459,
"preview": "{\n\t\"New file name:\": \"新しいファイルの名前:\",\n\t\"Delete\": \"削除\",\n\t\"Cancel\": \"キャンセル\",\n\t\"Selected:\": \"選択済み: \",\n\t\"Delete and remove opt"
},
{
"path": "plugins/UiFileManager/media/codemirror/LICENSE",
"chars": 1107,
"preview": "MIT License\n\nCopyright (C) 2017 by Marijn Haverbeke <marijnh@gmail.com> and others\n\nPermission is hereby granted, free o"
},
{
"path": "plugins/UiFileManager/media/codemirror/all.css",
"chars": 19401,
"preview": "\n/* ---- base/codemirror.css ---- */\n\n\n/* BASICS */\n\n.CodeMirror {\n /* Set height, width, borders, and global font prop"
},
{
"path": "plugins/UiFileManager/media/codemirror/all.js",
"chars": 779186,
"preview": "\n/* ---- base/codemirror.js ---- */\n\n\n// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under a"
},
{
"path": "plugins/UiFileManager/media/codemirror/base/codemirror.css",
"chars": 8705,
"preview": "/* BASICS */\n\n.CodeMirror {\n /* Set height, width, borders, and global font properties here */\n font-family: monospace"
}
]
// ... and 337 more files (download for full content)
About this extraction
This page contains the full source code of the HelloZeroNet/ZeroNet GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 537 files (5.3 MB), approximately 1.4M tokens, and a symbol index with 4145 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.