Compare commits

...

5 Commits

Author SHA1 Message Date
Jason Schwarzenberger
9cee370a25 tvnz icon 2020-11-10 14:10:02 +13:00
Jason Schwarzenberger
5efc6ef2d3 add related stories (in api only) 2020-11-10 14:09:56 +13:00
Jason Schwarzenberger
4ec50e20cb feed thread loop. 2020-11-10 10:10:38 +13:00
Jason Schwarzenberger
c1b7877f4b remove limit. 2020-11-09 17:54:50 +13:00
Jason Schwarzenberger
7b8cbfc9b9 try to make feed only determined by the max age. 2020-11-09 17:50:58 +13:00
6 changed files with 73 additions and 63 deletions

View File

@ -1,5 +1,4 @@
import json from datetime import datetime, timedelta
from sqlalchemy import create_engine, Column, String, ForeignKey, Integer from sqlalchemy import create_engine, Column, String, ForeignKey, Integer
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
@ -66,18 +65,26 @@ def get_story_by_ref(ref):
session = Session() session = Session()
return session.query(Story).filter(Story.ref==ref).first() return session.query(Story).filter(Story.ref==ref).first()
def get_reflist(amount): def get_stories_by_url(url):
session = Session() session = Session()
q = session.query(Reflist).order_by(Reflist.rid.desc()).limit(amount) return session.query(Story).\
filter(Story.title != None).\
filter(Story.meta['url'].as_string() == url).\
order_by(Story.meta['date'].desc())
def get_reflist():
session = Session()
q = session.query(Reflist).order_by(Reflist.rid.desc())
return [dict(ref=x.ref, sid=x.sid, source=x.source) for x in q.all()] return [dict(ref=x.ref, sid=x.sid, source=x.source) for x in q.all()]
def get_stories(amount): def get_stories(maxage=60*60*24*2):
time = datetime.now().timestamp() - maxage
session = Session() session = Session()
q = session.query(Reflist, Story.meta).\ q = session.query(Reflist, Story.meta).\
join(Story).\ join(Story).\
filter(Story.title != None).\ filter(Story.title != None).\
order_by(Story.meta['date'].desc()).\ filter(Story.meta['date'] > time).\
limit(amount) order_by(Story.meta['date'].desc())
return [x[1] for x in q] return [x[1] for x in q]
def put_ref(ref, sid, source): def put_ref(ref, sid, source):

View File

@ -6,16 +6,13 @@ logging.basicConfig(
import requests import requests
import time import time
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import itertools
import settings import settings
from feeds import hackernews, reddit, tildes, substack, manual, news from feeds import hackernews, reddit, tildes, substack, manual, news
from scrapers import outline, declutter, local from scrapers import outline, declutter, local
ONE_HOUR = 60*60
ONE_DAY = 24*ONE_HOUR
INVALID_DOMAINS = ['youtube.com', 'bloomberg.com', 'wsj.com'] INVALID_DOMAINS = ['youtube.com', 'bloomberg.com', 'wsj.com']
MAX_AGE_IN_DAYS = 3*ONE_DAY
substacks = {} substacks = {}
for key, value in settings.SUBSTACK.items(): for key, value in settings.SUBSTACK.items():
@ -27,36 +24,39 @@ sitemaps = {}
for key, value in settings.SITEMAP.items(): for key, value in settings.SITEMAP.items():
sitemaps[key] = news.Sitemap(value['url'], value.get('tz')) sitemaps[key] = news.Sitemap(value['url'], value.get('tz'))
def list(): def get_list():
feed = [] feeds = {}
if settings.NUM_HACKERNEWS: if settings.NUM_HACKERNEWS:
feed += [(x, 'hackernews') for x in hackernews.feed()[:settings.NUM_HACKERNEWS]] feeds['hackernews'] = [(x, 'hackernews') for x in hackernews.feed()[:settings.NUM_HACKERNEWS]]
if settings.NUM_REDDIT: if settings.NUM_REDDIT:
feed += [(x, 'reddit') for x in reddit.feed()[:settings.NUM_REDDIT]] feeds['reddit'] = [(x, 'reddit') for x in reddit.feed()[:settings.NUM_REDDIT]]
if settings.NUM_TILDES: if settings.NUM_TILDES:
feed += [(x, 'tildes') for x in tildes.feed()[:settings.NUM_TILDES]] feeds['tildes'] = [(x, 'tildes') for x in tildes.feed()[:settings.NUM_TILDES]]
if settings.NUM_SUBSTACK: if settings.NUM_SUBSTACK:
feed += [(x, 'substack') for x in substack.top.feed()[:settings.NUM_SUBSTACK]] feeds['substack'] = [(x, 'substack') for x in substack.top.feed()[:settings.NUM_SUBSTACK]]
for key, publication in substacks.items(): for key, publication in substacks.items():
count = settings.SUBSTACK[key]['count'] count = settings.SUBSTACK[key]['count']
feed += [(x, key) for x in publication.feed()[:count]] feeds[key] = [(x, key) for x in publication.feed()[:count]]
for key, sites in categories.items(): for key, sites in categories.items():
count = settings.CATEGORY[key].get('count') or 0 count = settings.CATEGORY[key].get('count') or 0
excludes = settings.CATEGORY[key].get('excludes') excludes = settings.CATEGORY[key].get('excludes')
tz = settings.CATEGORY[key].get('tz') tz = settings.CATEGORY[key].get('tz')
feed += [(x, key) for x in sites.feed(excludes)[:count]] feeds[key] = [(x, key) for x in sites.feed(excludes)[:count]]
for key, sites in sitemaps.items(): for key, sites in sitemaps.items():
count = settings.SITEMAP[key].get('count') or 0 count = settings.SITEMAP[key].get('count') or 0
excludes = settings.SITEMAP[key].get('excludes') excludes = settings.SITEMAP[key].get('excludes')
feed += [(x, key) for x in sites.feed(excludes)[:count]] feeds[key] = [(x, key) for x in sites.feed(excludes)[:count]]
values = feeds.values()
feed = itertools.chain.from_iterable(itertools.zip_longest(*values, fillvalue=None))
feed = list(filter(None, feed))
return feed return feed
def get_article(url): def get_article(url):
@ -124,7 +124,7 @@ def update_story(story, is_manual=False):
logging.info('Story not ready yet') logging.info('Story not ready yet')
return False return False
if story['date'] and not is_manual and story['date'] + MAX_AGE_IN_DAYS < time.time(): if story['date'] and not is_manual and story['date'] + settings.MAX_STORY_AGE < time.time():
logging.info('Story too old, removing') logging.info('Story too old, removing')
return False return False

View File

@ -163,6 +163,8 @@ def get_sitemap_date(a):
return a.find('lastmod').text return a.find('lastmod').text
if a.find('news:publication_date'): if a.find('news:publication_date'):
return a.find('news:publication_date').text return a.find('news:publication_date').text
if a.find('ns2:publication_date'):
return a.find('ns2:publication_date').text
return '' return ''
class Sitemap(_Base): class Sitemap(_Base):

View File

@ -15,6 +15,7 @@ import traceback
import time import time
from urllib.parse import urlparse, parse_qs from urllib.parse import urlparse, parse_qs
import settings
import database import database
import search import search
import feed import feed
@ -27,9 +28,6 @@ from flask_cors import CORS
database.init() database.init()
search.init() search.init()
FEED_LENGTH = 75
news_index = 0
def new_id(): def new_id():
nid = gen_rand_id() nid = gen_rand_id()
while database.get_story(nid): while database.get_story(nid):
@ -42,7 +40,7 @@ cors = CORS(flask_app)
@flask_app.route('/api') @flask_app.route('/api')
def api(): def api():
stories = database.get_stories(FEED_LENGTH) stories = database.get_stories(settings.MAX_STORY_AGE)
res = Response(json.dumps({"stories": stories})) res = Response(json.dumps({"stories": stories}))
res.headers['content-type'] = 'application/json' res.headers['content-type'] = 'application/json'
return res return res
@ -101,7 +99,9 @@ def submit():
def story(sid): def story(sid):
story = database.get_story(sid) story = database.get_story(sid)
if story: if story:
res = Response(json.dumps({"story": story.data})) related = database.get_stories_by_url(story.meta['url'])
related = [r.meta for r in related]
res = Response(json.dumps({"story": story.data, "related": related}))
res.headers['content-type'] = 'application/json' res.headers['content-type'] = 'application/json'
return res return res
else: else:
@ -144,14 +144,8 @@ def static_story(sid):
http_server = WSGIServer(('', 33842), flask_app) http_server = WSGIServer(('', 33842), flask_app)
def feed_thread(): def _add_new_refs():
global news_index for ref, source in feed.get_list():
try:
while True:
# onboard new stories
if news_index == 0:
for ref, source in feed.list():
if database.get_story_by_ref(ref): if database.get_story_by_ref(ref):
continue continue
try: try:
@ -161,18 +155,13 @@ def feed_thread():
except database.IntegrityError: except database.IntegrityError:
continue continue
ref_list = database.get_reflist(FEED_LENGTH) def _update_current_story(item):
# update current stories
if news_index < len(ref_list):
item = ref_list[news_index]
try: try:
story = database.get_story(item['sid']).data story = database.get_story(item['sid']).data
except AttributeError: except AttributeError:
story = dict(id=item['sid'], ref=item['ref'], source=item['source']) story = dict(id=item['sid'], ref=item['ref'], source=item['source'])
logging.info('Updating story: ' + str(story['ref']) + ', index: ' + str(news_index)) logging.info('Updating story: {}'.format(str(story['ref'])))
valid = feed.update_story(story) valid = feed.update_story(story)
if valid: if valid:
@ -181,14 +170,23 @@ def feed_thread():
else: else:
database.del_ref(item['ref']) database.del_ref(item['ref'])
logging.info('Removed ref {}'.format(item['ref'])) logging.info('Removed ref {}'.format(item['ref']))
else:
logging.info('Skipping index: ' + str(news_index)) def feed_thread():
ref_list = []
try:
while True:
# onboard new stories
if not len(ref_list):
_add_new_refs()
ref_list = database.get_reflist()
# update current stories
if len(ref_list):
item = ref_list.pop(0)
_update_current_story(item)
gevent.sleep(6) gevent.sleep(6)
news_index += 1
if news_index == FEED_LENGTH: news_index = 0
except KeyboardInterrupt: except KeyboardInterrupt:
logging.info('Ending feed thread...') logging.info('Ending feed thread...')
except ValueError as e: except ValueError as e:

View File

@ -1,6 +1,8 @@
# QotNews settings # QotNews settings
# edit this file and save it as settings.py # edit this file and save it as settings.py
MAX_STORY_AGE = 3*24*60*60
# Feed Lengths # Feed Lengths
# Number of top items from each site to pull # Number of top items from each site to pull
# set to 0 to disable that site # set to 0 to disable that site

View File

@ -72,5 +72,6 @@ export const logos = {
stuff: "data:image/png;base64,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", stuff: "data:image/png;base64,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",
substack: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB80lEQVR4Ae3BwUtTcQAH8O/vt98L3/YYYm2TDusUZCBURlTHSV3yTzA8iHcVaYID50HQIWM3BY8P/QdaIAV2a2HIKDGhukgjtqEi7+3trb3X79c7jijbRr2fBz8fAk8sGIiVn0bL8FG/Xu2v1H9UKCSjkIzB43DhFCpOAT5yuHBw4Twg8PT10L6XTy6/go8evzh+dNLgJwwehRJl6Aq7Ax8plCjwUEjG4BECosnRhI+EgMCF84DAE1ZoOPswnIWPpt8Y04bDDQaPqhB1/IY6Dh/NvTPnDAcGhWQUklFIRiEZhWQUklFIRiEZQ5fKdV6e3zXnCQhZuKstxFQaQxcYOlR3RT37wcpm3lsZs8lNeDa/2JvJW6Hk1GBoKshIEB1gaBMX4PpnW0/tGKmSxUtoYTa5mdoxU2v71trivfDi6HV1lBJQtIGhDdvfmtszBWOmeOQUcYaSxUtjr0/HcntWbuVBeCVx9VICf8Fwho+nzkHybe1Z/rCRRweKR05x+Pnx8Mi1npHl+1rmZq8ygD9g+I2qzavp3Vp6/aC+7nLhokv5w0Z+6+v3rYmB4ER6SEtHVRrFLxha2C7s3J6VWyrWlgyHG/gHXC7c1X1rdeOTvTF7W5udHAxNqgwqWkXUQERP9OpxjcXxn8U1FtcTvXpEDUTg+QkFxcDjVd0KBQAAAABJRU5ErkJggg==", substack: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB80lEQVR4Ae3BwUtTcQAH8O/vt98L3/YYYm2TDusUZCBURlTHSV3yTzA8iHcVaYID50HQIWM3BY8P/QdaIAV2a2HIKDGhukgjtqEi7+3trb3X79c7jijbRr2fBz8fAk8sGIiVn0bL8FG/Xu2v1H9UKCSjkIzB43DhFCpOAT5yuHBw4Twg8PT10L6XTy6/go8evzh+dNLgJwwehRJl6Aq7Ax8plCjwUEjG4BECosnRhI+EgMCF84DAE1ZoOPswnIWPpt8Y04bDDQaPqhB1/IY6Dh/NvTPnDAcGhWQUklFIRiEZhWQUklFIRiEZQ5fKdV6e3zXnCQhZuKstxFQaQxcYOlR3RT37wcpm3lsZs8lNeDa/2JvJW6Hk1GBoKshIEB1gaBMX4PpnW0/tGKmSxUtoYTa5mdoxU2v71trivfDi6HV1lBJQtIGhDdvfmtszBWOmeOQUcYaSxUtjr0/HcntWbuVBeCVx9VICf8Fwho+nzkHybe1Z/rCRRweKR05x+Pnx8Mi1npHl+1rmZq8ygD9g+I2qzavp3Vp6/aC+7nLhokv5w0Z+6+v3rYmB4ER6SEtHVRrFLxha2C7s3J6VWyrWlgyHG/gHXC7c1X1rdeOTvTF7W5udHAxNqgwqWkXUQERP9OpxjcXxn8U1FtcTvXpEDUTg+QkFxcDjVd0KBQAAAABJRU5ErkJggg==",
"the bulletin": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADwElEQVR4AcXBW2iWBRzH8e/v/z7vfH3du5rOU7p0w8PwkIlM2kIsSbSoGdhFXkRkh0sp6qLool0EddnJKIT0oqguVDDEUjRRYSbOssY2zWpbs3Ind3Dnd8+/HQij8H0f9WKfjwq27HImkTHJjElmTDLjlghHTBDXiZsVcFOccYJEzCjITzAlDkPD0N45QO+wY4wR4EQREJEAR2wqncuzm0tYu7yQRNyQwIGhdEh9Qyv7Tv3GZ4cv0j0QIkQ2ARHl5Bjv7yijomwJZsa/CUjEY9y7+C5WLZrN848uY8c7JzhZ04KZkYmRlRHivP3CGraUL8HMyESKMa/gTjaVFSKJbAKyCllZdAdPbliBZIxJj6T5/Fg9R84209M/zIxUghVF+TyxfhGz86ex+1ANb+w+hySyCYhgU+kCTGKcOx8d+InKPdWYGU7ImANVTby79zyPlS3gy28bcDeQk01ABEVzc8EBgcvZf+pXMEY5Qoxz6B1wvjjWADIQkRgRhCEIMc6haE4uLsa5O9cJZExwogjIwh1+vtyFA2LCW8+VEY8FHDvXTFvPEIZAjHLAESKqgCzc4WBVI69uKyUnCJCMgvwUO196kJGRkLauXhpbrvHL5aucudDK4e+aaO9JE1UsWVJRSQYSdFxLgw9SvnIeJiGEJGJmpJIJ5s/M457iWWwuXcBTm0sYHOqn+mI7ILKJJUsqKslCwOnaVppaOlhZPJ1UcgqS+C9JJOJxHlhdSHdvH9UX2kEik1iypKKSSERtQxe7D9Vx4sdm6ps6aGrppuvaAEEAuYkcxCgJSaxZOotPvq5nOB2SScBNGk5DVU0bp2taQYwShGnuXzaLXa9tpCCVCxJ5yanct7yAo2dbgJAbMW6BBEiAGKcYp2rb+PSbOpyQMZK4e2Yu4GRiROQ4IsRx/kcCE119wzjXuYtsjIie3riIj19Zz4y8OI7jDo5wHHCm5sSoKCvEZIxxD2m80kM2ARFsf2Qxb24vx8zYsLqQI9WNfH+pnZaOfgyxcG6Kx9cVs3T+dP7xV2cfVTV/AiKTgIyMVcV5VD5TTswMychLTmXruhK2ruOG0iMjvL7rBINDApGRkVHI+UtXefG9o7T19OEekk1P/yAvf3icA1V/4CKrgGxM7DvZzPEf9rLtocU8vHY+yxbOITklhgB3ETr8fqWTr840sOdgLU1tgxgiioCI2nvS7Nxfxwf764jHQmakEkxLGCHiavcgXX1pQIAwoguISEwQkB4xrnQO4ThjhADjVgTcBiFulzHJjElmTLK/AU9/SZ4HPrs9AAAAAElFTkSuQmCC", "the bulletin": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADwElEQVR4AcXBW2iWBRzH8e/v/z7vfH3du5rOU7p0w8PwkIlM2kIsSbSoGdhFXkRkh0sp6qLool0EddnJKIT0oqguVDDEUjRRYSbOssY2zWpbs3Ind3Dnd8+/HQij8H0f9WKfjwq27HImkTHJjElmTDLjlghHTBDXiZsVcFOccYJEzCjITzAlDkPD0N45QO+wY4wR4EQREJEAR2wqncuzm0tYu7yQRNyQwIGhdEh9Qyv7Tv3GZ4cv0j0QIkQ2ARHl5Bjv7yijomwJZsa/CUjEY9y7+C5WLZrN848uY8c7JzhZ04KZkYmRlRHivP3CGraUL8HMyESKMa/gTjaVFSKJbAKyCllZdAdPbliBZIxJj6T5/Fg9R84209M/zIxUghVF+TyxfhGz86ex+1ANb+w+hySyCYhgU+kCTGKcOx8d+InKPdWYGU7ImANVTby79zyPlS3gy28bcDeQk01ABEVzc8EBgcvZf+pXMEY5Qoxz6B1wvjjWADIQkRgRhCEIMc6haE4uLsa5O9cJZExwogjIwh1+vtyFA2LCW8+VEY8FHDvXTFvPEIZAjHLAESKqgCzc4WBVI69uKyUnCJCMgvwUO196kJGRkLauXhpbrvHL5aucudDK4e+aaO9JE1UsWVJRSQYSdFxLgw9SvnIeJiGEJGJmpJIJ5s/M457iWWwuXcBTm0sYHOqn+mI7ILKJJUsqKslCwOnaVppaOlhZPJ1UcgqS+C9JJOJxHlhdSHdvH9UX2kEik1iypKKSSERtQxe7D9Vx4sdm6ps6aGrppuvaAEEAuYkcxCgJSaxZOotPvq5nOB2SScBNGk5DVU0bp2taQYwShGnuXzaLXa9tpCCVCxJ5yanct7yAo2dbgJAbMW6BBEiAGKcYp2rb+PSbOpyQMZK4e2Yu4GRiROQ4IsRx/kcCE119wzjXuYtsjIie3riIj19Zz4y8OI7jDo5wHHCm5sSoKCvEZIxxD2m80kM2ARFsf2Qxb24vx8zYsLqQI9WNfH+pnZaOfgyxcG6Kx9cVs3T+dP7xV2cfVTV/AiKTgIyMVcV5VD5TTswMychLTmXruhK2ruOG0iMjvL7rBINDApGRkVHI+UtXefG9o7T19OEekk1P/yAvf3icA1V/4CKrgGxM7DvZzPEf9rLtocU8vHY+yxbOITklhgB3ETr8fqWTr840sOdgLU1tgxgiioCI2nvS7Nxfxwf764jHQmakEkxLGCHiavcgXX1pQIAwoguISEwQkB4xrnQO4ThjhADjVgTcBiFulzHJjElmTLK/AU9/SZ4HPrs9AAAAAElFTkSuQmCC",
tvnz: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAASAAAAEgARslrPgAABWVJREFUWMOVl1+MlNUZxn/PmYGFXSgw7kJbiPzZVVkBaaSicTclFWyMJjaxiUkTNd6ZEOMF8cZojIlR74xpb9pb7AW98KY3VAu0Wi0IasVVEQPpAqIBZgd2gF3izJzHi++bmW92/rg9yTeZ88133vd33vO87/eOmOf4cMcmbHJBLJdYL7FGaKkEEleBc0H8D8IVIG498Nm87KrXj4d/dTs2AMsEY5J2StwhsVYwKGmRBIIbEpckzggdlzggOGwoB2DzPyb+f4B/j90OMCB4UOJxiXHBCkmku0ZAY05yLwiESoj3BG9K/N1mZksXiDaAd+8dRQbDrRJ7JD2aOO7gtDcEEiVgn8TrNqdDgE1vT3QH+Oc9owRExGMSrwrGJYKkhvHkmjPvDRGBf0k8Z3NUgs3vTLQDHLh7Y33n9wbpDxLbsga7OsXgSAgBhUDrmgYEgqMST9scy0YiAHw4/gtihJq51fBKtLfZYENsXE6uGInVGrFWwxL5whADo1vJD67EMeJkE9TXG9fvbbd5RWLYhslHtgCQB7h8YxagX2gPsAOBbUjpnVoMCxfSN7SSgbUbGLhlI/3rNrD45vX0/XQ11z7/L2feeJlqqQghJGFwPc4GC4ldNs9IPHf1KjMA+f133gaJ/YeQH8WSACvdRmqpb+Uq1j75FMvv3E7f0Cpy/QNJjNOxZNNWFg79jErxYnpfbRBGEjxmcxD428T9W8hHgMgywWPAivTBZGEaCcXI0o2bWfXAb8n193dJaGGpXjea8BkIJ0YLiMcF7wLTIT2rMcN449zsxjk2FuYXJNLuMUyil6YO3KKJ2NTEfYa7DIRajLK906bQ8uBcMcVab+eu6yYrwFYIUkBwwWYspz4CqGC4o502Ub3TnVXKZWoz14mVCpUrJVytdgSJdtNpNqKZjaWRuKcSbxTyNuuBtWRFlzm3iJECV76Y4MRrLxHyORYsWcrw7j0sWFHoEIV0aZutNtvDwLq8YQ1msFGWOkAgqM5c58Khd6BWpbDtLhxjl2PIJk9PiEGJ1XnbS0GLmmruDqGQSzMsdBVhVrxttlojswizJJ/MnSb+j0Ek8TV0B0h1QyeIOXMDeUMZM4u8eF4QvQAyoktKaE+IWYmrAXPOUGyp2z1yuT7vCpB9bo4w58yLNueDYdLmTNvLowtE7BkF94ZoTdFTNpOhWvNl28c7vsE6QTiF6Oa841u0o60jZy9duxxCwIYDtkvzhei0/UaIaR5Ri63W8E/Z/uDnNw0Q0lWHbd5rP7cOEKmx9qHM7jtAtNo+aPgIIKThLBvetJlqPEgXCEOs1TLJ3lRgvSGBnhBFm721SDkawu9PnKo73G/Yl+hkjpgyEChw/dxZSp9+TKU8TWV6mkp5mtInx5j59jxWyDjOQCS2ou29hkMA4+9/mSTmICP8cRSAYcGfBLsafWC2x2v0d2bxylX0r1lDCAFsZr85y/dTl5LesGVNSxe9X7AbmNxx+ASQtmRFTuE4Qshx2uZ54CeY7Y3a3TjmtGJKzF68wOyF75oOQiAEEe2k0UwLkQWyCeg/wAvRTGYrea7+5a2pEr+7qUBYyHnXOI7YAKyj3hg2tZZ8pE6TTlhJs9XWrwggIt4Gnq3W/IkC7DzyVTsAwFvFEo8sKxByfGv4ILVwC7C4I0TLvA7W4r+I9GfgRcMJgvjN0a+yLrv/Nds3OoKhX7BL8ITEryUVOvb87X9QpgQHJfZKHAJmH/joZJfk7TH+snGEvgDRLEP8Umhc4m6JYcGQxKIUYlaiKHFKcETS+xIfS5SrFXj4s5NdffTuMjPjr6MjACEELResQ6wOYonASNcE30icCWLaEB/+9Ot52f0B/MOqaxJsqlAAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTYtMDktMjhUMjA6NDA6MjkrMDA6MDD37mKbAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE2LTA5LTI4VDIwOjQwOjI5KzAwOjAwhrPaJwAAAEZ0RVh0c29mdHdhcmUASW1hZ2VNYWdpY2sgNi43LjgtOSAyMDE0LTA1LTEyIFExNiBodHRwOi8vd3d3LmltYWdlbWFnaWNrLm9yZ9yG7QAAAAAYdEVYdFRodW1iOjpEb2N1bWVudDo6UGFnZXMAMaf/uy8AAAAYdEVYdFRodW1iOjpJbWFnZTo6aGVpZ2h0ADE5Mg8AcoUAAAAXdEVYdFRodW1iOjpJbWFnZTo6V2lkdGgAMTky06whCAAAABl0RVh0VGh1bWI6Ok1pbWV0eXBlAGltYWdlL3BuZz+yVk4AAAAXdEVYdFRodW1iOjpNVGltZQAxNDc1MDk1MjI5BqTtUAAAAA90RVh0VGh1bWI6OlNpemUAMEJClKI+7AAAAFZ0RVh0VGh1bWI6OlVSSQBmaWxlOi8vL21udGxvZy9mYXZpY29ucy8yMDE2LTA5LTI4LzgzZWFmZGYwYzNkNzQzZDY4YzI0NzE0ZTVhMjY4YWY2Lmljby5wbmcMVz3tAAAAAElFTkSuQmCC",
webworm: "data:image/png;base64,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", webworm: "data:image/png;base64,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",
}; };