From 222375f2ab89b3cfe37f03b580716e0a9cb166af Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 9 Dec 2020 15:45:54 +0000 Subject: [PATCH 01/30] Clear caches when theme is changed --- daemon.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/daemon.py b/daemon.py index e02d1909f..24ff29748 100644 --- a/daemon.py +++ b/daemon.py @@ -3826,6 +3826,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.themeName = fields['themeDropdown'] setTheme(baseDir, self.server.themeName, domain, allowLocalNetworkAccess) + self.server.iconsCache = {} + self.server.fontsCache = {} self.server.showPublishAsIcon = \ getConfigParam(self.server.baseDir, 'showPublishAsIcon') @@ -4199,6 +4201,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.themeName = currTheme setTheme(baseDir, currTheme, domain, self.server.allowLocalNetworkAccess) + self.server.iconsCache = {} + self.server.fontsCache = {} self.server.showPublishAsIcon = \ getConfigParam(self.server.baseDir, 'showPublishAsIcon') From 3d3b307e8db1262b7946c4a31b1d9f1cb551c476 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 9 Dec 2020 15:57:29 +0000 Subject: [PATCH 02/30] Remove like icon from cache when its status changes --- daemon.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/daemon.py b/daemon.py index 24ff29748..44b99b84f 100644 --- a/daemon.py +++ b/daemon.py @@ -5704,6 +5704,11 @@ class PubServer(BaseHTTPRequestHandler): likedPostFilename, likeUrl, likeActor, domain, debug) + # clear the icon from the cache so that it gets updated + if self.server.iconsCache.get('like.png'): + del self.server.iconsCache['like.png'] + if self.server.iconsCache.get('like_inactive.png'): + del self.server.iconsCache['like_inactive.png'] else: print('WARN: unable to locate file for liked post ' + likeUrl) @@ -5808,6 +5813,11 @@ class PubServer(BaseHTTPRequestHandler): baseDir, likedPostFilename, likeUrl, undoActor, domain, debug) + # clear the icon from the cache so that it gets updated + if self.server.iconsCache.get('like.png'): + del self.server.iconsCache['like.png'] + if self.server.iconsCache.get('like_inactive.png'): + del self.server.iconsCache['like_inactive.png'] # send out the undo like to followers self._postToOutbox(undoLikeJson, self.server.projectVersion) self.server.GETbusy = False From c96b89326b5e38aa90c220f0522b1a0919551c1e Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 9 Dec 2020 16:02:11 +0000 Subject: [PATCH 03/30] Remove icons from cache so that they get updated --- daemon.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/daemon.py b/daemon.py index 44b99b84f..cf2a87348 100644 --- a/daemon.py +++ b/daemon.py @@ -5333,6 +5333,9 @@ class PubServer(BaseHTTPRequestHandler): debug, self.server.projectVersion) if announceJson: + # clear the icon from the cache so that it gets updated + if self.server.iconsCache.get('repeat.png'): + del self.server.iconsCache['repeat.png'] self._postToOutboxThread(announceJson) self.server.GETbusy = False actorAbsolute = httpPrefix + '://' + domainFull + actor @@ -5423,6 +5426,9 @@ class PubServer(BaseHTTPRequestHandler): 'type': 'Announce' } } + # clear the icon from the cache so that it gets updated + if self.server.iconsCache.get('repeat_inactive.png'): + del self.server.iconsCache['repeat_inactive.png'] self._postToOutboxThread(newUndoAnnounce) self.server.GETbusy = False actorAbsolute = httpPrefix + '://' + domainFull + actor @@ -5707,8 +5713,6 @@ class PubServer(BaseHTTPRequestHandler): # clear the icon from the cache so that it gets updated if self.server.iconsCache.get('like.png'): del self.server.iconsCache['like.png'] - if self.server.iconsCache.get('like_inactive.png'): - del self.server.iconsCache['like_inactive.png'] else: print('WARN: unable to locate file for liked post ' + likeUrl) @@ -5814,8 +5818,6 @@ class PubServer(BaseHTTPRequestHandler): likedPostFilename, likeUrl, undoActor, domain, debug) # clear the icon from the cache so that it gets updated - if self.server.iconsCache.get('like.png'): - del self.server.iconsCache['like.png'] if self.server.iconsCache.get('like_inactive.png'): del self.server.iconsCache['like_inactive.png'] # send out the undo like to followers @@ -5909,6 +5911,9 @@ class PubServer(BaseHTTPRequestHandler): self.server.cachedWebfingers, self.server.debug, self.server.projectVersion) + # clear the icon from the cache so that it gets updated + if self.server.iconsCache.get('bookmark.png'): + del self.server.iconsCache['bookmark.png'] # self._postToOutbox(bookmarkJson, self.server.projectVersion) self.server.GETbusy = False actorAbsolute = \ @@ -5999,6 +6004,9 @@ class PubServer(BaseHTTPRequestHandler): self.server.cachedWebfingers, debug, self.server.projectVersion) + # clear the icon from the cache so that it gets updated + if self.server.iconsCache.get('bookmark_inactive.png'): + del self.server.iconsCache['bookmark_inactive.png'] # self._postToOutbox(undoBookmarkJson, self.server.projectVersion) self.server.GETbusy = False actorAbsolute = \ From f0d0080f486a93ab28ce7c56da2cd0a6a85c7bab Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 9 Dec 2020 17:35:11 +0000 Subject: [PATCH 04/30] Note about changing themes --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 7a9ce56ff..3a7225875 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,11 @@ systemctl restart epicyon If you want to use your own favicon then copy your `favicon.ico` file to the base directory where you installed Epicyon. +## Changing themes + +When changing themes you may need to ensure that your nginx cache is cleared (/var/www/cache/*) and that your local browser cache is cleared for the site (Shift + Reload). Otherwise images and icons from the previous theme may remain. + + ## Adding Themes If you want to add a new theme then first add the name of your theme to the translations files. From 6d76b575afb085c95b81a84dc6b39b786b61492f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 9 Dec 2020 17:37:25 +0000 Subject: [PATCH 05/30] Capital --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a7225875..203d5f60f 100644 --- a/README.md +++ b/README.md @@ -244,7 +244,7 @@ systemctl restart epicyon If you want to use your own favicon then copy your `favicon.ico` file to the base directory where you installed Epicyon. -## Changing themes +## Changing Themes When changing themes you may need to ensure that your nginx cache is cleared (/var/www/cache/*) and that your local browser cache is cleared for the site (Shift + Reload). Otherwise images and icons from the previous theme may remain. From c3a4d8d05c45132cf2f0d2b4a30722d59702998f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 9 Dec 2020 17:39:02 +0000 Subject: [PATCH 06/30] More description --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 203d5f60f..c322b994d 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,8 @@ To run a security audit: ./security_audit ``` -Note that not all of the issues identified will necessarily be relevant to this project. +Note that not all of the issues identified will necessarily be relevant to this project. Consider its output as a list of things which potentially can be investigated but usually will turn out not to be relevant. + ## Installing on Onion or i2p domains From 1e52123c0db8e19e2c254bfe87a7851b0e2d5966 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 9 Dec 2020 19:17:42 +0000 Subject: [PATCH 07/30] Link back to moderator screen --- daemon.py | 4 +++- webapp_moderation.py | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/daemon.py b/daemon.py index cf2a87348..3e6aac753 100644 --- a/daemon.py +++ b/daemon.py @@ -1403,6 +1403,7 @@ class PubServer(BaseHTTPRequestHandler): """Actions on the moderator screeen """ usersPath = path.replace('/moderationaction', '') + nickname = usersPath.replace('/users/', '') actorStr = httpPrefix + '://' + domainFull + usersPath length = int(self.headers['Content-length']) @@ -1441,7 +1442,8 @@ class PubServer(BaseHTTPRequestHandler): elif moderationStr.startswith('submitInfo'): msg = htmlModerationInfo(self.server.cssCache, self.server.translate, - baseDir, httpPrefix) + baseDir, httpPrefix, + nickname) msg = msg.encode('utf-8') self._login_headers('text/html', len(msg), callingDomain) diff --git a/webapp_moderation.py b/webapp_moderation.py index 6c23ef401..78a36881a 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -45,7 +45,8 @@ def htmlModeration(cssCache: {}, defaultTimeline: str, def htmlModerationInfo(cssCache: {}, translate: {}, - baseDir: str, httpPrefix: str) -> str: + baseDir: str, httpPrefix: str, + nickname: str) -> str: msgStr1 = \ 'These are globally blocked for all accounts on this instance' msgStr2 = \ @@ -58,9 +59,9 @@ def htmlModerationInfo(cssCache: {}, translate: {}, infoForm = htmlHeaderWithExternalStyle(cssFilename) infoForm += \ - '

' + \ + '

' + \ translate['Moderation Information'] + \ - '

' + '

' infoShown = False suspendedFilename = baseDir + '/accounts/suspended.txt' From ef87a23079e161d41014df576bed847e4d739393 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 9 Dec 2020 22:55:15 +0000 Subject: [PATCH 08/30] Account info screen --- daemon.py | 62 +++++++++++++++++++++++++++++++++++++++--- epicyon-profile.css | 4 +++ epicyon.py | 9 ++++--- translations/ar.json | 4 ++- translations/ca.json | 4 ++- translations/cy.json | 4 ++- translations/de.json | 4 ++- translations/en.json | 4 ++- translations/es.json | 4 ++- translations/fr.json | 4 ++- translations/ga.json | 4 ++- translations/hi.json | 4 ++- translations/it.json | 4 ++- translations/ja.json | 4 ++- translations/oc.json | 4 ++- translations/pt.json | 4 ++- translations/ru.json | 4 ++- translations/zh.json | 4 ++- webapp_moderation.py | 64 +++++++++++++++++++++++++++++++++++++++++++- 19 files changed, 175 insertions(+), 24 deletions(-) diff --git a/daemon.py b/daemon.py index 3e6aac753..5691cd80a 100644 --- a/daemon.py +++ b/daemon.py @@ -136,6 +136,7 @@ from webapp_timeline import htmlInboxBlogs from webapp_timeline import htmlInboxNews from webapp_timeline import htmlInboxFeatures from webapp_timeline import htmlOutbox +from webapp_moderation import htmlAccountInfo from webapp_moderation import htmlModeration from webapp_moderation import htmlModerationInfo from webapp_create_post import htmlNewPost @@ -1440,10 +1441,27 @@ class PubServer(BaseHTTPRequestHandler): moderationText = \ urllib.parse.unquote_plus(modText.strip()) elif moderationStr.startswith('submitInfo'): - msg = htmlModerationInfo(self.server.cssCache, - self.server.translate, - baseDir, httpPrefix, - nickname) + searchHandle = \ + urllib.parse.unquote_plus(moderationStr.strip()) + if searchHandle: + if '@' not in searchHandle: + searchHandle = None + if searchHandle: + msg = \ + htmlAccountInfo(self.server.cssCache, + self.server.translate, + baseDir, httpPrefix, + nickname, + self.server.domain, + self.server.port, + searchHandle, + self.server.debug) + else: + msg = \ + htmlModerationInfo(self.server.cssCache, + self.server.translate, + baseDir, httpPrefix, + nickname) msg = msg.encode('utf-8') self._login_headers('text/html', len(msg), callingDomain) @@ -10978,6 +10996,42 @@ class PubServer(BaseHTTPRequestHandler): 'show blogs 2 done', 'show shares 2 done') + # block a domain from htmlAccountInfo + if authorized and '/users/' in self.path and \ + '/accountinfo?blockdomain=' in self.path: + nickname = self.path.split('/users/')[1] + if '/' in nickname: + nickname = nickname.split('/')[0] + if not isModerator(self.server.baseDir, nickname): + self._400() + return + blockDomain = self.path.split('/accountinfo?blockdomain=')[1] + blockDomain = urllib.parse.unquote_plus(blockDomain.strip()) + addGlobalBlock(self.server.baseDir, nickname, blockDomain) + self.server.GETbusy = False + # TODO this should go back to the account info screen + self._redirect_headers('/users/' + nickname + '/moderation', + cookie, callingDomain) + return + + # unblock a domain from htmlAccountInfo + if authorized and '/users/' in self.path and \ + '/accountinfo?unblockdomain=' in self.path: + nickname = self.path.split('/users/')[1] + if '/' in nickname: + nickname = nickname.split('/')[0] + if not isModerator(self.server.baseDir, nickname): + self._400() + return + blockDomain = self.path.split('/accountinfo?unblockdomain=')[1] + blockDomain = urllib.parse.unquote_plus(blockDomain.strip()) + removeGlobalBlock(self.server.baseDir, nickname, blockDomain) + self.server.GETbusy = False + # TODO this should go back to the account info screen + self._redirect_headers('/users/' + nickname + '/moderation', + cookie, callingDomain) + return + # get the bookmarks timeline for a given person if self.path.endswith('/tlbookmarks') or \ '/tlbookmarks?page=' in self.path or \ diff --git a/epicyon-profile.css b/epicyon-profile.css index 94309a067..083a7fc62 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -930,6 +930,10 @@ div.container { overflow: hidden; } +.accountInfoDomains { + margin: 0 10%; +} + @media screen and (min-width: 400px) { body, html { background-color: var(--main-bg-color); diff --git a/epicyon.py b/epicyon.py index 59c0e2cd5..37df367e9 100644 --- a/epicyon.py +++ b/epicyon.py @@ -526,8 +526,8 @@ if args.posts: if args.postDomains: if '@' not in args.postDomains: if '/users/' in args.postDomains: - postsNickname = getNicknameFromActor(args.posts) - postsDomain, postsPort = getDomainFromActor(args.posts) + postsNickname = getNicknameFromActor(args.postDomains) + postsDomain, postsPort = getDomainFromActor(args.postDomains) args.postDomains = postsNickname + '@' + postsDomain if postsPort: if postsPort != 80 and postsPort != 443: @@ -565,8 +565,9 @@ if args.postDomainsBlocked: # given handle but which are globally blocked on this instance if '@' not in args.postDomainsBlocked: if '/users/' in args.postDomainsBlocked: - postsNickname = getNicknameFromActor(args.posts) - postsDomain, postsPort = getDomainFromActor(args.posts) + postsNickname = getNicknameFromActor(args.postDomainsBlocked) + postsDomain, postsPort = \ + getDomainFromActor(args.postDomainsBlocked) args.postDomainsBlocked = postsNickname + '@' + postsDomain if postsPort: if postsPort != 80 and postsPort != 443: diff --git a/translations/ar.json b/translations/ar.json index 2a96a612f..8ce52a2f5 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "حدد رمز التحرير لإضافة موجز ويب لـ RSS", "Select the edit icon to add web links": "حدد رمز التحرير لإضافة روابط الويب", "Hashtag Categories RSS Feed": "Hashtag Categories RSS Feed", - "Ask about a shared item.": "اسأل عن عنصر مشترك." + "Ask about a shared item.": "اسأل عن عنصر مشترك.", + "Account Information": "معلومات الحساب", + "This account interacts with the following instances": "يتفاعل هذا الحساب مع الحالات التالية" } diff --git a/translations/ca.json b/translations/ca.json index 7ff65aab7..7e9b2d8a7 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "Seleccioneu la icona d'edició per afegir canals RSS", "Select the edit icon to add web links": "Seleccioneu la icona d'edició per afegir enllaços web", "Hashtag Categories RSS Feed": "Feed RSS de categories de hashtag", - "Ask about a shared item.": "Pregunteu sobre un element compartit." + "Ask about a shared item.": "Pregunteu sobre un element compartit.", + "Account Information": "Informació del compte", + "This account interacts with the following instances": "Aquest compte interactua amb les instàncies següents" } diff --git a/translations/cy.json b/translations/cy.json index b10bb537e..a0c996809 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "Dewiswch yr eicon golygu i ychwanegu porthwyr RSS", "Select the edit icon to add web links": "Dewiswch yr eicon golygu i ychwanegu dolenni gwe", "Hashtag Categories RSS Feed": "Categorïau Hashtag RSS Feed", - "Ask about a shared item.": "Gofynnwch am eitem a rennir." + "Ask about a shared item.": "Gofynnwch am eitem a rennir.", + "Account Information": "Gwybodaeth Gyfrif", + "This account interacts with the following instances": "Mae'r cyfrif hwn yn rhyngweithio â'r achosion canlynol" } diff --git a/translations/de.json b/translations/de.json index ebd9e4e5a..f9eac6115 100644 --- a/translations/de.json +++ b/translations/de.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "Wählen Sie das Bearbeitungssymbol, um RSS-Feeds hinzuzufügen", "Select the edit icon to add web links": "Wählen Sie das Bearbeitungssymbol, um Weblinks hinzuzufügen", "Hashtag Categories RSS Feed": "Hashtag Kategorien RSS Feed", - "Ask about a shared item.": "Fragen Sie nach einem gemeinsamen Artikel." + "Ask about a shared item.": "Fragen Sie nach einem gemeinsamen Artikel.", + "Account Information": "Kontoinformationen", + "This account interacts with the following instances": "Dieses Konto interagiert mit den folgenden Instanzen" } diff --git a/translations/en.json b/translations/en.json index 45e450a1e..b17f8b92b 100644 --- a/translations/en.json +++ b/translations/en.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "Select the edit icon to add RSS feeds", "Select the edit icon to add web links": "Select the edit icon to add web links", "Hashtag Categories RSS Feed": "Hashtag Categories RSS Feed", - "Ask about a shared item.": "Ask about a shared item." + "Ask about a shared item.": "Ask about a shared item.", + "Account Information": "Account Information", + "This account interacts with the following instances": "This account interacts with the following instances" } diff --git a/translations/es.json b/translations/es.json index 12e541e78..4c970fe79 100644 --- a/translations/es.json +++ b/translations/es.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "Seleccione el icono de edición para agregar fuentes RSS", "Select the edit icon to add web links": "Seleccione el icono de edición para agregar enlaces web", "Hashtag Categories RSS Feed": "Feed RSS de categorías de hashtags", - "Ask about a shared item.": "Pregunte por un elemento compartido." + "Ask about a shared item.": "Pregunte por un elemento compartido.", + "Account Information": "Información de la cuenta", + "This account interacts with the following instances": "Esta cuenta interactúa con las siguientes instancias" } diff --git a/translations/fr.json b/translations/fr.json index 7816fc8f8..167940b2a 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "Sélectionnez l'icône d'édition pour ajouter des flux RSS", "Select the edit icon to add web links": "Sélectionnez l'icône de modification pour ajouter des liens Web", "Hashtag Categories RSS Feed": "Flux RSS des catégories Hashtag", - "Ask about a shared item.": "Renseignez-vous sur un élément partagé." + "Ask about a shared item.": "Renseignez-vous sur un élément partagé.", + "Account Information": "Information sur le compte", + "This account interacts with the following instances": "Ce compte interagit avec les instances suivantes" } diff --git a/translations/ga.json b/translations/ga.json index ac41d0205..13e51eada 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "Roghnaigh an deilbhín eagar chun fothaí RSS a chur leis", "Select the edit icon to add web links": "Roghnaigh an deilbhín eagar chun naisc ghréasáin a chur leis", "Hashtag Categories RSS Feed": "Catagóirí Hashtag RSS Feed", - "Ask about a shared item.": "Fiafraigh faoi earra roinnte." + "Ask about a shared item.": "Fiafraigh faoi earra roinnte.", + "Account Information": "Faisnéis Chuntais", + "This account interacts with the following instances": "Idirghníomhaíonn an cuntas seo leis na cásanna seo a leanas" } diff --git a/translations/hi.json b/translations/hi.json index 65fec21ff..40ddfc5f6 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "RSS फ़ीड जोड़ने के लिए संपादन आइकन का चयन करें", "Select the edit icon to add web links": "वेब लिंक जोड़ने के लिए संपादन आइकन का चयन करें", "Hashtag Categories RSS Feed": "हैशटैग श्रेणियाँ आरएसएस फ़ीड", - "Ask about a shared item.": "एक साझा आइटम के बारे में पूछें।" + "Ask about a shared item.": "एक साझा आइटम के बारे में पूछें।", + "Account Information": "खाते की जानकारी", + "This account interacts with the following instances": "यह खाता निम्नलिखित उदाहरणों के साथ सहभागिता करता है" } diff --git a/translations/it.json b/translations/it.json index fabd4f973..5ab6e0dbc 100644 --- a/translations/it.json +++ b/translations/it.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "Seleziona l'icona di modifica per aggiungere feed RSS", "Select the edit icon to add web links": "Seleziona l'icona di modifica per aggiungere link web", "Hashtag Categories RSS Feed": "Feed RSS delle categorie hashtag", - "Ask about a shared item.": "Chiedi informazioni su un elemento condiviso." + "Ask about a shared item.": "Chiedi informazioni su un elemento condiviso.", + "Account Information": "Informazioni account", + "This account interacts with the following instances": "Questo account interagisce con le seguenti istanze" } diff --git a/translations/ja.json b/translations/ja.json index 7bed89c46..3afb8aff8 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "編集アイコンを選択してRSSフィードを追加します", "Select the edit icon to add web links": "編集アイコンを選択してWebリンクを追加します", "Hashtag Categories RSS Feed": "ハッシュタグカテゴリRSSフィード", - "Ask about a shared item.": "共有アイテムについて質問します。" + "Ask about a shared item.": "共有アイテムについて質問します。", + "Account Information": "口座情報", + "This account interacts with the following instances": "このアカウントは、次のインスタンスと相互作用します" } diff --git a/translations/oc.json b/translations/oc.json index a224b833a..9f8a92a0e 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -335,5 +335,7 @@ "Select the edit icon to add RSS feeds": "Select the edit icon to add RSS feeds", "Select the edit icon to add web links": "Select the edit icon to add web links", "Hashtag Categories RSS Feed": "Hashtag Categories RSS Feed", - "Ask about a shared item.": "Ask about a shared item." + "Ask about a shared item.": "Ask about a shared item.", + "Account Information": "Account Information", + "This account interacts with the following instances": "This account interacts with the following instances" } diff --git a/translations/pt.json b/translations/pt.json index 305243eac..53af4b8d6 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "Selecione o ícone de edição para adicionar feeds RSS", "Select the edit icon to add web links": "Selecione o ícone de edição para adicionar links da web", "Hashtag Categories RSS Feed": "Feed RSS das categorias de hashtag", - "Ask about a shared item.": "Pergunte sobre um item compartilhado." + "Ask about a shared item.": "Pergunte sobre um item compartilhado.", + "Account Information": "Informação da conta", + "This account interacts with the following instances": "Esta conta interage com as seguintes instâncias" } diff --git a/translations/ru.json b/translations/ru.json index 3c0155cea..e44e037f5 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "Щелкните значок редактирования, чтобы добавить RSS-каналы", "Select the edit icon to add web links": "Щелкните значок редактирования, чтобы добавить веб-ссылки", "Hashtag Categories RSS Feed": "RSS-канал категорий хэштегов", - "Ask about a shared item.": "Спросите об общем элементе." + "Ask about a shared item.": "Спросите об общем элементе.", + "Account Information": "Информация об аккаунте", + "This account interacts with the following instances": "Этот аккаунт взаимодействует со следующими экземплярами" } diff --git a/translations/zh.json b/translations/zh.json index 470be2cd5..f12a444da 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -339,5 +339,7 @@ "Select the edit icon to add RSS feeds": "选择编辑图标以添加RSS feed", "Select the edit icon to add web links": "选择编辑图标以添加Web链接", "Hashtag Categories RSS Feed": "标签类别RSS提要", - "Ask about a shared item.": "询问共享项目。" + "Ask about a shared item.": "询问共享项目。", + "Account Information": "帐户信息", + "This account interacts with the following instances": "此帐户与以下实例进行交互" } diff --git a/webapp_moderation.py b/webapp_moderation.py index 78a36881a..9d24db302 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -7,9 +7,13 @@ __email__ = "bob@freedombone.net" __status__ = "Production" import os +from utils import getNicknameFromActor +from utils import getDomainFromActor +from posts import getPublicPostDomains from webapp_timeline import htmlTimeline from webapp_utils import htmlHeaderWithExternalStyle from webapp_utils import htmlFooter +from blocking import isBlockedDomain def htmlModeration(cssCache: {}, defaultTimeline: str, @@ -44,6 +48,63 @@ def htmlModeration(cssCache: {}, defaultTimeline: str, authorized) +def htmlAccountInfo(cssCache: {}, translate: {}, + baseDir: str, httpPrefix: str, + nickname: str, domain: str, port: int, + searchHandle: str, debug: bool) -> str: + """Shows which domains a search handle interacts with. + This screen is shown if a moderator enters a handle and selects info + on the moderation screen + """ + msgStr1 = 'This account interacts with the following instances' + + infoForm = '' + cssFilename = baseDir + '/epicyon-profile.css' + if os.path.isfile(baseDir + '/epicyon.css'): + cssFilename = baseDir + '/epicyon.css' + + infoForm = htmlHeaderWithExternalStyle(cssFilename) + + searchNickname = getNicknameFromActor(searchHandle) + searchDomain, searchPort = getDomainFromActor(searchHandle) + + infoForm += \ + '

' + \ + translate['Account Information'] + \ + ': ' + searchNickname + '@' + searchDomain + \ + '



' + + infoForm += translate[msgStr1] + '


' + + proxyType = 'tor' + domainList = [] + domainList = getPublicPostDomains(None, + baseDir, searchNickname, searchDomain, + proxyType, searchPort, + httpPrefix, debug, + __version__, domainList) + infoForm += '
' + usersPath = '/users/' + nickname + '/accountinfo' + for postDomain in domainList: + infoForm += '' + postDomain + ' ' + if isBlockedDomain(postDomain): + infoForm += \ + '' + infoForm += '' + else: + infoForm += \ + '' + infoForm += '' + infoForm += '
' + + infoForm += '
' + infoForm += htmlFooter() + return infoForm + + def htmlModerationInfo(cssCache: {}, translate: {}, baseDir: str, httpPrefix: str, nickname: str) -> str: @@ -51,6 +112,7 @@ def htmlModerationInfo(cssCache: {}, translate: {}, 'These are globally blocked for all accounts on this instance' msgStr2 = \ 'Any blocks or suspensions made by moderators will be shown here.' + infoForm = '' cssFilename = baseDir + '/epicyon-profile.css' if os.path.isfile(baseDir + '/epicyon.css'): @@ -61,7 +123,7 @@ def htmlModerationInfo(cssCache: {}, translate: {}, infoForm += \ '

' + \ translate['Moderation Information'] + \ - '

' + '
' infoShown = False suspendedFilename = baseDir + '/accounts/suspended.txt' From 6e6c4f19bc7cf695a5af845da2551e3b25ab11dd Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 9 Dec 2020 23:01:12 +0000 Subject: [PATCH 09/30] Get handle --- daemon.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/daemon.py b/daemon.py index 5691cd80a..605508adf 100644 --- a/daemon.py +++ b/daemon.py @@ -1441,8 +1441,13 @@ class PubServer(BaseHTTPRequestHandler): moderationText = \ urllib.parse.unquote_plus(modText.strip()) elif moderationStr.startswith('submitInfo'): - searchHandle = \ - urllib.parse.unquote_plus(moderationStr.strip()) + searchHandle = None + if '=' in moderationStr: + moderationText = \ + moderationStr.split('=')[1].strip() + modText = moderationText.replace('+', ' ') + searchHandle = \ + urllib.parse.unquote_plus(modText.strip()) if searchHandle: if '@' not in searchHandle: searchHandle = None From 1eee9cad101ace73cdb4fe7b9f7fa9cbc9081a42 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 9 Dec 2020 23:05:27 +0000 Subject: [PATCH 10/30] Get handle --- daemon.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/daemon.py b/daemon.py index 605508adf..55174b46f 100644 --- a/daemon.py +++ b/daemon.py @@ -1441,13 +1441,7 @@ class PubServer(BaseHTTPRequestHandler): moderationText = \ urllib.parse.unquote_plus(modText.strip()) elif moderationStr.startswith('submitInfo'): - searchHandle = None - if '=' in moderationStr: - moderationText = \ - moderationStr.split('=')[1].strip() - modText = moderationText.replace('+', ' ') - searchHandle = \ - urllib.parse.unquote_plus(modText.strip()) + searchHandle = moderationText if searchHandle: if '@' not in searchHandle: searchHandle = None From 09d103255090066296ca09da72c43acd38e30eb2 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 9 Dec 2020 23:08:00 +0000 Subject: [PATCH 11/30] Missing parameter --- webapp_moderation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp_moderation.py b/webapp_moderation.py index 9d24db302..0b9783b37 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -88,7 +88,7 @@ def htmlAccountInfo(cssCache: {}, translate: {}, for postDomain in domainList: infoForm += '' + postDomain + ' ' - if isBlockedDomain(postDomain): + if isBlockedDomain(baseDir, postDomain): infoForm += \ '' infoForm += '' else: infoForm += \ - '' + '' infoForm += '' infoForm += '
' From 39873ede208f77525b1a2854508aafadc4868d83 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 10 Dec 2020 10:24:25 +0000 Subject: [PATCH 21/30] Unquote search handle --- daemon.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/daemon.py b/daemon.py index 99c38556d..10e8fb78b 100644 --- a/daemon.py +++ b/daemon.py @@ -11008,6 +11008,7 @@ class PubServer(BaseHTTPRequestHandler): return blockDomain = self.path.split('/accountinfo?blockdomain=')[1] searchHandle = blockDomain.split('?handle=')[1] + searchHandle = urllib.parse.unquote_plus(searchHandle) blockDomain = blockDomain.split('?handle=')[0] blockDomain = urllib.parse.unquote_plus(blockDomain.strip()) if '?' in blockDomain: @@ -11042,6 +11043,7 @@ class PubServer(BaseHTTPRequestHandler): return blockDomain = self.path.split('/accountinfo?unblockdomain=')[1] searchHandle = blockDomain.split('?handle=')[1] + searchHandle = urllib.parse.unquote_plus(searchHandle) blockDomain = blockDomain.split('?handle=')[0] blockDomain = urllib.parse.unquote_plus(blockDomain.strip()) removeGlobalBlock(self.server.baseDir, nickname, blockDomain) From 27e2304ce129d6e9b4545242d622246712ba5a1e Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 10 Dec 2020 10:28:30 +0000 Subject: [PATCH 22/30] Prefix --- daemon.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/daemon.py b/daemon.py index 10e8fb78b..50e12e0fd 100644 --- a/daemon.py +++ b/daemon.py @@ -11013,7 +11013,7 @@ class PubServer(BaseHTTPRequestHandler): blockDomain = urllib.parse.unquote_plus(blockDomain.strip()) if '?' in blockDomain: blockDomain = blockDomain.split('?')[0] - addGlobalBlock(self.server.baseDir, nickname, blockDomain) + addGlobalBlock(self.server.baseDir, nickname, '*@' + blockDomain) self.server.GETbusy = False msg = \ htmlAccountInfo(self.server.cssCache, @@ -11046,7 +11046,8 @@ class PubServer(BaseHTTPRequestHandler): searchHandle = urllib.parse.unquote_plus(searchHandle) blockDomain = blockDomain.split('?handle=')[0] blockDomain = urllib.parse.unquote_plus(blockDomain.strip()) - removeGlobalBlock(self.server.baseDir, nickname, blockDomain) + removeGlobalBlock(self.server.baseDir, nickname, + '*@' + blockDomain) self.server.GETbusy = False msg = \ htmlAccountInfo(self.server.cssCache, From 2234b670591b5df87e71765d5444728c903a6c86 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 10 Dec 2020 10:33:58 +0000 Subject: [PATCH 23/30] All users --- daemon.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/daemon.py b/daemon.py index 50e12e0fd..10e368d97 100644 --- a/daemon.py +++ b/daemon.py @@ -11013,7 +11013,7 @@ class PubServer(BaseHTTPRequestHandler): blockDomain = urllib.parse.unquote_plus(blockDomain.strip()) if '?' in blockDomain: blockDomain = blockDomain.split('?')[0] - addGlobalBlock(self.server.baseDir, nickname, '*@' + blockDomain) + addGlobalBlock(self.server.baseDir, '*', blockDomain) self.server.GETbusy = False msg = \ htmlAccountInfo(self.server.cssCache, @@ -11046,8 +11046,7 @@ class PubServer(BaseHTTPRequestHandler): searchHandle = urllib.parse.unquote_plus(searchHandle) blockDomain = blockDomain.split('?handle=')[0] blockDomain = urllib.parse.unquote_plus(blockDomain.strip()) - removeGlobalBlock(self.server.baseDir, nickname, - '*@' + blockDomain) + removeGlobalBlock(self.server.baseDir, '*', blockDomain) self.server.GETbusy = False msg = \ htmlAccountInfo(self.server.cssCache, From 9c2970b130e19c2b9e8d84ad9b48386566df5659 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 10 Dec 2020 10:53:27 +0000 Subject: [PATCH 24/30] Separate link to actor --- webapp_moderation.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/webapp_moderation.py b/webapp_moderation.py index 0f827c397..bb8859c11 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -71,8 +71,9 @@ def htmlAccountInfo(cssCache: {}, translate: {}, searchHandle = searchNickname + '@' + searchDomain infoForm += \ '

' + \ - translate['Account Information'] + ': ' + searchHandle + \ - '


' + translate['Account Information'] + ': ' + searchHandle + '
' infoForm += translate[msgStr1] + '


' From 074e2b3d8d6d176f681998d103a39407ed3931e5 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 10 Dec 2020 11:54:47 +0000 Subject: [PATCH 25/30] Oprn newswire links in a new tab --- webapp_column_right.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/webapp_column_right.py b/webapp_column_right.py index 91412956b..589184817 100644 --- a/webapp_column_right.py +++ b/webapp_column_right.py @@ -242,7 +242,8 @@ def htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool, title = removeLongWords(item[0], 16, []).replace('\n', '
') htmlStr += '

' + \ - '' + \ + '' + \ '' + title + \ '' + totalVotesStr if moderator: @@ -269,7 +270,8 @@ def htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool, title = removeLongWords(item[0], 16, []).replace('\n', '
') if moderator and moderatedItem: htmlStr += '

' + \ - '' + \ + '' + \ title + '' + totalVotesStr htmlStr += ' ' + dateShown htmlStr += '' + \ - '' + \ + '' + \ title + '' + \ totalVotesStr htmlStr += ' ' From 664167e2aee881921bdf87789515daa1b6c3b7b0 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 10 Dec 2020 11:54:47 +0000 Subject: [PATCH 26/30] Open newswire links in a new tab --- webapp_column_right.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/webapp_column_right.py b/webapp_column_right.py index 91412956b..589184817 100644 --- a/webapp_column_right.py +++ b/webapp_column_right.py @@ -242,7 +242,8 @@ def htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool, title = removeLongWords(item[0], 16, []).replace('\n', '
') htmlStr += '

' + \ - '' + \ + '' + \ '' + title + \ '' + totalVotesStr if moderator: @@ -269,7 +270,8 @@ def htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool, title = removeLongWords(item[0], 16, []).replace('\n', '
') if moderator and moderatedItem: htmlStr += '

' + \ - '' + \ + '' + \ title + '' + totalVotesStr htmlStr += ' ' + dateShown htmlStr += '' + \ - '' + \ + '' + \ title + '' + \ totalVotesStr htmlStr += ' ' From f40f3f07fa094621a25b1fb673135cfd1ef8e441 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 10 Dec 2020 12:06:39 +0000 Subject: [PATCH 27/30] Open links in a separate tab --- webapp_column_left.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webapp_column_left.py b/webapp_column_left.py index 5e5df5cf7..8d91101da 100644 --- a/webapp_column_left.py +++ b/webapp_column_left.py @@ -215,7 +215,8 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str, lineStr = lineStr[:len(lineStr)-1] # add link to the returned html htmlStr += \ - '

' + \ + '

' + \ lineStr + '

\n' linksFileContainsEntries = True else: From a5f817ba890b95d7f47976c55a7b66f15f35a70f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 10 Dec 2020 13:50:36 +0000 Subject: [PATCH 28/30] Hacker calendar --- theme/hacker/icons/calendar.png | Bin 2450 -> 6098 bytes theme/hacker/icons/calendar_notify.png | Bin 2732 -> 6925 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/theme/hacker/icons/calendar.png b/theme/hacker/icons/calendar.png index 80ae04060390ba58cb649332c8f4af6978e0ad93..c70130d9f706e63b7394cf1107f53007d4f00fa3 100644 GIT binary patch delta 6067 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 delta 2390 zcmV-c390tdFOn0G7=Ho-0002j2boO(00$>}R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3 z004N}?O0uM^ePU0*D7WSmIMfv!*A8y!7P6c*zR;E?Igb6JWNg9cG|clEQF3Yh*1Cc zUxWUIkGf6Bd5a;1u;Js9OOo*rxBZjWoj14c>*Ed;e!s}+p??sF6s_(*Eg$_eIscoU3m}4%k<86+nxjT66EuVK1cuY^eOm~ z54nDdWjJDlhkv&U_V0tgLi{waK0K0F1p-sQOy>;pXmO0b&n~-wh=wDhR#Q*f3vft|-6){ontWMn zaJ2MUaJHzM#x`x2Hn%=q0|X2pSj2BMw0~4lieX_7?PZFYH~Jraa|&X6Ax#8RD;A@;4KI6pzR ztnHk^@*g!9&-)|4{aY1u2k7G<&h`wbmhr{k?D75mAA-l$|SYjmNR6q>yV=f~!rQSp8t!D$uNVMoY-bs68h0%Bfe5T%qVu`UR`;4r_ zX{LAL-O840Yu;QQ9oUNvYu%%KC}p7NN8sbYgivmv`f%=;L+y$})lhG!(SN;=?h*B) zfHqAXiUY4DA^!$AyULyqZp<~bEt<%~A=#H=iRW1sO&)W-VNoqZ+ioYW1xR<8$E_qs z!S^P`=`QbF(GK0^oh#a*yS#HnJ9L+Ku4squ^3E0Q&|TiSYUwWTT+t4#I^iUZG?$_# zLn`~3-+sn8?F;uIo*53hsDA-vv9{=4ub3yDR^E5NF#p*K!bv;zfC^ellX|)#gsPw( zEaw^&FIfv2r*;!Vd4m&1Nm_7>1Q|`{!O3GT9-JU|e!&m)*F!$}NG2bxXDGlqs&FLr zD%rw3Dy(!^1T&GNRPjq>l`}ra$w(`g`%)mpYoIYz%M?FZiaYm!4S#y2y2wZ2WJ;5K zM(E1(r5THJ8X9p7Nezc4e-%^uE~wxgPOu5yVekb{3Yl4mgg_-XaDG|*FbOkLTg2lR z{7aK|BF#`NGuwxi?+PBe%R5)8O@F^2e$~-k-npV3y30FPv_p4!=ZbddF7I5?4*gjT z`av#qvdhpoH?!Pvntyfy6#~*d7G}nA8!5jw!SD7!y4nQK0wq4}rhm)O=iT(DGY;*C zoF*C9Q4)Z25~fx1o%)2H3Y0urfo~~Wv7B1nY3of@bQVj`RTQl6yuk=O<>MdHFm0YjBb5~S!sOI*CN2P4NT^%EDwDhM2{xS4FXGmu;v~Bbs z$Fv6Sucaob0004nlTHg9A6rXBD-JE9;*g;_Sr8R*)G8FALZ}s5buhW~Luk^FlZgu| zfB5TVrkWjNfT~$WI++l%xfLPwiXi$B!2r4?X6mz|n1bi{x`&UicX6KOeeTcEqvTBn z_ypn^rW+RVI`Pz|rE}gVj4ex=P&u2Zz8&k+Ro3-rd>W+rMX;{rvzpQ*w{@(&oqj000S4OjJbx00000 z0487{;V_u}00001bW%=J06^y0W&i*H0b)x>L;#2d9Y_EG010qNS#tmY4c7nw4c7re zD4Tcy000McNliru4lutN;K2 diff --git a/theme/hacker/icons/calendar_notify.png b/theme/hacker/icons/calendar_notify.png index 21d68fd858ebef56532ff01357423f579d975ca9..b29692291303f721f455deb9e49a0cfc533b095a 100644 GIT binary patch delta 6924 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≀9=l`B-=zlvQ<=8>Qmc4Qe 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 B^C Date: Thu, 10 Dec 2020 13:52:16 +0000 Subject: [PATCH 29/30] Favicon color --- theme/hacker/icons/favicon.ico | Bin 1150 -> 1150 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/theme/hacker/icons/favicon.ico b/theme/hacker/icons/favicon.ico index c7cb1bbbe0ff1c57a5974ddeb09fc6dc8e31d96f..e0436576125749b090b80164ed8973d5f8f5e767 100644 GIT binary patch literal 1150 zcmd5%I|{-;6db`;iH)r(_Xu{WQrpme`&;0Q`o-a4t*=gzM7=oK>Nf6wQ~`OUs>G9IP6vt{$7Mk$XM zRkwMWXGJ4q8hLHrjK7vXFO#jMb+J9$`_zm3WJCGbeYAgUu5&}akS2eK+kW*SZ%nfp zU&nkgU3qcL*QNiG?b=tfim&>h0uIE6C?3GR1a?w8Xc(3 literal 1150 zcmd6iF$%&!6hud`RbpdnN^griEjn+X0&v#!*{v3}tERlq{d;~rpPuafdfiU0f41u1 zOT8G^Ywhb~RFvX<6>IZ8lj>bwbGw$8QhT=J)Jwm~hVrrh(f+Zy&JA%PPkcyyUVVs- zc{bzLF)rpSFO6|2|CelPU(G7s>QfbPW^GvI1327){T0|=fZLJW7 Date: Thu, 10 Dec 2020 13:53:31 +0000 Subject: [PATCH 30/30] Event icon --- theme/hacker/icons/scope_event.png | Bin 2450 -> 6098 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/theme/hacker/icons/scope_event.png b/theme/hacker/icons/scope_event.png index 80ae04060390ba58cb649332c8f4af6978e0ad93..c70130d9f706e63b7394cf1107f53007d4f00fa3 100644 GIT binary patch delta 6067 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 delta 2390 zcmV-c390tdFOn0G7=Ho-0002j2boO(00$>}R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3 z004N}?O0uM^ePU0*D7WSmIMfv!*A8y!7P6c*zR;E?Igb6JWNg9cG|clEQF3Yh*1Cc zUxWUIkGf6Bd5a;1u;Js9OOo*rxBZjWoj14c>*Ed;e!s}+p??sF6s_(*Eg$_eIscoU3m}4%k<86+nxjT66EuVK1cuY^eOm~ z54nDdWjJDlhkv&U_V0tgLi{waK0K0F1p-sQOy>;pXmO0b&n~-wh=wDhR#Q*f3vft|-6){ontWMn zaJ2MUaJHzM#x`x2Hn%=q0|X2pSj2BMw0~4lieX_7?PZFYH~Jraa|&X6Ax#8RD;A@;4KI6pzR ztnHk^@*g!9&-)|4{aY1u2k7G<&h`wbmhr{k?D75mAA-l$|SYjmNR6q>yV=f~!rQSp8t!D$uNVMoY-bs68h0%Bfe5T%qVu`UR`;4r_ zX{LAL-O840Yu;QQ9oUNvYu%%KC}p7NN8sbYgivmv`f%=;L+y$})lhG!(SN;=?h*B) zfHqAXiUY4DA^!$AyULyqZp<~bEt<%~A=#H=iRW1sO&)W-VNoqZ+ioYW1xR<8$E_qs z!S^P`=`QbF(GK0^oh#a*yS#HnJ9L+Ku4squ^3E0Q&|TiSYUwWTT+t4#I^iUZG?$_# zLn`~3-+sn8?F;uIo*53hsDA-vv9{=4ub3yDR^E5NF#p*K!bv;zfC^ellX|)#gsPw( zEaw^&FIfv2r*;!Vd4m&1Nm_7>1Q|`{!O3GT9-JU|e!&m)*F!$}NG2bxXDGlqs&FLr zD%rw3Dy(!^1T&GNRPjq>l`}ra$w(`g`%)mpYoIYz%M?FZiaYm!4S#y2y2wZ2WJ;5K zM(E1(r5THJ8X9p7Nezc4e-%^uE~wxgPOu5yVekb{3Yl4mgg_-XaDG|*FbOkLTg2lR z{7aK|BF#`NGuwxi?+PBe%R5)8O@F^2e$~-k-npV3y30FPv_p4!=ZbddF7I5?4*gjT z`av#qvdhpoH?!Pvntyfy6#~*d7G}nA8!5jw!SD7!y4nQK0wq4}rhm)O=iT(DGY;*C zoF*C9Q4)Z25~fx1o%)2H3Y0urfo~~Wv7B1nY3of@bQVj`RTQl6yuk=O<>MdHFm0YjBb5~S!sOI*CN2P4NT^%EDwDhM2{xS4FXGmu;v~Bbs z$Fv6Sucaob0004nlTHg9A6rXBD-JE9;*g;_Sr8R*)G8FALZ}s5buhW~Luk^FlZgu| zfB5TVrkWjNfT~$WI++l%xfLPwiXi$B!2r4?X6mz|n1bi{x`&UicX6KOeeTcEqvTBn z_ypn^rW+RVI`Pz|rE}gVj4ex=P&u2Zz8&k+Ro3-rd>W+rMX;{rvzpQ*w{@(&oqj000S4OjJbx00000 z0487{;V_u}00001bW%=J06^y0W&i*H0b)x>L;#2d9Y_EG010qNS#tmY4c7nw4c7re zD4Tcy000McNliru4lutN;K2