Upgrade Electrum base to 3.3.8
36
contrib/build-osx/README.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
Building Mac OS binaries
|
||||
========================
|
||||
|
||||
This guide explains how to build Electrum binaries for macOS systems.
|
||||
|
||||
The build process consists of two steps:
|
||||
|
||||
## 1. Building the binary
|
||||
|
||||
This needs to be done on a system running macOS or OS X. We use El Capitan (10.11.6) as building it on High Sierra
|
||||
makes the binaries incompatible with older versions.
|
||||
|
||||
Before starting, make sure that the Xcode command line tools are installed (e.g. you have `git`).
|
||||
|
||||
|
||||
cd electrum
|
||||
./contrib/build-osx/make_osx
|
||||
|
||||
This creates a folder named Electrum.app.
|
||||
|
||||
## 2. Building the image
|
||||
The usual way to distribute macOS applications is to use image files containing the
|
||||
application. Although these images can be created on a Mac with the built-in `hdiutil`,
|
||||
they are not deterministic.
|
||||
|
||||
Instead, we use the toolchain that Bitcoin uses: genisoimage and libdmg-hfsplus.
|
||||
These tools do not work on macOS, so you need a separate Linux machine (or VM).
|
||||
|
||||
Copy the Electrum.app directory over and install the dependencies, e.g.:
|
||||
|
||||
apt install libcap-dev cmake make gcc faketime
|
||||
|
||||
Then you can just invoke `package.sh` with the path to the app:
|
||||
|
||||
cd electrum
|
||||
./contrib/build-osx/package.sh ~/Electrum.app/
|
12
contrib/build-osx/base.sh
Normal file
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
RED='\033[0;31m'
|
||||
BLUE='\033[0,34m'
|
||||
NC='\033[0m' # No Color
|
||||
function info {
|
||||
printf "\r💬 ${BLUE}INFO:${NC} ${1}\n"
|
||||
}
|
||||
function fail {
|
||||
printf "\r🗯 ${RED}ERROR:${NC} ${1}\n"
|
||||
exit 1
|
||||
}
|
86
contrib/build-osx/cdrkit-deterministic.patch
Normal file
|
@ -0,0 +1,86 @@
|
|||
--- cdrkit-1.1.11.old/genisoimage/tree.c 2008-10-21 19:57:47.000000000 -0400
|
||||
+++ cdrkit-1.1.11/genisoimage/tree.c 2013-12-06 00:23:18.489622668 -0500
|
||||
@@ -1139,8 +1139,9 @@
|
||||
scan_directory_tree(struct directory *this_dir, char *path,
|
||||
struct directory_entry *de)
|
||||
{
|
||||
- DIR *current_dir;
|
||||
+ int current_file;
|
||||
char whole_path[PATH_MAX];
|
||||
+ struct dirent **d_list;
|
||||
struct dirent *d_entry;
|
||||
struct directory *parent;
|
||||
int dflag;
|
||||
@@ -1164,7 +1165,8 @@
|
||||
this_dir->dir_flags |= DIR_WAS_SCANNED;
|
||||
|
||||
errno = 0; /* Paranoia */
|
||||
- current_dir = opendir(path);
|
||||
+ //current_dir = opendir(path);
|
||||
+ current_file = scandir(path, &d_list, NULL, alphasort);
|
||||
d_entry = NULL;
|
||||
|
||||
/*
|
||||
@@ -1173,12 +1175,12 @@
|
||||
*/
|
||||
old_path = path;
|
||||
|
||||
- if (current_dir) {
|
||||
+ if (current_file >= 0) {
|
||||
errno = 0;
|
||||
- d_entry = readdir(current_dir);
|
||||
+ d_entry = d_list[0];
|
||||
}
|
||||
|
||||
- if (!current_dir || !d_entry) {
|
||||
+ if (current_file < 0 || !d_entry) {
|
||||
int ret = 1;
|
||||
|
||||
#ifdef USE_LIBSCHILY
|
||||
@@ -1191,8 +1193,8 @@
|
||||
de->isorec.flags[0] &= ~ISO_DIRECTORY;
|
||||
ret = 0;
|
||||
}
|
||||
- if (current_dir)
|
||||
- closedir(current_dir);
|
||||
+ if(d_list)
|
||||
+ free(d_list);
|
||||
return (ret);
|
||||
}
|
||||
#ifdef ABORT_DEEP_ISO_ONLY
|
||||
@@ -1208,7 +1210,7 @@
|
||||
errmsgno(EX_BAD, "use Rock Ridge extensions via -R or -r,\n");
|
||||
errmsgno(EX_BAD, "or allow deep ISO9660 directory nesting via -D.\n");
|
||||
}
|
||||
- closedir(current_dir);
|
||||
+ free(d_list);
|
||||
return (1);
|
||||
}
|
||||
#endif
|
||||
@@ -1250,13 +1252,13 @@
|
||||
* The first time through, skip this, since we already asked
|
||||
* for the first entry when we opened the directory.
|
||||
*/
|
||||
- if (dflag)
|
||||
- d_entry = readdir(current_dir);
|
||||
+ if (dflag && current_file >= 0)
|
||||
+ d_entry = d_list[current_file];
|
||||
dflag++;
|
||||
|
||||
- if (!d_entry)
|
||||
+ if (current_file < 0)
|
||||
break;
|
||||
-
|
||||
+ current_file--;
|
||||
/* OK, got a valid entry */
|
||||
|
||||
/* If we do not want all files, then pitch the backups. */
|
||||
@@ -1348,7 +1350,7 @@
|
||||
insert_file_entry(this_dir, whole_path, d_entry->d_name);
|
||||
#endif /* APPLE_HYB */
|
||||
}
|
||||
- closedir(current_dir);
|
||||
+ free(d_list);
|
||||
|
||||
#ifdef APPLE_HYB
|
||||
/*
|
100
contrib/build-osx/make_osx
Normal file
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Parameterize
|
||||
PYTHON_VERSION=3.6.4
|
||||
BUILDDIR=/tmp/electrum-build
|
||||
PACKAGE=Electrum
|
||||
GIT_REPO=https://github.com/spesmilo/electrum
|
||||
LIBSECP_VERSION=452d8e4d2a2f9f1b5be6b02e18f1ba102e5ca0b4
|
||||
|
||||
. $(dirname "$0")/base.sh
|
||||
|
||||
src_dir=$(dirname "$0")
|
||||
cd $src_dir/../..
|
||||
|
||||
export PYTHONHASHSEED=22
|
||||
VERSION=`git describe --tags --dirty --always`
|
||||
|
||||
which brew > /dev/null 2>&1 || fail "Please install brew from https://brew.sh/ to continue"
|
||||
|
||||
info "Installing Python $PYTHON_VERSION"
|
||||
export PATH="~/.pyenv/bin:~/.pyenv/shims:~/Library/Python/3.6/bin:$PATH"
|
||||
if [ -d "~/.pyenv" ]; then
|
||||
pyenv update
|
||||
else
|
||||
curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash > /dev/null 2>&1
|
||||
fi
|
||||
PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install -s $PYTHON_VERSION && \
|
||||
pyenv global $PYTHON_VERSION || \
|
||||
fail "Unable to use Python $PYTHON_VERSION"
|
||||
|
||||
|
||||
info "Installing pyinstaller"
|
||||
python3 -m pip install -I --user pyinstaller==3.4 || fail "Could not install pyinstaller"
|
||||
|
||||
info "Using these versions for building $PACKAGE:"
|
||||
sw_vers
|
||||
python3 --version
|
||||
echo -n "Pyinstaller "
|
||||
pyinstaller --version
|
||||
|
||||
rm -rf ./dist
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
rm -rf $BUILDDIR > /dev/null 2>&1
|
||||
mkdir $BUILDDIR
|
||||
|
||||
cp -R ./contrib/deterministic-build/electrum-locale/locale/ ./electrum/locale/
|
||||
cp ./contrib/deterministic-build/electrum-icons/icons_rc.py ./electrum/gui/qt/
|
||||
|
||||
|
||||
info "Downloading libusb..."
|
||||
curl https://homebrew.bintray.com/bottles/libusb-1.0.22.el_capitan.bottle.tar.gz | \
|
||||
tar xz --directory $BUILDDIR
|
||||
cp $BUILDDIR/libusb/1.0.22/lib/libusb-1.0.dylib contrib/build-osx
|
||||
|
||||
info "Building libsecp256k1"
|
||||
brew install autoconf automake libtool
|
||||
git clone https://github.com/bitcoin-core/secp256k1 $BUILDDIR/secp256k1
|
||||
pushd $BUILDDIR/secp256k1
|
||||
git reset --hard $LIBSECP_VERSION
|
||||
git clean -f -x -q
|
||||
./autogen.sh
|
||||
./configure --enable-module-recovery --enable-experimental --enable-module-ecdh --disable-jni
|
||||
make
|
||||
popd
|
||||
cp $BUILDDIR/secp256k1/.libs/libsecp256k1.0.dylib contrib/build-osx
|
||||
|
||||
|
||||
info "Installing requirements..."
|
||||
python3 -m pip install -Ir ./contrib/deterministic-build/requirements.txt --user && \
|
||||
python3 -m pip install -Ir ./contrib/deterministic-build/requirements-binaries.txt --user || \
|
||||
fail "Could not install requirements"
|
||||
|
||||
info "Installing hardware wallet requirements..."
|
||||
python3 -m pip install -Ir ./contrib/deterministic-build/requirements-hw.txt --user || \
|
||||
fail "Could not install hardware wallet requirements"
|
||||
|
||||
info "Building $PACKAGE..."
|
||||
python3 setup.py install --user > /dev/null || fail "Could not build $PACKAGE"
|
||||
|
||||
info "Faking timestamps..."
|
||||
for d in ~/Library/Python/ ~/.pyenv .; do
|
||||
pushd $d
|
||||
find . -exec touch -t '200101220000' {} +
|
||||
popd
|
||||
done
|
||||
|
||||
info "Building binary"
|
||||
pyinstaller --noconfirm --ascii --clean --name $VERSION contrib/build-osx/osx.spec || fail "Could not build binary"
|
||||
|
||||
info "Adding bitcoin URI types to Info.plist"
|
||||
plutil -insert 'CFBundleURLTypes' \
|
||||
-xml '<array><dict> <key>CFBundleURLName</key> <string>bitcoin</string> <key>CFBundleURLSchemes</key> <array><string>bitcoin</string></array> </dict></array>' \
|
||||
-- dist/$PACKAGE.app/Contents/Info.plist \
|
||||
|| fail "Could not add keys to Info.plist. Make sure the program 'plutil' exists and is installed."
|
||||
|
||||
info "Creating .DMG"
|
||||
hdiutil create -fs HFS+ -volname $PACKAGE -srcfolder dist/$PACKAGE.app dist/electrum-$VERSION.dmg || fail "Could not create .DMG"
|
104
contrib/build-osx/osx.spec
Normal file
|
@ -0,0 +1,104 @@
|
|||
# -*- mode: python -*-
|
||||
|
||||
from PyInstaller.utils.hooks import collect_data_files, collect_submodules, collect_dynamic_libs
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
PACKAGE='Electrum'
|
||||
PYPKG='electrum'
|
||||
MAIN_SCRIPT='run_electrum'
|
||||
ICONS_FILE='electrum.icns'
|
||||
|
||||
for i, x in enumerate(sys.argv):
|
||||
if x == '--name':
|
||||
VERSION = sys.argv[i+1]
|
||||
break
|
||||
else:
|
||||
raise Exception('no version')
|
||||
|
||||
electrum = os.path.abspath(".") + "/"
|
||||
block_cipher = None
|
||||
|
||||
# see https://github.com/pyinstaller/pyinstaller/issues/2005
|
||||
hiddenimports = []
|
||||
hiddenimports += collect_submodules('trezorlib')
|
||||
hiddenimports += collect_submodules('safetlib')
|
||||
hiddenimports += collect_submodules('btchip')
|
||||
hiddenimports += collect_submodules('keepkeylib')
|
||||
hiddenimports += collect_submodules('websocket')
|
||||
hiddenimports += collect_submodules('ckcc')
|
||||
|
||||
datas = [
|
||||
(electrum + PYPKG + '/*.json', PYPKG),
|
||||
(electrum + PYPKG + '/wordlist/english.txt', PYPKG + '/wordlist'),
|
||||
(electrum + PYPKG + '/locale', PYPKG + '/locale'),
|
||||
(electrum + PYPKG + '/plugins', PYPKG + '/plugins'),
|
||||
]
|
||||
datas += collect_data_files('trezorlib')
|
||||
datas += collect_data_files('safetlib')
|
||||
datas += collect_data_files('btchip')
|
||||
datas += collect_data_files('keepkeylib')
|
||||
datas += collect_data_files('ckcc')
|
||||
|
||||
# Add libusb so Trezor and Safe-T mini will work
|
||||
binaries = [(electrum + "contrib/build-osx/libusb-1.0.dylib", ".")]
|
||||
binaries += [(electrum + "contrib/build-osx/libsecp256k1.0.dylib", ".")]
|
||||
|
||||
# Workaround for "Retro Look":
|
||||
binaries += [b for b in collect_dynamic_libs('PyQt5') if 'macstyle' in b[0]]
|
||||
|
||||
# We don't put these files in to actually include them in the script but to make the Analysis method scan them for imports
|
||||
a = Analysis([electrum+ MAIN_SCRIPT,
|
||||
electrum+'electrum/gui/qt/main_window.py',
|
||||
electrum+'electrum/gui/text.py',
|
||||
electrum+'electrum/util.py',
|
||||
electrum+'electrum/wallet.py',
|
||||
electrum+'electrum/simple_config.py',
|
||||
electrum+'electrum/bitcoin.py',
|
||||
electrum+'electrum/dnssec.py',
|
||||
electrum+'electrum/commands.py',
|
||||
electrum+'electrum/plugins/cosigner_pool/qt.py',
|
||||
electrum+'electrum/plugins/email_requests/qt.py',
|
||||
electrum+'electrum/plugins/trezor/client.py',
|
||||
electrum+'electrum/plugins/trezor/qt.py',
|
||||
electrum+'electrum/plugins/safe_t/client.py',
|
||||
electrum+'electrum/plugins/safe_t/qt.py',
|
||||
electrum+'electrum/plugins/keepkey/qt.py',
|
||||
electrum+'electrum/plugins/ledger/qt.py',
|
||||
electrum+'electrum/plugins/coldcard/qt.py',
|
||||
],
|
||||
binaries=binaries,
|
||||
datas=datas,
|
||||
hiddenimports=hiddenimports,
|
||||
hookspath=[])
|
||||
|
||||
# http://stackoverflow.com/questions/19055089/pyinstaller-onefile-warning-pyconfig-h-when-importing-scipy-or-scipy-signal
|
||||
for d in a.datas:
|
||||
if 'pyconfig' in d[0]:
|
||||
a.datas.remove(d)
|
||||
break
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||||
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
name=PACKAGE,
|
||||
debug=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
icon=electrum+ICONS_FILE,
|
||||
console=False)
|
||||
|
||||
app = BUNDLE(exe,
|
||||
version = VERSION,
|
||||
name=PACKAGE + '.app',
|
||||
icon=electrum+ICONS_FILE,
|
||||
bundle_identifier=None,
|
||||
info_plist={
|
||||
'NSHighResolutionCapable': 'True',
|
||||
'NSSupportsAutomaticGraphicsSwitching': 'True'
|
||||
}
|
||||
)
|
88
contrib/build-osx/package.sh
Normal file
|
@ -0,0 +1,88 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
cdrkit_version=1.1.11
|
||||
cdrkit_download_path=http://distro.ibiblio.org/fatdog/source/600/c
|
||||
cdrkit_file_name=cdrkit-${cdrkit_version}.tar.bz2
|
||||
cdrkit_sha256_hash=b50d64c214a65b1a79afe3a964c691931a4233e2ba605d793eb85d0ac3652564
|
||||
cdrkit_patches=cdrkit-deterministic.patch
|
||||
genisoimage=genisoimage-$cdrkit_version
|
||||
|
||||
libdmg_url=https://github.com/theuni/libdmg-hfsplus
|
||||
|
||||
|
||||
export LD_PRELOAD=$(locate libfaketime.so.1)
|
||||
export FAKETIME="2000-01-22 00:00:00"
|
||||
export PATH=$PATH:~/bin
|
||||
|
||||
. $(dirname "$0")/base.sh
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 Electrum.app"
|
||||
exit -127
|
||||
fi
|
||||
|
||||
mkdir -p ~/bin
|
||||
|
||||
if ! which ${genisoimage} > /dev/null 2>&1; then
|
||||
mkdir -p /tmp/electrum-macos
|
||||
cd /tmp/electrum-macos
|
||||
info "Downloading cdrkit $cdrkit_version"
|
||||
wget -nc ${cdrkit_download_path}/${cdrkit_file_name}
|
||||
tar xvf ${cdrkit_file_name}
|
||||
|
||||
info "Patching genisoimage"
|
||||
cd cdrkit-${cdrkit_version}
|
||||
patch -p1 < ../cdrkit-deterministic.patch
|
||||
|
||||
info "Building genisoimage"
|
||||
cmake . -Wno-dev
|
||||
make genisoimage
|
||||
cp genisoimage/genisoimage ~/bin/${genisoimage}
|
||||
fi
|
||||
|
||||
if ! which dmg > /dev/null 2>&1; then
|
||||
mkdir -p /tmp/electrum-macos
|
||||
cd /tmp/electrum-macos
|
||||
info "Downloading libdmg"
|
||||
LD_PRELOAD= git clone ${libdmg_url}
|
||||
cd libdmg-hfsplus
|
||||
info "Building libdmg"
|
||||
cmake .
|
||||
make
|
||||
cp dmg/dmg ~/bin
|
||||
fi
|
||||
|
||||
${genisoimage} -version || fail "Unable to install genisoimage"
|
||||
dmg -|| fail "Unable to install libdmg"
|
||||
|
||||
plist=$1/Contents/Info.plist
|
||||
test -f "$plist" || fail "Info.plist not found"
|
||||
VERSION=$(grep -1 ShortVersionString $plist |tail -1|gawk 'match($0, /<string>(.*)<\/string>/, a) {print a[1]}')
|
||||
echo $VERSION
|
||||
|
||||
rm -rf /tmp/electrum-macos/image > /dev/null 2>&1
|
||||
mkdir /tmp/electrum-macos/image/
|
||||
cp -r $1 /tmp/electrum-macos/image/
|
||||
|
||||
build_dir=$(dirname "$1")
|
||||
test -n "$build_dir" -a -d "$build_dir" || exit
|
||||
cd $build_dir
|
||||
|
||||
${genisoimage} \
|
||||
-no-cache-inodes \
|
||||
-D \
|
||||
-l \
|
||||
-probe \
|
||||
-V "Electrum" \
|
||||
-no-pad \
|
||||
-r \
|
||||
-dir-mode 0755 \
|
||||
-apple \
|
||||
-o Electrum_uncompressed.dmg \
|
||||
/tmp/electrum-macos/image || fail "Unable to create uncompressed dmg"
|
||||
|
||||
dmg dmg Electrum_uncompressed.dmg electrum-$VERSION.dmg || fail "Unable to create compressed dmg"
|
||||
rm Electrum_uncompressed.dmg
|
||||
|
||||
echo "Done."
|
||||
md5sum electrum-$VERSION.dmg
|
40
contrib/build-wine/build-secp256k1.sh
Normal file
|
@ -0,0 +1,40 @@
|
|||
#!/bin/bash
|
||||
# heavily based on https://github.com/ofek/coincurve/blob/417e726f553460f88d7edfa5dc67bfda397c4e4a/.travis/build_windows_wheels.sh
|
||||
|
||||
set -e
|
||||
|
||||
build_dll() {
|
||||
#sudo apt-get install -y mingw-w64
|
||||
export SOURCE_DATE_EPOCH=1530212462
|
||||
./autogen.sh
|
||||
echo "LDFLAGS = -no-undefined" >> Makefile.am
|
||||
LDFLAGS="-Wl,--no-insert-timestamp" ./configure \
|
||||
--host=$1 \
|
||||
--enable-module-recovery \
|
||||
--enable-experimental \
|
||||
--enable-module-ecdh \
|
||||
--disable-jni
|
||||
make
|
||||
${1}-strip .libs/libsecp256k1-0.dll
|
||||
}
|
||||
|
||||
|
||||
cd /tmp/electrum-build
|
||||
|
||||
if [ ! -d secp256k1 ]; then
|
||||
git clone https://github.com/bitcoin-core/secp256k1.git
|
||||
cd secp256k1;
|
||||
else
|
||||
cd secp256k1
|
||||
git pull
|
||||
fi
|
||||
|
||||
git reset --hard 452d8e4d2a2f9f1b5be6b02e18f1ba102e5ca0b4
|
||||
git clean -f -x -q
|
||||
|
||||
build_dll i686-w64-mingw32 # 64-bit would be: x86_64-w64-mingw32
|
||||
mv .libs/libsecp256k1-0.dll libsecp256k1.dll
|
||||
|
||||
find -exec touch -d '2000-11-11T11:11:11+00:00' {} +
|
||||
|
||||
echo "building libsecp256k1 finished"
|
|
@ -118,7 +118,7 @@ exe_standalone = EXE(
|
|||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
name=os.path.join('build\\pyi.win32\\electrum', cmdline_name + ".exe"),
|
||||
name=os.path.join('build\\pyi.win32\\electrum-lbry', cmdline_name + ".exe"),
|
||||
debug=False,
|
||||
strip=None,
|
||||
upx=False,
|
||||
|
@ -131,7 +131,7 @@ exe_portable = EXE(
|
|||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas + [ ('is_portable', 'README.md', 'DATA' ) ],
|
||||
name=os.path.join('build\\pyi.win32\\electrum', cmdline_name + "-portable.exe"),
|
||||
name=os.path.join('build\\pyi.win32\\electrum-lbry', cmdline_name + "-portable.exe"),
|
||||
debug=False,
|
||||
strip=None,
|
||||
upx=False,
|
||||
|
@ -145,7 +145,7 @@ exe_dependent = EXE(
|
|||
pyz,
|
||||
a.scripts,
|
||||
exclude_binaries=True,
|
||||
name=os.path.join('build\\pyi.win32\\electrum', cmdline_name),
|
||||
name=os.path.join('build\\pyi.win32\\electrum-lbry', cmdline_name),
|
||||
debug=False,
|
||||
strip=None,
|
||||
upx=False,
|
||||
|
|
34
contrib/build-wine/docker/Dockerfile
Normal file
|
@ -0,0 +1,34 @@
|
|||
FROM ubuntu:18.04@sha256:5f4bdc3467537cbbe563e80db2c3ec95d548a9145d64453b06939c4592d67b6d
|
||||
|
||||
ENV LC_ALL=C.UTF-8 LANG=C.UTF-8
|
||||
|
||||
RUN dpkg --add-architecture i386 && \
|
||||
apt-get update -q && \
|
||||
apt-get install -qy \
|
||||
wget=1.19.4-1ubuntu2.1 \
|
||||
gnupg2=2.2.4-1ubuntu1.1 \
|
||||
dirmngr=2.2.4-1ubuntu1.1 \
|
||||
python3-software-properties=0.96.24.32.1 \
|
||||
software-properties-common=0.96.24.32.1 \
|
||||
&& \
|
||||
wget -nc https://dl.winehq.org/wine-builds/Release.key && \
|
||||
apt-key add Release.key && \
|
||||
apt-add-repository https://dl.winehq.org/wine-builds/ubuntu/ && \
|
||||
apt-get update -q && \
|
||||
apt-get install -qy \
|
||||
wine-stable-amd64:amd64=3.0.1~bionic \
|
||||
wine-stable-i386:i386=3.0.1~bionic \
|
||||
wine-stable:amd64=3.0.1~bionic \
|
||||
winehq-stable:amd64=3.0.1~bionic \
|
||||
git \
|
||||
p7zip-full=16.02+dfsg-6 \
|
||||
make=4.1-9.1ubuntu1 \
|
||||
mingw-w64=5.0.3-1 \
|
||||
autotools-dev=20180224.1 \
|
||||
autoconf=2.69-11 \
|
||||
libtool=2.4.6-2 \
|
||||
gettext=0.19.8.1-6 \
|
||||
&& \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
apt-get autoremove -y && \
|
||||
apt-get clean
|
103
contrib/build-wine/docker/README.md
Normal file
|
@ -0,0 +1,103 @@
|
|||
Deterministic Windows binaries with Docker
|
||||
==========================================
|
||||
|
||||
Produced binaries are deterministic, so you should be able to generate
|
||||
binaries that match the official releases.
|
||||
|
||||
This assumes an Ubuntu host, but it should not be too hard to adapt to another
|
||||
similar system. The docker commands should be executed in the project's root
|
||||
folder.
|
||||
|
||||
1. Install Docker
|
||||
|
||||
```
|
||||
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
||||
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get install -y docker-ce
|
||||
```
|
||||
|
||||
2. Build image
|
||||
|
||||
```
|
||||
$ sudo docker build --no-cache -t electrum-wine-builder-img contrib/build-wine/docker
|
||||
```
|
||||
|
||||
Note: see [this](https://stackoverflow.com/a/40516974/7499128) if having dns problems
|
||||
|
||||
3. Build Windows binaries
|
||||
|
||||
It's recommended to build from a fresh clone
|
||||
(but you can skip this if reproducibility is not necessary).
|
||||
|
||||
```
|
||||
$ FRESH_CLONE=contrib/build-wine/fresh_clone && \
|
||||
rm -rf $FRESH_CLONE && \
|
||||
mkdir -p $FRESH_CLONE && \
|
||||
cd $FRESH_CLONE && \
|
||||
git clone https://github.com/spesmilo/electrum.git && \
|
||||
cd electrum
|
||||
```
|
||||
|
||||
And then build from this directory:
|
||||
```
|
||||
$ git checkout $REV
|
||||
$ sudo docker run \
|
||||
--name electrum-wine-builder-cont \
|
||||
-v $PWD:/opt/wine64/drive_c/electrum \
|
||||
--rm \
|
||||
--workdir /opt/wine64/drive_c/electrum/contrib/build-wine \
|
||||
electrum-wine-builder-img \
|
||||
./build.sh
|
||||
```
|
||||
4. The generated binaries are in `./contrib/build-wine/dist`.
|
||||
|
||||
|
||||
|
||||
Note: the `setup` binary (NSIS installer) is not deterministic yet.
|
||||
|
||||
|
||||
Code Signing
|
||||
============
|
||||
|
||||
Electrum Windows builds are signed with a Microsoft Authenticode™ code signing
|
||||
certificate in addition to the GPG-based signatures.
|
||||
|
||||
The advantage of using Authenticode is that Electrum users won't receive a
|
||||
Windows SmartScreen warning when starting it.
|
||||
|
||||
The release signing procedure involves a signer (the holder of the
|
||||
certificate/key) and one or multiple trusted verifiers:
|
||||
|
||||
|
||||
| Signer | Verifier |
|
||||
|-----------------------------------------------------------|-----------------------------------|
|
||||
| Build .exe files using `build.sh` | |
|
||||
| Sign .exe with `./sign.sh` | |
|
||||
| Upload signed files to download server | |
|
||||
| | Build .exe files using `build.sh` |
|
||||
| | Compare files using `unsign.sh` |
|
||||
| | Sign .exe file using `gpg -b` |
|
||||
|
||||
| Signer and verifiers: |
|
||||
|-----------------------------------------------------------------------------------------------|
|
||||
| Upload signatures to 'electrum-signatures' repo, as `$version/$filename.$builder.asc` |
|
||||
|
||||
|
||||
|
||||
Verify Integrity of signed binary
|
||||
=================================
|
||||
|
||||
Every user can verify that the official binary was created from the source code in this
|
||||
repository. To do so, the Authenticode signature needs to be stripped since the signature
|
||||
is not reproducible.
|
||||
|
||||
This procedure removes the differences between the signed and unsigned binary:
|
||||
|
||||
1. Remove the signature from the signed binary using osslsigncode or signtool.
|
||||
2. Set the COFF image checksum for the signed binary to 0x0. This is necessary
|
||||
because pyinstaller doesn't generate a checksum.
|
||||
3. Append null bytes to the _unsigned_ binary until the byte count is a multiple
|
||||
of 8.
|
||||
|
||||
The script `unsign.sh` performs these steps.
|
|
@ -2,11 +2,11 @@
|
|||
;Include Modern UI
|
||||
!include "TextFunc.nsh" ;Needed for the $GetSize function. I know, doesn't sound logical, it isn't.
|
||||
!include "MUI2.nsh"
|
||||
|
||||
|
||||
;--------------------------------
|
||||
;Variables
|
||||
|
||||
!define PRODUCT_NAME "Electrum"
|
||||
!define PRODUCT_NAME "LBRY_Wallet"
|
||||
!define PRODUCT_WEB_SITE "https://github.com/spesmilo/electrum"
|
||||
!define PRODUCT_PUBLISHER "Electrum Technologies GmbH"
|
||||
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
|
||||
|
@ -16,7 +16,7 @@
|
|||
|
||||
;Name and file
|
||||
Name "${PRODUCT_NAME}"
|
||||
OutFile "dist/electrum-setup.exe"
|
||||
OutFile "dist/electrum-lbry-setup.exe"
|
||||
|
||||
;Default installation folder
|
||||
InstallDir "$PROGRAMFILES\${PRODUCT_NAME}"
|
||||
|
@ -29,31 +29,31 @@
|
|||
|
||||
;Specifies whether or not the installer will perform a CRC on itself before allowing an install
|
||||
CRCCheck on
|
||||
|
||||
|
||||
;Sets whether or not the details of the install are shown. Can be 'hide' (the default) to hide the details by default, allowing the user to view them, or 'show' to show them by default, or 'nevershow', to prevent the user from ever seeing them.
|
||||
ShowInstDetails show
|
||||
|
||||
|
||||
;Sets whether or not the details of the uninstall are shown. Can be 'hide' (the default) to hide the details by default, allowing the user to view them, or 'show' to show them by default, or 'nevershow', to prevent the user from ever seeing them.
|
||||
ShowUninstDetails show
|
||||
|
||||
|
||||
;Sets the colors to use for the install info screen (the default is 00FF00 000000. Use the form RRGGBB (in hexadecimal, as in HTML, only minus the leading '#', since # can be used for comments). Note that if "/windows" is specified as the only parameter, the default windows colors will be used.
|
||||
InstallColors /windows
|
||||
|
||||
|
||||
;This command sets the compression algorithm used to compress files/data in the installer. (http://nsis.sourceforge.net/Reference/SetCompressor)
|
||||
SetCompressor /SOLID lzma
|
||||
|
||||
|
||||
;Sets the dictionary size in megabytes (MB) used by the LZMA compressor (default is 8 MB).
|
||||
SetCompressorDictSize 64
|
||||
|
||||
|
||||
;Sets the text that is shown (by default it is 'Nullsoft Install System vX.XX') in the bottom of the install window. Setting this to an empty string ("") uses the default; to set the string to blank, use " " (a space).
|
||||
BrandingText "${PRODUCT_NAME} Installer v${PRODUCT_VERSION}"
|
||||
|
||||
BrandingText "${PRODUCT_NAME} Installer v${PRODUCT_VERSION}"
|
||||
|
||||
;Sets what the titlebars of the installer will display. By default, it is 'Name Setup', where Name is specified with the Name command. You can, however, override it with 'MyApp Installer' or whatever. If you specify an empty string (""), the default will be used (you can however specify " " to achieve a blank string)
|
||||
Caption "${PRODUCT_NAME}"
|
||||
|
||||
;Adds the Product Version on top of the Version Tab in the Properties of the file.
|
||||
VIProductVersion 1.0.0.0
|
||||
|
||||
|
||||
;VIAddVersionKey - Adds a field in the Version Tab of the File Properties. This can either be a field provided by the system or a user defined field.
|
||||
VIAddVersionKey ProductName "${PRODUCT_NAME} Installer"
|
||||
VIAddVersionKey Comments "The installer for ${PRODUCT_NAME}"
|
||||
|
@ -63,7 +63,7 @@
|
|||
VIAddVersionKey FileVersion ${PRODUCT_VERSION}
|
||||
VIAddVersionKey ProductVersion ${PRODUCT_VERSION}
|
||||
VIAddVersionKey InternalName "${PRODUCT_NAME} Installer"
|
||||
VIAddVersionKey LegalTrademarks "${PRODUCT_NAME} is a trademark of ${PRODUCT_PUBLISHER}"
|
||||
VIAddVersionKey LegalTrademarks "${PRODUCT_NAME} is a trademark of ${PRODUCT_PUBLISHER}"
|
||||
VIAddVersionKey OriginalFilename "${PRODUCT_NAME}.exe"
|
||||
|
||||
;--------------------------------
|
||||
|
@ -71,9 +71,9 @@
|
|||
|
||||
!define MUI_ABORTWARNING
|
||||
!define MUI_ABORTWARNING_TEXT "Are you sure you wish to abort the installation of ${PRODUCT_NAME}?"
|
||||
|
||||
|
||||
!define MUI_ICON "c:\electrum\electrum\gui\icons\electrum.ico"
|
||||
|
||||
|
||||
;--------------------------------
|
||||
;Pages
|
||||
|
||||
|
@ -108,7 +108,7 @@ Section
|
|||
RMDir /r "$INSTDIR\*.*"
|
||||
Delete "$DESKTOP\${PRODUCT_NAME}.lnk"
|
||||
Delete "$SMPROGRAMS\${PRODUCT_NAME}\*.*"
|
||||
|
||||
|
||||
;Files to pack into the installer
|
||||
File /r "dist\electrum\*.*"
|
||||
File "c:\electrum\electrum\gui\icons\electrum.ico"
|
||||
|
@ -122,21 +122,23 @@ Section
|
|||
|
||||
;Create desktop shortcut
|
||||
DetailPrint "Creating desktop shortcut..."
|
||||
CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" ""
|
||||
CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-lbry-${PRODUCT_VERSION}.exe" ""
|
||||
|
||||
;Create start-menu items
|
||||
DetailPrint "Creating start-menu items..."
|
||||
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
|
||||
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0
|
||||
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" "" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" 0
|
||||
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME} Testnet.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" "--testnet" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" 0
|
||||
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" "" "$INSTDIR\electrum-lbry-${PRODUCT_VERSION}.exe" 0
|
||||
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME} Testnet.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" "--testnet" "$INSTDIR\electrum-lbry-${PRODUCT_VERSION}.exe" 0
|
||||
|
||||
|
||||
|
||||
|
||||
;Links bitcoin: URI's to Electrum
|
||||
WriteRegStr HKCU "Software\Classes\bitcoin" "" "URL:bitcoin Protocol"
|
||||
WriteRegStr HKCU "Software\Classes\bitcoin" "URL Protocol" ""
|
||||
WriteRegStr HKCU "Software\Classes\bitcoin" "DefaultIcon" "$\"$INSTDIR\electrum.ico, 0$\""
|
||||
WriteRegStr HKCU "Software\Classes\bitcoin\shell\open\command" "" "$\"$INSTDIR\electrum-${PRODUCT_VERSION}.exe$\" $\"%1$\""
|
||||
WriteRegStr HKCU "Software\Classes\bitcoin\shell\open\command" "" "$\"$INSTDIR\electrum-lbry-${PRODUCT_VERSION}.exe$\" $\"%1$\""
|
||||
|
||||
;Adds an uninstaller possibility to Windows Uninstall or change a program section
|
||||
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
|
||||
|
@ -166,8 +168,8 @@ Section "Uninstall"
|
|||
Delete "$DESKTOP\${PRODUCT_NAME}.lnk"
|
||||
Delete "$SMPROGRAMS\${PRODUCT_NAME}\*.*"
|
||||
RMDir "$SMPROGRAMS\${PRODUCT_NAME}"
|
||||
|
||||
DeleteRegKey HKCU "Software\Classes\bitcoin"
|
||||
|
||||
DeleteRegKey HKCU "Software\Classes\lbc"
|
||||
DeleteRegKey HKCU "Software\${PRODUCT_NAME}"
|
||||
DeleteRegKey HKCU "${PRODUCT_UNINST_KEY}"
|
||||
SectionEnd
|
||||
|
|
82
contrib/make_locale
Normal file
|
@ -0,0 +1,82 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
import subprocess
|
||||
import io
|
||||
import zipfile
|
||||
import requests
|
||||
|
||||
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
||||
os.chdir('..')
|
||||
|
||||
cmd = "find electrum -type f -name '*.py' -o -name '*.kv'"
|
||||
|
||||
files = subprocess.check_output(cmd, shell=True)
|
||||
|
||||
with open("app.fil", "wb") as f:
|
||||
f.write(files)
|
||||
|
||||
print("Found {} files to translate".format(len(files.splitlines())))
|
||||
|
||||
# Generate fresh translation template
|
||||
if not os.path.exists('electrum/locale'):
|
||||
os.mkdir('electrum/locale')
|
||||
cmd = 'xgettext -s --from-code UTF-8 --language Python --no-wrap -f app.fil --output=electrum/locale/messages.pot'
|
||||
print('Generate template')
|
||||
os.system(cmd)
|
||||
|
||||
os.chdir('electrum')
|
||||
|
||||
crowdin_identifier = 'electrum'
|
||||
crowdin_file_name = 'files[electrum-client/messages.pot]'
|
||||
locale_file_name = 'locale/messages.pot'
|
||||
crowdin_api_key = None
|
||||
|
||||
filename = os.path.expanduser('~/.crowdin_api_key')
|
||||
if os.path.exists(filename):
|
||||
with open(filename) as f:
|
||||
crowdin_api_key = f.read().strip()
|
||||
|
||||
if "crowdin_api_key" in os.environ:
|
||||
crowdin_api_key = os.environ["crowdin_api_key"]
|
||||
|
||||
if crowdin_api_key:
|
||||
# Push to Crowdin
|
||||
print('Push to Crowdin')
|
||||
url = ('https://api.crowdin.com/api/project/' + crowdin_identifier + '/update-file?key=' + crowdin_api_key)
|
||||
with open(locale_file_name, 'rb') as f:
|
||||
files = {crowdin_file_name: f}
|
||||
response = requests.request('POST', url, files=files)
|
||||
print("", "update-file:", "-"*20, response.text, "-"*20, sep="\n")
|
||||
# Build translations
|
||||
print('Build translations')
|
||||
response = requests.request('GET', 'https://api.crowdin.com/api/project/' + crowdin_identifier + '/export?key=' + crowdin_api_key)
|
||||
print("", "export:", "-" * 20, response.text, "-" * 20, sep="\n")
|
||||
|
||||
# Download & unzip
|
||||
print('Download translations')
|
||||
s = requests.request('GET', 'https://crowdin.com/backend/download/project/' + crowdin_identifier + '.zip').content
|
||||
zfobj = zipfile.ZipFile(io.BytesIO(s))
|
||||
|
||||
print('Unzip translations')
|
||||
for name in zfobj.namelist():
|
||||
if not name.startswith('electrum-client/locale'):
|
||||
continue
|
||||
if name.endswith('/'):
|
||||
if not os.path.exists(name[16:]):
|
||||
os.mkdir(name[16:])
|
||||
else:
|
||||
with open(name[16:], 'wb') as output:
|
||||
output.write(zfobj.read(name))
|
||||
|
||||
# Convert .po to .mo
|
||||
print('Installing')
|
||||
for lang in os.listdir('locale'):
|
||||
if lang.startswith('messages'):
|
||||
continue
|
||||
# Check LC_MESSAGES folder
|
||||
mo_dir = 'locale/%s/LC_MESSAGES' % lang
|
||||
if not os.path.exists(mo_dir):
|
||||
os.mkdir(mo_dir)
|
||||
cmd = 'msgfmt --output-file="%s/electrum.mo" "locale/%s/electrum.po"' % (mo_dir,lang)
|
||||
print('Installing', lang)
|
||||
os.system(cmd)
|
BIN
electrum.icns
Normal file
|
@ -139,7 +139,7 @@ class BaseWizard(Logger):
|
|||
('standard', _("Standard wallet")),
|
||||
('2fa', _("Wallet with two-factor authentication")),
|
||||
('multisig', _("Multi-signature wallet")),
|
||||
('imported', _("Import Bitcoin addresses or private keys")),
|
||||
('imported', _("Import LBRY Credits addresses or private keys")),
|
||||
]
|
||||
choices = [pair for pair in wallet_kinds if pair[0] in wallet_types]
|
||||
self.choice_dialog(title=title, message=message, choices=choices, run_next=self.on_wallet_type)
|
||||
|
@ -211,8 +211,8 @@ class BaseWizard(Logger):
|
|||
|
||||
def import_addresses_or_keys(self):
|
||||
v = lambda x: keystore.is_address_list(x) or keystore.is_private_key_list(x, raise_on_error=True)
|
||||
title = _("Import Bitcoin Addresses")
|
||||
message = _("Enter a list of Bitcoin addresses (this will create a watching-only wallet), or a list of private keys.")
|
||||
title = _("Import LBRY Credits Addresses")
|
||||
message = _("Enter a list of LBRY Credits addresses (this will create a watching-only wallet), or a list of private keys.")
|
||||
self.add_xpub_dialog(title=title, message=message, run_next=self.on_import,
|
||||
is_valid=v, allow_multi=True, show_wif_help=True)
|
||||
|
||||
|
@ -393,14 +393,13 @@ class BaseWizard(Logger):
|
|||
# There is no general standard for HD multisig.
|
||||
# For legacy, this is partially compatible with BIP45; assumes index=0
|
||||
# For segwit, a custom path is used, as there is no standard at all.
|
||||
default_choice_idx = 2
|
||||
default_choice_idx = 0
|
||||
choices = [
|
||||
('standard', 'legacy multisig (p2sh)', normalize_bip32_derivation("m/45'/0")),
|
||||
('p2wsh-p2sh', 'p2sh-segwit multisig (p2wsh-p2sh)', purpose48_derivation(0, xtype='p2wsh-p2sh')),
|
||||
('p2wsh', 'native segwit multisig (p2wsh)', purpose48_derivation(0, xtype='p2wsh')),
|
||||
|
||||
]
|
||||
else:
|
||||
default_choice_idx = 2
|
||||
default_choice_idx = 0
|
||||
choices = [
|
||||
('standard', 'legacy (p2pkh)', bip44_derivation(0, bip43_purpose=44)),
|
||||
('p2wpkh-p2sh', 'p2sh-segwit (p2wpkh-p2sh)', bip44_derivation(0, bip43_purpose=49)),
|
||||
|
@ -625,11 +624,11 @@ class BaseWizard(Logger):
|
|||
_("The type of addresses used by your wallet will depend on your seed."),
|
||||
_("Segwit wallets use bech32 addresses, defined in BIP173."),
|
||||
_("Please note that websites and other wallets may not support these addresses yet."),
|
||||
_("Thus, you might want to keep using a non-segwit wallet in order to be able to receive bitcoins during the transition period.")
|
||||
_("Thus, you might want to keep using a non-segwit wallet in order to be able to receive LBRY Credits during the transition period.")
|
||||
])
|
||||
if choices is None:
|
||||
choices = [
|
||||
('create_segwit_seed', _('Segwit')),
|
||||
|
||||
('create_standard_seed', _('Legacy')),
|
||||
]
|
||||
self.choice_dialog(title=title, message=message, choices=choices, run_next=self.run)
|
||||
|
|
|
@ -24,6 +24,9 @@ import os
|
|||
import threading
|
||||
from typing import Optional, Dict, Mapping, Sequence
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
|
||||
from . import util
|
||||
from .bitcoin import hash_encode, int_to_hex, rev_hex
|
||||
from .crypto import sha256d
|
||||
|
@ -35,9 +38,10 @@ from .logging import get_logger, Logger
|
|||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
HEADER_SIZE = 80 # bytes
|
||||
MAX_TARGET = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
|
||||
|
||||
HEADER_SIZE = 112 # bytes
|
||||
MAX_TARGET = 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||
GENESIS_BITS = 0x1f00ffff
|
||||
N_TARGET_TIMESPAN = 150
|
||||
|
||||
class MissingHeader(Exception):
|
||||
pass
|
||||
|
@ -49,6 +53,7 @@ def serialize_header(header_dict: dict) -> str:
|
|||
s = int_to_hex(header_dict['version'], 4) \
|
||||
+ rev_hex(header_dict['prev_block_hash']) \
|
||||
+ rev_hex(header_dict['merkle_root']) \
|
||||
+ rev_hex(header_dict['claim_trie_root']) \
|
||||
+ int_to_hex(int(header_dict['timestamp']), 4) \
|
||||
+ int_to_hex(int(header_dict['bits']), 4) \
|
||||
+ int_to_hex(int(header_dict['nonce']), 4)
|
||||
|
@ -64,9 +69,10 @@ def deserialize_header(s: bytes, height: int) -> dict:
|
|||
h['version'] = hex_to_int(s[0:4])
|
||||
h['prev_block_hash'] = hash_encode(s[4:36])
|
||||
h['merkle_root'] = hash_encode(s[36:68])
|
||||
h['timestamp'] = hex_to_int(s[68:72])
|
||||
h['bits'] = hex_to_int(s[72:76])
|
||||
h['nonce'] = hex_to_int(s[76:80])
|
||||
h['claim_trie_root'] = hash_encode(s[68:100])
|
||||
h['timestamp'] = hex_to_int(s[100:104])
|
||||
h['bits'] = hex_to_int(s[104:108])
|
||||
h['nonce'] = hex_to_int(s[108:112])
|
||||
h['block_height'] = height
|
||||
return h
|
||||
|
||||
|
@ -77,10 +83,35 @@ def hash_header(header: dict) -> str:
|
|||
header['prev_block_hash'] = '00'*32
|
||||
return hash_raw_header(serialize_header(header))
|
||||
|
||||
def pow_hash_header(header: dict) -> str:
|
||||
if header is None:
|
||||
return '0' * 64
|
||||
return hash_encode(PoWHash(bfh(serialize_header(header))))
|
||||
|
||||
def sha256(x):
|
||||
return hashlib.sha256(x).digest()
|
||||
|
||||
def sha512(x):
|
||||
return hashlib.sha512(x).digest()
|
||||
|
||||
def ripemd160(x):
|
||||
h = hashlib.new('ripemd160')
|
||||
h.update(x)
|
||||
return h.digest()
|
||||
|
||||
def Hash(x):
|
||||
return sha256(sha256(x))
|
||||
|
||||
def hash_raw_header(header: str) -> str:
|
||||
return hash_encode(sha256d(bfh(header)))
|
||||
|
||||
def PoWHash(x):
|
||||
|
||||
r = sha512(Hash(x))
|
||||
r1 = ripemd160(r[:len(r) // 2])
|
||||
r2 = ripemd160(r[len(r) // 2:])
|
||||
r3 = Hash(r1 + r2)
|
||||
return r3
|
||||
|
||||
# key: blockhash hex at forkpoint
|
||||
# the chain at some key is the best chain that includes the given hash
|
||||
|
@ -282,35 +313,37 @@ class Blockchain(Logger):
|
|||
self._size = os.path.getsize(p)//HEADER_SIZE if os.path.exists(p) else 0
|
||||
|
||||
@classmethod
|
||||
def verify_header(cls, header: dict, prev_hash: str, target: int, expected_header_hash: str=None) -> None:
|
||||
_hash = hash_header(header)
|
||||
if expected_header_hash and expected_header_hash != _hash:
|
||||
raise Exception("hash mismatches with expected: {} vs {}".format(expected_header_hash, _hash))
|
||||
def verify_header(self, header: dict, prev_hash: str, target: int, bits: int, expected_header_hash: str=None) -> None:
|
||||
_hash = pow_hash_header(header)
|
||||
if expected_header_hash:
|
||||
_hash2 = hash_header(header)
|
||||
if expected_header_hash != _hash2:
|
||||
raise Exception("hash mismatches with expected: {} vs {}".format(expected_header_hash, _hash2))
|
||||
if prev_hash != header.get('prev_block_hash'):
|
||||
raise Exception("prev hash mismatch: %s vs %s" % (prev_hash, header.get('prev_block_hash')))
|
||||
if constants.net.TESTNET:
|
||||
return
|
||||
bits = cls.target_to_bits(target)
|
||||
if bits != header.get('bits'):
|
||||
raise Exception("bits mismatch: %s vs %s" % (bits, header.get('bits')))
|
||||
block_hash_as_num = int.from_bytes(bfh(_hash), byteorder='big')
|
||||
if block_hash_as_num > target:
|
||||
raise Exception(f"insufficient proof of work: {block_hash_as_num} vs target {target}")
|
||||
|
||||
#if bits != header.get('bits'):
|
||||
# raise Exception("bits mismatch: %s vs %s" % (bits, header.get('bits')))
|
||||
#if int('0x' + _hash, 16) > target:
|
||||
# raise Exception("insufficient proof of work: %s vs target %s" % (int('0x' + _hash, 16), target))
|
||||
|
||||
def verify_chunk(self, index: int, data: bytes) -> None:
|
||||
num = len(data) // HEADER_SIZE
|
||||
start_height = index * 2016
|
||||
prev_hash = self.get_hash(start_height - 1)
|
||||
target = self.get_target(index-1)
|
||||
for i in range(num):
|
||||
height = start_height + i
|
||||
header = self.read_header(height - 1)
|
||||
#bits, target = self.get_target2(height - 1, header)
|
||||
try:
|
||||
expected_header_hash = self.get_hash(height)
|
||||
except MissingHeader:
|
||||
expected_header_hash = None
|
||||
raw_header = data[i*HEADER_SIZE : (i+1)*HEADER_SIZE]
|
||||
header = deserialize_header(raw_header, index*2016 + i)
|
||||
self.verify_header(header, prev_hash, target, expected_header_hash)
|
||||
self.verify_header(header, prev_hash, 0, 0, expected_header_hash)
|
||||
prev_hash = hash_header(header)
|
||||
|
||||
@with_lock
|
||||
|
@ -507,18 +540,73 @@ class Blockchain(Logger):
|
|||
bits = last.get('bits')
|
||||
target = self.bits_to_target(bits)
|
||||
nActualTimespan = last.get('timestamp') - first.get('timestamp')
|
||||
nTargetTimespan = 14 * 24 * 60 * 60
|
||||
nActualTimespan = max(nActualTimespan, nTargetTimespan // 4)
|
||||
nActualTimespan = min(nActualTimespan, nTargetTimespan * 4)
|
||||
new_target = min(MAX_TARGET, (target * nActualTimespan) // nTargetTimespan)
|
||||
# not any target can be represented in 32 bits:
|
||||
new_target = self.bits_to_target(self.target_to_bits(new_target))
|
||||
return new_target
|
||||
nTargetTimespan = 150
|
||||
nModulatedTimespan = nTargetTimespan - (nActualTimespan - nTargetTimespan) / 8
|
||||
nMinTimespan = nTargetTimespan - (nTargetTimespan / 8)
|
||||
nMaxTimespan = nTargetTimespan + (nTargetTimespan / 2)
|
||||
if nModulatedTimespan < nMinTimespan:
|
||||
nModulatedTimespan = nMinTimespan
|
||||
elif nModulatedTimespan > nMaxTimespan:
|
||||
nModulatedTimespan = nMaxTimespan
|
||||
|
||||
bnOld = ArithUint256.SetCompact(bits)
|
||||
bnNew = bnOld * nModulatedTimespan
|
||||
# this doesn't work if it is nTargetTimespan even though that
|
||||
# is what it looks like it should be based on reading the code
|
||||
# in lbry.cpp
|
||||
bnNew /= nModulatedTimespan
|
||||
if bnNew > MAX_TARGET:
|
||||
bnNew = ArithUint256(MAX_TARGET)
|
||||
return bnNew.compact(), bnNew._value
|
||||
|
||||
def get_target2(self, index, last, chain='main'):
|
||||
|
||||
if index == -1:
|
||||
return GENESIS_BITS, MAX_TARGET
|
||||
if index == 0:
|
||||
return GENESIS_BITS, MAX_TARGET
|
||||
first = self.read_header(index-1)
|
||||
assert last is not None, "Last shouldn't be none"
|
||||
# bits to target
|
||||
bits = last.get('bits')
|
||||
# print_error("Last bits: ", bits)
|
||||
self.check_bits(bits)
|
||||
|
||||
# new target
|
||||
nActualTimespan = last.get('timestamp') - first.get('timestamp')
|
||||
nTargetTimespan = N_TARGET_TIMESPAN
|
||||
nModulatedTimespan = nTargetTimespan - (nActualTimespan - nTargetTimespan) / 8
|
||||
nMinTimespan = nTargetTimespan - (nTargetTimespan / 8)
|
||||
nMaxTimespan = nTargetTimespan + (nTargetTimespan / 2)
|
||||
if nModulatedTimespan < nMinTimespan:
|
||||
nModulatedTimespan = nMinTimespan
|
||||
elif nModulatedTimespan > nMaxTimespan:
|
||||
nModulatedTimespan = nMaxTimespan
|
||||
|
||||
bnOld = ArithUint256.SetCompact(bits)
|
||||
bnNew = bnOld * nModulatedTimespan
|
||||
# this doesn't work if it is nTargetTimespan even though that
|
||||
# is what it looks like it should be based on reading the code
|
||||
# in lbry.cpp
|
||||
bnNew /= nModulatedTimespan
|
||||
if bnNew > MAX_TARGET:
|
||||
bnNew = ArithUint256(MAX_TARGET)
|
||||
return bnNew.compact, bnNew._value
|
||||
|
||||
def check_bits(self, bits):
|
||||
bitsN = (bits >> 24) & 0xff
|
||||
assert 0x03 <= bitsN <= 0x1f, \
|
||||
"First part of bits should be in [0x03, 0x1d], but it was {}".format(hex(bitsN))
|
||||
bitsBase = bits & 0xffffff
|
||||
assert 0x8000 <= bitsBase <= 0x7fffff, \
|
||||
"Second part of bits should be in [0x8000, 0x7fffff] but it was {}".format(bitsBase)
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def bits_to_target(cls, bits: int) -> int:
|
||||
bitsN = (bits >> 24) & 0xff
|
||||
if not (0x03 <= bitsN <= 0x1d):
|
||||
if not (0x03 <= bitsN <= 0x1f):
|
||||
raise Exception("First part of bits should be in [0x03, 0x1d]")
|
||||
bitsBase = bits & 0xffffff
|
||||
if not (0x8000 <= bitsBase <= 0x7fffff):
|
||||
|
@ -573,25 +661,33 @@ class Blockchain(Logger):
|
|||
def can_connect(self, header: dict, check_height: bool=True) -> bool:
|
||||
if header is None:
|
||||
return False
|
||||
|
||||
height = header['block_height']
|
||||
if check_height and self.height() != height - 1:
|
||||
print("cannot connect at height", height)
|
||||
return False
|
||||
if height == 0:
|
||||
return hash_header(header) == constants.net.GENESIS
|
||||
|
||||
try:
|
||||
prev_hash = self.get_hash(height - 1)
|
||||
except:
|
||||
return False
|
||||
|
||||
if prev_hash != header.get('prev_block_hash'):
|
||||
return False
|
||||
|
||||
try:
|
||||
target = self.get_target(height // 2016 - 1)
|
||||
bits, target = self.get_target2(height, header)
|
||||
except MissingHeader:
|
||||
return False
|
||||
|
||||
try:
|
||||
self.verify_header(header, prev_hash, target)
|
||||
self.verify_header(header, prev_hash, target, bits)
|
||||
except BaseException as e:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def connect_chunk(self, idx: int, hexdata: str) -> bool:
|
||||
|
@ -632,3 +728,83 @@ def can_connect(header: dict) -> Optional[Blockchain]:
|
|||
if b.can_connect(header):
|
||||
return b
|
||||
return None
|
||||
|
||||
class ArithUint256:
|
||||
# https://github.com/bitcoin/bitcoin/blob/master/src/arith_uint256.cpp
|
||||
|
||||
__slots__ = '_value', '_compact'
|
||||
|
||||
def __init__(self, value: int) -> None:
|
||||
self._value = value
|
||||
self._compact: Optional[int] = None
|
||||
|
||||
@classmethod
|
||||
def SetCompact(cls, nCompact):
|
||||
return (ArithUint256.from_compact(nCompact))
|
||||
|
||||
@classmethod
|
||||
def from_compact(cls, compact) -> 'ArithUint256':
|
||||
size = compact >> 24
|
||||
word = compact & 0x007fffff
|
||||
if size <= 3:
|
||||
return cls(word >> 8 * (3 - size))
|
||||
else:
|
||||
return cls(word << 8 * (size - 3))
|
||||
|
||||
@property
|
||||
def value(self) -> int:
|
||||
return self._value
|
||||
|
||||
@property
|
||||
def compact(self) -> int:
|
||||
if self._compact is None:
|
||||
self._compact = self._calculate_compact()
|
||||
return self._compact
|
||||
|
||||
@property
|
||||
def negative(self) -> int:
|
||||
return self._calculate_compact(negative=True)
|
||||
|
||||
@property
|
||||
def bits(self) -> int:
|
||||
""" Returns the position of the highest bit set plus one. """
|
||||
bits = bin(self._value)[2:]
|
||||
for i, d in enumerate(bits):
|
||||
if d:
|
||||
return (len(bits) - i) + 1
|
||||
return 0
|
||||
|
||||
@property
|
||||
def low64(self) -> int:
|
||||
return self._value & 0xffffffffffffffff
|
||||
|
||||
def _calculate_compact(self, negative=False) -> int:
|
||||
size = (self.bits + 7) // 8
|
||||
if size <= 3:
|
||||
compact = self.low64 << 8 * (3 - size)
|
||||
else:
|
||||
compact = ArithUint256(self._value >> 8 * (size - 3)).low64
|
||||
# The 0x00800000 bit denotes the sign.
|
||||
# Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
|
||||
if compact & 0x00800000:
|
||||
compact >>= 8
|
||||
size += 1
|
||||
assert (compact & ~0x007fffff) == 0
|
||||
assert size < 256
|
||||
compact |= size << 24
|
||||
if negative and compact & 0x007fffff:
|
||||
compact |= 0x00800000
|
||||
return compact
|
||||
|
||||
def __mul__(self, x):
|
||||
# Take the mod because we are limited to an unsigned 256 bit number
|
||||
return ArithUint256((self._value * x) % 2 ** 256)
|
||||
|
||||
def __truediv__(self, x):
|
||||
return ArithUint256(int(self._value / x))
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._value > other
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._value < other
|
||||
|
|
|
@ -239,7 +239,7 @@ class Commands:
|
|||
@command('')
|
||||
async def restore(self, text, passphrase=None, password=None, encrypt_file=True, wallet_path=None):
|
||||
"""Restore a wallet from text. Text can be a seed phrase, a master
|
||||
public key, a master private key, a list of bitcoin addresses
|
||||
public key, a master private key, a list of LBRY Credits addresses
|
||||
or bitcoin private keys.
|
||||
If you want to be prompted for an argument, type '?' or ':' (concealed)
|
||||
"""
|
||||
|
@ -667,7 +667,7 @@ class Commands:
|
|||
|
||||
@command('w')
|
||||
async def setlabel(self, key, label, wallet: Abstract_Wallet = None):
|
||||
"""Assign a label to an item. Item may be a bitcoin address or a
|
||||
"""Assign a label to an item. Item may be a LBRY Credits address or a
|
||||
transaction ID"""
|
||||
wallet.set_label(key, label)
|
||||
|
||||
|
@ -1012,8 +1012,8 @@ def eval_bool(x: str) -> bool:
|
|||
|
||||
param_descriptions = {
|
||||
'privkey': 'Private key. Type \'?\' to get a prompt.',
|
||||
'destination': 'Bitcoin address, contact or alias',
|
||||
'address': 'Bitcoin address',
|
||||
'destination': 'LBRY Credits address, contact or alias',
|
||||
'address': 'LBRY Credits address',
|
||||
'seed': 'Seed phrase',
|
||||
'txid': 'Transaction ID',
|
||||
'pos': 'Position',
|
||||
|
@ -1023,8 +1023,8 @@ param_descriptions = {
|
|||
'pubkey': 'Public key',
|
||||
'message': 'Clear text message. Use quotes if it contains spaces.',
|
||||
'encrypted': 'Encrypted message',
|
||||
'amount': 'Amount to be sent (in BTC). Type \'!\' to send the maximum available.',
|
||||
'requested_amount': 'Requested amount (in BTC).',
|
||||
'amount': 'Amount to be sent (in LBC). Type \'!\' to send the maximum available.',
|
||||
'requested_amount': 'Requested amount (in LBC).',
|
||||
'outputs': 'list of ["address", amount]',
|
||||
'redeem_script': 'redeem script (hexadecimal)',
|
||||
}
|
||||
|
@ -1042,7 +1042,7 @@ command_options = {
|
|||
'labels': ("-l", "Show the labels of listed addresses"),
|
||||
'nocheck': (None, "Do not verify aliases"),
|
||||
'imax': (None, "Maximum number of inputs"),
|
||||
'fee': ("-f", "Transaction fee (absolute, in BTC)"),
|
||||
'fee': ("-f", "Transaction fee (absolute, in LBC)"),
|
||||
'feerate': (None, "Transaction fee rate (in sat/byte)"),
|
||||
'from_addr': ("-F", "Source address (must be a wallet address; use sweep to spend from non-wallet address)."),
|
||||
'from_coins': (None, "Source coins (must be in wallet; use sweep to spend from non-wallet address)."),
|
||||
|
@ -1062,7 +1062,7 @@ command_options = {
|
|||
'timeout': (None, "Timeout in seconds"),
|
||||
'force': (None, "Create new address beyond gap limit, if no more addresses are available."),
|
||||
'pending': (None, "Show only pending requests."),
|
||||
'push_amount': (None, 'Push initial amount (in BTC)'),
|
||||
'push_amount': (None, 'Push initial amount (in LBC)'),
|
||||
'expired': (None, "Show only expired requests."),
|
||||
'paid': (None, "Show only paid requests."),
|
||||
'show_addresses': (None, "Show input and output addresses"),
|
||||
|
@ -1106,10 +1106,10 @@ config_variables = {
|
|||
'addrequest': {
|
||||
'ssl_privkey': 'Path to your SSL private key, needed to sign the request.',
|
||||
'ssl_chain': 'Chain of SSL certificates, needed for signed requests. Put your certificate at the top and the root CA at the end',
|
||||
'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of bitcoin: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"',
|
||||
'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of lbry credits: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"',
|
||||
},
|
||||
'listrequests':{
|
||||
'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of bitcoin: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"',
|
||||
'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of lbry credits: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"',
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1194,7 +1194,7 @@ def get_parser():
|
|||
subparsers = parser.add_subparsers(dest='cmd', metavar='<command>')
|
||||
# gui
|
||||
parser_gui = subparsers.add_parser('gui', description="Run Electrum's Graphical User Interface.", help="Run GUI (default)")
|
||||
parser_gui.add_argument("url", nargs='?', default=None, help="bitcoin URI (or bip70 file)")
|
||||
parser_gui.add_argument("url", nargs='?', default=None, help="lbry credits URI (or bip70 file)")
|
||||
parser_gui.add_argument("-g", "--gui", dest="gui", help="select graphical user interface", choices=['qt', 'kivy', 'text', 'stdio'])
|
||||
parser_gui.add_argument("-m", action="store_true", dest="hide_gui", default=False, help="hide GUI on startup")
|
||||
parser_gui.add_argument("-L", "--lang", dest="language", default=None, help="default language used in GUI")
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
import os
|
||||
import json
|
||||
|
||||
BLOCKS_PER_CHUNK = 96
|
||||
from .util import inv_dict
|
||||
from . import bitcoin
|
||||
|
||||
|
@ -60,14 +61,14 @@ class AbstractNet:
|
|||
class BitcoinMainnet(AbstractNet):
|
||||
|
||||
TESTNET = False
|
||||
WIF_PREFIX = 0x80
|
||||
ADDRTYPE_P2PKH = 0
|
||||
ADDRTYPE_P2SH = 5
|
||||
SEGWIT_HRP = "bc"
|
||||
GENESIS = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
|
||||
WIF_PREFIX = 0x1c
|
||||
ADDRTYPE_P2PKH = 0x55
|
||||
ADDRTYPE_P2SH = 0x7A
|
||||
SEGWIT_HRP = "lbc"
|
||||
GENESIS = "9c89283ba0f3227f6c03b70216b9f665f0118d5e0fa729cedf4fb34d6a34f463"
|
||||
DEFAULT_PORTS = {'t': '50001', 's': '50002'}
|
||||
DEFAULT_SERVERS = read_json('servers.json', {})
|
||||
CHECKPOINTS = read_json('checkpoints.json', [])
|
||||
CHECKPOINTS = read_json('bullshit.json', [])
|
||||
BLOCK_HEIGHT_FIRST_LIGHTNING_CHANNELS = 497000
|
||||
|
||||
XPRV_HEADERS = {
|
||||
|
@ -86,7 +87,7 @@ class BitcoinMainnet(AbstractNet):
|
|||
'p2wsh': 0x02aa7ed3, # Zpub
|
||||
}
|
||||
XPUB_HEADERS_INV = inv_dict(XPUB_HEADERS)
|
||||
BIP44_COIN_TYPE = 0
|
||||
BIP44_COIN_TYPE = 140
|
||||
LN_REALM_BYTE = 0
|
||||
LN_DNS_SEEDS = [
|
||||
'nodes.lightning.directory.',
|
||||
|
@ -100,7 +101,7 @@ class BitcoinTestnet(AbstractNet):
|
|||
WIF_PREFIX = 0xef
|
||||
ADDRTYPE_P2PKH = 111
|
||||
ADDRTYPE_P2SH = 196
|
||||
SEGWIT_HRP = "tb"
|
||||
SEGWIT_HRP = "tlbc"
|
||||
GENESIS = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
|
||||
DEFAULT_PORTS = {'t': '51001', 's': '51002'}
|
||||
DEFAULT_SERVERS = read_json('servers_testnet.json', {})
|
||||
|
@ -132,7 +133,7 @@ class BitcoinTestnet(AbstractNet):
|
|||
|
||||
class BitcoinRegtest(BitcoinTestnet):
|
||||
|
||||
SEGWIT_HRP = "bcrt"
|
||||
SEGWIT_HRP = "blbc"
|
||||
GENESIS = "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
|
||||
DEFAULT_SERVERS = read_json('servers_regtest.json', {})
|
||||
CHECKPOINTS = []
|
||||
|
@ -144,7 +145,7 @@ class BitcoinSimnet(BitcoinTestnet):
|
|||
WIF_PREFIX = 0x64
|
||||
ADDRTYPE_P2PKH = 0x3f
|
||||
ADDRTYPE_P2SH = 0x7b
|
||||
SEGWIT_HRP = "sb"
|
||||
SEGWIT_HRP = "slbc"
|
||||
GENESIS = "683e86bd5c6d110d91b94b97137ba6bfe02dbbdb8e3dff722a669b5d69d77af6"
|
||||
DEFAULT_SERVERS = read_json('servers_regtest.json', {})
|
||||
CHECKPOINTS = []
|
||||
|
|
|
@ -93,7 +93,7 @@ class Contacts(dict, Logger):
|
|||
'type': 'openalias',
|
||||
'validated': validated
|
||||
}
|
||||
raise Exception("Invalid Bitcoin address or alias", k)
|
||||
raise Exception("Invalid LBRY Credits address or alias", k)
|
||||
|
||||
def resolve_openalias(self, url):
|
||||
# support email-style addresses, per the OA standard
|
||||
|
@ -103,7 +103,7 @@ class Contacts(dict, Logger):
|
|||
except DNSException as e:
|
||||
self.logger.info(f'Error resolving openalias: {repr(e)}')
|
||||
return None
|
||||
prefix = 'btc'
|
||||
prefix = 'lbc'
|
||||
for record in records:
|
||||
string = to_string(record.strings[0], 'utf8')
|
||||
if string.startswith('oa1:' + prefix):
|
||||
|
@ -121,7 +121,7 @@ class Contacts(dict, Logger):
|
|||
return regex.search(haystack).groups()[0]
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
|
||||
def _validate(self, data):
|
||||
for k, v in list(data.items()):
|
||||
if k == 'contacts':
|
||||
|
@ -133,4 +133,3 @@ class Contacts(dict, Logger):
|
|||
if _type != 'address':
|
||||
data.pop(k)
|
||||
return data
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
"BTC",
|
||||
"BTN",
|
||||
"BWP",
|
||||
"BYN",
|
||||
"BZD",
|
||||
"CAD",
|
||||
"CDF",
|
||||
|
@ -46,6 +47,7 @@
|
|||
"DZD",
|
||||
"EGP",
|
||||
"ETB",
|
||||
"ETH",
|
||||
"EUR",
|
||||
"FJD",
|
||||
"FKP",
|
||||
|
@ -160,6 +162,7 @@
|
|||
"XCD",
|
||||
"XOF",
|
||||
"XPF",
|
||||
"XRP",
|
||||
"YER",
|
||||
"ZAR",
|
||||
"ZMW",
|
||||
|
@ -172,175 +175,6 @@
|
|||
"Bitbank": [
|
||||
"JPY"
|
||||
],
|
||||
"BitcoinAverage": [
|
||||
"AED",
|
||||
"AFN",
|
||||
"ALL",
|
||||
"AMD",
|
||||
"ANG",
|
||||
"AOA",
|
||||
"ARS",
|
||||
"AUD",
|
||||
"AWG",
|
||||
"AZN",
|
||||
"BAM",
|
||||
"BBD",
|
||||
"BDT",
|
||||
"BGN",
|
||||
"BHD",
|
||||
"BIF",
|
||||
"BMD",
|
||||
"BND",
|
||||
"BOB",
|
||||
"BRL",
|
||||
"BSD",
|
||||
"BTN",
|
||||
"BWP",
|
||||
"BYN",
|
||||
"BZD",
|
||||
"CAD",
|
||||
"CDF",
|
||||
"CHF",
|
||||
"CLF",
|
||||
"CLP",
|
||||
"CNH",
|
||||
"CNY",
|
||||
"COP",
|
||||
"CRC",
|
||||
"CUC",
|
||||
"CUP",
|
||||
"CVE",
|
||||
"CZK",
|
||||
"DJF",
|
||||
"DKK",
|
||||
"DOP",
|
||||
"DZD",
|
||||
"EGP",
|
||||
"ERN",
|
||||
"ETB",
|
||||
"EUR",
|
||||
"FJD",
|
||||
"FKP",
|
||||
"GBP",
|
||||
"GEL",
|
||||
"GGP",
|
||||
"GHS",
|
||||
"GIP",
|
||||
"GMD",
|
||||
"GNF",
|
||||
"GTQ",
|
||||
"GYD",
|
||||
"HKD",
|
||||
"HNL",
|
||||
"HRK",
|
||||
"HTG",
|
||||
"HUF",
|
||||
"IDR",
|
||||
"ILS",
|
||||
"IMP",
|
||||
"INR",
|
||||
"IQD",
|
||||
"IRR",
|
||||
"ISK",
|
||||
"JEP",
|
||||
"JMD",
|
||||
"JOD",
|
||||
"JPY",
|
||||
"KES",
|
||||
"KGS",
|
||||
"KHR",
|
||||
"KMF",
|
||||
"KPW",
|
||||
"KRW",
|
||||
"KWD",
|
||||
"KYD",
|
||||
"KZT",
|
||||
"LAK",
|
||||
"LBP",
|
||||
"LKR",
|
||||
"LRD",
|
||||
"LSL",
|
||||
"LYD",
|
||||
"MAD",
|
||||
"MDL",
|
||||
"MGA",
|
||||
"MKD",
|
||||
"MMK",
|
||||
"MNT",
|
||||
"MOP",
|
||||
"MRO",
|
||||
"MUR",
|
||||
"MVR",
|
||||
"MWK",
|
||||
"MXN",
|
||||
"MYR",
|
||||
"MZN",
|
||||
"NAD",
|
||||
"NGN",
|
||||
"NIO",
|
||||
"NOK",
|
||||
"NPR",
|
||||
"NZD",
|
||||
"OMR",
|
||||
"PAB",
|
||||
"PEN",
|
||||
"PGK",
|
||||
"PHP",
|
||||
"PKR",
|
||||
"PLN",
|
||||
"PYG",
|
||||
"QAR",
|
||||
"RON",
|
||||
"RSD",
|
||||
"RUB",
|
||||
"RWF",
|
||||
"SAR",
|
||||
"SBD",
|
||||
"SCR",
|
||||
"SDG",
|
||||
"SEK",
|
||||
"SGD",
|
||||
"SHP",
|
||||
"SLL",
|
||||
"SOS",
|
||||
"SRD",
|
||||
"SSP",
|
||||
"STD",
|
||||
"SVC",
|
||||
"SYP",
|
||||
"SZL",
|
||||
"THB",
|
||||
"TJS",
|
||||
"TMT",
|
||||
"TND",
|
||||
"TOP",
|
||||
"TRY",
|
||||
"TTD",
|
||||
"TWD",
|
||||
"TZS",
|
||||
"UAH",
|
||||
"UGX",
|
||||
"USD",
|
||||
"UYU",
|
||||
"UZS",
|
||||
"VES",
|
||||
"VND",
|
||||
"VUV",
|
||||
"WST",
|
||||
"XAF",
|
||||
"XAG",
|
||||
"XAU",
|
||||
"XCD",
|
||||
"XDR",
|
||||
"XOF",
|
||||
"XPD",
|
||||
"XPF",
|
||||
"XPT",
|
||||
"YER",
|
||||
"ZAR",
|
||||
"ZMW",
|
||||
"ZWL"
|
||||
],
|
||||
"BitcoinVenezuela": [
|
||||
"ARS",
|
||||
"ETH",
|
||||
|
@ -350,9 +184,6 @@
|
|||
"VEF",
|
||||
"XMR"
|
||||
],
|
||||
"Bitcointoyou": [
|
||||
"BRL"
|
||||
],
|
||||
"Bitso": [
|
||||
"MXN"
|
||||
],
|
||||
|
@ -604,6 +435,7 @@
|
|||
"THB",
|
||||
"TRY",
|
||||
"TWD",
|
||||
"UAH",
|
||||
"USD",
|
||||
"VEF",
|
||||
"VND",
|
||||
|
@ -657,12 +489,14 @@
|
|||
"CUC",
|
||||
"CVE",
|
||||
"CZK",
|
||||
"DAI",
|
||||
"DJF",
|
||||
"DKK",
|
||||
"DOP",
|
||||
"DZD",
|
||||
"EEK",
|
||||
"EGP",
|
||||
"EOS",
|
||||
"ERN",
|
||||
"ETB",
|
||||
"ETC",
|
||||
|
@ -733,6 +567,7 @@
|
|||
"NPR",
|
||||
"NZD",
|
||||
"OMR",
|
||||
"OXT",
|
||||
"PAB",
|
||||
"PEN",
|
||||
"PGK",
|
||||
|
@ -741,10 +576,12 @@
|
|||
"PLN",
|
||||
"PYG",
|
||||
"QAR",
|
||||
"REP",
|
||||
"RON",
|
||||
"RSD",
|
||||
"RUB",
|
||||
"RWF",
|
||||
"SAI",
|
||||
"SAR",
|
||||
"SBD",
|
||||
"SCR",
|
||||
|
@ -773,6 +610,7 @@
|
|||
"UYU",
|
||||
"UZS",
|
||||
"VEF",
|
||||
"VES",
|
||||
"VND",
|
||||
"VUV",
|
||||
"WST",
|
||||
|
@ -781,10 +619,13 @@
|
|||
"XAU",
|
||||
"XCD",
|
||||
"XDR",
|
||||
"XLM",
|
||||
"XOF",
|
||||
"XPD",
|
||||
"XPF",
|
||||
"XPT",
|
||||
"XRP",
|
||||
"XTZ",
|
||||
"YER",
|
||||
"ZAR",
|
||||
"ZEC",
|
||||
|
@ -802,14 +643,14 @@
|
|||
],
|
||||
"LocalBitcoins": [
|
||||
"AED",
|
||||
"AMD",
|
||||
"AOA",
|
||||
"ARS",
|
||||
"AUD",
|
||||
"BAM",
|
||||
"BDT",
|
||||
"BGN",
|
||||
"BOB",
|
||||
"BRL",
|
||||
"BWP",
|
||||
"BYN",
|
||||
"CAD",
|
||||
"CHF",
|
||||
|
@ -828,7 +669,6 @@
|
|||
"GHS",
|
||||
"GTQ",
|
||||
"HKD",
|
||||
"HNL",
|
||||
"HRK",
|
||||
"HUF",
|
||||
"IDR",
|
||||
|
@ -836,25 +676,26 @@
|
|||
"INR",
|
||||
"IRR",
|
||||
"JOD",
|
||||
"JPY",
|
||||
"KES",
|
||||
"KRW",
|
||||
"KWD",
|
||||
"KZT",
|
||||
"LKR",
|
||||
"LTC",
|
||||
"MAD",
|
||||
"MDL",
|
||||
"MUR",
|
||||
"MXN",
|
||||
"MYR",
|
||||
"NGN",
|
||||
"NIO",
|
||||
"NOK",
|
||||
"NZD",
|
||||
"OMR",
|
||||
"PAB",
|
||||
"PEN",
|
||||
"PHP",
|
||||
"PKR",
|
||||
"PLN",
|
||||
"QAR",
|
||||
"PYG",
|
||||
"RON",
|
||||
"RSD",
|
||||
"RUB",
|
||||
|
@ -865,7 +706,6 @@
|
|||
"SZL",
|
||||
"THB",
|
||||
"TRY",
|
||||
"TTD",
|
||||
"TWD",
|
||||
"TZS",
|
||||
"UAH",
|
||||
|
@ -875,21 +715,15 @@
|
|||
"VES",
|
||||
"VND",
|
||||
"XAF",
|
||||
"XMR",
|
||||
"XOF",
|
||||
"XRP",
|
||||
"ZAR"
|
||||
],
|
||||
"MercadoBitcoin": [
|
||||
"BRL"
|
||||
],
|
||||
"NegocieCoins": [
|
||||
"BRL"
|
||||
"ZAR",
|
||||
"ZMW"
|
||||
],
|
||||
"TheRockTrading": [
|
||||
"EUR"
|
||||
],
|
||||
"Zaif": [
|
||||
"JPY"
|
||||
],
|
||||
"itBit": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -352,7 +352,7 @@ POINT_AT_INFINITY = ECPubkey(None)
|
|||
def msg_magic(message: bytes) -> bytes:
|
||||
from .bitcoin import var_int
|
||||
length = bfh(var_int(len(message)))
|
||||
return b"\x18Bitcoin Signed Message:\n" + length + message
|
||||
return b"\x18LBRYcrd Signed Message:\n" + length + message
|
||||
|
||||
|
||||
def verify_signature(pubkey: bytes, sig: bytes, h: bytes) -> bool:
|
||||
|
|
|
@ -184,7 +184,7 @@ class ElectrumWindow(App):
|
|||
|
||||
def on_new_intent(self, intent):
|
||||
data = intent.getDataString()
|
||||
if intent.getScheme() == 'bitcoin':
|
||||
if intent.getScheme() == 'lbrycredits':
|
||||
self.set_URI(data)
|
||||
elif intent.getScheme() == 'lightning':
|
||||
self.set_ln_invoice(data)
|
||||
|
|
56
electrum/gui/kivy/uix/context_menu.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
#!python
|
||||
#!/usr/bin/env python
|
||||
from kivy.app import App
|
||||
from kivy.uix.bubble import Bubble
|
||||
from kivy.animation import Animation
|
||||
from kivy.uix.floatlayout import FloatLayout
|
||||
from kivy.lang import Builder
|
||||
from kivy.factory import Factory
|
||||
from kivy.clock import Clock
|
||||
|
||||
from electrum.gui.kivy.i18n import _
|
||||
|
||||
Builder.load_string('''
|
||||
<MenuItem@Button>
|
||||
background_normal: ''
|
||||
background_color: (0.192, .498, 0.745, 1)
|
||||
height: '48dp'
|
||||
size_hint: 1, None
|
||||
|
||||
<ContextMenu>
|
||||
size_hint: 1, None
|
||||
height: '48dp'
|
||||
pos: (0, 0)
|
||||
show_arrow: False
|
||||
arrow_pos: 'top_mid'
|
||||
padding: 0
|
||||
orientation: 'horizontal'
|
||||
BoxLayout:
|
||||
size_hint: 1, 1
|
||||
height: '48dp'
|
||||
padding: '12dp', '0dp'
|
||||
spacing: '3dp'
|
||||
orientation: 'horizontal'
|
||||
id: buttons
|
||||
''')
|
||||
|
||||
|
||||
class MenuItem(Factory.Button):
|
||||
pass
|
||||
|
||||
class ContextMenu(Bubble):
|
||||
|
||||
def __init__(self, obj, action_list):
|
||||
Bubble.__init__(self)
|
||||
self.obj = obj
|
||||
for k, v in action_list:
|
||||
l = MenuItem()
|
||||
l.text = _(k)
|
||||
def func(f=v):
|
||||
Clock.schedule_once(lambda dt: f(obj), 0.15)
|
||||
l.on_release = func
|
||||
self.ids.buttons.add_widget(l)
|
||||
|
||||
def hide(self):
|
||||
if self.parent:
|
||||
self.parent.hide_menu()
|
169
electrum/gui/kivy/uix/dialogs/invoices.py
Normal file
|
@ -0,0 +1,169 @@
|
|||
from kivy.app import App
|
||||
from kivy.factory import Factory
|
||||
from kivy.properties import ObjectProperty
|
||||
from kivy.lang import Builder
|
||||
from decimal import Decimal
|
||||
|
||||
Builder.load_string('''
|
||||
<InvoicesLabel@Label>
|
||||
#color: .305, .309, .309, 1
|
||||
text_size: self.width, None
|
||||
halign: 'left'
|
||||
valign: 'top'
|
||||
|
||||
<InvoiceItem@CardItem>
|
||||
requestor: ''
|
||||
memo: ''
|
||||
amount: ''
|
||||
status: ''
|
||||
date: ''
|
||||
icon: 'atlas://electrum/gui/kivy/theming/light/important'
|
||||
Image:
|
||||
id: icon
|
||||
source: root.icon
|
||||
size_hint: None, 1
|
||||
width: self.height *.54
|
||||
mipmap: True
|
||||
BoxLayout:
|
||||
spacing: '8dp'
|
||||
height: '32dp'
|
||||
orientation: 'vertical'
|
||||
Widget
|
||||
InvoicesLabel:
|
||||
text: root.requestor
|
||||
shorten: True
|
||||
Widget
|
||||
InvoicesLabel:
|
||||
text: root.memo
|
||||
color: .699, .699, .699, 1
|
||||
font_size: '13sp'
|
||||
shorten: True
|
||||
Widget
|
||||
BoxLayout:
|
||||
spacing: '8dp'
|
||||
height: '32dp'
|
||||
orientation: 'vertical'
|
||||
Widget
|
||||
InvoicesLabel:
|
||||
text: root.amount
|
||||
font_size: '15sp'
|
||||
halign: 'right'
|
||||
width: '110sp'
|
||||
Widget
|
||||
InvoicesLabel:
|
||||
text: root.status
|
||||
font_size: '13sp'
|
||||
halign: 'right'
|
||||
color: .699, .699, .699, 1
|
||||
Widget
|
||||
|
||||
|
||||
<InvoicesDialog@Popup>
|
||||
id: popup
|
||||
title: _('Invoices')
|
||||
BoxLayout:
|
||||
id: box
|
||||
orientation: 'vertical'
|
||||
spacing: '1dp'
|
||||
ScrollView:
|
||||
GridLayout:
|
||||
cols: 1
|
||||
id: invoices_container
|
||||
size_hint: 1, None
|
||||
height: self.minimum_height
|
||||
spacing: '2dp'
|
||||
padding: '12dp'
|
||||
''')
|
||||
|
||||
from kivy.properties import BooleanProperty
|
||||
from electrum.gui.kivy.i18n import _
|
||||
from electrum.util import format_time
|
||||
from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
|
||||
from electrum.gui.kivy.uix.context_menu import ContextMenu
|
||||
|
||||
invoice_text = {
|
||||
PR_UNPAID:_('Pending'),
|
||||
PR_UNKNOWN:_('Unknown'),
|
||||
PR_PAID:_('Paid'),
|
||||
PR_EXPIRED:_('Expired')
|
||||
}
|
||||
pr_icon = {
|
||||
PR_UNPAID: 'atlas://electrum/gui/kivy/theming/light/important',
|
||||
PR_UNKNOWN: 'atlas://electrum/gui/kivy/theming/light/important',
|
||||
PR_PAID: 'atlas://electrum/gui/kivy/theming/light/confirmed',
|
||||
PR_EXPIRED: 'atlas://electrum/gui/kivy/theming/light/close'
|
||||
}
|
||||
|
||||
|
||||
class InvoicesDialog(Factory.Popup):
|
||||
|
||||
def __init__(self, app, screen, callback):
|
||||
Factory.Popup.__init__(self)
|
||||
self.app = app
|
||||
self.screen = screen
|
||||
self.callback = callback
|
||||
self.cards = {}
|
||||
self.context_menu = None
|
||||
|
||||
def get_card(self, pr):
|
||||
key = pr.get_id()
|
||||
ci = self.cards.get(key)
|
||||
if ci is None:
|
||||
ci = Factory.InvoiceItem()
|
||||
ci.key = key
|
||||
ci.screen = self
|
||||
self.cards[key] = ci
|
||||
ci.requestor = pr.get_requestor()
|
||||
ci.memo = pr.get_memo()
|
||||
amount = pr.get_amount()
|
||||
if amount:
|
||||
ci.amount = self.app.format_amount_and_units(amount)
|
||||
status = self.app.wallet.invoices.get_status(ci.key)
|
||||
ci.status = invoice_text[status]
|
||||
ci.icon = pr_icon[status]
|
||||
else:
|
||||
ci.amount = _('No Amount')
|
||||
ci.status = ''
|
||||
exp = pr.get_expiration_date()
|
||||
ci.date = format_time(exp) if exp else _('Never')
|
||||
return ci
|
||||
|
||||
def update(self):
|
||||
self.menu_actions = [('Pay', self.do_pay), ('Details', self.do_view), ('Delete', self.do_delete)]
|
||||
invoices_list = self.ids.invoices_container
|
||||
invoices_list.clear_widgets()
|
||||
_list = self.app.wallet.invoices.sorted_list()
|
||||
for pr in _list:
|
||||
ci = self.get_card(pr)
|
||||
invoices_list.add_widget(ci)
|
||||
|
||||
def do_pay(self, obj):
|
||||
self.hide_menu()
|
||||
self.dismiss()
|
||||
pr = self.app.wallet.invoices.get(obj.key)
|
||||
self.app.on_pr(pr)
|
||||
|
||||
def do_view(self, obj):
|
||||
pr = self.app.wallet.invoices.get(obj.key)
|
||||
pr.verify(self.app.wallet.contacts)
|
||||
self.app.show_pr_details(pr.get_dict(), obj.status, True)
|
||||
|
||||
def do_delete(self, obj):
|
||||
from .question import Question
|
||||
def cb(result):
|
||||
if result:
|
||||
self.app.wallet.invoices.remove(obj.key)
|
||||
self.hide_menu()
|
||||
self.update()
|
||||
d = Question(_('Delete invoice?'), cb)
|
||||
d.open()
|
||||
|
||||
def show_menu(self, obj):
|
||||
self.hide_menu()
|
||||
self.context_menu = ContextMenu(obj, self.menu_actions)
|
||||
self.ids.box.add_widget(self.context_menu)
|
||||
|
||||
def hide_menu(self):
|
||||
if self.context_menu is not None:
|
||||
self.ids.box.remove_widget(self.context_menu)
|
||||
self.context_menu = None
|
157
electrum/gui/kivy/uix/dialogs/requests.py
Normal file
|
@ -0,0 +1,157 @@
|
|||
from kivy.app import App
|
||||
from kivy.factory import Factory
|
||||
from kivy.properties import ObjectProperty
|
||||
from kivy.lang import Builder
|
||||
from decimal import Decimal
|
||||
|
||||
Builder.load_string('''
|
||||
<RequestLabel@Label>
|
||||
#color: .305, .309, .309, 1
|
||||
text_size: self.width, None
|
||||
halign: 'left'
|
||||
valign: 'top'
|
||||
|
||||
<RequestItem@CardItem>
|
||||
address: ''
|
||||
memo: ''
|
||||
amount: ''
|
||||
status: ''
|
||||
date: ''
|
||||
icon: 'atlas://electrum/gui/kivy/theming/light/important'
|
||||
Image:
|
||||
id: icon
|
||||
source: root.icon
|
||||
size_hint: None, 1
|
||||
width: self.height *.54
|
||||
mipmap: True
|
||||
BoxLayout:
|
||||
spacing: '8dp'
|
||||
height: '32dp'
|
||||
orientation: 'vertical'
|
||||
Widget
|
||||
RequestLabel:
|
||||
text: root.address
|
||||
shorten: True
|
||||
Widget
|
||||
RequestLabel:
|
||||
text: root.memo
|
||||
color: .699, .699, .699, 1
|
||||
font_size: '13sp'
|
||||
shorten: True
|
||||
Widget
|
||||
BoxLayout:
|
||||
spacing: '8dp'
|
||||
height: '32dp'
|
||||
orientation: 'vertical'
|
||||
Widget
|
||||
RequestLabel:
|
||||
text: root.amount
|
||||
halign: 'right'
|
||||
font_size: '15sp'
|
||||
Widget
|
||||
RequestLabel:
|
||||
text: root.status
|
||||
halign: 'right'
|
||||
font_size: '13sp'
|
||||
color: .699, .699, .699, 1
|
||||
Widget
|
||||
|
||||
<RequestsDialog@Popup>
|
||||
id: popup
|
||||
title: _('Requests')
|
||||
BoxLayout:
|
||||
id:box
|
||||
orientation: 'vertical'
|
||||
spacing: '1dp'
|
||||
ScrollView:
|
||||
GridLayout:
|
||||
cols: 1
|
||||
id: requests_container
|
||||
size_hint: 1, None
|
||||
height: self.minimum_height
|
||||
spacing: '2dp'
|
||||
padding: '12dp'
|
||||
''')
|
||||
|
||||
from kivy.properties import BooleanProperty
|
||||
from electrum.gui.kivy.i18n import _
|
||||
from electrum.util import format_time
|
||||
from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
|
||||
from electrum.gui.kivy.uix.context_menu import ContextMenu
|
||||
|
||||
pr_icon = {
|
||||
PR_UNPAID: 'atlas://electrum/gui/kivy/theming/light/important',
|
||||
PR_UNKNOWN: 'atlas://electrum/gui/kivy/theming/light/important',
|
||||
PR_PAID: 'atlas://electrum/gui/kivy/theming/light/confirmed',
|
||||
PR_EXPIRED: 'atlas://electrum/gui/kivy/theming/light/close'
|
||||
}
|
||||
request_text = {
|
||||
PR_UNPAID: _('Pending'),
|
||||
PR_UNKNOWN: _('Unknown'),
|
||||
PR_PAID: _('Received'),
|
||||
PR_EXPIRED: _('Expired')
|
||||
}
|
||||
|
||||
|
||||
class RequestsDialog(Factory.Popup):
|
||||
|
||||
def __init__(self, app, screen, callback):
|
||||
Factory.Popup.__init__(self)
|
||||
self.app = app
|
||||
self.screen = screen
|
||||
self.callback = callback
|
||||
self.cards = {}
|
||||
self.context_menu = None
|
||||
|
||||
def get_card(self, req):
|
||||
address = req['address']
|
||||
ci = self.cards.get(address)
|
||||
if ci is None:
|
||||
ci = Factory.RequestItem()
|
||||
ci.address = address
|
||||
ci.screen = self
|
||||
self.cards[address] = ci
|
||||
|
||||
amount = req.get('amount')
|
||||
ci.amount = self.app.format_amount_and_units(amount) if amount else ''
|
||||
ci.memo = req.get('memo', '')
|
||||
status, conf = self.app.wallet.get_request_status(address)
|
||||
ci.status = request_text[status]
|
||||
ci.icon = pr_icon[status]
|
||||
#exp = pr.get_expiration_date()
|
||||
#ci.date = format_time(exp) if exp else _('Never')
|
||||
return ci
|
||||
|
||||
def update(self):
|
||||
self.menu_actions = [(_('Show'), self.do_show), (_('Delete'), self.do_delete)]
|
||||
requests_list = self.ids.requests_container
|
||||
requests_list.clear_widgets()
|
||||
_list = self.app.wallet.get_sorted_requests(self.app.electrum_config)
|
||||
for pr in _list:
|
||||
ci = self.get_card(pr)
|
||||
requests_list.add_widget(ci)
|
||||
|
||||
def do_show(self, obj):
|
||||
self.hide_menu()
|
||||
self.dismiss()
|
||||
self.app.show_request(obj.address)
|
||||
|
||||
def do_delete(self, req):
|
||||
from .question import Question
|
||||
def cb(result):
|
||||
if result:
|
||||
self.app.wallet.remove_payment_request(req.address, self.app.electrum_config)
|
||||
self.hide_menu()
|
||||
self.update()
|
||||
d = Question(_('Delete request'), cb)
|
||||
d.open()
|
||||
|
||||
def show_menu(self, obj):
|
||||
self.hide_menu()
|
||||
self.context_menu = ContextMenu(obj, self.menu_actions)
|
||||
self.ids.box.add_widget(self.context_menu)
|
||||
|
||||
def hide_menu(self):
|
||||
if self.context_menu is not None:
|
||||
self.ids.box.remove_widget(self.context_menu)
|
||||
self.context_menu = None
|
89
electrum/gui/kivy/uix/ui_screens/invoice.kv
Normal file
|
@ -0,0 +1,89 @@
|
|||
#:import Decimal decimal.Decimal
|
||||
|
||||
|
||||
|
||||
Popup:
|
||||
id: popup
|
||||
is_invoice: True
|
||||
amount: 0
|
||||
requestor: ''
|
||||
exp: ''
|
||||
description: ''
|
||||
status: ''
|
||||
signature: ''
|
||||
isaddr: ''
|
||||
fund: 0
|
||||
pk: ''
|
||||
title: _('Invoice') if popup.is_invoice else _('Request')
|
||||
tx_hash: ''
|
||||
BoxLayout:
|
||||
orientation: 'vertical'
|
||||
ScrollView:
|
||||
GridLayout:
|
||||
cols: 1
|
||||
height: self.minimum_height
|
||||
size_hint_y: None
|
||||
padding: '10dp'
|
||||
spacing: '10dp'
|
||||
GridLayout:
|
||||
cols: 1
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
spacing: '10dp'
|
||||
BoxLabel:
|
||||
text: (_('Status') if popup.amount or popup.is_invoice or popup.isaddr == 'y' else _('Amount received')) if root.status else ''
|
||||
value: root.status
|
||||
BoxLabel:
|
||||
text: _('Request amount') if root.amount else ''
|
||||
value: app.format_amount_and_units(root.amount) if root.amount else ''
|
||||
BoxLabel:
|
||||
text: _('Requestor') if popup.is_invoice else _('Address')
|
||||
value: root.requestor
|
||||
BoxLabel:
|
||||
text: _('Signature') if root.signature else ''
|
||||
value: root.signature
|
||||
BoxLabel:
|
||||
text: _('Expiration') if root.exp else ''
|
||||
value: root.exp
|
||||
BoxLabel:
|
||||
text: _('Description') if root.description else ''
|
||||
value: root.description
|
||||
BoxLabel:
|
||||
text: _('Balance') if popup.fund else ''
|
||||
value: app.format_amount_and_units(root.fund) if root.fund else ''
|
||||
TopLabel:
|
||||
text: _('Private Key')
|
||||
RefLabel:
|
||||
id: pk_label
|
||||
touched: True if not self.touched else True
|
||||
data: root.pk
|
||||
|
||||
TopLabel:
|
||||
text: _('Outputs') if popup.is_invoice else ''
|
||||
OutputList:
|
||||
id: output_list
|
||||
TopLabel:
|
||||
text: _('Transaction ID') if popup.tx_hash else ''
|
||||
TxHashLabel:
|
||||
data: popup.tx_hash
|
||||
name: _('Transaction ID')
|
||||
Widget:
|
||||
size_hint: 1, 0.1
|
||||
|
||||
BoxLayout:
|
||||
size_hint: 1, None
|
||||
height: '48dp'
|
||||
Widget:
|
||||
size_hint: 0.5, None
|
||||
height: '48dp'
|
||||
Button:
|
||||
size_hint: 2, None
|
||||
height: '48dp'
|
||||
text: _('Close')
|
||||
on_release: popup.dismiss()
|
||||
Button:
|
||||
size_hint: 2, None
|
||||
height: '48dp'
|
||||
text: _('Hide private key') if pk_label.data else _('Export private key')
|
||||
on_release:
|
||||
setattr(pk_label, 'data', '') if pk_label.data else popup.export(pk_label, popup.requestor)
|
|
@ -82,7 +82,7 @@ from .amountedit import AmountEdit, BTCAmountEdit, FreezableLineEdit, FeerateEdi
|
|||
from .qrcodewidget import QRCodeWidget, QRDialog
|
||||
from .qrtextedit import ShowQRTextEdit, ScanQRTextEdit
|
||||
from .transaction_dialog import show_transaction
|
||||
from .fee_slider import FeeSlider
|
||||
#from .fee_slider import FeeSlider
|
||||
from .util import (read_QIcon, ColorScheme, text_dialog, icon_path, WaitingDialog,
|
||||
WindowModalDialog, ChoicesLayout, HelpLabel, Buttons,
|
||||
OkButton, InfoButton, WWLabel, TaskThread, CancelButton,
|
||||
|
@ -991,8 +991,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
|||
msg = ' '.join([
|
||||
_('Expiration date of your request.'),
|
||||
_('This information is seen by the recipient if you send them a signed payment request.'),
|
||||
_('Expired requests have to be deleted manually from your list, in order to free the corresponding Bitcoin addresses.'),
|
||||
_('The bitcoin address never expires and will always be part of this electrum wallet.'),
|
||||
_('Expired requests have to be deleted manually from your list, in order to free the corresponding LBRY Credits addresses.'),
|
||||
_('The LBRY Credits address never expires and will always be part of this electrum wallet.'),
|
||||
])
|
||||
grid.addWidget(HelpLabel(_('Request expires'), msg), 2, 0)
|
||||
grid.addWidget(self.expires_combo, 2, 1)
|
||||
|
@ -1033,7 +1033,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
|||
addr = str(self.receive_address_e.text())
|
||||
self.receive_address_widgets.setVisible(bool(addr))
|
||||
|
||||
msg = _('Bitcoin address where the payment should be received. Note that each payment request uses a different Bitcoin address.')
|
||||
msg = _('LBRY Credits address where the payment should be received. Note that each payment request uses a different LBRY Credits address.')
|
||||
receive_address_label = HelpLabel(_('Receiving address'), msg)
|
||||
|
||||
self.receive_address_e = ButtonsTextEdit()
|
||||
|
@ -1246,7 +1246,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
|||
self.amount_e = BTCAmountEdit(self.get_decimal_point)
|
||||
self.payto_e = PayToEdit(self)
|
||||
msg = _('Recipient of the funds.') + '\n\n'\
|
||||
+ _('You may enter a Bitcoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Bitcoin address)')
|
||||
+ _('You may enter a LBRY Credits address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a LBRY Credits address)')
|
||||
payto_label = HelpLabel(_('Pay to'), msg)
|
||||
grid.addWidget(payto_label, 1, 0)
|
||||
grid.addWidget(self.payto_e, 1, 1, 1, -1)
|
||||
|
@ -2199,7 +2199,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
|||
def show_mpk(index):
|
||||
mpk_text.setText(mpk_list[index])
|
||||
mpk_text.repaint() # macOS hack for #4777
|
||||
|
||||
|
||||
# only show the combobox in case multiple accounts are available
|
||||
if len(mpk_list) > 1:
|
||||
# only show the combobox if multiple master keys are defined
|
||||
|
|
|
@ -445,8 +445,8 @@ class Interface(Logger):
|
|||
self.logger.info(f'requesting block header {height} in mode {assert_mode}')
|
||||
# use lower timeout as we usually have network.bhi_lock here
|
||||
timeout = self.network.get_network_timeout_seconds(NetworkTimeout.Urgent)
|
||||
res = await self.session.send_request('blockchain.block.header', [height], timeout=timeout)
|
||||
return blockchain.deserialize_header(bytes.fromhex(res), height)
|
||||
res = await self.session.send_request('blockchain.block.headers', [height,1], timeout=timeout)
|
||||
return blockchain.deserialize_header(bytes.fromhex(res['hex']), height)
|
||||
|
||||
async def request_chunk(self, height: int, tip=None, *, can_return_early=False):
|
||||
index = height // 2016
|
||||
|
@ -518,10 +518,12 @@ class Interface(Logger):
|
|||
|
||||
async def run_fetch_blocks(self):
|
||||
header_queue = asyncio.Queue()
|
||||
await self.session.subscribe('blockchain.headers.subscribe', [], header_queue)
|
||||
await self.session.subscribe('blockchain.headers.subscribe', [True], header_queue)
|
||||
while True:
|
||||
item = await header_queue.get()
|
||||
raw_header = item[0]
|
||||
print(item)
|
||||
raw_header = item[1]
|
||||
print(raw_header)
|
||||
height = raw_header['height']
|
||||
header = blockchain.deserialize_header(bfh(raw_header['hex']), height)
|
||||
self.tip_header = header
|
||||
|
|
99
electrum/jsonrpc.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Electrum - lightweight Bitcoin client
|
||||
# Copyright (C) 2018 Thomas Voegtlin
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person
|
||||
# obtaining a copy of this software and associated documentation files
|
||||
# (the "Software"), to deal in the Software without restriction,
|
||||
# including without limitation the rights to use, copy, modify, merge,
|
||||
# publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
# and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
from base64 import b64decode
|
||||
import time
|
||||
|
||||
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer, SimpleJSONRPCRequestHandler
|
||||
|
||||
from . import util
|
||||
|
||||
|
||||
class RPCAuthCredentialsInvalid(Exception):
|
||||
def __str__(self):
|
||||
return 'Authentication failed (bad credentials)'
|
||||
|
||||
|
||||
class RPCAuthCredentialsMissing(Exception):
|
||||
def __str__(self):
|
||||
return 'Authentication failed (missing credentials)'
|
||||
|
||||
|
||||
class RPCAuthUnsupportedType(Exception):
|
||||
def __str__(self):
|
||||
return 'Authentication failed (only basic auth is supported)'
|
||||
|
||||
|
||||
# based on http://acooke.org/cute/BasicHTTPA0.html by andrew cooke
|
||||
class VerifyingJSONRPCServer(SimpleJSONRPCServer):
|
||||
|
||||
def __init__(self, *args, rpc_user, rpc_password, **kargs):
|
||||
|
||||
self.rpc_user = rpc_user
|
||||
self.rpc_password = rpc_password
|
||||
|
||||
class VerifyingRequestHandler(SimpleJSONRPCRequestHandler):
|
||||
def parse_request(myself):
|
||||
# first, call the original implementation which returns
|
||||
# True if all OK so far
|
||||
if SimpleJSONRPCRequestHandler.parse_request(myself):
|
||||
# Do not authenticate OPTIONS-requests
|
||||
if myself.command.strip() == 'OPTIONS':
|
||||
return True
|
||||
try:
|
||||
self.authenticate(myself.headers)
|
||||
return True
|
||||
except (RPCAuthCredentialsInvalid, RPCAuthCredentialsMissing,
|
||||
RPCAuthUnsupportedType) as e:
|
||||
myself.send_error(401, str(e))
|
||||
except BaseException as e:
|
||||
import traceback, sys
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
myself.send_error(500, str(e))
|
||||
return False
|
||||
|
||||
SimpleJSONRPCServer.__init__(
|
||||
self, requestHandler=VerifyingRequestHandler, *args, **kargs)
|
||||
|
||||
def authenticate(self, headers):
|
||||
if self.rpc_password == '':
|
||||
# RPC authentication is disabled
|
||||
return
|
||||
|
||||
auth_string = headers.get('Authorization', None)
|
||||
if auth_string is None:
|
||||
raise RPCAuthCredentialsMissing()
|
||||
|
||||
(basic, _, encoded) = auth_string.partition(' ')
|
||||
if basic != 'Basic':
|
||||
raise RPCAuthUnsupportedType()
|
||||
|
||||
encoded = util.to_bytes(encoded, 'utf8')
|
||||
credentials = util.to_string(b64decode(encoded), 'utf8')
|
||||
(username, _, password) = credentials.partition(':')
|
||||
if not (util.constant_time_compare(username, self.rpc_user)
|
||||
and util.constant_time_compare(password, self.rpc_password)):
|
||||
time.sleep(0.050)
|
||||
raise RPCAuthCredentialsInvalid()
|
|
@ -140,7 +140,7 @@ class Mnemonic(Logger):
|
|||
mnemonic = normalize_text(mnemonic)
|
||||
passphrase = passphrase or ''
|
||||
passphrase = normalize_text(passphrase)
|
||||
return hashlib.pbkdf2_hmac('sha512', mnemonic.encode('utf-8'), b'electrum' + passphrase.encode('utf-8'), iterations = PBKDF2_ROUNDS)
|
||||
return hashlib.pbkdf2_hmac('sha512', mnemonic.encode('utf-8'), b'lbryum' + passphrase.encode('utf-8'), iterations = PBKDF2_ROUNDS)
|
||||
|
||||
def mnemonic_encode(self, i):
|
||||
n = len(self.wordlist)
|
||||
|
|
94
electrum/msqr.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
# from http://eli.thegreenplace.net/2009/03/07/computing-modular-square-roots-in-python/
|
||||
|
||||
def modular_sqrt(a, p):
|
||||
""" Find a quadratic residue (mod p) of 'a'. p
|
||||
must be an odd prime.
|
||||
|
||||
Solve the congruence of the form:
|
||||
x^2 = a (mod p)
|
||||
And returns x. Note that p - x is also a root.
|
||||
|
||||
0 is returned is no square root exists for
|
||||
these a and p.
|
||||
|
||||
The Tonelli-Shanks algorithm is used (except
|
||||
for some simple cases in which the solution
|
||||
is known from an identity). This algorithm
|
||||
runs in polynomial time (unless the
|
||||
generalized Riemann hypothesis is false).
|
||||
"""
|
||||
# Simple cases
|
||||
#
|
||||
if legendre_symbol(a, p) != 1:
|
||||
return 0
|
||||
elif a == 0:
|
||||
return 0
|
||||
elif p == 2:
|
||||
return p
|
||||
elif p % 4 == 3:
|
||||
return pow(a, (p + 1) // 4, p)
|
||||
|
||||
# Partition p-1 to s * 2^e for an odd s (i.e.
|
||||
# reduce all the powers of 2 from p-1)
|
||||
#
|
||||
s = p - 1
|
||||
e = 0
|
||||
while s % 2 == 0:
|
||||
s //= 2
|
||||
e += 1
|
||||
|
||||
# Find some 'n' with a legendre symbol n|p = -1.
|
||||
# Shouldn't take long.
|
||||
#
|
||||
n = 2
|
||||
while legendre_symbol(n, p) != -1:
|
||||
n += 1
|
||||
|
||||
# Here be dragons!
|
||||
# Read the paper "Square roots from 1; 24, 51,
|
||||
# 10 to Dan Shanks" by Ezra Brown for more
|
||||
# information
|
||||
#
|
||||
|
||||
# x is a guess of the square root that gets better
|
||||
# with each iteration.
|
||||
# b is the "fudge factor" - by how much we're off
|
||||
# with the guess. The invariant x^2 = ab (mod p)
|
||||
# is maintained throughout the loop.
|
||||
# g is used for successive powers of n to update
|
||||
# both a and b
|
||||
# r is the exponent - decreases with each update
|
||||
#
|
||||
x = pow(a, (s + 1) // 2, p)
|
||||
b = pow(a, s, p)
|
||||
g = pow(n, s, p)
|
||||
r = e
|
||||
|
||||
while True:
|
||||
t = b
|
||||
m = 0
|
||||
for m in range(r):
|
||||
if t == 1:
|
||||
break
|
||||
t = pow(t, 2, p)
|
||||
|
||||
if m == 0:
|
||||
return x
|
||||
|
||||
gs = pow(g, 2 ** (r - m - 1), p)
|
||||
g = (gs * gs) % p
|
||||
x = (x * gs) % p
|
||||
b = (b * g) % p
|
||||
r = m
|
||||
|
||||
def legendre_symbol(a, p):
|
||||
""" Compute the Legendre symbol a|p using
|
||||
Euler's criterion. p is a prime, a is
|
||||
relatively prime to p (if p divides
|
||||
a, then a|p = 0)
|
||||
|
||||
Returns 1 if a has a square root modulo
|
||||
p, -1 otherwise.
|
||||
"""
|
||||
ls = pow(a, (p - 1) // 2, p)
|
||||
return -1 if ls == p - 1 else ls
|
|
@ -117,7 +117,7 @@ def filter_noonion(servers):
|
|||
return {k: v for k, v in servers.items() if not k.endswith('.onion')}
|
||||
|
||||
|
||||
def filter_protocol(hostmap, protocol='s'):
|
||||
def filter_protocol(hostmap, protocol='t'):
|
||||
'''Filters the hostmap for those implementing protocol.
|
||||
The result is a list in serialized form.'''
|
||||
eligible = []
|
||||
|
@ -128,7 +128,7 @@ def filter_protocol(hostmap, protocol='s'):
|
|||
return eligible
|
||||
|
||||
|
||||
def pick_random_server(hostmap=None, protocol='s', exclude_set=None):
|
||||
def pick_random_server(hostmap=None, protocol='t', exclude_set=None):
|
||||
if hostmap is None:
|
||||
hostmap = constants.net.DEFAULT_SERVERS
|
||||
if exclude_set is None:
|
||||
|
|
5
electrum/plugins/greenaddress_instant/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from electrum.i18n import _
|
||||
|
||||
fullname = 'GreenAddress instant'
|
||||
description = _("Allows validating if your transactions have instant confirmations by GreenAddress")
|
||||
available_for = ['qt']
|
106
electrum/plugins/greenaddress_instant/qt.py
Normal file
|
@ -0,0 +1,106 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Electrum - lightweight Bitcoin client
|
||||
# Copyright (C) 2014 Thomas Voegtlin
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person
|
||||
# obtaining a copy of this software and associated documentation files
|
||||
# (the "Software"), to deal in the Software without restriction,
|
||||
# including without limitation the rights to use, copy, modify, merge,
|
||||
# publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
# and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
import base64
|
||||
import urllib.parse
|
||||
import sys
|
||||
import requests
|
||||
|
||||
from PyQt5.QtWidgets import QApplication, QPushButton
|
||||
|
||||
from electrum.plugin import BasePlugin, hook
|
||||
from electrum.i18n import _
|
||||
|
||||
|
||||
class Plugin(BasePlugin):
|
||||
|
||||
button_label = _("Verify GA instant")
|
||||
|
||||
@hook
|
||||
def transaction_dialog(self, d):
|
||||
d.verify_button = QPushButton(self.button_label)
|
||||
d.verify_button.clicked.connect(lambda: self.do_verify(d))
|
||||
d.buttons.insert(0, d.verify_button)
|
||||
self.transaction_dialog_update(d)
|
||||
|
||||
def get_my_addr(self, d):
|
||||
"""Returns the address for given tx which can be used to request
|
||||
instant confirmation verification from GreenAddress"""
|
||||
for o in d.tx.outputs():
|
||||
if d.wallet.is_mine(o.address):
|
||||
return o.address
|
||||
return None
|
||||
|
||||
@hook
|
||||
def transaction_dialog_update(self, d):
|
||||
if d.tx.is_complete() and self.get_my_addr(d):
|
||||
d.verify_button.show()
|
||||
else:
|
||||
d.verify_button.hide()
|
||||
|
||||
def do_verify(self, d):
|
||||
tx = d.tx
|
||||
wallet = d.wallet
|
||||
window = d.main_window
|
||||
|
||||
if wallet.is_watching_only():
|
||||
d.show_critical(_('This feature is not available for watch-only wallets.'))
|
||||
return
|
||||
|
||||
# 1. get the password and sign the verification request
|
||||
password = None
|
||||
if wallet.has_keystore_encryption():
|
||||
msg = _('GreenAddress requires your signature \n'
|
||||
'to verify that transaction is instant.\n'
|
||||
'Please enter your password to sign a\n'
|
||||
'verification request.')
|
||||
password = window.password_dialog(msg, parent=d)
|
||||
if not password:
|
||||
return
|
||||
try:
|
||||
d.verify_button.setText(_('Verifying...'))
|
||||
QApplication.processEvents() # update the button label
|
||||
|
||||
addr = self.get_my_addr(d)
|
||||
message = "Please verify if %s is GreenAddress instant confirmed" % tx.txid()
|
||||
sig = wallet.sign_message(addr, message, password)
|
||||
sig = base64.b64encode(sig).decode('ascii')
|
||||
|
||||
# 2. send the request
|
||||
response = requests.request("GET", ("https://greenaddress.it/verify/?signature=%s&txhash=%s" % (urllib.parse.quote(sig), tx.txid())),
|
||||
headers = {'User-Agent': 'Electrum'})
|
||||
response = response.json()
|
||||
|
||||
# 3. display the result
|
||||
if response.get('verified'):
|
||||
d.show_message(_('{} is covered by GreenAddress instant confirmation').format(tx.txid()), title=_('Verification successful!'))
|
||||
else:
|
||||
d.show_critical(_('{} is not covered by GreenAddress instant confirmation').format(tx.txid()), title=_('Verification failed!'))
|
||||
except BaseException as e:
|
||||
import traceback
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
d.show_error(str(e))
|
||||
finally:
|
||||
d.verify_button.setText(self.button_label)
|
11
electrum/plugins/trezor/client.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
from trezorlib.client import proto, BaseClient, ProtocolMixin
|
||||
from .clientbase import TrezorClientBase
|
||||
|
||||
class TrezorClient(TrezorClientBase, ProtocolMixin, BaseClient):
|
||||
def __init__(self, transport, handler, plugin):
|
||||
BaseClient.__init__(self, transport=transport)
|
||||
ProtocolMixin.__init__(self, transport=transport)
|
||||
TrezorClientBase.__init__(self, handler, plugin, proto)
|
||||
|
||||
|
||||
TrezorClientBase.wrap_methods(TrezorClient)
|
95
electrum/plugins/trezor/transport.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
from electrum.util import PrintError
|
||||
|
||||
|
||||
class TrezorTransport(PrintError):
|
||||
|
||||
@staticmethod
|
||||
def all_transports():
|
||||
"""Reimplemented trezorlib.transport.all_transports so that we can
|
||||
enable/disable specific transports.
|
||||
"""
|
||||
try:
|
||||
# only to detect trezorlib version
|
||||
from trezorlib.transport import all_transports
|
||||
except ImportError:
|
||||
# old trezorlib. compat for trezorlib < 0.9.2
|
||||
transports = []
|
||||
try:
|
||||
from trezorlib.transport_bridge import BridgeTransport
|
||||
transports.append(BridgeTransport)
|
||||
except BaseException:
|
||||
pass
|
||||
try:
|
||||
from trezorlib.transport_hid import HidTransport
|
||||
transports.append(HidTransport)
|
||||
except BaseException:
|
||||
pass
|
||||
try:
|
||||
from trezorlib.transport_udp import UdpTransport
|
||||
transports.append(UdpTransport)
|
||||
except BaseException:
|
||||
pass
|
||||
try:
|
||||
from trezorlib.transport_webusb import WebUsbTransport
|
||||
transports.append(WebUsbTransport)
|
||||
except BaseException:
|
||||
pass
|
||||
else:
|
||||
# new trezorlib.
|
||||
transports = []
|
||||
try:
|
||||
from trezorlib.transport.bridge import BridgeTransport
|
||||
transports.append(BridgeTransport)
|
||||
except BaseException:
|
||||
pass
|
||||
try:
|
||||
from trezorlib.transport.hid import HidTransport
|
||||
transports.append(HidTransport)
|
||||
except BaseException:
|
||||
pass
|
||||
try:
|
||||
from trezorlib.transport.udp import UdpTransport
|
||||
transports.append(UdpTransport)
|
||||
except BaseException:
|
||||
pass
|
||||
try:
|
||||
from trezorlib.transport.webusb import WebUsbTransport
|
||||
transports.append(WebUsbTransport)
|
||||
except BaseException:
|
||||
pass
|
||||
return transports
|
||||
return transports
|
||||
|
||||
def enumerate_devices(self):
|
||||
"""Just like trezorlib.transport.enumerate_devices,
|
||||
but with exception catching, so that transports can fail separately.
|
||||
"""
|
||||
devices = []
|
||||
for transport in self.all_transports():
|
||||
try:
|
||||
new_devices = transport.enumerate()
|
||||
except BaseException as e:
|
||||
self.print_error('enumerate failed for {}. error {}'
|
||||
.format(transport.__name__, str(e)))
|
||||
else:
|
||||
devices.extend(new_devices)
|
||||
return devices
|
||||
|
||||
def get_transport(self, path=None):
|
||||
"""Reimplemented trezorlib.transport.get_transport,
|
||||
(1) for old trezorlib
|
||||
(2) to be able to disable specific transports
|
||||
(3) to call our own enumerate_devices that catches exceptions
|
||||
"""
|
||||
if path is None:
|
||||
try:
|
||||
return self.enumerate_devices()[0]
|
||||
except IndexError:
|
||||
raise Exception("No TREZOR device found") from None
|
||||
|
||||
def match_prefix(a, b):
|
||||
return a.startswith(b) or b.startswith(a)
|
||||
transports = [t for t in self.all_transports() if match_prefix(path, t.PATH_PREFIX)]
|
||||
if transports:
|
||||
return transports[0].find_by_path(path)
|
||||
raise Exception("Unknown path prefix '%s'" % path)
|
47
electrum/scripts/util.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
import asyncio
|
||||
from typing import List, Sequence
|
||||
|
||||
from aiorpcx import TaskGroup
|
||||
|
||||
from electrum.network import parse_servers, Network
|
||||
from electrum.interface import Interface
|
||||
|
||||
|
||||
#electrum.util.set_verbosity(True)
|
||||
|
||||
async def get_peers(network: Network):
|
||||
while not network.is_connected():
|
||||
await asyncio.sleep(1)
|
||||
print("waiting for network to get connected...")
|
||||
interface = network.interface
|
||||
session = interface.session
|
||||
print(f"asking server {interface.server} for its peers")
|
||||
peers = parse_servers(await session.send_request('server.peers.subscribe'))
|
||||
print(f"got {len(peers)} servers")
|
||||
return peers
|
||||
|
||||
|
||||
async def send_request(network: Network, servers: List[str], method: str, params: Sequence):
|
||||
print(f"contacting {len(servers)} servers")
|
||||
num_connecting = len(network.connecting)
|
||||
for server in servers:
|
||||
network._start_interface(server)
|
||||
# sleep a bit
|
||||
for _ in range(10):
|
||||
if len(network.connecting) < num_connecting:
|
||||
break
|
||||
await asyncio.sleep(1)
|
||||
print(f"connected to {len(network.interfaces)} servers. sending request to all.")
|
||||
responses = dict()
|
||||
async def get_response(iface: Interface):
|
||||
try:
|
||||
res = await iface.session.send_request(method, params, timeout=10)
|
||||
except Exception as e:
|
||||
print(f"server {iface.server} errored or timed out: ({repr(e)})")
|
||||
res = e
|
||||
responses[iface.server] = res
|
||||
async with TaskGroup() as group:
|
||||
for interface in network.interfaces.values():
|
||||
await group.spawn(get_response(interface))
|
||||
print("%d answers" % len(responses))
|
||||
return responses
|
|
@ -1,405 +1,14 @@
|
|||
{
|
||||
"3smoooajg7qqac2y.onion": {
|
||||
"spv1.lbry.com": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
"version": "1.2"
|
||||
},
|
||||
"81-7-10-251.blue.kundencontroller.de": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"E-X.not.fyi": {
|
||||
"lbryumx2.lbry.io": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"VPS.hsmiths.com": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"b.ooze.cc": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"bauerjda5hnedjam.onion": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"bauerjhejlv6di7s.onion": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"bitcoin.corgi.party": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"bitcoin3nqy3db7c.onion": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"bitcoins.sk": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"btc.cihar.com": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"btc.xskyx.net": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"currentlane.lovebitco.in": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"daedalus.bauerj.eu": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum.jochen-hoenicke.de": {
|
||||
"pruning": "-",
|
||||
"s": "50005",
|
||||
"t": "50003",
|
||||
"version": "1.4"
|
||||
},
|
||||
"dragon085.startdedicated.de": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"e-1.claudioboxx.com": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"e.keff.org": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum-server.ninja": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum-unlimited.criptolayer.net": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum.eff.ro": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum.festivaldelhumor.org": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum.hsmiths.com": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum.leblancnet.us": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum.mindspot.org": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum.qtornado.com": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum.taborsky.cz": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum.villocq.com": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum2.eff.ro": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum2.villocq.com": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrumx.bot.nu": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrumx.ddns.net": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrumx.ftp.sh": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrumx.soon.it": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrumxhqdsmlu.onion": {
|
||||
"pruning": "-",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"elx01.knas.systems": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"enode.duckdns.org": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"fedaykin.goip.de": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"fn.48.org": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50003",
|
||||
"version": "1.4"
|
||||
},
|
||||
"helicarrier.bauerj.eu": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"hsmiths4fyqlw5xw.onion": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"hsmiths5mjk6uijs.onion": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum.emzy.de": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"ndnd.selfhost.eu": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"ndndword5lpb7eex.onion": {
|
||||
"pruning": "-",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"orannis.com": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"ozahtqwp25chjdjd.onion": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"qtornadoklbgdyww.onion": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"rbx.curalle.ovh": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"s7clinmo4cazmhul.onion": {
|
||||
"pruning": "-",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"tardis.bauerj.eu": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"technetium.network": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"tomscryptos.com": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"ulrichard.ch": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"vmd27610.contaboserver.net": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"vmd30612.contaboserver.net": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"wsw6tua3xl24gsmi264zaep6seppjyrkyucpsmuxnjzyt3f3j6swshad.onion": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"xray587.startdedicated.de": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"yuio.top": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"bitcoin.dragon.zone": {
|
||||
"pruning": "-",
|
||||
"s": "50004",
|
||||
"t": "50003",
|
||||
"version": "1.4"
|
||||
},
|
||||
"ecdsa.net" : {
|
||||
"pruning": "-",
|
||||
"s": "110",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"btc.usebsv.com": {
|
||||
"pruning": "-",
|
||||
"s": "50006",
|
||||
"version": "1.4"
|
||||
},
|
||||
"e2.keff.org": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum.hodlister.co": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum3.hodlister.co": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrum5.hodlister.co": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrumx.electricnewyear.net": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"version": "1.4"
|
||||
},
|
||||
"fortress.qtornado.com": {
|
||||
"pruning": "-",
|
||||
"s": "443",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"green-gold.westeurope.cloudapp.azure.com": {
|
||||
"pruning": "-",
|
||||
"s": "56002",
|
||||
"t": "56001",
|
||||
"version": "1.4"
|
||||
},
|
||||
"electrumx.erbium.eu": {
|
||||
"pruning": "-",
|
||||
"s": "50002",
|
||||
"t": "50001",
|
||||
"version": "1.4"
|
||||
"version": "1.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,13 +23,12 @@ FEE_DEPTH_TARGETS = [10000000, 5000000, 2000000, 1000000, 500000, 200000, 100000
|
|||
FEE_LN_ETA_TARGET = 2 # note: make sure the network is asking for estimates for this target
|
||||
|
||||
# satoshi per kbyte
|
||||
FEERATE_MAX_DYNAMIC = 1500000
|
||||
FEERATE_MAX_DYNAMIC = 50000
|
||||
FEERATE_WARNING_HIGH_FEE = 600000
|
||||
FEERATE_FALLBACK_STATIC_FEE = 150000
|
||||
FEERATE_DEFAULT_RELAY = 1000
|
||||
FEERATE_MAX_RELAY = 50000
|
||||
FEERATE_STATIC_VALUES = [1000, 2000, 5000, 10000, 20000, 30000,
|
||||
50000, 70000, 100000, 150000, 200000, 300000]
|
||||
FEERATE_FALLBACK_STATIC_FEE = 50000
|
||||
FEERATE_DEFAULT_RELAY = 50000
|
||||
FEERATE_STATIC_VALUES = [50000,100000]
|
||||
|
||||
FEERATE_REGTEST_HARDCODED = 180000 # for eclair compat
|
||||
|
||||
|
||||
|
@ -197,7 +196,7 @@ class SimpleConfig(Logger):
|
|||
base_unit = self.user_config.get('base_unit')
|
||||
if isinstance(base_unit, str):
|
||||
self._set_key_in_user_config('base_unit', None)
|
||||
map_ = {'btc':8, 'mbtc':5, 'ubtc':2, 'bits':2, 'sat':0}
|
||||
map_ = {'lbc':8, 'mlbc':5, 'ulbc':2, 'lbcs':2, 'dewey':0}
|
||||
decimal_point = map_.get(base_unit.lower())
|
||||
self._set_key_in_user_config('decimal_point', decimal_point)
|
||||
|
||||
|
|
|
@ -68,11 +68,11 @@ def inv_dict(d):
|
|||
ca_path = certifi.where()
|
||||
|
||||
|
||||
base_units = {'BTC':8, 'mBTC':5, 'bits':2, 'sat':0}
|
||||
base_units = {'LBC':8, 'mLBC':5, 'deweys':2, 'dewey':0}
|
||||
base_units_inverse = inv_dict(base_units)
|
||||
base_units_list = ['BTC', 'mBTC', 'bits', 'sat'] # list(dict) does not guarantee order
|
||||
base_units_list = ['LBC', 'mLBC', 'deweys', 'dewey'] # list(dict) does not guarantee order
|
||||
|
||||
DECIMAL_POINT_DEFAULT = 5 # mBTC
|
||||
DECIMAL_POINT_DEFAULT = 8 # mBTC
|
||||
|
||||
# types of payment requests
|
||||
PR_TYPE_ONCHAIN = 0
|
||||
|
@ -554,9 +554,9 @@ def user_dir():
|
|||
elif os.name == 'posix':
|
||||
return os.path.join(os.environ["HOME"], ".electrum")
|
||||
elif "APPDATA" in os.environ:
|
||||
return os.path.join(os.environ["APPDATA"], "Electrum")
|
||||
return os.path.join(os.environ["APPDATA"], "Electrum-lbry")
|
||||
elif "LOCALAPPDATA" in os.environ:
|
||||
return os.path.join(os.environ["LOCALAPPDATA"], "Electrum")
|
||||
return os.path.join(os.environ["LOCALAPPDATA"], "Electrum-lbry")
|
||||
else:
|
||||
#raise Exception("No home directory found in environment variables.")
|
||||
return
|
||||
|
@ -721,39 +721,7 @@ def time_difference(distance_in_time, include_seconds):
|
|||
return "over %d years" % (round(distance_in_minutes / 525600))
|
||||
|
||||
mainnet_block_explorers = {
|
||||
'Bitupper Explorer': ('https://bitupper.com/en/explorer/bitcoin/',
|
||||
{'tx': 'transactions/', 'addr': 'addresses/'}),
|
||||
'Bitflyer.jp': ('https://chainflyer.bitflyer.jp/',
|
||||
{'tx': 'Transaction/', 'addr': 'Address/'}),
|
||||
'Blockchain.info': ('https://blockchain.com/btc/',
|
||||
{'tx': 'tx/', 'addr': 'address/'}),
|
||||
'blockchainbdgpzk.onion': ('https://blockchainbdgpzk.onion/',
|
||||
{'tx': 'tx/', 'addr': 'address/'}),
|
||||
'Blockstream.info': ('https://blockstream.info/',
|
||||
{'tx': 'tx/', 'addr': 'address/'}),
|
||||
'Bitaps.com': ('https://btc.bitaps.com/',
|
||||
{'tx': '', 'addr': ''}),
|
||||
'BTC.com': ('https://btc.com/',
|
||||
{'tx': '', 'addr': ''}),
|
||||
'Chain.so': ('https://www.chain.so/',
|
||||
{'tx': 'tx/BTC/', 'addr': 'address/BTC/'}),
|
||||
'Insight.is': ('https://insight.bitpay.com/',
|
||||
{'tx': 'tx/', 'addr': 'address/'}),
|
||||
'TradeBlock.com': ('https://tradeblock.com/blockchain/',
|
||||
{'tx': 'tx/', 'addr': 'address/'}),
|
||||
'BlockCypher.com': ('https://live.blockcypher.com/btc/',
|
||||
{'tx': 'tx/', 'addr': 'address/'}),
|
||||
'Blockchair.com': ('https://blockchair.com/bitcoin/',
|
||||
{'tx': 'transaction/', 'addr': 'address/'}),
|
||||
'blockonomics.co': ('https://www.blockonomics.co/',
|
||||
{'tx': 'api/tx?txid=', 'addr': '#/search?q='}),
|
||||
'OXT.me': ('https://oxt.me/',
|
||||
{'tx': 'transaction/', 'addr': 'address/'}),
|
||||
'smartbit.com.au': ('https://www.smartbit.com.au/',
|
||||
{'tx': 'tx/', 'addr': 'address/'}),
|
||||
'mynode.local': ('http://mynode.local:3002/',
|
||||
{'tx': 'tx/', 'addr': 'address/'}),
|
||||
'system default': ('blockchain:/',
|
||||
'LBRY Explorer': ('https://explorer.lbry.io/',
|
||||
{'tx': 'tx/', 'addr': 'address/'}),
|
||||
}
|
||||
|
||||
|
@ -778,7 +746,7 @@ def block_explorer_info():
|
|||
|
||||
def block_explorer(config: 'SimpleConfig') -> str:
|
||||
from . import constants
|
||||
default_ = 'Blockstream.info'
|
||||
default_ = 'LBRY Explorer'
|
||||
be_key = config.get('block_explorer', default_)
|
||||
be = block_explorer_info().get(be_key)
|
||||
return be_key if be is not None else default_
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
ELECTRUM_VERSION = '4.0.0a0' # version of the client package
|
||||
APK_VERSION = '4.0.0.0' # read by buildozer.spec
|
||||
|
||||
PROTOCOL_VERSION = '1.4' # protocol version requested
|
||||
PROTOCOL_VERSION = '1.2' # protocol version requested
|
||||
|
||||
# The hash of the mnemonic seed must begin with this
|
||||
SEED_PREFIX = '01' # Standard wallet
|
||||
|
|
128
electrum/websockets.py
Normal file
|
@ -0,0 +1,128 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Electrum - lightweight Bitcoin client
|
||||
# Copyright (C) 2015 Thomas Voegtlin
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person
|
||||
# obtaining a copy of this software and associated documentation files
|
||||
# (the "Software"), to deal in the Software without restriction,
|
||||
# including without limitation the rights to use, copy, modify, merge,
|
||||
# publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
# and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
import threading
|
||||
import os
|
||||
import json
|
||||
from collections import defaultdict
|
||||
import asyncio
|
||||
from typing import Dict, List, Tuple, TYPE_CHECKING
|
||||
import traceback
|
||||
import sys
|
||||
|
||||
try:
|
||||
from SimpleWebSocketServer import WebSocket, SimpleSSLWebSocketServer
|
||||
except ImportError:
|
||||
sys.exit("install SimpleWebSocketServer")
|
||||
|
||||
from .util import PrintError
|
||||
from . import bitcoin
|
||||
from .synchronizer import SynchronizerBase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .network import Network
|
||||
from .simple_config import SimpleConfig
|
||||
|
||||
|
||||
request_queue = asyncio.Queue()
|
||||
|
||||
|
||||
class ElectrumWebSocket(WebSocket, PrintError):
|
||||
|
||||
def handleMessage(self):
|
||||
assert self.data[0:3] == 'id:'
|
||||
self.print_error("message received", self.data)
|
||||
request_id = self.data[3:]
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
request_queue.put((self, request_id)), asyncio.get_event_loop())
|
||||
|
||||
def handleConnected(self):
|
||||
self.print_error("connected", self.address)
|
||||
|
||||
def handleClose(self):
|
||||
self.print_error("closed", self.address)
|
||||
|
||||
|
||||
class BalanceMonitor(SynchronizerBase):
|
||||
|
||||
def __init__(self, config: 'SimpleConfig', network: 'Network'):
|
||||
SynchronizerBase.__init__(self, network)
|
||||
self.config = config
|
||||
self.expected_payments = defaultdict(list) # type: Dict[str, List[Tuple[WebSocket, int]]]
|
||||
|
||||
def make_request(self, request_id):
|
||||
# read json file
|
||||
rdir = self.config.get('requests_dir')
|
||||
n = os.path.join(rdir, 'req', request_id[0], request_id[1], request_id, request_id + '.json')
|
||||
with open(n, encoding='utf-8') as f:
|
||||
s = f.read()
|
||||
d = json.loads(s)
|
||||
addr = d.get('address')
|
||||
amount = d.get('amount')
|
||||
return addr, amount
|
||||
|
||||
async def main(self):
|
||||
# resend existing subscriptions if we were restarted
|
||||
for addr in self.expected_payments:
|
||||
await self._add_address(addr)
|
||||
# main loop
|
||||
while True:
|
||||
ws, request_id = await request_queue.get()
|
||||
try:
|
||||
addr, amount = self.make_request(request_id)
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
continue
|
||||
self.expected_payments[addr].append((ws, amount))
|
||||
await self._add_address(addr)
|
||||
|
||||
async def _on_address_status(self, addr, status):
|
||||
self.print_error('new status for addr {}'.format(addr))
|
||||
sh = bitcoin.address_to_scripthash(addr)
|
||||
balance = await self.network.get_balance_for_scripthash(sh)
|
||||
for ws, amount in self.expected_payments[addr]:
|
||||
if not ws.closed:
|
||||
if sum(balance.values()) >= amount:
|
||||
ws.sendMessage('paid')
|
||||
|
||||
|
||||
class WebSocketServer(threading.Thread):
|
||||
|
||||
def __init__(self, config: 'SimpleConfig', network: 'Network'):
|
||||
threading.Thread.__init__(self)
|
||||
self.config = config
|
||||
self.network = network
|
||||
asyncio.set_event_loop(network.asyncio_loop)
|
||||
self.daemon = True
|
||||
self.balance_monitor = BalanceMonitor(self.config, self.network)
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
asyncio.set_event_loop(self.network.asyncio_loop)
|
||||
host = self.config.get('websocket_server')
|
||||
port = self.config.get('websocket_port', 9999)
|
||||
certfile = self.config.get('ssl_chain')
|
||||
keyfile = self.config.get('ssl_privkey')
|
||||
self.server = SimpleSSLWebSocketServer(host, port, ElectrumWebSocket, certfile, keyfile)
|
||||
self.server.serveforever()
|
67
icons.qrc
Normal file
|
@ -0,0 +1,67 @@
|
|||
<RCC>
|
||||
<qresource prefix="/" >
|
||||
<file>icons/electrum.png</file>
|
||||
<file>icons/clock1.png</file>
|
||||
<file>icons/clock2.png</file>
|
||||
<file>icons/clock3.png</file>
|
||||
<file>icons/clock4.png</file>
|
||||
<file>icons/clock5.png</file>
|
||||
<file>icons/confirmed.png</file>
|
||||
<file>icons/copy.png</file>
|
||||
<file>icons/digitalbitbox.png</file>
|
||||
<file>icons/digitalbitbox_unpaired.png</file>
|
||||
<file>icons/expired.png</file>
|
||||
<file>icons/electrum_light_icon.png</file>
|
||||
<file>icons/electrum_dark_icon.png</file>
|
||||
<file>icons/electrumb.png</file>
|
||||
<file>icons/eye1.png</file>
|
||||
<file>icons/file.png</file>
|
||||
<file>icons/info.png</file>
|
||||
<file>icons/keepkey.png</file>
|
||||
<file>icons/keepkey_unpaired.png</file>
|
||||
<file>icons/key.png</file>
|
||||
<file>icons/ledger.png</file>
|
||||
<file>icons/ledger_unpaired.png</file>
|
||||
<file>icons/lock.png</file>
|
||||
<file>icons/microphone.png</file>
|
||||
<file>icons/network.png</file>
|
||||
<file>icons/offline_tx.png</file>
|
||||
<file>icons/revealer.png</file>
|
||||
<file>icons/revealer_c.png</file>
|
||||
<file>icons/qrcode.png</file>
|
||||
<file>icons/qrcode_white.png</file>
|
||||
<file>icons/preferences.png</file>
|
||||
<file>icons/safe-t_unpaired.png</file>
|
||||
<file>icons/safe-t.png</file>
|
||||
<file>icons/seed.png</file>
|
||||
<file>icons/status_connected.png</file>
|
||||
<file>icons/status_connected_fork.png</file>
|
||||
<file>icons/status_connected_proxy.png</file>
|
||||
<file>icons/status_connected_proxy_fork.png</file>
|
||||
<file>icons/status_disconnected.png</file>
|
||||
<file>icons/status_waiting.png</file>
|
||||
<file>icons/status_lagging.png</file>
|
||||
<file>icons/status_lagging_fork.png</file>
|
||||
<file>icons/seal.png</file>
|
||||
<file>icons/tab_addresses.png</file>
|
||||
<file>icons/tab_coins.png</file>
|
||||
<file>icons/tab_console.png</file>
|
||||
<file>icons/tab_contacts.png</file>
|
||||
<file>icons/tab_history.png</file>
|
||||
<file>icons/tab_receive.png</file>
|
||||
<file>icons/tab_send.png</file>
|
||||
<file>icons/tor_logo.png</file>
|
||||
<file>icons/speaker.png</file>
|
||||
<file>icons/trezor_unpaired.png</file>
|
||||
<file>icons/trezor.png</file>
|
||||
<file>icons/coldcard.png</file>
|
||||
<file>icons/coldcard_unpaired.png</file>
|
||||
<file>icons/trustedcoin-status.png</file>
|
||||
<file>icons/trustedcoin-wizard.png</file>
|
||||
<file>icons/unconfirmed.png</file>
|
||||
<file>icons/unpaid.png</file>
|
||||
<file>icons/unlock.png</file>
|
||||
<file>icons/warning.png</file>
|
||||
<file>icons/zoom.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
BIN
icons/clock1.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
icons/clock2.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
icons/clock3.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
icons/clock4.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
icons/clock5.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
icons/coldcard.png
Normal file
After Width: | Height: | Size: 528 B |
BIN
icons/coldcard_unpaired.png
Normal file
After Width: | Height: | Size: 788 B |
BIN
icons/confirmed.png
Normal file
After Width: | Height: | Size: 53 KiB |
44
icons/confirmed.svg
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- https://commons.wikimedia.org/wiki/File:CrystalClearActionApply.svg -->
|
||||
<svg width="512" height="512" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<linearGradient id="linearGradient3930">
|
||||
<stop style="stop-color:#ffffff;stop-opacity:1" offset="0"/>
|
||||
<stop style="stop-color:#b3d187;stop-opacity:1" offset="0.53316939"/>
|
||||
<stop style="stop-color:#28f400;stop-opacity:1" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3904">
|
||||
<stop style="stop-color:#4df60b;stop-opacity:1" offset="0"/>
|
||||
<stop style="stop-color:#008000;stop-opacity:1" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3878">
|
||||
<stop style="stop-color:#79ef39;stop-opacity:1" offset="0"/>
|
||||
<stop style="stop-color:#e9ffe3;stop-opacity:1" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3044">
|
||||
<stop style="stop-color:#f9ffd1;stop-opacity:1" offset="0"/>
|
||||
<stop style="stop-color:#84e246;stop-opacity:1" offset="0.25998953"/>
|
||||
<stop style="stop-color:#008000;stop-opacity:1" offset="1"/>
|
||||
</linearGradient>
|
||||
<radialGradient cx="60.764378" cy="104.22466" r="63.17857" fx="60.764378" fy="104.22466" id="radialGradient3838" xlink:href="#linearGradient3044" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.85744972,-0.78795737,0.89944031,0.97876469,-84.596269,34.939755)"/>
|
||||
<radialGradient cx="145" cy="29" r="230" id="radialGradient3838-0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.66070117,-0.56004574,0.69392651,0.81864398,-39.045089,37.984063)">
|
||||
<stop style="stop-color:#FFFFFF;stop-opacity:1" offset="0"/>
|
||||
<stop style="stop-color:#FFFFFF;stop-opacity:1" offset="0.20"/>
|
||||
<stop style="stop-color:#8BE456;stop-opacity:1" offset="0.51"/>
|
||||
<stop style="stop-color:#8BE456;stop-opacity:1" offset="0.74"/>
|
||||
<stop style="stop-color:#8BE456;stop-opacity:1" offset="1"/>
|
||||
</radialGradient>
|
||||
<radialGradient cx="48.356026" cy="122.04626" r="63.17857" fx="48.356026" fy="122.04626" id="radialGradient3838-4" xlink:href="#linearGradient3904" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.97494521,-0.22244513,0.1978519,0.86715661,-18.612993,12.209071)"/>
|
||||
<radialGradient cx="57.965954" cy="109.5996" r="63.17857" fx="57.965954" fy="109.5996" id="radialGradient3838-5" xlink:href="#linearGradient3930" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.77328328,-0.70601122,0.71173774,0.77955545,-64.080277,49.199946)"/>
|
||||
</defs>
|
||||
<g>
|
||||
<path d="M 24.642857,32.642859 1.4285714,54.07143 51.071429,97.285716 126.78571,31.57143 l -22.5,-20 -52.142853,47.142858 z" id="path2997-1" style="fill:url(#radialGradient3838);fill-opacity:1;stroke:none"/>
|
||||
<path d="M 1.4285714,54.428573 51.071429,97.64286 126.78571,31.928573 126.86922,40.559647 51.78571,108.71429 1.77525,63.026751 z" id="path2997-7" style="color:#000000;fill:url(#radialGradient3838-4);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"/>
|
||||
<path d="m 24.285714,39.785715 27.5,25.000001 52.142856,-46.428569 15.71429,14.64285 c 0,0 -14.28571,12.857149 -28.928573,25.714289 -14.642854,12.85714 -54.642859,15 -80.7142871,-5.71429 C 20.357143,43.714286 24.285714,39.785715 24.285714,39.785715 z" id="path3042" style="color:#000000;fill:url(#radialGradient3838-0);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"/>
|
||||
<path d="M 1.4285714,54.07143 51.071429,97.285716 126.78571,31.57143 51.071424,101.21429 z" id="path2997" style="color:#000000;fill:url(#radialGradient3838-5);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.1 KiB |
BIN
icons/copy.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
icons/digitalbitbox.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
icons/digitalbitbox_unpaired.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
icons/electrum.ico
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
icons/electrum.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
icons/electrum_dark_icon.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
icons/electrum_launcher.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
icons/electrum_light_icon.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
icons/electrum_presplash.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
icons/electrumb.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
icons/expired.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
icons/eye1.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
icons/file.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
icons/info.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
icons/keepkey.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
icons/keepkey_unpaired.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
icons/key.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
icons/ledger.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
icons/ledger_unpaired.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
icons/lock.png
Normal file
After Width: | Height: | Size: 39 KiB |
277
icons/lock.svg
Normal file
|
@ -0,0 +1,277 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.0"
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 22 22"
|
||||
id="svg2">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
id="linearGradient2411">
|
||||
<stop
|
||||
id="stop2413"
|
||||
style="stop-color:#fee7b1;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop2419"
|
||||
style="stop-color:#ebd4b4;stop-opacity:1"
|
||||
offset="0.25796592" />
|
||||
<stop
|
||||
id="stop2421"
|
||||
style="stop-color:#c8a775;stop-opacity:1"
|
||||
offset="0.50796592" />
|
||||
<stop
|
||||
id="stop2423"
|
||||
style="stop-color:#b0935b;stop-opacity:1"
|
||||
offset="0.74009573" />
|
||||
<stop
|
||||
id="stop2415"
|
||||
style="stop-color:#fcebbf;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="6.72682"
|
||||
y1="32.161697"
|
||||
x2="40.938126"
|
||||
y2="32.161697"
|
||||
id="linearGradient2576"
|
||||
xlink:href="#linearGradient2411"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.4857987,0,0,0.5667573,-0.657656,-4.7557638)" />
|
||||
<linearGradient
|
||||
id="linearGradient9845">
|
||||
<stop
|
||||
id="stop9847"
|
||||
style="stop-color:white;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop9849"
|
||||
style="stop-color:white;stop-opacity:0.49484536"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="10.907269"
|
||||
y1="25.002281"
|
||||
x2="30.875446"
|
||||
y2="36.127281"
|
||||
id="linearGradient2573"
|
||||
xlink:href="#linearGradient9845"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.4541292,0,0,0.5078849,0.107594,-1.9931168)" />
|
||||
<linearGradient
|
||||
id="linearGradient5881">
|
||||
<stop
|
||||
id="stop5883"
|
||||
style="stop-color:#d6c8a7;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop5885"
|
||||
style="stop-color:#d0bd99;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="24.875"
|
||||
y1="21"
|
||||
x2="24.75"
|
||||
y2="17"
|
||||
id="linearGradient2570"
|
||||
xlink:href="#linearGradient5881"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.4705882,0,0,0.807484,-0.294082,-6.1887078)" />
|
||||
<linearGradient
|
||||
id="linearGradient12071">
|
||||
<stop
|
||||
id="stop12073"
|
||||
style="stop-color:white;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop12075"
|
||||
style="stop-color:white;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="21.941509"
|
||||
y1="21.550869"
|
||||
x2="21.941509"
|
||||
y2="18.037588"
|
||||
id="linearGradient2567"
|
||||
xlink:href="#linearGradient12071"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.4545455,0,0,0.2515938,0.090945,5.0971072)" />
|
||||
<filter
|
||||
x="-0.49411765"
|
||||
y="-0.082352944"
|
||||
width="1.9882354"
|
||||
height="1.1647059"
|
||||
color-interpolation-filters="sRGB"
|
||||
id="filter5957">
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur5959"
|
||||
stdDeviation="0.69878785" />
|
||||
</filter>
|
||||
<radialGradient
|
||||
cx="15.9375"
|
||||
cy="20.3125"
|
||||
r="3.3125"
|
||||
fx="15.9375"
|
||||
fy="20.3125"
|
||||
id="radialGradient2563"
|
||||
xlink:href="#linearGradient6075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.7547171,0,0,0.3566673,-5.528266,1.0326108)" />
|
||||
<linearGradient
|
||||
id="linearGradient6075">
|
||||
<stop
|
||||
id="stop6077"
|
||||
style="stop-color:black;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop6079"
|
||||
style="stop-color:black;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
cx="15.9375"
|
||||
cy="20.3125"
|
||||
r="3.3125"
|
||||
fx="15.9375"
|
||||
fy="20.3125"
|
||||
id="radialGradient2560"
|
||||
xlink:href="#linearGradient6075"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.7547175,0,0,0.3566673,3.471729,1.0326108)" />
|
||||
<linearGradient
|
||||
id="linearGradient10591">
|
||||
<stop
|
||||
id="stop10593"
|
||||
style="stop-color:#cad0c6;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop10599"
|
||||
style="stop-color:#eaece9;stop-opacity:1"
|
||||
offset="0.5" />
|
||||
<stop
|
||||
id="stop10595"
|
||||
style="stop-color:#c5cbc0;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="10.650842"
|
||||
y1="2.9136841"
|
||||
x2="27.192274"
|
||||
y2="17.470011"
|
||||
id="linearGradient2557"
|
||||
xlink:href="#linearGradient10591"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.4093677,0,0,0.4456702,1.146515,-1.679622)" />
|
||||
<linearGradient
|
||||
x1="35.004684"
|
||||
y1="14.849737"
|
||||
x2="33.004314"
|
||||
y2="14.849737"
|
||||
id="linearGradient2580"
|
||||
xlink:href="#linearGradient6227"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(1.6824037,1.125)" />
|
||||
<filter
|
||||
x="-0.24242526"
|
||||
y="-0.047579072"
|
||||
width="1.4848505"
|
||||
height="1.0951581"
|
||||
color-interpolation-filters="sRGB"
|
||||
id="filter6251">
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur6253"
|
||||
stdDeviation="0.24444548" />
|
||||
</filter>
|
||||
<linearGradient
|
||||
id="linearGradient6227">
|
||||
<stop
|
||||
id="stop6229"
|
||||
style="stop-color:black;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop6231"
|
||||
style="stop-color:black;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="32.128025"
|
||||
y1="13.789077"
|
||||
x2="35.020981"
|
||||
y2="13.789077"
|
||||
id="linearGradient2578"
|
||||
xlink:href="#linearGradient6227"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-19.532826,1.7437184)" />
|
||||
<filter
|
||||
color-interpolation-filters="sRGB"
|
||||
id="filter5745">
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur5747"
|
||||
stdDeviation="0.8362597" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
id="layer1">
|
||||
<path
|
||||
d="m 3.585783,7.0017592 c 4.897701,-0.724037 9.847515,-0.611633 14.828433,0 0.601506,0 1.085748,0.523475 1.085748,1.173711 l 0,11.6979168 c 0,0.650237 -0.515495,1.079658 -1.085748,1.173711 -5.164043,0.60626 -9.5918631,0.601474 -14.828433,0 C 2.890521,20.827641 2.500036,20.523624 2.500036,19.873387 l 0,-11.6979168 c 0,-0.650236 0.484243,-1.173711 1.085747,-1.173711 z"
|
||||
id="rect1314"
|
||||
style="fill:url(#linearGradient2576);fill-opacity:1;fill-rule:evenodd;stroke:#a2824e;stroke-width:0.99999946;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0" />
|
||||
<path
|
||||
d="m 4.085707,8.5000012 13.828656,0 c 0.324462,0 0.585672,0.266352 0.585672,0.597203 l 0,10.3958448 c 0,0.33085 -0.231917,0.483593 -0.585672,0.597203 -4.521671,0.546964 -8.9847586,0.545698 -13.828656,0 -0.324462,-0.11361 -0.585671,-0.266353 -0.585671,-0.597203 l 0,-10.3958448 c 0,-0.330851 0.261209,-0.597203 0.585671,-0.597203 z"
|
||||
id="rect6903"
|
||||
style="opacity:0.37999998;fill:none;stroke:url(#linearGradient2573);stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.60109289;stroke-dashoffset:0" />
|
||||
<path
|
||||
d="m 3.779465,7.5385202 c 4.8137134,-0.786353 9.627427,-0.646293 14.441141,0 0.431803,0 0.77943,0.386003 0.77943,0.865475 l 0,1.498987 c 0,0.4794728 -0.347627,0.8654758 -0.77943,0.8654758 -5.023394,0.371496 -9.6453579,0.238912 -14.441141,0 -0.431804,0 -0.779429,-0.386003 -0.779429,-0.8654758 l 0,-1.498987 c 0,-0.479472 0.347625,-0.865475 0.779429,-0.865475 z"
|
||||
id="rect1460"
|
||||
style="fill:url(#linearGradient2570);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible" />
|
||||
<path
|
||||
d="m 4.045579,9.4999992 13.908915,0 c 0.30223,0 0.545542,0.129295 0.545542,0.289899 l 0,0.174986 c 0,0.1606028 -0.243312,0.2898978 -0.545542,0.2898978 -4.593039,0.317179 -9.2379615,0.33659 -13.908915,0 -0.302231,0 -0.545543,-0.129295 -0.545543,-0.2898978 l 0,-0.174986 c 0,-0.160604 0.243312,-0.289899 0.545543,-0.289899 z"
|
||||
id="rect1593"
|
||||
style="opacity:0.6;fill:none;stroke:url(#linearGradient2567);stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
|
||||
<rect
|
||||
width="2.8284271"
|
||||
height="16.970562"
|
||||
rx="1.6077254"
|
||||
ry="1.6077254"
|
||||
x="14.594036"
|
||||
y="23.226137"
|
||||
transform="matrix(0.923405,0,0,0.5777374,-8.226979,-3.3564678)"
|
||||
id="rect5887"
|
||||
style="opacity:0.2;fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter5957);enable-background:accumulate" />
|
||||
<path
|
||||
d="m 9.0000359,8.2774169 c 0,0.6525027 -1.1192909,1.1814597 -2.4999999,1.1814597 -1.380712,0 -2.5,-0.528957 -2.5,-1.1814597 0,-0.6525037 1.119288,-1.1814615 2.5,-1.1814615 1.380709,0 2.4999999,0.5289578 2.4999999,1.1814615 z"
|
||||
id="path6073"
|
||||
style="opacity:0.3;fill:url(#radialGradient2563);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
d="m 18.000036,8.2774169 c 0,0.6525027 -1.119288,1.1814597 -2.500001,1.1814597 -1.380712,0 -2.499999,-0.528957 -2.499999,-1.1814597 0,-0.6525037 1.119287,-1.1814615 2.499999,-1.1814615 1.380713,0 2.500001,0.5289578 2.500001,1.1814615 z"
|
||||
id="path6083"
|
||||
style="opacity:0.3;fill:url(#radialGradient2560);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
d="m 5.502269,8.1969323 0,-2.55585 c 0,-3.5074844 2.152214,-5.17378339 5.477269,-5.1299805 3.343147,0.0438029 5.518265,1.5812319 5.518265,5.1299805 l 0,2.6672674 c 0,0.8709416 -2.247715,0.98179 -2.247715,0 l 0,-1.7759272 c 0,-0.8913402 0.232705,-3.7756533 -3.247128,-3.7756533 -3.45114,0 -3.19968,2.9020879 -3.186298,3.7720995 l 0,1.6830728 c 0,1.0493847 -2.314393,1.0449226 -2.314393,-0.015009 z"
|
||||
id="path2086"
|
||||
style="fill:url(#linearGradient2557);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:0.99999946;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<path
|
||||
d="m 34.687087,10.837069 1.263948,0.125 c 0.927239,2.822733 0.736052,9.510413 0.736052,9.510413 -0.0625,1.125 -2.03125,0.53125 -2,0 l 0,-9.635413 z"
|
||||
transform="matrix(0.4093677,0,0,0.4456703,1.146515,-0.8211368)"
|
||||
id="rect1345"
|
||||
style="opacity:0.18235294;fill:url(#linearGradient2580);fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter6251)" />
|
||||
<path
|
||||
d="m 12.926606,11.544175 0.371719,0.169195 c 1.720331,1.054966 2.173532,9.37783 2.173532,9.37783 -0.0625,1.125 -2.03125,0.53125 -2,0 0,0 0.37822,-6.87064 -0.545251,-9.547025 z"
|
||||
transform="matrix(-0.4093677,0,0,0.4456703,13.04224,-1.0968812)"
|
||||
id="path6332"
|
||||
style="opacity:0.14117647;fill:url(#linearGradient2578);fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter6251)" />
|
||||
<path
|
||||
d="m 13.876557,17.722122 0.124999,-7.5 c 0,-9.8763728 18.6875,-10.6764 18.6875,0.875 l 0,6.875"
|
||||
transform="matrix(0.459148,0,0,0.4456703,-0.021657,0.2462079)"
|
||||
id="path5675"
|
||||
style="opacity:0.62352941;fill:none;stroke:white;stroke-width:4.42126894;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter5745);enable-background:accumulate" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
BIN
icons/microphone.png
Normal file
After Width: | Height: | Size: 199 B |
BIN
icons/network.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
icons/offline_tx.png
Normal file
After Width: | Height: | Size: 463 B |
BIN
icons/preferences.png
Normal file
After Width: | Height: | Size: 57 KiB |
686
icons/preferences.svg
Normal file
|
@ -0,0 +1,686 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:ns="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="512px"
|
||||
height="512px"
|
||||
id="svg4289"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.45"
|
||||
sodipodi:docbase="https://commons.wikimedia.org/wiki/File:Gnome-preferences-system.svg"
|
||||
sodipodi:docname="preferences-system.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
viewBox="0 0 48 48">
|
||||
<defs
|
||||
id="defs4291">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient6998">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop7000" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop7002" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient5443">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5445" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5447" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient5437">
|
||||
<stop
|
||||
style="stop-color:#2e3436;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop5439" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop5441" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient6791">
|
||||
<stop
|
||||
id="stop6793"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop6795"
|
||||
offset="1"
|
||||
style="stop-color:#ffffff;stop-opacity:0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient6707">
|
||||
<stop
|
||||
id="stop6709"
|
||||
offset="0"
|
||||
style="stop-color:#888a85;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop6711"
|
||||
offset="1"
|
||||
style="stop-color:#555753;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient6696">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop6698" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop6700" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient6576">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop6578" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop6580" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient6545">
|
||||
<stop
|
||||
style="stop-color:#d3d7cf;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop6547" />
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop6549" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient6525">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop6527" />
|
||||
<stop
|
||||
style="stop-color:#babdb6;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop6529" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient6424">
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop6426" />
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop6428" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5440">
|
||||
<stop
|
||||
id="stop5442"
|
||||
offset="0"
|
||||
style="stop-color:#eeeeec;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop5444"
|
||||
offset="1"
|
||||
style="stop-color:#a2a298;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient5402">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5404" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5406" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2808">
|
||||
<stop
|
||||
id="stop2810"
|
||||
offset="0"
|
||||
style="stop-color:white;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop2812"
|
||||
offset="1"
|
||||
style="stop-color:white;stop-opacity:0.2937853" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient6221">
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop6223" />
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop6225" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient5220">
|
||||
<stop
|
||||
style="stop-color:#0c1d35;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop5222" />
|
||||
<stop
|
||||
style="stop-color:white;stop-opacity:0.2937853"
|
||||
offset="1"
|
||||
id="stop5224" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient5210">
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop5212" />
|
||||
<stop
|
||||
style="stop-color:#295ead;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop5214" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6221"
|
||||
id="radialGradient6819"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.982963,0,0,0.508943,0.37414,16.84139)"
|
||||
cx="21.96048"
|
||||
cy="34.498356"
|
||||
fx="21.96048"
|
||||
fy="34.498356"
|
||||
r="12.727922" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6221"
|
||||
id="radialGradient6821"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.982963,0,0,0.508943,0.37414,16.84139)"
|
||||
cx="21.96048"
|
||||
cy="34.498356"
|
||||
fx="21.96048"
|
||||
fy="34.498356"
|
||||
r="12.727922" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6545"
|
||||
id="linearGradient6823"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="101.75"
|
||||
y1="16.75"
|
||||
x2="84.875"
|
||||
y2="23.5" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6707"
|
||||
id="linearGradient6825"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="101.76143"
|
||||
y1="23.366385"
|
||||
x2="84.3106"
|
||||
y2="40.943737" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6791"
|
||||
id="linearGradient6827"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="99.686363"
|
||||
y1="7.6145449"
|
||||
x2="75.039978"
|
||||
y2="16.260931" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6525"
|
||||
id="linearGradient6829"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="94"
|
||||
y1="43.240894"
|
||||
x2="94"
|
||||
y2="40.766018" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5437"
|
||||
id="linearGradient6831"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.9982232,0,0,1.1271997,101.97505,-16.992011)"
|
||||
x1="-5.7610831"
|
||||
y1="40.212852"
|
||||
x2="-12.691682"
|
||||
y2="44.514675" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6576"
|
||||
id="linearGradient6833"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,-58.460697,73.506628)"
|
||||
x1="93.686363"
|
||||
y1="11.614545"
|
||||
x2="96.311363"
|
||||
y2="3.2395456" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6696"
|
||||
id="linearGradient6835"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="19.5"
|
||||
y1="17.750786"
|
||||
x2="19.5"
|
||||
y2="7.8089299"
|
||||
gradientTransform="translate(-1,-1)" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6221"
|
||||
id="radialGradient6837"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.982963,0,0,0.508943,0.37414,16.84139)"
|
||||
cx="21.96048"
|
||||
cy="34.498356"
|
||||
fx="21.96048"
|
||||
fy="34.498356"
|
||||
r="12.727922" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6221"
|
||||
id="radialGradient6839"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.982963,0,0,0.508943,0.37414,16.84139)"
|
||||
cx="21.96048"
|
||||
cy="34.498356"
|
||||
fx="21.96048"
|
||||
fy="34.498356"
|
||||
r="12.727922" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6998"
|
||||
id="radialGradient7004"
|
||||
cx="24.32572"
|
||||
cy="24.577896"
|
||||
fx="24.32572"
|
||||
fy="24.577896"
|
||||
r="5.140625"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.7495432,-0.7495432,1.8567518,1.8567518,-40.477603,-2.5737503)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5210"
|
||||
id="linearGradient7047"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.8213511,0,0,1.0094537,61.676283,-5.2539543)"
|
||||
x1="-10.69499"
|
||||
y1="41.105709"
|
||||
x2="-1.0492263"
|
||||
y2="41.137775" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5443"
|
||||
id="linearGradient7049"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="53.58926"
|
||||
y1="32.856834"
|
||||
x2="69.976395"
|
||||
y2="44.960426" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5440"
|
||||
id="linearGradient7051"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.7118239,-0.7118239,0.7071068,0.7071068,20.979979,22.298119)"
|
||||
x1="24.518135"
|
||||
y1="22.429499"
|
||||
x2="25.910631"
|
||||
y2="23.831284" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2808"
|
||||
id="linearGradient7053"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.581783,0,0,0.6787466,57.543659,10.506054)"
|
||||
x1="-6.9787297"
|
||||
y1="37.126617"
|
||||
x2="-9.9043236"
|
||||
y2="36.848248" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5220"
|
||||
id="linearGradient7055"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.4887947,0,0,0.6787448,59.055567,10.472634)"
|
||||
x1="-8.9375"
|
||||
y1="40.375"
|
||||
x2="-7"
|
||||
y2="40.375" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5402"
|
||||
id="linearGradient7057"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="57.349243"
|
||||
y1="37.496914"
|
||||
x2="59.350101"
|
||||
y2="37.505516" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6424"
|
||||
id="linearGradient7059"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="54.5"
|
||||
y1="1.7340142"
|
||||
x2="54.5"
|
||||
y2="7.1931787" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666"
|
||||
borderopacity="0.31372549"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="4"
|
||||
inkscape:cx="40.725752"
|
||||
inkscape:cy="9.5969463"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:grid-bbox="false"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="897"
|
||||
inkscape:window-height="925"
|
||||
inkscape:window-x="88"
|
||||
inkscape:window-y="25"
|
||||
inkscape:showpageshadow="false"
|
||||
gridspacingx="0.5px"
|
||||
gridspacingy="0.5px"
|
||||
gridempspacing="2"
|
||||
inkscape:grid-points="false"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
showborder="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid5999" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata4294">
|
||||
<rdf:RDF>
|
||||
<ns:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>System Preferences</dc:title>
|
||||
<dc:creator>
|
||||
<ns:Agent>
|
||||
<dc:title>Andreas Nilsson</dc:title>
|
||||
</ns:Agent>
|
||||
</dc:creator>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>category</rdf:li>
|
||||
<rdf:li>system</rdf:li>
|
||||
<rdf:li>preferences</rdf:li>
|
||||
<rdf:li>settings</rdf:li>
|
||||
<rdf:li>control center</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
<dc:contributor>
|
||||
<ns:Agent>
|
||||
<dc:title>Jakub Steiner
|
||||
Ulisse Perusin</dc:title>
|
||||
</ns:Agent>
|
||||
</dc:contributor>
|
||||
<ns:license
|
||||
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
|
||||
</ns:Work>
|
||||
<ns:License
|
||||
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
|
||||
<ns:permits
|
||||
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<ns:permits
|
||||
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<ns:requires
|
||||
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<ns:permits
|
||||
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<ns:requires
|
||||
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
<ns:requires
|
||||
rdf:resource="http://web.resource.org/cc/SourceCode" />
|
||||
</ns:License>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>Preferences</dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Andreas Nilsson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>Lapo Calamandrei, Ulisse Perusin, Jakub Steiner</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>category</rdf:li>
|
||||
<rdf:li>system</rdf:li>
|
||||
<rdf:li>preferences</rdf:li>
|
||||
<rdf:li>settings</rdf:li>
|
||||
<rdf:li>control center</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/SourceCode" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0.15;fill:url(#radialGradient6839);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path5331"
|
||||
sodipodi:cx="21.743534"
|
||||
sodipodi:cy="34.299805"
|
||||
sodipodi:rx="12.727922"
|
||||
sodipodi:ry="6.3639612"
|
||||
d="M 34.471457 34.299805 A 12.727922 6.3639612 0 1 1 9.0156116,34.299805 A 12.727922 6.3639612 0 1 1 34.471457 34.299805 z"
|
||||
transform="matrix(0.9035244,0,0,0.6241817,-8.1457785,20.562958)" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0.2;fill:url(#radialGradient6837);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path6769"
|
||||
sodipodi:cx="21.743534"
|
||||
sodipodi:cy="34.299805"
|
||||
sodipodi:rx="12.727922"
|
||||
sodipodi:ry="6.3639612"
|
||||
d="M 34.471457 34.299805 A 12.727922 6.3639612 0 1 1 9.0156116,34.299805 A 12.727922 6.3639612 0 1 1 34.471457 34.299805 z"
|
||||
transform="matrix(0.3535525,0,0,0.2357023,2.8125306,34.415459)" />
|
||||
<g
|
||||
id="g6432"
|
||||
transform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,0.4039197,-30.117395)">
|
||||
<rect
|
||||
transform="matrix(0.9999917,-4.085772e-3,-2.7048962e-3,0.9999963,0,0)"
|
||||
ry="3.6587055"
|
||||
rx="4.0743828"
|
||||
y="27.726946"
|
||||
x="50.588039"
|
||||
height="17.996519"
|
||||
width="8.9973431"
|
||||
id="rect5288"
|
||||
style="fill:url(#linearGradient7047);fill-opacity:1;stroke:#204a87;stroke-width:1.0000124;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
transform="matrix(0.9999873,-5.0480452e-3,-2.8992949e-3,0.9999958,0,0)"
|
||||
ry="2.5968282"
|
||||
rx="3.0795631"
|
||||
y="28.815769"
|
||||
x="51.574001"
|
||||
height="15.960262"
|
||||
width="7.0178103"
|
||||
id="rect5292"
|
||||
style="opacity:0.5;fill:none;fill-opacity:1;stroke:url(#linearGradient7049);stroke-width:1.00001645;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccccc"
|
||||
id="path5286"
|
||||
d="M 52.246834,0.49999993 L 52.604531,5.4548034 L 53.59322,7.162543 L 53.585977,28.755101 C 53.674365,30.257703 56.419206,30.336084 56.595983,28.745094 L 56.621068,7.1748733 L 57.628707,5.8770552 L 57.95997,0.51454306 C 57.95997,0.51454306 52.246834,0.49999993 52.246834,0.49999993 z "
|
||||
style="fill:url(#linearGradient7051);fill-opacity:1;stroke:#888a85;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:0.3;fill:url(#linearGradient7053);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect2804"
|
||||
width="1.4200811"
|
||||
height="10.612979"
|
||||
x="51.725819"
|
||||
y="32.225933"
|
||||
rx="0.6661315"
|
||||
ry="1.6036282"
|
||||
transform="matrix(0.9999908,-4.299452e-3,-4.299452e-3,0.9999908,0,0)" />
|
||||
<rect
|
||||
transform="matrix(0.9999869,-5.11738e-3,-3.6122511e-3,0.9999935,0,0)"
|
||||
ry="1.6036212"
|
||||
rx="1.3473127"
|
||||
y="32.192463"
|
||||
x="54.167618"
|
||||
height="10.859921"
|
||||
width="1.9551785"
|
||||
id="rect5290"
|
||||
style="opacity:0.3;fill:url(#linearGradient7055);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:0.25;fill:url(#linearGradient7057);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect5398"
|
||||
width="1.420082"
|
||||
height="10.612979"
|
||||
x="57.132236"
|
||||
y="32.24918"
|
||||
rx="0.6661315"
|
||||
ry="1.603629"
|
||||
transform="matrix(0.9999908,-4.2994573e-3,-4.2994573e-3,0.9999908,0,0)" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccccc"
|
||||
id="path5450"
|
||||
d="M 52.78125,1 L 53.09375,5.3125 L 54.03125,6.90625 C 54.073567,6.982692 54.095116,7.0688875 54.09375,7.15625 L 56.125,7.1875 C 56.120433,7.0757816 56.153441,6.9657558 56.21875,6.875 L 57.125,5.65625 L 57.4375,1 C 56.652768,1 53.565982,1 52.78125,1 z "
|
||||
style="fill:url(#linearGradient7059);fill-opacity:1;stroke:none;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" />
|
||||
</g>
|
||||
<path
|
||||
style="opacity:0.5;fill:url(#radialGradient7004);fill-opacity:1;stroke:none;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 25.96875,19.46875 L 18.46875,26.96875 L 21.25,29.75 L 28.75,22.25 L 25.96875,19.46875 z "
|
||||
id="path6010" />
|
||||
<g
|
||||
id="g6807"
|
||||
transform="translate(-1,0)">
|
||||
<path
|
||||
transform="matrix(0.8642397,0,0,0.6241817,18.208399,20.562958)"
|
||||
d="M 34.471457 34.299805 A 12.727922 6.3639612 0 1 1 9.0156116,34.299805 A 12.727922 6.3639612 0 1 1 34.471457 34.299805 z"
|
||||
sodipodi:ry="6.3639612"
|
||||
sodipodi:rx="12.727922"
|
||||
sodipodi:cy="34.299805"
|
||||
sodipodi:cx="21.743534"
|
||||
id="path6765"
|
||||
style="opacity:0.15;fill:url(#radialGradient6819);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="matrix(0.3535525,0,0,0.2357023,29.812531,34.415459)"
|
||||
d="M 34.471457 34.299805 A 12.727922 6.3639612 0 1 1 9.0156116,34.299805 A 12.727922 6.3639612 0 1 1 34.471457 34.299805 z"
|
||||
sodipodi:ry="6.3639612"
|
||||
sodipodi:rx="12.727922"
|
||||
sodipodi:cy="34.299805"
|
||||
sodipodi:cx="21.743534"
|
||||
id="path6773"
|
||||
style="opacity:0.2;fill:url(#radialGradient6821);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
sodipodi:type="arc" />
|
||||
<g
|
||||
transform="translate(-1.697983,0.2707704)"
|
||||
id="g6739">
|
||||
<g
|
||||
id="g6553"
|
||||
transform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,-57.460697,74.506628)">
|
||||
<path
|
||||
sodipodi:nodetypes="csccsccscccccc"
|
||||
id="path6491"
|
||||
d="M 91,1.1482865 C 88.356663,2.3083638 86.5,4.9532014 86.5,8.0232865 C 86.5,10.894407 88.12854,13.387995 90.5,14.648286 L 90.5,43.414214 C 90.5,45.353214 92.061,46.914213 94,46.914214 C 95.939,46.914214 97.5,45.353213 97.5,43.414214 L 97.5,14.648286 C 99.87146,13.387995 101.5,10.894407 101.5,8.0232865 C 101.5,4.9532011 99.643337,2.3083637 97,1.1482865 L 97,7.0857865 L 95.28125,9.0857865 L 92.71875,9.0857865 L 91,7.0857865 L 91,1.1482865 z "
|
||||
style="opacity:1;fill:url(#linearGradient6823);fill-opacity:1;stroke:url(#linearGradient6825);stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.7;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cscccscccscccccccccc"
|
||||
id="path6505"
|
||||
d="M 89.96875,2.9920365 C 88.491165,4.1803215 87.53125,5.9777353 87.53125,8.0232865 C 87.53125,10.510038 88.917637,12.651991 90.96875,13.742036 C 91.312399,13.913596 91.530012,14.264195 91.53125,14.648286 L 91.53125,43.414214 C 91.53125,44.807674 92.606539,45.882963 94,45.882964 C 95.39346,45.882964 96.46875,44.807673 96.46875,43.414214 L 96.46875,14.648286 C 96.469988,14.264195 96.687601,13.913596 97.03125,13.742036 C 99.082363,12.651991 100.46875,10.510038 100.46875,8.0232865 C 100.46875,5.977735 99.508835,4.1803214 98.03125,2.9920365 L 98.03125,7.0857865 C 98.028519,7.3272888 97.939894,7.5599296 97.78125,7.7420365 L 96.0625,9.7420365 C 95.871073,9.9773335 95.584572,10.114853 95.28125,10.117036 L 92.71875,10.117036 C 92.415428,10.114853 92.128927,9.9773335 91.9375,9.7420365 L 90.21875,7.7420365 C 90.060106,7.5599296 89.971481,7.3272888 89.96875,7.0857865 L 89.96875,2.9920365 z "
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:url(#linearGradient6827);stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0.7;stroke-opacity:1" />
|
||||
<path
|
||||
transform="translate(-3.7626907e-8,0.9142136)"
|
||||
d="M 95.5 42.5 A 1.5 1.5 0 1 1 92.5,42.5 A 1.5 1.5 0 1 1 95.5 42.5 z"
|
||||
sodipodi:ry="1.5"
|
||||
sodipodi:rx="1.5"
|
||||
sodipodi:cy="42.5"
|
||||
sodipodi:cx="94"
|
||||
id="path6507"
|
||||
style="opacity:1;fill:#888a85;fill-opacity:1;stroke:url(#linearGradient6829);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.7;stroke-opacity:1"
|
||||
sodipodi:type="arc" />
|
||||
<rect
|
||||
style="opacity:0.23106061;fill:url(#linearGradient6831);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
|
||||
id="rect6533"
|
||||
width="3.9928944"
|
||||
height="21.999802"
|
||||
x="91.992836"
|
||||
y="16.963778"
|
||||
rx="1.7379364"
|
||||
ry="1.7444341"
|
||||
transform="matrix(0.9999999,3.8645919e-4,3.8358553e-4,0.9999999,0,0)" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:url(#linearGradient6833);stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0.7;stroke-opacity:1"
|
||||
d="M 13.973556,7.3037539 L 16.868274,10.198472 C 17.037111,10.371171 17.138946,10.598341 17.155536,10.839288 L 17.35441,13.468841 C 17.385431,13.770581 17.280086,14.070409 17.067148,14.286434 L 15.255187,16.098395 C 15.039162,16.311332 14.739334,16.416678 14.437595,16.385657 L 11.808041,16.186783 C 11.567094,16.170192 11.339925,16.068358 11.167226,15.899521 L 8.2725073,13.004802"
|
||||
id="path6573"
|
||||
sodipodi:nodetypes="cccccccccc" />
|
||||
<path
|
||||
style="opacity:0.59051723;fill:url(#linearGradient6835);fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.7;stroke-opacity:1"
|
||||
d="M 14.71875,6.8125 C 14.129935,6.8140249 13.543329,6.8880281 12.96875,7.03125 L 16.5,10.5625 C 16.589624,10.650873 16.646088,10.749545 16.65625,10.875 L 16.875,13.5 C 16.888638,13.656013 16.830347,13.827626 16.71875,13.9375 L 15.125,15.5625 C 17.279079,16.073694 19.038866,17.020591 21.34375,15.78125 C 22.074648,13.392376 21.483569,10.671069 19.59375,8.78125 C 18.245921,7.4334204 16.485196,6.8079254 14.71875,6.8125 z M 8,12 C 7.6061401,13.580092 7.7314214,15.26324 8.4375,16.75 C 9.564272,16.068398 10.560695,15.675078 11.46875,15.46875 L 8,12 z "
|
||||
id="path6651"
|
||||
sodipodi:nodetypes="ccccccccsccccc" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 26 KiB |
BIN
icons/qrcode.png
Normal file
After Width: | Height: | Size: 314 B |
BIN
icons/qrcode_white.png
Normal file
After Width: | Height: | Size: 380 B |
BIN
icons/revealer.png
Normal file
After Width: | Height: | Size: 272 B |
BIN
icons/revealer_c.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
icons/safe-t.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
icons/safe-t_unpaired.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
icons/seal.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
icons/seed.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
icons/speaker.png
Normal file
After Width: | Height: | Size: 392 B |
BIN
icons/status_connected.png
Normal file
After Width: | Height: | Size: 69 KiB |
173
icons/status_connected.svg
Normal file
|
@ -0,0 +1,173 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.0"
|
||||
id="svg7854"
|
||||
height="512"
|
||||
width="512"
|
||||
viewBox="9 9 30 30">
|
||||
<defs
|
||||
id="defs7856">
|
||||
<linearGradient
|
||||
id="linearGradient860">
|
||||
<stop
|
||||
id="stop856"
|
||||
offset="0"
|
||||
style="stop-color:#90bb65;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop858"
|
||||
offset="1"
|
||||
style="stop-color:#6ac017;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient7577">
|
||||
<stop
|
||||
id="stop7579"
|
||||
offset="0"
|
||||
style="stop-color:#000000;stop-opacity:0.3137255;" />
|
||||
<stop
|
||||
id="stop7581"
|
||||
offset="1"
|
||||
style="stop-color:#ffffff;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5167">
|
||||
<stop
|
||||
style="stop-color:#76d717;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop5169" />
|
||||
<stop
|
||||
style="stop-color:#509e07;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop5171" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5184">
|
||||
<stop
|
||||
style="stop-color:white;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5186" />
|
||||
<stop
|
||||
style="stop-color:white;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5188" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(2.1074616,0,0,2.1078593,-9.43551,-10.006786)"
|
||||
y2="17.024479"
|
||||
x2="16.657505"
|
||||
y1="10.883683"
|
||||
x1="15.011773"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient8317"
|
||||
xlink:href="#linearGradient7577" />
|
||||
<radialGradient
|
||||
gradientTransform="matrix(1.897257,0,0,1.897615,-6.10046,-6.6146433)"
|
||||
r="7.5896134"
|
||||
fy="20.410854"
|
||||
fx="15.865708"
|
||||
cy="20.410854"
|
||||
cx="15.865708"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient8319"
|
||||
xlink:href="#linearGradient5167" />
|
||||
<radialGradient
|
||||
r="5.96875"
|
||||
fy="11.308558"
|
||||
fx="14.05685"
|
||||
cy="11.308558"
|
||||
cx="14.05685"
|
||||
gradientTransform="matrix(-4.2002315,0.5953403,0.2958442,2.0989386,75.31118,-18.732928)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient8321"
|
||||
xlink:href="#linearGradient5184" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.7591324,0,0,1.7580929,-3.90899,-4.3562887)"
|
||||
y2="26.431587"
|
||||
x2="13.458839"
|
||||
y1="2.0178134"
|
||||
x1="8.9317284"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient8323"
|
||||
xlink:href="#linearGradient860" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata7859">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Lapo Calamandrei</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:source />
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
|
||||
<dc:title></dc:title>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>record</rdf:li>
|
||||
<rdf:li>media</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Steiner</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/SourceCode" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1">
|
||||
<ellipse
|
||||
ry="14.997972"
|
||||
rx="14.995141"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.4;fill:url(#linearGradient8317);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.11079514;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
id="path7691"
|
||||
cx="24.00086"
|
||||
cy="24.002029" />
|
||||
<ellipse
|
||||
ry="13.502028"
|
||||
rx="13.49948"
|
||||
cy="24.002029"
|
||||
cx="24.000866"
|
||||
id="path7968"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient8319);fill-opacity:1;fill-rule:nonzero;stroke:#336402;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
|
||||
<path
|
||||
id="path7970"
|
||||
d="M 25.3861,13.485003 C 20.31979,12.724926 15.45183,15.857848 14,20.764516 c 1.18871,3.18039 3.90811,5.70993 7.46677,6.47724 5.29459,1.141602 10.50115,-2.027543 12.01505,-7.143895 -1.18869,-3.180413 -3.90812,-5.709952 -7.46675,-6.477239 -0.217,-0.04678 -0.41248,-0.103152 -0.62897,-0.135619 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.404;fill:url(#radialGradient8321);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.09465754;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
|
||||
<ellipse
|
||||
ry="12.509292"
|
||||
rx="12.516688"
|
||||
cy="24.009293"
|
||||
cx="24.000891"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.54494413;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient8323);stroke-width:1.00000215;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
id="path7972" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.4 KiB |
BIN
icons/status_connected_fork.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
icons/status_connected_proxy.png
Normal file
After Width: | Height: | Size: 68 KiB |
173
icons/status_connected_proxy.svg
Normal file
|
@ -0,0 +1,173 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.0"
|
||||
id="svg7854"
|
||||
height="512"
|
||||
width="512"
|
||||
viewBox="9 9 30 30">
|
||||
<defs
|
||||
id="defs7856">
|
||||
<linearGradient
|
||||
id="linearGradient860">
|
||||
<stop
|
||||
id="stop856"
|
||||
offset="0"
|
||||
style="stop-color:#479fc6;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop858"
|
||||
offset="1"
|
||||
style="stop-color:#0c89c1;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient7577">
|
||||
<stop
|
||||
id="stop7579"
|
||||
offset="0"
|
||||
style="stop-color:#000000;stop-opacity:0.3137255;" />
|
||||
<stop
|
||||
id="stop7581"
|
||||
offset="1"
|
||||
style="stop-color:#ffffff;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5167">
|
||||
<stop
|
||||
style="stop-color:#0090ef;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop5169" />
|
||||
<stop
|
||||
style="stop-color:#0062b2;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop5171" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5184">
|
||||
<stop
|
||||
style="stop-color:white;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5186" />
|
||||
<stop
|
||||
style="stop-color:white;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5188" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(2.1074616,0,0,2.1078593,-9.43551,-10.006786)"
|
||||
y2="17.024479"
|
||||
x2="16.657505"
|
||||
y1="10.883683"
|
||||
x1="15.011773"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient8317"
|
||||
xlink:href="#linearGradient7577" />
|
||||
<radialGradient
|
||||
gradientTransform="matrix(1.897257,0,0,1.897615,-6.10046,-6.6146433)"
|
||||
r="7.5896134"
|
||||
fy="20.410854"
|
||||
fx="15.865708"
|
||||
cy="20.410854"
|
||||
cx="15.865708"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient8319"
|
||||
xlink:href="#linearGradient5167" />
|
||||
<radialGradient
|
||||
r="5.96875"
|
||||
fy="11.308558"
|
||||
fx="14.05685"
|
||||
cy="11.308558"
|
||||
cx="14.05685"
|
||||
gradientTransform="matrix(-4.2002315,0.5953403,0.2958442,2.0989386,75.31118,-18.732928)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient8321"
|
||||
xlink:href="#linearGradient5184" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.7591324,0,0,1.7580929,-3.90899,-4.3562887)"
|
||||
y2="26.431587"
|
||||
x2="13.458839"
|
||||
y1="2.0178134"
|
||||
x1="8.9317284"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient8323"
|
||||
xlink:href="#linearGradient860" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata7859">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Lapo Calamandrei</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:source />
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
|
||||
<dc:title></dc:title>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>record</rdf:li>
|
||||
<rdf:li>media</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Steiner</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/SourceCode" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1">
|
||||
<ellipse
|
||||
ry="14.997972"
|
||||
rx="14.995141"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.4;fill:url(#linearGradient8317);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.11079514;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
id="path7691"
|
||||
cx="24.00086"
|
||||
cy="24.002029" />
|
||||
<ellipse
|
||||
ry="13.502028"
|
||||
rx="13.49948"
|
||||
cy="24.002029"
|
||||
cx="24.000866"
|
||||
id="path7968"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient8319);fill-opacity:1;fill-rule:nonzero;stroke:#003f70;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
|
||||
<path
|
||||
id="path7970"
|
||||
d="M 25.3861,13.485003 C 20.31979,12.724926 15.45183,15.857848 14,20.764516 c 1.18871,3.18039 3.90811,5.70993 7.46677,6.47724 5.29459,1.141602 10.50115,-2.027543 12.01505,-7.143895 -1.18869,-3.180413 -3.90812,-5.709952 -7.46675,-6.477239 -0.217,-0.04678 -0.41248,-0.103152 -0.62897,-0.135619 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.404;fill:url(#radialGradient8321);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.09465754;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
|
||||
<ellipse
|
||||
ry="12.509292"
|
||||
rx="12.516688"
|
||||
cy="24.009293"
|
||||
cx="24.000891"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.54494413;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient8323);stroke-width:1.00000215;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
id="path7972" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.4 KiB |
BIN
icons/status_connected_proxy_fork.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
icons/status_disconnected.png
Normal file
After Width: | Height: | Size: 65 KiB |
293
icons/status_disconnected.svg
Normal file
|
@ -0,0 +1,293 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="9 9 30 30"
|
||||
id="svg7854"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.45"
|
||||
version="1.0"
|
||||
sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/actions"
|
||||
sodipodi:docname="media-record.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
inkscape:export-filename="/home/lapo/Desktop/media-icons.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs7856">
|
||||
<linearGradient
|
||||
id="linearGradient7577">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0.3137255;"
|
||||
offset="0"
|
||||
id="stop7579" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop7581" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5167">
|
||||
<stop
|
||||
id="stop5169"
|
||||
offset="0"
|
||||
style="stop-color:#ef2929;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop5171"
|
||||
offset="1"
|
||||
style="stop-color:#c60e0e;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5184"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop5186"
|
||||
offset="0"
|
||||
style="stop-color:white;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop5188"
|
||||
offset="1"
|
||||
style="stop-color:white;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5172"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop5174"
|
||||
offset="0"
|
||||
style="stop-color:white;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop5176"
|
||||
offset="1"
|
||||
style="stop-color:white;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient7577"
|
||||
id="linearGradient8317"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="15.011773"
|
||||
y1="10.883683"
|
||||
x2="16.657505"
|
||||
y2="17.024479" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5167"
|
||||
id="radialGradient8319"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="15.865708"
|
||||
cy="20.410854"
|
||||
fx="15.865708"
|
||||
fy="20.410854"
|
||||
r="7.5896134" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5184"
|
||||
id="radialGradient8321"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-4.2002315,0.5953403,0.2958442,2.0989386,-274.68882,-18.732928)"
|
||||
cx="14.05685"
|
||||
cy="11.308558"
|
||||
fx="14.05685"
|
||||
fy="11.308558"
|
||||
r="5.96875" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5172"
|
||||
id="linearGradient8323"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="8.9317284"
|
||||
y1="2.0178134"
|
||||
x2="13.458839"
|
||||
y2="26.431587" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#afafaf"
|
||||
borderopacity="1"
|
||||
gridtolerance="10000"
|
||||
guidetolerance="10"
|
||||
objecttolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="-137.53856"
|
||||
inkscape:cy="10.827794"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
width="48px"
|
||||
height="48px"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:window-width="872"
|
||||
inkscape:window-height="971"
|
||||
inkscape:window-x="117"
|
||||
inkscape:window-y="27"
|
||||
showgrid="false"
|
||||
gridspacingx="0.5px"
|
||||
gridspacingy="0.5px"
|
||||
gridempspacing="2"
|
||||
inkscape:grid-points="true"
|
||||
showborder="true"
|
||||
showguides="false"
|
||||
inkscape:guide-bbox="true"
|
||||
borderlayer="true">
|
||||
<sodipodi:guide
|
||||
orientation="horizontal"
|
||||
position="13.125"
|
||||
id="guide7377" />
|
||||
<sodipodi:guide
|
||||
orientation="horizontal"
|
||||
position="5.4800776"
|
||||
id="guide7379" />
|
||||
<sodipodi:guide
|
||||
orientation="horizontal"
|
||||
position="35"
|
||||
id="guide7492" />
|
||||
<sodipodi:guide
|
||||
orientation="horizontal"
|
||||
position="48"
|
||||
id="guide7046" />
|
||||
<sodipodi:guide
|
||||
orientation="horizontal"
|
||||
position="-17.5"
|
||||
id="guide7233" />
|
||||
<sodipodi:guide
|
||||
orientation="horizontal"
|
||||
position="-29"
|
||||
id="guide7235" />
|
||||
<sodipodi:guide
|
||||
orientation="horizontal"
|
||||
position="22.097087"
|
||||
id="guide7556" />
|
||||
<sodipodi:guide
|
||||
orientation="vertical"
|
||||
position="-76.125"
|
||||
id="guide7644" />
|
||||
<sodipodi:guide
|
||||
orientation="vertical"
|
||||
position="-26.125"
|
||||
id="guide7646" />
|
||||
<sodipodi:guide
|
||||
orientation="vertical"
|
||||
position="24"
|
||||
id="guide7648" />
|
||||
<sodipodi:guide
|
||||
orientation="vertical"
|
||||
position="-125.28125"
|
||||
id="guide7665" />
|
||||
<sodipodi:guide
|
||||
orientation="vertical"
|
||||
position="-175.125"
|
||||
id="guide7667" />
|
||||
<sodipodi:guide
|
||||
orientation="vertical"
|
||||
position="-225.83223"
|
||||
id="guide7685" />
|
||||
<sodipodi:guide
|
||||
orientation="vertical"
|
||||
position="-326.06462"
|
||||
id="guide7695" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7859">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Lapo Calamandrei</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:source />
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
|
||||
<dc:title>Record</dc:title>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>record</rdf:li>
|
||||
<rdf:li>media</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Steiner</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/SourceCode" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
id="g7170"
|
||||
transform="translate(350,0)">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0.4;color:#000000;fill:url(#linearGradient8317);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52702755;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
id="path7691"
|
||||
sodipodi:cx="15.865708"
|
||||
sodipodi:cy="16.134291"
|
||||
sodipodi:rx="7.115262"
|
||||
sodipodi:ry="7.115262"
|
||||
d="M 22.98097 16.134291 A 7.115262 7.115262 0 1 1 8.7504463,16.134291 A 7.115262 7.115262 0 1 1 22.98097 16.134291 z"
|
||||
transform="matrix(2.1074616,0,0,2.1078593,-359.43551,-10.006786)" />
|
||||
<g
|
||||
id="g7564">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="color:#000000;fill:url(#radialGradient8319);fill-opacity:1;fill-rule:nonzero;stroke:#a40000;stroke-width:0.52702755;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
id="path7968"
|
||||
sodipodi:cx="15.865708"
|
||||
sodipodi:cy="16.134291"
|
||||
sodipodi:rx="7.115262"
|
||||
sodipodi:ry="7.115262"
|
||||
d="M 22.98097 16.134291 A 7.115262 7.115262 0 1 1 8.7504463,16.134291 A 7.115262 7.115262 0 1 1 22.98097 16.134291 z"
|
||||
transform="matrix(1.897257,0,0,1.897615,-356.10046,-6.6146433)" />
|
||||
<path
|
||||
style="opacity:0.64044949;color:#000000;fill:url(#radialGradient8321);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.09465754;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M -324.6139,13.485003 C -329.68021,12.724926 -334.54817,15.857848 -336,20.764516 C -334.81129,23.944906 -332.09189,26.474446 -328.53323,27.241756 C -323.23864,28.383358 -318.03208,25.214213 -316.51818,20.097861 C -317.70687,16.917448 -320.4263,14.387909 -323.98493,13.620622 C -324.20193,13.573837 -324.39741,13.51747 -324.6139,13.485003 z "
|
||||
id="path7970" />
|
||||
<path
|
||||
transform="matrix(1.7591324,0,0,1.7580929,-353.90899,-4.3562887)"
|
||||
d="M 22.98097 16.134291 A 7.115262 7.115262 0 1 1 8.7504463,16.134291 A 7.115262 7.115262 0 1 1 22.98097 16.134291 z"
|
||||
sodipodi:ry="7.115262"
|
||||
sodipodi:rx="7.115262"
|
||||
sodipodi:cy="16.134291"
|
||||
sodipodi:cx="15.865708"
|
||||
id="path7972"
|
||||
style="opacity:0.54494413;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient8323);stroke-width:0.56863129;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
sodipodi:type="arc" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 10 KiB |
BIN
icons/status_lagging.png
Normal file
After Width: | Height: | Size: 73 KiB |
173
icons/status_lagging.svg
Normal file
|
@ -0,0 +1,173 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.0"
|
||||
id="svg7854"
|
||||
height="512"
|
||||
width="512"
|
||||
viewBox="9 9 30 30">
|
||||
<defs
|
||||
id="defs7856">
|
||||
<linearGradient
|
||||
id="linearGradient860">
|
||||
<stop
|
||||
id="stop856"
|
||||
offset="0"
|
||||
style="stop-color:#ef9d29;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop858"
|
||||
offset="1"
|
||||
style="stop-color:#c67f0e;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient7577">
|
||||
<stop
|
||||
id="stop7579"
|
||||
offset="0"
|
||||
style="stop-color:#000000;stop-opacity:0.3137255;" />
|
||||
<stop
|
||||
id="stop7581"
|
||||
offset="1"
|
||||
style="stop-color:#ffffff;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5167">
|
||||
<stop
|
||||
style="stop-color:#ef9a29;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop5169" />
|
||||
<stop
|
||||
style="stop-color:#a6600c;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop5171" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5184">
|
||||
<stop
|
||||
style="stop-color:white;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5186" />
|
||||
<stop
|
||||
style="stop-color:white;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5188" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(2.1074616,0,0,2.1078593,-9.43551,-10.006786)"
|
||||
y2="17.024479"
|
||||
x2="16.657505"
|
||||
y1="10.883683"
|
||||
x1="15.011773"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient8317"
|
||||
xlink:href="#linearGradient7577" />
|
||||
<radialGradient
|
||||
gradientTransform="matrix(1.897257,0,0,1.897615,-6.10046,-6.6146433)"
|
||||
r="7.5896134"
|
||||
fy="20.410854"
|
||||
fx="15.865708"
|
||||
cy="20.410854"
|
||||
cx="15.865708"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient8319"
|
||||
xlink:href="#linearGradient5167" />
|
||||
<radialGradient
|
||||
r="5.96875"
|
||||
fy="11.308558"
|
||||
fx="14.05685"
|
||||
cy="11.308558"
|
||||
cx="14.05685"
|
||||
gradientTransform="matrix(-4.2002315,0.5953403,0.2958442,2.0989386,75.31118,-18.732928)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient8321"
|
||||
xlink:href="#linearGradient5184" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.7591324,0,0,1.7580929,-3.90899,-4.3562887)"
|
||||
y2="26.431587"
|
||||
x2="13.458839"
|
||||
y1="2.0178134"
|
||||
x1="8.9317284"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient8323"
|
||||
xlink:href="#linearGradient860" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata7859">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Lapo Calamandrei</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:source />
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
|
||||
<dc:title></dc:title>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>record</rdf:li>
|
||||
<rdf:li>media</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Steiner</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/SourceCode" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1">
|
||||
<ellipse
|
||||
ry="14.997972"
|
||||
rx="14.995141"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.4;fill:url(#linearGradient8317);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.11079514;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
id="path7691"
|
||||
cx="24.00086"
|
||||
cy="24.002029" />
|
||||
<ellipse
|
||||
ry="13.502028"
|
||||
rx="13.49948"
|
||||
cy="24.002029"
|
||||
cx="24.000866"
|
||||
id="path7968"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient8319);fill-opacity:1.0;fill-rule:nonzero;stroke:#8e5700;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
|
||||
<path
|
||||
id="path7970"
|
||||
d="M 25.3861,13.485003 C 20.31979,12.724926 15.45183,15.857848 14,20.764516 c 1.18871,3.18039 3.90811,5.70993 7.46677,6.47724 5.29459,1.141602 10.50115,-2.027543 12.01505,-7.143895 -1.18869,-3.180413 -3.90812,-5.709952 -7.46675,-6.477239 -0.217,-0.04678 -0.41248,-0.103152 -0.62897,-0.135619 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.404;fill:url(#radialGradient8321);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.09465754;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
|
||||
<ellipse
|
||||
ry="12.509292"
|
||||
rx="12.516688"
|
||||
cy="24.009293"
|
||||
cx="24.000891"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.54494413;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient8323);stroke-width:1.00000215;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
id="path7972" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.4 KiB |
BIN
icons/status_lagging_fork.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
icons/status_waiting.png
Normal file
After Width: | Height: | Size: 79 KiB |
398
icons/status_waiting.svg
Normal file
|
@ -0,0 +1,398 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:export-ydpi="90.000000"
|
||||
inkscape:export-xdpi="90.000000"
|
||||
inkscape:export-filename="c:\Tango\git\view-refresh.png"
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 48 48"
|
||||
id="svg11300"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.45"
|
||||
sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/actions"
|
||||
sodipodi:docname="view-refresh.svg"
|
||||
version="1.0"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient5335">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5337" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5339" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5313">
|
||||
<stop
|
||||
id="stop5315"
|
||||
offset="0"
|
||||
style="stop-color:#99b8df;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#3969a8;stop-opacity:1;"
|
||||
offset="0.23705086"
|
||||
id="stop5333" />
|
||||
<stop
|
||||
style="stop-color:#4f7eba;stop-opacity:1;"
|
||||
offset="0.54706067"
|
||||
id="stop5317" />
|
||||
<stop
|
||||
id="stop5321"
|
||||
offset="0.74557692"
|
||||
style="stop-color:#96b6d7;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#a0bddc;stop-opacity:1"
|
||||
offset="0.87321436"
|
||||
id="stop5331" />
|
||||
<stop
|
||||
id="stop5319"
|
||||
offset="1"
|
||||
style="stop-color:#729fcf;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient8152">
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop8154" />
|
||||
<stop
|
||||
id="stop3174"
|
||||
offset="0.5"
|
||||
style="stop-color:#4f7eba;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop8156" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3207">
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:0.47058824;"
|
||||
offset="0"
|
||||
id="stop3209" />
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3211" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient2847">
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop2849" />
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop2851" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2831">
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop2833" />
|
||||
<stop
|
||||
id="stop2855"
|
||||
offset="0.33333334"
|
||||
style="stop-color:#5b86be;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#83a8d8;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop2835" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient8662">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop8664" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop8666" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2831"
|
||||
id="linearGradient1486"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0818662,0,0,1.1166851,-0.8207482,-1.8622434)"
|
||||
x1="13.478554"
|
||||
y1="10.612206"
|
||||
x2="15.419417"
|
||||
y2="19.115122" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2847"
|
||||
id="linearGradient1488"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-1.0818662,0,0,-1.1166851,50.09459,49.644854)"
|
||||
x1="37.128052"
|
||||
y1="29.729605"
|
||||
x2="37.40255"
|
||||
y2="26.800913" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient8662"
|
||||
id="radialGradient1503"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.536723,0,16.87306)"
|
||||
cx="24.837126"
|
||||
cy="36.421127"
|
||||
fx="24.837126"
|
||||
fy="36.421127"
|
||||
r="15.644737" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient8152"
|
||||
id="linearGradient8158"
|
||||
x1="49.412277"
|
||||
y1="37.904068"
|
||||
x2="11.881318"
|
||||
y2="19.776045"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2831"
|
||||
id="linearGradient8170"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-1.0818662,0,0,-1.1166851,48.639854,47.862243)"
|
||||
x1="13.478554"
|
||||
y1="10.612206"
|
||||
x2="15.419417"
|
||||
y2="19.115122" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2847"
|
||||
id="linearGradient8172"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0818662,0,0,1.1166851,-2.2754847,-3.644854)"
|
||||
x1="37.128052"
|
||||
y1="29.729605"
|
||||
x2="37.40255"
|
||||
y2="26.800913" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient8152"
|
||||
id="linearGradient8174"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="49.412277"
|
||||
y1="37.904068"
|
||||
x2="11.881318"
|
||||
y2="19.776045" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3207"
|
||||
id="linearGradient8178"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="5.8925977"
|
||||
y1="20.540676"
|
||||
x2="45.198921"
|
||||
y2="27.721035" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5313"
|
||||
id="linearGradient8180"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="61.572533"
|
||||
y1="28.049652"
|
||||
x2="10.969182"
|
||||
y2="20.333939" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5335"
|
||||
id="linearGradient5341"
|
||||
x1="8.6878577"
|
||||
y1="25.265626"
|
||||
x2="52.122673"
|
||||
y2="25.265626"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
stroke="#3465a4"
|
||||
fill="#729fcf"
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#e8e8e8"
|
||||
borderopacity="0.86666667"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="48.628749"
|
||||
inkscape:cy="21.704614"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:window-width="892"
|
||||
inkscape:window-height="938"
|
||||
inkscape:window-x="374"
|
||||
inkscape:window-y="37"
|
||||
width="48px"
|
||||
height="48px"
|
||||
borderlayer="true" />
|
||||
<metadata
|
||||
id="metadata4">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Steiner</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:source>http://jimmac.musichall.cz</dc:source>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
|
||||
<dc:title>View Refresh</dc:title>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>reload</rdf:li>
|
||||
<rdf:li>refresh</rdf:li>
|
||||
<rdf:li>view</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>Ricardo 'Rick' González</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/SourceCode" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true">
|
||||
<path
|
||||
transform="matrix(-1.5146484,0,0,-0.7917058,60.923237,69.528413)"
|
||||
d="M 40.481863 36.421127 A 15.644737 8.3968935 0 1 1 9.1923885,36.421127 A 15.644737 8.3968935 0 1 1 40.481863 36.421127 z"
|
||||
sodipodi:ry="8.3968935"
|
||||
sodipodi:rx="15.644737"
|
||||
sodipodi:cy="36.421127"
|
||||
sodipodi:cx="24.837126"
|
||||
id="path8660"
|
||||
style="opacity:0.36111109;color:#000000;fill:url(#radialGradient1503);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
sodipodi:type="arc"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true" />
|
||||
<path
|
||||
style="color:#000000;fill:url(#linearGradient1486);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient1488);stroke-width:1.04300582000000008;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible;opacity:0.51807229"
|
||||
d="M 20.478497,9.7711467 C 20.478497,9.7711467 12.632988,7.9438002 14.368023,21.024298 L 5.1028658,21.024298 C 5.1028658,21.024298 6.0085332,7.5377773 20.478497,9.7711467 z "
|
||||
id="path2865"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<g
|
||||
id="g1878"
|
||||
transform="matrix(-0.6129282,-0.5154381,-0.5178496,0.610074,58.686164,13.911361)"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
style="fill:url(#linearGradient8158);fill-opacity:1;stroke:#204a87;stroke-width:1.24932528;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
id="path1880"
|
||||
d="M 45.862102,50.273522 C 62.924432,34.96305 47.150241,15.929711 22.760624,12.513943 L 22.113577,3.1522143 L 7.613534,20.510135 L 22.703188,33.23244 C 22.703188,33.23244 22.454828,23.347105 22.454828,23.347105 C 41.289895,24.339584 54.775794,35.675041 45.862102,50.273522 z "
|
||||
style="opacity:1;color:#000000;fill:url(#linearGradient8180);fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:1.24977946000000006;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true" />
|
||||
</g>
|
||||
<g
|
||||
style="fill:none;fill-opacity:1;stroke:url(#linearGradient5341);stroke-width:1.24928653000000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;opacity:0.54819277"
|
||||
inkscape:r_cy="true"
|
||||
inkscape:r_cx="true"
|
||||
transform="matrix(-0.612811,-0.5154406,-0.5177506,0.6100769,58.675633,13.911365)"
|
||||
id="g3185">
|
||||
<path
|
||||
sodipodi:type="inkscape:offset"
|
||||
inkscape:radius="-1.197237"
|
||||
inkscape:original="M 22.125 3.15625 L 7.625 20.5 L 22.71875 33.21875 C 22.718749 33.21875 22.46875 23.34375 22.46875 23.34375 C 41.298509 24.342727 54.468144 35.661007 45.5625 50.25 C 62.614067 34.952315 46.852277 15.923275 22.46875 12.5 L 22.125 3.15625 z "
|
||||
style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient5341);stroke-width:1.24928653000000001;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
|
||||
id="path3189"
|
||||
d="M 21.0625,6.3125 L 9.3125,20.34375 L 21.46875,30.59375 C 21.39688,27.754893 21.28125,23.375 21.28125,23.375 C 21.27502,23.044409 21.405774,22.725958 21.642519,22.495132 C 21.879264,22.264306 22.200923,22.141654 22.53125,22.15625 C 32.170255,22.667629 40.441027,25.773015 45.28125,30.875 C 48.676469,34.453835 50.102049,39.131532 49.125,44.21875 C 50.368339,42.205641 51.107893,40.194594 51.375,38.21875 C 51.870422,34.55401 50.856988,30.946652 48.5625,27.59375 C 43.973525,20.887947 34.236978,15.361613 22.3125,13.6875 C 21.732114,13.606381 21.295727,13.117098 21.28125,12.53125 L 21.0625,6.3125 z "
|
||||
transform="translate(1.0080026e-6,8.5223784e-7)" />
|
||||
</g>
|
||||
<g
|
||||
id="g2424"
|
||||
transform="matrix(0.190868,0.16126,0.16126,-0.190868,-0.719083,15.30613)"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:r_cy="true"
|
||||
inkscape:r_cx="true"
|
||||
id="path8160"
|
||||
d="M 27.340608,36.228853 C 27.340608,36.228853 35.186117,38.0562 33.451082,24.975702 L 42.71624,24.975702 C 42.71624,24.975702 41.810572,38.462223 27.340608,36.228853 z "
|
||||
style="color:#000000;fill:url(#linearGradient8170);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient8172);stroke-width:1.04300582000000008;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible;opacity:0.51807229" />
|
||||
<g
|
||||
style="fill:url(#linearGradient8174);fill-opacity:1;stroke:#204a87;stroke-width:1.24932528;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:r_cy="true"
|
||||
inkscape:r_cx="true"
|
||||
transform="matrix(0.6101332,0.5154999,0.5154881,-0.6101471,-10.618024,32.088556)"
|
||||
id="g8162">
|
||||
<path
|
||||
inkscape:r_cy="true"
|
||||
inkscape:r_cx="true"
|
||||
style="opacity:1;color:#000000;fill:url(#linearGradient8180);fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:1.25256376;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
|
||||
d="M 45.862102,50.273522 C 62.924432,34.96305 47.150241,15.929711 22.760624,12.513943 L 22.113577,3.1522141 L 7.6135337,20.510135 L 22.703188,33.23244 C 22.703188,33.23244 22.454828,23.347105 22.454828,23.347105 C 41.289895,24.339584 54.775794,35.675041 45.862102,50.273522 z "
|
||||
id="path8164"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
</g>
|
||||
<g
|
||||
id="g8166"
|
||||
transform="matrix(0.6128107,0.5154406,0.5177504,-0.6100769,-10.856505,32.088635)"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
style="fill:none;fill-opacity:1;stroke:#204a87;stroke-width:1.24928653;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
|
||||
<path
|
||||
transform="matrix(0.9972307,-2.4605589e-3,-2.4605593e-3,0.9980642,0.2457029,0.2077351)"
|
||||
d="M 21.0625,6.3125 L 9.3125,20.34375 L 21.46875,30.59375 C 21.39688,27.754893 21.28125,23.375 21.28125,23.375 C 21.27502,23.044409 21.405774,22.725958 21.642519,22.495132 C 21.879264,22.264306 22.200923,22.141654 22.53125,22.15625 C 32.170255,22.667629 40.441027,25.773015 45.28125,30.875 C 48.676469,34.453835 50.102049,39.131532 49.125,44.21875 C 50.368339,42.205641 51.107893,40.194594 51.375,38.21875 C 51.870422,34.55401 50.856988,30.946652 48.5625,27.59375 C 43.973525,20.887947 34.236978,15.361613 22.3125,13.6875 C 21.732114,13.606381 21.295727,13.117098 21.28125,12.53125 L 21.0625,6.3125 z "
|
||||
id="path8168"
|
||||
style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient8178);stroke-width:1.24973191;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.70588235;visibility:visible;display:block;overflow:visible"
|
||||
inkscape:original="M 22.125 3.15625 L 7.625 20.5 L 22.71875 33.21875 C 22.718749 33.21875 22.46875 23.34375 22.46875 23.34375 C 41.298509 24.342727 54.468144 35.661007 45.5625 50.25 C 62.614067 34.952315 46.852277 15.923275 22.46875 12.5 L 22.125 3.15625 z "
|
||||
inkscape:radius="-1.197237"
|
||||
sodipodi:type="inkscape:offset" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 17 KiB |
BIN
icons/tab_addresses.png
Normal file
After Width: | Height: | Size: 886 B |