Compare commits

...

8 Commits
0.1 ... main

Author SHA1 Message Date
84361afe5c correct commandline example 2023-09-23 11:39:15 +00:00
Tilman Kranz
22a18a2069 label listed updates in text output 2023-07-21 14:02:12 +02:00
Tilman Kranz
943af1a316 ensure only one subprocess is running at a time 2023-07-21 12:52:51 +02:00
Tilman Kranz
94ebd86d35 optimized png for storage size 2023-07-20 20:49:36 +02:00
Tilman Kranz
4daa42e883 add screenshot 2023-07-20 17:49:03 +02:00
Tilman Kranz
106bd53a55 code formatting cleanup; vim modeline 2023-07-20 09:57:56 +02:00
Tilman Kranz
0caa892f25 improved output formatting 2023-07-20 08:02:45 +02:00
Tilman Kranz
5e8c57937f new icon 2023-07-20 08:02:30 +02:00
4 changed files with 320 additions and 117 deletions

View File

@ -8,10 +8,12 @@ A GUI for basic tasks of package management using apt:
* Check for and list all available upgrades
* Download and install all available upgrades
![Screenshot](doc/screenshot.png "Screenshot: Updating the Package Cache")
## Dependencies
```shell
apt install python3-gi
sudo apt install python3-gi
```
## Installation

View File

@ -60,9 +60,8 @@ class UpdateWindow(Gtk.ApplicationWindow):
self.buffer.set_text("")
def scroll_to_bottom(self):
adj = self.scrolledwindow.get_vadjustment()
adj.set_value(adj.get_upper())
self.scrolledwindow.set_vadjustment(adj)
self.buffer.get_end_iter()
self.text_view.scroll_to_mark(self.text_mark_end, 0, False, 0, 0)
def level_to_color(self, level):
if level == "INFO":
@ -72,63 +71,104 @@ class UpdateWindow(Gtk.ApplicationWindow):
else:
return "grey"
def prepend_mesg(self, level, text):
self.prepend(text)
self.prepend_color(level + ": ", self.level_to_color(level))
def append_mesg(self, level, text):
self.append_color(level + ": ", self.level_to_color(level))
self.append_color(
level + ": ",
self.level_to_color(level)
)
self.append(text)
def prepend_markup(self, markup):
self.insert_markup(markup, self.buffer.get_start_iter())
def append_markup(self, markup):
self.insert_markup(markup, self.buffer.get_end_iter())
self.insert_markup(
markup,
self.buffer.get_end_iter()
)
def insert_markup(self, markup, iter):
self.buffer.insert_markup(iter, markup, -1)
def prepend_color(self, text, color):
self.insert_color(text, color, self.buffer.get_start_iter())
def append_color(self, text, color):
self.insert_color(text, color, self.buffer.get_end_iter())
self.insert_color(
text,
color,
self.buffer.get_end_iter()
)
def insert_color(self, text, color, iter):
self.buffer.insert_markup(
iter,
"<span color=\"%s\">%s</span>" % (color, html.escape(text)),
"<span color=\"%s\">%s</span>" % (
color,
html.escape(text)),
-1)
def prepend(self, text):
self.insert(text, self.buffer.get_start_iter())
def append(self, text):
self.insert(text, self.buffer.get_end_iter())
self.insert(
text,
self.buffer.get_end_iter()
)
self.scroll_to_bottom()
def insert(self, text, iter):
self.buffer.insert(iter, text + "\n")
def execute(self, args, ignore_stderr=False, output_msg=None,
empty_msg=None, env={}):
def run_thread(self, args, env, prefix=None):
if self.thread is None:
do_run = True
elif not self.thread.is_alive():
do_run = True
else:
do_run = False
if do_run:
self.thread = threading.Thread(
target=self.run,
args=(args, env, prefix,))
self.thread.start()
return False
else:
return True
def execute(
self,
args,
ignore_stderr=False,
output_msg=None,
empty_msg=None,
prefix=None,
env={},
clear=True
):
self.lock()
self.clear()
if clear:
self.clear()
self.output_msg = output_msg
self.empty_msg = empty_msg
self.ignore_stderr = ignore_stderr
self.stdout = ''
self.stderr = ''
self.prepend_mesg(
self.append_mesg(
"INFO",
"Running command \"%s\" ..." % " ".join(args))
thread = threading.Thread(target=self.run, args=(args, env,))
thread.start()
def run(self, args, env={}):
GLib.timeout_add(
250,
self.run_thread,
args,
env,
prefix
)
def run(self, args, env={}, prefix=None):
p = subprocess.Popen(
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False,
args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=False,
env=dict(os.environ, **env))
sel = selectors.DefaultSelector()
@ -142,7 +182,10 @@ class UpdateWindow(Gtk.ApplicationWindow):
if data:
if key.fileobj is p.stdout:
self.stdout_queue.put(data)
if prefix is None:
self.stdout_queue.put(data)
else:
self.stdout_queue.put(prefix + " " + data)
else:
self.stderr_queue.put(data)
@ -173,24 +216,32 @@ class UpdateWindow(Gtk.ApplicationWindow):
env=env,
empty_msg="No package upgrades were performed.")
def on_upgrade(self, *args):
self.upgrade()
def update(self):
def update(self, clear=True):
args = ['/usr/bin/apt-get', '-y', 'update']
env = {'DEBIAN_FRONTEND': 'noninteractive'}
self.execute(args, env=env)
self.execute(
args,
env=env,
clear=clear,
output_msg="The package cache was refreshed."
)
def on_update(self, *args):
self.update()
def list(self):
def list(self, clear=True):
args = ['/usr/bin/apt', '-qq', 'list', '--upgradable']
self.execute(
args,
ignore_stderr=True,
output_msg="Found the following package upgrades:",
empty_msg="Currently there are no available package upgrades.")
clear=clear,
prefix="UPDATE",
output_msg="Done listing available upgrades.",
empty_msg="No package upgrades found."
)
def on_update(self, *args):
self.update()
def on_upgrade(self, *args):
self.upgrade()
def on_list(self, *args):
self.list()
@ -198,28 +249,39 @@ class UpdateWindow(Gtk.ApplicationWindow):
def on_quit(self, *args):
self.application.quit()
def process_exit(self, exit_code, empty_msg=None, output_msg=None):
self.thread.join()
if exit_code != 0:
self.append_mesg(
"ERROR",
"Command exited with code %d" % exit_code
)
elif self.stdout == '' and self.empty_msg is not None:
self.append_mesg("INFO", self.empty_msg)
elif self.stdout != '' and self.output_msg is not None:
self.append_mesg("INFO", self.output_msg)
self.unlock()
def update_buffer(self):
try:
text = self.stdout_queue.get(block=False)
match = re.fullmatch(r'(EXIT|UPDATE) (.*)', text)
self.stdout += text
self.append_mesg("STDOUT", text)
match = re.fullmatch(r'EXIT (\d+)', text)
if match is not None:
exit_code = int(match.group(1))
if exit_code != 0:
self.append_mesg(
"ERROR",
"Command exited with code %d" % exit_code)
elif self.stdout == '' and self.empty_msg is not None:
self.append_mesg("INFO", self.empty_msg)
elif self.stdout != '' and self.output_msg is not None:
self.append_mesg("INFO", self.empty_msg)
self.unlock()
if match is None:
self.stdout += text
self.append_mesg("STDOUT", text)
elif match.group(1) == 'EXIT':
exit_code = int(match.group(2))
self.process_exit(exit_code)
elif match.group(1) == 'UPDATE':
text = match.group(2)
self.stdout += text
self.append_mesg("UPDATE", text)
else:
self.stdout += text
self.append_mesg("UPDATE", text)
except queue.Empty:
pass
@ -237,20 +299,31 @@ class UpdateWindow(Gtk.ApplicationWindow):
return True
def __init__(self, application):
super(UpdateWindow, self).__init__(
super(
UpdateWindow,
self
).__init__(
application=application,
title="Simple APT Update")
title="Simple APT Update"
)
self.application = application
self.thread = None
self.stdout_queue = queue.Queue()
self.stderr_queue = queue.Queue()
GLib.timeout_add(100, self.update_buffer)
self.init_ui()
GLib.timeout_add(100, self.update_buffer)
def init_ui(self):
self.set_border_width(10)
self.set_default_size(630, 390)
hbox = Gtk.Box(spacing=6, orientation=Gtk.Orientation.VERTICAL)
hbox = Gtk.Box(
spacing=6,
orientation=Gtk.Orientation.VERTICAL
)
self.add(hbox)
grid = Gtk.Grid()
@ -269,9 +342,12 @@ class UpdateWindow(Gtk.ApplicationWindow):
grid.attach(self.list_button, 1, 0, 1, 1)
self.upgrade_button = Gtk.Button.new_from_icon_name(
"gtk-apply", Gtk.IconSize.BUTTON)
"gtk-apply",
Gtk.IconSize.BUTTON
)
self.upgrade_button.set_tooltip_text(
"Download and install all available upgrades")
"Download and install all available upgrades"
)
self.upgrade_button.connect("clicked", self.on_upgrade)
grid.attach(self.upgrade_button, 2, 0, 1, 1)
@ -280,7 +356,9 @@ class UpdateWindow(Gtk.ApplicationWindow):
grid.attach(self.spinner, 3, 0, 1, 1)
self.quit_button = Gtk.Button.new_from_icon_name(
"exit", Gtk.IconSize.BUTTON)
"exit",
Gtk.IconSize.BUTTON
)
self.quit_button.set_tooltip_text("Exit the program")
self.quit_button.set_halign(Gtk.Align.END)
self.quit_button.connect("clicked", self.on_quit)
@ -293,24 +371,32 @@ class UpdateWindow(Gtk.ApplicationWindow):
self.scrolledwindow.set_max_content_height(300)
self.buffer = Gtk.TextBuffer()
text_view = Gtk.TextView(buffer=self.buffer)
text_view.set_editable(False)
text_view.set_monospace(True)
text_view.set_cursor_visible(False)
self.text_view = Gtk.TextView(buffer=self.buffer)
self.text_view.set_editable(False)
self.text_view.set_monospace(True)
self.text_view.set_cursor_visible(False)
self.scrolledwindow.add(text_view)
text_buffer = self.text_view.get_buffer()
iter = text_buffer.get_end_iter()
self.text_mark_end = text_buffer.create_mark("", iter, False)
self.scrolledwindow.add(self.text_view)
hbox.pack_start(self.scrolledwindow, True, True, 0)
class SimpleAptUpdate(Gtk.Application):
def __init__(self):
super().__init__(application_id='de.linuxfoo.SimpleAptUpdate',
flags=Gio.ApplicationFlags.FLAGS_NONE)
self.connect('activate', self.on_activate)
signal.signal(signal.SIGINT, signal.SIG_DFL)
super(
SimpleAptUpdate,
self
).__init__(
application_id='de.linuxfoo.SimpleAptUpdate',
flags=Gio.ApplicationFlags.FLAGS_NONE
)
def do_command_line(self, cmdline):
pass
self.connect('activate', self.on_activate)
signal.signal(signal.SIGINT, signal.SIG_DFL)
def on_activate(self, application):
self.window = UpdateWindow(application)
@ -318,7 +404,10 @@ class SimpleAptUpdate(Gtk.Application):
action = Gio.SimpleAction.new("quit", None)
action.connect("activate", self.window.on_quit)
self.add_action(action)
self.set_accels_for_action('app.quit', ['<Primary>q', '<Primary>w'])
self.set_accels_for_action(
'app.quit',
['<Primary>q', '<Primary>w']
)
action = Gio.SimpleAction.new("update", None)
action.connect("activate", self.window.on_update)
@ -337,6 +426,7 @@ class SimpleAptUpdate(Gtk.Application):
self.window.present()
self.window.show_all()
self.window.list(clear=False)
##
@ -350,3 +440,5 @@ def main():
if __name__ == '__main__':
main()
# vim:fenc=utf-8:et:ts=4:sw=4

BIN
doc/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -1,40 +1,149 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--part of the matt icon theme by sixsixfive released under CC0 (https://creativecommons.org/publicdomain/zero/1.0/) on openclipart-->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 128 128">
<defs id="0">
<linearGradient id="6">
<stop id="H" stop-opacity="0.306"/>
<stop offset="1" id="I" stop-opacity="0"/>
</linearGradient>
<linearGradient id="7">
<stop id="J" stop-opacity="0.754"/>
<stop offset="1" id="K" stop-opacity="0"/>
</linearGradient>
<linearGradient id="8">
<stop id="L" stop-color="#969696"/>
<stop offset="1" id="M" stop-color="#7b7b7b"/>
</linearGradient>
<linearGradient id="9">
<stop id="N" stop-color="#d6d6d6"/>
<stop offset="1" id="O" stop-color="#bcbcbc"/>
</linearGradient>
<linearGradient id="A">
<stop id="P" stop-color="#fff"/>
<stop id="Q" offset="0.099" stop-color="#fff" stop-opacity="0.28"/>
<stop offset="1" id="R" stop-color="#fff" stop-opacity="0"/>
</linearGradient>
<radialGradient xlink:href="#9" id="B" cx="72.06" cy="39.09" r="55.29" gradientTransform="matrix(1.0158202,-0.1265619,0.1233367,0.9899345,-5.960866,9.5726837)" gradientUnits="userSpaceOnUse"/>
<linearGradient xlink:href="#8" id="C" y1="5.062" x2="0" y2="122.29" gradientUnits="userSpaceOnUse"/>
<radialGradient xlink:href="#7" id="D" cx="64.47" cy="123.18" r="36.15" gradientTransform="matrix(1,0,0,0.1021597,0,110.59188)" gradientUnits="userSpaceOnUse"/>
<filter id="E" x="-0.057" width="1.114" y="-0.897" height="2.795">
<feGaussianBlur stdDeviation="1.63995" id="S"/>
</filter>
<radialGradient xlink:href="#6" id="F" cx="68.18" cy="125.16" r="55.29" gradientTransform="matrix(0.9999658,-8.2732372e-3,1.2111425e-2,1.4638781,-1.1101262,-42.162074)" gradientUnits="userSpaceOnUse"/>
<linearGradient xlink:href="#A" id="G" y1="8.719" x2="0" y2="118.59" gradientUnits="userSpaceOnUse"/>
</defs>
<path id="1" d="M 99.12281,123.17544 A 34.649124,2.1929824 0 1 1 29.824562,123.17544 A 34.649124,2.1929824 0 1 1 99.12281,123.17544 z" transform="matrix(1.7335396,0,0,1.776976,-47.767688,-97.518674)" opacity="0.729" fill="url(#D)" filter="url(#E)" stroke-linejoin="round" stroke-width="3"/>
<path id="2" d="M 81.53125,5.0625 C 80.012371,5.0317137 78.459738,5.7474636 77.625,6.96875 C 77.624953,6.9791666 77.624953,6.9895834 77.625,7 L 68.6875,20.125 C 66.293801,19.919124 63.872046,19.924571 61.4375,20.125 L 52.15625,7.53125 C 51.035342,6.0057061 48.679084,5.2975765 46.84375,6.0625 L 36.40625,10.40625 C 34.436767,11.22709 33.307877,13.283592 33.71875,15.40625 L 36.59375,30.4375 C 34.82634,31.965221 33.219714,33.626132 31.75,35.375 L 16.09375,33.03125 C 14.21147,32.745339 12.113645,33.712045 11.28125,35.71875 L 6.9375,46.15625 C 6.9270171,46.1666 6.9166002,46.177017 6.90625,46.1875 C 6.0237532,48.31833 6.8056177,50.447781 8.59375,51.65625 L 21.53125,60.375 C 21.362663,62.963245 21.425741,65.550234 21.71875,68.125 L 9.4375,77.0625 C 9.4270171,77.07285 9.4166002,77.083267 9.40625,77.09375 C 7.7629238,78.300351 7.0441021,80.400176 7.90625,82.46875 L 9.78125,86.96875 L 11.59375,91.40625 C 11.6041,91.416733 11.614517,91.42715 11.625,91.4375 C 12.540538,93.634188 14.437031,94.486598 16.53125,94.15625 C 16.541667,94.156297 16.552083,94.156297 16.5625,94.15625 L 31.5625,91.75 C 33.185169,93.758047 34.96495,95.599042 36.90625,97.28125 L 34,112.59375 C 33.598995,114.71665 34.598039,116.7886 36.71875,117.65625 L 47.1875,121.9375 C 49.23552,122.77407 51.346462,122.04186 52.5625,120.375 L 61.875,107.65625 C 64.135567,107.84502 66.432193,107.83107 68.75,107.65625 L 77.40625,120.3125 C 78.661422,122.15281 80.883533,122.74928 82.90625,121.90625 L 93.34375,117.5625 C 95.340326,116.73037 96.331656,114.62732 96.03125,112.71875 L 93.625,97.28125 C 95.481421,95.688847 97.181565,93.969926 98.71875,92.125 L 114.3125,95.0625 C 114.32292,95.062547 114.33333,95.062547 114.34375,95.0625 C 116.31285,95.423743 118.32121,94.284677 119.15625,92.5625 L 119.1875,92.59375 L 119.21875,92.53125 C 119.24084,92.47968 119.26168,92.427581 119.28125,92.375 C 119.30259,92.344091 119.32343,92.312836 119.34375,92.28125 L 123.46875,82.15625 L 123.5,82.125 C 123.5573,82.023525 123.60945,81.919226 123.65625,81.8125 C 123.76638,81.544688 123.88174,81.176171 123.9375,80.8125 C 124.2106,79.032133 123.41988,77.438151 122.09375,76.46875 L 109.15625,67.03125 C 109.35598,64.947857 109.38959,62.846032 109.28125,60.71875 L 122.1875,51.875 C 124.10182,50.570207 124.54191,48.274988 123.75,46.375 L 121.28125,40.4375 L 118.8125,34.53125 C 118.01226,32.611195 116.0833,31.37221 113.8125,31.8125 L 98.46875,34.75 C 97.040356,33.176473 95.495441,31.736933 93.875,30.40625 L 96.3125,14.53125 C 96.586174,12.718045 95.763902,11.129454 94.46875,10.1875 C 94.028834,9.8675133 93.56027,9.6865812 93.5625,9.6875 C 93.5314,9.6766385 93.500147,9.6662208 93.46875,9.65625 L 93.34375,9.625 L 83.34375,5.5 L 83.28125,5.46875 C 83.219709,5.4356174 83.157181,5.4043531 83.09375,5.375 C 83.073022,5.3643737 83.052188,5.3539565 83.03125,5.34375 C 82.56107,5.1524705 82.037543,5.0727621 81.53125,5.0625 z M 65.59375,47.25 C 72.0069,47.284961 78.118207,51.060486 80.75,57.375 C 84.259756,65.796026 80.270215,75.394229 71.84375,78.90625 C 63.417125,82.418337 53.82355,78.455386 50.3125,70.03125 C 46.800412,61.604626 50.763365,52.01105 59.1875,48.5 C 61.283542,47.626402 63.452468,47.238327 65.59375,47.25 z" fill="url(#C)"/>
<path d="M 37.743827,13.586918 C 37.291812,13.775309 37.031625,14.281161 37.124481,14.760875 L 40.384337,31.718699 C 37.609247,33.863984 35.178223,36.37347 33.0953,39.094773 L 15.606406,36.454412 C 15.135419,36.38287 14.649048,36.634626 14.466798,37.073987 L 10.138469,47.505995 C 9.9509101,47.958866 10.122468,48.514788 10.528755,48.789368 L 25.071655,58.586331 C 24.61969,62.238027 24.751171,66.025546 25.339726,69.753701 L 11.479891,79.868381 C 11.095897,80.150323 10.909732,80.697741 11.093284,81.138142 L 12.958959,85.614496 L 14.824635,90.09085 C 15.008184,90.531248 15.528027,90.784421 15.998591,90.710193 L 32.939358,87.987657 C 35.172752,91.030268 37.770087,93.790056 40.681707,96.039863 L 37.401327,113.26529 C 37.310306,113.74714 37.584347,114.26035 38.038017,114.44596 L 48.493977,118.71611 C 48.934317,118.89598 49.455517,118.7278 49.736287,118.34294 L 60.173267,104.06351 C 63.572317,104.50002 67.065987,104.54018 70.543237,104.07958 L 80.291757,118.33302 C 80.567077,118.73669 81.109507,118.90802 81.561517,118.71963 L 91.992657,114.37209 C 92.430857,114.18946 92.662177,113.72729 92.588047,113.25632 L 89.909967,95.959623 C 92.772637,93.748499 95.270657,91.180845 97.394067,88.357649 L 114.95831,91.64142 C 115.44091,91.729954 115.90907,91.475254 116.09792,91.021845 L 116.12187,90.963661 L 120.36806,80.565885 L 120.43308,80.490585 C 120.46364,80.416273 120.47617,80.350943 120.48782,80.274967 C 120.54516,79.901164 120.39655,79.522916 120.07703,79.289347 L 105.53062,68.674423 C 105.99202,65.464222 106.0876,62.18593 105.74525,58.896513 L 120.228,49.004225 C 120.63147,48.729224 120.74452,48.161812 120.55642,47.710513 L 118.09168,41.796798 L 115.62693,35.883082 C 115.43884,35.431787 114.95628,35.112614 114.47693,35.205556 L 97.255587,38.527048 C 95.160447,35.968164 92.764917,33.72813 90.160207,31.795837 L 92.862137,13.992072 C 92.921207,13.600709 92.757187,13.228888 92.451347,13.006453 C 92.389187,12.961239 92.333967,12.924144 92.259677,12.893532 L 92.160427,12.886697 L 81.786607,8.5823195 L 81.728417,8.5583683 C 81.273467,8.3732857 80.762977,8.5264708 80.486117,8.9315382 L 70.453027,23.717454 C 66.953117,23.237972 63.370957,23.204441 59.785307,23.680878 L 49.386537,9.6020375 C 49.104237,9.2178313 48.613167,9.0567459 48.174957,9.2393814 L 37.743827,13.586918 z M 57.857227,45.307422 C 68.013047,41.074635 79.690757,45.881731 83.923547,56.037551 C 88.156337,66.193371 83.349237,77.871085 73.193417,82.103874 C 63.037597,86.336664 51.359887,81.529566 47.127097,71.373745 C 42.894307,61.217926 47.701407,49.540212 57.857227,45.307422 z" id="3" fill="url(#B)"/>
<path id="4" d="M 37.743827,13.586918 C 37.291812,13.775309 37.031625,14.281161 37.124481,14.760875 L 40.384337,31.718699 C 37.609247,33.863984 35.178223,36.37347 33.0953,39.094773 L 15.606406,36.454412 C 15.135419,36.38287 14.649048,36.634626 14.466798,37.073987 L 10.138469,47.505995 C 9.9509101,47.958866 10.122468,48.514788 10.528755,48.789368 L 25.071655,58.586331 C 24.61969,62.238027 24.751171,66.025546 25.339726,69.753701 L 11.479891,79.868381 C 11.095897,80.150323 10.909732,80.697741 11.093284,81.138142 L 12.958959,85.614496 L 14.824635,90.09085 C 15.008184,90.531248 15.528027,90.784421 15.998591,90.710193 L 32.939358,87.987657 C 35.172752,91.030268 37.770087,93.790056 40.681707,96.039863 L 37.401327,113.26529 C 37.310306,113.74714 37.584347,114.26035 38.038017,114.44596 L 48.493977,118.71611 C 48.934317,118.89598 49.455517,118.7278 49.736287,118.34294 L 60.173267,104.06351 C 63.572317,104.50002 67.065987,104.54018 70.543237,104.07958 L 80.291757,118.33302 C 80.567077,118.73669 81.109507,118.90802 81.561517,118.71963 L 91.992657,114.37209 C 92.430857,114.18946 92.662177,113.72729 92.588047,113.25632 L 89.909967,95.959623 C 92.772637,93.748499 95.270657,91.180845 97.394067,88.357649 L 114.95831,91.64142 C 115.44091,91.729954 115.90907,91.475254 116.09792,91.021845 L 116.12187,90.963661 L 120.36806,80.565885 L 120.43308,80.490585 C 120.46364,80.416273 120.47617,80.350943 120.48782,80.274967 C 120.54516,79.901164 120.39655,79.522916 120.07703,79.289347 L 105.53062,68.674423 C 105.99202,65.464222 106.0876,62.18593 105.74525,58.896513 L 120.228,49.004225 C 120.63147,48.729224 120.74452,48.161812 120.55642,47.710513 L 118.09168,41.796798 L 115.62693,35.883082 C 115.43884,35.431787 114.95628,35.112614 114.47693,35.205556 L 97.255587,38.527048 C 95.160447,35.968164 92.764917,33.72813 90.160207,31.795837 L 92.862137,13.992072 C 92.921207,13.600709 92.757187,13.228888 92.451347,13.006453 C 92.389187,12.961239 92.333967,12.924144 92.259677,12.893532 L 92.160427,12.886697 L 81.786607,8.5823195 L 81.728417,8.5583683 C 81.273467,8.3732857 80.762977,8.5264708 80.486117,8.9315382 L 70.453027,23.717454 C 66.953117,23.237972 63.370957,23.204441 59.785307,23.680878 L 49.386537,9.6020375 C 49.104237,9.2178313 48.613167,9.0567459 48.174957,9.2393814 L 37.743827,13.586918 z M 57.857227,45.307422 C 68.013047,41.074635 79.690757,45.881731 83.923547,56.037551 C 88.156337,66.193371 83.349237,77.871085 73.193417,82.103874 C 63.037597,86.336664 51.359887,81.529566 47.127097,71.373745 C 42.894307,61.217926 47.701407,49.540212 57.857227,45.307422 z" fill="url(#F)"/>
<path id="5" d="M 81.5625,10.21875 L 71.75,24.625 C 71.410855,25.125524 70.818151,25.391636 70.21875,25.3125 C 66.85521,24.851699 63.440269,24.82413 60,25.28125 C 59.417375,25.354909 58.841324,25.102887 58.5,24.625 L 48.375,10.90625 L 38.78125,14.90625 L 41.9375,31.40625 C 42.049679,31.997343 41.820166,32.601323 41.34375,32.96875 C 38.689326,35.020754 36.382461,37.439786 34.375,40.0625 C 34.020593,40.539466 33.430691,40.780243 32.84375,40.6875 L 15.75,38.125 L 11.78125,47.6875 L 25.96875,57.28125 C 26.458453,57.614982 26.723114,58.192424 26.65625,58.78125 C 26.225873,62.258524 26.337312,65.896109 26.90625,69.5 C 26.998993,70.086941 26.758216,70.676843 26.28125,71.03125 L 12.75,80.90625 L 14.4375,85 C 14.437602,85.010416 14.437602,85.020834 14.4375,85.03125 L 16.125,89.09375 L 32.6875,86.4375 C 33.274441,86.344757 33.864343,86.585534 34.21875,87.0625 C 36.37214,89.996121 38.876153,92.633071 41.65625,94.78125 C 42.132666,95.148677 42.362179,95.752657 42.25,96.34375 L 39.0625,113.15625 L 48.6875,117.09375 L 58.90625,103.125 C 59.247574,102.64711 59.823625,102.39509 60.40625,102.46875 C 63.686119,102.88995 66.988763,102.94027 70.3125,102.5 C 70.911901,102.42086 71.504605,102.68698 71.84375,103.1875 L 81.34375,117.09375 L 90.96875,113.0625 L 88.34375,96.21875 C 88.256047,95.64819 88.483051,95.074708 88.9375,94.71875 C 91.680542,92.600026 94.083445,90.089365 96.125,87.375 C 96.492427,86.898584 97.096407,86.669071 97.6875,86.78125 L 114.8125,90 L 118.78125,80.3125 L 104.59375,69.96875 C 104.11586,69.627426 103.86384,69.051375 103.9375,68.46875 C 104.3817,65.378184 104.48397,62.211395 104.15625,59.0625 C 104.10133,58.484333 104.36459,57.921921 104.84375,57.59375 L 118.9375,47.9375 L 116.625,42.40625 L 114.3125,36.875 L 97.5625,40.09375 C 96.977469,40.213051 96.374747,39.996071 96,39.53125 C 93.990773,37.077294 91.721205,34.918936 89.21875,33.0625 C 88.730038,32.715631 88.476638,32.124365 88.5625,31.53125 L 91.21875,14.1875 L 81.5625,10.21875 z M 65.625,42.1875 C 74.015976,42.233243 81.981635,47.189501 85.40625,55.40625 C 89.972083,66.361142 84.764888,78.997714 73.8125,83.5625 C 62.860181,88.127257 50.221485,82.953462 45.65625,72 C 41.091492,61.047681 46.265289,48.408985 57.21875,43.84375 C 59.961718,42.700524 62.82965,42.172262 65.625,42.1875 z" fill="none" stroke="url(#G)" stroke-width="3"/>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
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"
width="31.72216mm"
height="36.307823mm"
viewBox="0 0 31.72216 36.307823"
version="1.1"
id="svg8">
<defs
id="defs2">
<linearGradient
id="linearGradient4117">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4113" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop4115" />
</linearGradient>
<linearGradient
id="linearGradient4107"
osb:paint="solid">
<stop
style="stop-color:#2fb958;stop-opacity:1;"
offset="0"
id="stop4105" />
</linearGradient>
<linearGradient
id="linearGradient4101"
osb:paint="solid">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4099" />
</linearGradient>
<linearGradient
id="linearGradient4095"
osb:paint="solid">
<stop
style="stop-color:#bdbdbd;stop-opacity:1;"
offset="0"
id="stop4093" />
</linearGradient>
<linearGradient
id="linearGradient1878"
osb:paint="gradient">
<stop
style="stop-color:#61b97b;stop-opacity:0.51138261"
offset="0"
id="stop1874" />
<stop
style="stop-color:#2fb958;stop-opacity:0"
offset="1"
id="stop1876" />
</linearGradient>
<marker
style="overflow:visible"
id="Arrow2Lend"
refX="0"
refY="0"
orient="auto">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path892" />
</marker>
<linearGradient
xlink:href="#linearGradient4095"
id="linearGradient4087"
x1="41.938935"
y1="60.562257"
x2="50.744767"
y2="60.562257"
gradientUnits="userSpaceOnUse" />
<linearGradient
xlink:href="#linearGradient4095"
id="linearGradient4089"
x1="22.932867"
y1="48.843493"
x2="42.555965"
y2="48.843493"
gradientUnits="userSpaceOnUse" />
<linearGradient
xlink:href="#linearGradient4095"
id="linearGradient4097"
gradientUnits="userSpaceOnUse"
x1="19.885436"
y1="48.390368"
x2="51.607597"
y2="48.390368" />
<linearGradient
xlink:href="#linearGradient4117"
id="linearGradient4121"
x1="22.932867"
y1="48.843493"
x2="42.555965"
y2="48.843493"
gradientUnits="userSpaceOnUse" />
<linearGradient
xlink:href="#linearGradient4117"
id="linearGradient4123"
x1="19.885436"
y1="48.390368"
x2="51.607597"
y2="48.390368"
gradientUnits="userSpaceOnUse" />
</defs>
<metadata
id="metadata5">
<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>
<g
id="layer1"
transform="translate(-19.885436,-34.013894)">
<rect
style="fill:url(#linearGradient4123);fill-opacity:1;stroke:url(#linearGradient4097);stroke-width:0.999999;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke;stroke-opacity:1"
id="rect867"
width="30.722162"
height="27.752951"
x="20.385435"
y="34.513893"
ry="2.9184699" />
<path
style="fill:url(#linearGradient4121);stroke:url(#linearGradient4089);stroke-width:3.765;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
d="m 24.815338,34.950563 c 0.145105,26.252732 17.704313,25.913942 17.704313,25.913942"
id="path1321" />
<path
style="fill:#bebebe;fill-opacity:1;stroke:url(#linearGradient4087);stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 42.10017,59.891406 -0.02493,-8.714785 8.491092,10.446869 -8.494225,8.380984 z"
id="path1869" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB