From be9d28c2557bdf09203bbc124b9fd434325ccc47 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 21 Jul 2012 07:36:06 +0200 Subject: [PATCH 01/11] djeuscan: helpers.py is actually unused Signed-off-by: Corentin Chary --- euscanwww/djeuscan/helpers.py | 108 ---------------------------------- 1 file changed, 108 deletions(-) delete mode 100644 euscanwww/djeuscan/helpers.py diff --git a/euscanwww/djeuscan/helpers.py b/euscanwww/djeuscan/helpers.py deleted file mode 100644 index f7a6b82..0000000 --- a/euscanwww/djeuscan/helpers.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -djeuscan.helpers -""" - -from distutils.version import StrictVersion, LooseVersion - - -def xint(i): - """ - Tries to cast to int, fallbacks to 0 - """ - try: - return int(i) - except Exception: - return 0 - - -def select_related_last_versions(queryset): - queryset = queryset.select_related( - 'last_version_gentoo', - 'last_version_overlay', - 'last_version_upstream' - ) - - -def version_key(version): - version = version.version - try: - return StrictVersion(version) - # in case of abnormal version number, fall back to LooseVersion - except ValueError: - return LooseVersion(version) - - -def packages_from_names(data): - """ - Returns a list of Package objects from a string of names - """ - - from djeuscan.models import Package - - packages = [] - data = data.replace("\r", "") - - for pkg in data.split('\n'): - if '/' in pkg: - cat, pkg = pkg.split('/') - packages.extend(Package.objects.filter(category=cat, name=pkg)) - else: - packages.extend(Package.objects.filter(name=pkg)) - return packages - - -def rename_fields(vqs, fields): - ret = [] - for n in vqs: - for tr in fields: - if tr[0] in n: - n[tr[1]] = n[tr[0]] - del n[tr[0]] - ret.append(n) - return ret - - -class catch_and_return(object): - def __init__(self, err, response): - self.err = err - self.response = response - - def __call__(self, fn): - def wrapper(*args, **kwargs): - try: - return fn(*args, **kwargs) - except self.err: - return self.response - return wrapper - - -def get_account_categories(user): - from djeuscan.models import Package, CategoryAssociation - - # TODO: This is quite ugly - category_names = [obj.category for obj in - CategoryAssociation.objects.filter(user=user)] - return [c for c in Package.objects.categories() - if c["category"] in category_names] - - -def get_account_herds(user): - from djeuscan.models import Package, HerdAssociation - - ids = [obj.herd.pk for obj in - HerdAssociation.objects.filter(user=user)] - return Package.objects.herds(ids=ids) - - -def get_account_maintainers(user): - from djeuscan.models import Package, MaintainerAssociation - - ids = [obj.maintainer.pk for obj in - MaintainerAssociation.objects.filter(user=user)] - return Package.objects.maintainers(ids=ids) - - -def get_account_packages(user): - from djeuscan.models import PackageAssociation - return [obj.package for obj in - PackageAssociation.objects.filter(user=user)] From b0cd34ed75d202306999a35cd827899cefd61ab2 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 21 Jul 2012 07:36:35 +0200 Subject: [PATCH 02/11] djeuscan: portage. can be used instead of PORTDB Signed-off-by: Corentin Chary --- euscanwww/djeuscan/processing/scan/scan_portage.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/euscanwww/djeuscan/processing/scan/scan_portage.py b/euscanwww/djeuscan/processing/scan/scan_portage.py index a30254e..79fa62a 100644 --- a/euscanwww/djeuscan/processing/scan/scan_portage.py +++ b/euscanwww/djeuscan/processing/scan/scan_portage.py @@ -13,9 +13,6 @@ from euscan.version import get_version_type from djeuscan.processing import FakeLogger from djeuscan.models import Package, Version, VersionLog -PORTDB = None - - class ScanPortage(object): def __init__(self, logger=None, no_log=False, purge_packages=False, purge_versions=False): @@ -24,10 +21,6 @@ class ScanPortage(object): self.purge_packages = purge_packages self.purge_versions = purge_versions - global PORTDB - if not PORTDB: # Lazy loading for portdb - PORTDB = portage.db[portage.root]["porttree"].dbapi - self.style = color_style() self._cache = {'packages': {}, 'versions': {}} @@ -231,7 +224,7 @@ class ScanPortage(object): package.category, package.name, ver, rev, slot, overlay ) - overlay_path = overlay_path or PORTDB.settings["PORTDIR"] + overlay_path = overlay_path or portage.settings["PORTDIR"] package_path = join(overlay_path, package.category, package.name) ebuild_path = join(package_path, "%s.ebuild" % cpv.split("/")[-1]) metadata_path = join(package_path, "metadata.xml") From 9617fd25a19f6bedd5ab9626ffb2a930e965ca05 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 24 Jul 2012 07:59:00 +0200 Subject: [PATCH 03/11] djeuscan: add cp() and cpv() for Package and Version Signed-off-by: Corentin Chary --- euscanwww/djeuscan/models.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/euscanwww/djeuscan/models.py b/euscanwww/djeuscan/models.py index 5101ea8..0c38909 100644 --- a/euscanwww/djeuscan/models.py +++ b/euscanwww/djeuscan/models.py @@ -88,9 +88,12 @@ class Package(models.Model): class Meta: unique_together = ['category', 'name'] - def __unicode__(self): + def cp(self): return '%s/%s' % (self.category, self.name) + def __unicode__(self): + return self.cp() + def save(self, *args, **kwargs): self.full_clean() @@ -137,10 +140,17 @@ class Version(models.Model): class Meta: unique_together = ['package', 'slot', 'revision', 'version', 'overlay'] + def cpv(self): + return '%s/%s-%s-%s' % ( + self.package.category, self.package.name, self.version, + self.revision if self.revision != 'r0' else '' + ) + def __unicode__(self): return '%s/%s-%s-%s:%s [%s]' % ( self.package.category, self.package.name, self.version, - self.revision, self.slot, self.overlay or "" + self.revision if self.revision != 'r0' else '', + self.slot, self.overlay or "" ) def save(self, *args, **kwargs): From 5d39cbf2fd8bfe23d73fca0d82cafa94b36f52ff Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 24 Jul 2012 07:59:40 +0200 Subject: [PATCH 04/11] djeuscan: in scan_metadata, if packages=None, skip packages scan But if packages=[], scan all packages. Signed-off-by: Corentin Chary --- euscanwww/djeuscan/processing/scan/scan_metadata.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/euscanwww/djeuscan/processing/scan/scan_metadata.py b/euscanwww/djeuscan/processing/scan/scan_metadata.py index f9e5e86..ee028d4 100644 --- a/euscanwww/djeuscan/processing/scan/scan_metadata.py +++ b/euscanwww/djeuscan/processing/scan/scan_metadata.py @@ -160,6 +160,7 @@ class ScanMetadata(object): maintainer = self.store_maintainer( maintainer_name, maintainer_email ) + herd.maintainers.add(maintainer) @@ -169,7 +170,7 @@ def scan_metadata(packages=None, category=None, logger=None, populate=False): if category: packages = Package.objects.filter(category=category) - elif not packages: + elif packages == None: packages = Package.objects.all() if populate: From 7e911bd9c6ce7d1173c0bd563a5a9cb0b0550417 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 24 Jul 2012 08:03:42 +0200 Subject: [PATCH 05/11] djeuscan: use debug to dump json on error Signed-off-by: Corentin Chary --- euscanwww/djeuscan/processing/scan/scan_upstream.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/euscanwww/djeuscan/processing/scan/scan_upstream.py b/euscanwww/djeuscan/processing/scan/scan_upstream.py index 8461a25..02b4287 100644 --- a/euscanwww/djeuscan/processing/scan/scan_upstream.py +++ b/euscanwww/djeuscan/processing/scan/scan_upstream.py @@ -31,8 +31,11 @@ class ScanUpstream(object): ebuild = out[package]["metadata"]["ebuild"] except KeyError: self.logger.error( - "Error while scanning upstream for package %s!\n%s", - package, + "Error while scanning upstream for package %s!", + package + ) + self.logger.debug( + "Error %s", out_json ) return {} From 3d6126cf81d6f7f60a1f8d192bf331994186bf29 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 24 Jul 2012 08:05:12 +0200 Subject: [PATCH 06/11] djeuscan: run scan_metadata(packages=None, populate=True) Scan only additional stuff, not packages. Signed-off-by: Corentin Chary --- euscanwww/djeuscan/tasks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/euscanwww/djeuscan/tasks.py b/euscanwww/djeuscan/tasks.py index 77cce14..07ea20f 100644 --- a/euscanwww/djeuscan/tasks.py +++ b/euscanwww/djeuscan/tasks.py @@ -158,6 +158,7 @@ def update_portage_trees(): @task def update_portage(packages=None): update_portage_trees() + scan_metadata(packages=None, populate=True) ( group_one(scan_portage, portage.settings.categories, attr_name="category", purge_packages=True, From 6bb42d72fcfb9b30d0a73ee5a142a2ea686dbd91 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 24 Jul 2012 08:06:10 +0200 Subject: [PATCH 07/11] djeuscan: display confidence and tweak result display Signed-off-by: Corentin Chary --- euscanwww/djeuscan/templates/euscan/package.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/euscanwww/djeuscan/templates/euscan/package.html b/euscanwww/djeuscan/templates/euscan/package.html index 40037d9..2357318 100644 --- a/euscanwww/djeuscan/templates/euscan/package.html +++ b/euscanwww/djeuscan/templates/euscan/package.html @@ -132,6 +132,7 @@ {% endif %} {{ version.version }} - {{ version.urls }} + {% if confidence < 100 %}({{ version.confidence }}%){% endif %} {% endfor %} @@ -168,9 +169,7 @@
euscan log

Date: {{ log.datetime }} -

-      {{ log.result|ansi_to_html|safe }}
-    
+
{{ msg|ansi_to_html|safe }}
{% endif %} From e0a5308463a8ffad5f53cdcf18a29c7549f8dc31 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 24 Jul 2012 08:07:09 +0200 Subject: [PATCH 08/11] djeuscan: add euscan result log into a variable Signed-off-by: Corentin Chary --- euscanwww/djeuscan/views.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/euscanwww/djeuscan/views.py b/euscanwww/djeuscan/views.py index b1eb056..af7d7be 100644 --- a/euscanwww/djeuscan/views.py +++ b/euscanwww/djeuscan/views.py @@ -1,6 +1,7 @@ """ Views """ import inspect +import json from annoying.decorators import render_to, ajax_request from django.http import Http404 @@ -202,6 +203,13 @@ def package(request, category, package): log = log[0] if log else None vlog = VersionLog.objects.for_package(package, order=True) + result = json.loads(log.result) if log else None + + if result and package.cp() in result: + msg = result[package.cp()]['messages'] + else: + msg = "" + try: last_scan = EuscanResult.objects.for_package(package).latest().datetime except EuscanResult.DoesNotExist: @@ -242,6 +250,7 @@ def package(request, category, package): 'upstream': upstream, 'log': log, 'vlog': vlog, + 'msg' : msg, 'last_scan': last_scan, 'favourited': favourited, 'refreshed': refreshed, From fe7a81654bf416d6063a43957a244222aa1fe5fb Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 24 Jul 2012 08:08:37 +0200 Subject: [PATCH 09/11] djeuscan: switch to ansi2html Signed-off-by: Corentin Chary --- .../djeuscan/templatetags/djeuscan_helpers.py | 6 +- euscanwww/djeuscan/utils.py | 92 ------------------- 2 files changed, 3 insertions(+), 95 deletions(-) delete mode 100644 euscanwww/djeuscan/utils.py diff --git a/euscanwww/djeuscan/templatetags/djeuscan_helpers.py b/euscanwww/djeuscan/templatetags/djeuscan_helpers.py index 2df1d07..427b421 100644 --- a/euscanwww/djeuscan/templatetags/djeuscan_helpers.py +++ b/euscanwww/djeuscan/templatetags/djeuscan_helpers.py @@ -3,8 +3,6 @@ from django.conf import settings from euscan.version import is_version_type_stable, get_version_type -from djeuscan.utils import plaintext2html - register = template.Library() @@ -73,4 +71,6 @@ def version_type(version): @register.filter def ansi_to_html(text): - return plaintext2html(text) + from ansi2html import Ansi2HTMLConverter + conv = Ansi2HTMLConverter(inline=True, linkify=True) + return conv.convert(text, full=False) diff --git a/euscanwww/djeuscan/utils.py b/euscanwww/djeuscan/utils.py deleted file mode 100644 index 60965e0..0000000 --- a/euscanwww/djeuscan/utils.py +++ /dev/null @@ -1,92 +0,0 @@ -import re -import cgi - -colorcodes = { - 'bold': ('\\\u001b[01m|\\\u001b[36;01m', '\\\u001b[39;49;00m'), - 'cyan': ('\\\u001b[36m', '\\\u001b[39m'), - 'blue': ('\\\u001b[34m', '\\\u001b[39m'), - 'red': ('\\\u001b[31m', '\\\u001b[39m'), - 'magenta': ('\\\u001b[35m', '\\\u001b[39m'), - 'green': ('\\\u001b[32;01m', '\\\u001b[39;49;00m'), - 'underline': ('\\\u001b[4m', '\\\u001b[24m'), -} - - -def recolor(color, text): - regexp = r"(?:%s)(.*?)(?:%s)" % colorcodes[color] - regexp = regexp.replace('[', r'\[') - return re.sub( - regexp, r'''\1''' % color, text - ) - - -def bold(text): - regexp = "(?:%s)(.*?)(?:%s)" % colorcodes['bold'] - regexp = regexp.replace('[', r'\[') - return re.sub(regexp, r'\1', text) - - -def underline(text): - regexp = "(?:%s)(.*?)(?:%s)" % colorcodes['underline'] - regexp = regexp.replace('[', r'\[') - return re.sub( - regexp, r'\1', text - ) - - -def removebells(text): - return text.replace('\07', '') - - -def removebackspaces(text): - backspace_or_eol = r'(.\010)|(\033\[K)' - n = 1 - while n > 0: - text, n = re.subn(backspace_or_eol, '', text, 1) - return text - - -def plaintext2html(text, tabstop=4): - def do_sub(m): - c = m.groupdict() - if c['htmlchars']: - return cgi.escape(c['htmlchars']) - if c['lineend']: - return '
' - elif c['space']: - t = m.group().replace('\t', ' ' * tabstop) - t = t.replace(' ', ' ') - return t - elif c['space'] == '\t': - return ' ' * tabstop - else: - url = m.group('protocal') - if url.startswith(' '): - prefix = ' ' - url = url[1:] - else: - prefix = '' - last = m.groups()[-1] - if last in ['\n', '\r', '\r\n']: - last = '
' - return '%s%s' % (prefix, url) - re_string = re.compile( - r'(?P[<&>])|(?P^[ \t]+)|(?P\r\n|\r|\n)|' - r'(?P(^|\s)((http|ftp)://.*?))(\s|$)', - re.S | re.M | re.I - ) - result = re.sub(re_string, do_sub, text) - - result = re.sub(r"\\n", "
", result) - - result = recolor('cyan', result) - result = recolor('blue', result) - result = recolor('red', result) - result = recolor('magenta', result) - result = recolor('green', result) - result = bold(result) - result = underline(result) - result = removebells(result) - result = removebackspaces(result) - - return result From 96a5a91e0c0fa1f608fb77fecb51a1a4a98cc4e4 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 24 Jul 2012 08:09:17 +0200 Subject: [PATCH 10/11] djeuscan: remove empty CELERYBEAT_SCHEDULE Signed-off-by: Corentin Chary --- euscanwww/euscanwww/settings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/euscanwww/euscanwww/settings.py b/euscanwww/euscanwww/settings.py index 2397c10..fc6b668 100644 --- a/euscanwww/euscanwww/settings.py +++ b/euscanwww/euscanwww/settings.py @@ -239,7 +239,6 @@ CELERYD_CONCURRENCY = 4 TASKS_UPSTREAM_GROUPS = 32 CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler" -CELERYBEAT_SCHEDULE = {} # LDAP authentication # TODO: Test data - change me! From 9d905166bed0c7554da7667a1d437d639b19b8a6 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 24 Jul 2012 08:09:47 +0200 Subject: [PATCH 11/11] djeuscan: smaller icons, change refresh icon Signed-off-by: Corentin Chary --- euscanwww/htdocs/img/refresh-active.png | Bin 1919 -> 1423 bytes euscanwww/htdocs/img/refresh-inactive.png | Bin 1809 -> 1032 bytes euscanwww/htdocs/img/unwatch-icon.png | Bin 2000 -> 821 bytes euscanwww/htdocs/img/watch-icon.png | Bin 1758 -> 1140 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/euscanwww/htdocs/img/refresh-active.png b/euscanwww/htdocs/img/refresh-active.png index c4b88d7dd0b8855a52ffa0d63d7cb83373b3aad2..6306868c455413359bc8561bdd55df9951579c27 100644 GIT binary patch literal 1423 zcmV;A1#tR_P)B30mTEcwgqc( z96-bn1(YjMNPrNo;S3>SxR1yc2#6?$kbie6ad0eCznM4tzWv_+w{Lgf?#BS|pGF=H zweRWaJtsT6Ad1fyMN|LvnAdGKs7`Wn)(@n8i;5i_oXnp;9|bk)(?0rbI!5P>z(z(3 zb<4^m%JK0D#Ky8?iBLZ;;~T48f1%efmtbZ%}mVpBbZLne~-P@F4!;G zfkU-!IP!20+^QYnQuzsfk{v*3%TZh;gGF_+aQSfn;`>g)r^bml&17hXg+(6k?HxdW z{}2?4!Ks$}kO%v08*C}wgwIPh!$xEU1FjyHWEx@hgXLIq-xy4R89c;a;+F<5oNDsM z>DHq-TC}~6GSwN+_w^0DCzUp#yIVPB>togup(WPju7-u+T^MoZtISU>tXZ>bWsJ=h z+u@D-t+1YBjt}^z*jM2QpW59xCfx(~a)+FmOF_%WKqxF9?da%5wfG?{;@-j1%w;Om z2c{!>S-SleR~MzJ_ru1W@bEc%^JX@vB_#=vnkoc8 zPo#2B*fXh_p~)iP!zMg~Z&#(7TF(S?I2VK^-j0a4{+tE~1eM5>6yi$W73G3-{Y{2E-L=cI4VYU?ER0=>-`6{yvQJM` zRNURvB1dk1C6YJ-P%ULlvozFIp&b*GcquL}{Y6?@A=1+e(c0RL%4RXLs0CK1EkoKZ=SZG>*)$f+jPir!2};XS^UZ z^s>Uw?_{&1y-ndqoZp=+IiHxyu8C|Ya2msHUe&+0(EqBK`!qiZ6|q`lX{nv z(rm@SgGa*Dx@m@n8vGJI-Ofo!;FQpPyd>HR{iZ d)1K{z`VW`BewjY9;Cui8002ovPDHLkV1i0lvl0LR literal 1919 zcmV-_2Y~pAP)l~UD;FI=ELjpkN$Z+lUm3Mu#aYFp`m)9XcI|Ete*_ka(eU>$eV3}DE?z{q# z&JTty(|T&z+O7jP1ZZx&d!+13-wt&5{R@)GtJ}e%n-GINvYhjHenB}%WW-tN&7Q8A z%7E^cQ_$bj@mefyJ@(*J1IF|KXYUG^<*&|QT%%{;5{Kw(^SVnG=4KZIVzJ5IH|=7! zf*a1CIS1_*n*W|ivWI@MZTLEfG{BjPaB0q0Gk_(5ArELK16AZ|{P%Tc6S8pe^Jo0cfgQIa=gh;kX-`UDeId+12~~s*|ZB zPGjxyrLjA57I|!8TMP)V3E~N52=rtdP!t2cH*n>m8w_38QTb^1(=$2z{@(`u9tFKs zilfCo!Ib5^C6b&|ET(5oFYW!NKJ@nct*;(DsXy)joH%sH*kXmb#f*8}dHiVrJJphO zp==OL+QIWv9EL9YfN5lV#oCUIGeOku&bl8ZQX30d%!P=mx=Zg-d9z()UZl=Yg6ulf z*m~%cagPIVcwgDjQrwqGWIJR zP6u#uXQmoY&^@=Ku!p;osuY&Hu;jW1p(ImOdgkRu?P$HR!~r<4`?hD2N$c5^Mpa#> zeCsJ=l-U762?i?hoWr@WBJ+rs0P>3RjQo=P=N6Qocy6X$IJPzL>_QwZR0TdXxIhtH zK}Xz%;L#-iVs{JisjzC!*YVBT(Jg^rm62GkicMQwL84pX`9xvVlqt28UspvXugbnP z8-SAy{9cTrF>1|K{Jj@~QX&EC7mK4RVx~NP_R4rI$91f1d56$98}uLF2*7zZF9YL; zD>E^V4r}+pK{^+J(|fZ^tvFjxbbHk>(~WC)a@yXmDnT9vWQCxhi;{pi8g_xM+2SJK z0nr8k!xRx?V$@K@opk~en11xNI^CKTpfq1V0WX4t#@P8zi^1f5i4VRsAE^q#UYAHR z-J;;8h60IE4_~>;g^43<+OJCJ*rF!2#RV=-Y>;TmMXDPpGxb!{pWjKDw*oK$v3_kP`sF%5zq**f zbGE%|g^SzgF4%={yI;`PH?N{Kx|r{h1OO2Fn3J?=`*(hFb0Bq2MNA%WyE;w zrLo9#gFg>Ll89j6);wIkNap|5D8`gx5z8ntpyANfsQKX5*tBo0pX*(~A<%cf=|Nw= zQ$Z^hdXOJmC_XY~t$K1~#ti!Zx{M}XXXo1S3$rgA;J;)~FN@G!L81Tv002ovPDHLk FV1fm5sQLf^ diff --git a/euscanwww/htdocs/img/refresh-inactive.png b/euscanwww/htdocs/img/refresh-inactive.png index 457c6c9926abc82d1b0623892d9df82f98f4346f..7e8585f65413e647a1a991e8fe946c513c481e96 100644 GIT binary patch literal 1032 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H0wnYHF4+L2SkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aIAngIhZYQ(t7#NrtJzX3_G|uNvj_n93m1v*;|L3gYXUVa- zY3}BikBX-G8aiuCx^SxL?IOJ>jwXSm;KeSRyJNn&8HDfR*!Z5eCn{=1>xGQH6DDxD zs0gKGxAT7UE|?@Rj6zvtM_uoWi{Y(G-HyJqEy<+abN+4X-Et=(|! zXMff^0Aaz*}H zyh_J|Ag73TnN$LZZ}TU*{X1A`gvi=7;V+BsG)UTxQBnAfy$ z%f9XA>R+F1<2N}ry`SI(6Y_i)wwi2DFr)sU4UT&Vb5A+Ub@AHTfyUJvlV0C5rzdbdTDNj~D zXO5b(y6N@QoCu%x@MrV*6n-aV&0qXZvF6I>%j(zbLo`f;mgjG`%I=&T{o`%w-keI^ zVzQq*!1h_=iS@f?{4^aV{^5d`BGjRp*6U)Z+G*(VDgKC*;&E?4P&1tHG|#=ag7ty25<|9+V672sPtx!e0@cRRn`5=oT| zCvjKjsgX)cE?E4%y6xPvBOA*!6&JiQ30(BsKP}Zs?dh^7Po_P2(spM;p=HG+jX>*O zArpa*pB@R>TwWPGss4~g;iDrvWc9kv70+dPR8=W>fx$%~IWt$yp66X${eupsUHxyO z>`gKjZB1SCo5kjV{7G}ai4Lz{X?O+hvbx~0r?TrwSNrK@4M7q??YbYQ|4RI^cB7HT zWQS=J>lx)wml!C8<`)MX5lF!N|bSNY}tz*T^Wuz|zXZ%*xPA o+rY@mz@TVV%pw#Gx%nxXX_dG&Fn@m{2h_me>FVdQ&MBb@0C)bw_W%F@ literal 1809 zcmV+s2k!WZP)J3sJOC&|(zDa)X)}$;J81%w%TXnfHCqdp^3jGefS?m}{k* zK5$@Q&N=_zdCvbl&kVsw#LUbLu`G*GN-aVNgb>{KeR=fgQT&Y``&Mbcr z;Kq#`%Y=|rxm=z&apJ_;RpP$|@aJ?o-IqutK*+`trnN>cmqR|EFAE|5aQ5ukOX~t$ zx^$_sW53f}FT!yg3=R&$w(T_#jYb1ku3V`qrH1d_ zyH{L&1w=~O74M{&5CWwX^7%YG&x2{2Xf~UepPxsuSd^aUEqR^?&iRgHGHDDC4F*i4tb6xif z##rBj2M<1b`t<2%(P%WyIUk#wn_GJQ`nA?t>xG2{U9Z>I7;|J~1f27e2M!#Fb^(MC zL@Cu3?c8m%*@To59YZ#o&3s>9-^ldz^j~h@zFqB{?9rn~wTBNMew#=nMx>N?s?}-$ zAY58n5}b1thM@|>P={ftEz82dz`!N|zwQFGS}mfK!fFTrFijJYNCdWRBOZ@q+qP|6 z`}_Md?{oX~^mH|mNc_gKtbYk1azcpZa=E+`hG8=dLqGf>#P;pmC4j>KzyRRTp+jGV zVQ5iGyJi9a!!Y1D4lK)pVHilIQV>G?;_%_aJu@>iGw*_U{P=Nj$(Vn0AUz{QVPd$5R1jI zYu7F~j+423`SR)aWkO2%Pbua1TI)Ab$~V66XN3@1Aw*sXQH(~T%R-2F_Z4u?CmW5% zAA=xp+Gf%1SD+}R$}kMY7^9YDnU-atzrR0BrBXfb0~jA4_fDNU^-3wVoiP>(f}jb& z0T2P;5JGGzrLlkieqsQ?#Kgqc0KUd246St?Km|aAa~_dWMzq!ut+lO`ifFAZt#!8& zuGg$cG#VwXR!eSFJd?>-K@e!h*a`sK_kFv4dK-YvIgc>L)a>l6Ha^s-) zjOm*o&|L?V%&0ccQ4xl+pN2m`PH*sWH}CWI7L_kwq35db-U{5bmh`pCk37{auwHE0vW28lDLODPKt@ML*S)fdi3vt2 z9keV<5JFr^X@gQ)Cxp}h)BvmiSgBMhRmRxdhcW;F2*VJB5S31+RW_SdjImDN==SDw z=gyHxBw|xalK`mi`%OX!Cxn=kQWJnFgfIb^oO5$!Wkpj;Uu_8B>eZ{Nr>948&UG%A z(;Z_1V3|yY*tSg>V}@y(41nOAd+io&05GML1|h^?jG0nOqfjUql+xGt@86f*O1NIM zS}k3x)wJunYrfmGX%iV99wxC^4DC`*wAPdmqP5lvfCL}_NUgOHLWq|yUwQ!ky|lEX zHUzL<%+Jq*5TXYM2fM!^$PfKox5Z^!ToOXW;^Lz4eSh)p-Mg*M9_+s@I1394SYBSn z-o1NQ_YvI|R&8-vDwSlpT&~`_b*sF3J^K_@FPqIG8jWJ-&Yi0Yp;lUJMJZK{Mne{h z#n!cJ*D7zXWuL0_zIgFM4-O6@9*=7PiV&hq)0D33s%o|BPfbm^?^?$`VeQB4>?~@v znkIzkSS+TLQp)#ze*XOV5dY&KKjnYt|9AWc2%+nUJQ;Ab00000NkvXXu0mjfn$u1z diff --git a/euscanwww/htdocs/img/unwatch-icon.png b/euscanwww/htdocs/img/unwatch-icon.png index f6875a622809ee7ea698671d23b2fccaeaa69175..28ae542cff8cbfd6e0464e8cc5eb01b069290e5c 100644 GIT binary patch literal 821 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 A)&Kwi