Files
Stend_mont/app/main.py
T
ruslan efa1c26e5d Email improvements: domain-aware portal URL, embedded logo, fix product list color
- Store request origin domain in PendingAccessRequest.portal_url
- Use per-request portal URL in approval/rejection emails
- Embed logo as base64 so it displays without external image loading
- Fix 'Предоставлен доступ к продуктам' text color to match body color
- Switch Telegram polling to 30-second interval with single-worker flock fix
2026-05-29 16:10:40 +00:00

2110 lines
260 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import datetime as dt
import logging
import re
import secrets
import threading
import uuid
import time
import contextvars
from typing import Optional
from fastapi import Depends, FastAPI, File, Form, HTTPException, Query, Request, UploadFile, status
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from markupsafe import Markup, escape
from sqlalchemy import select
from sqlalchemy import delete, select, text, update
from sqlalchemy.orm import Session
from starlette.responses import HTMLResponse as _HR
import urllib.request as _urllib_request
import urllib.parse as _urllib_parse
import json as _json
from config import (
COOKIE_NAME, CSRF_COOKIE, GO_POOL_LOCK_TIMEOUT_SECONDS,
GO_USER_LOCK_TIMEOUT_SECONDS, LOG_LEVEL, LOG_SLOW_REQUEST_MS,
MAX_ACTIVE_SERVICES_PER_USER, PUBLIC_HOST, SESSION_IDLE_SECONDS,
WEB_POOL_BUFFER, WEB_POOL_SIZE,
TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, TELEGRAM_API_URL,
SMTP_HOST, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD,
SMTP_FROM_EMAIL, SMTP_FROM_NAME, PORTAL_URL,
)
from database import get_db
from models import (
AuditLog, Category, RdpSlot, Service, ServiceCategory, ServiceType,
PendingAccessRequest, SessionModel, SessionStatus, User, UserServiceAccess,
)
from utils import (
audit, ensure_icons_dir, format_service_comment, log_event, normalize_web_target,
now_utc, parse_rdp_target, remove_icon_file, request_id_ctx, set_service_categories,
session_closed_reason, store_service_icon,
)
from auth import (
get_current_user, has_access, issue_auth_cookie, issue_csrf_cookie,
require_admin, require_user, user_is_valid, validate_csrf, verify_password, hash_password,
)
from runtime import (
acquire_universal_slot, acquire_web_pool_slot, allocator_lock,
container_running, create_runtime_container, desired_pool_size,
dispatch_universal_target, dispatch_web_pool_target,
docker_client, ensure_universal_pool, ensure_warm_pool, ensure_web_pool,
find_active_session_for_service, find_active_session_for_user_service,
get_active_sessions_count, get_pool_detailed_status, get_pool_status_for_service,
get_universal_pool_status, get_web_pool_status, LockTimeoutError, open_warm_web_url,
_rdp_slot_container_name, route_ready, sanitize_client_resolution,
service_uses_universal_pool, session_redirect_url,
connect_rdp_slot, start_rdp_slot_container, stop_rdp_slot_container,
stop_runtime_container, terminate_active_slot_sessions,
terminate_session_record, wait_for_session_route,
)
from maintenance import on_startup
logging.basicConfig(
level=LOG_LEVEL,
format="%(asctime)s %(levelname)s %(name)s %(message)s",
)
logger = logging.getLogger("portal")
templates = Jinja2Templates(directory="templates")
def _get_real_ip(request) -> str:
"""Real client IP from X-Forwarded-For (Traefik trusts NPM via trustedIPs)."""
forwarded_for = request.headers.get("x-forwarded-for", "")
if forwarded_for:
return forwarded_for.split(",")[0].strip()
return request.client.host if request.client else "unknown"
def _get_geo(ip: str) -> str:
"""Lookup city/country for IP via ip-api.com. Returns formatted string or empty."""
try:
if ip in ("unknown", "127.0.0.1", "::1") or ip.startswith("10.") or ip.startswith("192.168."):
return ""
url = f"http://ip-api.com/json/{ip}?lang=ru&fields=status,country,regionName,city,query"
req = _urllib_request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
with _urllib_request.urlopen(req, timeout=5) as resp:
data = _json.loads(resp.read())
if data.get("status") == "success":
parts = [data.get("country", ""), data.get("regionName", ""), data.get("city", "")]
return ", ".join(p for p in parts if p)
except Exception:
pass
return ""
import secrets as _secrets
import string as _string
import smtplib as _smtplib
import ssl as _ssl
import json as _json2
from email.mime.multipart import MIMEMultipart as _MIMEMultipart
from email.mime.text import MIMEText as _MIMEText
def _generate_password(length: int = 10) -> str:
alphabet = _string.ascii_letters + _string.digits
while True:
pwd = ''.join(_secrets.choice(alphabet) for _ in range(length))
if (any(c.isupper() for c in pwd) and any(c.islower() for c in pwd)
and any(c.isdigit() for c in pwd)):
return pwd
def _send_email(to: str, subject: str, html_body: str) -> None:
msg = _MIMEMultipart("alternative")
msg["Subject"] = subject
msg["From"] = f"{SMTP_FROM_NAME} <{SMTP_FROM_EMAIL}>"
msg["To"] = to
msg.attach(_MIMEText(html_body, "html", "utf-8"))
ctx = _ssl.create_default_context()
with _smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT, context=ctx) as srv:
srv.login(SMTP_USERNAME, SMTP_PASSWORD)
srv.sendmail(SMTP_FROM_EMAIL, to, msg.as_string())
def _tg_api(method: str, payload: dict) -> dict:
import urllib.request as _ur
import json as _j
url = f"{TELEGRAM_API_URL}{TELEGRAM_BOT_TOKEN}/{method}"
data = _j.dumps(payload).encode()
req = _ur.Request(url, data=data, headers={"Content-Type": "application/json"})
with _ur.urlopen(req, timeout=10) as r:
return _j.loads(r.read())
def _make_approval_keyboard(req_id: str) -> dict:
return {
"inline_keyboard": [
[
{"text": "7 дней", "callback_data": f"a7_{req_id}"},
{"text": "14 дней", "callback_data": f"a14_{req_id}"},
{"text": "30 дней", "callback_data": f"a30_{req_id}"},
{"text": "90 дней", "callback_data": f"a90_{req_id}"},
],
[{"text": "Отказать", "callback_data": f"r_{req_id}"}],
]
}
_tg_poll_offset: int = 0
_tg_poll_lock_file = None
async def _telegram_poll_loop():
"""Poll Telegram for callback_query updates every 5 minutes."""
import asyncio as _asyncio
import json as _jp
global _tg_poll_offset
await _asyncio.sleep(10) # wait for app to fully start
while True:
try:
result = _tg_api("getUpdates", {
"offset": _tg_poll_offset,
"timeout": 0,
"allowed_updates": ["callback_query"],
})
updates = result.get("result", [])
for upd in updates:
_tg_poll_offset = upd["update_id"] + 1
cq = upd.get("callback_query")
if cq:
try:
await _process_callback_query(cq)
except Exception as ex:
log_event("tg_callback_error", error=str(ex))
except Exception as ex:
log_event("tg_poll_error", error=str(ex))
await _asyncio.sleep(30) # 30 seconds
async def _process_callback_query(cq: dict):
import json as _jc
import datetime as _dtc
import re as _rec
from database import SessionLocal as _SL
cq_id = cq["id"]
cb_data = cq.get("data", "")
chat_id = cq["message"]["chat"]["id"]
msg_id = cq["message"]["message_id"]
try:
_tg_api("answerCallbackQuery", {"callback_query_id": cq_id})
except Exception:
pass
approve_match = _rec.match(r'^a(\d+)_(.+)$', cb_data)
reject_match = _rec.match(r'^r_(.+)$', cb_data)
if not approve_match and not reject_match:
return
req_id = approve_match.group(2) if approve_match else reject_match.group(1)
db = _SL()
try:
pending = db.get(PendingAccessRequest, req_id)
if not pending:
_tg_api("editMessageText", {
"chat_id": chat_id, "message_id": msg_id,
"text": "Запрос не найден (возможно уже обработан).",
})
return
if pending.status != "pending":
_tg_api("editMessageText", {
"chat_id": chat_id, "message_id": msg_id,
"text": f"Запрос уже обработан: {pending.status}.",
})
return
products = _jc.loads(pending.products_json or "[]")
portal_url = pending.portal_url or PORTAL_URL
if approve_match:
days = int(approve_match.group(1))
password = _generate_password()
username = pending.email
if db.scalar(select(User).where(User.username == username)):
import secrets as _sec
username = pending.email.split("@")[0] + "_" + _sec.token_hex(3)
expires = _dtc.datetime.now(_dtc.timezone.utc) + _dtc.timedelta(days=days)
parts = pending.name.strip().split(None, 1)
new_user = User(
username=username,
password_hash=hash_password(password),
expires_at=expires,
active=True,
is_admin=False,
first_name=parts[0] if parts else "",
last_name=parts[1] if len(parts) > 1 else "",
)
db.add(new_user)
db.flush()
if products:
from sqlalchemy import func as _func2
matched = db.scalars(
select(Service).where(
_func2.lower(Service.name).in_([p.lower() for p in products]),
Service.active == True,
)
).all()
for svc in matched:
db.add(UserServiceAccess(user_id=new_user.id, service_id=svc.id))
db.commit()
products_html = ""
if products:
items = "".join(f"<li>{p}</li>" for p in products)
products_html = (
'<p style="margin:16px 0 6px;color:#c8d8ea"><b>Предоставлен доступ к продуктам:</b></p>'
f'<ul style="margin:0;padding-left:20px;color:#c8d8ea">{items}</ul>'
)
day_word = "день" if days == 1 else ("дня" if days < 5 else "дней")
html_email = f"""<!DOCTYPE html>
<html lang="ru"><head><meta charset="utf-8"/></head>
<body style="margin:0;padding:0;background:#0a1929;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif">
<table width="100%" cellpadding="0" cellspacing="0"><tr><td align="center" style="padding:40px 20px">
<table width="560" cellpadding="0" cellspacing="0" style="background:linear-gradient(150deg,#0b1a2e,#0d2040);border-radius:16px;overflow:hidden;border:1px solid rgba(255,255,255,0.08)">
<tr><td style="padding:32px 36px 0">
<img src="data:image/png;base64,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" alt="MONT" height="40" style="margin-bottom:24px"/><br>
<h1 style="margin:0 0 8px;font-size:22px;color:#e8f1fb">Доступ к Инфраструктурному полигону MONT</h1>
<p style="margin:0 0 24px;color:#7a9abd;font-size:14px">Ваш запрос одобрен</p>
<hr style="border:none;border-top:1px solid rgba(255,255,255,0.08);margin:0 0 24px"/>
</td></tr>
<tr><td style="padding:0 36px">
<p style="color:#c8d8ea;font-size:15px;line-height:1.6;margin:0 0 20px">Здравствуйте, <b>{pending.name}</b>!<br>
Вам предоставлен доступ к полигону на <b>{days} {day_word}</b>.</p>
<table width="100%" cellpadding="12" cellspacing="0" style="background:rgba(255,255,255,0.04);border-radius:10px;border:1px solid rgba(255,255,255,0.07)">
<tr><td style="color:#7a9abd;font-size:13px;width:40%">Адрес портала</td>
<td><a href="{portal_url}" style="color:#5b9bd5;font-size:14px">{portal_url}</a></td></tr>
<tr><td style="color:#7a9abd;font-size:13px;border-top:1px solid rgba(255,255,255,0.06)">Логин</td>
<td style="border-top:1px solid rgba(255,255,255,0.06);color:#e8f1fb;font-size:14px;font-family:monospace">{username}</td></tr>
<tr><td style="color:#7a9abd;font-size:13px;border-top:1px solid rgba(255,255,255,0.06)">Пароль</td>
<td style="border-top:1px solid rgba(255,255,255,0.06);color:#e8f1fb;font-size:14px;font-family:monospace">{password}</td></tr>
<tr><td style="color:#7a9abd;font-size:13px;border-top:1px solid rgba(255,255,255,0.06)">Доступ до</td>
<td style="border-top:1px solid rgba(255,255,255,0.06);color:#e8f1fb;font-size:14px">{expires.strftime("%d.%m.%Y")}</td></tr>
</table>
{products_html}
<div style="margin:28px 0">
<a href="{portal_url}" style="display:inline-block;padding:12px 28px;background:linear-gradient(135deg,#1a5db5,#2d8cf0);color:#fff;text-decoration:none;border-radius:8px;font-size:15px;font-weight:600">Войти в полигон</a>
</div>
</td></tr>
<tr><td style="padding:20px 36px 28px;color:#4a6a8a;font-size:12px;border-top:1px solid rgba(255,255,255,0.06);line-height:1.6">
Если у вас возникли вопросы, свяжитесь с вашим менеджером MONT или напишите на <a href="mailto:mont@mont.ru" style="color:#5b9bd5">mont@mont.ru</a>
</td></tr>
</table></td></tr></table>
</body></html>"""
pending.status = "approved"
db.commit()
try:
_send_email(pending.email, "Доступ к Инфраструктурному полигону MONT", html_email)
email_status = "Email отправлен"
except Exception as ex:
log_event("email_send_error", error=str(ex))
email_status = f"Ошибка email: {ex}"
_tg_api("editMessageText", {
"chat_id": chat_id, "message_id": msg_id,
"text": (
f"✅ Одобрено на {days} {day_word}\n"
f"👤 Логин: `{username}`\n"
f"🔑 Пароль: `{password}`\n"
f"📧 {email_status}"
),
"parse_mode": "Markdown",
})
elif reject_match:
manager_contact = pending.manager if pending.manager else "менеджера MONT"
html_email = f"""<!DOCTYPE html>
<html lang="ru"><head><meta charset="utf-8"/></head>
<body style="margin:0;padding:0;background:#0a1929;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif">
<table width="100%" cellpadding="0" cellspacing="0"><tr><td align="center" style="padding:40px 20px">
<table width="560" cellpadding="0" cellspacing="0" style="background:linear-gradient(150deg,#0b1a2e,#0d2040);border-radius:16px;overflow:hidden;border:1px solid rgba(255,255,255,0.08)">
<tr><td style="padding:32px 36px 0">
<img src="data:image/png;base64,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" alt="MONT" height="40" style="margin-bottom:24px"/><br>
<h1 style="margin:0 0 8px;font-size:22px;color:#e8f1fb">Запрос на доступ к полигону MONT</h1>
<hr style="border:none;border-top:1px solid rgba(255,255,255,0.08);margin:16px 0 24px"/>
</td></tr>
<tr><td style="padding:0 36px">
<p style="color:#c8d8ea;font-size:15px;line-height:1.7;margin:0 0 20px">Здравствуйте, <b>{pending.name}</b>!<br><br>
К сожалению, на данный момент мы не можем предоставить доступ к полигону.</p>
<p style="color:#c8d8ea;font-size:15px;line-height:1.7;margin:0 0 24px">
Для уточнения деталей свяжитесь с <b>{manager_contact}</b>.<br>
Если не знаете кто ваш менеджер — напишите на <a href="mailto:mont@mont.ru" style="color:#5b9bd5">mont@mont.ru</a>.</p>
</td></tr>
<tr><td style="padding:20px 36px 28px;color:#4a6a8a;font-size:12px;border-top:1px solid rgba(255,255,255,0.06)">
С уважением, команда MONT
</td></tr>
</table></td></tr></table>
</body></html>"""
pending.status = "rejected"
db.commit()
try:
_send_email(pending.email, "Запрос на доступ к полигону MONT", html_email)
email_status = "Email отправлен"
except Exception as ex:
log_event("email_send_error", error=str(ex))
email_status = f"Ошибка email: {ex}"
_tg_api("editMessageText", {
"chat_id": chat_id, "message_id": msg_id,
"text": f"❌ Отклонено. {email_status}",
})
finally:
db.close()
app = FastAPI(title="MONT - инфрастуктурный полигон")
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.middleware("http")
async def request_logging_middleware(request: Request, call_next):
req_id = request.headers.get("X-Request-ID", str(uuid.uuid4())[:8])
token = request_id_ctx.set(req_id)
started = time.time()
client_ip = request.client.host if request.client else "-"
user_agent = request.headers.get("user-agent", "-")
try:
response = await call_next(request)
except Exception:
log_event(
"request_failed",
level=logging.ERROR,
method=request.method,
path=request.url.path,
client_ip=client_ip,
user_agent=user_agent,
)
request_id_ctx.reset(token)
raise
duration_ms = int((time.time() - started) * 1000)
level = logging.INFO
if response.status_code >= 500:
level = logging.ERROR
elif response.status_code >= 400:
level = logging.WARNING
log_event(
"request",
level=level,
method=request.method,
path=request.url.path,
query=str(request.url.query or ""),
status=response.status_code,
duration_ms=duration_ms,
client_ip=client_ip,
user_agent=user_agent,
)
if duration_ms >= LOG_SLOW_REQUEST_MS:
log_event(
"slow_request",
level=logging.WARNING,
method=request.method,
path=request.url.path,
duration_ms=duration_ms,
threshold_ms=LOG_SLOW_REQUEST_MS,
)
response.headers["X-Request-ID"] = req_id
request_id_ctx.reset(token)
return response
_MOBILE_UA_RE = re.compile(
r"(Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|webOS)",
re.IGNORECASE,
)
_MOBILE_PAGE = (
"<!doctype html>"
'<html lang="ru">'
"<head>"
'<meta charset="utf-8"/>'
'<meta name="viewport" content="width=device-width,initial-scale=1"/>'
"<title>MONT - инфрастуктурный полигон</title>"
"<style>"
"*{box-sizing:border-box;margin:0;padding:0}"
"body{min-height:100dvh;display:flex;flex-direction:column;align-items:center;"
"justify-content:center;background:linear-gradient(160deg,#0a2a4a 0%,#1565a0 60%,#1e88c8 100%);"
"font-family:sans-serif;color:#fff;padding:2rem 1.5rem;text-align:center}"
".logo{width:120px;margin-bottom:2rem}"
"h1{font-size:1.3rem;font-weight:700;margin-bottom:1rem;line-height:1.35}"
"p{font-size:0.95rem;color:rgba(255,255,255,.75);line-height:1.5;max-width:280px}"
".icon{font-size:3.5rem;margin-bottom:1.2rem}"
"</style>"
"</head>"
"<body>"
'<img class="logo" src="/static/logo.png" alt="MONT"/>'
'<div class="icon">&#128421;</div>'
"<h1>Ресурс доступен<br>только с ПК</h1>"
"<p>Пожалуйста, откройте эту страницу на компьютере или ноутбуке.</p>"
"</body>"
"</html>"
)
@app.middleware("http")
async def mobile_block_middleware(request: Request, call_next):
path = request.url.path
if path.startswith("/static/"):
return await call_next(request)
ua = request.headers.get("user-agent", "")
if _MOBILE_UA_RE.search(ua):
return _HR(content=_MOBILE_PAGE, status_code=200)
return await call_next(request)
@app.on_event("startup")
async def startup_event():
global _tg_poll_lock_file
on_startup()
import asyncio as _aio, fcntl as _fcntl
_lf = open("/tmp/portal-tg-poll.lock", "w")
try:
_fcntl.flock(_lf.fileno(), _fcntl.LOCK_EX | _fcntl.LOCK_NB)
_tg_poll_lock_file = _lf
_aio.create_task(_telegram_poll_loop())
except BlockingIOError:
_lf.close()
@app.get("/", response_class=HTMLResponse)
def index(request: Request, user: Optional[User] = Depends(get_current_user), db: Session = Depends(get_db)):
session_closed = (request.query_params.get("session_closed") or "").strip().lower()
launch_error = (request.query_params.get("launch_error") or "").strip().lower()
session_notice = ""
if session_closed == "idle":
session_notice = "Сессия была закрыта из-за простоя. Откройте сервис заново."
elif session_closed == "limit":
session_notice = (
f"Сессия была закрыта из-за лимита в {MAX_ACTIVE_SERVICES_PER_USER} сервиса(ов). "
"Освободите один сервис и попробуйте снова."
)
elif launch_error == "max_services":
session_notice = (
f"Есть ограничение на {MAX_ACTIVE_SERVICES_PER_USER} сервиса(ов). "
"Освободите один сервис и попробуйте снова."
)
if not user:
csrf = request.cookies.get(CSRF_COOKIE) or secrets.token_urlsafe(24)
response = templates.TemplateResponse(
"login.html",
{
"request": request,
"csrf_token": csrf,
"login_error": "",
"session_notice": session_notice,
},
)
response.set_cookie(CSRF_COOKIE, csrf, httponly=False, secure=True, samesite="lax", path="/")
return response
services = db.scalars(
select(Service)
.join(UserServiceAccess, UserServiceAccess.service_id == Service.id)
.where(
UserServiceAccess.user_id == user.id,
Service.active == True,
Service.type.in_([ServiceType.WEB, ServiceType.RDP]),
)
.order_by(Service.name)
).all()
service_categories = {svc.id: [] for svc in services}
categories = []
if services:
service_ids = [svc.id for svc in services]
rows = db.execute(
select(ServiceCategory.service_id, Category.id, Category.name, Category.slug)
.join(Category, Category.id == ServiceCategory.category_id)
.where(ServiceCategory.service_id.in_(service_ids))
.order_by(Category.name)
).all()
category_map = {}
for service_id, category_id, category_name, category_slug in rows:
service_categories.setdefault(service_id, []).append(
{
"id": category_id,
"name": category_name,
"slug": category_slug,
}
)
if category_id not in category_map:
category_map[category_id] = {"id": category_id, "name": category_name, "slug": category_slug}
categories = sorted(category_map.values(), key=lambda x: x["name"].lower())
selected_category_slug = (request.query_params.get("category") or "").strip().lower()
if selected_category_slug:
services = [
svc for svc in services
if any(cat["slug"] == selected_category_slug for cat in service_categories.get(svc.id, []))
]
service_comment_html = {svc.id: format_service_comment(svc.comment) for svc in services}
return templates.TemplateResponse(
"dashboard.html",
{
"request": request,
"user": user,
"services": services,
"categories": categories,
"selected_category_slug": selected_category_slug,
"service_categories": service_categories,
"service_comment_html": service_comment_html,
"csrf_token": request.cookies.get(CSRF_COOKIE, ""),
"session_notice": session_notice,
},
)
@app.get("/admin", response_class=HTMLResponse)
def admin_page(request: Request, admin: User = Depends(require_admin), db: Session = Depends(get_db)):
users = db.scalars(select(User).order_by(User.id)).all()
categories = db.scalars(select(Category).order_by(Category.name)).all()
services = db.scalars(select(Service).where(Service.type.in_([ServiceType.WEB, ServiceType.RDP])).order_by(Service.id)).all()
web_services = [s for s in services if s.type == ServiceType.WEB]
rdp_services = [s for s in services if s.type == ServiceType.RDP]
service_category_map = {s.id: [] for s in services}
if services:
service_rows = db.execute(
select(ServiceCategory.service_id, ServiceCategory.category_id).where(
ServiceCategory.service_id.in_([s.id for s in services])
)
).all()
for service_id, category_id in service_rows:
service_category_map.setdefault(service_id, []).append(category_id)
acl_rows = db.scalars(select(UserServiceAccess)).all()
acl = {}
for row in acl_rows:
acl.setdefault(row.user_id, []).append(row.service_id)
for user_id in acl:
acl[user_id] = sorted(acl[user_id])
pool_status = {s.id: get_pool_status_for_service(s) for s in services}
service_health = {}
for sid, st in pool_status.items():
service_health[sid] = {
"health": st["health"],
"running": st["running"],
"desired": st["desired"],
"active_sessions": get_active_sessions_count(db, sid),
}
web_pool = get_web_pool_status()
web_totals = {
"services": len(web_services),
"running": web_pool["running"],
"desired": web_pool["desired"],
"active_sessions": sum(service_health[s.id]["active_sessions"] for s in web_services),
}
recent_sessions = db.execute(
text(
"""
SELECT s.id, u.username, sv.name AS service_name, sv.slug AS service_slug,
s.status, s.created_at, s.last_access_at
FROM sessions s
JOIN users u ON u.id = s.user_id
JOIN services sv ON sv.id = s.service_id
WHERE sv.type IN ('WEB','RDP')
ORDER BY s.created_at DESC
LIMIT 200
"""
)
).mappings().all()
open_stats = db.execute(
text(
"""
SELECT u.username, sv.name AS service_name, sv.slug AS service_slug, COUNT(*) AS opens
FROM sessions s
JOIN users u ON u.id = s.user_id
JOIN services sv ON sv.id = s.service_id
WHERE sv.type IN ('WEB','RDP')
GROUP BY u.username, sv.name, sv.slug
ORDER BY opens DESC, u.username ASC
LIMIT 200
"""
)
).mappings().all()
cutoff = now_utc() - dt.timedelta(seconds=SESSION_IDLE_SECONDS)
online_sessions = db.execute(
text(
"""
SELECT s.id, u.username, sv.name AS service_name, sv.slug AS service_slug,
sv.type AS service_type, s.container_id, s.created_at, s.last_access_at
FROM sessions s
JOIN users u ON u.id = s.user_id
JOIN services sv ON sv.id = s.service_id
WHERE s.status = 'ACTIVE'
AND s.last_access_at >= :cutoff
AND sv.type IN ('WEB','RDP')
ORDER BY s.last_access_at DESC, s.created_at DESC
LIMIT 500
"""
),
{"cutoff": cutoff},
).mappings().all()
rdp_slots: dict[int, list] = {}
for svc in rdp_services:
slots = db.scalars(select(RdpSlot).where(RdpSlot.service_id == svc.id).order_by(RdpSlot.id)).all()
slot_list = []
for slot in slots:
active_sess = db.scalar(
select(SessionModel).where(
SessionModel.container_id == f"RDPSLOT:{slot.id}",
SessionModel.status == SessionStatus.ACTIVE,
)
)
running = False
if slot.container_name:
try:
c = docker_client().containers.get(slot.container_name)
running = c.status == "running"
except Exception:
pass
occupied_username = None
if active_sess:
u = db.get(User, active_sess.user_id)
occupied_username = u.username if u else f"id={active_sess.user_id}"
slot_list.append({
"id": slot.id,
"rdp_username": slot.rdp_username,
"container_name": slot.container_name or "",
"running": running,
"occupied_username": occupied_username,
})
rdp_slots[svc.id] = slot_list
return templates.TemplateResponse(
"admin.html",
{
"request": request,
"admin": admin,
"users": users,
"web_services": web_services,
"rdp_services": rdp_services,
"services": services,
"categories": categories,
"service_category_map": service_category_map,
"acl": acl,
"pool_status": pool_status,
"service_health": service_health,
"web_totals": web_totals,
"web_pool_size": WEB_POOL_SIZE,
"web_pool_buffer": WEB_POOL_BUFFER,
"recent_sessions": recent_sessions,
"open_stats": open_stats,
"online_sessions": online_sessions,
"csrf_token": request.cookies.get(CSRF_COOKIE, ""),
"max_active_services_per_user": MAX_ACTIVE_SERVICES_PER_USER,
"rdp_slots": rdp_slots,
},
)
@app.get("/yandex_b847b9b35f967fcc.html", include_in_schema=False)
def yandex_verify():
from fastapi.responses import HTMLResponse
return HTMLResponse('''<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>Verification: b847b9b35f967fcc</body>
</html>''')
@app.get("/privacy", include_in_schema=False)
def privacy_page():
from fastapi.responses import RedirectResponse
return RedirectResponse(url="https://www.mont.ru/ru-ru/privacy", status_code=301)
@app.post("/api/telegram-webhook", include_in_schema=False)
async def telegram_webhook(request: Request, db: Session = Depends(get_db)):
import json as _jw
import datetime as _dt2
try:
data = await request.json()
except Exception:
return {"ok": True}
cq = data.get("callback_query")
if not cq:
return {"ok": True}
cq_id = cq["id"]
cb_data = cq.get("data", "")
chat_id = cq["message"]["chat"]["id"]
msg_id = cq["message"]["message_id"]
try:
_tg_api("answerCallbackQuery", {"callback_query_id": cq_id})
except Exception:
pass
# parse callback_data: a7_ID, a14_ID, a30_ID, a90_ID, r_ID
import re as _rew
approve_match = _rew.match(r'^a(\d+)_(.+)$', cb_data)
reject_match = _rew.match(r'^r_(.+)$', cb_data)
if not approve_match and not reject_match:
return {"ok": True}
req_id = approve_match.group(2) if approve_match else reject_match.group(1)
pending = db.get(PendingAccessRequest, req_id)
if not pending:
try:
_tg_api("editMessageText", {
"chat_id": chat_id, "message_id": msg_id,
"text": "Запрос не найден (возможно уже обработан).",
})
except Exception:
pass
return {"ok": True}
if pending.status != "pending":
try:
_tg_api("editMessageText", {
"chat_id": chat_id, "message_id": msg_id,
"text": f"Запрос уже обработан: {pending.status}.",
})
except Exception:
pass
return {"ok": True}
products = _jw.loads(pending.products_json or "[]")
portal_url = pending.portal_url or PORTAL_URL
if approve_match:
days = int(approve_match.group(1))
password = _generate_password()
username = pending.email
# ensure username unique
if db.scalar(select(User).where(User.username == username)):
username = pending.email.split("@")[0] + "_" + _secrets.token_hex(3)
expires = _dt2.datetime.now(_dt2.timezone.utc) + _dt2.timedelta(days=days)
parts = pending.name.strip().split(None, 1)
new_user = User(
username=username,
password_hash=hash_password(password),
expires_at=expires,
active=True,
is_admin=False,
first_name=parts[0] if parts else "",
last_name=parts[1] if len(parts) > 1 else "",
)
db.add(new_user)
db.flush()
# assign requested services
if products:
from sqlalchemy import func as _func
matched = db.scalars(
select(Service).where(
func.lower(Service.name).in_([p.lower() for p in products]),
Service.active == True,
)
).all()
for svc in matched:
db.add(UserServiceAccess(user_id=new_user.id, service_id=svc.id))
db.commit()
# send approval email
products_html = ""
if products:
items = "".join(f"<li>{p}</li>" for p in products)
products_html = f"<p style='margin:16px 0 6px;color:#c8d8ea'><b>Предоставлен доступ к продуктам:</b></p><ul style='margin:0;padding-left:20px;color:#c8d8ea'>{items}</ul>"
html_email = f"""<!DOCTYPE html>
<html lang="ru"><head><meta charset="utf-8"/></head>
<body style="margin:0;padding:0;background:#0a1929;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif">
<table width="100%" cellpadding="0" cellspacing="0"><tr><td align="center" style="padding:40px 20px">
<table width="560" cellpadding="0" cellspacing="0" style="background:linear-gradient(150deg,#0b1a2e,#0d2040);border-radius:16px;overflow:hidden;border:1px solid rgba(255,255,255,0.08)">
<tr><td style="padding:32px 36px 0">
<img src="data:image/png;base64,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" alt="MONT" height="40" style="margin-bottom:24px"/><br>
<h1 style="margin:0 0 8px;font-size:22px;color:#e8f1fb">Доступ к Инфраструктурному полигону MONT</h1>
<p style="margin:0 0 24px;color:#7a9abd;font-size:14px">Ваш запрос одобрен</p>
<hr style="border:none;border-top:1px solid rgba(255,255,255,0.08);margin:0 0 24px"/>
</td></tr>
<tr><td style="padding:0 36px">
<p style="color:#c8d8ea;font-size:15px;line-height:1.6;margin:0 0 20px">Здравствуйте, <b>{pending.name}</b>!<br>
Вам предоставлен доступ к полигону на <b>{days} {'день' if days==1 else 'дня' if days<5 else 'дней'}</b>.</p>
<table width="100%" cellpadding="12" cellspacing="0" style="background:rgba(255,255,255,0.04);border-radius:10px;border:1px solid rgba(255,255,255,0.07)">
<tr><td style="color:#7a9abd;font-size:13px;width:40%">Адрес портала</td>
<td><a href="{portal_url}" style="color:#5b9bd5;font-size:14px">{portal_url}</a></td></tr>
<tr><td style="color:#7a9abd;font-size:13px;border-top:1px solid rgba(255,255,255,0.06)">Логин</td>
<td style="border-top:1px solid rgba(255,255,255,0.06);color:#e8f1fb;font-size:14px;font-family:monospace">{username}</td></tr>
<tr><td style="color:#7a9abd;font-size:13px;border-top:1px solid rgba(255,255,255,0.06)">Пароль</td>
<td style="border-top:1px solid rgba(255,255,255,0.06);color:#e8f1fb;font-size:14px;font-family:monospace">{password}</td></tr>
<tr><td style="color:#7a9abd;font-size:13px;border-top:1px solid rgba(255,255,255,0.06)">Доступ до</td>
<td style="border-top:1px solid rgba(255,255,255,0.06);color:#e8f1fb;font-size:14px">{expires.strftime('%d.%m.%Y')}</td></tr>
</table>
{products_html}
<div style="margin:28px 0">
<a href="{portal_url}" style="display:inline-block;padding:12px 28px;background:linear-gradient(135deg,#1a5db5,#2d8cf0);color:#fff;text-decoration:none;border-radius:8px;font-size:15px;font-weight:600">Войти в полигон</a>
</div>
</td></tr>
<tr><td style="padding:20px 36px 28px;color:#4a6a8a;font-size:12px;border-top:1px solid rgba(255,255,255,0.06);line-height:1.6">
Если у вас возникли вопросы, свяжитесь с вашим менеджером MONT или напишите на <a href="mailto:mont@mont.ru" style="color:#5b9bd5">mont@mont.ru</a>
</td></tr>
</table></td></tr></table>
</body></html>"""
pending.status = "approved"
db.commit()
try:
_send_email(pending.email, "Доступ к Инфраструктурному полигону MONT", html_email)
email_status = "Email отправлен"
except Exception as ex:
log_event("email_send_error", error=str(ex))
email_status = f"Ошибка отправки email: {ex}"
try:
_tg_api("editMessageText", {
"chat_id": chat_id, "message_id": msg_id,
"text": (
f"Одобрено на {days} дней\n"
f"Логин: `{username}`\n"
f"Пароль: `{password}`\n"
f"{email_status}"
),
"parse_mode": "Markdown",
})
except Exception:
pass
elif reject_match:
manager_contact = pending.manager if pending.manager else "менеджера MONT"
html_email = f"""<!DOCTYPE html>
<html lang="ru"><head><meta charset="utf-8"/></head>
<body style="margin:0;padding:0;background:#0a1929;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif">
<table width="100%" cellpadding="0" cellspacing="0"><tr><td align="center" style="padding:40px 20px">
<table width="560" cellpadding="0" cellspacing="0" style="background:linear-gradient(150deg,#0b1a2e,#0d2040);border-radius:16px;overflow:hidden;border:1px solid rgba(255,255,255,0.08)">
<tr><td style="padding:32px 36px 0">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABqAAAAHoCAYAAAAmBi7bAAAgAElEQVR4nOzdd7htd0Hn/3cKJRA6AgpKEARBMhZkFCsqEsRBRkFRRESwQMRCCSJdRxEIoCgKIoLUGWVwlEFNRCUqKgrYQpEyP+kliHQIkOT+/lj3QBJuOeeevfd37b1fr+c5TyB3370+z707p73PWuu4gLV36q3PPKF6dnXuueec8ZjRewAAAAAA2G4njB4A7M/F4tNdq9tc+5TbfuK8N7/kZYNnAQAAAACwxQQoWGOXik87RCgAAAAAAIYSoGBNHSY+7RChAAAAAAAYRoCCNXSU+LRDhAIAAAAAYAgBCtbMLuPTjttc+5Tb/sd5b37JK5Y8CwAAAAAAPk2AgjWyx/i04/bXPuW255335pe8ckmzAAAAAADgEgQoWBPHGJ92fLsIBQAAAADAqghQsAb2GZ92iFAAAAAAAKyEAAUzt6D4tEOEAgAAAABg6QQomLEFx6cdIhQAAAAAAEslQMFMLSk+7RChAAAAAABYGgEKZmjJ8WmHCAUAAAAAwFIIUDAzK4pPO0QoAAAAAAAWToCCGVlxfNohQgEAAAAAsFACFMzEoPi0Q4QCAAAAAGBhBCiYgcHxaYcIBQAAAADAQghQMNhM4tMOEQoAAAAAgH0ToGCgmcWnHSIUAAAAAAD7IkDBIDONTztEKAAAAAAAjpkABQPMPD7tEKEAAAAAADgmAhSs2JrEpx0iFAAAAAAAeyZAwQqtWXzaIUIBAAAAALAnAhSsyJrGpx0iFAAAAAAAuyZAwQqseXzaIUIBAAAAALArAhQs2YbEpx0iFAAAAAAARyVAwRJtWHzaIUIBAAAAAHBEAhQsyYbGpx0iFAAAAAAAhyVAwRJseHzaIUIBAAAAAHBIAhQs2JbEpx0iFAAAAAAAn0WAggXasvi0Q4QCAAAAAOASBChYkC2NTztEKAAAAAAAPk2AggXY8vi0Q4QCAAAAAKASoGDfxKdLEKEAAAAAABCgYD/Ep0MSoQAAAAAAtpwABcdIfDoiEQoAAAAAYIsJUHAMxKddEaEAAAAAALaUAAV7JD7tiQgFAAAAALCFBCjYA/HpmIhQAAAAAABbRoCCXRKf9kWEAgAAAADYIgIU7IL4tBAiFAAAAADAlhCg4CjEp4USoQAAAAAAtoAABUcgPi2FCAUAAAAAsOEEKDgM8WmpRCgAAAAAgA0mQMEhiE8rIUIBAAAAAGyo40cPgLkRn1bqN0699Zn3GT1inZx99lnXPfvss/zwAAAAAAAwawIUXIz4NIQItUtnn33W9aq/r54tQgEAAAAAcyZAwUHi01Ai1FEcjE/nVNdteo2KUAAAAADAbB03egDMgfg0G6efe84ZTxk9Ym4uFp9ueKlfen5199NOu92FKx8FAAAAAHAEAhRbT3yaHRHqYo4Qn3aIUAAAAADA7LgEH1tNfJoll+M7aBfxqabX7tPOPvssP1AAAAAAAMyGAMXWEp9mbesj1C7j0457Vr8hQgEAAAAAc+GblWwl8WltbOXl+PYYny7uqdXpp512uwMLHwUAAAAAsAcCFFtHfFo7WxWh9hGfdohQAAAAAMBwAhRbRXxaW1sRoRYQn3aIUAAAAADAUAIUW0N8WnsbHaEWGJ92iFAAAAAAwDACFFtBfNoYGxmhlhCfdohQAAAAAMAQAhQbT3zaOBsVoZYYn3aIUAAAAADAyglQbDTxaWNtRIRaQXzaIUIBAAAAACslQLGxxKeNt9YRaoXxaYcIBQAAAACsjADFRhKftsZaRqgB8WmHCAUAAAAArIQAxcYRn7bOWkWogfFphwgFAAAAACydAMVGEZ+21lpEqBnEpx0iFAAAAACwVAIUG0N82nqzjlAzik87RCgAAAAAYGkEKDaC+MRBs4xQM4xPO0QoAAAAAGApBCjWnvjEpcwqQs04Pu0QoQAAAACAhROgWGviE4cxiwi1BvFphwgFAAAAACyUAMXaEp84iqERao3i0w4RCgAAAABYGAGKtSQ+sUtDItQaxqcdIhQAAAAAsBACFGtHfGKPVhqh1jg+7RChAAAAAIB9E6BYK+ITx2glEWoD4tMOEQoAAAAA2BcBirUhPrFPS41QGxSfdohQAAAAAMAxE6BYC+ITC7KUCLWB8WmHCAUAAAAAHBMBitkTn1iwhUaoDY5PO0QoAAAAAGDPBChmTXxiSRYSobYgPu0QoQAAAACAPRGgmC3xiSXbV4Taovi0Q4QCAAAAAHZNgGKWxCdW5Jgi1BbGpx0iFAAAAACwKwIUsyM+sWJ7ilBbHJ92iFAAAAAAwFEJUMyK+MQgu4pQ4tOniVAAAAAAwBEJUMyG+MRgR4xQ4tNnEaEAAAAAgMMSoJgF8YmZOGSEEp8OS4QCAAAAAA5JgGI48YmZuUSEEp+OSoQCAAAAAD6LAMVQ4hMzdfq555zxFPFp10QoAAAAAOASBCiGEZ8W7kD11tEjNsSB617npJ+/3w/d6KGJT7slQgEAAAAAnyZAMYT4tBQfPPecM646esQmcObTMROhAAAAAICqjh89gO0jPjFn4tO+3Lv6jbPPPssPNwAAAADAlhOgWCnxiTkTnxZChAIAAAAABChWR3xizsSnhRKhAAAAAGDLCVCshPjEnIlPSyFCAQAAAMAWE6BYOvGJOROflkqEAgAAAIAtJUCxVOITcyY+rYQIBQAAAABbSIBiacQn5kx8WikRCgAAAAC2jADFUohPzJn4NIQIBQAAAABbRIBi4cQn5kx8GkqEAgAAAIAtIUCxUOITcyY+zYIIBQAAAABbQIBiYcQn5kx8mhURCgAAAAA2nADFQohPzJn4NEsiFAAAAABsMAGKfROfmDPxadZEKAAAAADYUAIU+yI+MWfi01oQoQAAAABgAwlQHDPxiTkTn9aKCAUAAAAAG0aA4piIT8yZ+LSWRCgAAAAA2CACFHsmPjFn4tNaE6EAAAAAYEMIUOyJ+MSciU8bQYQCAAAAgA0gQLFr4hNzJj5tFBEKAAAAANacAMWuiE/Mmfi0kUQoAAAAAFhjAhRHJT4xZ+LTRhOhAAAAAGBNCVAckfjEnIlPW0GEAgAAAIA1JEBxWOITcyY+bRURCgAAAADWjADFIYlPzJn4tJVEKAAAAABYIwIUn0V8Ys7Ep60mQgEAAADAmhCguATxiTkTn0iEAgAAAIC1IEDxaeITcyY+cTEiFAAAAADMnABFJT4xb+IThyBCAQAAAMCMCVCIT8ya+MQRiFAAAAAAMFMC1JYTn5gz8YldEKEAAAAAYIZOHD2AccQn5kx8Yg/uXXX22WedftpptzswegwAa+/k6qrVFQ6+XdoHq49VH6g+scJdAAAAa0WA2lLiE3MmPnEMRCgAduuU6ibVF1c3qr6gum51veoa7e1rpI9X76neWb2tenP1+uqN1Wuq9y9oMwAAwNpxyaItJD5trA+ee84ZVx09Yr/EJ/bpqZUIBcCOa1RfX31tdYvqK6qrrPD4b6n+sXpl9VfVP1SfXOHxAQAAhhGgtsyptz7zuOoZ1T0GT2Hx1j5AiU8siAjFOnlEdc+Bxz9Q/bemMzU4dt9bPWbwhh+t/nTwhjm4bFNw+vbqttWXjJ3zWT5R/V11VvVH1avHzpmNpzX9fY30gOqFgzcsy6iPNV9XvX3Bz3nl6l8X/JyM52MYAGwol+DbIgfj028kPjFD4hML5HJ8rJOrV9cfvOHx1bcN3rDOTqoeV33+4B2HulfRtrhc02v4e5vC08lj5xzR5apbH3x7TNMZUi+snl+9atiq8a7V+PeFT6v+tnrX4B3LMOpjzTK+33B8418rLN42fwwDgI12/OgBrMbF4tO9R2+BSxOfWIJ7V79x9tlnOdMXju52jT/zYJ3dv/HxaVvdsikanFf9n+ouzTs+Hcr1m15Dr6zeVD2k+tyhi7bX1avfzlVCAABgYQSoLSA+MWfiE0skQsHuPaE6YfSINXSd6sGjR2yZy1U/XP1z0/2UfqTpklyb4IbVL1Zvq/6g+oaxc7bSt+VrJgAAWBgBasOJTwDALty8utfoEWvo51u/M27W1VWrh1VvrX6r+tKxc5bqhOqO1V82nRl1l3zdtkqPr75o9AgAANgEvpDZYOIT6+C002739qb7IPy/wVPYPE+t3AcKdu9/VFcaPWKNnJpotwpXrR5VvbnpNXqtkWMGuEX1v6pXN4UoZ/Uu3xWq5+R+yQAAsG8C1IYSn1gnIhRLID7B3l2r+tnRI9bIE/K59DKdWP14032RHlldZeyc4W7aFKJekUvzrcJXNd2PCwAA2AdfNG8g8Yl1JEKxQOITHLv7VdcfPWIN3L761tEjNthtqn+pnlxdY/CWublF06X5XlB9weAtm+7h1VeOHgEAAOtMgNow4hPrTIRiAcQn2J/LV48ePWLmTmy6RwyLd83q2dVLqpsN3jJ3d65eU/1k0z2jWLwTq+dWJ40eAgAA60qA2iDiE5tAhGIfxCdYjLtW/3X0iBn70abLobFY31m9rvqB0UPWyMnVk6qXVTcavGVT3aR67OgRAACwrgSoDSE+sUlEKI6B+ASL9cTquNEjZugq1c+NHrFhTq5+u/r9pjOg2Luvrv65+pHRQzbUT+SSmwAAcEwEqA0gPrGJRCj2QHyCxfvapkt8cUkPSSRZpJtVr6zuOXrIBrhi9bTq+Qf/N4v1O9XVRo8AAIB1I0CtOfGJTSZCsQviEyzPY6vLjR4xIzeofmr0iA3yPdU/NF3ijMX5vurvqxuPHrJhPq/pay4AAGAPBKg1Jj6xDUQojkB8guW6QdOlp5g8JkFuEY6rHlH9bs7UWZYvqV5efePoIRvme5sCHwAAsEsC1JoSn9gmIhSHID7Bajwsl5yr+pqmM3bYn8tWz8x9tFbhatVLqruNHrJhfqO67ugRAACwLgSoNSQ+sY1EKC5GfILVuUr1qNEjBjuueuLoERvgpOp/Vz84esgWuUz1nOrHRw/ZIFdtuh/UcYN3AADAWhCg1oz4xDYToUh8ghHuXX3x6BED3aX6qtEj1twVqj+q7jB6yJZ6cvXg0SM2yG2q+44eAQAA60CAWiPiE4hQW058gjFOqB4/esQgl2+69xPH7qTqxdU3jR6y5X6petDoERvkcW13mAcAgF0RoNaE+ASfIUJtJfEJxvr2pp/63zY/XV1/9Ig1dtnqdxOf5uKx1X1Gj9gQl6+e23SZQwAA4DAEqDUgPsFnE6G2ivgE8/DEtutzx2tVDxk9Yo0dVz0tl92bmydXdx49YkPconr46BEAADBn2/RNhLUkPsHhiVBbQXyC+Ti1+qHRI1bo56srjR6xxh5S/eDoEXyW46tnV7ccPWRDPCT3iAMAgMMSoGZMfIKjE6E2mvgE8/ML1cmjR6zAzasfHj1ijX1302uFeTqpelF1vdFDNsAJTZfiu+LoIQAAMEcC1EyJT7B7ItRGEp9gnq5T/czoESvw+KZvLLN3X1w9Y/QIjuo61e/lHkaLcKOm9xkAAMClCFAzJD7B3olQG0V8gnl7YJt95sRpB9/YuytWL2g7zpLbBLeqHjt6xIa4d/Vto0cAAMDcnDh6AJckPsGxO+2027397LPPunV1TnXDsWs4RuITzN/lq1+qfmD0kCU4MWcy7McTmy5fuM7Or9508O1d1Ueqjx58O7m6alNoO6XpzJfrV8eNGLog96teUv3J6CEb4BlNr//3jR4CAABzIUDNiPgE+ydCrTXxCdbH3aonVa8cPWTB7tX6B5RRblf96OgRx+Ct1UubPm/46+rfq4v28PsvV31Z9fVNZ2J/Q3WlhS5cvqc3ve7fP3rImrtO9ZvVnUcP2XAXVW8ZPWIPLlt97oDjvqv65IDjHquPjR4AACyHADUT4hMsjgi1lsQnWD9PbPpm+6a4cvXzo0esqatUvz16xB78R9P9j55bvbzaz8eeT1R/f/Dt8dVJ1R2q72+6JNs63GPp86pfawrL7M+dms4Ofc7oIRvsQ01nIK6LL6v+acBxb1/984DjAgBcgntAzYD4BIvnnlBrRXyC9fT11XeNHrFAP1tda/SINfXopogxd6+v7lldt/rx6u/aX3w6lI83xa07Vl/QdI+lDy34GMvw/dW3jh6xIX6t6e8eAAC2ngA1mPgEyyNCrQXxCdbb45ouL7TuTql+evSINfUVzf/z2DdWd6luVj2z1V2W6t3Vg5vuE/WopvtIzdmvtRn/PY92lepZ+VobAAB8UjyS+ATLJ0LNmvgE6++G1X1Hj1iAR1eXHz1iDR1XPbn5fk1xftOZbTdvOitpL/d2WqQPVD9X3bh64aANu3GT6n6jR2yIWydqAwDAbL9Y3HjiE6yOCDVL4hNsjodX1xg9Yh++qvq+0SPW1H+vbjV6xGG8qvrS6jGt7oyno3lndefqu6v3D95yOD9bXW30iA3x6OpLRo8AAICRBKgBxCdYPRFqVsQn2CxXrR4xesQxOq564ugRa+rEpm+wz9GTm8LYG0YPOYz/3RTHXjl6yCFcpXrI6BEb4nLVc3NZQwAAtpgAtWLiE4wjQs2C+ASb6fSmy4utm++uvmb0iDX1fdUXjx5xKRdWP1L9RPWpwVuO5m3V11cvGD3kEO5bXWv0iA3xZU2XXwQAgK0kQK2Q+ATjiVBDiU+wuU6szhw9Yo8uVz129Ig1dVz14NEjLuWT1XdVTx89ZA/Or+7S9PFxTi6f+xct0oOqrx09AgAARhCgVkR8gvkQoYYQn2DzfUf1TaNH7MFPVaeMHrGm7lDdbPSIi/lU9e3Vi0YPOQYHms4gfNLoIZdyenWl0SM2xPHVs6uTRw8BAIBVE6BWQHyC+RGhVkp8gu3xxNbj88vPqR46esQau9/oARdzUdPlAP9s9JB9OND0Z/rs0UMu5irVPUeP2CBfWP3K6BEAALBq6/ANgrUmPsF8iVArIT7Bdvmy6gdHj9iFR1VXHj1iTd2k6WPnXPxs9cLRIxbgQNP9q/569JCL+bHRAzbMvZrOHgQAgK0hQC2R+ATzJ0ItlfgE2+kXqiuOHnEEN8031vdjTp/XvqB63OgRC/TJ6s7Vu0YPOeim1TeMHrFhnt50BiYAAGwFAWpJxCdYHyLUUohPsL0+rzpj9IgjeHx1wugRa+oy1fePHnHQm5vOKNk051V3bTojag7uMXrAhrlW9VujRwAAwKoIUEsgPsH6EaEWSnwCzqiuO3rEIXxrdfvRI9bYtzSfszfuWX149IglOaf61dEjDrpTdbnRIzbMHXN/LQAAtoQAtWDiE6wvEWohxCeg6grVL44ecSknVE8YPWLNfe/oAQc9o3rp6BFL9tDq7aNHNN0r7XajR2ygX6luMHoEAAAsmwC1QOITrD8Ral/EJ+Di7l59xegRF/ND1amjR6yxE5rO3BjtQ9WDR49YgY82n0tZ3mn0gA10pepZ+XocAIAN5xPeBRGfYHOIUHv3rvee/9wHPebVfyM+ARdzXPXE0SMOOrn6hdEj1tzXVFcdPaI6s3rv6BEr8rvVq0aPaDoDyteNi/f1zScyAgDAUvhCYgHEJ9g8ItSePPVJv/OmR1x04MCzTr31mXO5OT0wD9/YPM6aeXB17dEj1twc7p31/qZLl22LA9WjRo9ouu/XLUeP2FA/X33p6BEAALAsAtQ+iU+wuUSoXXlqdfoFFxw40PQx5dkiFHApZ1aXGXj8z68eMPD4m+K2owdUv159ZPSIFfuj6tzRI5rH3/8mumz1nOpyo4cAAMAyCFD7ID7B5hOhjuhQ93wSoYBL+6Lq9IHH/6Xq8gOPvwlOrr5s8IYLqqcM3jDCgaavN0b7utEDluQvRg9oujedS4QCALCRBKhjJD7B9hChDulQ8WmHCAVc2iOrqw047i0r74v271aN/7rhxdU7B28Y5XnVRwdvuFV1wuANy3Dv6j2jRzSdpfmNo0cAAMCijf5Cci2JT7B9RKhLOFJ82iFCARd3teoRA477ywOOuYluNXpA02XKttWHqz8cvOFK1ZcM3rAM761+ePSI6rjqWdWVRw8BAIBFEqD2SHyC7SVCVbuLTztEKODifrzpcnyrcqfqa1d4vE325YOP/7HqjwdvGO33Rg9o/OtgWV5cPW30iOr61ZNGjwAAgEUSoPZAfAK2PELtJT7tEKGAHZepHruiY122etyKjrUNTh18/D+tzh+8YbSXNP7PYPTrYJke0Dw+t7tH9V2jRwAAwKIIULskPgE7tjRCHUt82iFCATu+s/qGFRznJ6ovXMFxtsHJjf+zPHvw8efgY9XfDN6wyQHqI9Xdq4tGD6l+s7rO6BEAALAIAtQuiE/ApW1ZhNpPfNohQsF8fLCxZ1I8seV+DnqN6uFLfP6jeefAYy/DjZvuTzPSOYOPPxfnDD7+TQcff9n+ttWdpXkk16yePnoEAAAsggB1FOITcDhbEqEWEZ92iFAwDx+onjDw+Leo7rbE539UdZUlPv/RPGzgsZfhlMHH/1D1+sEb5uLvBh//uk2X0txkj6z+afSI6turHx09AgAA9kuAOgLxCTiaDY9Qi4xPO0QomIfHVucNPP6jqyss4XlvUt1nCc+7Wy+r/s/A4y/DKYOP/4pqkR+H1tkrBx//+OrzB29Ytk81BfJPjB7SdLbojUaPAACA/RCgDkN8AnZrQyPUMuLTDhEKxvtw00/6j3Ld6gFLeN7HVycs4Xl36/4Dj70sXzD4+K8dfPw5+WD1jsEbNj1A1fSa+9nRI6orVs9u7Ps0AADYFwHqEMQnYK82LEItMz7tEKFgvKdXrxt4/J+pPneBz/fN1X9b4PPt1fOaztbZNNcafHyX37uk0X8e1x58/FX5leovRo+obtX0vhIAANaSAHUp4hNwrDYkQq0iPu0QoWCsC6oHDTz+FatfWNBzHd90uapRzq8eOvD4y3T1wcd/8+Djz81bBh9/9OthVQ5U92g662y0n6u+YvQIAAA4FgLUxYhPwH6teYRaZXzaIULBWC9u7E/5/1D1pQt4nnss6HmO1ZMaHwaW5RqDjz/6knNz887Bxx/9elilt1X3HT2iOrF6bnX50UMAAGCvBKiDxCdgUdY0Qo2ITztEKBjrAU0/7T/Cce3/zKWTW9yZVMfiP6pfGnj8ZRt9xst/DD7+3Lx38PFHvx5W7bnVC0aPqG7aZr+fAQBgQwlQiU/A4q1ZhBoZn3aIUDDOP1fPGnj8b67usI/f/6AWey+pvfq55nGZrmU5YfDxPzD4+HMz+rU2+vUwwn0af+ZZ1U83vb8EAIC1sfUBSnwClmVNItQc4tMOEQrGeVj18YHHP7PpMlN7db3qgQveshdvaHo/uskuM/j4Hxl8/LkZHeRGvx5GeF91r9EjDnpWddXRIwAAYLe2OkCJT8CyzTxCzSk+7RChYIx3VE8YePybdGyfj/1iddKCt+zFg6oLBh5/Fa44egCzsq2vh7Oqp4we0RTdnzx6BAAA7NbWBijxCViVmUaoOcanHSIUjPHY6j0Dj/+o9vaT/beofmA5U3blr6o/HHh8YLUeWL1x9Ijq+6vvGT0CAAB2YysDlPgErNrMItSc49MOEQpW7yPVIwYe/xpNlwLcrSdWxy1py248YOCxV+nDowdwCaO/ftvm18PHqrtVF44e0nQ21ueNHgEAAEcz+guYlROfgFFmEqHWIT7tEKFg9Z5RvWbg8X+y+sJdPO47q29Y8pYjeV71yoHHX6XR32y/8uDjz83oP4/Rr4fR/qHp0p+jXb3p/fXICA8AAEe1VQFKfAJGGxyh1ik+7RChYLUuaLqv0SiXqR53lMdcdhePWabzq58dePxV+9Tg4+/lsozb4GqDjz/69TAH/6N5BOjTqvuMHgEAAEeyNQFKfALmYlCEWsf4tEOEgtX64+rPBx7/TtXXHeHXf7y60Yq2HMovV28bePxV+8/Bx7/W4OPPzecMPv7o18McXNB0Kb6Pjx5SPb668egRAABwOFsRoMQnYG5WHKHWOT7tEKFgtR5QjXyfcbj7O129sfepem/1mIHHH+F9g49/3cHHn5vRfx6jXw9z8frGni2646TqudWJo4cAAMChbHyAEp+AuVpRhNqE+LRDhILV+ZfqWQOPf8vqrof4949o7CXZHlV9aODxRxh9xsspg48/N6cMPv7o18Oc/Hr1p6NHNL2/fOjoEQAAcCgbHaDEJ2DulhyhNik+7RChYHUeWn1s4PF/qemn+3fcuDp90Jaaznh42sDjj/Kewcf/4sHHn5vRfx7vHnz8OTlQ3bN6/+gh1cObQhQAAMzKxgYo8QlYF0uKUJsYn3aIULAa72y6v8gon1/d/2L//3HVZQZtqTqj6d4v2+Ytg4//JYOPPyef0/h7Yr118PHn5h3VfUaPqE6onlNdYfQQAAC4uI0MUOITsG4WHKE2OT7tEKFgNc5s7BkPD66u0/T+8Y4Dd5xT/d+Bxx/pzYOP/xVN31ynbjH4+Bc0BRcu6Xer/zl6RHWTplAPAACzsXEBSnwC1tWCItQ2xKcdIhQs30eaLu00ysnVL1RPHLjhQPXAgccf7c2Dj3/F6tTBG+biqwcf/23VhYM3zNXpzSPO/Xh12ugRAACwY6MClPgErLt9Rqhtik87RChYvmdWrx54/HtVXz7w+M+rXjXw+KO9ofHR4daDjz8Xtxl8/NcOPv6cfaC6x+gRBz2juvroEQAAUBsUoMQnYFMcY4Taxvi0Q4SC5bqw6f5H2+j86iGjRwx2fvXGwRuc0VFXqb5q8IZzBx9/7v6s+tXRI6rPa/q6GAAAhtuIACU+AZtmjxFqm+PTDhEKluus6iWjRwzwxKbLjm270eHhm6srDd4w2u2rEwdvGP06WAc/U/3b6BHVXaq7jh4BAABrH6DEJ2BT7TJCiU+fIULBcj2w6X5I2+K86jGjR8zEPw4+/mWrOw7eMNr3jB7Q+NfBOji/ult1weghTV8jX2/0CAAAtttaByjxCdh0R4lQz69+XHy6BBEKludfm+4HtS0eWX149IiZ+JvRA6q7jx4w0DWazoAa6X3V6wdvWBevqn5u9Iimyzb+TnXc4B0AAEAPAKYAACAASURBVGyxtQ1Q4hOwLQ4ToZ5f3f2002530ZBR8yZCwfI8vPrY6BEr8Lrq6aNHzMgrqk8N3nCb6oaDN4zyQ01ngY30t23XGZD79UvVy0ePqL6l+snRIwAA2F5rGaDEJ2DbXCpC7cSnC4eOmjcRCpbjndXjRo9YgQc1j0tozcX5TRFqpOOqnxi8YYQTq9NHj6j+evSANXNh01l7Hx09pHpsddPRIwAA2E5rF6DEJ2BbHYxQX5P4tFsiFCzH46t3jR6xRH9RvXj0iBk6e/SA6oera44esWLfU91g9Ijm8fe/bt7YdO+80S5X3Xb0CAAAttNaBSjxCdh2p512u/PEpz0RoWDxPtp0Kb5NdKB5fMN4jv549IDqitXPjB6xQic23YtstHc03QOOvfvN5vHfDgAADLE2AUp8AuAYiVCweM+szh09YgmeU/3T6BEz9Y/VeaNHVPetrj96xIr8cHXj0SOqPxk9YI0dqO5VvW/0EAAAGGEtApT4BMA+iVCwWBe1eWcKnV89dPSIGbuo+v3RI6rLV788esQKXLN69OgRB71g9IA19+7qx0aPAACAEWYfoMQnABZEhILF+tM2674wT6jePnrEzD1/9ICDvvPg2yZ7UnW10SOq91Z/PnrEBnhh0xmWAACwVWYdoMQnABZMhILFOqPpzJh1957qsaNHrIG/abof0Bw8rbrO6BFLcqfqrqNHHPSCyr0nF+O+1VtHjwAAgFWabYASnwBYEhEKFufcpvtBrbtHVB8ePWINXNR8/r6vWT2vOmH0kAW7QfX00SMu5hmjB2yQD1U/2HRfKAAA2AqzDFDiEwBLJkLB4jy8+ujoEfvwmnyTfS+e1nzOevvm6nGjRyzQlaoXVVcdPeSgV1SvGj1iw5zTdtzDDAAAqhkGKPEJgBURoWAx3lWdOXrEPjyoumD0iDXytuqPRo+4mPs3Xdps3V22+r3q5qOHXMxTRw/YUA+pXj16BAAArMKsApT4BMCKiVCwGI+v3jl6xDH48+qPR49YQ08cPeBSfq1a5/fjJ1TPrm43esjFvLv6n6NHbKhPVD9QfXL0EAAAWLbZBCjxCYBBRCjYv49WDxs9Yo8OVA8YPWJNnVP9/egRl/Ls6kdGjzgGl61eWN1l9JBLeVL18dEjNtg/V48cPQIAAJZtFgFKfAJgMBEK9u9Z1b+OHrEHz6r+ZfSINfaY0QMu5fim+1P9fHXc4C27dfXqz6o7jh5yKR/M5fdW4czqb0aPAACAZRoeoMQnAGZChIL9uaj1OaPo463fGVtz84fVK0aPOISHV79fXWX0kKP48uqV1dePHnIIZ1YfGD1iC1zYdCm+j4weAgAAyzI0QIlPAMyMCAX782fVn4wesQtPqN4xesSaO1A9ePSIw/jvTWe3zTHuHF/dv3p5dYPBWw7l3dUvjx6xRf69+unRIwAAYFmGBSjxCYCZEqFgfx7U9JP9c/We6rGjR2yIv2i+wfH61V9Wv15dbfCWHV/adMm1JzTd+2mOHll9bPSILfPb1f8dPQIAAJZhSIASnwCYOREKjt2rq2eMHnEEj8glrxbpp6pPjh5xGMdVp1dvajrr6ORBO25Y/Vb1j9VXD9qwG6+snj56xJb64eq9o0cAAMCirTxAiU8ArAkRCo7dI6qPjh5xCK9uOtuAxXlj8z+j7OpNZx29uekMn2us6Lj/pXp+9fqmwDD8/rtHcKC6T9O93Fi985peIwAAsFFW+kWQ+ATAmhGh4Ni8u3lGiTOa9+UB19WjmyLL3F2jelT1ruoPq++pTlrwMT6vemD1T033ofq+6oQFH2MZfrXpDCjGeVHzPnsUAAD2bGUBSnwCYE2JUHBsnlC9c/SIi3lJddboERvq/OoHW5+4d5nqO6rfrd5fndMUpr65utYenueEpsvr3bl6ctMZdu+ozqy+bGFrl+8N1UNGj6Cqn67+ffQIAABYlBNXcRDxCYA1txOhOvecM543egysiY9VD62eOXpI0+XFHjh6xIb7++oxTX/n6+Ry1TcefNvxoab7Rr2z6X5hHz34dpWm+0idXJ1SfWFTzFpnFzbFw4+NHkJVH67uXv1l875kIwAA7MrSA5T4BMCGEKFg755d/VTjzwZ5ZvWvgzdsg0dVt66+duyMfbty9RUH3zbdw6qXjx7BJbys6Sy6nxk9BAAA9mupP1UlPgGwYVyOD/bmosafefSx6uGDN2yLC5ruq/Te0UPYlRc3z3u1UY9suocYAACstaUFKPEJgA0lQsHe/Hn1RwOP//jmdS+qTffO6i7Vp0YP4Yje0HSptwOjh3BIn6h+4OA/AQBgbS0lQIlPAGw4EQr25kFN95pZtXc3XcqK1XppdfroERzWf1Z3qN4/eghHdG7rd081AAC4hIUHKPEJgC0hQsHuvbZ6+oDjPrz6yIDjMv19P270CD7Lp6rvbDoDivn75eovR48AAIBjtdAAJT4BsGVEKNi9R7baGPTq6pkrPB6f7cHVb40ewaddVN25+qvRQ9i1i6ofrD48eggAAByLhQUo8QmALSVCwe68p3rsCo/3gMZc9o/POFDdp3r+6CF0UdM9n140egh79pbqvqNHAADAsVhIgBKfANhyIhTszhOqd6zgOGdXf7qC43B0FzaFDxFqnJ349LzRQzhmz65+f/QIAADYq30HKPEJACoRCnbj49VDl3yMi6ozlnwM9mYnQrkc3+p9qvruxKdN8GNNZ5ICAMDa2FeAEp8A4BJEKDi651T/vMTnf2Z17hKfn2NzYdM30H9x9JAt8qHq23LmzKb4j+qeo0cAAMBeHHOAEp8A4JBEKDiyi6r7L+m5P1o9fEnPzf4dqB7W9E30Tw3esuneWt2q+vPRQ1ioP65+c/QIAADYrWMKUOITAByRCAVH9tLqxUt43jOrdy3heVmsZ1bfksuJLctLq1tWrx09hKV4YPWm0SMAAGA39hygxCcA2BURCo7sjKbLsi3Ku6rHL/D5WK6/rr68etnoIRvmzOpbq/NGD2FpPtJ0T7WLRg8BAICj2VOAEp8AYE9EKDi8f6uetsDne3jTJfhYH++qvql6VIuNkdvo3U33e3pQ/iy3wd9Vjx49AgAAjmbXAUp8AoBjIkLB4T2q+vACnufcpsu6sX4uqH6u+trqjYO3rKvfr06tzho9hJX6+eofR48AAIAj2VWAEp8AYF9EKDi086rHLOB5HpjLUa27v6/+S/WLTVGKo3tn9V3Vnar/GLyF1ftUdbfqE6OHAADA4Rw1QIlPALAQIhQc2i9Xb9/H7z+r+tMFbWGs86uHVV9W/fngLXP2qab/bm5a/Z/BWxjrddXPjB4BAACHc8QAJT4BwEKJUPDZPl495Bh/74XVGQvcwjy8prpNdcfqDYO3zM2LqptX968+NHgL8/CrCbYAAMzUYQOU+AQASyFCwWd7Xsd2L5NnVK9e8Bbm40XVl1Q/VP2/wVtGO7u6VaIcn+1AdY/qg4N3AADAZzlkgBKfAGCpRCi4pIua7uO0Fx+tHrGELczLBdXvVF9c/WB17tA1q3Wg6RJ7t6puV7187Bxm7O3V6aNHAADApX1WgBKfAGAlRCi4pJc2nfGyW4+t3r2kLczPBdWzqy+tblu9uClcbqIPVL9WfVH1XQlP7M7zq98dPQIAAC7uEgFKfAKAlRKh4JIe1HRfp6N5Z/WEJW9hng5UL6nuUH1+01lwbxq6aDEONEXYu1efW/1kLjvI3p3e9P4RAABm4dMBSnwCgCFEKPiM11dP3cXjHlZ9bMlbmL93Vv+j6Uyhr2w6K26dos1F1V83xabrVd9cPac6f+Qo1tp/VvccPQIAAHYcX+ITAAwmQsFn/Fz1oSP8+r9Wz1rRFtbHq6oHVzeqblLdr/qTjvxaGuEtTZHprtU1q29outyes1ZYlLOrXx89AgAAqk4UnwBgFnYiVOeec8bzRo9hZd5R/cuKjzn3b3S/t+kMp3sd5tfv37zv/XNhq/87rfrggGPO1RsOvv1KdUL15dXXHPznLaqbHfz3y/aR6p+a4tirqpdVb17BcdfReU1xbtXm/L5kPx7U9Hq/7uAdFww+/hx8sjGv7U8OOCYAwGc57tRbn/mUxCfYBB+qrj96BFvrCxrzDddNdFH1A+eec8bzRw8B2FCX7TNnSn1R08ew6x58u2Z11epqR3mOT1YfqN7fFE/eUb21elv1uuqNB//3gcXPBwAAWA8n5qclYVNcuembIMB6u7Dpp+YBWI5PVq89+HYkV+ozZ0pdvs/cm+n83KcJAADgqE44780v+bNrn3Lbk6qvGz0GALbcp6o7n3vOGS8aPQSAPtlnYtNHLva/XVYMAABgF06oEqEAYDjxCQAAAICN8emb74pQADCM+AQAAADARjnh4v9HhAKAlROfAAAAANg4J1z6X4hQALAy4hMAAAAAG+mzAlSJUACwAuITAAAAABvrkAGqPh2hrln91xXuAYBtcFH1veeec8YfjB4CAAAAAMtw/FF+/Serp65iCABsiYuqu597zhkvHD0EAAAAAJblsGdAVZ335pd07VNu+8fVtauvXM0kANhYO/HpeaOHAAAAAMAyHTFAlQgFAAsiPgEAAACwNY4aoEqEAoB9Ep8AAAAA2Cq7ClAlQgHAMRKfAAAAANg6uw5QJUIBwB6JTwAAAABspT0FqBKhAGCXxCcAAAAAttaeA1SJUABwFOITAAAAAFvtmAJUiVAAcBjiEwAAAABb75gDVIlQAHAp4hMAAAAAtM8AVSIUABwkPgEAAADAQfsOUCVCAbD1xCcAAAAAuJiFBKgSoQDYWuITAAAAAFzKwgJUiVAAbB3xCQAAAAAOYaEBqkQoALaG+AQAAAAAh7HwAFUiFAAbT3wCAAAAgCNYSoAqEQqAjSU+AQAAAMBRLC1AlQgFwMYRnwAAAABgF5YaoEqEAmBjiE8AAAAAsEtLD1AlQgGw9sQnAAAAANiDlQSoEqEAWFviEwAAAADs0coCVIlQAKwd8QkAAAAAjsFKA1SJUACsDfEJAAAAAI7RygNUiVAAzJ74BAAAAAD7MCRAlQgFwGyJTwAAAACwT8MCVIlQAMyO+AQAAAAACzA0QJUIBcBsiE8AAAAAsCDDA1SJUAAMJz4BAAAAwALNIkCVCAXAMOITAAAAACzYbAJUiVAArJz4BAAAAABLMKsAVSIUACsjPgEAAADAkswuQJUIBcDSiU8AAAAAsESzDFAlQgGwNOITAAAAACzZbANUiVAALJz4BAAAAAArMOsAVSIUAAsjPgEAAADAisw+QJUIBcC+iU8AAAAAsEJrEaBKhALgmIlPAAAAALBiaxOgSoQCYM/EJwAAAAAYYK0CVIlQAOya+AQAsN4uV12tulZ11eoK1QUH3wAAmLnjRg84Vqfe+szjqt+o7j16CwCzIz4BAKyXy1W3qW5d3bK6SXWdwzz2fdW/Vn9b/XH18qbP/wAAmJG1DVAlQgFwSOITAMD6uFF1v+pu1ZWP8Tm+s/qDhS0CAGAhjh89YD/OPeeMA9Xp1VNHbwFgFsQnAID1cHL1xOrfmr6uP9b4BADATK11gCoRCoBPE58AANbDTatXNp35tHb3pgYAjuqaTR/vrzV6CGOtfYAqEQoA8QkAYE18efVXTfd4AgA2x2Wqn67eUL23em31nuqN1RnV5cdNY5S1vgfUpbknFMBWEp9gMU5outn7NaqrVyc13RD+oupD1YGmLyLe03TzdwDYq89vOvNp0T8N7R5QADDW1asXV7c6wmNeWd2+6etKtsRGBagSoQC2jPgEx+bzqq+tblndvLpZdd3qxF3+/k9V/1697uDbK6qXVectfCkAm+L46m+qr17CcwtQADDOcdVZ1W138di/qr6p6fs5bIGNC1AlQgFsCfEJdu/4puB0p+p2Le+yR29s+qm3P2j6JuOFSzoOAOvnvtWv7eP3X9ThbyMgQAHAON9R/eEeHv+91e8uaQszs5EBqkQogA0nPsHufGH1w9U9qs9d8bHfUz2j+s3qLSs+NgDzclL1/zVd6nU3DjR9I+v3qr+t3tb0+d9xTTc1P6XpDN5vbPqm1z0ToABglN+rvnsPj39xdYclbWFmNjZAlQgFsKHEJzi6r266yet3Nv7zvQPV71ePaLoJLQDb597VU3b52H+v7tJ0edfduFx1her9x7ALANi/11c33sPj3950X0i2wOhvSCydCAWwUcQnOLIvqR7d9NPgc3Og+l/VA6p3Dd4CwGq9vPqqXTzu3w8+zs3JAWB9vKPpPsO79Z/VNZa0hZk53PWTN8a555xxoDq9euroLQDsi/gEh3dy9cTqX5pnfKrpB5++r/q36j5twQ9CAVDV9dpdfKr6/sQnAFg3b9vj49+xlBXM0sYHqBKhADaA+ASHd+vq3Op+1Qljp+zKlZvOTn9xdbXBWwBYvm/Z5eP+oPq7ZQ4BAJbiz5b8eNbYVgSoEqEA1pj4BId2QvUL1V803Yx9Uc6v3tN0GaR/udjbW6uPL/A4t69eVZ26wOcEYH6+epePe85SVwAAy/Lr7f5rxU9WT1riFmZm6y594p5QAGtFfIJDu2rT/ZRO2+fzvKU6p/rbphvHvqmjXw7hKtUXVTdvuqTSN1Y33ceGD1V3qP5qH88BwHy9rPraozzmwupKLfYHHQCA1fn+6rm7eNyPVr+15C3MyNYFqBKhANaE+ASHdr3qTzv26PPa6lnV71VvXtCmG1Z3rn6susEx/P4PV99a/f2C9gAwH++urn2Ux7yuutkKtgAAy/Nd1VOqax3i195X/UT1P1e6iOG2MkCVCAUwc+ITHNqNqpc2Rai9uLD639Xjq1cuetTFHF99R/Xo9h7I/rPpJ+T/bdGjABjmxKZL7Rztew8vbjobFgBYbydXd6q+pilEvbfpHo+/X31w4C4G2doAVSIUwEyJT3BoN6z+srruHn/fn1RnVK9Z+KLDO6H6yeoXq5P28PteX92y6YwoANbf1Zt+4vlonlv9wJK3AACwYsePHjDSueeccaA6vXrq6C0AVOITHM7nNIWkvcSn91XfU92+1canms64+uXqK6s37uH33aR68lIWATDClXf5OD94AACwgbY6QJUIBTAj4hMc2mWrP6i+aA+/56+qU6sXLGXR7r22+q/VP+zh99y96TJ+AGyPT44eAADA4m19gCoRCmAGxCc4vF9run72bj2zuk31ruXM2bMPVLetXrWH3/OrTeENAAAAWFMC1EEiFMAw4hMc3vdVP7qHxz+2ulf1qeXMOWYfbLq5/Lt3+fjr5x6dAAAAsNYEqIsRoQBWTnyCw/uC9vY5yZOrB1cHljNn395V3XUPj39IdcUlbQEAAACWTIC6FBEKYGXEJziyp7T7m7f/3+qnl7hlUV5a/dYuH3vt6nuXuAUAAABYIgHqEEQogKUTn+DI7lzdfpeP/X/V3aoLlzdnoR5WfXSXj/2xZQ4BAAAAlkeAOgwRCmBpxCc4spOqM3f52AubLmv3oeXNWbjzql/f5WNvWZ26xC0AAADAkghQRyBCASyc+ARH92PVKbt87K9W/7C8KUvz603vD3bjjsscAgAAACyHAHUUIhTAwohPcHQnVT+7y8e+u3rU8qYs1Vurs3b52NstcwgAAACwHCeOHrAOzj3njAOn3vrM0w/+33sPHQOwnsQn2J17Vtfa5WMf0npdeu/SXtju7nP11dVVqg8ud85CXK360uqm1fWrazdtv3fTpQdX5YSDG76oulF1vYM7rlhdpvpE9bHqP5ti4P9Xvb56Y3VghTuZlytUX9n0Gj6luk7Ta6bqI02vmfdUb2p6rfxLu7+fG3tzfHWT6sZ95r/hqzX9HV22+mTTn/37q7c1/Z28oenvZbdnl7JZblh9cdNr5guaXi8n95nv+Xyk6ePoO6u3V/9Wvbb68MqXLs+Vq5v1mY99n9P0PuwqB3/9I03/3fxn038zb6pe12o/Po902eoWTe/jb1Bdt+k1UtOfy4eb/ixeW73m4D9XdX/Rz6luXv2Xpo8/Vz34dtzBbe9r+nzlNdUrqv+/vfsMk6wq9zZ+zwwz5JwlOCCgIIMiCGJiQFRQTAhGjmBWxCMGjvEomAV8VRRFFA9iBhOCqCQHEAmKIiCSc5QMg+DAMO+Hp1uaprvr2VU7VdX9u66+mGFW1V7dXbtq7/Vf61m31dSvpqxBfB4/mTifVyV+f4uI8/g+4r3/spGvv9M/e8FOZS3iHN5o5M+rEO9lM8e0uZd4PdxCfO+XEq/Vh2rtaX2WIV4LTyLOjdWJn8moe4hrgeuJ97RziXNFeaP3TRvxyGtvWeIzZTpx33Q/Mflz9L7pr8RrsB+tBmxOvOeuO/L3Jcf8+x3ArcRravR6/6ZeDzqt1ycYJnPmHjgN+DqGUJJUhOGTlDONuInaINH2upF2CyrtUbVWJy5mM9ej2wO/L+GYHwa2TrR7PfmB9WcAuwEvJAYKJrIecHXy+bq1EfAKYDvgmcSNU1F3AKcTP+ufE6+zJmV/Xy+vuiOTWA/4UqLdscDhPR5rU+DTiXY/HvnKWgd4FfEz3JpHD/J0shD4M/F6ORr4S4HH6rHW55Fz+DnEwEdRdwJ/5JFz+KrSeje5w5h64sRSwPMTz3MlcEGXfSj6uh8EKwK7ED/bucRnalGLgAuBPwC/Bk4iBtr6xQzifNkJ2JYYUOumys8lxGfficT79f1ldbBLbwZekmj3Xjqf40sDuxLv89sDSxTox93ACcAPiZ9LmQHHdODZwItHvia7fprMX4FfAN+l/sH214x8dZL5/Yz1dODVxM/jSQX7dA/x3n8i8V54Y8HHN2UV4vvdifjce1yXz3MfcDZwHPHZd00pvcsr+/5iA+I19lIiNC76vnYD8bP4KXAy9U4uq/PauBdr88j7YrfXXNcR11vHEZU92jyh42nEa2on4p6iqOuIa4RfAcfTxRiEAVRBhlCSVIjhk5T3POLCLuM9xP5P/e4iYsZZJ/sAXynheL8kt6fUisBdU/z7YsDuwAfIDZpUFUAtQ6ya250YuCjTImJA7kjgezQTdmZ/X03d0zyVGATr5CvEa7gXc8mFsPuTK825LfH6fRHllWW/hAgjDiNWGqizJYE9gDcA21Tw/GcS5/B3qW5Q/WpixWeTsq/7QfBCYq/IFxMrIsp0H/AjYvuBc0t+7jJtALyLGKxfs+Tnnk989hwKnFHyc2d9mbjO62Rz4LxJ/m1FYF9iO4nlJ2lTxDXAJ4n3kl6CqJWIsbS3EzPve7WQCBw+SszUr8N+wCcS7ab6/YyaRVzD7QPM6a1b/7EImEfcJxxDO1e2v4B4HbyE8itzLSLCgC8RgVwdyrq/eCHwP0QoUpbLgQOA/6OeVWJ1XhsXNZ0I5N9K3HeXef9wPxH+foNYpdkGiwGvBd5H/F7KcjvwbeJ3mF4Z5R5QBbknlCSlGT5Jxbwl2e4+mp0xVqazku02q7QXxexAzBj/P4rP2C3LSsQAyNXExX/Z4RPETdlziRuMq4mBrKWneoD6whZEkDUP2Jly7wefCHyRGKj8OI8u56FHW46YMX0NMVhRRfjEyPN+Y+Q4H6G7Gb5q3jRitdNfiIHVV1B++ATxHv8WYmXjCcQK3zZ5KvATYrX4PpQfPkFM7NidWBX2B2K2eD+ZRgyuXkG8x5QRPkGEzIcTodyGXTx+GSIovhb4DOWETxCr4HYjStB9hmKreJs0jXidXUr8XMsKn0afeztihdjfgVeW+Ny92pa49v8d8T5WxbYw04jz9gQigCq6mqwJGxMrlX5LueETRGB/GFFGraprjbabRqz+uZD4DNmB8ievLQm8ETgH+A0RQDdpZ+L7PZJywyeAlYEPEivXPw4snnmQAVQXDKEkqSPDJ6mYZYgyCxk/Y3D2XfkIcYHe6eszTXVwjFnAV4mb2Sc21IdpxIqni4nZtyvXdNw1idmTFxMDPeo/SxOv3z8Rq6mqtBIx0Ph3cvu8DZvXE6vFPkvs61GHVYn30UtGjm8llP6xCXAK8dlf54DW84kVdN+lvs+ayaxIjL38hSiZVNfr91lEqaHf0l3oUreViPJIh/HoPWLKtDWxOu7FBR6zM7Hi/eNUN5FlJnFN+Qdi/6Q224CYBPI9ql89ujFRhu0EciW+q7I8MRA+j1ypurLsQLxvvLXGYxYxDXg/sVKu7OBpvE2IygYfqvg4bTP6ff+IXNWNMuxIvO6+wSP77NVlOeAHRInDqu9XlyCu98/NHMsAqkuGUJI0KcMnqbgXEftkZHy/yo7U7GbipqvT15VNdXDE8sTN+94N9mFd4gbqcOobtB5vbeAoYq+QVRrqg4rbjCiHsjf1Bg/rEa+Vr1HNao1+8ziizOr3aW6AdI2R459E93ttqB7TgY8Rs9bnNtiPNxDhwXYNHf/lRHD6dpoLTl9IzCT/UIN96GQ9Yg+gnWs41rLE6ppO+y+OTtw5lthvsA5bET+HJsOWqfwXcV373JqP+3ziveT1NR8X4CnEYPx/NXBsiJUphwEH0a7zd3EiFDmI+q6RZgCfAw4Z+fMgm0a8Z/+VmEzQhHcQe1vWtfLsicQKrNfVdLxRTyZWTk8ZohpA9cAQSpIew/BJ6k52JuntRIkG1Wc0fNq2wT68hBiwaOoGarwXEf15dtMdUUcvI1YxNDl7/11EeDrMgcfziAG45zXdkRHbE+fwC5ruiCa0GrHq5lNUU6KqqNWI1b/vqvGYM4mB2V/Q3KSLsWYRA7fH074JGGsTpVXrXJ09kxg8n6xM4/LEa7iJiTvrESXe2vC6GTWNeD0fSXPljJciJiDUGT5sA5wGrF/T8abyfmI1fxvMIt5LXt3Q8fcCvtDQseuwDLEv1+dofgLUbOBUYM+KjzOHWAHaVJWOZYDjmOJ+2QCqR4ZQkvQfhk9S93ZMtjuFONdUj5nE4NdWDfbhg0RJnarK6XRrLaKUypsa7ocm93pic/bs6soqbUXcGLd1VnqV9iZC7NWb7sg4qxL7FPx30x3Ro2xClMp8ftMdGWcGsZqxjBZ1qwAAIABJREFUjvJNyxMBwvtrOFZROxK/n7bsK7M0MZBddSm3iSxBrIoev8/U6MSdplbNQQQeP6cdqzxmEOX22vJ63oso6Vn1wPxTieC6TXsPfoDmr1unEUFg1SX3Onk/1YciTViVCOSzpe3rMJPYO3jfip5/TeI9t+nJEUsS981PmOgf2zCbpu9dMG/fRXPmHrjXyF/f0WhnJKkZhk9S955EzC7OOLHKjugxvkizAyifJwKobt1H1OW+nNj4+27gQaLsx4rEgNWTiEGCbjbunkGUBFwZOLCHfqp8uxAzrYtMOLyMKDN1JfBP4AFgETHAuRYxq3Jruh9MWo8ILZ8BXN/lc/SbDxEzcLt1P3EOXwZcB9xJnMOzeOQc3ojYGyi1CfQ404GvACsAn+yhnyrHU4jyiN0OIj1MlBu6CLiGWDW9gDiHlyf2CNqIeM/vdl+nz40877e6fHwnqxLhUy/7XV0HnE+cN7cSn4ULiZ/DKkQQ/mS6Xxk6m1jVuT1RXqlJBxMz37MeAK4G7iDeS5YhwvHH0d0E9XWI18ToeNhiRCjVzcSd24EbR/o2jXi9rkn3r9VnEwO+n+/y8WX5OsVK3z1EnMeXEufxbcR5PJM4j2cT125b0N21G8Tq6KOAVxLnRtlWJSZPdbPaawGPvI/dAtxDXL/OJD77ViXO4afQ3cqqg4lqEtd08dgyvJ/i+6mOnht3Ee/zyxLnxZr0FiQeTExuvLaH52iTVYjvZ9MuH38/UUruYuJ98l/E63EWj7wfbUy89rrZ2+kA4ndY5ufnDCL0KVraeT7xvZ5PvMfcOfJcyxCvr02IEt5FJzesCPwQeCbj3lsMoEpiCCVpiBk+Sb15ToG2p1TWC433IuDdBR+ziLhhuYYYYL+FuKC/o4vjf5LuwqdbiJmVPyNmaT+UeMxSxEDNa4ib4qI3VQcQN2mHFHycqrEZ8RroNJi4kCiR9JOR/96aeO4ZwJbAa4n9HFYq2Le1iH2hnkXc/A6yD9Bd+HQbsYH0T4la/gsSj1mCKHX0WqKkT9GQcH/g33RXkuc7TP06WA54Y+J5ziPK1HTjrC4f1yab0F34tJBYAXMkMUnl7uTjnkzMEN+TCKWKOIQYoDu94OM6WY5YlddN+PQn4LvEe9kVycc8jtjfaQ+Kl9kdHeh8NrFHVRO2p/NqjkXE6+IXxPl1CROvpF+aCDReTLwmshOjAN5G7PX0D+LaJVva827iWuU4Yt+mWyZptwZxrfxKYnJFkdBlf2IwtKkB9vcQP59O7gZ+TLzvn0EMhHeyFLAD8Vn8MoqHUS8jAogqSmt+nWL7fi0CjiE+T04kgtKM2US4tzf5AfilifewOvZLG29j4DOJdlcR5+wJxHvbZPcRixGTg55NvJ/vRLF9rpYlfhYvKfCYtlqSeA0VDZ8WEOVEf0y8p2euuWYQE7J2IfZJLFLu81Di93tSsW5O6j0jfcl4mLjmP5SoSpCpqvJ44hx7N/lzbCtiUsJXx/7PNm3ANhDmzD1wGvFmawglaRgYPkm9O5TYXLuTe4mZj4uq7c5A+yVxw93JWsS+Oet2aPcgcbNyEnEhfz4RxPTqzcC3Cz7mKmLg5/vkQqfJLEPMznwvjy2rM5WHiQ3Jj+3h2ONlf19N3dM8lZil28lXgH16PNZcoqRIJ18gfmZTlYdaSGzIfSDxuunWMsSgz4cpHngcDbyqh2O33auJwYwiricGpr5DbgBkMqO/lw9QfOXA64iBmDLNJvc6K+M86VerE2Fjp8+csR4mynrtT2/n8TTiPeMzRAiWdTWx8qasIHkGEURkSxKP+h2wH72HkJsAH6f4nixXE4N//+zx+GN9mRhU7ORuJv+cfpBH3ueLrvSYNXL8/ciXcP0eMZD9RzpPfriJ2N/suxS/ZlqH2EupyOfHEeRC8Kz9gE8k2u1JrHSYKhi6jZiocBi9nUvrEq/fN1H8muiNxM+oLDtT7FrwDGL89MIejrkk8GngfQUeswWxN2MZsterZxKTRSZzKvF9nEx393uziXNr94KP24byJnLUeW081vco9n2PXgt/Eri5h+MuSdzHf4JYTZ5xOzFZ7MYejsvI8a4md792HjHZ4vwuj7U0sZo0u6/fzcQKxf+E6e4BVTL3hJI0RAyfpHJkZ/qej+FTXT7K1AOBlxAzRlclBssOIm7cygifngZ8o0D7hSPH34QYQOglfIIYANmfCDB+WuBx04lVG23YaHqYvZWpw6ezicGBveht0BritfJ5Ykbv8QUfuxvFShL1k42JWv9Zi4hZ6BsT95C9hE/wyO/licTM/yK+Q7EQQr2bQYSVRcKnS4hVhHvS+3m8iBg8fSoRQmWvM2bTW3nJ8T5JsfDpFuAVI48pY+D0ImIV8FyibG3WbOKzr4mJEJMNOp5JDG7uTXdlxhYQwdXWwA3Jx7yaGMztNMb4FaJ82jfo7prpupFjvY38nqj/RbHVOGU5kKnDp8OI1Yf/j96D3GuBtwDPJb8CcNTBFHv/mco0IgDJ+gqx+rCX8AlikPv95FabjeqlxHW3JgufridWIc0lJrV1e793NfF635koXZj1kS6P1xZ7Uix8upL4XexFb+ETxGvvy8Q1XHZV08rAN3s8LkRwmwmfRisPdBs+QZSyfTf5fUPXYNwKXQOoChhCSRoChk9SebIbWfdy0ahiJlvJfhsxwL8JseI9W+ooa2li9UG2jMpdRKmbfcmXK8m6mQgJ3kV+f4BliRVYlvluzlSl0A4mBqd6HegZ70ZisKPoHkIHEyWwBsniROizZLL9fGLW9HsovyTh7UTI90ZiNUTGEsR7UDf7Sak7HyQGHbN+RkxUKLvs4IPAx4gyZ9nXyzuJMKFXzyH2S8s6gwhYflnCscc7lZgYVGQFxw7E4HcbfJ14n7+4hOe6kNgH885E21nE72Qy84lV0vtQzmSdb/HIvlOdzCBWltdtsrJc9xPlUt9O7mdbxB+Ap1OsvNeyxASmMkLUFxJhdsbXiddDmXtQfYsI9DJeSrGV/lU5kdhT6LgSn/PXwPOJ0CDjRcT+Rv1oLSIAyjqV+Az9U8n9uJkogXhEsv3OxM+9F5mJXP8gQvsy3nchyuodnGxrAFUHQyhJA8zwSSrP6uRLV/U6y1l5E10jzyNuEL9NftZtUV8gvxfHLcAzqH5fsK8Ts8yzA5LbUGwgUfX4MBFy9Lq6ZjKLiPIj+xZ4zEpEqZlBsh/5wbfbiH0byixbOZEjiFUimT1FIAaR96+sNxprc4r9rA8lJgaUNZA0kV+QX504gwiterE0uT3rRh1L7H1UZsm78eYTn3tFxnI+Q+yr1aQvEJNGel0JPdZlFFtVMpF7iZDumN678yjfBI5Ktt2z5GN36x5i4lDREq1F3Ens5VXks2U7Yj+bXu2RbHceUeq5Ch8jVsp1sgQRQjXph0Ro0c1esZ2cQ7705Axi5VQ/+gb5IPFk4vwrewLhqIeIlYg/T7b/EhHed2MDcvtd7U0+iMz6MLFqr5OnARuO/sUAqkKGUJIGkOGTVK4iJS8yF3qqxrHErM5ea3VPZTNiNnnGncTMxro2Pj+WGPTMBm8fIWYkqh0+Q5Rkq8NBFCvL9QYGp+TbBuRXQdxHzH79W3XdeZRTiJVW2YHp91HOyhZNbhoxkzi7YvRwYmyhjlK8R5N/z3gdsEoPx/og+Wuhk4FdqS5IH2shEeZkg4JZ5FdeVOFIqpv88VNyexBOZBFRGuvs8rrzKO8F/p1o93hiz7ImPUiUWftDDcdaQJwrRX7un6W3FexLEavcMqqcEHM/UdovY/uK+pBxChHYlbkCbLyjidVQGS+usB9V2Y44pzIuJCYWVP35sZAIvDOlXDciSr92Y8tEm4uoZqLiv8hfI+ww+gcDqIoZQkkaIIZPUvmKlDvI1uFXuc4hwpeqb1i+RP7a/L+ACyrsy0SOIT9Tf0nK3RtE3TsG+N+aj/m/wAnJtjOIVUOD4CDy5TPfTHUDspM5kfwKtZnE96PqvJrYkyHjTOoLn0btR26Sw0wihOrGuuRfk9cAr6Ke8GnUw8QKgr8m27+AZgZxLyPKuVXpgC4f9xXgV2V2ZJwbiT24MnaqsB8Z7wZOq/F4C4iSmrcm229E9+cyxKr8JRLtzqH6n8OPyL1fZt+Dy3YL8RlQ5mrFyXw82W4bYJkqO1KyaeTvNe4n7uXura47j3Ivk5dzH2+fLo+RWXFbpBRnUd8jV/597ugfDKBqYAglaQAYPknVmKw+/ERuqqwXmsx8YgZpZnZtL+aSn4X5ZfKzGcv2aaJ2esbuwBMr7Is6G92zrM5Ba4jZn28hf6P/Cvp/L6gtiRVGGd8BflJhX6byZeD4ZNuXEeVTVL7p5PdMu5f6gxeIz739km27HbT+CLkB60Ujx6iiTFUnDxADl9l9Fj9VYV8m807K3wdyvBMpfh16PfDRCvoy3pHJds+otBdTO54oGVi3G4D/LtD+3T0c6znJdnWMJ9xIbu/cDcmXQi/TPsQ1Wh3+MvLVyUxg64r7UqYdyPf345SzL14RJ5O7X9uc2LevqKn2fB11RRfPm3UPcHqi3X+CMgOomhhCSepjhk9SdVYo0Da7B4/K8ylydeR79b5ku+vJz2SswsPEQFfmtTiN7mf1qRz/Q37mc9muI79ibjF632Okadm9LG4nfi9N2ov8flDZ9yYV81LG7IvQQXavhSocnTz20yl2PQOwMlGCM+NbwB8LPn+ZriC/X93mjJnxXYNTiYHOqi0kv7J11Gepdr+yUX8gBkM7yZSsqsID5FdDVOHH5F8jWxLnczc2S7Yr+jrq1p+S7WZX2YkJnEf9k1B+mmyX/R22wbuS7S4nJt80Ibty9LVdPPfSiTZV7Vk86jhiP62pvlYjqh0YQNXJEEpSHzJ8kqq1bIG2d1XWC03kDmJ/jqptSOwFk/Fx6isfMZl/AIcl2+4BrFhhXzS5fwDfbbgPXwduTrbt182vIfY7e1Wy7aeJEKpJ1wAHJ9u+iv5fndZG2b3C/kFssN6UheRWl0yneOjydqJcayf3U88qmk4OJL8CKBtIl+FrNR6ryN5F9xElmuqwkFxJ03UoHpSW4ZvUM5lpKh8r0HaPLo/xhESbe6lvJUr2OOtX2ovHOoj6V6Zn93B7SqW9KM86FLt3qqPU4UROAy5NtHsZxfOZzN5hqxd8zqIOJt5Tp/pajZG+GkDVzBBKUh8xfJLapepZTHq0b5FfJdCLNxCrhTq5jnrKlmQcQG4V1JLALhX3RRP7As2/Z9xPftbp+sCmFfalSq8ht3H77TRTgmkiBxEDxJ3MpLuZuZrcE4BnJ9t+kubP4+OS7YqWa8yufjqM+kpVTWUB+dnsLyJXHqlX9wDH1nCcURcWaPtLooxxXbJ9W6fSXjzWQ3S/f1aZziJfQvmlXR7jc8SeaVN9Zc/7MtyYbLdKpb14tPnAL2o83qjzyYVej6+6IyXZjZFVNR3cQKzkbdJRiTZrUrxEaGZi6iYFn7NSmQtlleyCefsumjP3wL1G/trkUlxJmozhk9Q+mfIiVdkR+FCDxx81n/yMt15lbhjKsFuy3aHUvwfIZK4lBpcyfd8NOLza7micu2n+hnvUd4lVP5n7zpdRbICzLbLn8LepJ9TOuI0oy/TmRNvdgC9W252hkn293ES+bFKV/kSUEOu0V1ORAHkO+T0CDynwvFU7HPgMsFSHdosRe9tV/dl3OtXvUTnWlQXanlRZLyZ2ebLd2sAFVXZknF+TD0KqdjiwbaLdOsBTiVJxRTS1t+FkssH1MpX24tFOpZ6ylOP9i5jItm6Hdv2y4jm75+bhNLf6adTvyK1AfC7FSs1mKgzsSKxCakUVFQOohhhCSWoxwyepnZaimZsWgDXI3bRW7e6ajnMT8NcajrMpuUG4ReQ32a7LEeQGUp9HlOG7s9LeaKyjaO69Yrybic3rd0q03Z4Y3O0n65LfBLuN53AmgNqaGLRtah+iQZMt13gEzQ+cQfThUGC9Du2uLfCc2RDuDOCyAs9btXuBn5ErGfpKqg+gzqr4+ce7jbhPzFRSqrtv2f0Oqy5JNV7TpXDH+hmxCjdT+nIHigdQbZPdO7dToFym02o81ng30TmAWquOjvRoZfKriH9UZUeSziE3iSN7LTkq89m4FHFdnd0vq1KW4GuQ5fgktZDhk1SvIoNLsyrrhcY7i3rqs2+XbHcO7Rv8PYHcflSLkb9RVDmOb7oD42T7syX9d3+6fbLdP4CLquxIF84Abkm2fW6VHRkiKwObJ9vWtQo3473Ayzt87VPg+Z6XbPezAs9Zl+yqtOeSKxHVi0sqfv7xHib3ub8QuKLivoyXneRS5x5QD1L/SrCp/As4Jdl2yyo70jJ13l/9o8ZjjZcJaZeuvBe9exa5a8XLqW+/saksIHf9V7QE35+S7fYC3lfwuSvRbxf4A8cQSlKLGD5J9StSH78fbgoGxV9qOs6zku1OqLQX3XkIODnZNvt9qncLyf9e6pJ9/S4HbFRlRyrwzGS7Np7Di8j3yxC5HNn3whuAv1XZkQYtDmyRbNvG8+b35FZWLA1sVnFfbqr4+SeSmTj1T/KrT8qSndBVdSg41hnkArs6nZhst1WlvRheRcpYlm1hst3ilfaid9mVQm26Fs6U/VyDYnsH3gD8Pdn2i8SklkZLLBpAtYAhlKQWMHySmlGkTNbMynqh8bJ7CfQqOxiZ3Ti6bvOS7bKD9OrdJbRvwOtS8uUzqx6wLVs2mGmy7M5U5iXbbVNlJ4ZI9vVyKvWswm3CFuQGOG8nP7hWp3vJT1Kp+rOvyCSmOo/ZlhKwE1m2xmNlVyjU6Zxku/Wod2+kYXFf0x1IyJRobFI2HD2j0l4Uky1RO7vg8xbZd203YmXqt4lrkWkFj9UzA6iWMISS1CDDJ6k5RTakX62yXmi862o4xrLEvioZba3Dn90na+NKe6Gxzm26A5PIDtg+vtJelGsxYMNk2zr2lOtGtl9PooHBigH05GS7tp7HZdgk2a6tn3tQ7LwZRk0EY21U12r6Is4n7v0zOu0XpOLuaroDAyB7T3EFUXKzDV/ZEqGzk+1GfYNiYwlLEHt/nk78fL4G7EKxlVddW6yOgyjngnn7Lpoz98C9Rv76jkY7I2lYGD5JzbqxQNs1KuuFxru5hmOsn2x3EzETvI3OT7ZbhQjc2rYyZxDVvSdI1iXk9jzrpwBqXXL30/cBV1Xcl279nSjL06ks1RJE6ZYbKu/RYNsg2a6NA9dlyX72ZT9fmpDtW/Z71WBq4+fxfcRqjNmJtrNpdu/C5YmJWmvyyED+6Kqs5ei8oGJ2ZT1TU2aRLyPXphVQWesUbH8b8Engc10caz3gXSNfi4DLiMkV5xGTYP5MPjhLMYBqGUMoSTUyfJKal12SDw3XbW6JukpXZOuk9yI7MFXkNVK3u4B7iIGATtZncPc0aZPrm+7AJLKrCvvpfS57DtexorJbC4BbyP3c18cAqhfTiQGfjKsr7EfTnpBs1+bz5upkOwOo4dbWz+MbyYUzRQfDu7U0sCWxt8+mxCrJJ2IJQD3Wugz2auwVu3jMF4EdgW17OO40Yg/WjYBXj/n/lwJnAWcTgd759FAe2ACqhQyhJNXA8ElqhyLhQl03ghO5FjimwuefAeycaLegwj6Mld2vphdrJtu1eRAOYoAlU1Jplao7IqDYqso63ZRst0KlvShXNixrc4gM8R6T+V5WrrojA24lcns5LmKwg77Vk+3a/DPIBguuXB9e/wZubboTk8heV1a5F9BTgJcQA+fPoPMqXAn6a5JSN7o55x4EdgV+TwS4ZRoNpd4w8vdbgZOBk4ATKHiPagDVUoZQkipk+CS1x7+J2eeZAZns3hFVOGXkqyorAnck2tURDEE9m79nbzLaXrYuO8BS58bfw6yuc6SobBmPWZX2olzZc/ieSnvRu+w5vHylvRh82dn89xADSoMq+1nQ1sF7yO/jUuUAvtrtgaY7MIV/JdtlVrcXsTLwJmAPmr2nUf9avOkOVKzb7+82YgXU0cD25XXnMVYFXjPyBbEy6kjg+ySudTvVzFSDLpi37yJgL+DQpvsiaWAYPkntk62vPqfSXjQrO7D570p7Ua/sIFzbB6+zA6WWUqlHXasEi8r2q59eJ9nB5bpKh3YrW3LUwfTeZAdz2/566VX2dVRHKdxuZSeGLI5jbsMqG1I2IXtdWdaEkDWBLwHXAAdg+KTuLd10ByrWy0SfO4AXAB8G7i+nOx1tDRxCVDn4Mh1WqPlh2HKGUJJKZPgktdO5yXbrMbgX3tnybNkyXv2gnwbap5IdLLXyQj3aGlhmZ1z3k34qFziV7EDpEpX2YvBlx14GefUTwFLJdm19Lyuq7FUkUl16vU6dCewLXALsw+Dew6g+g3LvNJle97daCHwe2Bj4LvVdTywFvAe4HPgok4TXBlB9wBBKUgkMn6T2ygZQ04BtquxIg9ZNtmv7XipFtHl2t/qX+yjUZ1DO4UHe0Ftq2qAHihpcvYTA6wF/IFY8WYJZqtc1wJ7AE4BPU9/+sEuOHO9UJri3dyZin3BPKEk9MHyS2u2cAm23Izb+HDSzk+2urrAPdaurPELVsrMRB72sVFu0dYZxdtVD2/c8G6uf+jqVbMmXtu4vNmgGfZJw9rwZlBWGfvYNp0E4j7sNT+cCv6D3c3ghMZB+LXAzUWLsQSIYW0jnz6QNgHf12Ae1y/xku/uI1Tj9puyJltcB/wt8AngWsBuwE3FuVOkZwB+J94L//B4MoPqIIZSkLhg+Se13JXFjtUai7fOIpe2DZuNku0FaAZUte9X2QbiZyXaDEri1XVs3aM7uJdFPqwWyA+ltn/3tOVyP7Hv+oJdsy76O2ryaMxvaDkpIreLafB5XOSFke+B4ursWuRY4ETgd+DNwKb1dE8zFAGrQZAP984FnVtmRPvMwcV6dPvL39YhJrdsQwdSTKH81/FrACcAWwJ0wGKn8ULEcn6QCDJ+k/nFist3TgdWr7EhDtki2u7DSXtQruydO2wOo7OvR1RP1aOvrJRvC3FFpL8qVHUhfsdJe9G61ZLvszGNNLPt6WYrBLouYHdTOvi6bsFKy3SDufaecpWnveZz9PC66em9T4BiKhU/3AV8HtgYeD7yF2Lvm7/TXhBTV44Fku7ZeC7fFVcB3gLcCmxDvCc8C9gb+D7iIGEvs1XrAYaN/MYDqQ4ZQkhIMn6T+cnyy3XTgNVV2pAFLAXMS7e4mNjIeFNcl261VaS96t06y3fWV9kKj2vp6WTPZrq469WXIrshs6+9kVPYczr5naWJ3kNs3bCaDOdFkVPZ1tHalvehNtm+DtGpbxSxGe8/jbLhb5D1/CeAo8mWZHwK+QuwT8y6KlSPX8Lop2W6VSnsxeO4jSuYdArwJeDKxivOFwIHAX3p47l2JlZEGUP3KEErSFAyfpP5zHLAg2fZ1VXakAduTKwt9DrCo4r7U6Ypku/Uq7UVvViNXyuUhHLyuS1vDjuxAXD+9TrLn8ONpbzmxpcn/brLfryb2IPnXdzYU7EdXJts9ZgPzFlk/2c5zZri19fM4OyGkSIC6L/ly2tcAzwH2ob9WPat515JbmbMq+VKTmth9RAm9/yEqlWwI7E931+kfBAOovmYIJWkChk9Sf5oPHJtsuxXwlAr7Urcdk+3OrrQX9buaXKC2MvnBgro9NdnuGiKEUvU2aboDk9gw2e6aSntRrpvIldhanOo3fO7WZsl2/8QSfGW4KtmuredxGbIBVPa12YTsNVj2e9VgauN5PAN4QrJtdqB5RWKQOuMK4NnAWcn20lgLgBuSbds8ga8fXQ7sR0zAeAfFwuPnA+saQPU5QyhJYxg+Sf3tiAJtszd6bbcY8Mpk25Or7EgDFpDf0yob9NQtu3fXXyvtRXOrS7KlZurU1tdKdmb0+ZX2onznJdu19ffSlnN4WFycbPe0SnvRrHOT7Z5KeydMb5lsl31/0GBq4/v+bGBWot1V5Pdr24Pc9dB8YGcsyazeZD9HM+XdVdxDwDeJSSJ/Tj5mGvCCtn6gqwBDKEkYPkmD4LfkZxu+mriJ7Hc7Amsk2t0NnFFxX5qQ/Z62q7QX3Xt+st0fK+1FfkPtsq3Y0HGnshHt69fy5GZczwcurbgvZftDsl1bz+Edku0G8f23Cdn3wm0q7UV3vkBMlJnqK7M30sXkZk4vRzsH8FcjP7CZfX/QYHpG0x2YQDY8zQbFAK9Ktvs0+fBAmkx29Vx2go26cwNxDZndn3lbA6gBYQglDTXDJ2kwPAR8Pdl2BvDZCvtSl7cn2/2C2D9j0GQHdbNBT52WAZ6VbNvt4PUDyXaZ2bxVaGNZtenkQ4W6PIuY/djJX8jV9m+TbKDwgkp70Z1ZjGwMnWAAVY7s62VL2rWJ+jTgPcRKh6m+7ks81yL6+7x5YbLdVUSZTg2vrYEVmu7EOM9JtssGUEsCT0+0uxf4avI5y+J492A6M9lu20p7IYgJonsk2z7JE3KAGEJJQ8nwSRoshxIXcxmvpb8vrjcnSnFk/LDKjjToBHID7k8lVra0yS7kgp9bKTaTdqxsALVql8/fq7buxZY9r+qSDcT6sczmyeRep+uRn3lel53JrR68BwOoslwJ3JhoN412nccbEnuZTeU24M7k8/062e7VyXZ1en2yXfZ71OCaQftC1Ozn8UnJdpsT5bQ7OY7cnollattqcJXjTHL7yrZtIsegOhs4LdFutgHUgDGEkoaK4ZM0eO4Cvlyg/VfpPCjUVp9OtruK/hyYzvgnMC/Z9g0V9qMbb062+zmwsMtj3Jpst26Xz9+ruQ0dt5NX0lxZwvGmAbsm2x5fZUcqMp98v9t2Du+ZbPcr4N8V9mPY/DzZ7o2V9qKY5ybaFJlo8HPyky/atI/H2uRXJB9VZUfUN/ZsugNjPBl4YqLdrcSK5IzZyXZVl2KeyPoNHFPVu4vcfeE0YrLcoJkN7Jf4ypS+LkvmOnj5TFKtPnPBvH0XzZl74F4jf31Ho52mn+YoAAAeSklEQVSRVBXDJ2lwHUR8fq+eaDuHCHL2rbRH5dsFeFGy7SH0X1muIo4mVwbrHcBngPur7U7KVuQGJCG+v25lVgpADKj8pofjdGML4PE1HzNraeA1wLea7ghR7medRLt/kh/waptfkBvk2BP4ODF40rRNyK+wcSC9XEcBeyfaPZcYMP57td1JeUWizakFnm908kXms++9wJsKPHeV3keurNdNuGpQ4YXEtcI1TXeEYqv3stfd2VVG1ybblck9gAbXL8mVQ90TOKzarqRsTu6e4QQ6rxRcAfhE4rluAK5ItCvDRYk2M10BNaBcCSUNNMMnabDNBz5coP0HiBUP/WIl4GvJtncC36ywL23wA6I2ficrk98zq2ofS7a7FPh9D8e5Ltlu6x6O0a02rU6YyAfJlcWp2ruT7b5P/wbNPyW3Wm9ZYJ+K+5L1CXL7ct0A/LbivgybM8gPRv9vlR1JWpNcGbETCj5v9rN9d9oR9q8GvC3Z9jv07/uZyjWdYtf0VVkSeGuy7fcLPO9yyXaZ69wyLUY7909VOX5KbmX2NsAzKu5LxleIyUpTff0QWJB4rluSx3xy8W52LXV+G0ANMEMoaWDtbfgkDbwjgNMLtP8e7bjA7mQG8GNiQCvjC0QgN8juBb6dbPtxYhCsSS8GXpJs+2V6G4S7MNluLvXe16xJvgRhU55A84HlJuRWTgAcXmVHKvYA8I1k233JrQir0nOBVyXbHgw8WGFfhtHDxGBUxquAp1fYl4z30jnMvpLie/39nNyqiJnAFws+dxW+SKwu7eRB8pNsNBzeRPP7eL6N3H44V1Fs4lB2Vf4KBZ6zDC8lJrxpMN1GTODL2L/KjiQsT26i3Dnk9ra6mdy9cZ3jAjMSbe43gBpwhlDSwNnrgnn7Zgc5JPWvRcQA933J9ksCv6OZlSBFHEh+RuK1xODnMPgKuUHeFYH/V3FfOh3/kGTb24Dv9ni8S8ndZK0BPLvHYxXxOWCJGo/Xrc/RbNhxELmb0jPIle9os6+T22B9qZG2mdVHVViafDmaewu0VTHfBu5JtJtGrKaZWW13JvUEcqsYu5kY9xD5PS9fSQwoN2VHYiVWxveJAUJp1ExikkVT7/srkivZBdHPIhOH7k62W7nAc/ZqGvChGo+nZmTvEV9As58fuwGzEu2yq80XARck2j2dXDn/MqyVaHOzAdQQMISSBobhkzRcLqNYuabliBI421XTnZ7tT8ykztqHdux3VIdrgK8m276efBmVMk0jVuZlSyF9nNyA/FQeBv6cbPvfPR4r6yXAHjUdq1fLEqsjMze+ZdsD2CnZ9tNVdqQmtwAHJNvuTLH3wjIdRm4Teog959qwX9Uguhf4UrLtpgXalmkGsY9cp7B9AfmJCeMdQqy4yDiC2Hy9buuSL0l2P/HZJ433bOCjDR37G+T2arqd4hO/sns7ZT93yrAHza8cVfX+RpSuyzgEWLXCvkxmBrF3YEb2ewH4Y6LNdOANBZ6zF09NtLnSAGpIGEJJfc/wSRpO3yYGXbJGQ6i6BuMzZhGDnkUGZX5MsQvxQfAp4I5k20OAHSrsy0S+RH4G4YXEwGUZjk+22wXYqqRjTmYOEej0k22pf8XNHPIlqM5mcPYYOhC4sUDbumfkfhp4XbLtVeRXp6g7XyC/z927gL0r7MtEDiA3oeUI8ntSjLcA+J9k2xWBY6l3EHFV4NfkV28cAFxfXXfU5z5F/Xu27gW8Otn2IIrv1XR5st32BZ+3W08kP6FL/e+D5CpIrA0cRf0TsvYCNk60Owu4pMDz/ibZ7n3EZLQqTSNXmv1cA6ghYggl9S3DJ2m4vZMoUZW1GFHS7Vjyey1VZV3gVIqt2LmaGGwbNncB70m2nQn8Cnhhdd35j+lE2b9s3x4mXrOZOuYZxyXbjZaqWqak4443BziFqOXeb95MhFCZcni92oAIlDK/h0XkZ4b2g38Rr/2M6cQm2rtU153/mAbsR7HZ93uR2+Bb3bsf+ECB9l+lvs/Gj5I7N+8jXlu9+Cn59/lNifeXNXo8ZsaawIkjx8y4lPwqSA2vHwGvrelYu5IPY64r0Hasa4AbEu2eRv5c6tbaRDnyqq4D1T6XkV+1N5f4vKkrhNqCmGiSkd0XctTpwK2JdmsAny343EW9nLj27+R0A6ghYwgl9R3DJ0kPEBd3RfdI2ZmYTfUBYo+oOi02ctyLKLYJ6v3EpuvZlUCD5vvAT5JtlyRWB72H6la3rECsRCtSLuxzwB9K7MM/iJmBGU8mVs+V/Xp/ORECZzbwbqt3EDP5q/wetiZ+To9Ltj+UXBmRfvIrYuVqxkxiMOQjRCBVheWAH5Lf/wNiMGdQVqW13VHE7yfra0Q5rcWr6Q5LECuWs2UxPw3cVMJx30xuMA1iIPscYnCvKlsBfwKekmz/IBEq9Fp2VoNvJrFn2v5UOynkXcT1ZPazZS/y+86O9/tku891+fwZmwNnki8TrcHxMfL3yC8hKoVUPYlhC+I6KnM/chFxLVjEAvIVUvamulJ8q5ILz+4BTjaAGkKGUFLfMHySNOo2YrXLFQUftyxR6ukyIhBaqeR+jTcLeBtw8chxly7w2IeJC+Q/VdCvfvJOYhVYxnSiTNbJwIYl9+PlwN8pVibsj/Q+G34i3yzQ9sXEYMj6JRx3LSIU/AUTl7BYVMIxyjbVYPALiY2LX0+5oeVixIqJ04DVko+5hsHdJPy9xHtgxjRir6XTKX92+I5EOczXFHjMX4mSNqrPO4ErC7R/B/AXorxmmZ4FnEt+xfKZxOd8Gf5J7NvycLL9OkT5zs9Q7oSDZYjZ4n8kt6n6qA8TvxNprMlKbE4jylL/gQhUy7QGcDQRVmfHe39AfhXiRH6UbLcz5a96Hp3wdiaxAkrD5wHiunZBsv22wHmUfy0Mcc69k7imy0742pfuqkZ8hfjeM/6PuLYr8/t9HLHicJ1E26OB+w2ghtSYEOrIpvsiaUKGT5LGu57YxPjCLh67FjFQdBMxmL4L5ZWomEascjqY2Iz4m8ATuniet1N8BtggupOYoXdPgcdsR6wUOoLeBrFnEIHTWcTrJLuSBeJ3vwvlld4b6wcUC1+3JsKzA4gykEU9hVhlcDlxgzqZNu4H9R3gz1P8+xpEqPZnYj+gmT0ca3FgTyJs+TT5sib/JkoDFXmN95P5xDl8W4HHPBM4n1jB18uA5HQieJpH7BGQGRgYdTMRPGcHNFSOe4j3zvkFHrMJj/yOt6e3QaVnAr8kBsM3ST7mTmB3YGEPxx3vNxQLP2cQqwevJAa1e5lgs/LIc1xJhElFVqYcAXyxh2NrcL2fqVcVPYP4LD6aOA97sTrweeK6ZdcCj7uICLV78Tvy+9l9kQh5e7n2YOTxryeu9Q6kulWh6g/nEfeRWasT18JnEedLr6sRFyM+x88hSl5nJ0Z8n/xet+PdQL5s5nTi/eE0ilUmmcgsImS7gFh52MkiRj4jF+vxwOpjF8zbd9GcuQe+iXgdZDeklVQ9wydJk7mZCKGOBp7fxeNnEQOMLycGjs4jBrH+RgzwX8bUZXBmAbOB9YDNiBvmZ9NbWa+HgTcB3+3hOQbNhUQQ9BvyNzEziBnkexCrGH5F/G7PZepNpVcHtgGeR9yEdVOW4raRx3e7EX0nDxKrZY4u8JgliFmF7yduCE8mfi7XELPtR8OPFYm9PjYkyi69gFwt878RN35VlbXo1kNEKahzifJrk3kaEewdQsx8/h3xc7qMqVd2rU2c888nNlPvZk+stzN1SDYILidW453I1L+HsaYRm8W/mngPOIY4h/8E3D3F41bh0edwkZUbo+4gXvvXdvFY9e5vwMuIkj1FBmZ3HPm6DvgZ8Xo5i6nfi5cnzv8diAGzJxXs64PAKyi2aivrIGLiQ5Gyr2sQg1ufIz4zf0vsPXkZk0+ImEG8z29HrAx9Ed3tC3IssepbmshlRPmr/5uizTTifXtX4pz6OfH6PYe4VpnMYsS5+xxiwsPzKT6+ew9xLhcJvyeyEPgk8K1k+w+PHPeLxHXdVJ9vYy1BDJ6/jFjZ2+l69UF6D7rUP44gSjDuV+AxWxGvwTuJiRgnEatrr2Tqa+HpxGTLLYlJIC8lXwFg1OXE+0Mv9ifOpcx9C8T1+5nEit2fEBUjLqDzxKO1iO/1BUSp/CL3/d8hJkkaQA27C+btu3DO3ANHb5wNoaTmGT5J6uRuYCdiBuH/9PA8M4ga1eP3UXiA2IvpHmLm5kzipm+5ka8yl+/fQ9xE/qbE5xwUpxLlSn5FsVKGEDPSNueRfV9uIVbQzSf2qFiKCF4eT3cBwlg3EAPfl/f4PJ38lBiY2aXg46YTAxa9zvgb61/E63aJEp+zTJcTIcZxdJ7VuQKxkmH3kb8v4JGQ7gFiAHdJ4mZzNvHa6cWHGZ6w+RziZv13FD/PNh35+ujI328jwqF7eeQcXoE4h1fosZ+3EQMoF/T4POrNKcTA6s8oXlZuHWCfkS+Iz9ZrgduJz/PFidfMOhRb2Treg0TofmoPz9HJ+4j3oaKlIGcRP7+Xjfz9IaKc7a3EOfMw8Vm6CjGJpteB6WOIgbgHe3weDbYjiAlbmVB1faKc3AdG/n4v8Xl8O/F5PHo9vgaxuruX8dz7ieD10h6eY6wjiMklWybbP4kIrL5BTLI4n0euPUZXVi5LTJJai/g8nEN+pdPdxArJQ5LtNRj2Jz4/i35+rAi8ceQLHn0tvIBYub80cR+8PPGa7OUz5A5iklI2fJ3MfcB/EZNPiqwCfBqPrLZ/mLhHvIl4n5lPVElZlkeuG4reh466iTFjFQZQMoSS2sPwSVLWQuLi+vfA4fQ2oDTeEiNfK5b4nBP5GzF4U9bN7yA6hahVfgzdrWoYtfrIV9nOJ0KybOmVXr2NCEyb3GT6YSLcuRh4aoP96OS3xGq4I8nvAwExiLsh5e8pBrGK7QsVPG+bnU3MOD2WCPC6tQq9rTSdzMXEOVx0f0FV4zfESoZf0tvveznK31NsAbAbMSmiah8igqMDKPb+NdZixKzw7MzwIr5GhH1lliDU4Ho/sTpiqpK+E1mW8s9jiID6JcAZJT7nQ8RA+J8oVuJ7MWIF7zYl9mUBUelBw+lDRHB0IN1/flR5LTy6r3NZ979nEeWws3uxjTedCLS7KVk+lQeJSgl3jD2QxAXz9l1IzGb6YdN9kYaU4ZOkbvwWeDIxi3CqUgFtspAYhH4Ghk8Z5xKz1E5quiPjHE78DusKnyBmAe848t8mjM7+72Wz7jr9gCjH9++G+/Fv4uc2bOHTqAuJc/jYpjsyzg+Ap2P41DZnECtYT2+6I2PcCDyXesKnUV+k2tKu3ZhPvKe+G8Mn5S0iJoR8remOAFcR5bNPq+C5LyZC6ibPjfuJKhHzGuyDmvf/iBXobfr8gKhQsC1RAq9MPyYC4Cr24e3Gg0RZ0TPH/k8DKP2HIZTUGMMnSb24i1gZsiXtv+E6lVjB8iHc6L6IfxLByweJm+sm3UwMwL2lob5cDMwlykXU6U6iXMYPaj5ur46imZ/XqL8TM5u/19Dx2+JOojTYe5h6T7Y63E6Umdmd3vf+UDWuJ/Yn+jjNB8i/Jj63z27g2POIMO5nDRx7vNOIIPnHTXdEfWkhEVzuTazQacJPiXuFv1d4jN8Sn3VNXB/eTFzvnNLAsdU+JxOVCo5vuiMjfkacfxdV9PzfJ8LXqfaOq8OdxArLx0xYMYDSoxhCSbUzfJJUlr8QA1bbETeAbXIWcVE8lyi9p+IWEuWINqbeWehjj/8l4Ik0PwB3IbA1UYKyDvOIm9gTazpe2c4CnkK9IdCDxKbkWwB/rfG4bbYIOJjY++KoBo6/EPgmsBGxX4fabSHwKWATogxr3W4mSobtPPLnptxEzKR+MdXvNTjZ8Xcnrl8ua+D4GiyHENcvdX4u3gS8gliddEeHtmX4NbHK6uIajjXqt0RYfU6Nx1T73Ux8dryM2BOwCdcS59+u9L7nUycnEdf7P6/4OJM5lZio8buJ/tEASo9hCCXVxvBJUhXmEWHPJkQJgqZmQt1PzMZ6NrECom2hWL+6hriR2oLYJ6Tq0ov/Ar5KbI79PmLvgDa4kSjPtDdRT70K1xHXxNsTN5D97A7ie9mWalcyPESEHBsAn6D51RttdCOxj9hmwE+o/hx+gPidPAl4B/UMQKo8VxL7mTyDmEH9cMXHu5VYpbw+7RoPOJ6YgPEG4B81HO9K4J3AE4iVr/1S5ljtdx6wFfF+XGW4eztxLj+BuF6s03nEdeoniOvIqlxHBMQ70WxQrnb7FTGB7q3AJTUd81riHmVD6j3/bib2XtqBcvd5m8plxISV7Zgi6DOA0oQMoaTKGT5Jqto/iI2PH0dchB5M9Xsu3UmssngVsDpRj7qui99h8xdiRt2GwH6UOzN8EfAHYvBtXeC/aWcAs4iYTbweUZ6wrL1szgXeTIQo32OwBh5PIwaytycGs8sqBXQl8L/EQNc7aOfrpW0uAF4DzAY+SvmD6mcT5+7jid9JE6tHVJ6ziRnUGxKl+S4s8bkfJlaU7g6sTezX1nS514k8RLwnb0pMQDiCcidF3EeETS8mBisPpZ0/B/W/0ckajydKGpc5MeR0oszq42n2XP4XsRJ6NhFElbln6JnE97gB/VcaWc1YAHybmKC5E/FZUvakuvnA0cTK4fWIe5SmSm6eTEwCfSbxfd9V8vM/ROyJuysxwemHdLhfmlZyBzRg5sw9cAZwJPC6pvsiDRDDJ0lNWou4GN0KmENcNK5L8evC24lZTn8B/kSUvbiQdm/MvT3xvXbyQ5q7YejFpkSZoLnEzNN1yU04e4CYvfZHonzCacANlfSwWtOJ0jYvJmbhbQYsk3jcXcTgz8nAseTLxqwEvDTR7iJ6Lwszl1zJwf2JQDJrReJG/PnAs4jBnMx7wc1ECaFTiJ/beQxWUNeUJxKv3bnA04kBxBmJxy0gJhicTayCPY32hIDLEAMUnZRxngybDYnPtWcR733rA4slHreQeJ/7IzFJ5DjiM70fLUGE6nOB5xLXNaskH3sHcD7xM5g38t82BE5bEYOknfyK+lc07krnz9U7qL9U8BrEXpmdnDfy1Yv9iEClk80LHmt94ppiO+J8Xj3xmIXEtfhZRPmtU2jPe/9404iKCDsRA+ObA8snH3sTca9xEnACuVUsdb4m+uH+oq4+1nlt3KsliNfic0b+uxn5zw+I/RovIs6/00e+2rryf3Hi/Ntu5L+bAmsWePx8Yv+4PxP3I6cQE0/TDKDUkSGUVCrDJ0ltNJNYKbUmMSC9IjBrzL/PJ25G7gFuIW5u76u5jypuFrEi5XHAssByREjzADEz9Q6ipN/1DGZ4MB1Yh5jRvyqwwph/u4cY0LiW/gjb5lJNADXeEsSg9uOIm/CZI/9//sjXrURY2ZZSjINuJjEouRZx/i5LBFL/5pFz+FpiZnnVpdnUfjOIAca1gZWBJYlBp4eJc/Ze4Cri9fJgQ32sw4pEmL4ysDRx3kB8//cRZVuvoODgmTRiP6oJoMZbiXgdr8Yjg+KLiH1k5hPXLlfQnxOmRq1FXKetRny/o+4mwuBbiNW799bfNQ2p5YnrrtWBpYhrr1F3Ea/Nm4l7p35/Xa5AXO+vTXxWjg2E7yOuM28h3mtupsd7RQMopRhCSaUwfJIkSd2YSz0BlCRJmtx+1BNASdLAcA8opbgnlNQzwydJkiRJkiRJQ8MASmmGUFLXDJ8kSZIkSZIkDRUDKBViCCUVZvgkSZIkSZIkaegYQKkwQygpzfBJkiRJkiRJ0lAygFJXDKGkjgyfJEmSJEmSJA0tAyh1zRBKmpThkyRJkiRJkqShZgClnhhCSY9h+CRJkiRJkiRp6BlAqWeGUNJ/GD5JkiRJkiRJEgZQKokhlGT4JEmSJEmSJEmjDKBUGkMoDTHDJ0mSJEmSJEkawwBKpTKE0hAyfJIkSZIkSZKkcQygVDpDKA0RwydJkiRJkiRJmoABlCphCKUhYPgkSZIkSZIkSZMwgFJlDKE0wAyfJEmSJEmSJGkKBlCqlCGUBpDhkyRJkiRJkiR1YAClyhlCaYAYPkmSJEmSJElSggGUamEIpQFg+CRJkiRJkiRJSQZQqo0hlPqY4ZMkSZIkSZIkFTCt6Q5o+MyZe+AM4EjgdU33RUowfJIkSU3bANg70e63I1+SJKl8O458dXIgcEPFfZGkvmAApUYYQqlPGD5JkiRJkiRJUhdmNN0BDad/Xn3iotVnv+AYYjbnnKb7I03A8EmSJEmSJEmSumQApcYYQqnFDJ8kSZIkSZIkqQcGUGqUIZRayPBJkiRJkiRJknpkAKXGGUKpRQyfJEmSJEmSJKkEBlBqBUMotYDhkyRJkiRJkiSVxABKrWEIpQYZPkmSJEmSJElSiQyg1CqGUGqA4ZMkSZIkSZIklcwASq1jCKUaGT5JkiRJkiRJUgUMoNRKhlCqgeGTJEmSJEmSJFXEAEqtZQilChk+SZIkSZIkSVKFDKDUaoZQqoDhkyRJkiRJkiRVzABKrWcIpRIZPkmSJEmSJElSDQyg1BcMoVQCwydJkiRJkiRJqokBlPqGIZR6YPgkSZIkSZIkSTUygFJfMYRSFwyfJEmSJEmSJKlmBlDqO4ZQKsDwSZIkSZIkSZIaYAClvmQIpQTDJ0mSJEmSJElqiAGU+pYhlKZg+CRJkiRJkiRJDTKAUl8zhNIEDJ8kSZIkSZIkqWEGUOp7hlAaw/BJkiRJkiRJklrAAEoDwRBKGD5JkiRJkiRJUmsYQGlgGEINNcMnSZIkSZIkSWoRAygNFEOooWT4JEmSJEmSJEktYwClgWMINVQMnyRJkiRJkiSphQygNJAMoYaC4ZMkSZIkSZIktZQBlAaWIdRAM3ySJEmSJEmSpBYzgNJAM4QaSIZPkiRJkiRJktRyBlAaeIZQA8XwSZIkSZIkSZL6gAGUhoIh1EAwfJIkSZIkSZKkPmEApaFhCNXXDJ8kSZIkSZIkqY8YQGmoGEL1JcMnSZIkSZIkSeozBlAaOoZQfcXwSZIkSZIkSZL6kAGUhpIhVF8wfJIkSZIkSZKkPmUApaFlCNVqhk+SJEmSJEmS1McMoDTUDKFayfBJkiRJkiRJkvqcAZSGniFUqxg+SZIkSZIkSdIAMICSMIRqCcMnSZIkSZIkSRoQBlDSCEOoRhk+SZIkSZIkSdIAMYCSxjCEaoThkyRJkiRJkiQNGAMoaRxDqFoZPkmSJEmSJEnSADKAkiZgCFULwydJkiRJkiRJGlAGUNIkDKEqZfgkSZIkSZIkSQPMAEqagiFUJQyfJEmSJEmSJGnAGUBJHRhClcrwSZIkSZIkSZKGgAGUlGAIVQrDJ0mSJEmSJEkaEgZQUpIhVE8MnyRJkiRJkiRpiBhASQUYQnXF8EmSJEmSJEmShowBlFSQIVQhhk+SJEmSJEmSNIQMoKQuGEKlGD5JkiRJkiRJ0pAygJK6ZAg1JcMnSZIkSZIkSRpiBlBSDwyhJmT4JEmSJEmSJElDzgBK6pEh1KMYPkmSJEmSJEmSDKCkMhhCAYZPkiRJkiRJkqQRBlBSSYY8hDJ8kiRJkiRJkiT9hwGUVKIhDaEMnyRJkiRJkiRJj2IAJZVsyEIowydJkiRJkiRJ0mMYQEkVGJIQyvBJkiRJkiRJkjQhAyipIgMeQhk+SZIkSZIkSZImZQAlVWhAQyjDJ0mSJEmSJEnSlAygpIoNWAhl+CRJkiRJkiRJ6sgASqrBgIRQhk+SJEmSJEmSpBQDKKkmfR5CGT5JkiRJkiRJktIMoKQa9WkIZfgkSZIkSZIkSSrEAEqqWZ+FUIZPkiRJkiRJkqTCDKCkBvRJCGX4JEmSJEmSJEnqigGU1JCWh1CGT5IkSZIkSZKkrhlASQ1qaQhl+CRJkiRJkiRJ6okBlNSwloVQhk+SJEmSJEmSpJ4ZQEkt0JIQyvBJkiRJkiRJklQKAyipJRoOoQyfJEmSJEmSJEmlMYCSWqShEMrwSZIkSZIkSZJUKgMoqWVqDqEMnyRJkiRJkiRJpTOAklqophDK8EmSJEmSJEmSVAkDKKmlKg6hDJ8kSZIkSZIkSZUxgJJarKIQ6r0XzNv3ayU9lyRJkiRJkiRJjzG96Q5ImtoF8/ZdCLwB+GEJT/fhC+bt++USnkeSJEmSJEmSpEm5AkrqAyWthPrwBfP2/XyJ3ZIkSZIkSZIkaUIGUFKf6DGEMnySJEmSJEmSJNXGAErqI12GUIZPkiRJkiRJkqRaGUBJfaZgCGX4JEmSJEmSJEmqnQGU1IeSIZThkyRJkiRJkiSpEQZQUp/qEEIZPkmSJEmSJEmSGmMAJfWxSUIowydJkiRJkiRJUqOmNd0BSb2bM/fAGcCRwAWGT5IkSZIkSZKkpv1//TJqkIICpR4AAAAASUVORK5CYII=" alt="MONT" height="40" style="margin-bottom:24px"/><br>
<h1 style="margin:0 0 8px;font-size:22px;color:#e8f1fb">Запрос на доступ к полигону MONT</h1>
<hr style="border:none;border-top:1px solid rgba(255,255,255,0.08);margin:16px 0 24px"/>
</td></tr>
<tr><td style="padding:0 36px">
<p style="color:#c8d8ea;font-size:15px;line-height:1.7;margin:0 0 20px">Здравствуйте, <b>{pending.name}</b>!<br><br>
К сожалению, на данный момент мы не можем предоставить доступ к полигону.</p>
<p style="color:#c8d8ea;font-size:15px;line-height:1.7;margin:0 0 24px">
Для уточнения деталей, пожалуйста, свяжитесь с <b>{manager_contact}</b>.<br>
Если вы не знаете, кто ваш менеджер, напишите нам на <a href="mailto:mont@mont.ru" style="color:#5b9bd5">mont@mont.ru</a> — мы поможем.</p>
</td></tr>
<tr><td style="padding:20px 36px 28px;color:#4a6a8a;font-size:12px;border-top:1px solid rgba(255,255,255,0.06)">
С уважением, команда MONT
</td></tr>
</table></td></tr></table>
</body></html>"""
pending.status = "rejected"
db.commit()
try:
_send_email(pending.email, "Запрос на доступ к полигону MONT", html_email)
email_status = "Email отправлен"
except Exception as ex:
log_event("email_send_error", error=str(ex))
email_status = f"Ошибка отправки email: {ex}"
try:
_tg_api("editMessageText", {
"chat_id": chat_id, "message_id": msg_id,
"text": f"Отклонено. {email_status}",
})
except Exception:
pass
return {"ok": True}
@app.get("/robots.txt", include_in_schema=False)
def robots_txt():
from fastapi.responses import FileResponse
return FileResponse("static/robots.txt", media_type="text/plain")
@app.get("/sitemap.xml", include_in_schema=False)
def sitemap_xml():
from fastapi.responses import FileResponse
return FileResponse("static/sitemap.xml", media_type="application/xml")
@app.get("/api/public/services-by-category")
def public_services_by_category(db: Session = Depends(get_db)):
services = db.execute(
select(Service).where(Service.active == True).order_by(Service.name)
).scalars().all()
categories = db.execute(select(Category).order_by(Category.name)).scalars().all()
cat_map = {c.id: c.name for c in categories}
svc_cats: dict[int, list[str]] = {}
links = db.execute(select(ServiceCategory)).scalars().all()
for lnk in links:
svc_cats.setdefault(lnk.service_id, []).append(cat_map.get(lnk.category_id, ""))
result: dict[str, list[dict]] = {"Без категории": []}
for svc in services:
cats = svc_cats.get(svc.id, [])
entry = {"id": svc.id, "name": svc.name}
if cats:
for cat in cats:
result.setdefault(cat, []).append(entry)
else:
result["Без категории"].append(entry)
if not result["Без категории"]:
del result["Без категории"]
return result
@app.post("/api/request-access")
async def request_access(request: Request, db: Session = Depends(get_db)):
try:
data = await request.json()
except Exception:
raise HTTPException(status_code=400, detail="Invalid JSON")
name = str(data.get("name", "")).strip()
company = str(data.get("company", "")).strip()
email = str(data.get("email", "")).strip()
phone = str(data.get("phone", "")).strip()
manager = str(data.get("manager", "")).strip()
products = data.get("products", [])
import re as _re
if not name or not company or not email or not phone:
raise HTTPException(status_code=422, detail="Заполните все обязательные поля")
if not _re.match(r'^[^\s@]+@[^\s@]+\.[^\s@]+$', email):
raise HTTPException(status_code=422, detail="Некорректный email")
if not _re.match(r'^[\+\d][\d\s\-\(\)]{6,18}$', phone):
raise HTTPException(status_code=422, detail="Некорректный номер телефона")
products_text = ""
if products:
items = "\n".join(f"{p}" for p in products)
products_text = f"\n\n🖥 *Интересующие продукты:*\n{items}"
divider = "━━━━━━━━━━━━━━━━━━━━━━"
manager_text = f"\n🤝 *Менеджер MONT:* {manager}" if manager else ""
text = (
f"🔔 *Новый запрос доступа к полигону MONT*\n"
f"{divider}\n\n"
f"👤 *Имя:* {name}\n"
f"🏢 *Компания:* {company}\n"
f"📧 *Email:* {email}\n"
f"📱 *Телефон:* {phone}"
f"{manager_text}"
f"{products_text}"
)
log_event("ip_headers", xff=request.headers.get("x-forwarded-for",""), xri=request.headers.get("x-real-ip",""), client=str(request.client.host if request.client else ""))
ip = _get_real_ip(request)
geo = _get_geo(ip)
geo_text = ""
if geo:
geo_text += "\n📍 *Местоположение:* " + geo
geo_text += "\n🖥 *IP:* " + ip
text += geo_text
if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
log_event("telegram_not_configured")
return {"ok": True}
# save pending request
import json as _j2
req_id = _secrets.token_urlsafe(8)[:12]
_origin = request.headers.get('origin', '')
if 'stand.mont.ru' in _origin:
_req_portal_url = 'https://stand.mont.ru'
else:
_req_portal_url = PORTAL_URL
pending = PendingAccessRequest(
id=req_id, name=name, company=company, email=email,
phone=phone, manager=manager,
products_json=_j2.dumps(products, ensure_ascii=False),
portal_url=_req_portal_url,
)
db.add(pending)
db.commit()
try:
_tg_api("sendMessage", {
"chat_id": TELEGRAM_CHAT_ID,
"text": text,
"parse_mode": "Markdown",
"reply_markup": _make_approval_keyboard(req_id),
})
except Exception as e:
log_event("telegram_send_error", error=str(e))
return {"ok": True}
@app.post("/api/contact")
async def contact_ruslan(request: Request):
import re as _re
try:
data = await request.json()
except Exception:
raise HTTPException(status_code=400, detail="Invalid JSON")
name = str(data.get("name", "")).strip()
email = str(data.get("email", "")).strip()
phone = str(data.get("phone", "")).strip()
text = str(data.get("text", "")).strip()
if not name or not email or not phone or not text:
raise HTTPException(status_code=422, detail="Заполните все обязательные поля")
if not _re.match(r"^[^\s@]+@[^\s@]+\.[^\s@]+$", email):
raise HTTPException(status_code=422, detail="Некорректный email")
if not _re.match(r"^[\+\d][\d\s\-\(\)]{6,18}$", phone):
raise HTTPException(status_code=422, detail="Некорректный номер телефона")
divider = "━━━━━━━━━━━━━━━━━━━━━━"
msg = (
f"🔔 *Сообщение через форму полигона*\n"
f"{divider}\n\n"
f"👤 *Имя:* {name}\n"
f"📧 *Email:* {email}\n"
f"📱 *Телефон:* {phone}\n\n"
f"💬 *Сообщение:*\n{text}"
)
ip = _get_real_ip(request)
geo = _get_geo(ip)
geo_text = ""
if geo:
geo_text += f"\n📍 *Местоположение:* {geo}"
geo_text += f"\n🖥 *IP:* {ip}"
msg += geo_text
if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
log_event("telegram_not_configured")
return {"ok": True}
try:
payload = _json.dumps({
"chat_id": TELEGRAM_CHAT_ID,
"text": msg,
"parse_mode": "Markdown",
}).encode()
url = f"{TELEGRAM_API_URL}{TELEGRAM_BOT_TOKEN}/sendMessage"
req = _urllib_request.Request(url, data=payload, headers={"Content-Type": "application/json"})
with _urllib_request.urlopen(req, timeout=10) as resp:
resp.read()
except Exception as e:
log_event("telegram_send_error", error=str(e))
raise HTTPException(status_code=502, detail="Ошибка отправки")
return {"ok": True}
@app.post("/login")
def login(
request: Request,
username: str = Form(...),
password: str = Form(...),
csrf_token: str = Form(...),
db: Session = Depends(get_db),
):
cookie_csrf = request.cookies.get(CSRF_COOKIE)
if not cookie_csrf or csrf_token != cookie_csrf:
raise HTTPException(status_code=403, detail="CSRF failed")
user = db.scalar(select(User).where(User.username == username))
if not user or not verify_password(password, user.password_hash):
csrf = request.cookies.get(CSRF_COOKIE) or secrets.token_urlsafe(24)
response = templates.TemplateResponse(
"login.html",
{
"request": request,
"csrf_token": csrf,
"login_error": "Неверный логин или пароль",
"session_notice": "",
},
status_code=401,
)
response.set_cookie(CSRF_COOKIE, csrf, httponly=False, secure=True, samesite="lax", path="/")
return response
if not user_is_valid(user):
csrf = request.cookies.get(CSRF_COOKIE) or secrets.token_urlsafe(24)
response = templates.TemplateResponse(
"login.html",
{
"request": request,
"csrf_token": csrf,
"login_error": "Доступ к сервису приостоновлен, обратитесь к вашему менеджеру",
},
status_code=403,
)
response.set_cookie(CSRF_COOKIE, csrf, httponly=False, secure=True, samesite="lax", path="/")
return response
response = RedirectResponse(url="/", status_code=303)
issue_auth_cookie(response, user)
issue_csrf_cookie(response)
audit(db, "LOGIN", f"login success: {username}", user_id=user.id)
return response
@app.post("/logout")
def logout(request: Request):
response = RedirectResponse(url="/", status_code=303)
response.delete_cookie(COOKIE_NAME, path="/")
response.delete_cookie(CSRF_COOKIE, path="/")
return response
@app.get("/go/{slug}")
def go_service(
slug: str,
sw: Optional[int] = Query(default=None, ge=320, le=7680),
sh: Optional[int] = Query(default=None, ge=240, le=4320),
user: User = Depends(require_user),
db: Session = Depends(get_db),
):
total_started = time.perf_counter()
phase_ms = {}
def _mark(name: str, started: float) -> None:
phase_ms[name] = int((time.perf_counter() - started) * 1000)
def _emit(result: str, **extra) -> None:
payload = {
"user_id": user.id,
"service_slug": slug,
"result": result,
"total_ms": int((time.perf_counter() - total_started) * 1000),
}
payload.update(phase_ms)
payload.update(extra)
log_event("go_service_timing", **payload)
log_event("session_open_requested", user_id=user.id, service_slug=slug, sw=sw, sh=sh)
service = db.scalar(select(Service).where(Service.slug == slug, Service.active == True))
if not service:
raise HTTPException(status_code=404, detail="Service not found")
if service.type == ServiceType.VNC:
raise HTTPException(status_code=410, detail="VNC services are deprecated")
if not has_access(db, user.id, service.id):
raise HTTPException(status_code=403, detail="ACL denied")
client_width, client_height = sanitize_client_resolution(sw, sh)
log_event(
"session_open_resolution",
user_id=user.id,
service_slug=slug,
sw=sw,
sh=sh,
client_width=client_width,
client_height=client_height,
)
user_lock_started = time.perf_counter()
try:
with allocator_lock(db, 92000 + int(user.id), timeout_seconds=GO_USER_LOCK_TIMEOUT_SECONDS):
_mark("wait_user_lock_ms", user_lock_started)
t_existing = time.perf_counter()
existing_user_session = find_active_session_for_user_service(db, user.id, service.id)
_mark("check_existing_ms", t_existing)
if existing_user_session:
_emit("reuse_session", session_id=existing_user_session.id)
if existing_user_session.container_id and existing_user_session.container_id.startswith("RDPSLOT:"):
try:
_rdp_slot_id = int(existing_user_session.container_id.split(":", 1)[1])
threading.Thread(target=connect_rdp_slot, args=(_rdp_slot_id,), daemon=True).start()
except Exception:
pass
return RedirectResponse(url=session_redirect_url(existing_user_session), status_code=303)
t_limit = time.perf_counter()
cutoff = now_utc() - dt.timedelta(seconds=SESSION_IDLE_SECONDS)
active_rows = db.scalars(
select(SessionModel).where(
SessionModel.user_id == user.id,
SessionModel.status == SessionStatus.ACTIVE,
SessionModel.last_access_at >= cutoff,
)
).all()
active_rows = sorted(active_rows, key=lambda row: row.created_at)
active_service_ids = {row.service_id for row in active_rows}
_mark("check_limit_ms", t_limit)
if service.id not in active_service_ids and len(active_service_ids) >= MAX_ACTIVE_SERVICES_PER_USER:
oldest = next((row for row in active_rows if row.service_id != service.id), None)
if oldest:
t_rotate = time.perf_counter()
terminate_session_record(db, oldest, SessionStatus.ROTATED, stop_container=True)
db.commit()
_mark("rotate_oldest_ms", t_rotate)
log_event(
"session_rotated",
user_id=user.id,
closed_session_id=oldest.id,
closed_service_id=oldest.service_id,
new_service_id=service.id,
)
else:
_emit("max_services_redirect")
return RedirectResponse(url="/?launch_error=max_services", status_code=303)
if service.type == ServiceType.RDP:
t_rdp_slots = time.perf_counter()
slots = db.scalars(select(RdpSlot).where(RdpSlot.service_id == service.id)).all()
_mark("check_rdp_slots_ms", t_rdp_slots)
if slots:
session_id = str(uuid.uuid4())
try:
with allocator_lock(db, 91003, timeout_seconds=GO_POOL_LOCK_TIMEOUT_SECONDS):
busy_slot_ids: set[int] = set()
for row in db.scalars(
select(SessionModel).where(
SessionModel.status == SessionStatus.ACTIVE,
SessionModel.service_id == service.id,
SessionModel.container_id.like("RDPSLOT:%"),
)
).all():
try:
busy_slot_ids.add(int(row.container_id.split(":", 1)[1]))
except Exception:
pass
free_slot = next((s for s in slots if s.id not in busy_slot_ids), None)
if not free_slot:
_emit("rdp_all_slots_busy")
raise HTTPException(
status_code=503,
detail="Все слоты этого RDP сервиса заняты. Попробуйте позже.",
)
session_obj = SessionModel(
id=session_id,
user_id=user.id,
service_id=service.id,
container_id=f"RDPSLOT:{free_slot.id}",
status=SessionStatus.ACTIVE,
created_at=now_utc(),
last_access_at=now_utc(),
)
db.add(session_obj)
db.commit()
except LockTimeoutError:
_emit("rdp_slot_lock_timeout")
raise HTTPException(status_code=503, detail="Пул RDP занят. Повторите через несколько секунд.")
log_event("session_created", user_id=user.id, service_slug=service.slug, session_id=session_id, mode="rdp_slot", slot_id=free_slot.id)
audit(db, "SESSION_CREATE_RDP_SLOT", f"service={service.slug} session={session_id} slot={free_slot.id}", user_id=user.id)
_emit("session_created_rdp_slot", session_id=session_id, slot_id=free_slot.id)
threading.Thread(target=connect_rdp_slot, args=(free_slot.id,), daemon=True).start()
return RedirectResponse(url=f"/s/{session_id}/", status_code=303)
else:
# Legacy: no slots configured — exclusive single-session behaviour
active_owner = find_active_session_for_service(db, service.id)
if active_owner:
if active_owner.user_id != user.id:
_emit("rdp_busy_legacy")
raise HTTPException(status_code=503, detail="RDP сервис занят. Попробуйте позже.")
_emit("reuse_rdp_session", session_id=active_owner.id)
return RedirectResponse(url=session_redirect_url(active_owner), status_code=303)
session_id = str(uuid.uuid4())
if service.type == ServiceType.WEB and WEB_POOL_SIZE > 0:
try:
t_pool_lock = time.perf_counter()
with allocator_lock(db, 91001, timeout_seconds=GO_POOL_LOCK_TIMEOUT_SECONDS):
_mark("wait_web_pool_lock_ms", t_pool_lock)
t_ensure = time.perf_counter()
ensure_web_pool()
_mark("ensure_web_pool_ms", t_ensure)
t_acquire = time.perf_counter()
slot = acquire_web_pool_slot(db)
_mark("acquire_web_slot_ms", t_acquire)
slot_cid = f"WEBPOOLIDX:{slot}"
t_dispatch = time.perf_counter()
terminate_active_slot_sessions(db, slot_cid)
dispatch_web_pool_target(slot, service, width=client_width, height=client_height)
_mark("dispatch_web_target_ms", t_dispatch)
t_commit = time.perf_counter()
session_obj = SessionModel(
id=session_id,
user_id=user.id,
service_id=service.id,
container_id=slot_cid,
status=SessionStatus.ACTIVE,
created_at=now_utc(),
last_access_at=now_utc(),
)
db.add(session_obj)
db.commit()
_mark("db_commit_ms", t_commit)
except LockTimeoutError:
_emit("web_pool_lock_timeout")
raise HTTPException(status_code=503, detail="Пул WEB занят. Повторите через несколько секунд.")
except Exception as exc:
logger.exception("web_pool_dispatch_failed slug=%s user_id=%s", slug, user.id)
log_event("session_create_failed", level=logging.ERROR, user_id=user.id, service_slug=slug, mode="web_pool", error=str(exc))
audit(db, "SESSION_CREATE_FAILED", f"slug={slug} err={str(exc)}", user_id=user.id)
_emit("web_pool_create_failed", error=str(exc))
raise HTTPException(status_code=502, detail="WEB runtime failed to switch target")
log_event("session_created", user_id=user.id, service_slug=service.slug, session_id=session_id, mode="web_pool", slot=slot)
audit(db, "SESSION_CREATE_WEB_POOL", f"service={service.slug} session={session_id} slot={slot}", user_id=user.id)
_emit("session_created_web_pool", session_id=session_id, slot=slot)
return RedirectResponse(url=f"/s/{session_id}/", status_code=303)
if service_uses_universal_pool(service):
try:
t_pool_lock = time.perf_counter()
with allocator_lock(db, 91002, timeout_seconds=GO_POOL_LOCK_TIMEOUT_SECONDS):
_mark("wait_universal_pool_lock_ms", t_pool_lock)
t_ensure = time.perf_counter()
ensure_universal_pool()
_mark("ensure_universal_pool_ms", t_ensure)
t_acquire = time.perf_counter()
slot = acquire_universal_slot(db)
_mark("acquire_universal_slot_ms", t_acquire)
slot_cid = f"POOLIDX:{slot}"
t_dispatch = time.perf_counter()
terminate_active_slot_sessions(db, slot_cid)
dispatch_universal_target(slot, service, width=client_width, height=client_height)
_mark("dispatch_universal_target_ms", t_dispatch)
t_commit = time.perf_counter()
session_obj = SessionModel(
id=session_id,
user_id=user.id,
service_id=service.id,
container_id=slot_cid,
status=SessionStatus.ACTIVE,
created_at=now_utc(),
last_access_at=now_utc(),
)
db.add(session_obj)
db.commit()
_mark("db_commit_ms", t_commit)
except LockTimeoutError:
_emit("universal_pool_lock_timeout")
raise HTTPException(status_code=503, detail="Пул RDP занят. Повторите через несколько секунд.")
except Exception as exc:
logger.exception("universal_pool_dispatch_failed slug=%s user_id=%s", slug, user.id)
log_event("session_create_failed", level=logging.ERROR, user_id=user.id, service_slug=slug, mode="universal_pool", error=str(exc))
audit(db, "SESSION_CREATE_FAILED", f"slug={slug} err={str(exc)}", user_id=user.id)
_emit("universal_pool_create_failed", error=str(exc))
raise HTTPException(status_code=502, detail="Universal runtime failed to switch target")
log_event("session_created", user_id=user.id, service_slug=service.slug, session_id=session_id, mode="universal_pool", slot=slot)
audit(db, "SESSION_CREATE_POOL", f"service={service.slug} session={session_id} slot={slot}", user_id=user.id)
_emit("session_created_universal_pool", session_id=session_id, slot=slot)
return RedirectResponse(url=f"/s/{session_id}/", status_code=303)
if service.type == ServiceType.WEB and desired_pool_size(service) > 0:
t_warm = time.perf_counter()
ensure_warm_pool(service)
open_warm_web_url(service, service.target)
_mark("warm_pool_prepare_ms", t_warm)
t_commit = time.perf_counter()
session_obj = SessionModel(
id=session_id,
user_id=user.id,
service_id=service.id,
container_id=f"POOL:{service.slug}",
status=SessionStatus.ACTIVE,
created_at=now_utc(),
last_access_at=now_utc(),
)
db.add(session_obj)
db.commit()
_mark("db_commit_ms", t_commit)
log_event("session_created", user_id=user.id, service_slug=service.slug, session_id=session_id, mode="warm_pool")
audit(db, "SESSION_CREATE_POOL", f"service={service.slug} session={session_id}", user_id=user.id)
_emit("session_created_warm_pool", session_id=session_id)
return RedirectResponse(url=f"/s/{session_id}/", status_code=303)
try:
t_create = time.perf_counter()
container_id = create_runtime_container(service, session_id)
_mark("create_runtime_container_ms", t_create)
except Exception as exc:
logger.exception("session_container_create_failed slug=%s user_id=%s", slug, user.id)
log_event("session_create_failed", level=logging.ERROR, user_id=user.id, service_slug=slug, mode="single_runtime", error=str(exc))
audit(db, "SESSION_CREATE_FAILED", f"slug={slug} err={str(exc)}", user_id=user.id)
_emit("single_runtime_create_failed", error=str(exc))
raise HTTPException(status_code=502, detail="Session runtime failed to start")
t_commit = time.perf_counter()
session_obj = SessionModel(
id=session_id,
user_id=user.id,
service_id=service.id,
container_id=container_id,
status=SessionStatus.ACTIVE,
created_at=now_utc(),
last_access_at=now_utc(),
)
db.add(session_obj)
db.commit()
_mark("db_commit_ms", t_commit)
log_event("session_created", user_id=user.id, service_slug=service.slug, session_id=session_id, mode="single_runtime", container_id=container_id)
audit(db, "SESSION_CREATE", f"service={service.slug} session={session_id}", user_id=user.id)
t_wait = time.perf_counter()
ready = wait_for_session_route(session_id)
_mark("wait_session_route_ms", t_wait)
log_event("session_route_ready", session_id=session_id, ready=ready)
_emit("session_created_single_runtime", session_id=session_id, ready=ready)
return RedirectResponse(url=f"/s/{session_id}/", status_code=303)
except LockTimeoutError:
_emit("user_lock_timeout")
raise HTTPException(status_code=429, detail="Слишком много параллельных запусков. Повторите через несколько секунд.")
@app.get("/svc/{slug}/", response_class=HTMLResponse)
def service_wait_page(slug: str, request: Request, user: User = Depends(require_user), db: Session = Depends(get_db)):
service = db.scalar(select(Service).where(Service.slug == slug, Service.active == True))
if not service:
raise HTTPException(status_code=404, detail="Service not found")
if not has_access(db, user.id, service.id):
raise HTTPException(status_code=403, detail="ACL denied")
return HTMLResponse(
content="""
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>Service Starting</title>
<style>
body { font-family: sans-serif; background: #f4f6f8; display: grid; place-items: center; height: 100vh; margin: 0; color:#1b3145; }
.card { background: #fff; padding: 1rem 1.2rem; border-radius: 10px; box-shadow: 0 8px 20px rgba(0,0,0,.08); min-width: 340px; }
.title { font-weight: 700; margin-bottom: 0.5rem; }
.state { margin-bottom: 0.6rem; }
ul { margin: 0; padding-left: 1.1rem; }
li { margin: 0.2rem 0; }
</style>
</head>
<body>
<div class="card">
<div class="title">Сервис запускается</div>
<div class="state" id="state">Проверка...</div>
<ul id="steps"></ul>
</div>
<script>
const slug = window.location.pathname.replace(/^\\/svc\\//, '').replace(/\\/$/, '');
async function tick() {
const r = await fetch(`/api/services/${slug}/status`, {credentials:'include'});
if (!r.ok) return;
const data = await r.json();
document.getElementById('state').textContent = data.message || 'Запуск...';
const ul = document.getElementById('steps');
ul.innerHTML = '';
(data.steps || []).forEach((x) => {
const li = document.createElement('li');
li.textContent = x;
ul.appendChild(li);
});
if (data.ready) window.location.replace(`/svc/${slug}/`);
}
setInterval(tick, 1000);
tick();
</script>
</body>
</html>
""".strip(),
status_code=200,
)
@app.get("/s/{session_id}/", response_class=HTMLResponse)
def session_wait_page(session_id: str, request: Request, user: User = Depends(require_user), db: Session = Depends(get_db)):
sess = db.get(SessionModel, session_id)
if not sess or sess.user_id != user.id:
raise HTTPException(status_code=404, detail="Session not found")
if sess.status != SessionStatus.ACTIVE:
raise HTTPException(status_code=410, detail="Session is not active")
service = db.get(Service, sess.service_id)
service_title = service.name if service else "Сервис"
is_rdp = service and service.type == ServiceType.RDP
label = "Ожидайте..." if is_rdp else "Сессия запускается..."
redirect_target = session_redirect_url(sess)
return HTMLResponse(
content=f"""
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>{service_title}</title>
<style>
*{{box-sizing:border-box}}
body{{font-family:sans-serif;background:#0f1720;display:grid;place-items:center;height:100vh;margin:0;color:#dce8f5}}
.card{{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);padding:1.6rem 2rem;border-radius:14px;
box-shadow:0 12px 32px rgba(0,0,0,.4);min-width:320px;max-width:440px;text-align:center}}
.spinner{{width:48px;height:48px;border:4px solid rgba(220,232,245,.15);border-top-color:#2a8cd6;
border-radius:50%;animation:spin .9s linear infinite;margin:0 auto 1.2rem}}
@keyframes spin{{to{{transform:rotate(360deg)}}}}
.title{{font-size:1.15rem;font-weight:700;margin-bottom:.5rem;color:#fff}}
.state{{font-size:.9rem;color:#a0b8cc;margin-bottom:.8rem;min-height:1.2em}}
ul{{margin:0;padding:0;list-style:none;font-size:.82rem;color:#7a99b0;text-align:left}}
li::before{{content:"· ";color:#2a8cd6}}
li+li{{margin-top:.2rem}}
.sid{{display:block;margin-top:1.2rem;font-size:.7rem;color:rgba(160,184,204,.4);word-break:break-all}}
</style>
</head>
<body>
<div class="card">
<div class="spinner"></div>
<div class="title">{label}</div>
<div class="state" id="state">Проверка...</div>
<ul id="steps"></ul>
<span class="sid">{session_id}</span>
</div>
<script>
const sessionId = "{session_id}";
async function tick() {{
const r = await fetch(`/api/sessions/${{sessionId}}/status`, {{credentials:'include'}});
if (!r.ok) return;
const data = await r.json();
document.getElementById('state').textContent = data.message || 'Запуск...';
const ul = document.getElementById('steps');
ul.innerHTML = '';
(data.steps || []).forEach((x) => {{
const li = document.createElement('li');
li.textContent = x;
ul.appendChild(li);
}});
if (data.ready) window.location.replace(data.redirect_url || "{redirect_target}");
}}
setInterval(tick, 1000);
tick();
</script>
</body>
</html>
""".strip(),
status_code=200,
)
@app.get("/s/{session_id}/view", response_class=HTMLResponse)
def session_view_page(session_id: str, request: Request, user: User = Depends(require_user), db: Session = Depends(get_db)):
sess = db.get(SessionModel, session_id)
if not sess or sess.user_id != user.id:
raise HTTPException(status_code=404, detail="Session not found")
if sess.status != SessionStatus.ACTIVE:
raise HTTPException(status_code=410, detail="Session is not active")
service = db.get(Service, sess.service_id)
if not service:
raise HTTPException(status_code=404, detail="Service not found")
iframe_src = None
if sess.container_id and sess.container_id.startswith("POOL:"):
iframe_src = f"/svc/{service.slug}/?sid={session_id}"
elif sess.container_id and sess.container_id.startswith("WEBPOOLIDX:"):
try:
slot = int(sess.container_id.split(":", 1)[1])
iframe_src = f"/w/{slot}/?sid={session_id}"
except Exception:
iframe_src = None
elif sess.container_id and sess.container_id.startswith("POOLIDX:"):
try:
slot = int(sess.container_id.split(":", 1)[1])
iframe_src = f"/u/{slot}/?sid={session_id}"
except Exception:
iframe_src = None
elif sess.container_id and sess.container_id.startswith("RDPSLOT:"):
try:
slot = int(sess.container_id.split(":", 1)[1])
iframe_src = f"/rdp/{slot}/?sid={session_id}"
except Exception:
iframe_src = None
if iframe_src:
creds_html = ""
if service.type != ServiceType.RDP and (service.svc_login or service.svc_password):
rows = ""
if service.svc_login:
login_esc = service.svc_login.replace('"', '&quot;').replace('<', '&lt;')
rows += f'''<div class="cr-row"><span class="cr-label">Логин</span><span class="cr-val">{login_esc}</span></div>'''
if service.svc_password:
pass_esc = service.svc_password.replace('"', '&quot;').replace('<', '&lt;')
rows += f'''<div class="cr-row"><span class="cr-label">Пароль</span><span class="cr-val cr-masked">{pass_esc}</span></div>'''
if service.svc_cred_hint:
hint_esc = service.svc_cred_hint.replace('<', '&lt;')
rows += f'''<p class="cr-hint">{hint_esc}</p>'''
creds_html = f'''
<div class="creds-panel" id="creds-panel">
<button class="creds-close" id="creds-close" title="Закрыть">✕</button>
{rows}
</div>
<script>
document.getElementById("creds-close").onclick = function() {{
document.getElementById("creds-panel").style.display = "none";
}};
</script>'''
return HTMLResponse(
content=f"""
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>{service.name}</title>
<style>
html,body,iframe {{ margin:0; width:100%; height:100%; border:0; background:#0f1720; }}
.creds-panel{{
position:fixed;right:16px;top:16px;z-index:999;
background:linear-gradient(180deg,rgba(15,24,36,.88),rgba(9,14,22,.94));
border:1px solid rgba(255,255,255,.22);backdrop-filter:blur(6px);
box-shadow:0 10px 28px rgba(0,0,0,.4);padding:10px 12px 11px;border-radius:14px;
min-width:220px;max-width:320px;
}}
.creds-close{{
position:absolute;top:6px;right:8px;background:none;border:none;
color:rgba(255,255,255,.55);font-size:14px;cursor:pointer;line-height:1;padding:2px 4px;
}}
.creds-close:hover{{color:#fff}}
.cr-row{{display:flex;align-items:center;gap:6px;margin-bottom:5px;}}
.cr-label{{font:600 11px/1 sans-serif;text-transform:uppercase;letter-spacing:.04em;
color:rgba(180,210,240,.7);min-width:46px;flex-shrink:0;}}
.cr-val{{font:600 13px/1 monospace;color:#dce8f5;flex:1;overflow:hidden;
text-overflow:ellipsis;white-space:nowrap;}}
.cr-masked{{letter-spacing:.1em;font-size:14px;}}
.cr-hint{{margin:4px 0 0;font:400 11px/1.35 sans-serif;color:rgba(180,210,240,.65);}}
</style>
</head>
<body>
<iframe src="{iframe_src}" allow="clipboard-read; clipboard-write"></iframe>{creds_html}
</body>
</html>
""".strip()
)
return RedirectResponse(url=f"/s/{session_id}/", status_code=303)
@app.post("/api/sessions/{session_id}/touch")
def touch_session(session_id: str, user: User = Depends(require_user), db: Session = Depends(get_db)):
sess = db.get(SessionModel, session_id)
if not sess or sess.user_id != user.id:
raise HTTPException(status_code=404, detail="Session not found")
if sess.status != SessionStatus.ACTIVE:
reason = session_closed_reason(sess, db)
log_event(
"session_touch_rejected",
level=logging.WARNING,
session_id=session_id,
user_id=user.id,
status=sess.status.value,
reason=reason,
)
return JSONResponse(
status_code=410,
content={
"ok": False,
"reason": reason,
"status": sess.status.value,
},
)
sess.last_access_at = now_utc()
db.commit()
return {"ok": True}
@app.post("/api/sessions/{session_id}/close")
def close_session(session_id: str, user: User = Depends(require_user), db: Session = Depends(get_db)):
sess = db.get(SessionModel, session_id)
if not sess or sess.user_id != user.id:
raise HTTPException(status_code=404, detail="Session not found")
if sess.status != SessionStatus.ACTIVE:
log_event(
"session_close_already_closed",
session_id=session_id,
user_id=user.id,
status=sess.status.value,
reason=session_closed_reason(sess, db),
)
return {"ok": True, "status": sess.status.value}
terminate_session_record(db, sess, SessionStatus.TERMINATED, stop_container=True)
db.commit()
log_event("session_closed_by_user", session_id=session_id, user_id=user.id)
return {"ok": True, "status": "TERMINATED"}
@app.get("/api/services/{slug}/status")
def service_status(slug: str, user: User = Depends(require_user), db: Session = Depends(get_db)):
service = db.scalar(select(Service).where(Service.slug == slug, Service.active == True))
if not service:
raise HTTPException(status_code=404, detail="Service not found")
if service.type == ServiceType.VNC:
raise HTTPException(status_code=410, detail="VNC services are deprecated")
if not has_access(db, user.id, service.id):
raise HTTPException(status_code=403, detail="ACL denied")
pool = get_pool_status_for_service(service)
route_ok = route_ready(f"/svc/{slug}/")
ready = route_ok and (pool["running"] > 0 if desired_pool_size(service) > 0 else True)
steps = [
f"ACL: OK ({user.username})",
f"Пул: {pool['running']} / {pool['desired']}",
f"Маршрут /svc/{slug}/: {'OK' if route_ok else 'ожидание'}",
]
return {
"ready": ready,
"message": "Готово, открываем..." if ready else "Поднимаем контейнер и маршрут...",
"steps": steps,
}
@app.get("/api/sessions/{session_id}/status")
def session_status(session_id: str, user: User = Depends(require_user), db: Session = Depends(get_db)):
sess = db.get(SessionModel, session_id)
if not sess or sess.user_id != user.id:
raise HTTPException(status_code=404, detail="Session not found")
if sess.status != SessionStatus.ACTIVE:
raise HTTPException(status_code=410, detail="Session is not active")
service = db.get(Service, sess.service_id)
pooled_web = bool(sess.container_id and sess.container_id.startswith("POOL:") and service and service.type == ServiceType.WEB)
web_pool_idx = None
universal_pool_idx = None
if sess.container_id and sess.container_id.startswith("WEBPOOLIDX:"):
try:
web_pool_idx = int(sess.container_id.split(":", 1)[1])
except Exception:
web_pool_idx = None
if sess.container_id and sess.container_id.startswith("POOLIDX:"):
try:
universal_pool_idx = int(sess.container_id.split(":", 1)[1])
except Exception:
universal_pool_idx = None
pooled_rdp = bool(sess.container_id and sess.container_id.startswith("POOL:") and service and service.type == ServiceType.RDP)
rdp_slot_idx = None
if sess.container_id and sess.container_id.startswith("RDPSLOT:"):
try:
rdp_slot_idx = int(sess.container_id.split(":", 1)[1])
except Exception:
rdp_slot_idx = None
if pooled_web and service:
route_path = f"/svc/{service.slug}/"
elif pooled_rdp and service:
route_path = f"/svc/{service.slug}/"
elif rdp_slot_idx is not None:
route_path = f"/rdp/{rdp_slot_idx}/"
else:
route_path = f"/s/{session_id}/"
if web_pool_idx is not None:
route_path = f"/w/{web_pool_idx}/"
if universal_pool_idx is not None:
route_path = f"/u/{universal_pool_idx}/"
route_ok = route_ready(route_path)
running = container_running(sess.container_id)
ready = running and route_ok
steps = [
f"Контейнер: {'running' if running else 'starting'}",
f"Маршрут {route_path}: {'OK' if route_ok else 'ожидание'}",
]
payload = {
"ready": ready,
"message": "Готово, открываем..." if ready else "Запуск сессии...",
"steps": steps,
}
if pooled_web or pooled_rdp:
payload["redirect_url"] = f"/s/{session_id}/view"
if web_pool_idx is not None:
payload["redirect_url"] = f"/s/{session_id}/view"
if universal_pool_idx is not None:
payload["redirect_url"] = f"/s/{session_id}/view"
if rdp_slot_idx is not None:
payload["redirect_url"] = f"/s/{session_id}/view"
return payload
@app.post("/api/admin/services")
def create_service(payload: dict, request: Request, _: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
service_type = ServiceType(payload["type"])
if service_type == ServiceType.VNC:
raise HTTPException(status_code=400, detail="VNC services are no longer supported")
target = payload["target"]
if service_type == ServiceType.WEB:
target = normalize_web_target(target)
elif service_type == ServiceType.RDP:
parse_rdp_target(target)
service = Service(
name=payload["name"],
slug=payload["slug"],
type=service_type,
target=target,
comment=payload.get("comment", ""),
svc_login=payload.get("svc_login", ""),
svc_password=payload.get("svc_password", ""),
svc_cred_hint=payload.get("svc_cred_hint", ""),
active=payload.get("active", True),
warm_pool_size=max(0, int(payload.get("warm_pool_size", 0))),
)
db.add(service)
db.flush()
set_service_categories(db, service.id, payload.get("category_ids", []))
db.commit()
if service.type == ServiceType.WEB and WEB_POOL_SIZE <= 0:
ensure_warm_pool(service)
elif service_uses_universal_pool(service):
ensure_universal_pool()
return {"id": service.id}
@app.get("/api/admin/services/{service_id}/containers/status")
def service_containers_status(service_id: int, _: User = Depends(require_admin), db: Session = Depends(get_db)):
service = db.get(Service, service_id)
if not service:
raise HTTPException(status_code=404, detail="Service not found")
out = get_pool_detailed_status(service)
out["active_sessions"] = get_active_sessions_count(db, service.id)
return out
@app.post("/api/admin/services/{service_id}/icon")
async def upload_service_icon(
service_id: int,
request: Request,
file: UploadFile = File(...),
_: User = Depends(require_admin),
db: Session = Depends(get_db),
):
validate_csrf(request)
service = db.get(Service, service_id)
if not service:
raise HTTPException(status_code=404, detail="Service not found")
new_path = await store_service_icon(service, file)
old_path = service.icon_path
service.icon_path = new_path
db.commit()
if old_path and old_path != new_path:
remove_icon_file(old_path)
return {"ok": True, "icon_path": new_path}
@app.delete("/api/admin/services/{service_id}/icon")
def delete_service_icon(service_id: int, request: Request, _: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
service = db.get(Service, service_id)
if not service:
raise HTTPException(status_code=404, detail="Service not found")
old_path = service.icon_path
service.icon_path = ""
db.commit()
remove_icon_file(old_path)
return {"ok": True}
@app.put("/api/admin/services/{service_id}")
def edit_service(service_id: int, payload: dict, request: Request, _: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
service = db.get(Service, service_id)
if not service:
raise HTTPException(status_code=404, detail="Service not found")
for key in ["name", "slug", "target", "active", "comment", "svc_login", "svc_password", "svc_cred_hint"]:
if key in payload:
setattr(service, key, payload[key])
if "type" in payload:
service.type = ServiceType(payload["type"])
if service.type == ServiceType.VNC:
raise HTTPException(status_code=400, detail="VNC services are no longer supported")
if service.type == ServiceType.WEB:
service.target = normalize_web_target(service.target)
elif service.type == ServiceType.RDP:
parse_rdp_target(service.target)
if "warm_pool_size" in payload:
service.warm_pool_size = max(0, int(payload["warm_pool_size"]))
if "category_ids" in payload:
set_service_categories(db, service.id, payload.get("category_ids", []))
db.commit()
if service.type == ServiceType.WEB:
if WEB_POOL_SIZE <= 0:
ensure_warm_pool(service)
open_warm_web_url(service, service.target)
elif service_uses_universal_pool(service):
ensure_universal_pool()
return {"ok": True}
@app.delete("/api/admin/services/{service_id}")
def delete_service(service_id: int, request: Request, _: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
service = db.get(Service, service_id)
if not service:
raise HTTPException(status_code=404, detail="Service not found")
if service.type == ServiceType.WEB and WEB_POOL_SIZE <= 0:
ensure_warm_pool(service, 0)
remove_icon_file(service.icon_path)
db.delete(service)
db.commit()
return {"ok": True}
@app.post("/api/admin/services/{service_id}/prewarm")
def prewarm_now(service_id: int, request: Request, _: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
service = db.get(Service, service_id)
if not service:
raise HTTPException(status_code=404, detail="Service not found")
if service.type == ServiceType.WEB:
ensure_web_pool()
return {"ok": True, "pool": get_web_pool_status()}
if service_uses_universal_pool(service):
ensure_universal_pool()
return {"ok": True, "pool": get_universal_pool_status()}
if service.type == ServiceType.RDP:
return {"ok": True, "pool": get_pool_status_for_service(service), "message": "RDP запускается on-demand"}
ensure_warm_pool(service)
return {"ok": True, "pool": get_pool_status_for_service(service)}
@app.post("/api/admin/services/{service_id}/rdp-slots")
def create_rdp_slot(service_id: int, payload: dict, request: Request, _: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
service = db.get(Service, service_id)
if not service or service.type != ServiceType.RDP:
raise HTTPException(status_code=404, detail="RDP service not found")
rdp_username = (payload.get("rdp_username") or "").strip()
rdp_password = (payload.get("rdp_password") or "").strip()
if not rdp_username:
raise HTTPException(status_code=400, detail="rdp_username is required")
slot = RdpSlot(service_id=service_id, rdp_username=rdp_username, rdp_password=rdp_password)
db.add(slot)
db.flush()
try:
container_name = start_rdp_slot_container(slot, service)
slot.container_name = container_name
except Exception as exc:
logger.exception("rdp_slot_container_start_failed service_id=%s", service_id)
raise HTTPException(status_code=502, detail=f"Контейнер не запустился: {exc}")
db.commit()
audit(db, "RDP_SLOT_CREATE", f"service={service.slug} slot={slot.id} user={rdp_username}", user_id=None)
return {"ok": True, "slot_id": slot.id, "container_name": slot.container_name}
@app.delete("/api/admin/rdp-slots/{slot_id}")
def delete_rdp_slot(slot_id: int, request: Request, _: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
slot = db.get(RdpSlot, slot_id)
if not slot:
raise HTTPException(status_code=404, detail="Slot not found")
container_name = slot.container_name
db.delete(slot)
db.commit()
if container_name:
threading.Thread(target=stop_rdp_slot_container, args=(container_name,), daemon=True).start()
return {"ok": True}
@app.post("/api/admin/categories")
def create_category(payload: dict, request: Request, _: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
name = (payload.get("name") or "").strip()
slug = (payload.get("slug") or "").strip().lower().replace(" ", "-")
if not name:
raise HTTPException(status_code=400, detail="Category name is required")
if not slug:
raise HTTPException(status_code=400, detail="Category slug is required")
exists = db.scalar(select(Category).where((Category.name == name) | (Category.slug == slug)))
if exists:
raise HTTPException(status_code=409, detail="Category already exists")
category = Category(name=name, slug=slug)
db.add(category)
db.commit()
return {"id": category.id}
@app.delete("/api/admin/categories/{category_id}")
def delete_category(category_id: int, request: Request, _: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
category = db.get(Category, category_id)
if not category:
raise HTTPException(status_code=404, detail="Category not found")
db.delete(category)
db.commit()
return {"ok": True}
@app.put("/api/admin/web-pool-size")
def update_web_pool_size(payload: dict, request: Request, _: User = Depends(require_admin)):
validate_csrf(request)
global WEB_POOL_SIZE
value = max(0, int(payload.get("size", WEB_POOL_SIZE)))
WEB_POOL_SIZE = value
ensure_web_pool()
return {"ok": True, "size": WEB_POOL_SIZE, "pool": get_web_pool_status()}
@app.post("/api/admin/users")
def create_user(payload: dict, request: Request, _: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
expires_at = dt.datetime.fromisoformat(payload["expires_at"])
user = User(
username=payload["username"],
password_hash=hash_password(payload["password"]),
expires_at=expires_at,
active=payload.get("active", True),
is_admin=payload.get("is_admin", False),
first_name=payload.get("first_name", ""),
last_name=payload.get("last_name", ""),
)
db.add(user)
db.commit()
return {"id": user.id}
@app.put("/api/admin/users/{user_id}")
def edit_user(user_id: int, payload: dict, request: Request, _: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
user = db.get(User, user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
for key in ["username", "active", "is_admin", "first_name", "last_name"]:
if key in payload:
setattr(user, key, payload[key])
if "password" in payload and payload["password"]:
user.password_hash = hash_password(payload["password"])
if "expires_at" in payload:
user.expires_at = dt.datetime.fromisoformat(payload["expires_at"])
db.commit()
return {"ok": True}
@app.delete("/api/admin/users/{user_id}")
def delete_user(user_id: int, request: Request, admin: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
user = db.get(User, user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
if user.id == admin.id:
raise HTTPException(status_code=400, detail="Cannot delete current admin")
db.delete(user)
db.commit()
return {"ok": True}
@app.put("/api/admin/users/{user_id}/acl")
def set_acl(user_id: int, payload: dict, request: Request, _: User = Depends(require_admin), db: Session = Depends(get_db)):
validate_csrf(request)
user = db.get(User, user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
service_ids = set(payload.get("service_ids", []))
existing = db.scalars(select(UserServiceAccess).where(UserServiceAccess.user_id == user_id)).all()
existing_map = {x.service_id: x for x in existing}
for sid in service_ids:
if sid not in existing_map:
db.add(UserServiceAccess(user_id=user_id, service_id=sid))
for sid, row in existing_map.items():
if sid not in service_ids:
db.delete(row)
db.commit()
return {"ok": True}