[Pkg-privacy-commits] [tor-monitor] 01/39: Initial commit
Sascha Steinbiss
sascha-guest at moszumanska.debian.org
Tue Aug 25 18:00:42 UTC 2015
This is an automated email from the git hooks/post-receive script.
sascha-guest pushed a commit to branch master
in repository tor-monitor.
commit 1a5d6a5dc9c8e64485547001a076e9aa8a3cdd99
Author: Tails developers <tails at boum.org>
Date: Mon Feb 9 20:54:41 2015 +0000
Initial commit
---
README | 20 +++
setup.py | 10 ++
tormonitor | 448 +++++++++++++++++++++++++++++++++++++++++++++++++++++
tormonitor.desktop | 10 ++
tormonitor.svg | 330 +++++++++++++++++++++++++++++++++++++++
5 files changed, 818 insertions(+)
diff --git a/README b/README
new file mode 100644
index 0000000..7cd4ecc
--- /dev/null
+++ b/README
@@ -0,0 +1,20 @@
+Tor Monitor - a GTK application to display Tor circuits and streams
+Copyright (C) 2015 Tails developers
+
+Dependencies
+============
+
+Tor Monitor depends on python (>= 2.7), python-gi (>= 1.42), python-stem
+(>= 1.2.2), Gtk GIR (>= 3.14), GLib GIR (>= 1.42).
+
+It recommends pycountry (>= 1.8).
+
+On Debian system (>= 8.0), these can be installed with:
+
+ apt-get install python-gi python-stem python-pycountry gir1.2-gtk-3.0 gir1.2-glib-2.0
+
+Installation
+============
+
+ ./setup.py build
+ sudo ./setup.py install
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..c45a6c4
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+from distutils.core import setup
+
+setup(name='tormonitor',
+ version='0.1',
+ scripts=['tormonitor'],
+ data_files=[('share/icons/hicolor/scalable/apps', ['tormonitor.svg']),
+ ('share/applications', ['tormonitor.desktop'])],
+ requires=['stem','gi']
+ )
diff --git a/tormonitor b/tormonitor
new file mode 100755
index 0000000..94c972c
--- /dev/null
+++ b/tormonitor
@@ -0,0 +1,448 @@
+#!/usr/bin/env python
+#
+# Tor Monitor - a GTK applicaton to display Tor circuits and streams
+# Copyright (C) 2015 Tails developers
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import datetime
+import gettext
+import logging
+import os
+import threading
+import sys
+
+try:
+ import pycountry
+except ImportError:
+ pycountry = None
+
+import stem
+import stem.connection
+import stem.control
+import stem.descriptor.remote
+
+from gi.repository import (GLib,
+ GObject,
+ Gtk)
+
+gettext.install('tormonitor')
+
+if os.environ.has_key('DEBUG') and os.environ['DEBUG']:
+ logging.basicConfig(level=logging.DEBUG)
+else:
+ logging.getLogger('stem').setLevel(logging.WARNING)
+
+class TorMonitorWindow(Gtk.ApplicationWindow):
+
+ # Constants used to distinguish circuits and streams in our TreeStore
+ TYPE_CIRC = 0
+ TYPE_STREAM = 1
+
+ def __init__(self, app):
+ Gtk.Window.__init__(self, application=app)
+
+ self._listeners_initialized = False
+ self._circ_to_iter = {}
+ self._stream_to_iter = {}
+ self.controller = self.get_application().controller
+
+ self._create_ui()
+
+ if self.controller:
+ self.init_listeners()
+ self.populate_treeview()
+ else:
+ GLib.timeout_add_seconds(1, self.controller_connect_cb)
+ self._hbox.set_sensitive(False)
+ self._infobar_label.set_text(_("Cannot connect to the Tor daemon. "
+ "Tor Monitor will try to reconnect..."))
+ self._infobar.set_message_type(Gtk.MessageType.ERROR)
+ self._infobar.show()
+
+ def _create_ui(self):
+ self.set_default_size(600, 400)
+ self.set_icon_name('tormonitor')
+ self.connect('delete-event', self.delete_event_cb)
+
+ headerbar = Gtk.HeaderBar()
+ headerbar.set_title(_("Tor Monitor"))
+ headerbar.set_subtitle(_("Display Tor circuits and streams"))
+ headerbar.set_show_close_button(True)
+ self.set_titlebar(headerbar)
+
+ grid = Gtk.Grid()
+ self.add(grid)
+
+ self._infobar = Gtk.InfoBar()
+ self._infobar.set_no_show_all(True)
+ self._infobar_label = Gtk.Label("");
+ self._infobar_label.show()
+ self._infobar.get_content_area().add(self._infobar_label)
+ self._infobar.add_button(_("OK"), Gtk.ResponseType.OK)
+ self._infobar.connect('response', lambda infobar, rid, data=None: self._infobar.hide())
+ grid.attach(self._infobar, 0, 0, 2, 1)
+
+ self._hbox = Gtk.Box(Gtk.Orientation.HORIZONTAL, 12)
+ self._hbox.set_homogeneous(True)
+ self._hbox.set_margin_top(6)
+ self._hbox.set_margin_right(6)
+ self._hbox.set_margin_left(6)
+ self._hbox.set_margin_bottom(6)
+ self._hbox.set_halign(Gtk.Align.FILL)
+ self._hbox.set_valign(Gtk.Align.FILL)
+ self._hbox.set_hexpand(True)
+ self._hbox.set_vexpand(True)
+ grid.attach(self._hbox, 0, 1, 2, 1)
+
+ self._treestore = Gtk.TreeStore(GObject.TYPE_INT,
+ GObject.TYPE_STRING,
+ GObject.TYPE_STRING,
+ GObject.TYPE_STRING)
+ self._treeview = Gtk.TreeView.new_with_model(self._treestore)
+ self._treeview.get_selection().connect('changed', self.cb_treeselection_changed)
+ def append_column(tv, col, name=None):
+ tvcolumn = Gtk.TreeViewColumn(name)
+ tv.append_column(tvcolumn)
+ cell = Gtk.CellRendererText()
+ tvcolumn.pack_start(cell, True)
+ tvcolumn.add_attribute(cell, 'text', col)
+ append_column(self._treeview, 2, _("Name"))
+ append_column(self._treeview, 3, _("Status"))
+
+ scrolledwindow_circuits = Gtk.ScrolledWindow()
+ scrolledwindow_circuits.add(self._treeview)
+ self._hbox.pack_start(scrolledwindow_circuits, expand=True, fill=True, padding=0)
+
+ self._path = Gtk.Label(_("Click on a path to get details"))
+ self._hbox.pack_start(self._path, expand=True, fill=True, padding=0)
+
+ self.show_all()
+
+ def init_listeners(self):
+ if not self._listeners_initialized:
+ self.controller.add_event_listener(self.update_circ_cb,
+ stem.control.EventType.CIRC)
+ self.controller.add_event_listener(self.update_stream_cb,
+ stem.control.EventType.STREAM)
+ self.controller.add_status_listener(self.update_status_cb)
+ self._listeners_initialized = True
+
+ def update_status_cb(self, controller, state, timestamp):
+ if state == stem.control.State.CLOSED:
+ GLib.idle_add(self.connection_closed_cb)
+ GLib.timeout_add_seconds(1, self.controller_reconnect_cb)
+ elif state == stem.control.State.INIT:
+ GLib.idle_add(self.connection_init_cb)
+
+ def connection_closed_cb(self):
+ logging.debug("Controller connection closed")
+ self._hbox.set_sensitive(False)
+ self._infobar_label.set_text(_("Lost connection to the Tor daemon. "
+ "Tor Monitor will try to reconnect..."))
+ self._infobar.set_message_type(Gtk.MessageType.ERROR)
+ self._infobar.show()
+ return False
+
+ def connection_init_cb(self):
+ logging.debug("Controller initialized")
+ self._hbox.set_sensitive(True)
+ self._infobar_label.set_text(_("Reconnected to the Tor daemon! "
+ "You can use Tor Monitor again."))
+ self._infobar.set_message_type(Gtk.MessageType.INFO)
+ self._infobar.show()
+ self.init_listeners()
+ self.populate_treeview()
+
+ return False
+
+ def controller_reconnect_cb(self):
+ logging.debug("Trying to reconnect the controller")
+ try:
+ self.controller.connect()
+ self.controller.authenticate()
+ except stem.SocketError:
+ return True
+ self.connection_init_cb()
+ return False
+
+ def controller_connect_cb(self):
+ logging.debug("Trying to connect the controller")
+ controller = self.get_application().connect_controller()
+ if controller:
+ self.controller = controller
+ self.connection_init_cb()
+ return False
+ else:
+ return True
+
+ def delete_event_cb(self, widget, event, data=None):
+ logging.info("quitting, waiting all threads to return...")
+ self.hide()
+ while Gtk.events_pending():
+ Gtk.main_iteration()
+ return False
+
+ # CRICUITS AND STREAMS LIST
+ # =========================
+
+ @staticmethod
+ def circuit_label(circuit):
+ if circuit.path:
+ circ_str = ' '.join([nick for fp, nick in circuit.path])
+ else:
+ circ_str = _("Building...")
+ return circ_str
+
+ @staticmethod
+ def stream_label(stream):
+ return "%s" % stream.target
+
+ def add_circuit(self, circuit):
+ circ_iter = self._treestore.append(None,
+ [self.TYPE_CIRC,
+ circuit.id,
+ self.circuit_label(circuit),
+ str(circuit.status).lower()])
+ self._circ_to_iter[circuit.id] = circ_iter
+ return circ_iter
+
+ def add_circuit_cb(self, circuit):
+ self.add_circuit(circuit)
+ return False
+
+ def update_circuit(self, circuit):
+ logging.debug("updating circuit %s" % circuit)
+ if circuit.reason:
+ status = _("%s: %s") % (str(circuit.status).lower(),
+ str(circuit.reason).lower())
+ else:
+ status = str(circuit.status).lower()
+ self._treestore.set(
+ self._circ_to_iter[circuit.id],
+ 2, self.circuit_label(circuit),
+ 3, status)
+
+ def remove_circuit(self, circuit):
+ self._treestore.remove(self._circ_to_iter[circuit.id])
+ del self._circ_to_iter[circuit.id]
+ return False # to cancel the repetition when using in timeout_add
+
+ def update_circ_cb(self, circ_event):
+ if circ_event.id not in self._circ_to_iter:
+ GLib.idle_add(self.add_circuit_cb, circ_event)
+ else:
+ GLib.idle_add(self.update_circuit, circ_event)
+ if (circ_event.status == stem.CircStatus.FAILED
+ or circ_event.status == stem.CircStatus.CLOSED):
+ GLib.timeout_add_seconds(5, self.remove_circuit, circ_event)
+
+ def add_stream(self, stream):
+ if not stream.circ_id:
+ return None
+ circ_iter = self._circ_to_iter[stream.circ_id]
+ if not circ_iter:
+ logging.warn("No iter found for %s" % circ_id)
+ circ_iter = self.add_circuit(self.controller.get_circuit(circ_id))
+ stream_iter = self._treestore.append(circ_iter,
+ [self.TYPE_STREAM,
+ stream.id,
+ self.stream_label(stream),
+ str(stream.status).lower()])
+ self._stream_to_iter[stream.id] = stream_iter
+ self._treeview.expand_to_path(self._treestore.get_path(stream_iter))
+ return stream_iter
+
+ def add_stream_cb(self, stream):
+ self.add_stream(stream)
+ return False
+
+ def update_stream(self, stream):
+ stream_iter = self._stream_to_iter[stream.id]
+ # If the stream changed circuit, reparent it
+ if stream.circ_id != self._treestore.get_value(stream_iter, 1):
+ self.remove_stream(stream)
+ stream_iter = self.add_stream(stream)
+ self._treestore.set(stream_iter, 2, self.stream_label(stream))
+ if stream.status:
+ self._treestore.set(stream_iter, 3, str(stream.status).lower())
+
+ def remove_stream(self, stream):
+ self._treestore.remove(self._stream_to_iter[stream.id])
+ del self._stream_to_iter[stream.id]
+ return False # to cancel the repetition when using in timeout_add
+
+ def update_stream_cb(self, stream_event):
+ if stream_event.id not in self._stream_to_iter:
+ GLib.idle_add(self.add_stream_cb, stream_event)
+ else:
+ GLib.idle_add(self.update_stream, stream_event)
+ if (stream_event.status == stem.StreamStatus.FAILED
+ or stream_event.status == stem.StreamStatus.CLOSED):
+ GLib.timeout_add_seconds(5, self.remove_stream, stream_event)
+
+ def populate_treeview(self, data=None):
+ self._treestore.clear()
+ self._circ_to_iter = {}
+ self._stream_to_iter = {}
+
+ for c in self.controller.get_circuits():
+ self.add_circuit(c)
+ for s in self.controller.get_streams():
+ self.add_stream(s)
+ self._treeview.expand_all()
+ return True
+
+ # CRICUIT DETAILS
+ # ===============
+
+ def cb_treeselection_changed(self, treeselection, data=None):
+ (model, selected_iter) = treeselection.get_selected()
+ if not selected_iter:
+ return False
+
+ if model.get_value(selected_iter, 0) == self.TYPE_STREAM: # Stream
+ circuit_iter = model.iter_parent(selected_iter)
+ else: # Circuit
+ circuit_iter = selected_iter
+
+ circ_id = model.get_value(circuit_iter, 1)
+ try:
+ circuit = self.controller.get_circuit(circ_id)
+ except ValueError, e: # The circuit doesn't exist anymore
+ logging.debug("circuit %i not known by Tor: %s" % (circ_id, e))
+ return False
+ self.show_circuit_details(circuit)
+ return False
+
+ def download_descriptors(self, path):
+ descriptors = {}
+ for desc in self.get_application().get_downloader().get_server_descriptors(
+ [fp for fp, nick in path], timeout=10):
+ descriptors[desc.fingerprint] = desc
+ GLib.idle_add(self.descriptor_downloaded_cb,
+ [descriptors[fp] for fp, nick in path])
+
+ def descriptor_downloaded_cb(self, descriptors):
+ # Replace the old content of _path by a fresh ListBox.
+ self._path.destroy()
+ self._path = Gtk.ListBox()
+ self._hbox.pack_start(self._path, expand=True, fill=True, padding=0)
+
+ # Display the nodes descriptors.
+ for desc in descriptors:
+ self.display_node(desc)
+ self._path.show_all()
+
+ return False
+
+ def show_circuit_details(self, circuit):
+ logging.debug("looking up details for %s" % circuit)
+
+ # Replace the old content of _path by a spinner and a label while we're
+ # downloading descriptors.
+ self._path.destroy()
+ self._path = Gtk.Grid()
+ spinner = Gtk.Spinner()
+ spinner.start()
+ spinner.set_size_request(48, 48)
+ spinner.set_halign(Gtk.Align.CENTER)
+ spinner.set_valign(Gtk.Align.END)
+ spinner.set_hexpand(True)
+ spinner.set_vexpand(True)
+ self._path.attach(spinner, 0, 0, 1, 1)
+ label = Gtk.Label(_("Downloading circuit details..."))
+ label.set_halign(Gtk.Align.CENTER)
+ label.set_valign(Gtk.Align.START)
+ label.set_hexpand(True)
+ label.set_vexpand(True)
+ self._path.attach(label, 0, 1, 1, 1)
+ self._path.show_all()
+ self._hbox.pack_start(self._path, expand=True, fill=True, padding=0)
+
+ # Launch descriptors download
+ threading.Thread(target=self.download_descriptors,
+ args=[circuit.path]
+ ).start()
+
+ def display_node(self, desc):
+ country = self.controller.get_info("ip-to-country/%s" % desc.address)
+ if pycountry:
+ country = pycountry.countries.get(alpha2=country.upper()).name
+
+ uptime = datetime.timedelta(seconds = desc.uptime)
+
+ grid = Gtk.Grid()
+ grid.set_property('row-spacing', 6)
+ grid.set_property('column-spacing', 12)
+ grid.set_property('margin', 12)
+
+ title = Gtk.Label()
+ title.set_markup("<b>%s</b>" % desc.nickname)
+ title.set_halign(Gtk.Align.START)
+ grid.attach(title, 0, 0, 2, 1)
+
+ line = 1
+ for l, v in [(_("Fingerprint:"), desc.fingerprint),
+ (_("Published:"), desc.published),
+ (_("IP:"), _("%s (%s)") % (desc.address, country)),
+ (_("Platform:"), desc.platform),
+ (_("Uptime:"), uptime)]:
+ label = Gtk.Label(l)
+ label.set_halign(Gtk.Align.START)
+ grid.attach(label, 0, line, 1, 1)
+ value = Gtk.Label(v)
+ value.set_halign(Gtk.Align.START)
+ grid.attach(value, 1, line, 1, 1)
+ line += 1
+
+ self._path.add(grid)
+ grid.show_all()
+
+class TorMonitorApplication(Gtk.Application):
+
+ def __init__(self):
+ Gtk.Application.__init__(self)
+
+ self.connect_controller()
+
+ # Initialise the downloader in the background
+ self._downloader = None
+ self._downloader_thread = threading.Thread(target=self.create_downloader)
+ self._downloader_thread.start()
+
+ def connect_controller(self):
+ self.controller = stem.connection.connect_socket_file()
+ return self.controller
+
+ def get_downloader(self):
+ # If the downloader is not ready, join its initialisation thread to the caller's
+ if not self._downloader:
+ logging.debug("downloader not ready, joining threads")
+ self._downloader_thread.join()
+ return self._downloader
+
+ def create_downloader(self):
+ self._downloader = stem.descriptor.remote.DescriptorDownloader(use_mirrors = True)
+
+ def do_activate(self):
+ win = TorMonitorWindow(self)
+ win.show_all()
+
+ def do_startup(self):
+ Gtk.Application.do_startup(self)
+
+app = TorMonitorApplication()
+exit_status = app.run(sys.argv)
+sys.exit(exit_status)
diff --git a/tormonitor.desktop b/tormonitor.desktop
new file mode 100644
index 0000000..316399f
--- /dev/null
+++ b/tormonitor.desktop
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Name=Tor Monitor
+Comment=Display Tor circuits and streams
+TryExec=tormonitor
+Exec=tormonitor
+StartupNotify=true
+Terminal=false
+Type=Application
+Icon=tormonitor
+Categories=GTK;Network;
diff --git a/tormonitor.svg b/tormonitor.svg
new file mode 100644
index 0000000..468f412
--- /dev/null
+++ b/tormonitor.svg
@@ -0,0 +1,330 @@
+<?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"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="256"
+ height="256"
+ id="图层_1"
+ inkscape:version="0.48.5 r10040"
+ <metadata
+ id="metadata22">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs20">
+ <radialGradient
+ id="radialGradient2842"
+ gradientUnits="userSpaceOnUse"
+ cx="24.129999"
+ cy="37.967999"
+ r="16.528999"
+ gradientTransform="matrix(1,0,0,0.23797,0,28.933)">
+ <stop
+ id="stop4479"
+ offset="0" />
+ <stop
+ id="stop4481"
+ stop-opacity="0"
+ offset="1" />
+ </radialGradient>
+ <linearGradient
+ id="linearGradient2852"
+ y2="30.558001"
+ gradientUnits="userSpaceOnUse"
+ y1="26.58"
+ x2="31.336"
+ x1="27.365999">
+ <stop
+ id="stop2848"
+ stop-color="#8a8a8a"
+ offset="0" />
+ <stop
+ id="stop2850"
+ stop-color="#484848"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4446"
+ y2="31.062"
+ gradientUnits="userSpaceOnUse"
+ x2="33.219002"
+ gradientTransform="matrix(1.3346,0,0,1.2913,-6.9738,-7.4607)"
+ y1="34"
+ x1="30.656">
+ <stop
+ id="stop4442"
+ stop-color="#7d7d7d"
+ offset="0" />
+ <stop
+ id="stop4448"
+ stop-color="#b1b1b1"
+ offset=".5" />
+ <stop
+ id="stop4444"
+ stop-color="#686868"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2372"
+ y2="25.743"
+ gradientUnits="userSpaceOnUse"
+ y1="13.602"
+ x2="17.500999"
+ x1="18.292999">
+ <stop
+ id="stop2368"
+ stop-color="#fff"
+ offset="0" />
+ <stop
+ id="stop2374"
+ stop-color="#fff"
+ stop-opacity=".21905"
+ offset=".5" />
+ <stop
+ id="stop2370"
+ stop-color="#fff"
+ offset="1" />
+ </linearGradient>
+ <radialGradient
+ id="radialGradient4493"
+ gradientUnits="userSpaceOnUse"
+ cy="37.967999"
+ cx="24.129999"
+ gradientTransform="matrix(1,0,0,0.23797,0,28.933)"
+ r="16.528999">
+ <stop
+ id="stop4489"
+ stop-color="#fff"
+ offset="0" />
+ <stop
+ id="stop4491"
+ stop-color="#fff"
+ stop-opacity="0"
+ offset="1" />
+ </radialGradient>
+ <radialGradient
+ id="radialGradient4460"
+ gradientUnits="userSpaceOnUse"
+ cy="21.818001"
+ cx="18.240999"
+ r="8.3085003">
+ <stop
+ id="stop4456"
+ stop-color="#729fcf"
+ stop-opacity=".20784"
+ offset="0" />
+ <stop
+ id="stop4458"
+ stop-color="#729fcf"
+ stop-opacity=".67619"
+ offset="1" />
+ </radialGradient>
+ <radialGradient
+ id="radialGradient4473"
+ gradientUnits="userSpaceOnUse"
+ cy="13.078"
+ cx="15.414"
+ gradientTransform="matrix(2.593,0,0,2.2521,-25.06,-18.941)"
+ r="6.6561999">
+ <stop
+ id="stop4469"
+ stop-color="#fff"
+ offset="0" />
+ <stop
+ id="stop4471"
+ stop-color="#fff"
+ stop-opacity=".24762"
+ offset="1" />
+ </radialGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2852"
+ id="linearGradient3312"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.5930626,0,0,2.5930626,81.86829,74.451177)"
+ x1="27.365999"
+ y1="26.58"
+ x2="31.336"
+ y2="30.558001" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4446"
+ id="linearGradient3314"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.4607013,0,0,3.3484217,63.78479,55.105115)"
+ x1="30.656"
+ y1="34"
+ x2="33.219002"
+ y2="31.062" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2372"
+ id="linearGradient3316"
+ gradientUnits="userSpaceOnUse"
+ x1="18.292999"
+ y1="13.602"
+ x2="17.500999"
+ y2="25.743" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#radialGradient4460"
+ id="radialGradient3318"
+ gradientUnits="userSpaceOnUse"
+ cx="18.240999"
+ cy="21.818001"
+ r="8.3085003" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#radialGradient4473"
+ id="radialGradient3320"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(6.7238113,0,0,5.8398363,16.886141,25.335978)"
+ cx="15.414"
+ cy="13.078"
+ r="6.6561999" />
+ </defs>
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1280"
+ inkscape:window-height="773"
+ id="namedview18"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:zoom="1.2756757"
+ inkscape:cx="153.41641"
+ inkscape:cy="146.63862"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="图层_1" />
+ <path
+ d="m 118.4668,8.450985 29.56604,12.265868 c 0,7.518094 -0.61115,30.44852 4.08997,37.212603 49.17194,63.327924 40.89911,190.269954 -9.96086,193.526324 -77.4495,0 -106.986987,-52.61381 -106.986987,-100.97143 0,-44.09771 52.865153,-73.41241 84.436377,-99.468899 8.0171,-7.01542 6.6249,-22.519884 -1.14454,-42.564466 z"
+ id="path2534"
+ style="fill:#fffcdb"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 148.04172,20.275619 10.65527,5.43552 c -1.00168,7.013585 0.50084,22.550613 7.51443,26.557328 31.07038,19.292405 60.38324,40.338666 71.90989,61.384923 41.09084,74.16461 -28.81386,142.81446 -89.19711,136.29987 32.82241,-24.30446 42.34386,-74.16276 30.06688,-128.53411 -5.01023,-21.29759 -12.77966,-40.589998 -26.561,-62.388435 -5.9701,-10.700093 -3.88569,-23.970245 -4.38836,-38.755096 z"
+ id="path2536"
+ style="fill:#7d4698"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline"
+ id="layer4"
+ transform="matrix(1.8345764,0,0,1.8345764,-325.3193,-202.78493)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path2538"
+ d="m 255.226,120.58877 12.018,1.639 c -3.551,11.745 6.966,19.939 10.38,21.852 7.64801,4.234 15.02301,8.604 20.89601,13.93 11.063,10.106 17.345,24.31 17.345,39.333 0,14.886 -6.829,29.226 -18.301,38.786 -10.789,9.014 -25.67501,12.838 -40.15201,12.838 -9.014,0 -17.072,-0.409 -25.812,-3.278 -19.939,-6.692 -34.826,-23.763 -36.055,-44.25 -1.093,-15.979 2.458,-28.134 14.887,-40.835 6.418,-6.692 19.393,-14.34 28.271,-20.486 4.371,-3.005 9.014,-11.473 0.136,-27.451 l 1.776,-1.366 13.15659, [...]
+ <path
+ inkscape:connector-curvature="0"
+ id="path2540"
+ d="m 251.539,140.80177 c -1.229,6.283 -2.595,17.618 -8.058,21.852 -2.322,1.638 -4.644,3.278 -7.102,4.916 -9.833,6.693 -19.667,12.974 -24.173,29.09 -0.956,3.415 -0.136,7.102 0.684,10.516 2.458,9.833 9.423,20.486 14.886,26.769 0,0.273 1.093,0.956 1.093,1.229 4.507,5.327 5.873,6.829 22.944,10.652 l -0.41,1.913 c -10.243,-2.731 -18.71,-5.189 -24.037,-11.336 0,-0.136 -0.956,-1.093 -0.956,-1.093 -5.736,-6.556 -12.702,-17.481 -15.296,-27.724 -0.956,-4.098 -1.775,-7.238 -0.683,-11.473 4.6 [...]
+ <path
+ inkscape:connector-curvature="0"
+ id="path2542"
+ d="m 255.90625,166.74951 c 0.137,7.102 -0.55625,10.66475 1.21875,15.71875 1.092,3.004 4.782,7.1015 5.875,11.0625 1.502,5.327 3.138,11.19901 3,14.75001 0,4.09799 -0.25625,11.74249 -2.03125,19.93749 -1.35362,6.77108 -4.47323,12.58153 -9.71875,15.875 -5.37327,-1.10644 -11.68224,-2.99521 -15.40625,-6.1875 -7.238,-6.282 -13.64875,-16.7865 -14.46875,-25.9375 -0.682,-7.51099 6.27275,-18.5885 15.96875,-24.1875 8.194,-4.78 10.1,-10.22775 11.875,-18.96875 -2.458,7.648 -4.7665,14.05925 -12.6 [...]
+ <path
+ inkscape:connector-curvature="0"
+ id="path2544"
+ d="m 255.09375,193.53076 c 0.136,4.78 2.056,10.90451 2.875,17.18751 0.684,4.64399 0.387,9.30824 0.25,13.40624 -0.13495,4.74323 -1.7152,13.24218 -3.875,17.375 -2.03673,-0.93403 -2.83294,-1.99922 -4.15625,-3.71875 -1.638,-2.322 -2.75075,-4.644 -3.84375,-7.375 -0.819,-2.049 -1.7765,-4.394 -2.1875,-7.125 -0.546,-4.097 -0.393,-10.5065 4.25,-17.06249 3.551,-5.19001 4.36475,-5.58476 5.59375,-11.59376 -1.64,5.326 -2.8625,5.869 -6.6875,10.37501 -4.233,4.917 -4.9375,12.15924 -4.9375,18.0312 [...]
+ <path
+ inkscape:connector-curvature="0"
+ id="path2550"
+ d="m 255.499,135.06577 c 0.137,7.101 0.683,20.35 2.595,25.539 0.546,1.775 5.599,9.56 9.149,18.983 2.459,6.556 3.005,12.565 3.415,14.34 1.639,7.785 -0.41,20.896 -3.142,33.324 -1.365,6.692 -6.009,15.023 -11.335,18.301 l -1.092,1.912 c 3.005,-0.137 10.379,-7.375 12.974,-16.389 4.371,-15.296 6.146,-22.398 4.098,-39.333 -0.273,-1.64 -0.956,-7.238 -3.551,-13.248 -3.824,-9.151 -9.287,-17.891 -9.969,-19.667 -1.23,-2.867 -2.869,-15.295 -3.142,-23.762 z" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path2552"
+ d="m 258.06151,125.35303 c -0.40515,7.29812 -0.51351,9.98574 0.85149,15.31174 1.502,5.873 9.151,14.34 12.292,24.037 6.009,18.574 4.507,42.884 0.136,61.867 -1.638,6.691 -9.424,16.389 -17.208,19.529 l 5.736,1.366 c 3.141,-0.137 11.198,-7.648 14.34,-16.252 5.052,-13.521 6.009,-29.636 3.96,-46.571 -0.137,-1.639 -2.869,-16.252 -5.463,-22.398 -3.688,-9.15 -10.244,-17.345 -10.926,-19.119 -1.228,-3.005 -3.92651,-9.24362 -3.71849,-17.77074 z" />
+ <rect
+ id="rect2556"
+ y="120.21686"
+ x="253.71959"
+ height="126.01891"
+ width="0.550412" />
+ </g>
+ <g
+ id="g3293"
+ transform="matrix(1.989497,0,0,1.989497,-173.35492,-119.80229)">
+ <path
+ d="m 130.17186,82.602729 c -21.10753,0 -38.234708,17.128734 -38.234708,38.232111 -5.19e-4,21.10494 17.127178,38.23471 38.234708,38.23471 9.02126,0 16.98715,-3.5888 23.52686,-8.8216 -0.53158,2.60862 -0.20226,5.27689 1.96035,7.15426 l 28.43293,24.7067 c 3.19725,2.77717 8.00479,2.41414 10.78196,-0.7857 2.77976,-3.19724 2.41414,-8.00478 -0.78311,-10.78195 l -28.43034,-24.7067 c -1.74253,-1.51176 -3.87144,-1.96036 -5.9796,-1.66734 5.14982,-6.51377 8.72307,-14.38631 8.72307,-23.33238 0, [...]
+ stroke-miterlimit="10"
+ style="color:#000000;fill:#dcdcdc;fill-rule:evenodd;stroke:url(#linearGradient3312);stroke-width:5.18612528;stroke-linecap:round;stroke-miterlimit:10"
+ sodipodi:nodetypes="csscccscccscczzzz"
+ id="path2844"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 130.10703,82.438847 c -21.17495,0 -38.359171,17.184226 -38.359171,38.359173 10e-4,21.17236 17.184221,38.35658 38.359171,38.35658 9.05239,0 17.04161,-3.60176 23.60465,-8.85012 -0.53417,2.61899 -0.20226,5.29504 1.96814,7.1776 l 28.52109,24.78708 c 3.20762,2.78495 8.03331,2.42192 10.81826,-0.78829 2.78754,-3.20762 2.42192,-8.03071 -0.7857,-10.81825 l -28.52369,-24.7845 c -1.74513,-1.51694 -3.88181,-1.96813 -5.99775,-1.67252 5.16797,-6.53711 8.75159,-14.43558 8.75159,-23.40758 0, [...]
+ style="color:#000000;fill:#dcdcdc;fill-rule:evenodd"
+ id="path4430"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ d="m 184.31241,182.26553 c -1.24207,-5.89403 3.62251,-12.47781 9.29354,-12.41817 L 165.7046,145.84078 c -7.63657,-0.1478 -11.07238,5.89403 -9.794,11.92809 l 28.40181,24.49666 z"
+ style="color:#000000;fill:url(#linearGradient3314);fill-rule:evenodd"
+ id="path4438"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:cx="17.500893"
+ sodipodi:cy="18.920233"
+ d="m 28.549437,18.920233 c 0,6.101942 -4.946602,11.048544 -11.048544,11.048544 -6.101943,0 -11.0485443,-4.946602 -11.0485443,-11.048544 0,-6.101943 4.9466013,-11.0485442 11.0485443,-11.0485442 6.101942,0 11.048544,4.9466012 11.048544,11.0485442 z"
+ sodipodi:type="arc"
+ stroke-miterlimit="10"
+ transform="matrix(3.2301781,0,0,3.2301781,72.986273,58.433829)"
+ style="color:#000000;fill:none;stroke:url(#linearGradient3316);stroke-width:0.80273002;stroke-linecap:round;stroke-miterlimit:10"
+ sodipodi:ry="11.048544"
+ sodipodi:rx="11.048544"
+ id="path4450" />
+ <rect
+ x="215.30113"
+ y="2.5537879"
+ height="11.514462"
+ stroke-miterlimit="10"
+ width="49.392918"
+ transform="matrix(0.75298602,0.65803652,-0.64890183,0.76087214,0,0)"
+ rx="5.540626"
+ style="opacity:0.43316004;color:#000000;fill:none;stroke:#ffffff;stroke-width:2.59306574;stroke-linecap:round;stroke-miterlimit:10"
+ ry="4.8954291"
+ id="rect4495" />
+ <path
+ sodipodi:cx="17.589281"
+ sodipodi:cy="18.478292"
+ d="m 25.897786,18.478292 c 0,4.588661 -3.719844,8.308506 -8.308505,8.308506 -4.588661,0 -8.308505,-3.719845 -8.308505,-8.308506 0,-4.58866 3.719844,-8.308505 8.308505,-8.308505 4.588661,0 8.308505,3.719845 8.308505,8.308505 z"
+ sodipodi:type="arc"
+ stroke-miterlimit="10"
+ transform="matrix(3.6266574,0,0,3.6266574,65.72829,52.93135)"
+ style="color:#000000;fill:url(#radialGradient3318);fill-rule:evenodd;stroke:#3063a3;stroke-width:0.71499002;stroke-linecap:round;stroke-miterlimit:10"
+ sodipodi:ry="8.3085051"
+ sodipodi:rx="8.3085051"
+ id="path4452" />
+ <path
+ d="m 128.95053,93.631283 c -13.50467,0 -24.43858,10.935727 -24.43858,24.437797 0,3.89997 1.08986,7.48877 2.7152,10.76121 3.24781,1.198 6.69658,2.01222 10.35798,2.01222 16.00179,0 28.783,-12.60747 29.76836,-28.36033 -4.48859,-5.304884 -10.91679,-8.850897 -18.40296,-8.850897 z"
+ style="opacity:0.83422002;color:#000000;fill:url(#radialGradient3320);fill-rule:evenodd"
+ id="path4462"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/tor-monitor.git
More information about the Pkg-privacy-commits
mailing list