[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