django-restit 4.2.73__py3-none-any.whl → 4.2.75__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
account/models/member.py CHANGED
@@ -224,7 +224,11 @@ class Member(User, RestModel, MetaDataModel):
224
224
 
225
225
  @property
226
226
  def force_single_session(self):
227
- return self.getProperty("force_single_session", category="permissions", default=None)
227
+ return self.hasPermission("force_single_session")
228
+
229
+ @property
230
+ def email_disabled(self):
231
+ return self.hasPermission("email_disabled")
228
232
 
229
233
  @property
230
234
  def has_totp(self):
@@ -528,7 +532,7 @@ class Member(User, RestModel, MetaDataModel):
528
532
  body += "<br>\n".join(accounts)
529
533
  Member.notifyWithPermission("user_audit", subject, message=body, email_only=True)
530
534
 
531
- def locateByIP(self, ip):
535
+ def locateByIP(self, ip, security_check=True):
532
536
  loc = GeoIP.get(ip)
533
537
  if loc is not None:
534
538
  self.setProperty("last_ip", ip)
@@ -537,6 +541,26 @@ class Member(User, RestModel, MetaDataModel):
537
541
  self.setProperty("country", loc.country, "location")
538
542
  self.setProperty("lat", loc.lat, "location")
539
543
  self.setProperty("lng", loc.lng, "location")
544
+ if security_check:
545
+ self.checkLocationSecurity(loc)
546
+
547
+ def checkLocationSecurity(self, loc=None, ip=None):
548
+ if loc is None and ip is None:
549
+ return
550
+ if loc is None:
551
+ loc = GeoIP.get(ip)
552
+ auth_session = self.auth_sessions.last()
553
+ # check for state or country changes
554
+ if auth_session is not None and auth_session.location is not None:
555
+ try:
556
+ if auth_session.location.country != loc.country:
557
+ details = f"user login from new country {loc.country} vs previous {auth_session.location.country}"
558
+ self.reportIncident("account", details)
559
+ elif auth_session.location.state != loc.state:
560
+ details = f"user login from new state {loc.state} vs previous {auth_session.location.state}"
561
+ self.reportIncident("account", details)
562
+ except Exception:
563
+ rh.log_exception(self.username)
540
564
 
541
565
  def sendSMS(self, msg):
542
566
  from telephony.models import SMS
@@ -622,7 +646,11 @@ class Member(User, RestModel, MetaDataModel):
622
646
  email = self.email
623
647
  valid_email = email is not None and "@" in email and "invalid" not in email
624
648
  allow_sms = not email_only and phone and (force or via in ["all", "sms"])
625
- allow_email = valid_email and (force or via in ["all", "email"])
649
+ if not force:
650
+ allow_email = not self.email_disabled and valid_email and (force or via in ["all", "email"])
651
+ else:
652
+ allow_email = valid_email
653
+
626
654
  if not allow_email and not allow_sms:
627
655
  return False
628
656
 
@@ -1049,7 +1077,7 @@ class Member(User, RestModel, MetaDataModel):
1049
1077
  return Member.objects.filter(phone_number=phone_number.lower()).last()
1050
1078
 
1051
1079
  @staticmethod
1052
- def GetWithPermission(perm, email_list=False):
1080
+ def GetWithPermission(perm, email_list=False, ignore_disabled_email=True):
1053
1081
  if type(perm) is list:
1054
1082
  queries = [Q(properties__category="permissions", properties__key=p, properties__value="1") for p in perm]
1055
1083
  query = queries.pop()
@@ -1059,12 +1087,17 @@ class Member(User, RestModel, MetaDataModel):
1059
1087
  else:
1060
1088
  qset = Member.objects.filter(is_active=True).filter(properties__category="permissions", properties__key=perm, properties__value="1")
1061
1089
 
1090
+ if not ignore_disabled_email:
1091
+ qset = qset.exclude(
1092
+ properties__category="permissions",
1093
+ properties__key="email_disabled",
1094
+ properties__int_value=1)
1062
1095
  if email_list:
1063
1096
  return list(qset.exclude(email__icontains="invalid").values_list('email', flat=True))
1064
1097
  return qset
1065
1098
 
1066
1099
  @staticmethod
1067
- def GetWithNotification(perm, email_list=False, exclude_member=None):
1100
+ def GetWithNotification(perm, email_list=False, exclude_member=None, ignore_disabled_email=True):
1068
1101
  qset = Member.objects.filter(is_active=True)
1069
1102
  if exclude_member:
1070
1103
  qset = qset.exclude(pk=exclude_member.pk)
@@ -1087,6 +1120,11 @@ class Member(User, RestModel, MetaDataModel):
1087
1120
  properties__key=perm,
1088
1121
  properties__int_value=1)
1089
1122
 
1123
+ if not ignore_disabled_email:
1124
+ qset = qset.exclude(
1125
+ properties__category="permissions",
1126
+ properties__key="email_disabled",
1127
+ properties__int_value=1)
1090
1128
  if email_list:
1091
1129
  return list(qset.exclude(email__icontains="invalid").values_list('email', flat=True))
1092
1130
  return qset
@@ -1133,7 +1171,7 @@ class Member(User, RestModel, MetaDataModel):
1133
1171
  email_only=False, sms_msg=None, force=False, from_email=None):
1134
1172
  NotificationRecord = RestModel.getModel("account", "NotificationRecord")
1135
1173
  NotificationRecord.notify(
1136
- Member.GetWithPermission(perm), subject, message,
1174
+ Member.GetWithPermission(perm, ignore_disabled_email=True), subject, message,
1137
1175
  template, context, email_only, sms_msg, force,
1138
1176
  from_email=from_email)
1139
1177
 
@@ -1143,7 +1181,8 @@ class Member(User, RestModel, MetaDataModel):
1143
1181
  exclude_member=None):
1144
1182
  NotificationRecord = RestModel.getModel("account", "NotificationRecord")
1145
1183
  NotificationRecord.notify(
1146
- Member.GetWithNotification(setting, exclude_member=exclude_member), subject, message,
1184
+ Member.GetWithNotification(setting, exclude_member=exclude_member, ignore_disabled_email=True),
1185
+ subject, message,
1147
1186
  template, context, email_only, sms_msg, force,
1148
1187
  from_email=from_email)
1149
1188
 
account/models/notify.py CHANGED
@@ -151,12 +151,90 @@ class NotificationRecord(models.Model, RestModel):
151
151
  members = Member.objects.filter(email__in=emails)
152
152
  cls.notify(members, subject, message, template, context, email_only, sms_msg, force, from_email, attachments)
153
153
 
154
+
154
155
  @classmethod
155
156
  def notify(cls, notify_users, subject, message=None,
156
157
  template=None, context=None, email_only=False,
157
158
  sms_msg=None, force=False,
158
159
  from_email=settings.DEFAULT_FROM_EMAIL,
159
160
  attachments=[]):
161
+ dup_list = []
162
+ email_to = []
163
+ sms_to = []
164
+ for member in notify_users:
165
+ via = member.getProperty("notify_via", "all")
166
+ phone = member.getProperty("phone")
167
+ email = member.email
168
+ valid_email = email is not None and "@" in email and "invalid" not in email
169
+ allow_sms = not email_only and phone and (force or via in ["all", "sms"])
170
+ allow_email = not member.email_disabled and valid_email and (force or via in ["all", "email"])
171
+ if not allow_email and not allow_sms:
172
+ continue
173
+ if allow_email and email not in dup_list:
174
+ dup_list.append(email)
175
+ email_to.append(member)
176
+ if not email_only and allow_sms and phone not in dup_list:
177
+ dup_list.append(phone)
178
+ sms_to.append(phone)
179
+
180
+ if len(dup_list) == 0:
181
+ return
182
+
183
+ if not message and not template and subject:
184
+ message = subject
185
+ if not sms_msg and subject:
186
+ sms_msg = subject
187
+ if not sms_msg and message:
188
+ sms_msg = message
189
+
190
+ if subject and len(subject) > 80:
191
+ epos = subject.find('. ') + 1
192
+ if epos > 10:
193
+ subject = subject[:epos]
194
+ if len(subject) > 80:
195
+ subject = subject[:80]
196
+ subject = subject[:subject.rfind(' ')] + "..."
197
+
198
+ if sms_to:
199
+ for phone in sms_to:
200
+ SMS.send(phone, sms_msg)
201
+
202
+ if not email_to:
203
+ return
204
+ for member in email_to:
205
+ cls._notifyViaEmail(member, subject, message, template, context, attachments, from_email)
206
+
207
+ @classmethod
208
+ def _notifyViaEmail(cls, member, subject, message, template, context,
209
+ attachments, from_email=None):
210
+ # lets verify the db is working
211
+ if template:
212
+ if context is None:
213
+ context = {}
214
+ if message is not None:
215
+ context["body"] = message
216
+ context["unsubscribe_token"] = member.getUUID()
217
+ message = inbox.utils.renderTemplate(template, context)
218
+
219
+ nr = NotificationMemberRecord(member=member, to_addr=member.email)
220
+ email_record = NotificationRecord(
221
+ method="email",
222
+ subject=subject,
223
+ from_addr=from_email,
224
+ body=message)
225
+ try:
226
+ email_record.save()
227
+ email_record.addAttachments(attachments)
228
+ email_record.send([nr])
229
+ except Exception as err:
230
+ rh.log_exception("email send failed", email_to)
231
+
232
+ @classmethod
233
+ def notifyLegacy(cls, notify_users, subject, message=None,
234
+ template=None, context=None, email_only=False,
235
+ sms_msg=None, force=False,
236
+ from_email=settings.DEFAULT_FROM_EMAIL,
237
+ attachments=[]):
160
238
  # this will create a record for each email address message is sent to
161
239
  from telephony.models import SMS
162
240
  email_to = []
@@ -165,7 +243,6 @@ class NotificationRecord(models.Model, RestModel):
165
243
 
166
244
  if not message and not template and subject:
167
245
  message = subject
168
-
169
246
  if not sms_msg and subject:
170
247
  sms_msg = subject
171
248
  if not sms_msg and message:
@@ -197,7 +274,7 @@ class NotificationRecord(models.Model, RestModel):
197
274
  email = member.email
198
275
  valid_email = email is not None and "@" in email and "invalid" not in email
199
276
  allow_sms = not email_only and phone and (force or via in ["all", "sms"])
200
- allow_email = valid_email and (force or via in ["all", "email"])
277
+ allow_email = not member.email_disabled and valid_email and (force or via in ["all", "email"])
201
278
  if not allow_email and not allow_sms:
202
279
  continue
203
280
  if allow_email and email not in email_list:
@@ -226,7 +303,7 @@ class NotificationRecord(models.Model, RestModel):
226
303
  email_record.addAttachments(attachments)
227
304
  email_record.send(email_to)
228
305
  except Exception as err:
229
- print(("failed to create record: {}".format(str(err))))
306
+ rh.log_exception("email send failed", email_to)
230
307
  # we need to send emails the old way
231
308
  addrs = []
232
309
  for to in email_to:
@@ -302,6 +379,7 @@ class BounceHistory(models.Model, RestModel):
302
379
  if bounce_count > 2:
303
380
  # TODO notify support an account has been disabled because of bounce
304
381
  user.setProperty("notify_via", "off")
382
+ user.addPermission("email_disabled")
305
383
  user.log("disabled", "notifications disabled because email bounced", method="notify")
306
384
  else:
307
385
  # TODO notify support of unknown bounce
account/rpc/auth.py CHANGED
@@ -58,7 +58,7 @@ def jwt_login(request):
58
58
 
59
59
 
60
60
  def on_complete_jwt(request, member):
61
- if member.security_token is None or member.security_token == JWT_KEY:
61
+ if member.security_token is None or member.security_token == JWT_KEY or member.force_single_session:
62
62
  member.refreshSecurityToken()
63
63
 
64
64
  member.log(
account/rpc/member.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from rest import decorators as rd
2
- from rest.views import restPermissionDenied, restStatus
2
+ from rest.views import restPermissionDenied, restStatus, restHTML
3
+ from rest import helpers as rh
3
4
  from account import models as am
4
5
 
5
6
 
@@ -39,3 +40,16 @@ def rest_on_authtoken(request, pk=None):
39
40
  def rest_on_session(request, pk=None):
40
41
  return am.AuthSession.on_rest_request(request, pk)
41
42
 
43
+
44
+ @rd.urlGET('unsubscribe')
45
+ @rd.requires_params(["t"])
46
+ def rest_on_member(request):
47
+ t = request.DATA.get("t")
48
+ m = am.Member.objects.filter(uuid=t).last()
49
+ if m is not None:
50
+ m.addPermission("email_disabled")
51
+ m.reportIncident("email", f"{m.email} has unsubscribed to all email")
52
+ context = rh.getContext(request, member=m)
53
+ if request.DATA.get("format") == "json":
54
+ return restStatus(request, True)
55
+ return restHTML(request, template="unsubscribed.html", context=context)
@@ -281,7 +281,7 @@
281
281
  <a href="{{settings.BASE_URL}}">{{settings.SITE_LABEL}}</a>
282
282
  </div>
283
283
  {% endblock %}
284
- <p style="text-align: center; font-size: 10px;">Don't want to get notifications? <a href="{{settings.BASE_URL}}rpc/account/member/unsubscribe?email={{to}}&token={{to_token}}">Unsubscribe</a>
284
+ <p style="text-align: center; font-size: 10px;">Don't want to get notifications? <a href="{{UNSUBSCRIBE_URL}}?t={{unsubscribe_token}}">Unsubscribe</a>
285
285
  </p>
286
286
  <div>
287
287
 
@@ -387,11 +387,6 @@
387
387
  <!-- START FOOTER -->
388
388
  <div class="footer">
389
389
  <table role="presentation" border="0" cellpadding="0" cellspacing="0">
390
- <tr>
391
- <td class="content-block">
392
- <br> Don't like these emails? <a href="{{BASE_URL}}member/unsubscribe/">Unsubscribe</a>.
393
- </td>
394
- </tr>
395
390
  <tr>
396
391
  <td class="content-block powered-by">
397
392
  <div>Powered by {{SITE_LABEL}}</div>
@@ -295,13 +295,6 @@
295
295
  {% endif %}
296
296
  <tr>
297
297
  <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
298
- <div style="font-family:Roboto, Helvetica, Arial, sans-serif;font-size:14px;font-weight:300;line-height:20px;text-align:center;color:#000000;">
299
- Don't like these emails? <a style="color: #c0c1ff;font-weight: bold;text-decoration: none;" href="{{BASE_URL}}member/unsubscribe/">Unsubscribe</a>.
300
- </div>
301
- </td>
302
- </tr>
303
- <tr>
304
- <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
305
298
 
306
299
  <table
307
300
  align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
@@ -284,13 +284,6 @@
284
284
  </tr>
285
285
  <tr>
286
286
  <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
287
- <div style="font-family:Roboto, Helvetica, Arial, sans-serif;font-size:14px;font-weight:300;line-height:20px;text-align:center;color:#000000;">
288
- Don't like these emails? <a style="color: #c0c1ff;font-weight: bold;text-decoration: none;" href="{{BASE_URL}}member/unsubscribe/">Unsubscribe</a>.
289
- </div>
290
- </td>
291
- </tr>
292
- <tr>
293
- <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
294
287
 
295
288
  <table
296
289
  align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
@@ -377,11 +377,6 @@
377
377
  <!-- START FOOTER -->
378
378
  <div class="footer">
379
379
  <table role="presentation" border="0" cellpadding="0" cellspacing="0">
380
- <tr>
381
- <td class="content-block">
382
- <br> Don't like these emails? <a href="{{BASE_URL}}member/unsubscribe/">Unsubscribe</a>.
383
- </td>
384
- </tr>
385
380
  <tr>
386
381
  <td class="content-block powered-by">
387
382
  <div>Powered by {{SITE_LABEL}}</div>
@@ -293,13 +293,6 @@
293
293
  </tr>
294
294
  <tr>
295
295
  <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
296
- <div style="font-family:Roboto, Helvetica, Arial, sans-serif;font-size:14px;font-weight:300;line-height:20px;text-align:center;color:#fafafa;">
297
- Don't like these emails? <a style="color: #c0c1ff;font-weight: bold;text-decoration: none;" href="{{BASE_URL}}member/unsubscribe/">Unsubscribe</a>.
298
- </div>
299
- </td>
300
- </tr>
301
- <tr>
302
- <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
303
296
 
304
297
  <table
305
298
  align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
@@ -284,13 +284,6 @@
284
284
  </tr>
285
285
  <tr>
286
286
  <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
287
- <div style="font-family:Roboto, Helvetica, Arial, sans-serif;font-size:14px;font-weight:300;line-height:20px;text-align:center;color:#fafafa;">
288
- Don't like these emails? <a style="color: #c0c1ff;font-weight: bold;text-decoration: none;" href="{{BASE_URL}}member/unsubscribe/">Unsubscribe</a>.
289
- </div>
290
- </td>
291
- </tr>
292
- <tr>
293
- <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
294
287
 
295
288
  <table
296
289
  align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
@@ -0,0 +1,74 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Unsubscription Successful</title>
7
+ <style>
8
+ body {
9
+ font-family: 'Arial', sans-serif;
10
+ background-color: #c6dde0;
11
+ margin: 0;
12
+ padding: 0;
13
+ display: flex;
14
+ justify-content: center;
15
+ align-items: center;
16
+ height: 100vh;
17
+ color: #333;
18
+ }
19
+ .container {
20
+ /* background-color: white;*/
21
+ padding: 40px 60px;
22
+ /* border-radius: 10px;*/
23
+ /* box-shadow: 0 4px 8px rgba(0,0,0,0.1);*/
24
+ text-align: center;
25
+ max-width: 500px;
26
+ }
27
+ .footer {
28
+ padding: 40px 60px;
29
+ text-align: center;
30
+ }
31
+ h1 {
32
+ color: #4c79af;
33
+ margin: 0;
34
+ text-shadow: 1px 1px 1px #a7a7a7;
35
+ }
36
+ h2, h3, h4 {
37
+ color: #4CAF50;
38
+ margin-top: 5px;
39
+ }
40
+ p {
41
+ margin-top: 20px;
42
+ font-size: 16px;
43
+ font-weight: bold;
44
+ }
45
+
46
+ span {
47
+ text-decoration: underline;
48
+ }
49
+ </style>
50
+ </head>
51
+ <body>
52
+ <div>
53
+ <div class="container">
54
+ <svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
55
+ <image id="Image-Layer" x="-1" y="-1" width="202" height="202" xlink:href="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAMoAAADKCAYAAADkZd+oAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAyqADAAQAAAABAAAAygAAAAA1p/4yAABAAElEQVR4Aey9V7Rmx3XnVzfHvp3RjUajEQgmkASzqKHSSCPPaCSNrNGDPWvZnjXLXvaT37z84gf7aR68bC+PrCV5lCwqkCIpiRQ5DCIpCgQoAARBEiQIIjYa3Q10zuGmvsn/33/XPt/5bt9uBHa4LX1173dOhV27du1Q6dSp01eqe+SFfT/bNzDw/tK3csfKyspkX1//wEopfZneu/c48A+dA1J2qf7yUl9f38Wy0ndoZWnpyZ96270PU28bwkPP7VsZGOwrAviHzote/XoceP0cUE+xvLxcfuZt9/b10ZOs9Pc91DOS18+/HuQ/Hg6oiyl9yys/N+jhVpHp9FyPAz0OXMYBOpC+gf739zMnuSy1F9HjQI8DHQ7IRvrVs0x0Ynq+Hgd6HFjNAWykX13L4OqEXrjHgR4HOhzARvp7S8AdhvR8PQ6sxQFspH+thF5cjwM9DnRzoGco3fzohXocWJMDPUNZky29yB4HujnQM5RufvRCPQ6syYGeoazJll5kjwPdHOgZSjc/eqEeB9bkQM9Q1mRLL7LHgW4O9Aylmx+9UI8Da3KgZyhrsqUX2eNANwd621e6+XHTQguLi3ptqJTBwYHee0E3TQpXLrhnKFfmzXVN4YWg518+UL73w2fL/lePlNPnL3qjxMapybJr523lLXfdWe6/d0/ZsWXTdaWjh/z1caBnKK+PT9cMakkG8uh3vl++/HePlqdfeEnGUd8q7e8v/fwGBspTL+wvA+NPlw2bNpZ33XNn+aWPfKC8467be+9lXzMpvHFEPUN54zx70zkOHjpaPvm5L5W/f+IHvJwtPHp7Toaiq/5WGHnpVW35luXXUGx6erY8+dLB8vShk+U/++B7yi9/+F1lamzkTZffy/jmOdAzlDfPu9edc1mK/9WHHy2f+OyXyumzZ6uRcEZBv/zLDR76FgylLC6VZf36ZCzcGaZ9XUO0V06dKb/xT95X3rJza5On57kxHOitel1nPs9dWii//aefLr/1R58op86cqUZCoeo1aq+CXwH3KfQmyzKeFRnH6t++YyfK73z178vDz7wsmOtMeA99Fwd6PUoXO65t4PzFmfLbf/bp8s1Hn9Ab1+ohPMton3Sz7BgOwyHdBqN5ik7McS/SJ2NZktH0KdyP4QhidmGh/JWGbqeE+5ff/44yMjRwbYnuYVuTAz1DWZMtP37ksZOn1Yt8qnzvqadlBAyvmIXgmJHYNCIkA2BohmMoVqT3fQoODtKjqHchfSl+LAQwBADbQ1oIODM9U/71T7ynbJ4YJXvPXUcO9AzlOjB3/6Ej5Td//+Plhb0HbB46wUNzDwrSHaPBMBTGCBaZh8gQPKEf4KyP5TIgg+ljjrKknkRDMpuY7jEkU95l9UD9feVHR4+X6ce+V35DE/07Nm+4DjXpoUwO9OYoyYlrdP/Ri/vKv//N3y8vvLRfCs7QKq5+51qGoTOiXNLS0mJZWFiUoYSRDI0Ol8kNG8rUpi1lYsNUGR4eLv30MMuISFbl1TENyxS3rC6HXGDaf/Js+dPHflCePXLqGtWgh2YtDvR6lLW48ibiltXiP/jYE+V3/vhTZW7uEqptF/eYuDN59596kAXNNXgTe3R0tAwNj5TB4aHSNzRYhkZHyvDoRBke0XBqcLBcEpblgUGdLaWfjIVeZWBlwMMveqZ+9Swnpy+Wjz/+/fIv7r+vfPS+PWVAcT13bTnQM5RrwM95rWx96vNfKZ/+wlc8H2cFC8e1T/6cnRDHMGtxccEPFkfGxsrg0LCMZFT3QRvLEIYzJMMZwWBGysDIcJleWC7zMhIdBx3GIsw2BRmasauMeQ3VvvT0i+X0xdnyi+9+S5mQ4fXcteNAz1B+TF7Ozs+X//AHnyiPaiWqT1NtBkXZntMD4Li6N1FvsKR5x4B6ik1btmiOUsrw+FgZ0NxkaBCDGVGPMloGNOwa0BP6ERlJvwxpZHyonJcx0rtoPGYj87AM3C6D4ZnKlmV+++DhclyT/N94//1l62Rvkg/LroXrGcqPwcULenL+f/zHj5Uf/OiFwCJFRXHTUPycxFYShsLkfWxivExunJJS95eJCRmJjAajGKJn0a9/aMg9C36n0dNoCXhYRnNRc5oZGVqflpD5ecsLhqMf9qJD2kzHwTPny598+6ny6w+8o9yzberHqGEva3KgZyjJiTd4P66n5P/37/9ZefbFl92T9PXpOYj1FEMJxV3RsxFaeZZ/F/UsZHJqQxmf2GBjGPWwS0YiQxnkJ2MZkJEMaPcwd+YkA4MyGvU20ePIWDQUG5GxTGt+w6Q+DAXj1E+dSp/WlvtYW9bv7MxM+dR3f+h5y3t376Aj6rkfgwM9Q3kTzHvlyLHy23/0yfLCvldtFCtSTIwDVbXTTeoqC7GV+Lblth1lTMMseg7PPehJMIraowxo/jE4HIaDkfTrhwENeKOkehAZkg6LVu8iY1keLhdm52wsFEnZ/aw/MwLj4sJLmdOK2n/64Yvl8JkL5RffdW8ZUf6ee3Mc6BnKG+Tb0y/sK7/zsU+Vo8dPqrfAMFBTGUod9iQ6Hg5aX9WU77j9jjKkoROKPz4+XvplIIP0HlJ+egUbBH7Fs3u4f6CThjEZdx1uMQwbUbmjMqTTc3NFT1rcWzDsAhcUceE5C/mg4bvajHlyZrb86/e+rbepMgX0Bu89Q3mdDGO+8dC3vlt+7+OfK/OawKOIy1LYNBU00nOSig8lHVDvsWnb1jKmYRYTc5aC6UH69cM4+hlW0WPoZ6Ohh5EB9PVhLKRFLxKGYu3Xk3tN/IV7hDmMVrbOq2dZkFH2K08Mv0SAQDGZMOAIv3p2unz2qRfLL99/b9m+Yfx11roHlhzoGUpy4ir3S5oX/NXffL185ksPlpWl7D1Q5BjjqC23kfS5hynenzWgFaxdd+62Mo9oFYseBWMYrEOqMIToBeyvvQs9CsvAaUCymJika3jneYnhRKwMY1iGNaLf2dlLZYFJflita4KZpIGF0fSVw+eny+dkLL/wtrvKvdt7L4RdReSXJfUM5TKWdEfMy0h+64/+vDz+/Wc810AXw0nJO4GMUseyopWtyfKWd76zzGpVjKft9D4ovodbtfcYGIg4jIQ9XsDE5Fx+jEUYyaPuxz0DE/QVGQfG5gm74PkQwaQm/MPqXc7qoeP8ghYPhIut+t4qqTt+20+9n5ZR/bV2H//0np3lQ3fvDCOsNerdrsyBnqFcmTfl3IWL5f/8vT8rz+17RVAoMiqnXgSl9V/LUkIbtQVlc7nj7rv0SslK2bz9NnUIYVA2FHoKGQb6H3OPGHZFyy8/aRiNlNrzDd3RcoWCSoxJMNJ+RWIo4KFnK3oOM1XOakfxrB5oRpqMhCU3OfAJ1Hc8rMJ988Dhcn7+UvmZ++5Ur1TxG7p3WYsDPUNZiyuKO3H6bPndj3+mvLD/1Tr0QdVwmqRXxYtw57plx21l267b/VR9wygPEmn96Rmi9/A8RFZCXBgdBoHCYwAaYtmfhiKgWo57HAUp1w8aQSBnA9PdS8yap2zdMFnOa4I/o14Q2KJnNTbsFizR/JjTPH3sTJm5tFh+/m17yobR3pN8semKrmcoa7CGV3b/8NOfL8+9rJ5EWtVub1fUQ4Sa8hQ+HK3/rj27y6SetvNkfYyVLTXzDKBQfp6FZC/hnkLZYlWK+Niv5YeIgg9FpqehlMhPHvwovXuHqu1QQs+GIS3L0Ab1wfNB9Q6Dc/NlWk/ytSss8ugaLnKA2lv6VfYBzVv+5rkD5efesqvc1pvkJ6Muu/cMZRVLfvDM3vInf/3lcuT4KSlrmEidsxuSN0JQTjsp3ICWcu+8++4yNjVeRscnY/mX1SqlkX/QQy8F5HKCLr2uhkCsepva8+BPg8IubBSC8HCMCBsPecKRbqe7TYZy1YtsVLnDet5yVr0LwzTAkmaZYNDmvFHeiZm58rcvvlp++u7by54tve36lb1dt56hVHaw+/eb2q/1x5//allg9y9DIaUxzkcdMQ2G/OgXSsn/kDYu7r733jKuI4Z4mDiu4ZZ7BgHRIzAfQYVlKxEvHLH1BDyhwKR7pUtp8tplr0Nh/gOffrywhQMsy+kQxXJ10Mv8p39Ae8pEw0XNQ/TGi14Co7wowP0T1goeaJOfjZff2HekfGB+ody/c8tqmzTsP+ZLz1Ak/XltCfn81x8pX3zocU90WZ4NNVKilA8XKqaAPX3aijJR7nvb27w1flRGMqGfFVyah0JiKHRI9AYoOdlsHIrs+DFC5i/RA4E8FNcQ4QeaoFyuZEV+QhWvcPr9FFsyy9MrZaif7S+LMvhBDcPmVUdt1gS5K0Q5Fa9vJrRckv9beq/lrOYtH9q9XQ81ge85OPCP3lBY2frdv/xieealVzRK0VKsOMKhDqGcoYi2ldQrBSYnJ8pb3/WuMj07XXZu26IHiXpGIoOwISgjhoHy6y0tGYuMjjTebEQ5MaCqe5pPMxCygZHH6ZlGmIJ1wxk3cfiJbPxgA1CDqwrLg1Aw+4m/Xilmsn9ey8KXVC9S2HKzrPxQAm1+DUx3cIL2hTPT5bzevPzonbeVTdpW03P/iA2F+cIRbUP5g89+pRw5ddZzi3hgqIEV2oLioH9S7PAoXuFx7fh929vf6iHZ7jt26k1ErRYBLjugR2G4hdFgIEzUw9S4yg8u/XcMJRRTYB5KoZA2GDwA2kGEQigxXmgTHueRX2/TK8rm5hyU6BwQKz9P7ae0Y3ls7JK26i+W2cWOQVEC6FjJY+5iLKBXzKl5vYi2/2T5yTu2ll2TI6pvDvyA/8fnbtnmYlhzCJ5MMw63wJGdhd7laSSKQgAJ/BCt/PJiObc0V/7tL3ykLEoJ2LdlTAJcASe4pGtW9eoH/9atW/VGonoQ8GgLfLhQTvIoOvDoit9EcRcu49SlqnJoJBBOc+lk6HKoezitjlmFQRWxFa2SoRc1d+Hyu2DFS7llMHQwmMKsDGVehsMwrQMDdoWF0g1ExU2s6VL+LWoceNSyqGc0vCqADbrT0j1LAgdURbgVyzs4ynBJefndqi4lfUvRv0OnjmzXS0kT2iBI652KY4GHNq5dnxz+IE4J/M4PvrutFjVPSD8GSCnwqhFoh6NQiZZTPMoTmqW7wgajm2k5wySqqlLceAuywQj9iQuPNRIkZBReogygKNcVYJxLDJ/j8QrSdQYGvPEzZFix4W1M4WuwUEathYuuyV030Jke0Y/xU79uAwxwFkouatfA8Zl5vVQ234XjVgnccobC3qbbxkfLBg15EKbnE43Qq0JciftIEod0lddeX7lkWo1I2Ex3si6+hwGkotA1WPlIc7rujsjMcQ+9DoDoVfJZjOJUXigZ2lc1ECQNHcCAh7gYbkUw41tlsfxVHcqOGqeLchVqwTgti6yAkaODJ/N7FTCjIYUE00ggE7qNhqHcFOePjQ2Xc3MLZf4W7FluQUMZLBMjQbZbPFpt5KOehY2CdimvCCleMCgG6bSwjUAToHX30+xWWN6OQWS8FHyVYmUK9xX3JFJPn6ACMasJSmgpfE1qWmLos2srHhEK22FQqJ5iqAeEtF0W1Y5W3Rv8FTa3tzRZyddC556i4jCN+GXASW93/QOQMla08T9oUpz4YFZXGifUyI3p1zOUhuvXz8NTbj+17moRkbAUjJbYioKQ7FGYuwRI1BXJyhRgIx/jdSsiuSuqBoNxtRFifAKsPZvhrRwdfFcsmhJF42pFvqoxXwHZmngEexnuVv5O3URHsgGaqF5TbyL40YeHIw0/LLdPGWx8TZjevoVQULBnsDuKzLeEi6bpliA1iBzUylIIRBwPKVXqLUkLMyJq2ILhcjUJtdNqPiNJP/eW6wq2YDTvYe4T2gTOLsAWguq1EV8e7ZirpV0hy2qDMJ+uAPumo9uslJ/5B/VME7KxKhRDvDZwlNglsjdNxI3PeMsNvYbzIZjP6l3FMLdgEhxpKRGGUhoCOCgd7nYpyHZCDmuIy/R2rhpvG6h+D/lUZuNCeWJZK/1NYsdTaVyt4AZI+jvQV/SlQWQP0NUzSJEzHgSZ1o5rI874hOukqR5KZIsMLsoUX/EzxGSYpb86WyO2lguPlGIemWkK33ouan2L0M0zhlEvycLwtZS4JQi8DurS9kdkq8Ykgmu1y7gmcwVox7f9q/MTJu/rc6nsrw+6GyqpIPZyBV8Vt5qktIxulDWUdY8eIzu56D3aiORXwcyd2rFZf/qX9K9ZzC0QeUsZCi8oTegZRofpbRWB2ylYvEpDfvVZAuPrSAcuXcaBZzUuwpmed/IlHHFtP2mrXTvf6rTu8Jq9SjfIFUNUDX1vGwnhtg2YHSIXipt4eXhKnw5vA0d0BY6zylg6iUWMjM98IDQWMuu/wVjjMRTvTGgWKpqct4znlhp6jWhJOJ4fI8HXcnT5LaW4KnjAdoOsFQfEGvE2wmxz1kjvRvyGQm+mp0mFp6Cr+bGKfH05iQIeF6tXflavUBzFxHyE015cXUmC4RbOq3tVJH1LsXDCoKxfhkF0zFcMesteUrrrvgJD2q/EgQrIp0oKzxunO6R8lXzgvBLeK8WD7mr5rlLctUiykl6Ntiwk5w0Z5h75OgaZ9RBS86qmt7PYr3jshF6kyyk+snTFdgJXTeyArTPfLdOjcB4W28djA5+4qNUlhisdAavlej0T4DVgwJG4OslYZLt3eC0Bd9JTd7J1vh4yT9yU5RbbEaG0Wf5l5QKj/04v4oCVvcM74oBhmKX6N3nIS0m66+cyXZB8bVsRPFmijDokaxHSBm1Fr3vvLWEoCHFIRoIAkJOfcSCytXoH4jra3gggjaGJaHk6StKK7DISxa+Jt21InbymsxNsfGvSW1PJ06VwijeelmYl3jZcwKC2DKOaoro8nfjOAMJDKywiVwqTjg6ICQoWCw4krB76ISpJLtG54nlTi9CKay1yLofqInXdBtpsWbdEsl2cI0clHkRrt5YQnCAjuZJCXimefFdLS7y+r3VZy2BXwb0mfuCvWKlVyFYHr2G+pDPvq4siTHGdIqtvFQ8yP41QuyEaWKMRW6uM9RZ3yxgKL1PxDsVqMbUZinD4tQWT6asFlvGX3avAU9CXpa8V0RL+6nwZdvnK22ndu/30EtSunb66KD+pAE66CfzqnqUd1/aDJ+nwKqC3mSB6SuTGEKvTOwIbdKigmgZb6E1W+oHTpL4+O2F4umwYoithwpsyAFen7FJGmn15FHzruHU/9KInGdbZVbzrgYAkAnO3irjhdFswTeQb8JDfQiVPVZTLR9hvAGEFTboiyHheytRyq4KtlPB2pbcMsiu+5mrHpT+VFJDwM0zrOOBWG5xTlWBIlB+e+44B1TBANWPIgnjMUCtlholsgIWT/BQ/of36PG2J9bBMW//3dd+jjOrLU5y0iDDmdJQpn3N7LZfKYcVPob1WptXp5EP219Kttu6r4b7WZXeVFYR0k1NDWS7PPLp4QIJ+mW585GFuxF0JutG4dIEYrkkuw9K4uZnpsLtMuwXu69pQxnRYw7iO/4H9B/Rhz//5//lYuaiTRSzDKzC3uwW/AtAa0WlcmcQc12qwltTRibXiM/Nr3Mm7On+7VXd2Cn89zkOm10mMYOklXL4XK6TU1NP0VBztcmsPFptTKjFsYQG0DsmaO4iU1q/tQ301LQZpgXdZn8XglTGE98XPf6Ec0jdcFtkXd4u4dWsoozrhZFKHW7Nt5VtPP1/+9z/+THlW52wt+iOhYrr5H1LtGAfhzviY+E7alSXSNpLUE4Z4FBFijrxWbiLQiSujU6JSRaDxulWOcHcLvQpBC6GVeY0SQqEzHxnqNnaiVE72oO17F6W2xqxh4mnfKxHQjKv3MKyIMr41UNCPxEtircRad9PjzaKC0f2MjoL62hNPlZP6jOXMpSW/OZnY1+t9Xc5RWOXi6J8hnSDyhUceL3/6xW+UM/o2YdELPwPaXIcYLUMbQpu1CKkK2TBqPWur2Ia6kr+BFXJjasncRqKMjlIRl/UAbaQdEtrk2N9C2bTmKFJTtvGAoA3ZRl79mVy3sreL7IKGcCfGECltJbNfBtt+fQHeVV40cJURa9IMUgsmimzmKiKAZ/w2GN2X9L3JY8eOl9Oz82VwaqLMaCg2oiZ7mNVNPQbwmctNgevDsy4NZYyPfA71l88+9Gj5fz/xn+LEEHYNp9A83FhL1N1dOcp3uUBfH+NXG0I7DF6UIJUzjWg15paONklt2PR3G4lA6w7dJlP1ZF18t+LJnHQ6n3WzTWAro1eqklUN34KXss4WpHBhJDWOlr87NUDhMPE6fUDX4LeHqR6SwZHKlWowimhc8otRwYUL53X862zZtnFDGdVB5hdPnyz9+oQFhsKPnRhDWsjhvh7c+qCixQm2qfDhz68++p3yJ5/9klqfRa94+a0+mG9BSlS6ozApmMuUreK8UnwW2VH3jLn63fgol6Ihg/tVHEplMl8DNuoSiLppzgLA1HbEp5G041f7K6FEy2t6uMC/BG34CkwTm6nd9wYB0Q7UYWYTugxHF0bhR6YLOphvXoddsDgzMqaviMlYZs6eLYsaivXpgLE40aavDGtUwUk3w3x4ySuf3eTcqND6MxQxZe8rh/U56q+W82fPiw+0XPpp3d7GgqGs0Xpma3slxmV6WyFXw14tLQ0iDcu61qUBq7F1wsA2WlmV8mpltdPoMexqnTPNdEBUnVxbZV1QgDfXJNxKzUQ8hpUOJpB52l2ZbmNNwFV3dy/0rtHPBG3deDr0Rl7Cyxp6LfTH3IQJ/bw+J87JNn16DHBpdlZylqEoXoddlsV+HbF06ZINZUzz1lF9Z2ataq6i7JoH15Wh0IrwwZ3/7y8+Uw5plSvaqJi49y9rCwsxPLCiNZTi1FfHG6akUIh4XYJucobHereGFBxvpMLbrQerMEQw7diwLcMIG5dSXWFotRay9lGoTTpDKBfCyF9+0exgG6+HWcrhB4M1p+JMvghh6AiPHIbG13BAUIYfNJJLuEDNEO21VoQSe8qHz07M6SDxRX38iB3JXsWU7Ef0XZkZvk0pQ0IMHAmF1PlgE8ckXVrQB5MWdfoOXy7zTo3XIPoaJq8rQ2E8+vATT5bvP/2CBclbcZyxayeG0vVKxFaMa8iD14cKyb2mQ4ECqLPxsJPJivK68HTydHypbp2YtX0UwGpYzDFq/6G4JKz7Dk1XI8npWHjL0Zs5RgqPPJpwhYFS0tsUp5Fgk/gvqZfg53PCBLskXMN6Zoa85/QIgEaTTQBseRlUAzAgKyVuWj3Osr49M6mTeFj0uVHuxpX0OmrEB0I//hd/Xfr4/JvgVxh1WRQyELUuTS/hE1cEAdctsQ5ywxC/yjV5a/xaPQMtZjverfQqPBmkVTx37ow/enpWQ8RFhTfp+/G79H2UTTq023uaVtFmYq+GNJGvunfO5spGQ3cTSs8SwEzEl5YWysnTp8vho4fLSY33KW/7tu3lrjvuKJs0B8jDL5xDyhdZL+dVGkfeA76+5uueSi28e6UoGww8aw+hRRzXNI6MIZx/SzKSBeYo6lX46BJ1hKIJ0Xn23DkduKdDCiXz+IKYsMvfP0B9+8vMsoxF8Bt0AuaNmuyvG0OBKc++tL8cOXpaXbE+sebeI3hPg+ZhAorXat2s2CkFJzEkk5EJJu8kp8CsWy3ltYqAu+pKpNeAkGe8y6nR4JudnSlPP/1c+aQWG7717Es6q+qSRKzXlPXcZ/fO7eXX/8XPlX/zS/+sjOlYJduFaUIZyN0igGCXEwCFtodQTleeVvl+yGfE4CJBRnvhXHnw4UfKp7/8jfL8wUM6mFsDfB3UPTGuc5Lv2lP++//iV8rPfviBurlUOTIr+B3QPSssr1TS8dGDQ1ecpp9Lvl71o0JRKaDtYgVM+Wt8Ww4Jo0yatC+WRQ2xaHDoVaDhkn5D6lVkN2VZk3x6kGV1K4wkBoSYH2iHNBSb052q21iaEzs7JVxr37oxFD4C+pVvfFPjUG1RkRCRY14jTEzEOkkX5NuSrQ0ijQSYNJCEf313JIDrLiviilrBS+Whbz5a/v3vfKx8/8DJsqilTM4ZHhzWifb9k+Xc6fny0l8/WPaemi7/y7/79TKu45Us3USX6BPh674ngu4MtNBnz54pf/jJz5b/6w8/VS5o4rDCdx+1cjiqb7ZM942WM6dmy/d+96/K/6aDuv/NP/1J0Ssc0AFK09N4GuTg9bDK6YQEarBoiAy4ykgyc0BTbWfO6M6d3k8fOrrEJym0ArakhpFNr0t6TsZ7MHze7/jRY1oexlB0xJHqsyJ/fK5cZPtRgbbCBPFlw+T171nWhaHQfR7Wgdl79eSdLtytGGwVo9XhwhkPvXRRehWUe5ZuQdhoEI4EmgbUNqbVfviccC7O+dCiUIpMyzuCf+qHz5Tf/JNPlx8cPFaWB0f18aCJsmn79rJ5x46y9bbtZWLTRh/4rQ/alS/+4OXya++/r4wKr4dPECbXNmZH1Eu21t21ikRosKISlEdtKx71brPly199qPzBp75Yzmms2j+iXmTTNtGzq2zSp/I2bd5cJjduLKP6TMW3Tlwqbz9yurz/jm2iLuYwWbcoRS15kKitKBnTuivOtLtk+buTwjBqvraRpJ+8OJYUMBAm9Au6z2uSvsxQS/Jd0tBufGKDhrKHtTp2qSypAV0SMYt+piKqhX+FYaOMhWFZmZ9DLdSzTDS9ZYusa+ZdF4YyrK7ziR8+V07qVHlcMLRyHDuBwcxRlLa6kUIIpDjNF8HDzOpHn3LHbnuC3VaQhG3HhV+ZG8TabjE9Xb7wlb8tTzz3sgU4rjnJjrvvKTvuvNPfk9+4aUpj7Al/K4WHpseF+Nj0pbJnUkuaHk6h3rVermn7opSqSBnb1IMI6Kh5o7YRPnTocPns1x4uR8/NaqQ1WDbKQHbce1/ZevsdZYs+lbdZNNLijo6N+vnUvunFcr9I0CePhC3nFR5ombmuN3RAZi0TL1wO1/HVCBtI1gooZxWONBDLqFW3Fc+nNDfheYqWhhcW6hBLMP6ejLq8Ue3MOK+eckif21vU3GRQvc7yyqCHanXyWknU4eMyOLY6TU1OVt1Jyq7d/aYbCuNQFgMf++53owtGIGkNKRvVl54FXmer1GZBCyyE25JaKFuNsEW0c7b8IMl8GR3WolAo+JFDh8rf6EHovJR+dGpT2f3Wt5Sdd92tr/9uLxjJVDWSCRnJuM7ZneDzcAsrZbfmCpyeHz3G6kJqYY1VdNUmKQnSkh5PBESTFO6Z518qT+urxQuicWLLtrLzrW8vt+/ZUzZv2VS2qCfhkw8bZCQczMFO7AU1v/NadB3X2J+lXaihdun8RN5jM3pW4tum3WFSx5c54+4cVX5pICmzaNRAKRPVJH5BH3BalAF4Qu95Ch9A4luUAzLs8XLqxEmvcA3ogcqStud7hUzPWmI9mfIwrBhhsKzMFpgxzROvh7vphsJ6+OETp8tLmsjj3Fpm65Pyk1TiYaNBAk5pzVCl6lbqUQcqfPn66ur4DF8pX3tSzQLDq4ePlFdOndPwZrTcppWk22UkDLc2ari1QUYype5/Qh8VGpdijut50Jgeoq1orqCPxEmgmnuJZmy1kpvFx53hBL0jiV5ZQn3FjcoD52PALufXcAXHKuEB9Sgnzl8sw/p+5G333FO237GrbHVPsqFs1sdL2ViK4Y4N6+k3xqJeh4bJwxaGtQzBKr8pv3GigRC/PpQ4HUYkuIRda9JOFZwv5Vjzut4ybv8Jx4KGXJd0yv3QoFbUhJYeXwMHZRbHWPrVsGtWQ6tBRQ4uim7ByVpUtg5ohwYjZDgOTX1aOpaxiOfX4xnLzTcUtSA/euElfXKar1YNmkH9miAPiEkDg9rzpYr3S8jDmiyzlSG+sJtS6wxCMqZ9TyVrx13mByg4fllSO4KWVl/60AHTi2VMirht186yadMmLwlvmtqgdf0xfYJaXwTWdoxxtmSIbgxlhC9WdTSnUfw27vBHy2j/anqsEFa9rmyaEqtF1hcalTS5fVvZulOf756aKps11No8OVamZCTj9G4axrAbe0TKN8wLIcYnVEmXvKn4WGqUFIkJ2i6Y9Ku5SG8hF3DiDzNRWH/MLXioOKLG0p2YMnJkLtteR8TPLVs2lldeuaBvUGqlS73KMsOvZZ3GgyyW+ZoBiPnsN+MNTe610MIzmAk1WNfa3XRDYej1nnfdX/6H/+7faaPcrFrHC+XczAWvJA0MjGg1ScMW7f/iK7ej+rE6hnlYDLq0jSH1i7h2fDKN9Ha85y6KaM9d2jjafpq6LVu3lK3qPRY3bi5Tm6MX2aDP1PHwC4UcG2eLRRgJw5yxYb7hMujhQXQVIszSTYpad+hww03N+IULGpSmjDmHiTrwAHagbBYdYzKMDfQiWi3arJ5to+hxL0KvJjpGxcNhfXaB/VIT2mw6KsXsW9G36LOQ1r1dhqnQpQ1nhW/3PK28HW/WoZPTvVbNt6j7tj23l5/94APlJ95xb9ko+dIvUP1FZZ3RnGPfq4fLi3tfUiOw7M2Ry0t6FVwGQi+6rB4nejJ6IOmC8vgua8leZUh1vZbu5huKajmlsTTGMstyIQ+f1PKd0/fPT585V06dO6vxN99PH9H4VZwQ7z0uFRc4jK2tVLHnKNjTpeSVYyhYO94GUiMsUqELJYwMbT+CuEO9yE+//93l8RNzZZJhloxkQr0H+4/ck0gp+QrXiAxkhJa8f7hsVO/Yt3JJCFUvKQgmnq1rJStunuynVyojuqAvaIh6csXFKTQQ21/e8ZZ7y55dt5V5Paib0AeWJmQkYxr6jbpHi+EWiyVjMhaUZ9OIDEZZmd9EGbolD0Qfk2mXIQUNT+dmMCmqqRE/ctgVEBWuGoOwtqPDj0brt6gHyVMasu7euaPsVsMzOzNTXta2+4Na+TwqmZ8+d1FwA+WCtuGLXDUgMiIxAiMZ1G9FvYpiVX0eRKscNWI8h+N5Cx+uRY/+wRkKjEMkfL6Mp73xYpY+X6034qY2jJSNUzvLjCp/UatHPKSa0xduN2jcz2aWbreGYNaI6s7z+kPMkTZt2lL+q1/7xXLkcw/ZELLVZu/RuHoSxsf0KN7tqgHEVjVqY+zDsFKqrKvSo0QUCZirwlWaBauRe3n7ffeVf/kzHynfOHjaNDDcG1MLzQZCVt4YAtKjsHV9TN9c2D6mXbjqTbShSgaCunUKxJdc7fjxXe7axo4/w/Qc6ScX/pwDEWb+cPvuPeUd732v5x9/+dh3yxkZx4IePi4uRo/RN6B5nYa4TPgVrUz6aRPlwJIm9HrWwjAYQqHVMxTJBvP2g0ktG8/LUJbrV5oVfU3cTe9RqAUf5ERotFB8T9GrG7rTGS8y2RNzt2zaoO+/z5dpfQd9u1aUGomaDQiToYkDboXbvQGxSlWebKEDzioAw0kKoEhY86qv7A4MlQ+85z3lv9Zj4W8dPau9SUNSRrXg6lFGNY/CWDiob1TDwx1qCrePskdpiQaPOXMU4kIvL8BDK6JNI+IXzbU+jl4jHwo4NbWx/De/9ktl5eFvl6NSmFjdGvJiAj0dw60hDbvGNOTaJb5tkcT70T4YLgdZ9NAEKQ8+UazLVmQYEs2S/AoD3+UqnjSGtpEA53jRSY/MRGRWS7w//69+tcwOjJaDR/QsCp3X3JT0gT7GDkEaT+zp9VgVc+8nS1hS/XjpiweUxi3zYOjeL/1g7spy87J4f0lLzksyMtKulbvphhLiqqseqhVVW8BI4KASeeqN1FhEHh4fLgfOzJStaik36lcH9ZUXEmYOF9bgDu2vpdBKQyFWx7WS7U3BhyKwVj9VfvWnPlTuPnKmfP+YjEVK6GGW6KElx0i2jw7JUDQh1TTUiqa65NJw4rusHOjzTzcUFMVS/Wkuwi/FIc5EAxKc443Pu3btKv/jr/3z8viBo2X/+QX3IPQmLJeOqifZLIO5fWK4bBIrB5bmxVsMJcqxR8M+6PSVYoWbEQ3lMdCy3+BkCiOWR3BVYU0rJtZxwS9wiGQpLHv1zi8Pl0e0SndmQXjV6MXQEksxMYbrV9k8oefH/GRZyr/kdO0F8/BKU33oU5nsBxtQLzmg+cuQfiPaYR6NrAwa/bmG7qYbChWOzW9ogJiNAuhH74Kf8TMNA7IA9lWNW/uPnSsf3KknzqOQf20Z0vAWOii05Sx8RU1qLvLhu28v77v3rnJoeqHM6bkGL5xNSDE3qLMblWbRk1APf6ulKlQLletm422KaDxtMBuJeULsGiCkoYSbNV/6l+++r1zQ0/kj+qDogtgyLjo3qReZlDINqoXt05NuaZ7xo3vdnDM1ogvTrEU1HkXgv4Jr6FN6GkiCeve3FHqmb7g8vO/Vsu/EWSlxlbOATL91QAaoutAwsgeMhtI9ioZRNJN8ilwK0OwYZpi1MLCghR69mqGh+ZJ4HxN95RMeWH8t3U03FCqD/DEMnqOJRdEqwCjFWVcVzygUISimHJGxfPfIyfLe7Vqe1TfQVzu3Yi1GEbaTgFKQLK0igLb2rc5Xc11+Ex3gGdY86t5JTURqGNUT9WEclEVO6sAzEqtlhyjyI3vHC7D9rIfPd0c+3VgKMyzYwC0lUC+SzjQrAC4gpjQn2jA1KhjxyxXXXIT9cxirWml59AcmDEMcqCRxMy6KI52LjCbScwjDHRyv7YyLFk77tE6rB3no5f3l0KkLoLRc3eKLRzjzAnqphHphK7rSgLmkI6psKBQtvnjYpTSerSyotxxUT7LEUnE1LGPUxVUH+TVyN91QYArvIlitqB0MUhzOgkRJYJXurLHDVFT80OxiuXToZHnfro1l+4ZJw5s5ymoFFCrznZTEp7yUFw6A6gVEvwa+hjMfUJ18ACK6aLX6UWSjxEhASU3w6ddIK1IUGfHh0ZUhmYgg2UagmxU8okgKZRdG00qEPWQIelth0+hXFDCDisN4GVYpbCTQToOEow4q3IZJUOHKBA+LGixKo2jS5WkVCZLLHbCSVb9W/Y5qF/O3DhyWkVyMibjyd/FSuZHpAA84lS/pYtiF8i+qt6CZJI2RB3MUdU4acmn1bpghGgaF2rR5fDlJP27MTTcUV0CM4i+WLJFJGEa8gyII0mmdrFAIS161jsfEoO8e1jDs9j49aBsPZoJQAF3G4nxEVw8wlOegRO/ylR4RDhukXkjPNEcJDhophKEKK2KeU1X4SqFCgjJO4FHPNg0Uzk94/FNlfNctHXSFhbhuGQ0tajIy2H3PKppGlZCG7DrWesgfZUfWyCIalYdlWBz4KSfr4izO5pq73pE7rsCajwC6J+kvZzVneFjba46dveDeAeUHs7kA7voDQ+TFF47VLWycQw9t4DISHk6yvYVGc2hxKIZoggNPiPYKPEmkP8b9phtKMEs80Rg6hl8hKBiH44bPQwAF+HO3rUjyHleL88TRU+XD4uo2PXizUpNHaKrMjWetC3hdAHeYfTVnZAgkerUOKPlQgMjfXabiUQYDR1uJtwuGcmtdo8EHGspMXZeBkBdkVmL8ARKKomAOo0hioQP+ZFmhTEGJ42m7MXAp3wrLxSDT/IDV7HA0AMRSSNC0LAJZIXNtlVdCM6hlJTxex5WRrGhB4/illfLQiy+Wo2dnYIFkhmEkrjAS8sWzMKXLD2YeJnqnNaxTnnk9DnBjpFqzirWopW56wKHFYeuBGyheYKGQdKY7A9fmfvMNpQoBqcAqsVleGBpMDR+qESIjHIqSCtivMXAp3z50trzntsWye/OUW5y12GMjajHU4le4YbEj4DmeGsDnMCWHs6JBr0CAQkid1BYMSRHsvjpjo5EB5eIqHoYdqiWKHI5ElF6lQIt5hTewpzFU4BofaWFp5CGVMpPSvMNvcd3gFa7i7cBWXMqddYeeePAJXvpL8UOKvKwl9Ff1zOuRl18tx85MS/GdKWBUZA6ryZX05x1mYRwYFRNzb5jUeyvZa2MooFtSr+KGVTBRd2JVPlXyRfdr7G6+ocAcCSbUVepBRf2PkjCZjDBxxIQRKUXMTMVnRH5Krcp3jmlfkHTh7q0bNOZNJevkaQTSYiIsTqciLAiHGysgNl3HDy7Kz5jXwt1gsExp7bXsKWJ5n+S8tu1cvDijYcYlj1p4cDmuXb8sRU/oPqgn61F73VIRKD+RXvUuqGpJoXCEMXKMQ8wyEqm5YSAuf4kUgA6XTD5JrfIxtD4pLz3JQa0CPrL3YDmhp+uYJXxh9xZkh5EQS3lGASY74JCpjUTDKYZpPnyCFTDKF33MRZihLmtuQhR5gu8YSfzQHz9bkVFdS3fTDcVyMkul7q6culgzRQ+MZCQMDWw8qrV3l4tDnuiZU8EKC1zhi3py+6SWjvs0frhr60aJQwKpMoahNqwQn7jcYaRhdFnR2KVZfVJh7ecWazE9hFRTmAvgVuMlSpWkt1zhSbOWaE+cOl5+9OyL5dHv/LA8/oNnysuHjpazFy6WOa3pgoWx+Jh2IW/VuyRv0Z6oX/jJD5Wf+YkPlnv23KltM5NSBJ4t1YpRpmhH8aJslApFon4oEiteAIXDCyifauAO1JKHXvK34Jbdy0CNXsU1pLxyrosyirMO2+BED7ukD88vlm/o1eizM3oybt4HT1a0OqgFc5UTZXpYCFEwvpbJsUUs6jCawyAYXmM07NSQwMMQ9HQeHSAtee8N1XpnhYVAG7sNpaMzJvIaXG66oUiUqgZqhKsMseBpIRzZudQWJJmUyh8AAhaSi5LkdzTB5znCPdowOKT3GGJCXCXi4ipi+yv6mqy+H45Dkn6Zp8ID2vLWnHFDg1Y75gnEqYWcvnihPL93b3n4se+Vr+v3lIYmZ+fUq6D0Km9gWEPGMT6YpKfU+i2ohT6qhuPY4Yvlsb96sEx+8ZHyzrt3l1/48PvKR9/zzvKOu3Z5x7JakTVIgpas0Cqi4GGNwkduU56RTlOMwlEjrlU+8hrasJHKK7qXRO++s9Plmy/uLxdm5qXJtXSV5V5E1khP0PRgSgd5NFz0FDIA/6BIf+Sz0UT8ikYLNJYY5ZKMRcn+QSr0+GUv0mXcwHEU77Xean/TDYXKUnEvR1ZlY/UlRJMtAwYUMGaOAm0jcX7FucXSfVqrLd85ck77wpbL23ds0vbydpsoRC4PTHISiJ3yuVPwRYISmPscklu9hHsZRaUNRWauypAuKmSgRa3a7NMzhM9/6cHypb9/vDx/+GSZ1rYcNn4WbZ7k4LcRvaQ0pp6CwymGtQN5WNth+vQAs09DLnpZMDMRPqqW9E8ff7Z87dlXywfuvb385z/x7vKu++7Sw07B1WqYDvyuBwRR3yaRqgsW/oYLY6kB31xrw5A3lBk20YDQL7AJHicMoo1nGc+evFie2H+wnNODTuQILPJj0GVYlx8yJGeUGTLMniNwiu8Mu9ybqGsRHq9+sQRsglW+npm47EobhsEwu19dCqukcAtDge5r6daFoVBxKqh6qtJqgGklq3BRcRogq621AZYiTO7htzArPJNBWKTRfvnhyWnNWfrKA7s2iXkVXLe2Y2gXaEMRPLYQgEVswxW2RunkjTOUjIJPGaSBL3vcItWAJAmJ28zF8+Xhb36r/Ic/+svyvRdfVcsrrJTHHiwZx6Tekpys77SP6fC3IbadyHAGpPi8uNQnJWz2KwkhrTPHkS5KmZ44NVMe/8xD5VceeGv5tz//wbJJu4bdmpiyuLSXrDMa3uBQPNNubkVcxnNHHgwE/ZKYynY+NRgMdVQDKaUm1DLmZ06eL9/ad7BcnJm1PSIG6h4rXOKPMjpOee2v0qSh43A/7s6hGwbCZkhviNTchBMlVzSPIx4+WBOGZIQSWPxEh40kepJ8jZhnLNfa3XRDQQD8oh3TXdzkPQtzW/F0u03rANOlz7RICZBG4h5GmNT2hGCkTHNSyu8fPy1GL5UHbt+izYHKhpC5yYHlckeqSkiJK4SAO065yNgdKaVTHsOhAIvllM7X+vPP/U35vb/4Yjl48pzeLxKrNZwaHtW7I1u3lim9Pjyl91smNWEf007XYW2o5N0btof3y0j8AhNGRUvZ4FXtGJKoLFaF5rQi9KCOdzr5tcfKf/vT7y97hE9ZzIMrVK5TDfvaHIhKcm3HErgsTvVYUKv9o+Pnyt/vPaBdwPOiS3BSfIyrkZdwQW+ERbNkQl1o+cGLAeBcJ/nZuuJtKEZG3ZUmgWPwQHp1zjnCD15QyYbc88YkHjb/AzQUVVH/jOXFUNXak3eMQUxg1SP6GoWlHHToKIk/VCM/jMNFq2RMCgGjlgl8EsaStPepoxe0Hr9c3rd7k/Y/ZdftnDaq5hT30HTjsAEiTf9EY+PQCIWV1N8MyVSW0l2eWsQD+w+U//iJz5RP/u0j5eys1q410eVc3cktW8vm23Rai05s2bBlsw6imPQ73iM6/8s9CQai5VXe7rTwVY7rSOtAgfzbUGLiy6sJU3qd9hVtMPyTJ14s/+UH317eun1KeSqseRW0J4+yGsIsZHBdsHJRX7XaKity4I+e0cNNsRr20JPMie8/1KbQ7+w/qpesmGwLgRKRoiDMU0XY3wmHkdAkovgqWr9q9IJliz1y85/qWMkLWOCFLeyLniV62gENP3zsqphFw+JNk6KNfWDX2t30HiUZiu41Tq2oDYdICd1Clp+7o6qBOK3qEHnNToTvFklhtWCoMMfT/ej0Be1KXiofunNrmZCxkA12olNxqSpTjSUUCaIkTAHGECthdccxJKvwBJdlJK8cfLX81sc+KSN5rFxURt6tGBwZ0+ko28vWO+K0lim9rDTlF60mdLRRvOzFdyrZKk5vOqD9UabJxAkvNFIT3Wl9mYtxhx8TS6M6qmdBh1gslr/60SvlN959p4xFp5GgaZWpzg6KGsbbdjROQiX8qCku6h2ygYO00MLIVna9QPfkqyfLkweOyUg4ElUZXQANWS2Jm2WlPI3c4DY0C6qCAe8eRA1i9CTCIQJsMDYmwilP6u9ayVg1xBXNrP71i1fRkxCWsYhG7tfarQNDySpZbR0IPgc3wziCQWg2jGdyjVjgOEzXVXeYqlaLMH7SEGId1PEM+TkdSscB0B+9d4eHOOSr4ksidEdJcKkseW/HGSAuKpDykPCF8+fKxz/z5fIXf/e4jEQ0S2BDkxtkILvLtt27yha9175RrxFv5AghvSEZW+H7ylYNu7ZNjJWtekORHg/VnNeE//SluXJCb/8t6o0+2nm2tUfdtHDBKpHKTUVbUHhucaX8zcvH/WryHcxZvNIU/DH18KRNuiOjAepEh5KZC7pgJO5R1MthJI8dOFG+t/+Iz+Mij+tesSZuYeygky+NJSJJo0wMJmRmHCqL+iDDuMNX2MomSdaMMQrJS/LnuFpw0tvSsITBMAxTz6IGZ0DGcq3dOjCUqDQVQ8n5xeSZgPx1eAMzBQlYMM7M7jAcowCm8yPN0M5jw1HEM9pSMb/3aPnwni1li5VpbaZaeM4JOSbKuLFT9MD02E+aThTRMatf/rtvlj//6t+XcxrmaUZehnXQw7a77iq36dyvLdu26eWzzTqXeGPZIuPZvWWi3Lttsty3bVPZpq3wA1KcPimEDd0YhVxKoIFNOT49Uw6emylHL86VCzr+iKOJmHdRZ3qX7GEWNHyZ0WT/sSNny6/ct1tnd8FC6KuNinxtRwpMCq5mimDlmBs5RcrHsPH8Ul95Yt8R9SRHrczutaPq7lTNdym5Mpo/4HSjpnvwCnkgn1idxC+LMCxo6EXaTpAKKg+GA1qolC6wWNKvF70Yag3RqwzpxxBM9GIfQ6xwWkhtbD++fx0YiiphJokD5q7CTOCpmyqcDCNoXsFgOfNZHIThtEJmfI1vRA9vMSDd6eZxPD7be36uzL98svzEnVvKzg1xDlSVb5QLHmksXb18BOIOPqNRGlHEKoIXoZ59cW/52Ge/XA5wiJ8m5MOapG+/5+6yc89dZdttt+nghy06KHtjuUPPdj5y923lrVt1vNGgjAP65mdcN6O0pUjiGI6UdFjKsFtvSt4+tqmc1wO9ly/MlH3n58scr8WKFrZ5uFcRHRz7M6CW99WZufKCto+8T4a4rIO7o/EJRTXRV71Ew0WVvTStoSNnkz2mHcDPa+GAtwgrE6LuotO8Rw76UYdOgxY8N49MRBiEw/CNH38yBPxuzJRfXv8I44njkpivClAGYrp057QeXt7yC1x1yHU9ehPYtS4MJbpRBIN0gs3ZKsQyYDAOgonP3sHMrUaSzEdM8DdgQoiIy2NpD7RogVfKQb0JOL//ePmnd28v26fGJC6GcyFoysGPs/LaF2H3cIqUWK0Qas98qv0XHny0PP7syzISfaBVx6xuuedunyK5XRP3bepJNshw7taq1D+//85yh85YHVzUgzk9FXU9UQZKsvXhy7KkGF7HFbyGUZu0vfw9m8fKZj1E/eGZWT0vUkvKwXDKz1BMQ30pFeFB7VA4Wd62bUovkSmshLX7TVdM/FL5afmUTi9C86xekR3AX1MjcFDLwPRYzPtsy/BAT/QzLxR386oTohR6jFbNXDCNl+VGY6FfDLvoQfBjOJRHGs/55aBTdHH2MHMRhl28Js7czvMT9ypXq6mLfVOX64P1DZBiBttAlEnMoYWNSoutYozHo0pCkDm8ooVPfzBaPEShmLsIYfYw+O00bGDp0q23BYAQlsqhiwvlKy8eLUfOTVvRKrRuMXcJUesaTbLxB0wipiy18nrY9qVvfltv2WlpVw8Lt+g4U05r3K6zf7dppWujnpfs0ZaaX3ngbr23LuVe4q09xts8JZLQraSIgjrovyGcKEEqzA8yBqXEu8eHyluYgmg7DHUlXiN1KYxeJpPh8Hoy747v1Seq3QI3RhDUr74yzHLZws34hZ0BGMnJ+ZXyhSdfKC8fP++D6ljehUCpr/iHkcChqkKVRl7lhR43aFQHELvoAW0MojnvbFthhVJRlmlM3mECFHXqjrzBKzPxMCt6EfHOJCvO8bqL/uvhrg/WN0Bp8NHqolyVq/AJRlUB5510GJkHDDQGIa6mMtmAHA6hgifOgaq9iyRiWJWmpHJS28G/9sKRsu+kjkVSyytMpj6ueGvYQwyWBGjhFIex6jY/P1ueVot7QFv9OUV+dPOmslV7srZt36Fzf9WT6EHinu1byr96771l25A+ZUBPwlhDdfEkWXX0EjAGoVhQtx20th1QtKD3bhovO5dmdFL9aR/8RuvMZJYjSYdpaTX8O6rT65f18pQbmTYS+ZNfEa0yYL2HNZqbyFCOaHPjg88fKIf5HrwMBL7jGnIIWlzBMYKBU3fF21957flHkxEs4Yhyz2HDYXEiZFZTjT9wYpgCFo/ciIpOltDzC8J+Mu84epZr/wwFem66ocBgOBKtE7wIY4kbSkSYFkdDJgmMh1JslGuMBAYGEgsHhrpV0t1Gg7DyD1icbmY8WaUAZ/Wq6qMHTpWXpOzgTiWK13CV2/nIq5+ataSN4Lxa9f2HjpRLDEnUo2zSWVVbNCfZqLPKJnUqOyc3/tRbbi/bdND0gHC7diDwD2KIYfTNnxxNZMtZdaLAVqzey1ev8b5dW8vo9Nly4vQpGwsKiiLxchMtq6rl74g0PUYLA3xNXke9GNKoXVYdTswtl4dkJAd0fKxbexoJ5WUIFLwBkZCLLyYN/lTeumOXH7jsNZyXOOVPF/gEI9whS3B30oFzWZRJPuWHXg+5XD/mJjw/US8i43C99RzqejxDgZZuqRBzgx1qkgxBec1g3RFE6gf80xDcE8nGQCQRD7dUBRq7nNAGs8kfDnzRZQsjnjUc4vF73a+cLc9rbM8xpaKkgURNMhTKQg5+KltC9OfSROzohimdIq9lYPUqE1rundSWlHfevrXsmZAAZSRq7zzMQuA5JHHdRSM7pVnRYXjonbu18h7KVGVx2VVp4M9GLTH/5J7tZfbECX1IiN3H6q2gSnl9oqYUaImlVeYc5ifcrvw2jxVguCW4bd8FoAAAQABJREFUPoZbejB6VA9IP/fkM2X/6YudngQGA2+a4ETIiTtx1AFnRa5+eEaYiTcuYSKgOOQnWBo/jhaiWuKAZSWPXNCKcHOUELs2WP6NeQmNAc9RfGfYyZ430+hSrullfUzmky9iHH9RWVokGQC9CMwkIJcMD4MQMyUj4iI+BGYmKw4l7srjUF46AgaenNM6wvDBfWf0GYGF8g611hN6voG8wI2iNc7CIKwjlKRc2/SUnbOlNug5yZZtt+lhIr3JeLldZ5Hdv03fURccCxXGkSQqt9BWrEQGfifr4nsTK091nfiAv2vntnL/kVPlqZOn/AxheCMPLnnCr6NTNV+hd+HZEY7ycKlMocgaqgie75Ac0NL5Q8/tK6e0uTEbgQ6/4bF6zVRE06g4VhBWOcujxmW6eVjzImM/B5JcIcp0tNhLVuAx72w8PXdVfowCQ2ERA57bL95iRJzSeb3cTe9RomJIEKVGGDUGQUgwWvSI3kJKbwEIgHs6C0ABZJDp8LwN08CK9ZTB+lbHVXzgVOuLinxbzyG+d/B4Oe+NfgGLcJtc0AC9KmhET90/+qEPlLft3qF9WxM6ASUeJu7YOFk+otZ+17haP8G7M2vRHeWDMepFmBA9DfSvJRgPa5TIMJVawDHOOP6Zd95b7t+sr2tdnNbhbxreiRnsC7x9XHMmCvZDu+CvsoTDcOlJNFzhXZK9Wk5+6IX95dhFfR+RVpz5WqfCmavhMUSSnjwHAL8Vu0JnWsrC6ZJjzEuCo1mEHyoydBCOeLCKATLRj6EZnRq9EwbiuYkMm82PYSgc/Deo5fHrZyjXD3Nl1mvdgl1wnRY+mB0MlgJlt2vmZU+DGvELh2KlILK1SzwNjOARiPcxSYlIRwgRCwW0XChSKO2MVs++f1JvHF46Xn5ST/E5X7j2B2QMF0jU9Q+U97/7neW3/tf/qXz5+y+VeZ3A/va7dpR/cu8er3AN6sC5Po0beSf8Mof0cauSaCDyNBQgKpTwGNppjlM+hmvbtB3mVx94R3np/KxOp9F5vXpnY7dO2L9HR9IOyHAgFd7AJ4ryJx8YEmllCyN5/vTZ8vVn9ums34UwEpDX+pEhvC4xCHAyCh0EJW7LQeW4jMzf5BB3FQeWePekNhDEGVaW7T1/pJMpOI4O0JsgKwwlepHoKYe0WsdKH/MWTuhknnK93E03FNgBM6ym4lCH6cnYYGQage8YVUjDTGaIxYoPKgXTrRBVMR2u3EtddRkwH6EKT9U/sttxm1dX9vS5uTK793D56F3b9TR9woJIJTCoBazXSrQk/N53vr088K4HvLzqh5VIm8m7fuHI2e0YLqA8l6cIO/+XJ3QjUAgQ8LB/7b23j5X3qaWN51HCq7JXMBQmeFQUpzvKtqLfkgzlGe2u/spTL+gZifinMmntG0bgcziixFmHjR+w6kLRI3AlP6mWRZVPhImLfJ1wlJGxfrolg7SMPHHHSBh+xc8LFzIQ5ifX011f7K+Xcg0PWGGiZYhWyuwRc2h1OsYT6EKQZpyEztNzFKURQgpWwEAyXMkXlfztP2KrzjhdFwsXASohFEXYBbOsnuXFC1J27Z963x1by45Nkx7z1+xN7cAjDZJi6nuCGDERcQkaQFY1Ig2eMhlWuKFQnny3BeuIj/yImprH6EFRC2Y01fhJtBoJ07J2KvN8QwpFwbTcHvIJgmbEy9CkyZgW9BWwpw6fKo/u3a+d1VRXdca4axnmCajtRJPLUMAGB68sAfPODQ9J+gUvfLU/4ypa2JRAwgBcwsZQi3IZVDI/MfEsRgiG/PQYQ+pBMJQwFhYhBKn46/3N+ZtuKA3LURDxjPG3lwxpRSS4FFgqmMe3lb8Iy4JQRg/TuIME1joBD3HJakpzoCoEIZVjfLpgeDa6mlnlL0rT9s4sl/lXT5T3ayl4t75DEvuJXExziXKFj9UcxwaOEHED1tDnGOpshUAnOv4c0rgSNCJAUSFQpnMhSonCFEvZNdAoo6Kt2PBDCsVP4/hFfaT1CX1/5Dt79Zltvd9u/lR8lEl56eC3dNN0mw6pcJSZwxzBdsBVRit34nJ+4QUUS2nXA37LoE07ABirAAxneOGLAm0o/eoFeSCaQzCWhjmxn57lerqbbihUDmGYieIR99iOwWRSCpKClj8ZJhADxtAljCnTSMIZBpGTz+1pxCZOYoECv1UDgVE4sbrR2rlV05337w/OaHeuPq3wEdF6h95KZPLIVu+2c27KqzS309b0d8EJV4MOTFClK3F4ICppJHw1tyodPkmz1PLywpUOyj54uDzyzEt1ewjAlJ31X5WZ+rgsrvoBigE4HjOHQEdX/qnpURp81YzCfDTt5ElDbnJQLQyjulpEAyYcnCVGfuNT74GBxKqeJvLqSVQrH0Z+PecnUJfNQpJ6c+5iEIpp5iMA/UIonR4lCUMsTGDJsaTVHC8BO8xibQiJVMMoHj5zsAFDi44hIBy6dIzUJbXSiFfXbxIqTZIcOY5rHP+4nrW8rHH9NN/gcOsHligHA4lhUyhPsDf9AXf5FcwMMmlVRWOjJW3lq/jNl8Bg/amo23zLOroBED2yDu8YYIgyrcnvI9rc+PjzL7v6wHIypKuqcpuyiZBTbTSspe40WoRptSutTLwVR26Gzb4rtWY1PyOfUsTSMAj5KZMeRJFJawx3qSP0gETy8pwTfERITVUXHohyen0/J9h7+NV50Cig6+rWRY/CJkWYDlu8TOgq0wLJIz6ZkZYKLYxggPTFWcjluIpEooyWzrGCC9xGGhnw0sLxV8t12dVoSPP4WGCIiR9KpLe5y3GFvnvstJ7EL5b7btvkNxSjNUtIAQc1NSfhbpcK4tYY44IIypSDHA+zHCIi4oMIIpPm8Icxpl95MQ4Dc5OC0ZNouDWj+2P7jpXval8a77oAE3WHz2YCSExA0AdNERVXAhgH5eOnnPDbZ9iKs/KWAgIeaMmOcvTPHTni8Ac+o3PLbX7K+KIE4kOe9CCkuSfpul/fYRd03nRDMbtUaVqc2D6CtgZD6bxR+g7HxDqnBZPDS4snZqsyapB8xx8xkRWWOwcZhIJx9LKbLlgASmGwwBANwg4MVjp5CTPxdqsm5TuhOfOT2ii4IoW7Z6deL9YT8kE9ITY8RNhxB9/lDjiXlwQLDsgmhzzEUIdQfGgAoIGwP9IyJ+QF/Z6LUCwrYPrNiI9fe+bl8uyrx7Xlhm3y/DOwzHLBGy6WySk/ywpKnKryK6cjp3uSzAlJmSdqTthRDQgPGsPYTIPTaQ0FLz/Us3rJ8IovrunieoIELxsh/Waj0mP3MEYTfiO5jpebbijUbVmrNZy8Aad4xz3e3mOSXZt4MxSm1ziUVi4EE3dElI2vE7nAZwcCj0VRAem5UglplTEFXjEFp/XNYgtMjsMLHYYs5ZQKe/z4xXJJw4j7dumbKZzoyGupHjKoYOXHGLyU6ryOCpqDKNBJQWTGpjNGweTE9OkNUFF6W+YYxHuYRFh/rlzEyktq5CcKPjAf6dfGyHPaJv+3z+wvz716zLTGsFW4KFwlkZVVo3htGlS1/tpx7ZanGr5JBrc8MYwCVhHGQhz5hEerbqZby+u8kRguRgIMVRl2qULRiykMDljGIo53L8gfPUrUmSEz40SKwjjgcRy8If7QqzAcWzVXrIVe09u6MJSsUQgBhlcBWJghBGwmhIu0xGgLJgRgLiqcccaHQOUhTiLFZ4WzqrfwRllRZiqA87cuiYEoWkRPjkXPRQnq+6dnpYAny1vVs2zWXi+WKW0sKrJtJEkb4ocGHD5oN42pkI7CcOWoI3dcZAneRGKtbyTn1b2JFKpPDxJP6E3Lh1+QkRw67m1A4CMrvxzeeSiL8ibPlQp7TBult/JQRnAycAQcseHgn+tHfiuvSzKdsYJJMTEEYwc42KDX4wasRQaBS15FQHHgUz7OEoC//slA6GHYJY2xXG938w0FQcDP2kquNhJSIj1FFEKK+DrsCgCizGTfNbQCF/LHyGA2auI/RwDVgTdAK5x0GIgWUGV4pCR8Hg5SpmR4VgL+0dlLmrOcKO+6Xaei6CC7ET2ApPWzc91C0A4rP8oUBClR+TGHaDlJVFk1GdobRxIJFV8oE/TLKBJQdDLh1fp1OawdwH+nF8n40u4Cy3bkU356JXQYA8HgeR/EiZCSeFxoLSiyOYZLE2ueY05JZMoRKOpDONMiLnOzaEF/GYd2QItSjC8KsJ84wWWBGBRb6xlKemmY3kS/6/XqLxS33U03FBhvxRFPU1C8A94IhHQJkNYqeBnGQcAMrbJoM9pGl2NcBAY2w9HHYzUtwTjUCbsscgjeNKgcDcUdZlrj11Kt3OAE6Uq5oIRn9GByaVHGsmtF76Ho+43ag8UQgrKjfpQLvJHUe7SExGppKspTwErknCTIAQAxWCp+hkUQqPI5Q5geLBRJ9Rsa0VL2QvnSk8/puyTn6lws5gXM+XCggovBiaDLQy6XAa9BLapdP4o0B83vGE0pt4WhlgI4r4aRGVyUofQ6rFLA+ZBPysh4RT41Zi+fbs5lSoJExSnUysPDnD6vdoWh8J48bzqyCnYj3M03FDM8BGOmVwEhoxAhbJCyWWjEhCObedxiJjAVnYBIhdcdAWVcKkCmG7BeUpjZGIIFUXjyDU4XIMUzgaJHxoBZz2gu8Ny0Xsc9dKLcr/fUb9Nrv3xvXjpMbv2hbvqcmjRDC6NWNLe44GkKsd7JHoJmlkspLlUBZR7kJ8VkXE49MMY4hURGp9Z2/4XZ8pUf7tUnF/QuCS0yKggCinHTDe1UIwuNMqHSdLqHEYB5mXx3UpVB4DEPk3aSjQ8cbb/oFwkuV/GAQ5LlhNFTtyjKHg/DmFv1aXcBePSnZPt5GzQfMsYZXmocxIPr9aKWiu1yN91QYoIHQ6L1ReloUWlp3GjCMYUbOZiDtIcoW0wGs0YpLGCdTVfi4q+yXGH7HG/U0fcnknqn5SQvsF4gkx+dZ3Mjk0gIcrrutM0Mi+Yk5L36tPayDod7QBl5DXhIPct5bSd/5ezFckKHQpzRpsWL83MyGBYmgkoUBHzUE2Ow9iTtxk+U9jNpOLdBL2xtGdXRRpP60q+28W/XKZOejGsn7d4zF8vXNdw6om8lgs88FR3QBnrTG5Wv5UVl2XQYZSoHmtty2TNg5lZ6KaflApxpBpi5ReBIoyDWowA81SU4dDROXmYpSzDcOCmJvPAVj8qRAOg1GXoxsvQzFC+cyHgYR94Ad/MNRdu5eS/e6qbmJiZ9wUgMxhNsBT3phG+wUf9+P0HpjpcE4X2slsA1mjHupKOQIYM44M0YSHJe4DAAwlyS7TYOouQoC3QIDlgLWgW6ZeSuP9J5b2ZGLd9Lete8/8jp8p6JzeWlY6fK04dPlBPTmvRf0oqQC6sGbo2rpZpGlZ4ECC84KatRLNIUZhI7quNXN+iYo3u3bSwfuOeucvjUmfLg0/rkgsrBQAINeTv0ymecjhSqMA7Vy8UaeVN8xJEDOBfre/A9eOccKiAajgAM+4FTlE1G4vEjI+5IWpECzDaBcCwu0NtidJSXhuKQDRijYDmY7Sr83JtS4A1wN99QZBycyRQMjZsVQ4wSt6yM/hgqjHOcuMJdLlhU/ZVh5A1hIUyLxJDypl4EHmOQ4iMw+cFivXWxVaEqTFsUbv0FHaUGAH7DyAoocVFDo8Edu8snv6ch0AW17nXYwGur0EaJsTJmqzGSZoVMIde/0hWIoxwvl5OutDk9w5lf1AF5egflSa1q8bkFGmXwSpfMN0+GBQs+6pmNTvBIhFQ+xlwqgk0a5VCs8mXP5yDx8JheFQcO4wFfpJEeAeqbjVmkZRayU2fOlsYF/yqM8ncaTAEiPMGGoTCJZ3imeurnIaAxXN/LTTcUqkf7Z0bBM7/1ZjbHMwRNcgnB+2zZGeN3VDWUj/QUEONg/CGCFIIEJkwIgMJCcSoMMgaeDFwkXP3bEd+0gAjdsc7gPBaUrVAPyQQ7oRWvjTrx8ZGnntPnHfQuCkLVpJP3JipK4ZYmU2eXE4qcAqc8/NxxGY+fIYqVq6Y5Xafrc27vuMqdmZmWTfok8sgPfleHkilP4iYvSkoCFOmGD2eeKBQGmdQqQXkMLXwstOC8sxn80vgaVWmO9Fzxcj1a9JI3TtZRHeWnTOp1iRUTc0jDMIxHxStJP8UDo2GnDQSD8USeZyrKnwYL4uvo1oWhBB/hSnTpFqYiFTTzSY8hVAoBFoeLLj38MLaRSQ04zEWKYaGBVA6/sejeVkZ6FaXqt0pZwWcX8eTvyif4KZ08uWF8uOw/fKzM6gFqPDWuQwTw6Y88+dk8/JDmgZKJoVTKESRpmGWWA2G0GeAAxv/4HaWLjGV0VG84cgCHemkvT0c9AieAcihXerjbYBzRuTR1pfhKmO7VZzjXX5giVtcOGCTaZU9E0KMweTAMA5hweUUMj3Esj5rP6fInL6DRCxaqU+eJvAxHz1RYIr4R7saUcrWaWCFQinA+eC2ZKO7D7DCSFAlwQDc5aHDsQqiRBjR5Y2WpwifertxhnImtQgbCvEIjmuAfmeVXXDP8kEinJkfKDp3d9bJOZJnT6fIeGqg3ob2EVOjBMPiLVlQ+xVsAFTf1gESCkYk8KFfEh5KR5uIdCXzzEzBbzqGVLwHYkSjnsuU3DsepfMJCTpA85hewNQwhsVEzGqhKmHEJRE6QSatCwX9yZ3zGAStAkhqXYUXqP3uGGHLV8hKedBHrk+vVm8Qqn3ppGQr1uhHupvcoVNPPTUI7PM62iNUE+UWr2HqqUb+6/coTQEMotKg67E19v8ffwoXcUMpw3Bk4hXIKyNFczWDCwtleqYl8iZ80Jt7MoQSLxrrLoQ8IXAhtkz7bvXVqovzohX1u0QXYCF4ZKExUhsFQhSwvMHBN+qJ0lMILEMpFXtSG8nyIH+gIe7WBtNiKY7KUqV+8GNOHiub02WmMhffLwUGmoBk6ULYonRLhc/BGnBesU1Tf7BGAabvIqd6kjrliNAuVSuF5kPICkzLyXXghI5DX8uApP5y9EY6hqXAge+hWxuxJeP0X/vDHy1s3yt10Q4GJ0YFLMBK0exBxvrLaTDIzxBNaYM8x4GtlsHI0fpjqCazSwQCXfRUsd/Jwx2X+9sijkWOTjnARBneQ421BSeG2aYl2VE/CX9D29dyXBR3pmFMwBCOvsyohqBAQhVvDEzqKcIhkYMnnzJX2mseNg9KhC7IwPih1vaXAw3o1+NKlS3oqv6DXZOMQvMAIsOD0w+7DUQhYFKFbw5tKcIYDtg0jmsgmxy38EWFeW9HVqHjSrXQVioK7GNU765BlpmwTH4D8gZHem6OJGHF4jiKcN2rYBT03ziQp7QrOhoLkEFyjTWY9EZ1cVSpxEwMFEq0aAtPSog1M4GQln+IsMKLw13tN5QZI44BpIqo/0sEDHdWkpVT87dy2Re+qD5eDOgsst65jGNHioYjymw6qBb3CT95aph8oSrVthB0qqpEHLMCUTHk8hfddcTy7cSOhhjx7qBg6AaE/Kemw953pExL6IlY46BcdRhi9VvAlewPyASmAlEPNSbTpJ78DhCNf0K88RlzpSiBoIQn5Ji55TSN0yOHHaAjCM3hkg/JVDY3iaGzY0+WTY2w0gnAjZhTX/bI+DAXG0X/T4oSkxDrEZTWzgGD0WkMBC1p5uNMoBoOVmThwiMlWUkcJpioAaRY8clFcGw8tW3w+WkByixKiBVvLAfYOfVpug95yfP5VfXVKn4izsAOcokVHx6FQgZ96duI5UDvraCU3fvIKyARKPNU4eMXYn/b2kIu6SukZo3q1SGG81I3CKc/s1An32jTI+P/CeZ1D3HIr+sQ4NLNbu3HmjRSWYhXZ8Ej+4CvqQgXMDd27nesg+nLFS29YKaPyIFfjVpqxarhoPEpC7nLgz3lK4FflqKCJkAHJUEgHD1QIXH48N8bd9KEX1WSp0oqEglbGZfWJN7OA0y+MBe51Oyt7OyolrThwwNQQdhUWeKtzmTUcsQJWOCGMGxyCx79dx6Uu6wzhp/UePQdQJCxp4ae8EGqUTc5UlsCRZXOPclBcKT/lAE48NMnfGaKghE4htYFrYJXWUF2RwC/Ov9K3h7V8PFNGtTIGnfxFueRuO8W3ZOA6Kdm01HvQAJFRL+DpMCLUgTVWAQcpcc+8lE2jSJ6QKbTXvPIAx89GwR1+8pCRpWGMhjrUOrqc63xZF4YCh9y+iTMIxEIhTn4rCRyT45rpRKXwnOh0Ig3kW8aHSHUlk24pGNKjLDKF8x4uwPTzkIHM+HWjMd+5ZVNZVg/yqg7HXtR6P+v84EiBgj8EiFKTK51azkawOi5IacBxtx8ENS47FHOldkHwh14EBfHpKrV1zTIgkyUDKPVxSbXYJCFb6zltn/GGTasoNFC+c6kOgSXyxJAw8Vd0uplQ00yJ4Rg2heE5BpyV3oThExHuXZTB0ALs5BABCpsXFWMM48xVs42OyT0Kwy8ZCxP5G7V9BZKCkiTuJt0hIoTUIQAlyh9M9ENGSdDMbOlfW5ChoIEDfH5SbSWoxqH5AwJsXNUiL/MiCUQnxcQ46winCi/y7Ll9h8f7h2Uk83qfwkpRcRinI4TFBhAGlDS1SjVO4KMuMfTw6S0ViFsO19yAWOmI5D3zWOWiGh73Uz7/smoaAM8b3MJrPYwwfzT3ctDCxsLzFy/4vF9rJyoA3cYDHPQETfLYtXkc/oDzELXiBrDG+h6KHvmbK2W4MPCHXyTZtWnEMph/BR2YIEbBj4eVNBaayLPvi4gb5G5cSVepEAK0rNowimgElNxUOsIJBUMpYHbApR/QxGclrYIwfsFf1psYg7FYV+LSjZNW/A6dK3zm7HltODyjw+JQWJUd/w2G9Ji+qkBJl2ErvS5NxkhaTkgTznlrLxJwohlchq2VUULAZYkZ7vAmUi7PR/z42Fi5eFGHcOtJH4ZkftFQtPgMXNJkPhIhF7DRiMEXfsClvYAipNmhVZjUmajpMn7RJEdjRHy4jiwTLueq9Ow4DAUj8bMULRGz7N2mK6Cu33WdDL2CUbCW1oJGjg2Gnmda1sEtt5aCSQFyN7MQFkxXmBt4PGyyACuM4mC6hy7AEc4WyfmAU7oyygca40E42/Q5ufM6LR5DyZae1o4Bl9s7K4BRdi7Wu8BpoqiUyuGvv84B1G8JXvF2GEQOd+qzEcHHhlFR47zcKu1V6fwMRPmJd5rqwNBLX5kIPtA7Up/IFiUpMKZXl6fnZsuIlo5Z3oZnXUCGzHzQCQQGgjECC90YSCo8kRQe9VRA/IUmwIiHIHCo/vBYv3i1WTGCCQPkrgARxMEnFiuEk9VEGxEyExq22t9Itz4MRTVG4cwsFvd5zlSZamaIaau7eeJz3K3kyxxx2XvAe0SEs+AaD7EILVpi/DHaprOXMDQOvmvXznLo+PFy5hxb1wWrv7CLoDdQoSxRBjnDAIgBSygweUJpwsRIxbWNnzqnIVhXUDA0Jq9VgSAgVpaEuxoXFSQ5agSdkTfwBV7z19gC4Yi+hbKgZy0ah2neopP7a55cXMmyEytZXa4KAm8M9TIbfFGZMBsHMb4FJeYF9JlO0iLe9Coy5E22mp96p1c4MZJYHgY2ttq7gBt0WReGAj+oPK09A1EOOjAjFbYwxDEYmD9408VYZUueOl/VmoRRsmI6Skh+F2hFdChwy8sQgl6NT7zde8fO8vz+V3R49Yzkj4Bisgx17BQQRZEZ8xKthDANyuPSEfoqP+ktB1zSSrTDvjvkNOOHB5SiCRSs4sLd5Sja5UKEfsDBOyu9/B38Sqmw6DTft59b0BllykbvEu10m1eCzwlbFAZRTd2y3o50gpoJIYshJcQEbDsMdaBieIUIAgewAR+0Bj+plU+5VKMFDr/ARe8Cghvo1oWhUF+35dRdmsrIOba1ROtrFlrobQGGAEIZYaqY7+zBfHDimNCnICxvIkMezoOfaXldt9JQh7dpB8pODbdePCgj0aerOeDNO2/JK2dj8LAiEEUjqowSHu9TdIRIT4VQQ/0id1yh2wbRFjh1FEoUg/pQe0wS515PFbAh8wxEePlx6gnKo6zVoYTgVpkiiTrDA9ChlERSZJYvTH7WsuBT7+d14LhetTUnAwZYhj045xE8IYZVrMI5XjHEkg53PHySL+ogWOrvIZRuzgN8/AHFT1QZDtjoqWxt9jP85NuVsdJVSwySCNwQt04MBcFKYXVZpDnS3Q8Y5Sc+BNC5W/GB4Sc2WYlWscsK59QUoIQEbDIYj4dciZeEPk109bHSjRPliD7Mc1bzEjKEoqdAA08lzHmiaNKrr+N1hFd0hJ4SViVFuuoR9NZ0Kg08BuN6VrwoVFhSrXcoGKlt3B4eZZzor1wSLqA6Dj6CjnkGS63sbJjTU3wOxwjFDd7ZsHK2XktyPaCbRMclBVFDy8yipC5BJynZiBg6kARBiqDa3sakRQZ0IfECmxsh6dX9dN5lRtYbcb28qbsRpa5RBqyENxYqQlEglCTumSUZnWHrew3A2saZ6x0cjncBbag0AqtF2Tg+UrZr7xbfZDylgxnQxkjR1X6oVDQGbBoJtPG1/UBWJy90k+o6VaUDd0RGvHWOLEx8jVd5mnIELSL4q+ypyGn/o6w0qqim4ARIQ15TDQ9MTMAjO1QRB1KvYAl+Wg8m6WmcE0OjwOoCVwRSFmmADsMoOfvljd6EUto0Bu6mvtRJw+0wEtHj8kyZcimnsrIp0g8cZdAagAUBN/C6LnoUJur+bqIUBD4vWSGqrpgZMJYfcWIqPNfPY3B5UmAGqJeAUZqyZXqXUVU89EbLGkZM6t32KX1v/vmX92sjIYe4hYBiGEEoymbVJ/FRBqSkUkfPI00LaN2rQJUZBQ84RaO9UYKjwBH4M28ovxVHdKZaeKglXrUXfKBFHBEv2M9CDxT1RdGDTnplhnKUAlz18UyGcpWfcjw/VFiZvIlyZnbWPGmMkGEg9TUuALud6wctdThmY4dQynPVo1zjEByO2kKPl/xFDcNWdkN7uCgY5oX4+YwFCzdxqISGoiC8wW5dGErUOSrvVlEc9F1MdGtnIcPcDEcOt4CrGdbKU+VBrsBnDMg7FJ+slLpFS6Xjegf9wCuHbSREIpjIl4aBEqB0teWlHOmBldEFkS5lkD/v4AGHlQ2/f7pEVQwHDSgnkG26Ypwe+PB3HLDgascRE/FZZ/MGGOjRH//463TDCkouaalvXEw3cDVqWlv1eXPSdaRnET5KcUm0OunwtsJBA/yj2Jqn0hG5TJHTwOmqCNhoDC9fDYeHTZH1QaN47ifygSgpuO73bKyue0GvVQAdKsxJBYB5wcRQzoxPPO4pWvDEJwyTVyoWDQ/tbcje6c5jaHfxOzZvKBNa7XnlyDHthdJSKU4Zvcol0QUNCLMKlDh+VjqptrVCpUlw4UeC5Kv01HvSZvxWqsgbeaJM0hh1+V6NMkKdulFOFy4DE5eQlC9a1UsAZyMjzf4Y3mR+w9CbmN6AVbOgTaB6DqMn+LiLGobFplDYAm5c1BGfUdeoxEtk1suNBHDOEvm9a9qTe3EyrCruAqL+Ni0MS3SAH6OP3cP0KmHsmY+ib4RbFz2K+CGmVMbAHCtJGAhMMMMAkoNBSiFW4qqMd55IF4C7amBzcx95gLQA5IP9CG7n5qmypPc1XtRXdZf1CYlqWWRVl4/GSoU0eYwjI5RBeGxy9oIz92zR62SbQz4BUCf5RLzSyIdXMcLr4Uk73omsYFH3oNJ5Kyz8CGyoNGQEr/JeSyLFcOZXFOkqhZKKcs0DGloC0rwA1Dxt6KN0mi791NPOzs3po6r6HqTq6KpQDUOEEtvgFMEQSlMJp4AKPrPUDsd5DuLPPZDK8E118pCLOusPAyUsJqiMWgD5ghRtRFaPwqZIehbBpuwp7Ua4dWEorqgYnQZhZZFEQhFIRVFqer2LhyE0p+AHQQ3oZqajdAyhxPxIzOFUKZt0AMSSvqB18MhJrfZEOi0XCoDgcKGgiFmOBDs8URbfcE/Fy2RjQksEQz3suAt34iUOo/A2DVA5OTFU2unVBOdGQzkzNVAKE4pGoJWXSXrCUX74A9Zl1HGXsjif8wrKil7LgAc2S2UwBhRXPJydndObkyN+/ZbMiT1oMBEeHqWsKCLL7/BCMUmgiaB+ok9l5Hws5Bj1dduDTOThK1ucA4CheBiWY0gKugFunRgKShQ9SCg1zVIYBzywPsBQfghJzBN3Hd9hPOnKp3hdIpMSHQSJua6b8t62ebIs6kNABw7rXF61svHwEBgJpSqbVQ40+vOhd01BlB3S5lmCHb1heIJWUGUMxAtvUC6vVxmAdk2sJPjJkQ4jQBENpfxpjGF4wJE3cqHYkVd0AosCwSf8SqH1JT2MvmYiCgTVgb9f8MR1VrACxHjEV9g3r13T9ArDeseloZd8crDC7Y1KJKfzwU+XX6FNq8GRtmG4e8JO4eQkj3/RW/HFLXp1hoJeIlYan8m+kRsioWtdGEo8G0D4+kPQ2r4eSoHggoHBRML4EAXdN3Btg2LlR0IRChgesKF0dOEwe8fWqXJaS7/HT521khLf2ZaOuaJFcuAOHwH7aNmq+qqQUIgEMS2GAxaowEPImNAi4wxFIB+0Z/1sHMZZyweg5YBDgaLOyusxCTiEl/pSNnfCeGt8KGFFRBJ49Od7xWdDJK3WibSmdm4ExBV6OMHPa6hKOs9aKAeXH1eNEFcRIgSUU0P1uYiDzh8NosLCQe+/rG00QZvyqdeQVRgYiXjvmnoTVr1Iu5GHSgTF68RQYBA/WkTuuLzTgoWOKc0K4URdQmWB7bjMq/wSupVHV49qJeRdmpOc0pm8R0+eVmyIUdGNAtL9+E1CGatbNSEOOsBblYueTi0cLtPoyUKJAQtY46IuVkbF19UlyiNf/qykZLNORTzewE18lKsoGzZ1SkWnpNw0id/O/COP8irCPBMDE1+FqqCh/EFD8DPUk4wgyFA0RigtzzNmtT8MKuhZaDrSBa30EZGdu+MczgYN2mJ+goHwLRyc6as0B0auLAWrtpIHp2PSi/gJfTUiZ7xBl3XRo8B0DxtUaUQT3W9ltpgHE2G/39kQLK1bW/DdfiMQNAotZus3pG0Zt+mUlHPnz5XDJ8+4LMpB4fjv5KfFUoKdSnS3z7AklAglpYV2yArZABuHezc0U3AUXZG7dUdp0uWcIFti56hlkbcDi1JFiLtbdSEhijxpk8ZLnBKA5sof6drtIt9VnBAZVndOcIEn4KYC1JM/FDYbMbbz8J2SWZ2hTD1GdWZAUEMmXOQPjgVuYoN+MAtjJSh4pBgZDFHwPvZ/sZBAGOLk7+NLwDyRRz4Kx4qBIG6cWxeGYva5wZFP3FvRvAEheEIOL+Bscpd7cjhE2nArwGC5Re/7hM652rZxvBw/fUbDrXhv3HAUKjgveabGkZU4SSmLcwzy0l84lBcSCBuJwtlaBkzmrSFns78mWC1QRCIVx42WN+sb+aKalNAxloAzPFiTD+5yBWdgZ1AaNDNvCGydJBQVo0Oh9QefSawOashCTwE+53b95DMcuRh6aefx4oJeh1goE+OTTe7EA22GdP2Ut9IBvnZ98McvLTqJgcZKp6K84uXXgDGchGlKu+6edWEorqU4iFAtWJgKR+PiZDNd/IFFboGqVsTYPhhXZaFcZO4rYxLm9o2T5eXDR3Q275zjQkHwovAShLzW2Fpk9FaKBX+gbagI+UQ+siV9xmOtV4zpjjv7lUDBL3qiilIR5KHVrODhgQbFG1aFYTgMrRonmuhtvTeLeIZzamFzvE8aiOIaucDfGKQSglYgcBQYPocgXjhsIPKTZDZTDvH00hpmskyswv0uPmeH8axlfEzfg6H8RB0IwaB/aAqDYHJOvVxPGSBF4o/GRgEV4axRuvPygDG22EeP4moG2A27UuN14KoQzOV4ahHCqkwUhX4XrzI4VmZgbo5v2dAHjxEl2qBt8noZafeWqfKKjje9OK0HiUKIkeDyjt/qIHgazWgBya9fgAJSHYsHohPJNi5KRLYoQK4YEevXcAVr41c6QyAcacaAgijML/Jr3K5QbCwBMuhMIwDQpQknig8ZOXQzDkiuac6rSD94BU4R2WtQR3oLehISsrymXop3GuUrPRf2kJDxkUllRX0VJyVe0jc4p2en/WCSstsOOnE+1UYZsxwMI+oWAKw88odBcosK0pgoVkM9n2DPoRJONMobelkXPQqqg24iOTNQ3I1WpnJZ8eZdw5qMd6YKm4krekYyXjZPjpW9rx4p56c1ltZf26WwyI1wSI3ygVJYCRHbwd9uxZK2Jq5qg/GACzSrnPG7XhWnqWopToWHnhxagNZPscMTdMkfGCKDe2AiwO2UWlvyOlpXeh3yVYLJk1SAxZskBUZ68ibh4270gqy5PBQjp5zyDeoZB9v05zRv4eC9IeYT+ktZovxp3GShPPCaPiJw6qViH538JLgsGk05np8IJ5N5aOTvRrv1YSiNkMVEtWju4oNbwdDKVJjTESTM0k9MdQ4xn+5xq4Zaw/rYznMHD2l1ZuH/b+9sf6y6qjB+KEyhwBQqNEBaa7RG/dCYNFG/mJj4nxsTPxu1Hyq1bbC2gVaBgDPQcQZ8fs+z1jlnENDc2Ds3vWfP3HP2y3rb62Xvfd5HlT7rBNByHdxEA+eEYg38yotqW7Ls0rzNE5lUb8OVDNT3ssmOYAJwwjlwTv6CR7t5AYMAcgbY0Ic4VZyZGzabTLChBoyZVlCrQmXVODkoRQweFp024Cul39Wufgdx4gNYlkJcTefUMGXXKt9nE1NOP9HfGffx0f6jYdAyjODxcsXkJQfithzs4TFKTB7NsCeI0AySi5cQWenxyiWO4U/ghJfkiF2cOckNCvJBtSyMUXxriOpGR8SJ3YDyVI83ConlDUsHnPCp1sq7utp+6cJrw6ef3R4e6YIiI5eXbMLpA2UT0IYxj4RJMv5Bt5cXtMgq4tHGnePHoIEnz71Q0DEvydJrcKiQ5k7K8onk/pCBh/56KdR0oGl67mtkJaBY/qAXqmnHAeEHXqeWmbJnJDeEr+vsiM7ZKQMvWPqh07Xeux+WoLDFCxsgLfrWn5kik2oZ+zlrxpXzfR0PcqCPTHBlSQoll6GrOg8caVQJfahW5Nu2qXOTaHLBkavyLBsBTv06txsxo9BhmcEGcB5D1M9BIIVmlCnVoFCULCzgmA2+o+dILu2eH/70yS0vA7AQdg1YjAwsxkbPrjcJ5YiJqsABAiH8XrKUZSJT+ALjA2s5KQlnHZ3fNdAMvyqKcpgQwCMPGj1KB37Ov/F6D7b1URWWx/mpR+FRnWm5mzN81f/0A9fF58CFbsufkZ26psIeHCY+nNXcqtH0gJxE8Onbfc0sPIefq/ih1f2HtnWF1yvi0bOp+qNCogUjpWJRQaLhjKlFqZemLqxpsxGBYlOxwbOlMoxCiiMw1ccZqY2RM5tQz8dkrl16fTjQgf0HH93SLKMx2xEiwzNDQct0TdIjMEZhRGY0ZsHTs4XHK9XBw4YEBnnaZGpjRkBKEvWqsmGbBTQB8K4rga0+2bFwBGirPccg4Ez97kA6hlP4HokFbgLaMrs4qR0tWT/i3tXVWAJNcjRty59eREZV0Ob+BzllUXR/aad+xsABFEKGoYml0iN9/gJ5d/TN+7Zh0ERJ9YUiXoxUll712jNAmYW0rzZ/Z6aOT8jPZUOUdaSNCJQYOyrskflZZTB9Z4khOJRcv7euXh0ePt4fPvtSdwATJB6NpGa1S6NWqh2ScqX5qByLEA7hD4jhaUh86uySHKdINhj8HTRjMEyO3l6UWTAyNG/wcLXsM0LSlrJzNIuEN9m5graSTf20tBVcPdtGZxEU7CLkfdoio11UALmgVw5rtMhl2FIH+jQcZenDgap86IcFy8FOnUctnNLl0WKWyGe5P0xwDoeK7pYbW+WMokDUZq1QV1x8iz0HJwqgHKtMemu+3/R+IwKlHcudlYLtqFJqjIvypDICAIOoPQ46DN+/fn24p28Y3rr9d6NipHYIgMk3jbkimbqz8IjhmVWwnf6d2mlxiqopQ8Z0FqNkKVtqF1hvCVjhNm/ymSWKXFPF4Ws5MbUgc/rsPiBV84JLyWR+o3zBziCTPLzt1C2ZaOQCHrQFM/JQ2YMLeMgc/KlOOmJ5afw0csJl3rdgQBfClchKqbwk/LFu0wffNzZay6HD4EQ/Riwx5xjHKzDIqAEIAoSr8tiNGyKbd3Fay25DAiVK7pEew6D0/lH2YaVGWer4jPQVLbdu37s33NHrTbFPHC5Kx+lzUSzKRpOtXBtT8EBqZ4dhGQYR78QDA2bsY6+S3jqPoxOgxczYMXRoBSfyCcl4ll+QoZJa6JmzSLHeByayIQ2QSc7BTlzdLuekX0B5lFeeevpuNGWSrzq4FE7kZCznWpAQik3rIhzZpsH1U+WYww7j8YHpFKGCiDzuXZaEFnbQbS7ndJ1l305+TjdTjjTMT7ODBRcRwcMbPfMLJfXfB/J5FmXddw135zcjUKQgO6KUNCoKx3TAtKgoMsckl3UK+M7d+34pncZNqVsGq2fA7VQoXH/OW/+uGAnFAClOplYtwyne6IRDk5gNyCEbziZ3ckOotFP1HhLHEqypMw1lHIipA8fVxQkeSSFicVSBbkhPeCm4gitwkc98QQuKH84CFrpua4FMGn7hgW7SD+inroRJAJrGpENoOhDIKEX2wkvVuKUW2/nspR8W0xljvT/sQNda9o/0EBjBwrledyU8LE+VJZC7qBbz5HVMBAiXG6cgG9mtJbMRgRIlSUv6t5JlOPYxRgxpZ1EwvHP97eGmrpE81FkV9Brjouxp3er6Uh940E9qxxyLzoRb7AZkO1NGcLViOOq9BU45CqJL8ECeokd6lgk4oWpwwDasb2eBOKN8JA+OSxCIFGD6PjLTDsdswzyzCXzhlwAyOWUtt0j5tbQBTxAArISsZFnejFKowk5NJ5SQFx6ePYGSElp/vQf+eSl6E05IhZ+dPvy58/dAL+54pI+xXtzdFfW+syK6Ykl3PKWfLNl8EC/dtj6Pw33zpY0IFCvYlpeSMYLyfUcpqkSB3JJyTQfuH356S9M4d67qTSkyyJE2HGPgmHH1KA2jjg4P7eckcTFKPwvusqrYGwM5hJcgJRenYRkIRx7yGp2snUOy+iKZ2qE0ulTRhSByt1NbcvFJcM2EhLdZog/giwFU3TDB4thdZ3rwnTMuXYQHbVyclX5E0l8pUz9YlpF8643wmV2BgXcnePhX7b7TlzrDAiXaynNJBFwWzJEnMoO7o7NhfF9yb++BXrZ31jIkKMMFdsjlritPrwmOvipv5QV0rduNCBSvRzE+PyVGYgYXX1BU5rxu5T6vc/If6fWm+49135aDKQptR7ProuCiAR1GUGih7FY89VF/cg1vztq0I9AKKZeVYc8xhe8cgCZLKJxCP8MicCcsnWoHPDCiILkFAC1mHWAF5/oUVFHBDU3zLm8v0i0rqCTKpq09qWXJRUPKOSZ5Hl7rnDawkYStGWuLnCJgHhSTBFv1wE10i0LJAW0HmZCaeuiCk9e4HnLLi5ZlZ3TjKtiZxbSnoIQkVgt79FWzSdcBs860EYGCplA6TohjH+kqO3elHqp8TrejXNC32/+ql9JxS0qG6GgTpfo6iTTGKD5q2RrEqXusikMay5ssx5wVrFuNnprJASJXl9m/aGRvmDaeZZNMXd972i0qe1mdege7OyZJiI3yBmj0Uks5UEd6U1BwLKA0c2po+oebmj4A4OYHLteb5skDCjS6EhoqZ6CJQNAiUWJcGHWvPJoeg1Zw1rzqwxM5WBvQv9BgeYh9vtYZMZ5Y5BN5nhmr82LtPmnryc7B4krXrH2zEYGC6jxSS9lHGml4jh19Xjx/fri6e3H4480PtUSQsnF8ruTiaUo4mPWpVcNoaAxMoy3EjnLgnStD5aAYwEoBSXAJhy/QkkxGbTmQb+dqh45zYEnDMdPJmP40Ajz1j4SWQY7JCD86U7HtnR9KgwjSsoMOf9q3g46wonWkO55NnZMYOFD1y300AbVq33oBt5ez0PXBtNphRWIJ5mOXwrXs0jP4lgUe1Zb+pB7cMba5hVsXBA0H7aYlGPLYLQOaKpTP8cYpv+WFi5L0x//wkv69BFOeg/k+PYw+TiJtRKCgWBTJ63QOj/TSadng4vnXNLMcDn/48M+j88Z1onSMR8LUDI4Y3KeQi1YczCDe2LiY1PaV8/m5/G7v0RDaMTuzmuUqEBsZJpU8MjpgkSry02znpKy/uU3jFIELicngjKzPJlqhQYpMFsc1tPFmSHWVEM2fCsahUoydRwAV22FNjbLkPtLHkMZkYNFEjqCb9giPTukrbVSOulfe/GiqgEYO4GhiSzs54ThYVKK3VMcmOn2sY5VDPs7UNNQODpjZ0E8owjp7F9a42YxAUYdxBj8/Le1cufz68JWeSLx7/35eOuB2tKJG6ynKakV7Xw5uBaNhgdiFGZaU4oxyDim6b8C0IdQGvmkD6KSy6HU7xmHGw0YxlIwoHC+LLFN4gDqN4IRPBYAI+ZYZ44dDO076gIuERurF23IjgcMw/MirCkds6TzTChU6duLGoJ8miazhmT6qUDqhgZG6l0OUDQveiAMu15GYuXR9SjMZdGkOfeUVYPTAKBpgHChq5BgTSQlmkrfUiRDmsswmloN8+nLwL/ouzVnfYiRiEtE/3mYf/ZvcWjcbESg4CY7MjHLtylV/bmFP777lzRx2PFRcFkSJUTlOk4N1NJZ63Ir6uJ3MbsXaYa18Qxb+3IGoT8IZoMXnH7hCDLv5U4ZxDnggR1Ibjz39mMq0w+ep3yBCidBxO4Go+qZif6GdUZ1UvOVlloHgNrTq0Ul+BRuMUSbo+2Zc7d0f6VXdiWcjN/4HABnpmCpkwSGVtaMzoZqOQHg5YNpf0Z3SR14yAWcm0EC2ilJ2lkrVEtJ4XhpOPU2d+LWeIMXd0r5DWCPKo/28FikzqQiiHP2fPoHXFCEbaSMCBUdGaa/q7NYHf/lI7//VEky3abP0iv5tFgtMzjaQEUanlNInCFr5TYkDSTulDEqLYY/hTBhtZCjGDXFQTpUKBscr/ARwePS5/ZbBcHY8sHAI/FF91JkbCjgV8pAsEe2U+R/lUovK6mbg3AyeYBhURriqowHy/DWieHmsx2FFpeVMP9RSjgxWn9GDGaRMjJ0S/Cx3GqyXyN/OTp8Kj4GCiEMWhKe/yFq4oQhR1akNWTphz7N6x8GDwwf+qCxnxkDj2Ak66/5uY8vFfjMCRdrgJQVf6LHdAz1Hcqh3R7FmRXE2rtpboSjOM4k9yBat/uAUk9K7kxgIOuyhMdGZjGcstc2NyQq+68lAG1zDuCwDFnuuHXSa83AgV4NhuLJO4MjuE69ayniGEbBoPiGgVM4gQV0cHacHzy/fgIglpH/0zWDa49ShYyz0BVH9g0FCRh8RUC3dzBOoHgQEY10Vb8MI3rS1a/kN48bUucx09KIkehCxTOSKT+8ZGS5r6f353/Y8uGB/vgDMMyksvU4qbUSgcKbroe7bevBAI4nyHklkQJnKdkG3GJANToHjOE5cNSkdE+AQbOxQytlnVGenLaO04xhUAG10MEnmqvq5E4yGjCQmrMWKYMBPWFleeTcjKvA4tPchOtIzjvk0ruRjnEYgfqaZLKjk7F9s9Eu4xcHTF/ck/aCPJWP6JcoOJNWOuCJZ79My+bCAi5l6r7p5/8M30BLPHJCAPGK5jj53BaTII60AfOcE7TYcIU+TZEJerpPoj5nDL5FQ3e7FC8P+/bv+JsoZvUQ9dw3nfWqgrjttRKAwTtz8+GNdZT+tKZcXQchUUmgvFVBKB4YG2kqyQhkloyJlW8bthE+PjBiS4x1S34gIbDsE9X3wPD9tjPGAy8upXYKC2YQV7bgCzgBvwXgaoD4Ook54NuIpShLOawdU0VfBEU7J3aJzKZovdI8FcSmBIYREvyNv4ByUwjdJbYJPsALMDEiflVWZpxH7IN6iuyF0JKE5uF4YdMnNJkMhdebHbK36HhxcqnafwBAf+j5dfxK0Z0xrS/XIl4EFegQEAcNz92d3zilQdlTHi/byhKNYnUjaiED56qsvhz19Bo6r7kcHfTwRp8FRnvrxVMwuh5KzxE1wStmMpQMNSuycRfnO4aSqU6UnbQxYMDFi0TJSO1HocVSCu9hZQIKZ96KETNBXo6vAtzdqTz2g+gFDe0tsNt6kzYIVSlVTOpbcf2gqze/haqBjgUSlQBkgMoMiSlNWfyK666oHgmdAsnY88gOdg+/o17OQYEi91AyMqxxEyZm1aKXH1o97jo5Y6iWh1ZzSlpyjziQnswkzce39Um5F6M6repm6Vxf0H9onkzYiUC7rBjnenHL3zj+GhwoYlmJPOEbR/kCv7+SF2rx5nrNiOYUsU9lZpThGNPKqytgmRVLgJ0Ph6DhqVByXxZFcAUgnAGUYGzhIagmWQbw8EC3oGS/OJQQlNg1LaCb5pj+30wZiB3DaG+M/S9VispHJfZCjdE/CE8yqiVCRQnAJILCig0CJLqRnjD27qVP0C5oS0QCccACXmXICD61AsJ1IFXs5ekO74xMEMlHSnmDh32WIOImPZhE1qwkIbXWW67Fsv/9YL6xQvQ/qG3zN+40IlOtXrwy/+Ol7w/17OkbR5wW+Zs3Pu7b081R8ihdCc+UWZWmDNsnzDmDlXbTiZdgqeE2MdivFEVLAidLercDFsME3k6kOs4nudJpzcgLqfTFSMLh0htjwzWllTJ4yW0bo5lURp3KnWVu7EXyhLWToV3gWamhnaSQAGCCCcQQNLzt80UdWs4CSMs6bcOg3PmQAdBOjfGDcQxMw2WoHGEKCMT544gNfrqjDupoBoAw9k3EjsJCgl/reDOAMfvrlZtQnw/Ub14c3di/47TqQO4m0EYGCYX/4vbeHvZ+/rzeofOFlg7VnrZZyBcPU61drag+Op2JFDscdrGFtEdooae/kcrJxNhNNhbZ2Qy09DI/Btb4wR+wdsyljqOKJUZm72vqBirOorWR2M5S8/m524MwS/MwneOZshyHnJtPL8Y/EgLgdOH2IDIKleo5QLOCGAzbauEd6LWGfkcZYXZd+ZMBI77slxNF/Uvgn32Gc4yLfetJMOzgAtMDaKetgDjOkSqfJUSfZeTnFjTcvD9+99qbQmme4rXO7EYFCh3d1y8rP3vvJ8O47b/lpuK8P+AKWGrAPeympz57YqVXXeuuDQRTLPUw7Op34qqZtbrbjIhaOj0EYoXwl2zYXLEEmIuCwn8yQXLZzh6LmuMOo4r+nIhy2OWPHMQTLSOSh2Wd8Kuh7JgrhVsBL2BR9QwicvrKu53eo5aq/CMCJgGojzHkIjFPE8/6MJeGPAxFKFp05C/gwK3BsQzP70ypzGneHL2OVXuPYz2KC7H/IHNcmAlQCF9o8h8IjFicZJIi0MYGCMLwZ/cabV3T+/A0beRphaJ1pkWIntKnkrTYxGgZMfYNt896zCgpQAFiL2pBzfeVp9oDCXqpDe61BcIDtFCeugUXA/DGrf5vTRgVKK5pZgN+S/j8asGNDahk8Vlbo4o0rq25B3CYNLIGyTdZe+rqyBpZAWVl1C+I2aWAJlG2y9tLXlTWwBMrKqlsQt0kDS6Bsk7WXvq6sgSVQVlbdgrhNGlgCZZusvfR1ZQ0sgbKy6hbEbdLAEijbZO2lrytrYAmUlVW3IG6TBpZA2SZrL31dWQNLoKysugVxmzSwBMo2WXvp68oaWAJlZdUtiNukAR63mZ7I2aaeL31dNPA/aoAYeUVPrumZ2yUtGlg08CINECM8Kr73IoClftHAogE/GLqndwKd+nxRxqKBRQMv0YBi5JWnR0e/n7844CXgS9Oiga3TALFBjPjVGb+5+cnTM3rFzPLugZ7r3OwAAABQSURBVK3zg6XDL9EAQcJnEn/943en0PjdzU9+pVdavq+XZ70lgIt6V9ZpnQ77dr+D5iVKWpq2TwOc3dLLDfVF9lP/5JCEmeSXP/rBb9HEvwEiiRFkFw8YLAAAAABJRU5ErkJggg=="/>
56
+ </svg>
57
+ {% if member %}
58
+ <h1>{{member.display_name}}</h1>
59
+ {% else %}
60
+ <h2>Successfully Unsubscribed</h2>
61
+ {% endif %}
62
+
63
+ <p>You have been successfully <span>unsubscribed</span> from all notifications.</p>
64
+ <p>You will no longer receive any further communications from us. If this was a mistake, you can resubscribe at any time.</p>
65
+ </div>
66
+ <div class="footer">
67
+ <div style="font-family:Roboto, Helvetica, Arial, sans-serif;font-size:14px;font-weight:300;line-height:20px;text-align:center">
68
+ <div>Powered by {{SITE_LABEL}}</div>
69
+ <div>© 2023 {{COMPANY_LABEL}}</div>
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </body>
74
+ </html>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-restit
3
- Version: 4.2.73
3
+ Version: 4.2.75
4
4
  Summary: A Rest Framework for DJANGO
5
5
  License: MIT
6
6
  Author: Ian Starnes
@@ -28,9 +28,9 @@ account/models/device.py,sha256=TloXvvrx3khF3BeGFuVYn6DhXjOW0AMZb4F9Fl5nBII,5491
28
28
  account/models/feeds.py,sha256=vI7fG4ASY1M0Zjke24RdnfDcuWeATl_yR_25jPmT64g,2011
29
29
  account/models/group.py,sha256=iDD_oSgswKV_t_gXZuVK80MvICrZZqdANm2jtGtOFy8,21985
30
30
  account/models/legacy.py,sha256=zYdtv4LC0ooxPVqWM-uToPwV-lYWQLorSE6p6yn1xDw,2720
31
- account/models/member.py,sha256=yM1tB0eXH5FZ49KPb2MKlt22v8qFOwcQRbO2_KRt5gw,51053
31
+ account/models/member.py,sha256=VoMxjh4p6y9nDhTBX8O571RQD16wEesG8K4z10ran1o,52796
32
32
  account/models/membership.py,sha256=90EpAhOsGaqphDAkONP6j_qQ0OWSRaQsI8H7E7fgMkE,9249
33
- account/models/notify.py,sha256=YnZujSHJHY7B09e6FIyZIEJRWLPYk1Sk1e92tFzB1IA,12078
33
+ account/models/notify.py,sha256=Qzi8gLsVi8nDx8gpL4dyr0MPExYYGIDxZvHFUdCs7H4,15072
34
34
  account/models/passkeys.py,sha256=TJxITUi4DT4_1tW2K7ZlOcRjJuMVl2NtKz7pKQU8-Tw,1516
35
35
  account/models/session.py,sha256=ELkWjB_2KXQvPtRPrvuGJpJsqrxCQX_4J53SbqGz_2U,3737
36
36
  account/models/settings.py,sha256=gOyRWBVd3BQpjfj_hJPtqX3H46ztyRAFxBrPbv11lQg,2137
@@ -40,23 +40,24 @@ account/passkeys/__init__.py,sha256=FwXYJXwSJXfkLojGBcVpF1dFpgFhzDdd9N_3naYQ0cc,
40
40
  account/passkeys/core.py,sha256=xj-vXjSrfWDvc5MYtEmXzwaMkNHl-cXrQKVrN9soRCg,4126
41
41
  account/periodic.py,sha256=-u0n-7QTJgDOkasGhBAPwHAwjpqWGA-MZLEFkVTqCGU,874
42
42
  account/rpc/__init__.py,sha256=SGF0M_-H0dKh3b1apSX29BotNWAvITYccGQVC0MIjL8,336
43
- account/rpc/auth.py,sha256=vcsAUCj-iyZEZA2D20KL4h7w7aeN2qgwoD_eUs0nJpQ,16452
43
+ account/rpc/auth.py,sha256=3BJMQZ6dxE0U3HvFbedx0kBGzLzZjP8XkkcUcBobRTk,16483
44
44
  account/rpc/device.py,sha256=mB14a6qvJIBnCa9ivLhPXwEt5Gk2foyqsKBtZxC506k,3070
45
45
  account/rpc/group.py,sha256=FD9GymgPY68y-gtDLsZxYVdwQJeLGpqcP4hjcDUh-GM,4022
46
- account/rpc/member.py,sha256=PU-Uz5KUI_BZFy-F-taDqAfnt_AwONYXSzUvfm7eyTw,1264
46
+ account/rpc/member.py,sha256=VNRSD38mmTUCbq3cCSy3qRyquzeVEwW_8zzrtS0-vAA,1817
47
47
  account/rpc/notify.py,sha256=Q2YWejP36egeF060Hih5uX4Psv_B8NWlLLPi7iDYlIw,3344
48
48
  account/rpc/oauth.py,sha256=ISLVsR5HvKALANokaOFRvF4FTRxWtXPvVnZAYANKxpo,2864
49
49
  account/rpc/passkeys.py,sha256=5x28nYILJUMMSwfVuWYL66hfoGUXahMqOwiHhM4I3Do,1729
50
50
  account/rpc/settings.py,sha256=EvPuwW63Gp_Va0ANIPAZ894tnS_JCctQ0FzqYRdKUNM,271
51
51
  account/settings.py,sha256=XEvZdcA6p_iUpDq9NmICK8rxzIQ8NViKfrpyuYgSV4o,53
52
- account/templates/email/base.html,sha256=GnqUkoOYLDmaL370E1M-Q0PKJ60VH0MzkcjUyg9DdyY,9709
53
- account/templates/email/invite.html,sha256=bGBkV9PsAiGTsQ-7trD4-hdAIh2unWTH6fuLFL2HxSs,10567
52
+ account/templates/email/base.html,sha256=GUuatccaZtO_hLLNZmMQQKew1Bjfz3e6Z7p3dM6BrWk,9669
53
+ account/templates/email/invite.html,sha256=PnhMpf3KCnZ_2vRxRAGsRnGQU27xz0ZQhnn87_F9IFc,10346
54
54
  account/templates/email/plain/base.html,sha256=TTV8pqYGaKgzxJ7W8oZbMt2B_cNh8delFPHh-HynNv4,12600
55
- account/templates/email/plain/invite.html,sha256=Af6pcOrI4rtc4I7dasm3KlM3i1O6xljD1ZwvvtDsI2c,15235
56
- account/templates/email/plain/reset_code.html,sha256=X9lyllq8gd28BvDe9It99aA5lBmyKhhuzsBIplcDzXI,13954
57
- account/templates/email/reset_code.html,sha256=X5H7pJD-3kRL3xj_Uokf6Hs9aAQoeh1zFwmTtP2oVWY,10261
58
- account/templates/email/simple/invite.html,sha256=hI6DS9QbCcJcofPKsyQtkPVGhknALwsk8NAuOlmPorY,15147
59
- account/templates/email/simple/reset_code.html,sha256=Dln4C8jC-PI1ToS-k2VpRUjXyaHWx2udLnsIyRuM100,13944
55
+ account/templates/email/plain/invite.html,sha256=5WznpzALEWU5tRfKBdZXRMEq_Fe1Nqvl8qJpeiVZgzI,14692
56
+ account/templates/email/plain/reset_code.html,sha256=d-p0S2zav2RoJ7wAtsNIzsMxpapVhN3kyCacdjghcYI,13411
57
+ account/templates/email/reset_code.html,sha256=OxXSU4Whlqt7tVReA1LLZzhOgVXmkiAD6-96-upZtNk,10040
58
+ account/templates/email/simple/invite.html,sha256=mGXatb2n7UzcOU4KWFwxB_UQxbbFUXdpP90vSFmF_Z0,14604
59
+ account/templates/email/simple/reset_code.html,sha256=o07xdV_2em8dWfJtrgUv-xVfb48QnlnuPfbAc2ssTeM,13401
60
+ account/templates/unsubscribed.html,sha256=UVp2eM3yqmy6GYzWz1FStO2I7YpWnGuXFJcTtWDNUV0,46361
60
61
  auditlog/README,sha256=q4DXhdz5CuMyuxYISHXzhlHnIkRJlojwOMchLzW2qOI,520
61
62
  auditlog/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
63
  auditlog/admin.py,sha256=-q7fstdFjNeDFfbwdrxVqy0WGKxMpBwrsM7AyG1p80g,1006
@@ -87,7 +88,7 @@ inbox/models/template.py,sha256=i5vf0vsM1U0251UmVsF61MDCV_c7xt-zdCdx1SiKOG0,1013
87
88
  inbox/rpc.py,sha256=7JXvpXlEGKG7by_NkANPGYLCzagyCnTIGM4rme_htpk,1534
88
89
  inbox/utils/__init__.py,sha256=P_UR2rGK3L0tZNlTN-mf99tpeYM-tLkA18iDKXSSLDM,89
89
90
  inbox/utils/parsing.py,sha256=ae8JKm10qg6Q3dGhC29oDKKycN3yeDxI6e9SryPKxcY,4615
90
- inbox/utils/render.py,sha256=AvHROjo2ZG9dT5E1GB7ScEC8AoOogJLBriKkFP_sMYc,4218
91
+ inbox/utils/render.py,sha256=CU_F2qUBQE7mjb9Q6Dn9ro5CS_O_zEY-wDMHEClKkIA,4331
91
92
  inbox/utils/sending.py,sha256=BKelTZnbkdSLGpjOY6IRTrzj-Hnw2pPZ7RYQGwe-tqk,2179
92
93
  incident/README.md,sha256=4vbZTJj7uUmq8rogYngxqNYjFTlBOujfWUGheLoFKMc,1114
93
94
  incident/__init__.py,sha256=xgdt3z3z7ygjWv5HxhiWgBtB2W3IUJmmR88NSyUeHuo,3455
@@ -108,18 +109,18 @@ incident/migrations/0014_event_group_alter_rulecheck_index.py,sha256=v3gm5k0LVoa
108
109
  incident/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
109
110
  incident/models/__init__.py,sha256=NMphuhb0RTMf7Ov4QkNv7iv6_I8Wtr3xQ54yjX_a31M,209
110
111
  incident/models/event.py,sha256=WRNzvjo0jypdnQNBksOOyi-_0kVT4qWUrDZf0Aw_MPM,7355
111
- incident/models/incident.py,sha256=Jx0RnOo70BzPX4BLMVF8jB5UOYwFPKPlxWznkTeMzOU,19332
112
+ incident/models/incident.py,sha256=HPbi6J9qm7_-FMjnDUPV9NcbmP_60WU-IO9HJSpoLTY,19360
112
113
  incident/models/ossec.py,sha256=p1ptr-8lnaj1EP_VmPR58b2LmaYBGaYYKAMqhWK5yZM,2227
113
114
  incident/models/rules.py,sha256=SMlDRw_r3fGv-vmRojRLmsklqRRxDcjrSLVBIz-gadA,6884
114
115
  incident/models/ticket.py,sha256=S3kqGQpYLE6Y4M9IKu_60sgW-f592xNr8uufqHnvDoU,2302
115
116
  incident/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
116
- incident/parsers/ossec.py,sha256=Bc82n0AeXMBxMxzfAR-1puHyxldcikqeu5MeGRk1zMc,7142
117
+ incident/parsers/ossec.py,sha256=jBvZh5RAYSIRSm-sLrvwdIVDfJxNULxzanoaYI-Z2Tw,7881
117
118
  incident/periodic.py,sha256=eX1rQK6v65A9ugofTvJPSmAWei6C-3EYgzCMuGZ03jM,381
118
- incident/rpc.py,sha256=jGh1XaxDrTBIUK8Mw0ixqgPo-lqeP-MmUG1ApboAd1I,7933
119
- incident/templates/email/incident_change.html,sha256=UjFpZF1v310dWo1Kqu7SSvnEBwLSUgl0XWaCRSW8kkc,13883
120
- incident/templates/email/incident_msg.html,sha256=I2W3tXTcAQfFDoK024P77NIhFM-NnWhsJwwXTc7iGNk,13768
121
- incident/templates/email/incident_new.html,sha256=IPX3CqIrvdrZSn13_jlR6sEb0If8ftvUrUpkzC5G2Gc,15173
122
- incident/templates/email/incident_plain.html,sha256=fx4zsoldG1AQEBA6IYx5BJp_MAMizgjjx9EmuR5m4SQ,14727
119
+ incident/rpc.py,sha256=3y0rfxRR9DikmCmj3IRcMaCLtzLCMrtH64lrjY1w2Og,7992
120
+ incident/templates/email/incident_change.html,sha256=tQYphypwLukkVdwH0TB2Szz2VEJ7GnsfRS3_ZJ-MYeE,13895
121
+ incident/templates/email/incident_msg.html,sha256=MZdKhTddUF2MpiH8Z3RTQEmW_ko1n3ajeZ11KLtiLlU,13780
122
+ incident/templates/email/incident_new.html,sha256=W6nwFQROnyDfMlXub8s02ws4hGnJp16pfgp9xTm_aEc,15185
123
+ incident/templates/email/incident_plain.html,sha256=AyTv_3ITUwHoAO7Tv_xCODzWQXTV61EdtlphFum0BnM,14739
123
124
  incident/tq.py,sha256=6KjeTFlWAlG_l8LWMlxUGdr8ULU0uE-DB5ex0ERW440,5226
124
125
  location/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
125
126
  location/admin.py,sha256=6S97Rlgjkk0jM15sbT1OJRPZbgvKn2rn7duCSazOXq4,297
@@ -349,7 +350,7 @@ metrics/models.py,sha256=lD9nVzfwdav70ENulqJ8rE8Ui8EWlzdVp05rg8bAlMA,13444
349
350
  metrics/periodic.py,sha256=VmL0YG05D6k5fcNsF4QqPEU-BBPbZXjbOrp3b8EHZ-U,651
350
351
  metrics/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
351
352
  metrics/providers/aws.py,sha256=RDM5RLeFADHexm4cHaJdAm3K6iz1NwMSNcV9GYuGtjY,7432
352
- metrics/rpc.py,sha256=L6gjRAK7MNzu9haG7Uw9ECWDCdYWknM_ft7kYr4H0ts,20412
353
+ metrics/rpc.py,sha256=aPgE1yEIHM_9rdj0onMQZngxduq2Dr8EU8P2eFXPCBk,20558
353
354
  metrics/settings.py,sha256=wwHA9Z7BAHNeu3tFVn8Fh5j46KR-eGx0E8r5dzCFlAU,132
354
355
  metrics/tq.py,sha256=WHBRYSinmTuxF9l-_-lx0yfzEYkb0ffVMt_uvCj9bYo,825
355
356
  metrics/utils.py,sha256=w6H2v8zjlOZ5uqZsJOQvZoN-2Kyv1h8PN76gMGow7AE,11995
@@ -383,7 +384,7 @@ rest/extra/__init__.py,sha256=YzmNsch5H5FFLkUK9mIAKyoRK_rJCA9HGb0kubp4h30,54
383
384
  rest/extra/json_metadata.py,sha256=p_ffzmANmOFix_oC3voR6_NNTjcn7-T7aXcH-I4_Npg,1078
384
385
  rest/fields.py,sha256=_v1TJVc6vyWlqmwFRJ6mtuR5Fo-lS0KcUhPWIrzKZUo,9719
385
386
  rest/forms.py,sha256=66Wm5cdy8tKib_mGicjq_yd-gNVMFWRECnrDksnNnwU,6316
386
- rest/helpers.py,sha256=Af1EXjgf8JYMrP76rkgmB0SsEGES6iF9eam3jipcu48,28213
387
+ rest/helpers.py,sha256=l_vA0mdY4gZmOwzmqt-qB3DcF3aKkmteerXzJd2Qq7Q,28369
387
388
  rest/joke.py,sha256=0PpKaX2iN7jlS62kgjfmmqkFBYLPURz15aQ8R7OJkJ8,260
388
389
  rest/jwtoken.py,sha256=2BjRrnQSzm7ydHgYl6LIjfGW1YPmqjt-gDIo21O0WTk,2388
389
390
  rest/log.py,sha256=hd1_4HBOS395sfXJIL6BTw9yekm1SLgBwYx_PdfIhKA,20930
@@ -417,7 +418,7 @@ rest/serializers/legacy.py,sha256=a5O-x2PqMKX8wYWrhCmdcivVbkPnru7UdyLbrhCaAdY,61
417
418
  rest/serializers/localizers.py,sha256=BegaCvTQVaruhWzvGHq3zWeVFmtBChatquRqAtkke10,410
418
419
  rest/serializers/model.py,sha256=08HJeqpmytjxvyiJFfsSRRG0uH-iK2mXCw6w0oMfWrI,8598
419
420
  rest/serializers/profiler.py,sha256=OxOimhEyvCAuzUBC9Q1dz2xaakjAqmSnekMATsjduXM,997
420
- rest/serializers/response.py,sha256=hl5ruTWKML352Nob75uc3YGTplYmBu7OMjWeEWVEs9Y,7234
421
+ rest/serializers/response.py,sha256=nUUFITnTKPDtqD5qtSRzYHFqhsG1TxO7thH81Bq-8Vk,7602
421
422
  rest/serializers/util.py,sha256=-In89fpuVTd6_Ul8nwEUt3DjVKdpeoEyAxudlyB8K6Y,2734
422
423
  rest/settings_helper.py,sha256=_Vn9nmL5_GPss9zIsXzacbTQkn99NbO42CqvOZC3ge4,1532
423
424
  rest/ssl_check.py,sha256=kH4Pk4upUEwKTAnBLR0DIKezNJHjkW3g2TdQAObEgW4,1419
@@ -501,7 +502,7 @@ ws4redis/servers/uwsgi.py,sha256=VyhoCI1DnVFqBiJYHoxqn5Idlf6uJPHvfBKgkjs34mo,172
501
502
  ws4redis/settings.py,sha256=K0yBiLUuY81iDM4Yr-k8hbvjn5VVHu5zQhmMK8Dtz0s,1536
502
503
  ws4redis/utf8validator.py,sha256=S0OlfjeGRP75aO6CzZsF4oTjRQAgR17OWE9rgZdMBZA,5122
503
504
  ws4redis/websocket.py,sha256=R0TUyPsoVRD7Y_oU7w2I6NL4fPwiz5Vl94-fUkZgLHA,14848
504
- django_restit-4.2.73.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
505
- django_restit-4.2.73.dist-info/METADATA,sha256=On1RFDnzXlyZJmbbSLrg9QAPXMYm2vNuDmrX9OVCP8U,7645
506
- django_restit-4.2.73.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
507
- django_restit-4.2.73.dist-info/RECORD,,
505
+ django_restit-4.2.75.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
506
+ django_restit-4.2.75.dist-info/METADATA,sha256=JzZ59EQ9VakJIy_mZyWZ5SbCrdnxqSpI53sVs484TFU,7645
507
+ django_restit-4.2.75.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
508
+ django_restit-4.2.75.dist-info/RECORD,,
inbox/utils/render.py CHANGED
@@ -80,6 +80,7 @@ def renderTemplate(template, context, group=None):
80
80
  context["BASE_URL"] = settings.BASE_URL
81
81
  context["SITE_LOGO"] = settings.SITE_LOGO
82
82
  context["SERVER_NAME"] = settings.SERVER_NAME
83
+ context["UNSUBSCRIBE_URL"] = settings.get("UNSUBSCRIBE_URL", f"{settings.BASE_URL}/api/account/unsubscribe")
83
84
  context["version"] = settings.VERSION
84
85
  if "COMPANY_NAME" not in context and settings.COMPANY_NAME:
85
86
  context["COMPANY_NAME"] = settings.COMPANY_NAME
@@ -424,7 +424,7 @@ class Incident(models.Model, rm.RestModel, rm.MetaDataModel):
424
424
  else:
425
425
  # notitfy everyone but the sender
426
426
  if history.by is None:
427
- members = Member.GetWithPermission(perm).exclude(pk=history.by.pk)
427
+ members = Member.GetWithPermission(perm, ignore_disabled_email=True).exclude(pk=history.by.pk)
428
428
  if members.count() == 0:
429
429
  return
430
430
  NotificationRecord = Incident.getModel("account", "NotificationRecord")
incident/parsers/ossec.py CHANGED
@@ -43,6 +43,21 @@ def extractUrlPath(text):
43
43
  return None
44
44
 
45
45
 
46
+ def extractMetaData(alert):
47
+ irule = int(alert.rule_id)
48
+ if irule == 31301:
49
+ patterns = {
50
+ "src_ip": re.compile(r"Src IP: (\S+)"),
51
+ "path": re.compile(r"request: (\S+ \S+)"),
52
+ "http_server": re.compile(r"server: (\S+)"),
53
+ "http_host": re.compile(r"host: (\S+)"),
54
+ "http_referrer": re.compile(r"referrer: (\S+)")
55
+ }
56
+ # Search for matches in the text
57
+ return {key: pattern.search(alert.text).group(1) for key, pattern in patterns.items() if pattern.search(alert.text)}
58
+ return {}
59
+
60
+
46
61
  def parseAlert(request, data):
47
62
  # helpers.log_print(data)
48
63
  try:
@@ -121,7 +136,7 @@ def parseAlert(request, data):
121
136
  alert.level = 8
122
137
  alert.username = m.group(1)
123
138
  alert.ssh_sig = ssh_sig
124
- alert.ssh_king = kind
139
+ alert.ssh_kind = kind
125
140
  alert.title = f"SSH LOGIN:{alert.username}@{alert.hostname} from {alert.src_ip}"
126
141
  # member = findUserBySshSig(ssh_sig)
127
142
  # if member:
@@ -158,9 +173,13 @@ def parseAlert(request, data):
158
173
  elif irule == 31101:
159
174
  m = re.search(r"GET\s+(http://[^\s]+)\s+HTTP/\d\.\d\s+(\d+)", data.text)
160
175
  if m and m.groups():
161
- code = m.groups(2)
176
+ code = m.group(2)
162
177
  request_path = m.group(1)
163
178
  alert.title = f"HTTP {code}: {request_path}"
179
+ elif irule == 31301:
180
+ m = re.search(r"(\[error\]|\[crit\])[^\*]*\*\d*\s+(.*?),", text)
181
+ if m and len(m.groups()) >=2:
182
+ alert.title = error
164
183
  elif irule == 100020:
165
184
  m = re.search(r"\[(\S+)\]", data.text)
166
185
  if m and m.groups():
incident/rpc.py CHANGED
@@ -78,6 +78,7 @@ def ossec_alert_creat_from_request(request):
78
78
  elif od.level <= 3:
79
79
  level = 8
80
80
  metadata = od.toDict(graph="default")
81
+ metadata.update(ossec.extractMetaData(od))
81
82
  # we reuse the ssh_sig because it is a text field to store urls
82
83
  ssh_sig = metadata.get("ssh_sig", None)
83
84
  if ssh_sig is not None and ssh_sig.startswith("http"):
@@ -279,7 +279,7 @@ updated by: {% if history %}{{history.by.username}}{% else %}system{% endif %}
279
279
  <tr>
280
280
  <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
281
281
  <div style="font-family:Roboto, Helvetica, Arial, sans-serif;font-size:14px;font-weight:300;line-height:20px;text-align:center;color:#000000;">
282
- Don't like these emails? <a style="color: #c0c1ff;font-weight: bold;text-decoration: none;" href="{{BASE_URL}}member/unsubscribe/">Unsubscribe</a>.
282
+ Don't like these emails? <a style="color: #c0c1ff;font-weight: bold;text-decoration: none;" href="{{UNSUBSCRIBE_URL}}?t={{unsubscribe_token}}">Unsubscribe</a>.
283
283
  </div>
284
284
  </td>
285
285
  </tr>
@@ -278,7 +278,7 @@ New Message:
278
278
  <tr>
279
279
  <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
280
280
  <div style="font-family:Roboto, Helvetica, Arial, sans-serif;font-size:14px;font-weight:300;line-height:20px;text-align:center;color:#000000;">
281
- Don't like these emails? <a style="color: #c0c1ff;font-weight: bold;text-decoration: none;" href="{{BASE_URL}}member/unsubscribe/">Unsubscribe</a>.
281
+ Don't like these emails? <a style="color: #c0c1ff;font-weight: bold;text-decoration: none;" href="{{UNSUBSCRIBE_URL}}?t={{unsubscribe_token}}">Unsubscribe</a>.
282
282
  </div>
283
283
  </td>
284
284
  </tr>
@@ -296,7 +296,7 @@
296
296
  <tr>
297
297
  <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
298
298
  <div style="font-family:Roboto, Helvetica, Arial, sans-serif;font-size:14px;font-weight:300;line-height:20px;text-align:center;color:#000000;">
299
- Don't like these emails? <a style="color: #c0c1ff;font-weight: bold;text-decoration: none;" href="{{BASE_URL}}member/unsubscribe/">Unsubscribe</a>.
299
+ Don't like these emails? <a style="color: #c0c1ff;font-weight: bold;text-decoration: none;" href="{{UNSUBSCRIBE_URL}}?t={{unsubscribe_token}}">Unsubscribe</a>.
300
300
  </div>
301
301
  </td>
302
302
  </tr>
@@ -297,7 +297,7 @@ updated by: {% if history %}{{history.by.username}}{% else %}system{% endif %}
297
297
  <tr>
298
298
  <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
299
299
  <div style="font-family:Roboto, Helvetica, Arial, sans-serif;font-size:14px;font-weight:300;line-height:20px;text-align:center;color:#000000;">
300
- Don't like these emails? <a style="color: #c0c1ff;font-weight: bold;text-decoration: none;" href="{{BASE_URL}}member/unsubscribe/">Unsubscribe</a>.
300
+ Don't like these emails? <a style="color: #c0c1ff;font-weight: bold;text-decoration: none;" href="{{UNSUBSCRIBE_URL}}?t={{unsubscribe_token}}">Unsubscribe</a>.
301
301
  </div>
302
302
  </td>
303
303
  </tr>
metrics/rpc.py CHANGED
@@ -296,11 +296,17 @@ def rest_on_ec2_restit_stats(request, pk=None):
296
296
  host = f"{name}.{hostname}"
297
297
  else:
298
298
  host = f"{name}.{hostname}"
299
- resp = net.REQUEST("GET", host, f"/{REST_PREFIX}versions", params=dict(detailed=1))
299
+ resp = net.REQUEST(
300
+ "GET", host,
301
+ f"/{REST_PREFIX}versions",
302
+ params=dict(detailed=1),
303
+ timeout=5.0)
300
304
  if resp.status:
301
305
  resp.data.id = host
302
306
  resp.data.hostname = host
303
307
  data.append(resp.data)
308
+ else:
309
+ data.append(dict(id=host, hostname=host))
304
310
  return rv.restReturn(request, dict(data=data))
305
311
 
306
312
 
@@ -594,7 +600,7 @@ def rest_on_ec2_logs(request, pk=None):
594
600
  resp = net.REQUEST(
595
601
  "GET", host,
596
602
  f"/{REST_PREFIX}metrics/logs/nginx",
597
- headers=headers, params=params)
603
+ headers=headers, params=params, timeout=30.0)
598
604
  if resp.status and resp.data:
599
605
  logs.extend(resp.data)
600
606
  return rv.restReturn(request, dict(data=logs, size=len(logs), count=len(logs)))
rest/helpers.py CHANGED
@@ -471,7 +471,9 @@ def getContext(request, *args, **kwargs):
471
471
  "SITE_LOGO":settings.SITE_LOGO,
472
472
  "SERVER_NAME":settings.SERVER_NAME,
473
473
  "BASE_URL":settings.BASE_URL,
474
- "DISCLAIMER": settings.REST_DISCLAIMER
474
+ "DISCLAIMER": settings.REST_DISCLAIMER,
475
+ "COMPANY_LABEL": settings.COMPANY_LABEL,
476
+ "UNSUBSCRIBE_URL": settings.get("UNSUBSCRIBE_URL", f"{settings.BASE_URL}api/account/unsubscribe")
475
477
  }
476
478
 
477
479
  if request:
@@ -147,6 +147,14 @@ def restExcel(request, qset, fields, name, size=10000, localize=None, **kwargs):
147
147
  return excel.qsetToExcel(request, qset[:size], fields, name)
148
148
 
149
149
 
150
+ def restHTML(request, html_content=None, template=None, context=None, status=200):
151
+ if not html_content and not template:
152
+ return HttpResponse("<html><body><h1>Hello, World!</h1><p>Welcome to my site.</p></body></html>")
153
+ if template:
154
+ return render(request, template, context, status=status)
155
+ return HttpResponse(html_content, status=status)
156
+
157
+
150
158
  def parse_accept_list(request):
151
159
  if request and hasattr(request, "DATA") and request.DATA.get('_type', None) is not None:
152
160
  accept_list = [request.DATA.get('_type')]