commit 2b5c765e418daa0b6694eec9d1eaf5c4264bfc90 Author: Validation Suite Date: Fri Jul 10 19:13:07 2026 +0000 Initial Validation Suite V2 report engine diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..83098280 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.12-slim +WORKDIR /app +ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 +RUN apt-get update && apt-get install -y --no-install-recommends gcc libpq-dev && rm -rf /var/lib/apt/lists/* +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY app/ . +CMD ["gunicorn","--bind","0.0.0.0:5000","--workers","2","--threads","4","app:app"] diff --git a/README.md b/README.md new file mode 100644 index 00000000..ecd4deb2 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Validation Suite V2 + +Lokaler Arbeitsstand mit vollständigem strukturellem Prüfbericht. + +## Start + +```bash +chmod +x start.command stop.command +./start.command +``` + +Browser: + +```text +http://localhost:5003 +``` + +Beim ersten Start registrieren. Eine Demo-Validierung mit Kunde, Gerät und sechs Loggern ist bereits angelegt. + +Über **V2-Prüfbericht herunterladen** wird ein langer Bericht erzeugt, der die Kapitelstruktur des Referenzberichts abbildet. Noch fehlende Originalbilder, Winlog-Daten, Zertifikate und das geschützte Logo sind als klar markierte Platzhalter enthalten. + +## Git + +Das Verzeichnis ist bereits als Git-Repository initialisiert. Nach dem Entpacken kann ein Remote ergänzt werden: + +```bash +git remote add origin DEINE_GIT_URL +git push -u origin main +``` diff --git a/_render_check/page-01.png b/_render_check/page-01.png new file mode 100644 index 00000000..a1407dc6 Binary files /dev/null and b/_render_check/page-01.png differ diff --git a/_render_check/page-02.png b/_render_check/page-02.png new file mode 100644 index 00000000..6d90db54 Binary files /dev/null and b/_render_check/page-02.png differ diff --git a/_render_check/page-03.png b/_render_check/page-03.png new file mode 100644 index 00000000..8cf85809 Binary files /dev/null and b/_render_check/page-03.png differ diff --git a/_render_check/page-04.png b/_render_check/page-04.png new file mode 100644 index 00000000..c2fd5a99 Binary files /dev/null and b/_render_check/page-04.png differ diff --git a/_render_check/page-05.png b/_render_check/page-05.png new file mode 100644 index 00000000..0c6b62bf Binary files /dev/null and b/_render_check/page-05.png differ diff --git a/_render_check/page-06.png b/_render_check/page-06.png new file mode 100644 index 00000000..9466f999 Binary files /dev/null and b/_render_check/page-06.png differ diff --git a/_render_check/page-07.png b/_render_check/page-07.png new file mode 100644 index 00000000..40c8147c Binary files /dev/null and b/_render_check/page-07.png differ diff --git a/_render_check/page-08.png b/_render_check/page-08.png new file mode 100644 index 00000000..585b3495 Binary files /dev/null and b/_render_check/page-08.png differ diff --git a/_render_check/page-09.png b/_render_check/page-09.png new file mode 100644 index 00000000..3256f653 Binary files /dev/null and b/_render_check/page-09.png differ diff --git a/_render_check/page-10.png b/_render_check/page-10.png new file mode 100644 index 00000000..61180f27 Binary files /dev/null and b/_render_check/page-10.png differ diff --git a/_render_check/page-11.png b/_render_check/page-11.png new file mode 100644 index 00000000..0dd239e7 Binary files /dev/null and b/_render_check/page-11.png differ diff --git a/_render_check/page-12.png b/_render_check/page-12.png new file mode 100644 index 00000000..e2eb4d48 Binary files /dev/null and b/_render_check/page-12.png differ diff --git a/_render_check/page-13.png b/_render_check/page-13.png new file mode 100644 index 00000000..7b31f38b Binary files /dev/null and b/_render_check/page-13.png differ diff --git a/_render_check/page-14.png b/_render_check/page-14.png new file mode 100644 index 00000000..497f3ae8 Binary files /dev/null and b/_render_check/page-14.png differ diff --git a/_render_check/page-15.png b/_render_check/page-15.png new file mode 100644 index 00000000..206262f0 Binary files /dev/null and b/_render_check/page-15.png differ diff --git a/_render_check/page-16.png b/_render_check/page-16.png new file mode 100644 index 00000000..9e546af7 Binary files /dev/null and b/_render_check/page-16.png differ diff --git a/_render_check/page-17.png b/_render_check/page-17.png new file mode 100644 index 00000000..a0b437ed Binary files /dev/null and b/_render_check/page-17.png differ diff --git a/_render_check/page-18.png b/_render_check/page-18.png new file mode 100644 index 00000000..44d5dc77 Binary files /dev/null and b/_render_check/page-18.png differ diff --git a/_render_check/page-19.png b/_render_check/page-19.png new file mode 100644 index 00000000..65b6edf0 Binary files /dev/null and b/_render_check/page-19.png differ diff --git a/_render_check/page-20.png b/_render_check/page-20.png new file mode 100644 index 00000000..1e69b5f0 Binary files /dev/null and b/_render_check/page-20.png differ diff --git a/_render_check/page-21.png b/_render_check/page-21.png new file mode 100644 index 00000000..1a2298dc Binary files /dev/null and b/_render_check/page-21.png differ diff --git a/_render_check/page-22.png b/_render_check/page-22.png new file mode 100644 index 00000000..93ec0626 Binary files /dev/null and b/_render_check/page-22.png differ diff --git a/_render_check/page-23.png b/_render_check/page-23.png new file mode 100644 index 00000000..b30f04a4 Binary files /dev/null and b/_render_check/page-23.png differ diff --git a/_render_check/page-24.png b/_render_check/page-24.png new file mode 100644 index 00000000..5a2c7a5b Binary files /dev/null and b/_render_check/page-24.png differ diff --git a/_render_check/page-25.png b/_render_check/page-25.png new file mode 100644 index 00000000..71badaca Binary files /dev/null and b/_render_check/page-25.png differ diff --git a/_render_check/page-26.png b/_render_check/page-26.png new file mode 100644 index 00000000..44c24d6e Binary files /dev/null and b/_render_check/page-26.png differ diff --git a/_render_check/page-27.png b/_render_check/page-27.png new file mode 100644 index 00000000..1b4f5147 Binary files /dev/null and b/_render_check/page-27.png differ diff --git a/_render_check/page-28.png b/_render_check/page-28.png new file mode 100644 index 00000000..87b7823d Binary files /dev/null and b/_render_check/page-28.png differ diff --git a/_render_check/page-29.png b/_render_check/page-29.png new file mode 100644 index 00000000..5b612c9f Binary files /dev/null and b/_render_check/page-29.png differ diff --git a/_render_check/page-30.png b/_render_check/page-30.png new file mode 100644 index 00000000..7743e9ee Binary files /dev/null and b/_render_check/page-30.png differ diff --git a/_render_check/page-31.png b/_render_check/page-31.png new file mode 100644 index 00000000..4534c126 Binary files /dev/null and b/_render_check/page-31.png differ diff --git a/_render_check/page-32.png b/_render_check/page-32.png new file mode 100644 index 00000000..1512e0e3 Binary files /dev/null and b/_render_check/page-32.png differ diff --git a/_render_check/page-33.png b/_render_check/page-33.png new file mode 100644 index 00000000..e024b222 Binary files /dev/null and b/_render_check/page-33.png differ diff --git a/_render_check/page-34.png b/_render_check/page-34.png new file mode 100644 index 00000000..8988d5cd Binary files /dev/null and b/_render_check/page-34.png differ diff --git a/_render_check/page-35.png b/_render_check/page-35.png new file mode 100644 index 00000000..52c6476b Binary files /dev/null and b/_render_check/page-35.png differ diff --git a/_render_check/page-36.png b/_render_check/page-36.png new file mode 100644 index 00000000..b4a1f183 Binary files /dev/null and b/_render_check/page-36.png differ diff --git a/_render_check/page-37.png b/_render_check/page-37.png new file mode 100644 index 00000000..f8169f5d Binary files /dev/null and b/_render_check/page-37.png differ diff --git a/_render_check/page-38.png b/_render_check/page-38.png new file mode 100644 index 00000000..9ea3c371 Binary files /dev/null and b/_render_check/page-38.png differ diff --git a/_render_check/page-39.png b/_render_check/page-39.png new file mode 100644 index 00000000..782373f5 Binary files /dev/null and b/_render_check/page-39.png differ diff --git a/_render_check/page-40.png b/_render_check/page-40.png new file mode 100644 index 00000000..f8750632 Binary files /dev/null and b/_render_check/page-40.png differ diff --git a/_render_check/page-41.png b/_render_check/page-41.png new file mode 100644 index 00000000..77b247a1 Binary files /dev/null and b/_render_check/page-41.png differ diff --git a/_render_check/page-42.png b/_render_check/page-42.png new file mode 100644 index 00000000..fcbed972 Binary files /dev/null and b/_render_check/page-42.png differ diff --git a/_render_check/page-43.png b/_render_check/page-43.png new file mode 100644 index 00000000..63a02b79 Binary files /dev/null and b/_render_check/page-43.png differ diff --git a/_render_check/page-44.png b/_render_check/page-44.png new file mode 100644 index 00000000..a81985fa Binary files /dev/null and b/_render_check/page-44.png differ diff --git a/_render_check/page-45.png b/_render_check/page-45.png new file mode 100644 index 00000000..f3a26973 Binary files /dev/null and b/_render_check/page-45.png differ diff --git a/_render_check/page-46.png b/_render_check/page-46.png new file mode 100644 index 00000000..a32dbc27 Binary files /dev/null and b/_render_check/page-46.png differ diff --git a/_render_check/page-47.png b/_render_check/page-47.png new file mode 100644 index 00000000..8b254ce3 Binary files /dev/null and b/_render_check/page-47.png differ diff --git a/_render_check/page-48.png b/_render_check/page-48.png new file mode 100644 index 00000000..5b896e72 Binary files /dev/null and b/_render_check/page-48.png differ diff --git a/_render_check/page-49.png b/_render_check/page-49.png new file mode 100644 index 00000000..c9f6759f Binary files /dev/null and b/_render_check/page-49.png differ diff --git a/_render_check/page-50.png b/_render_check/page-50.png new file mode 100644 index 00000000..857176ec Binary files /dev/null and b/_render_check/page-50.png differ diff --git a/_render_check/page-51.png b/_render_check/page-51.png new file mode 100644 index 00000000..5daa5424 Binary files /dev/null and b/_render_check/page-51.png differ diff --git a/_render_check/page-52.png b/_render_check/page-52.png new file mode 100644 index 00000000..89e44ab4 Binary files /dev/null and b/_render_check/page-52.png differ diff --git a/_render_check/page-53.png b/_render_check/page-53.png new file mode 100644 index 00000000..c417bce0 Binary files /dev/null and b/_render_check/page-53.png differ diff --git a/_render_check/page-54.png b/_render_check/page-54.png new file mode 100644 index 00000000..d0f9f18c Binary files /dev/null and b/_render_check/page-54.png differ diff --git a/_render_check/page-55.png b/_render_check/page-55.png new file mode 100644 index 00000000..e77ae730 Binary files /dev/null and b/_render_check/page-55.png differ diff --git a/_render_check/page-56.png b/_render_check/page-56.png new file mode 100644 index 00000000..780219c8 Binary files /dev/null and b/_render_check/page-56.png differ diff --git a/_render_check/page-57.png b/_render_check/page-57.png new file mode 100644 index 00000000..f774ab6d Binary files /dev/null and b/_render_check/page-57.png differ diff --git a/_render_check/page-58.png b/_render_check/page-58.png new file mode 100644 index 00000000..b8294a1e Binary files /dev/null and b/_render_check/page-58.png differ diff --git a/_render_check/page-59.png b/_render_check/page-59.png new file mode 100644 index 00000000..e11a75b3 Binary files /dev/null and b/_render_check/page-59.png differ diff --git a/_render_check/page-60.png b/_render_check/page-60.png new file mode 100644 index 00000000..da9c1afd Binary files /dev/null and b/_render_check/page-60.png differ diff --git a/_render_check/page-61.png b/_render_check/page-61.png new file mode 100644 index 00000000..d48fa6f8 Binary files /dev/null and b/_render_check/page-61.png differ diff --git a/app/__pycache__/app.cpython-313.pyc b/app/__pycache__/app.cpython-313.pyc new file mode 100644 index 00000000..2a9fc7c0 Binary files /dev/null and b/app/__pycache__/app.cpython-313.pyc differ diff --git a/app/app.py b/app/app.py new file mode 100644 index 00000000..4342d960 --- /dev/null +++ b/app/app.py @@ -0,0 +1,272 @@ +from __future__ import annotations + +import os +from datetime import date, datetime +from pathlib import Path + +from flask import Flask, flash, redirect, render_template, request, send_from_directory, url_for +from flask_login import LoginManager, UserMixin, current_user, login_required, login_user, logout_user +from flask_sqlalchemy import SQLAlchemy +from sqlalchemy import func, select +from werkzeug.security import check_password_hash, generate_password_hash + +from reporting.report_builder import build_validation_report + +db = SQLAlchemy() +login_manager = LoginManager() +BASE_DIR = Path(__file__).resolve().parent +GENERATED_DIR = BASE_DIR / "generated" +GENERATED_DIR.mkdir(exist_ok=True) + + +class User(UserMixin, db.Model): + __tablename__ = "users" + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(100), unique=True, nullable=False) + password_hash = db.Column(db.String(255), nullable=False) + + def set_password(self, password): + self.password_hash = generate_password_hash(password) + + def check_password(self, password): + return check_password_hash(self.password_hash, password) + + +class Customer(db.Model): + __tablename__ = "customers" + id = db.Column(db.Integer, primary_key=True) + practice_name = db.Column(db.String(180), nullable=False) + operator_name = db.Column(db.String(180), nullable=False) + contact_person = db.Column(db.String(180)) + hygiene_contact = db.Column(db.String(180)) + street = db.Column(db.String(180)) + postal_code = db.Column(db.String(20)) + city = db.Column(db.String(120)) + email = db.Column(db.String(180)) + phone = db.Column(db.String(80)) + + @property + def address(self): + return ", ".join(x for x in [ + self.street or "", + f"{self.postal_code or ''} {self.city or ''}".strip() + ] if x) + + +class Device(db.Model): + __tablename__ = "devices" + id = db.Column(db.Integer, primary_key=True) + customer_id = db.Column(db.Integer, db.ForeignKey("customers.id"), nullable=False) + manufacturer = db.Column(db.String(120), nullable=False) + model = db.Column(db.String(120), nullable=False) + serial_number = db.Column(db.String(120), unique=True, nullable=False) + year_built = db.Column(db.String(20)) + commissioning_date = db.Column(db.Date) + chamber_volume = db.Column(db.String(50)) + steam_generation = db.Column(db.String(180)) + water_supply = db.Column(db.String(180)) + documentation = db.Column(db.String(180)) + supplier = db.Column(db.String(180)) + customer = db.relationship("Customer", backref="devices") + + +class Equipment(db.Model): + __tablename__ = "equipment" + id = db.Column(db.Integer, primary_key=True) + designation = db.Column(db.String(150), nullable=False) + manufacturer = db.Column(db.String(120)) + model = db.Column(db.String(120)) + serial_number = db.Column(db.String(120), unique=True, nullable=False) + measurement_range = db.Column(db.String(150)) + calibration_date = db.Column(db.Date) + calibration_due = db.Column(db.Date) + equipment_type = db.Column(db.String(80)) + + +class Validation(db.Model): + __tablename__ = "validations" + id = db.Column(db.Integer, primary_key=True) + report_number = db.Column(db.String(60), unique=True, nullable=False) + customer_id = db.Column(db.Integer, db.ForeignKey("customers.id"), nullable=False) + device_id = db.Column(db.Integer, db.ForeignKey("devices.id"), nullable=False) + validation_type = db.Column(db.String(60), nullable=False) + project = db.Column(db.String(120), nullable=False) + test_date = db.Column(db.Date, nullable=False) + test_location = db.Column(db.String(120), nullable=False) + examiner = db.Column(db.String(150), nullable=False) + participants = db.Column(db.String(255)) + status = db.Column(db.String(30), default="Entwurf", nullable=False) + result = db.Column(db.String(30), default="Bestanden", nullable=False) + room_temperature = db.Column(db.String(20)) + room_humidity = db.Column(db.String(20)) + vacuum_leak_rate = db.Column(db.String(30)) + next_validation = db.Column(db.Date) + recommendations = db.Column(db.Text) + notes = db.Column(db.Text) + customer = db.relationship("Customer") + device = db.relationship("Device") + + +@login_manager.user_loader +def load_user(user_id): + try: + return db.session.get(User, int(user_id)) + except Exception: + return None + + +def parse_date(value): + if not value: + return None + try: + return datetime.strptime(value, "%Y-%m-%d").date() + except ValueError: + return None + + +def next_report_number(): + count = db.session.scalar(select(func.count()).select_from(Validation)) or 0 + return f"VAL-{datetime.now().year}-{count + 1:04d}" + + +def seed_demo_data(): + if db.session.scalar(select(func.count()).select_from(Customer)): + return + + customer = Customer( + practice_name="Urologische Praxis Muster", + operator_name="Dr. Max Mustermann", + contact_person="Dr. Max Mustermann", + hygiene_contact="Frau Beispiel", + street="Musterstraße 5", + postal_code="90459", + city="Nürnberg", + email="praxis@example.de", + phone="0911 123456", + ) + db.session.add(customer) + db.session.flush() + + device = Device( + customer_id=customer.id, + manufacturer="Euronda", + model="E10.7", + serial_number="DEMO-EXN250688", + year_built="2025", + commissioning_date=date(2025, 12, 5), + chamber_volume="23 Liter", + steam_generation="Eigendampferzeugung", + water_supply="Automatische Versorgung über Aquafilter", + documentation="Interne CF-Card, Ausgabe am PC möglich", + supplier="Medizintechnik Muster", + ) + db.session.add(device) + + equipment = [ + Equipment(designation="Temperatur Datenlogger 1", manufacturer="Ebro", model="EBI 11 T235", serial_number="15102807", measurement_range="0 °C bis +150 °C", calibration_date=date(2025,1,17), calibration_due=date(2027,1,17), equipment_type="Temperatur"), + Equipment(designation="Temperatur Datenlogger 2", manufacturer="Ebro", model="EBI 11 T240", serial_number="15211066", measurement_range="0 °C bis +150 °C", calibration_date=date(2025,1,17), calibration_due=date(2027,1,17), equipment_type="Temperatur"), + Equipment(designation="Temperatur Datenlogger 3", manufacturer="Ebro", model="EBI 11 T240", serial_number="15102538", measurement_range="0 °C bis +150 °C", calibration_date=date(2025,1,17), calibration_due=date(2027,1,17), equipment_type="Temperatur"), + Equipment(designation="Temperatur Datenlogger 4", manufacturer="Ebro", model="EBI 11 T240", serial_number="15211067", measurement_range="0 °C bis +150 °C", calibration_date=date(2025,1,17), calibration_due=date(2027,1,17), equipment_type="Temperatur"), + Equipment(designation="Temperatur Datenlogger 5", manufacturer="Ebro", model="EBI 11 T240", serial_number="15125738", measurement_range="0 °C bis +150 °C", calibration_date=date(2025,1,17), calibration_due=date(2027,1,17), equipment_type="Temperatur"), + Equipment(designation="Drucklogger", manufacturer="Ebro", model="EBI 11 P111", serial_number="15092368", measurement_range="-100 mbar bis 4 bar abs.", calibration_date=date(2025,1,17), calibration_due=date(2027,1,17), equipment_type="Druck"), + ] + db.session.add_all(equipment) + db.session.flush() + + validation = Validation( + report_number="VAL-DEMO-0001", + customer_id=customer.id, + device_id=device.id, + validation_type="Erstvalidierung", + project="Erst-Validierung", + test_date=date(2025, 12, 5), + test_location="Nürnberg", + examiner="Andreas Schubert", + participants="Frau Beispiel, Dr. Max Mustermann", + status="Entwurf", + result="Bestanden", + room_temperature="21 °C", + room_humidity="41 %", + vacuum_leak_rate="0,2 mbar/min", + next_validation=date(2027, 11, 1), + recommendations="Auflagen und Empfehlungen werden im Kapitel 4.2 dokumentiert.", + notes="V2-Vorschau: Winlog-Messwerte, Originalbilder, Zertifikate und Logo werden später dynamisch ersetzt.", + ) + db.session.add(validation) + db.session.commit() + + +def create_app(): + app = Flask(__name__) + app.config.update( + SECRET_KEY=os.getenv("SECRET_KEY", "validation-v2-local-secret"), + SQLALCHEMY_DATABASE_URI=os.getenv("DATABASE_URL", "sqlite:///validation-v2.db"), + SQLALCHEMY_TRACK_MODIFICATIONS=False, + ) + db.init_app(app) + login_manager.init_app(app) + login_manager.login_view = "login" + + @app.route("/register", methods=["GET", "POST"]) + def register(): + if current_user.is_authenticated: + return redirect(url_for("dashboard")) + if request.method == "POST": + username = (request.form.get("username") or "").strip() + password = request.form.get("password") or "" + repeat = request.form.get("password_repeat") or "" + if len(username) < 3 or len(password) < 6 or password != repeat: + flash("Bitte gültige Zugangsdaten eingeben.", "error") + elif db.session.scalar(select(User).where(func.lower(User.username) == username.lower())): + flash("Benutzername bereits vergeben.", "error") + else: + user = User(username=username) + user.set_password(password) + db.session.add(user) + db.session.commit() + return redirect(url_for("login")) + return render_template("register.html") + + @app.route("/login", methods=["GET", "POST"]) + def login(): + if current_user.is_authenticated: + return redirect(url_for("dashboard")) + if request.method == "POST": + username = (request.form.get("username") or "").strip() + user = db.session.scalar(select(User).where(func.lower(User.username) == username.lower())) + if user and user.check_password(request.form.get("password") or ""): + login_user(user) + return redirect(url_for("dashboard")) + flash("Anmeldung fehlgeschlagen.", "error") + return render_template("login.html") + + @app.route("/logout", methods=["POST"]) + @login_required + def logout(): + logout_user() + return redirect(url_for("login")) + + @app.route("/") + @login_required + def dashboard(): + validations = list(db.session.scalars(select(Validation).order_by(Validation.id.desc()))) + return render_template("dashboard.html", validations=validations) + + @app.route("/validations//report") + @login_required + def report(item_id): + validation = db.session.get(Validation, item_id) + if not validation: + return "Nicht gefunden", 404 + equipment = list(db.session.scalars(select(Equipment).order_by(Equipment.id))) + filename = build_validation_report(validation, equipment, GENERATED_DIR) + return send_from_directory(GENERATED_DIR, filename, as_attachment=True) + + with app.app_context(): + db.create_all() + seed_demo_data() + + return app + + +app = create_app() diff --git a/app/reporting/__init__.py b/app/reporting/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/reporting/__pycache__/__init__.cpython-313.pyc b/app/reporting/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 00000000..ae79f641 Binary files /dev/null and b/app/reporting/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/reporting/__pycache__/report_builder.cpython-313.pyc b/app/reporting/__pycache__/report_builder.cpython-313.pyc new file mode 100644 index 00000000..27342679 Binary files /dev/null and b/app/reporting/__pycache__/report_builder.cpython-313.pyc differ diff --git a/app/reporting/report_builder.py b/app/reporting/report_builder.py new file mode 100644 index 00000000..3f2c3bdd --- /dev/null +++ b/app/reporting/report_builder.py @@ -0,0 +1,496 @@ +from __future__ import annotations + +from pathlib import Path +from reportlab.lib import colors +from reportlab.lib.enums import TA_CENTER, TA_LEFT +from reportlab.lib.pagesizes import A4 +from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle +from reportlab.lib.units import mm +from reportlab.platypus import ( + BaseDocTemplate, Frame, PageTemplate, Paragraph, Spacer, Table, TableStyle, + PageBreak, KeepTogether +) + +PAGE_W, PAGE_H = A4 + + +def _header_footer(canvas, doc): + canvas.saveState() + canvas.setStrokeColor(colors.HexColor("#D0D5DD")) + canvas.line(18*mm, PAGE_H-16*mm, PAGE_W-18*mm, PAGE_H-16*mm) + canvas.setFont("Helvetica-Bold", 8) + canvas.setFillColor(colors.HexColor("#344054")) + canvas.drawString(18*mm, PAGE_H-12*mm, "VALIDATION SUITE - PRÜFBERICHT") + canvas.setFont("Helvetica", 8) + canvas.setFillColor(colors.HexColor("#667085")) + canvas.drawRightString(PAGE_W-18*mm, 10*mm, f"Seite {doc.page}") + canvas.restoreState() + + +def _table(data, widths=None, header=True): + t = Table(data, colWidths=widths, repeatRows=1 if header else 0) + style = [ + ("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#D0D5DD")), + ("VALIGN", (0,0), (-1,-1), "TOP"), + ("LEFTPADDING", (0,0), (-1,-1), 6), + ("RIGHTPADDING", (0,0), (-1,-1), 6), + ("TOPPADDING", (0,0), (-1,-1), 6), + ("BOTTOMPADDING", (0,0), (-1,-1), 6), + ] + if header: + style += [ + ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#EEF2FF")), + ("TEXTCOLOR", (0,0), (-1,0), colors.HexColor("#3730A3")), + ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"), + ] + t.setStyle(TableStyle(style)) + return t + + +def _placeholder(title, height=85): + data = [[Paragraph(f"{title}
Platzhalter - wird aus der jeweiligen Validierung ersetzt.", getSampleStyleSheet()["BodyText"])]] + t = Table(data, colWidths=[165*mm], rowHeights=[height*mm]) + t.setStyle(TableStyle([ + ("BOX",(0,0),(-1,-1),1,colors.HexColor("#98A2B3")), + ("BACKGROUND",(0,0),(-1,-1),colors.HexColor("#F8FAFC")), + ("VALIGN",(0,0),(-1,-1),"MIDDLE"), + ("ALIGN",(0,0),(-1,-1),"CENTER"), + ])) + return t + + +def build_validation_report(validation, equipment, output_dir: Path) -> str: + output_dir.mkdir(parents=True, exist_ok=True) + filename = f"{validation.report_number}_V2_Vorschau.pdf" + path = output_dir / filename + + styles = getSampleStyleSheet() + styles.add(ParagraphStyle(name="CoverTitle", parent=styles["Title"], fontSize=24, leading=29, alignment=TA_CENTER, textColor=colors.HexColor("#172033"))) + styles.add(ParagraphStyle(name="Chapter", parent=styles["Heading1"], fontSize=17, leading=21, spaceBefore=8, spaceAfter=10, textColor=colors.HexColor("#172033"))) + styles.add(ParagraphStyle(name="Section", parent=styles["Heading2"], fontSize=13, leading=17, spaceBefore=8, spaceAfter=7, textColor=colors.HexColor("#344054"))) + styles.add(ParagraphStyle(name="Small", parent=styles["BodyText"], fontSize=8, leading=11, textColor=colors.HexColor("#667085"))) + styles.add(ParagraphStyle(name="BodyV2", parent=styles["BodyText"], fontSize=9.3, leading=13.5, spaceAfter=6)) + + frame = Frame(18*mm, 17*mm, PAGE_W-36*mm, PAGE_H-36*mm, id="normal") + doc = BaseDocTemplate(str(path), pagesize=A4, leftMargin=18*mm, rightMargin=18*mm, topMargin=20*mm, bottomMargin=18*mm) + doc.addPageTemplates([PageTemplate(id="main", frames=frame, onPage=_header_footer)]) + + story = [] + + # Cover + story += [ + Spacer(1, 24*mm), + _placeholder("GESCHÜTZTES ORIGINALLOGO", 25), + Spacer(1, 14*mm), + Paragraph("Prüfbericht zur Validierung", styles["CoverTitle"]), + Paragraph("Funktions- und Leistungsqualifikation Klein-Sterilisator", styles["Heading2"]), + Spacer(1, 10*mm), + _table([ + ["Hersteller / Gerät", f"{validation.device.manufacturer} / {validation.device.model}"], + ["Seriennummer", validation.device.serial_number], + ["Projekt", validation.project], + ["Auftraggeber / Standort", f"{validation.customer.practice_name}
{validation.customer.operator_name}
{validation.customer.address}"], + ["Ort und Datum der Prüfung", f"{validation.test_location}, {validation.test_date.strftime('%d.%m.%Y')}"], + ["Technische Validierung durchgeführt", validation.examiner], + ["Mitwirkende Personen", validation.participants or "–"], + ["Berichtsnummer", validation.report_number], + ], widths=[55*mm, 110*mm], header=False), + Spacer(1, 12*mm), + Paragraph("Nur gültig mit Unterschrift des verantwortlichen Betreibers und des Prüfers.", styles["Small"]), + Spacer(1, 12*mm), + _table([ + ["Ort / Datum", "Unterschrift verantwortlicher Betreiber"], + ["", ""], + ["Ort / Datum", "Unterschrift Prüfer / Berichtsersteller"], + ["", ""], + ], widths=[55*mm, 110*mm], header=False), + PageBreak(), + ] + + # Summary + story += [ + Paragraph("Zusammenfassendes Ergebnis der Validierung", styles["Chapter"]), + Paragraph( + f"Es wurde die Validierung (Leistungsbeurteilung) eines sich im Betrieb befindlichen " + f"Klein-Sterilisators (< 1 STE / 60 Liter) durchgeführt. Im Rahmen der Leistungsqualifikation " + f"wurden mechanische, thermoelektrische und verfahrenstechnische Leistungsanforderungen überprüft.", + styles["BodyV2"] + ), + Paragraph( + "Die geforderten Spezifikationen, Prozesse und Umgebungsbedingungen wurden überprüft. " + "Die Bewertung der Messdaten wird nach dem Import der Winlog-Validation-Daten automatisch " + "in die Tabellen und Diagramme dieses Berichts übernommen.", + styles["BodyV2"] + ), + _table([ + ["Prüfung", "Ergebnis"], + ["Vakuumtest", validation.result], + ["Bowie-Dick / Leerkammerprofil", validation.result], + ["Testlauf 1 - 134 °C hohl verpackt", validation.result], + ["Testlauf 2 - 134 °C hohl verpackt", validation.result], + ["Testlauf 3 - 134 °C hohl verpackt", validation.result], + ["Gesamtergebnis", validation.result], + ], widths=[120*mm, 45*mm]), + Spacer(1, 8*mm), + Paragraph( + f"Die nächste Leistungsbeurteilung / Validierung ist vorgesehen für " + f"{validation.next_validation.strftime('%m/%Y') if validation.next_validation else 'noch festzulegen'}. " + "Prozessrelevante Änderungen können eine erneute Leistungsüberprüfung notwendig machen.", + styles["BodyV2"] + ), + PageBreak(), + ] + + # TOC-style overview + toc = [ + ("1.", "Funktionsqualifikation (BQ)"), + ("1.1", "Anlass und Ziel der Prüfung"), + ("1.2", "Gesetzliche Grundlagen"), + ("1.3", "Angaben zum Gerät"), + ("1.4", "Leistungsüberprüfung"), + ("1.5", "Checkliste Leistungsanforderung"), + ("1.8", "Umgebungsbedingungen"), + ("1.9", "Chargenkontrolle"), + ("1.10", "Beschreibung der verwendeten Programme"), + ("1.11", "Beladungsbeschreibungen"), + ("2.", "Eingesetzte Prüfmittel"), + ("2.1", "Beschreibung der Messgeräte"), + ("2.2", "Prüfmittel zur thermoelektrischen Untersuchung"), + ("3.", "Prüfkonfiguration"), + ("3.1", "Leistungsbeurteilung - Thermoelektrische Prüfungen"), + ("4.", "Ergebnisse der Validierung"), + ("4.2", "Empfehlungen und Auflagen"), + ("5.", "Anhang"), + ("6.", "Programmabläufe / Zyklen"), + ("7.", "Risikoeinstufung / Abschlussgespräch"), + ("8.", "Zertifikate"), + ("9.", "Werkskalibrierzertifikate Sensoren"), + ] + story += [Paragraph("Inhaltsverzeichnis", styles["Chapter"]), _table([["Kapitel","Inhalt"]] + toc, widths=[25*mm,140*mm]), PageBreak()] + + # Static chapters + story += [ + Paragraph("1. Funktionsqualifikation (BQ)", styles["Chapter"]), + Paragraph("1.1 Anlass und Ziel der Prüfung", styles["Section"]), + Paragraph( + f"Es wurde die Validierung eines sich im Betrieb befindlichen {validation.device.manufacturer} " + f"{validation.device.model} Klein-Sterilisators durchgeführt. Die Validierung gilt nur für das " + "zum Zeitpunkt der Prüfung berücksichtigte Gerät, die geprüfte Beladung und die verwendeten Programme.", + styles["BodyV2"] + ), + Paragraph( + "Mit der Validierung wird der dokumentierte Nachweis erbracht, dass ein Verfahren die vorher " + "spezifizierten Anforderungen im praktischen Einsatz reproduzierbar erfüllt.", + styles["BodyV2"] + ), + Paragraph("1.2 Gesetzliche Grundlagen", styles["Section"]), + Paragraph( + "Die Validierung erfolgt in Anlehnung an die für den Anwendungsbereich maßgeblichen Regelwerke, " + "Normen, Leitlinien und Empfehlungen. Die in der Originalvorlage enthaltenen fachlichen Textbausteine " + "werden in der finalen Berichtsversion unverändert versioniert übernommen.", + styles["BodyV2"] + ), + _table([ + ["Regelwerk / Grundlage"], + ["DIN EN ISO 17665 - Sterilisation von Produkten für die Gesundheitsfürsorge"], + ["DIN EN 13060 - Dampf-Kleinsterilisatoren"], + ["Leitlinien der DGKH, DGSV und AKI"], + ["Empfehlungen von RKI und BfArM zur Aufbereitung von Medizinprodukten"], + ], widths=[165*mm]), + PageBreak(), + ] + + story += [ + Paragraph("1.3 Angaben zum Gerät", styles["Chapter"]), + _table([ + ["Merkmal", "Angabe"], + ["Sterilisator-Typ", f"{validation.device.manufacturer} {validation.device.model}"], + ["Seriennummer", validation.device.serial_number], + ["Baujahr", validation.device.year_built or "–"], + ["Erstinbetriebnahme", validation.device.commissioning_date.strftime("%d.%m.%Y") if validation.device.commissioning_date else "–"], + ["Kammervolumen", validation.device.chamber_volume or "–"], + ["Art der Dampferzeugung", validation.device.steam_generation or "–"], + ["Wasserqualität / Versorgung", validation.device.water_supply or "–"], + ["Chargendokumentation", validation.device.documentation or "–"], + ["Lieferant", validation.device.supplier or "–"], + ["Betreiber", validation.customer.operator_name], + ["QM / Hygienebeauftragte", validation.customer.hygiene_contact or "–"], + ], widths=[60*mm,105*mm]), + Spacer(1, 5*mm), + _placeholder("Gerätefoto - aktueller Sterilisator", 80), + PageBreak(), + ] + + # Checklists + checklist_rows = [ + ["Prüfkriterium", "Ja", "Nein", "Kommentar"], + ["Trennung von Controlling- und Monitoring-Schaltkreisen", "X", "", ""], + ["Temperaturüberwachung Sterilisationsprozess", "X", "", ""], + ["Drucküberwachung Sterilisationsprozess", "X", "", ""], + ["Wasserzulauf / Ablauf", "X", "", "Automatische Versorgung"], + ["Automatische Aufzeichnung der Sterilisationsergebnisse", "X", "", validation.device.documentation or ""], + ["Überwachung Wasserqualität", "X", "", "Interne Überwachung"], + ["Separater Netzanschluss", "X", "", ""], + ["Sichtkontrolle Kessel, Sensoren, Türbereich", "X", "", ""], + ["Bedienungshandbuch / Installationsprotokoll", "X", "", "Vorhanden"], + ["Wartungshandbuch", "X", "", "Vorhanden"], + ["Arbeitsanweisungen / Checklisten / Beladungsmuster", "X", "", "Werden im System dokumentiert"], + ["Schulungsnachweise der Mitarbeiter", "X", "", ""], + ["Risikoeinstufung der Medizinprodukte", "X", "", ""], + ["Freigabedokumentation vorhanden", "X", "", ""], + ] + story += [ + Paragraph("1.5 Checkliste Leistungsanforderung", styles["Chapter"]), + _table(checklist_rows, widths=[90*mm,15*mm,15*mm,45*mm]), + PageBreak(), + Paragraph("1.8 Umgebungsbedingungen", styles["Chapter"]), + _table([ + ["Kontrolle", "Ja", "Nein", "Kommentar"], + ["Änderungen seit letzter Validierung", "", "X", validation.validation_type], + ["Aufstellungsort und Umgebungsbedingungen in Ordnung", "X", "", ""], + ["Relative Luftfeuchtigkeit in Ordnung", "X", "", validation.room_humidity or ""], + ["Gerät nach Sichtprüfung in Ordnung", "X", "", ""], + ["Trennung zwischen Rein- und Unreinbereich", "X", "", ""], + ["Sterilgutlagerung unter geschützten Bedingungen", "X", "", ""], + ["Raumbelüftung vorhanden", "X", "", ""], + ["Desinfektionsmittel-, Seifen- und Papierhandtuchspender vorhanden", "X", "", ""], + ], widths=[92*mm,14*mm,14*mm,45*mm]), + Spacer(1, 6*mm), + Paragraph( + f"Aufbereitungsraum: Raumtemperatur {validation.room_temperature or '–'}, " + f"relative Luftfeuchtigkeit {validation.room_humidity or '–'}, gemessen am " + f"{validation.test_date.strftime('%d.%m.%Y')}.", + styles["BodyV2"] + ), + _placeholder("Abbildung: Übersicht Aufbereitungsraum", 55), + Spacer(1, 4*mm), + _placeholder("Abbildung: Reiner / unreiner Bereich", 55), + PageBreak(), + ] + + story += [ + Paragraph("1.9 Chargenkontrolle", styles["Chapter"]), + _table([ + ["Kontrolle", "Durchführung", "Prüfintervall", "Prüfkörper"], + ["Vakuumtest", "Ja", "wöchentlich", "–"], + ["Bowie-Dick-Test", "nach Bedarf", "gemäß Validierungsplan", "Prüfkörper"], + ["Chargenüberwachung Chemoindikatoren", "Ja", "bei jeder Charge", "Helix-Test"], + ], widths=[55*mm,35*mm,40*mm,35*mm]), + Paragraph("1.10 Beschreibung der verwendeten Programme", styles["Chapter"]), + Paragraph( + "Für alle praxisrelevanten Beladungen werden die nachfolgenden Programme verwendet: " + "Vakuumtest, Leerkammerprofil / Bowie-Dick-Simulation sowie drei Testläufe im Programm " + "134 °C hohl verpackt.", + styles["BodyV2"] + ), + Paragraph("1.11 Beladungsbeschreibungen", styles["Chapter"]), + Paragraph( + "Als schwierigste zu sterilisierende Beladung wird eine repräsentative Worst-Case-Beladung " + "aus dem tatsächlichen Instrumentarium definiert. Die konkrete Beladung und alle Fotos werden " + "je Validierung neu erfasst.", + styles["BodyV2"] + ), + _placeholder("Referenzbeladung - Testlauf 1", 60), + Spacer(1, 4*mm), + _placeholder("Referenzbeladung - Testlauf 2", 60), + PageBreak(), + _placeholder("Referenzbeladung - Testlauf 3", 60), + Spacer(1, 5*mm), + _placeholder("Sensorpositionierung / Prüfkonfiguration", 80), + PageBreak(), + ] + + # Equipment + eq_data = [["Bezeichnung", "Typ", "Seriennummer", "Messbereich", "Kalibrierung"]] + for e in equipment: + eq_data.append([ + e.designation, + f"{e.manufacturer or ''} {e.model or ''}".strip(), + e.serial_number, + e.measurement_range or "–", + e.calibration_date.strftime("%d.%m.%Y") if e.calibration_date else "–", + ]) + story += [ + Paragraph("2. Eingesetzte Prüfmittel", styles["Chapter"]), + Paragraph( + "Für die Reproduzierbarkeit der thermoelektrischen Prüfungen werden hochauflösende " + "Temperatur- und Drucksensoren eingesetzt. Die Auswahl erfolgt je Validierung aus dem " + "Prüfmittelregister.", + styles["BodyV2"] + ), + Paragraph("2.1 Beschreibung der Messgeräte", styles["Section"]), + _table(eq_data, widths=[40*mm,42*mm,30*mm,33*mm,25*mm]), + PageBreak(), + Paragraph("2.2 Prüfmittel zur thermoelektrischen Untersuchung", styles["Chapter"]), + _placeholder("Abbildung / Beschreibung Bowie-Dick-Simulationstest", 70), + Spacer(1, 5*mm), + _placeholder("Abbildung / Beschreibung Chargenüberwachungssystem", 70), + PageBreak(), + ] + + # Performance qualification + story += [ + Paragraph("3. Prüfkonfiguration", styles["Chapter"]), + _placeholder("Beladungsebenen und Positionierung der Sensoren", 110), + Spacer(1, 6*mm), + _table([ + ["Sensor", "Position / Kanal"], + ["Drucksensor P111", "Ebene 1, hinten Mitte"], + ["Temperatursensor T235", "Ebene 1, vorne Mitte"], + ["Temperatursensor T240", "Position gemäß Fotodokumentation"], + ], widths=[70*mm,95*mm]), + PageBreak(), + Paragraph("3. Leistungsqualifikation (LQ)", styles["Chapter"]), + Paragraph("3.1 Leistungsbeurteilung - Thermoelektrische Prüfungen", styles["Section"]), + Paragraph( + "Der Nachweis der erforderlichen Prozessleistung gilt als erbracht, wenn die in der " + "Berichtsvorlage festgelegten Temperatur-, Druck-, Zeit- und Trocknungskriterien eingehalten werden. " + "Nach Vorliegen des Winlog-Exports werden diese Regeln automatisch auf die importierten Messdaten angewandt.", + styles["BodyV2"] + ), + Paragraph("1. Vakuumtest", styles["Section"]), + Paragraph( + f"Der Leckagetest wurde durchgeführt. Erfasste Leckrate: " + f"{validation.vacuum_leak_rate or 'noch nicht importiert'}.", + styles["BodyV2"] + ), + _placeholder("Winlog-Diagramm Vakuumtest", 95), + PageBreak(), + ] + + # Test runs, each 3 pages + for idx in range(1, 4): + story += [ + Paragraph(f"{idx+1}. Standardbeladung ({idx}. Durchlauf)", styles["Chapter"]), + Paragraph(f"Testlauf {idx} - 134 °C hohl verpackt", styles["Section"]), + _table([ + ["Parameter", "Wert"], + ["Programm", "134 °C hohl verpackt"], + ["Beladung", f"Referenzbeladung {idx}"], + ["Gesamtergebnis", validation.result], + ["Sterilisationstemperatur", "Winlog-Import ausstehend"], + ["Haltezeit", "Winlog-Import ausstehend"], + ["Temperaturband", "Winlog-Import ausstehend"], + ["Ausgleichszeit", "Winlog-Import ausstehend"], + ], widths=[70*mm,95*mm]), + Spacer(1, 6*mm), + _placeholder(f"Beladungsfoto Testlauf {idx}", 70), + PageBreak(), + Paragraph(f"Gesamte Messung Testlauf {idx}", styles["Chapter"]), + _placeholder(f"Winlog-Gesamtdiagramm Testlauf {idx}", 150), + PageBreak(), + Paragraph(f"Gesamtergebnis Testlauf {idx}", styles["Chapter"]), + _table([ + ["Bewertungskriterium", "Ergebnis"], + ["Temperaturen nicht unter Sterilisationstemperatur", "ausstehend"], + ["Maximal 3 K oberhalb der gewählten Temperatur", "ausstehend"], + ["Abweichung zwischen Sensoren maximal 2 K", "ausstehend"], + ["Ausgleichszeit innerhalb Vorgabe", "ausstehend"], + ["Haltezeit eingehalten", "ausstehend"], + ["Gesamtergebnis", validation.result], + ], widths=[120*mm,45*mm]), + Spacer(1, 8*mm), + _placeholder(f"Detaildiagramme / Kanäle Testlauf {idx}", 95), + PageBreak(), + ] + + # Results and recommendations + story += [ + Paragraph("4. Ergebnisse der Validierung", styles["Chapter"]), + Paragraph("4.1 Vakuumtest", styles["Section"]), + _table([ + ["Prüfung", "Soll", "Ist", "Bewertung"], + ["Leckrate", "max. 1,3 mbar/min", validation.vacuum_leak_rate or "–", validation.result], + ], widths=[45*mm,45*mm,35*mm,40*mm]), + Paragraph("4.1.2 Testläufe 1 bis 3 - Programm 134 °C", styles["Section"]), + _table([ + ["Testlauf", "Temperaturband", "Haltezeit", "Trocknung", "Ergebnis"], + ["Test 1", "Winlog", "Winlog", "Prüfung", validation.result], + ["Test 2", "Winlog", "Winlog", "Prüfung", validation.result], + ["Test 3", "Winlog", "Winlog", "Prüfung", validation.result], + ], widths=[30*mm,38*mm,32*mm,32*mm,33*mm]), + Spacer(1, 8*mm), + Paragraph("Nachweis der Trocknungseigenschaften Testläufe 1 bis 3", styles["Section"]), + _placeholder("Trocknungsnachweis / Wägeergebnisse", 70), + PageBreak(), + Paragraph("4.2 Empfehlungen und Auflagen", styles["Chapter"]), + Paragraph(validation.recommendations or "Keine Auflagen erfasst.", styles["BodyV2"]), + _table([ + ["Nr.", "Auflage / Empfehlung", "Frist", "Status"], + ["1", "Wird über die Weboberfläche erfasst.", "–", "offen"], + ], widths=[15*mm,105*mm,25*mm,25*mm]), + PageBreak(), + ] + + # Annex skeleton. This deliberately yields a long report similar to source. + annexes = [ + "5.1 Vakuumtest - Winlog-Auswertung", + "Testlauf Bowie-Dick / Leerkammerprofil", + "Testlauf 1 - Allgemeine Angaben", + "Testlauf 1 - Gesamte Messung", + "Testlauf 1 - Gesamtergebnis", + "Testlauf 2 - Allgemeine Angaben", + "Testlauf 2 - Gesamte Messung", + "Testlauf 2 - Gesamtergebnis", + "Testlauf 3 - Allgemeine Angaben", + "Testlauf 3 - Gesamte Messung", + "Testlauf 3 - Gesamtergebnis", + "Chargen- und Freigabedokumentation der Praxis", + "Chargendokumentation Bowie-Dick / Leerkammerprofil", + "Chargendokumentation Testlauf 1", + "Chargendokumentation Testlauf 2", + "Chargendokumentation Testlauf 3", + "5.2 Freigabedokumentation / Routineprüfungen", + "5.3 Nachweis umgeschlagener Indikatoren", + "6. Programmabläufe / Zyklen des Sterilisators", + "6.1 Zertifikate Praxis", + "7. Risikoeinstufung der Praxis", + "7.1 Abschlussgespräch", + "8. Zertifikate", + "9. Werkskalibrierzertifikate Sensoren", + ] + + for annex in annexes: + story += [ + Paragraph(annex, styles["Chapter"]), + Paragraph( + "Dieses Kapitel ist bereits fest in der Berichtsvorlage vorgesehen. " + "Die Originalbilder, Protokolle, Zertifikate oder importierten PDF-Seiten werden " + "im produktiven System automatisch an dieser Stelle eingefügt.", + styles["BodyV2"] + ), + _placeholder(annex, 170), + PageBreak(), + ] + + # Extra certificate placeholders to reach realistic report length. + for i, e in enumerate(equipment, start=1): + story += [ + Paragraph(f"Kalibrierzertifikat {i}: {e.designation}", styles["Chapter"]), + _placeholder(f"Kalibrierzertifikat {e.serial_number} - Seite 1", 205), + PageBreak(), + Paragraph(f"Kalibrierzertifikat {i}: {e.designation} - Fortsetzung", styles["Chapter"]), + _placeholder(f"Kalibrierzertifikat {e.serial_number} - Seite 2", 205), + PageBreak(), + ] + + story += [ + Paragraph("Abschlussvermerk", styles["Chapter"]), + Paragraph( + "Diese V2-Vorschau bildet die vollständige Berichtsstruktur ab. Das geschützte Logo, " + "die Originalbilder, die konkreten Praxis- und Gerätedaten sowie die Winlog-Messwerte " + "werden zukünftig je Validierung dynamisch eingesetzt. Die fachlichen Textbausteine " + "werden nach der finalen Abstimmung unverändert versioniert.", + styles["BodyV2"] + ), + Spacer(1, 15*mm), + _table([ + ["Ort / Datum", "Unterschrift verantwortlicher Betreiber"], + ["", ""], + ["Ort / Datum", "Unterschrift Prüfer / Berichtsersteller"], + ["", ""], + ], widths=[55*mm,110*mm], header=False), + ] + + doc.build(story) + return filename diff --git a/app/static/style.css b/app/static/style.css new file mode 100644 index 00000000..35d2fcc5 --- /dev/null +++ b/app/static/style.css @@ -0,0 +1 @@ +*{box-sizing:border-box}body{margin:0;background:#f4f6fb;color:#172033;font-family:Inter,system-ui,-apple-system,"Segoe UI",sans-serif}.shell{min-height:100vh}aside{position:fixed;width:250px;inset:0 auto 0 0;background:#171a2b;color:#fff;padding:24px;display:flex;flex-direction:column;gap:30px}.brand{display:flex;align-items:center;gap:12px}.brand b{display:grid;place-items:center;width:48px;height:48px;border-radius:14px;background:#4f46e5}.brand span{font-weight:800}aside nav a{color:#fff;text-decoration:none}aside form{margin-top:auto}button,.button{border:0;border-radius:10px;padding:11px 15px;font-weight:800;cursor:pointer;text-decoration:none;display:inline-flex}.primary{background:#4f46e5;color:#fff}.content{margin-left:250px;padding:36px}.auth{min-height:100vh;display:grid;place-items:center;padding:20px}.card{background:#fff;border:1px solid #e3e7ef;border-radius:18px;padding:24px;box-shadow:0 18px 45px rgba(30,41,59,.08)}.auth-card{width:min(420px,100%)}form{display:grid;gap:14px}label{display:grid;gap:7px;font-weight:700}input{border:1px solid #d0d5dd;border-radius:10px;padding:11px}.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:18px}header{margin-bottom:24px}h1{font-size:2.7rem;margin:.2rem 0}header small{color:#4f46e5;font-weight:900;letter-spacing:.13em}.badge{display:inline-flex;border-radius:999px;background:#eef2ff;color:#3730a3;padding:6px 10px;font-size:.8rem;font-weight:800}.msg{padding:12px;border-radius:10px;margin-bottom:15px}.error{background:#fef3f2;color:#b42318}@media(max-width:800px){aside{position:static;width:100%}.content{margin:0;padding:20px}} \ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html new file mode 100644 index 00000000..d075bfc6 --- /dev/null +++ b/app/templates/base.html @@ -0,0 +1 @@ +{% block title %}Validation Suite V2{% endblock %}
{% if current_user.is_authenticated %}{% endif %}
{% with messages=get_flashed_messages(with_categories=true) %}{% for category,message in messages %}
{{ message }}
{% endfor %}{% endwith %}{% block content %}{% endblock %}
\ No newline at end of file diff --git a/app/templates/dashboard.html b/app/templates/dashboard.html new file mode 100644 index 00000000..6c0dff12 --- /dev/null +++ b/app/templates/dashboard.html @@ -0,0 +1 @@ +{% extends "base.html" %}{% block content %}
V2 ARBEITSSTAND

Validierungsberichte

Die Demo-Validierung erzeugt bereits den vollständigen mehrseitigen Strukturbericht.

{% for v in validations %}
{{ v.status }}

{{ v.report_number }}

{{ v.customer.practice_name }}
{{ v.device.manufacturer }} {{ v.device.model }}
{{ v.test_date.strftime('%d.%m.%Y') }}

V2-Prüfbericht herunterladen
{% endfor %}
{% endblock %} \ No newline at end of file diff --git a/app/templates/login.html b/app/templates/login.html new file mode 100644 index 00000000..6cb0becb --- /dev/null +++ b/app/templates/login.html @@ -0,0 +1 @@ +{% extends "base.html" %}{% block content %}

Anmelden

Registrieren
{% endblock %} \ No newline at end of file diff --git a/app/templates/register.html b/app/templates/register.html new file mode 100644 index 00000000..ce65190d --- /dev/null +++ b/app/templates/register.html @@ -0,0 +1 @@ +{% extends "base.html" %}{% block content %}

Registrieren

{% endblock %} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..ad64aaa9 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,29 @@ +services: + db: + image: postgres:17 + environment: + POSTGRES_DB: validation + POSTGRES_USER: validation + POSTGRES_PASSWORD: validation123 + volumes: + - validation_v2_db:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL","pg_isready -U validation -d validation"] + interval: 5s + timeout: 5s + retries: 20 + web: + build: . + depends_on: + db: + condition: service_healthy + environment: + DATABASE_URL: postgresql+psycopg://validation:validation123@db:5432/validation + SECRET_KEY: validation-v2-local + ports: + - "5003:5000" + volumes: + - ./app/generated:/app/generated + - ./app/uploads:/app/uploads +volumes: + validation_v2_db: diff --git a/preview/VAL-DEMO-0001_V2_Vorschau.pdf b/preview/VAL-DEMO-0001_V2_Vorschau.pdf new file mode 100644 index 00000000..273d5a79 --- /dev/null +++ b/preview/VAL-DEMO-0001_V2_Vorschau.pdf @@ -0,0 +1,1220 @@ +%PDF-1.4 +%“Œ‹ž ReportLab Generated PDF document (opensource) +1 0 obj +<< +/F1 2 0 R /F2 3 0 R +>> +endobj +2 0 obj +<< +/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font +>> +endobj +3 0 obj +<< +/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font +>> +endobj +4 0 obj +<< +/Contents 68 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +5 0 obj +<< +/Contents 69 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +6 0 obj +<< +/Contents 70 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +7 0 obj +<< +/Contents 71 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +8 0 obj +<< +/Contents 72 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +9 0 obj +<< +/Contents 73 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +10 0 obj +<< +/Contents 74 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +11 0 obj +<< +/Contents 75 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +12 0 obj +<< +/Contents 76 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +13 0 obj +<< +/Contents 77 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +14 0 obj +<< +/Contents 78 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +15 0 obj +<< +/Contents 79 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +16 0 obj +<< +/Contents 80 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +17 0 obj +<< +/Contents 81 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +18 0 obj +<< +/Contents 82 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +19 0 obj +<< +/Contents 83 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +20 0 obj +<< +/Contents 84 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +21 0 obj +<< +/Contents 85 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +22 0 obj +<< +/Contents 86 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +23 0 obj +<< +/Contents 87 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +24 0 obj +<< +/Contents 88 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +25 0 obj +<< +/Contents 89 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +26 0 obj +<< +/Contents 90 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +27 0 obj +<< +/Contents 91 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +28 0 obj +<< +/Contents 92 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +29 0 obj +<< +/Contents 93 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +30 0 obj +<< +/Contents 94 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +31 0 obj +<< +/Contents 95 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +32 0 obj +<< +/Contents 96 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +33 0 obj +<< +/Contents 97 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +34 0 obj +<< +/Contents 98 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +35 0 obj +<< +/Contents 99 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +36 0 obj +<< +/Contents 100 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +37 0 obj +<< +/Contents 101 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +38 0 obj +<< +/Contents 102 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +39 0 obj +<< +/Contents 103 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +40 0 obj +<< +/Contents 104 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +41 0 obj +<< +/Contents 105 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +42 0 obj +<< +/Contents 106 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +43 0 obj +<< +/Contents 107 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +44 0 obj +<< +/Contents 108 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +45 0 obj +<< +/Contents 109 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +46 0 obj +<< +/Contents 110 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +47 0 obj +<< +/Contents 111 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +48 0 obj +<< +/Contents 112 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +49 0 obj +<< +/Contents 113 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +50 0 obj +<< +/Contents 114 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +51 0 obj +<< +/Contents 115 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +52 0 obj +<< +/Contents 116 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +53 0 obj +<< +/Contents 117 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +54 0 obj +<< +/Contents 118 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +55 0 obj +<< +/Contents 119 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +56 0 obj +<< +/Contents 120 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +57 0 obj +<< +/Contents 121 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +58 0 obj +<< +/Contents 122 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +59 0 obj +<< +/Contents 123 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +60 0 obj +<< +/Contents 124 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +61 0 obj +<< +/Contents 125 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +62 0 obj +<< +/Contents 126 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +63 0 obj +<< +/Contents 127 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +64 0 obj +<< +/Contents 128 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 67 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +65 0 obj +<< +/PageMode /UseNone /Pages 67 0 R /Type /Catalog +>> +endobj +66 0 obj +<< +/Author (\(anonymous\)) /CreationDate (D:20260710191256+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260710191256+00'00') /Producer (ReportLab PDF Library - \(opensource\)) + /Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False +>> +endobj +67 0 obj +<< +/Count 61 /Kids [ 4 0 R 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R + 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R + 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R + 34 0 R 35 0 R 36 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R 42 0 R 43 0 R + 44 0 R 45 0 R 46 0 R 47 0 R 48 0 R 49 0 R 50 0 R 51 0 R 52 0 R 53 0 R + 54 0 R 55 0 R 56 0 R 57 0 R 58 0 R 59 0 R 60 0 R 61 0 R 62 0 R 63 0 R + 64 0 R ] /Type /Pages +>> +endobj +68 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1471 +>> +stream +GauHJ>>sQ?'RnB330/0:#YC=5H)B%.=9=sE&=/]S:1mp-U*PK3.C*6&q"6eU*QJXETm^T0M+?")I-8thQiY/Z/,gnHJ?oe^/f68Pi=)(r!l?H)KY?Oid7jDj#GOB'"+a5i576g2HO354.//*!.e&;eUjs1N+UFEoXX/pQKmaHbR1G*\=XT_c!U#"(1seKMFFXqhgrZl0@dQN]7C5Bl.ldBSH8RfL%>U\t(uGkA!VG@EmYBt^MmL7UnFN"9(C2*+r8bLiZ0hD-:]u)W(n0M&A+7KV5Wk`kCOGoo0Dpi)S/G]Dledf!>"*;l?ik%ZSbX=(.Zb_H_B[:r![iNj#)Z%c!"$$m_EBdNUr/@gSt_6`ZmL/h'_FL6]Y;0"!,rGnp8BH(2aYJj6#3I]/ul:aYmj3iKCS+XNo0?PE%m$oh=,H0F*_sd\f;GiCcsj`p2UO2\'$1H>sul[=M1i(fM3U4;jcS8dCbik):)"YhkOaFNK)2H3>e6Slnp">^.VLVa5:BfaM=\\;oc)I;c+>*b[i/SQSsPu/W'.lbKZi=Z>iK@gN6N.+kL;r>7GX$0mnk&+LL"MN`n[t;%$cTd(mU&KU#-7>8n9P]/OqD>WDG&i,2A$j_Zo.Qou9*:DOh\k-dkPL>./]X$QD27+$\?beG_\Z%9k$=A1eY7i-IAPf;r6m6dI=iQB)QL'Z5j*9#-$VoTmqf;4=frYVsE1Eqga[G>p&]9jE]N:QD:o9cZaSduQ1,8;5e.SKdL-=^YR9?bs#\2;:+&6ZWiCm:=583j#QFU,H_-dr>9#7+;rf0WQk2Tm^_A!826C1Z`T&!b<5i-Nlpr,I@[eCV:\!S<%tX^+/[Vh=1`klD"Fhifd5XOFI8TBLSO9+.He@,`.l%H0QiHJh=+tM!7/70,dWN)H5Lhl4>Kncd@TG!.u#99(9IV"odTp[Hp1>HL-S*"n"R%'MM\N!,dAa;1@=qd_dSh+o8d@oZS=!l17S7*4_15b7BS_Xl03Hh_`9!h)`DaI3`!+a=Z^&hDWHa&9%V+:2mU$:p"-T(4p3C&6f.Ije$JH1FYu"*JSmF$*&'8E@hGbQ91u^7o((TkJOK.'YJI(<,ZQ2'k?8.#M.\\_(pr3Y_k6H:L(;'(,haq=K3hJD/>GI0A'j%Qrs,!EFptA@]Y-f-u(,.Pr!=FH_8qZmWjI8)KZH'k,DPBh[Pf>^H!aTc,\O2/*NOSm5EnsgWdPUnkQgl39!Q(Kt+!%D/ALP*i\V:MaP2:5BVS'U3a9Ze8kH@_#IK*Q)CoEU%]'<^d&b~>endstream +endobj +69 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1355 +>> +stream +Gat=*>B?8n'RnB330.sT-Kp&3R=2'([$t@iDAq!lb`6&7Oc=)eWIT5j^OD5SK->BsRG*iAUndO0k:Qg"IYms:/cfPj>^n"a-mT`SguFL?iAS7CIcX!D&mt;_1fd48C^8("7;`.8,\RSF,*$/N!/?KlU!i08W5W^#!>@jT-=$gN3Wp;Tk-fP,rte)XjaS?HBZpfe=!DsenjG?Wu0)67`<>\FGr]IN$'@`-d2rLY&tMKDMe/VCUPq-X^U+U9EHCJO^U8<93!qG=Kc7N)Q='k?G6H>1bu5a3X8[%9K#A^'s-Icl)_[#WSu/)Kr0bt)HE^sD(8JZ5%i+#2rqE_^g;Z_47ae?oY*WI=_lUaC:%kD[?f!.RR^j02N;o@-:72fQ?9i)+.PVn\i]Xf]1biFPq39tZOCbO\huD+m8bh)*cm&BZHerNj/FP5(,(#:0JMB6(!\Qem,U.afj^9?MhI:[iG!6O-PQg!%6b>=2aAo;0i^&VWAIpg%,]Iamg`Lo)0%,:rp(i\l@F-+[C4%-f9F]UN?c/_fTgP]h[OiG$2j\KE#A,BQ@[GL*j\`@6ke4<;YN5=FX`mm;F",AZ`XJ'/g8O!D=Jt0l=QDQS"QbNJ7:WU?'?4HPL&V2E.PCd[o.aP>0%kHuF:g5=@mp1:Ldt/U&K)T6Zero+;kBP&hi!q?^&@&r#U796#&beDehJTc9j%=bbO%g3+]0.8$7O1%#4D:.l&HG[M?4P7KZDBksp%=IJ"prF.u,!\Zn["E#H5<.,4k[-C5T3n#tgY9\Nu6%5+MA:+bi5G6?It+kP5AU"9_nKCe^aeYmN1I'3>Y\Q^g4Zp&'K`*O&V)nKj@pu?@)EHTgunHu)#:oendstream +endobj +70 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1399 +>> +stream +GasIg?$E&%&:Mm.R)eQb',Clt`1rkaC"fr=LU0,k-SO,KCRGnJDQ+\$qu:P+8h(bR3=-"6Zgr@hOk+_VQW_#"0*E]\\XGCP?k![Zf6PI28:JOfuJbcDk0YOqkX;-!X)ZJ?`^l3oQqso2R`j>FF(PcD/sC=\8;OSIci4_\%5T#3=lPXq(^,8?d2=[66"Hj:i1J//LJoK7#.mEi#h?j0G4'YBVGIjo;K.Dk,:67;jFF<>1#@rLRZ&6D*4[/)^jus*H/k"in,TUiu[bP59+6@U%-i4X?Tp_a$m$fVge#VB>'qOY]Ws!O3QUSV/#k]qrB[/5,I*:Fg/WW3n+Bs-nCSKa"^d=*bA=nPqscc=S<^5IQR5l*5q?a5)Y]p:LcH8:WufdA<[@jO2DQK"IUYPj/F#r0XRg@3N8+n'GF5-*SM4=3_j*s;j#Oi%W*\;AE[u'7Db1\6_!(q$m"&$jN,]A9bBmM%Yk`5NXQr^'R+*Od&*0T6\dQg*#UdW;C$Bqkg63:,=@5E`>faVZmk:]d,C'Y*>RhNLr@]&N!s_)(sTl;_a'iIAh14m)[n+]^3d]LJ+9.=&-~>endstream +endobj +71 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1389 +>> +stream +Gatm:gN):5&:Ml+oODJ_nQm`dna,J[Od!"'8g89g5P3A(^Cad,h4Gc\$CTq#IcO@r7S`0&!NdaY!lk\NV2D-?k'W4&I=13I-MoH/'O`t&gR')Y-`AE$@pBK67Il$)'!mh5*QL]H.A+h6&:\uEkN`*lshUr`7(,aV2&RNNA]PTJ9rO-r@JSQrUtQHbICX$e+sRD,E9j5JhSVZRY5Nl)BD*$:m/#3-X[`*4pS#-uC?L,taO2o.#e\Y<=$kf6!:an#1FTHd!:#KJ^a\']U.ILH42C@qj[-Su[[%;e.kF34Za#7uJoKuh2dj:+!+BgH2s6f'36]^RHqe5;8M@9g2\Jhd:@*r)Tk/7Zm^3no3&$CTon9FS;uuMV5RR\SKbC?;4]Z;d]M^P`3IksHUA3lR/]rTNNa-D,]p2UJtP7]\WhKtmtPDpX";k/Rc`CWnBBF;bFH&_k#U$/b#U%\I":n:s"3Of"tB#FIO4iDC^N'ej^p6NQedPB(@/bbSNSP_>VsCL>iEFm:FcW[dfWZ?[SQt-1OcLW!q+=%^Hg@'`a/"2*QXsESTQ@I7nM;^6Q\.5-&"b+?:]XS3q'HE4AuN"b#)1+7lWe9L]:FcGc55lgD?VA3X=r_b0&=XhM2[ip71pH%5E1`#HF`'Z6dkW?KDQo(UK_'SQNG2Bd(=D5abl$bppX#N(Z@lG0<$%H*uUGa\V-3HC0gbgJB^*Z^k`7e*88,`7,(%7hj\7d_udr$<8rsKgsD):-SE#KXO]/D3qYt88!kIA;qpumjfUQSN'A3T7Sc(7qLuO(HH2k\gY(kMUW+WA.YG;=;92_(I3XQI"m0[2bB;\Sfa+/oll_9Q:2-eBHXd)RTg@EH$kTP\r!FX'g$unb!%Bdg%,-_8YIus2;G%MDPXr?VHFAYSa;hN+te6Xt\:BFbAm0=$4M;P3X,'`h>^!6/es:Li_R"o,_:?gBHaWrV3s2'a/-E%u"u!1i?N7BUBARb&2]j'I]D~>endstream +endobj +72 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1304 +>> +stream +Gasao=]a?;'Ro4Hgde5S:aK86+%$;c1SeU(d!=P<+\H4"*NIb'b-.Ef08WCpgi.iihrVKI'a'>CXSi*[!h<$Dj#I4]@58'7Lk*SnN$_'PO,.4B)$RrHP/dWr$9oGH4rn2W)50/j*-A9A)r6T$S:/PG'tDK'l@2OI`sr;sJ.>YIV+!`q>T;'aF_7lM7%c]^S$nd(Ei!N#MW/N10a&=oM1P,"*.0=W`nKE5u[TnFn8DdAMfO=fkO(o+3hDSi*ok_MfhD$V;E.>ndnE@GAhp'hXgd]!d#VLt/("XB'GM-uDsm*oV9>,:Z0q>3^=]S#(\!C3t13Gb&)aPsY@`^nA=f(S*)rgBt]dcpHokCU@GQaAc9RAljh7QA+^umCm*mSTu4EpeT'oO8?oRYN/UL`=;\,DJG8#p`[Z^ZsGh[@%go!7*0,MY;o=o7*mXd'0TLQ0Z-af9-pfCPgh22>Wo,XP(d+;L4g6g@fZfT2"L0&7=n2^U@WT?,W%*L"XA,$THTS6>5P##tp:jdTC9p&8;,A"Dob^X&q<%euf1hefk..sZ]WV\mflM'>3-E@*3H=Fp(5D6apjG93+GkcL$m$Cg\D$^OjfS$;"Ga:Fufsk:\(bYX8g21.rbI;-Q[1#;5?4bJl$Ft5M@-&*&Uim-Xd1+.@9u>0,q&8]sp*hZMC5%;>]gKt`h\d"Us4plm*+,garjoIFStWTZ`6Z47RrW=0\eg,/EJD:MNmq4kHl.Mr&mbL*PBZFMF^)si@>_qhUM;;"mSGIA'l1C\$!fXMc+Dm!Y:fR@->PD;K`XdE"(*+A[K~>endstream +endobj +73 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1480 +>> +stream +Gatm;9m`@!&AJ$CbV@@P'D@%^Nj<-'8n-DW<2Tt.YdBRL?uZs4S%"Jo]cI`d?Lm4=C&`Hgtb1M`ih&!mMGIZu2&k,>u4Dpfd?1a=((etgY%>nUTd69QA6gGb7"W(<=H1&slrG,oD,ra"">F-ulV9Z"T5P5YF/S%RmFS5?VjK8,!n,s!.JdsMjtam6#HcseN7EG-(Cot_Y;Q9KV5[E_Uc\9fA_^*+j-6KHq,qF2']pKdAd[[g.Wgt%Z.`JKWA\^ZWOU$VOdGB^PS=@^[?C\8O2S0l^Sc>.G%5WL/-O>(mc9X,T;@R*Z7=.`e1]3qD\t'#Og*l?,0j0eXKturk7boUVc1[=h$ER;$UjF3.`b+cXq1O;B^9RLFDWr@HH6.RisB1HI#IQ#lIReJat8!kfou4e"jl*f$*^iW")'jBas'J58,7HaiBc`ke%>T.dK`SDYIDd!mAl2tql9Vb'RGsiWH[o)`Q34[STR-@KIIK0;FFI)`.NaZ1oK_Uat:**-[u20,"8FZUfA:)dk^2hl_$!g1rXPV2&EQ=^?lIAAbsja)tt]hitd,tWFj("iV59u3^)NOcG9K5Eb7AD2PPHJfnPQePG1(L7AH8DV`af%Q*,[@S_-#5%u?YQa"f2kLn6O2g8[5p\L-7"_HF[=5h]>f[Vt.4kM8kUC>R6YSH<=R(It6@`^h'Se\'^_Mm;i?t[9od7[9`NYrpigi!3hUK1J)47h0MJs[#nKGee$hr"bF8XqR+M>]$]7!U!MQ'OHSMm3YC-m[a"OnZ8Nendstream +endobj +74 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1465 +>> +stream +Gb"/%9iKe;&A@ZcqQa+;.SSu/;JqSX/.%RQj.uCa7E/hA6l&1RTo*3lh4kKR`3R%rX]eZUP58nhF\d5-'>X-6q!Zrp^tBFYHk7DG9G\g.dkJIgoBFZ+,8LVr6OPGE7Re;G/UdbgHp#Qe#f`^H&q\1[UPspb(p02_SOY,6+8PRUKX?-FCqVln>X_Nlicu4>;s431j@d@JRUYS-j8fVjA@@6Q+/bGAmn]ht?baDLpP\8rSA<\97Oe;pm!NjDm]YlI0YN,'/+QTYpm[UYku=9^*+!Ld+pEn+YN^V1YGIqDZVqqb#52_]ie@%-EjRaG\;Cm9+I:-F-BX-PQrOF.]GXpKd!u8:=#BC4Mif\*XW\"l20HCYh[EH]Pn)1_]2mJ1PZ&#(,oc(km2Ku^X4qq*$OLk"nF?08Tdq#%pdn$/)@XB;8h#0AK?@t>cMt1l35=U4K8FY*QU*s<9;Dm:n-#Bm_cLQQ4KFjWVKX?kmQd84*ZY0152=imP>1*Z\L'(?NDMDHCDTr(26T38]%];8*c_+5_Aj/`;]+]^ol=I<>:Ed^k)_^0SQtK#Ac#8Y?m@pg9,dQQ%5XiV&BU6%c3W-TsNGu%e)l$ZSp+RNh=>9DQ`a2?ejeb`3V/HR69's028=sosh3u15c69cW\_5kt%TdgbmlJ-AsGc6V8JB.ilM:_N<=qg9.=Zl*AP%dQ88ep9[`$WW%uG=@ZHgs7adc\cjCiWqPi%[7qCnH2N/,$eYZ((ZF;jhYpVerjMPfsT:[p^-uhp5'Sti2JjCf@tA.DFq*DhF#?!H]NFWfRXG^,U1o!d;<[)@F'V9X\%iM8aEKMp3b8)@u>Tk6sC9iO$g.JTR.+>Q@S>tQ]6?+H*qe5TtT.!X#R:@NU6%,a0']qC#7_%2"ki@6qo23N!T@sM40t8*JGp'._r7E6/POC9NG=iTGCN+kZ:jn,e*8joM^a\YfO($hZ>ZJl.-@tO3:6m]'KX]IJ4YFda2Dj-c0Yh4)7n33,rCY'na@6V62Xk>e):pR2)E/PZpsU`[E+/9YXnseH/J__]itl8&_ls.P3TRFufcAiep81FnU,Q'E5YChV.80Ao5cICmLl<9\Wbo%?=RBk`g_W1@!oWnt8tKeDY@oL&$.'`@28d'6m.?3Q.BgBX$:&-^UV8.@#qi!d%&'CfcY_@:1;&K95_A2%0Oajar5pU4+U`=g29qi@$M8IF7u2gC)endstream +endobj +75 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1474 +>> +stream +Gb"/&92jk?&AI`dqFJ'S=j;n;,isbhag.Tu/3)_MMm17q?p2S%_HZs7FR*Mk0po!-.2>c`BVp.Ql`VDZE:E@PfAEnK?p'"$QQ3McaTAuuI$e0VVod%f-S4=NLDj8CQ&'g8CA\3Rqs-fXMDJ%!/Kfj+;c'G87c67FmF4QS,Go2Y.C-?@t8#2!Gm`DtiQ<1,/Ie#Gr<)#"#a6T`t92h'F*,XfP`(,2jjYd6[[PD!Rf\,PGB)6X-CT0'o^C"G)IU'>D8nFVpb=E'Ebk+'0E[XU09Z*EH]9cp4PAV[$tp?FB]i_nmL5WiM&32)O';AS(i'jk0CVKH(0ZZMbbSk?n=F/\T)J'*_X1Ml*EtJpO1ntGe`2*j',6D.G/_WRr3!Whl*_j[CO,b\$PF:`Qe[1L9rh[(LE2BFq[elD?>O&F9NjehOG5L$#e*@sU(A`eC>V,cW.:t)CliSOHL%uVXb%,QlRLF(=^3"@`^>=Wl81KQ&OG<^F$\K[J%2*3%ah$S)N&ZC!UmuUYc-=%fMne#`RD_5.);uF%,b?5Gr,ZB'*$89r5h3HeP9lnC@,6.u$Z)<`c^bHAf>b(nu""-gq7tB&"JneUdWjp+$gRS.&9_$T(QL=:*Da8O9]2JQppkJAg06U0+S%J5bX,*hPi*qL9/[c7Vb*)FD&MUX]\J>?62.:7SSKT(##[9hV'=N%h=YFF^^iRXPs?bN[N?8D.;XhduD0hTRn2)CKt;jQ\2rZ2hQuEdQs(!F#*qu'qB.GhHgUR@tSCKYJ'7bfTSLHendstream +endobj +76 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 670 +>> +stream +Gb!#V9lJ`N&A@sBb`PB;B"pQj8P<6eW$UBaP`&bseC9l:(a8G841fYU6`?7C<016;SpbP6S&^'=Qc7j#COhlgY&5+2%VZDH&ddeCN76ih67c'hC*6P*mNeAB56b`gP6r!KPRGaP3),W6'%W_O,[:dN--VR/cbTg17s'M]3#.Hp^jbQ"&:jsD6G3g+X;eG-Yga5"E3_?[*j4rYn#k-]k>*f31.fN*$.IS&&G#O,4Ia"^OM69f"mJH`l*R"%UD/RO%&GD5)Vkd-7te7b/KS*\a?0,bj1u2On'Ro..pN6:h?F@YiCZ-Rc3Cu@Zs9QF=+u!U&o+KKW=:RU/%Fq=[>4Z(Tb5$[0iTDR>DLTeG9(;"=HjYYZl7!BM*PW?uT"rZcg9jBp;f[iFkX/L+/Q6)=UC%n:h:QY>LQsF/pQW3'?$pn(5fmF'XTr,iC.Nb0r]Z,^%kY$Dr%n7EK/Xg-IFh>8;C&KH=b^XH/]NFUe/A1oendstream +endobj +77 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1222 +>> +stream +Gat=+bBDVu&DcY&B'H25-sd%mV%q11P-f@J2Ci_MU1Z92PqZ1SRH7F`uL:ME$\)+CEfR;W^aZZ=_3-2hWE]mU+RX-ePO=iYR%(J$IXU5"CW..A:hq;!2<if*gRI,O@lQ!G$EM0`8,qb*Igd!Yp7b"g^,c]7q*1DRmB&LZkg>-fLS/FD\f`r2lQGu8!0fIpWXa-j]<\?;-BK>LCFTG:X0(EGX>ARpKeb2`drtiZ*S1`cXC03gK`#Vm=+SU0'1AfSEY&AE/?+up>sb>ZNXi?]C!1]HNQKEgC+Bl`.QaW6rs+[->V18=W'lLHDr1SfBiNZB"r;EGd/nAK<[^2XNBUbRoAWK;jM3OjJ8m$EB8uUKI?P+:d1$JpAgAtKHcj0;Rc_'6#&lr7Zuq>Ji0e/JF*6Y19J*CJ>f?m)u;F!>4^j)(j\b&?oYg%gW/I0A;a05)%S*m6kX(eiF(65ef-;PVC=u%'`V,\RVE]AMrE6'PHDe..]#h$h=h'u%VV(=f=A3*G@=7i\DKdcP:XK4m<[=K(%q?3H*%uX^KtKL$40Id;QtI`Cc6C"3M:H(oRUOtB,NR48b#;L5O;:$-W.h#j/USBNPqf:<8.4nc4tTs>TGEufP!T;InBl/R_FN-N&IBHh_L'$jLDDIS`Lj@m.X4ABuWQ5/B5/?>54Mq84?#7QT>9'#O_4/"sHabue"mTH]db26$:Dqa]4_U'o(TmX_rIiRJ7;2D&~>endstream +endobj +78 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 721 +>> +stream +Gb"/"bAu;j']&X:mZM/d7;l>PO@Mqkdh6W*b/SrEPh=8\2T%@Yh^^u4TZI^dC;tKL?et=`7gpgF=ScCS!2BTjY8Ar'`<.ec,S\jL=_,9&Ou&qU%3uaI>DZ.8Q\"DQX9$9Gj[+#BKWDe_$>*H+cQSA:/^_2uKMu;>#HXg]#9j]Z.>5`DcZU"LN1:fL)emKRo0%;PWEmJ%\m:,/q\8=8Cg@\p_DB9=em??"N(h8g2V)Zk%M]Ffn[]F9dB+^ar(Fi=!i]`hF)5epk+bj\7_gX$oGW`,",@_GTWTM!9AlR`q:,B^]9Z?fPX;FUaC#^@;n,sqeCuYi"SWj<h^PLh?cVH4rcQk-FiAa>)972/.)s8aOLaM#EQ!\hR+tC1k]%;si@.nfWT/*.BV?R^9GDF2V"L*,a(i0\QXl$hZfA_p,P5;kqoO+(.=7=[ff(.rO'7F8R^a^L0*6j84&X!c!NVt4kF1s++N\m?/\I4l^*LsS:NOc%ga6'_\5kYGt$?SZ~>endstream +endobj +79 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 920 +>> +stream +GasanbBDSn&DcpmZ_TU@U:748dZBbQD+S]Qb/OmB3!$WK-93G\hiTHOL6>Fo@&/)'RB&E$!Q?u*hfgT$ZP6.e(bcHa*1.uadRtFRKAQco0VoEl,S>o2BZ+>Bd4KotuIZC'g59pO7S=_rZ`iO'fJ==!t%,+R*thO4Z#-D#)S9Xmp5L]ZT>@sGp#Uc-.FXl-_FW>s-C"uKk/.Lm)b5pErT8-b3e&]@Q^EORu>TuA?.1`E[,\RBaFQJ$(Q/Cs6e.pN+E@Kr$:Sbn._=.oe0Y(EW'en*q]%UQ4+FR2.d(f$B"rGnM^CQ(H3kId6L[TSAr&+8-4bC"k[2q]sY73#C2?2[Zb4Zn56cbk8]X/SCql8TBq+#!4!_;KTseC?(Om?XB!,4s\Id]IAtj4n^&,N715'KRO4c3\,gq]jdp'u>%Ui3ad,$T0+[`D^M?K'Id7#FA:+KZC-E22X^e!roB)po[_FP0c26EMiYrDNAT!`$sP2r[s&AXWl[+^19[@lpVqVkn^R>VYRmYgc_eB4A6T%#AT&l,;2l$n)6G`C6[#q]WU)i:lXgrR+/6e3Lnr#(#`&dlMt/umGOSY$@hse/U7^tdR3qMe%9S">9PMhh>=*/'6!nD&/Bs%7F[MSY5W2N3ktVlcq@knhghcY+HsM?=07%s^4FI@?oD_4nOVI[+uQ,"K0NS!Wu1~>endstream +endobj +80 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1039 +>> +stream +Gatm9bAu>s&A7(,KR!$l[l@EohGOtN(iRrj0j(3nE)k;b+Mu@'gt;IK5!@B2Bk/HBq>CJ\R^E0H]"F(Y!.dq84jN7;[-Be'$6u##,Df`ah=YlY"(32K05q_8319//E$bBJFQ3n"5sN9'O2C4ks06DOXD$g1M#(Ppu^u1r9S9GrqR44IlT0[0S,._>L(4be*5EY]0FJ?:u4S83hQnh*FiS.!mrH_-5kB:r.6Fi!A#U'U`tesf@kHYPj]p57#?(;Z:?cMjNOSkBnM"/OjF/<.$LC@@ZQ$PLc#?aBGO,o)E$^I%GG^k51gIOpSr"aWf(Qj]U:\c#O"?Lipm;bn-sPb$Z%lOmSB+7g9KW$Fk,Ss>K*D8%DV7&je-=#sACEa+Y,_g$:mp$iW]Q0OF1BMf^d_N9$_tPjR,M"+>jK#jXfGHu@Au=q@>0tr.VN)Pk,W[JpMP!QBUnW6MM&i2R[M(an3X*f(j3>gu0I':;[f9f+q?SgBLr7]&S%G/YWR;N-56a,F6&?@AFH]U[5j](\@hN/H6gT:]`Rjh=ln!&RU&>p@ll(D@lhcL7+X:Z"j@N2Ebd[Mr)][Q!OZ!Y+-jnF\C8-\=#]8p/(biaU*U^::Wnn:jZTRB)nR/FSUFN11k.!-A^nLI7:Il=0eB1!D%m/SE)rh]I]^<_Nf=2'$'5W&Kk7r[egHIpELl?1s+*Hl0s_T_LY:r4,1W7:r29c_qeRB_q8)PhUCOn3]W5WMu-f&bBUke-[PR97K~>endstream +endobj +81 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1060 +>> +stream +Gat%!a`>iq&A@rkqO"'._sGQ$+Ub.qa(1d1eDpUop+5k3+amtV>01kKof$lFb5#tts:5.^Jd%39+6m)J--s"0U[1mrr9+A-1R:U@,mGuaolm/$Lq$a`>kKu:0_q!#&&G"iQr+>s-6Z`U],=G$&V2ak\<8i0Q3aIdY#0+c;L(s^aS@]jW'=_%ChVl\R)7@-$rTT`6Q!h.F;X?d5SWLN6@P:.,WQ5P%lf-p.aAiMZ+0OB]\)?s\3"($cF1^03fUVl]>Fr=f=;/Ik44gsNsUYH&>gcgq6C@3BQB%n'(39,mpWn4VsqkG:[u>`C*t/VLbVX25Y[1D3>#R_S9,J8!gPkfE#bZ3`%\=OQqJhi/<>mBX%$\Q(CGt9Y-85*Ak[![]Y3H)=;p45mdVbZilkK/]6Yt$AB6T6MD11cXe]C">f)3N@IGsda?=%Fq!,_#hd[+s.M-KfQ4=U$@["hCR2lL5Yn+(@1;dSZI8Wtp4P"f7`5'uih>]'5k;LA7eP,Ff"nN;0P'G\R@&j<=E^=WUhR_/M0Vj2bJ_VTpnRf>$uB^R\AK=R%e)>?tpRK%tUmdt$oY#:lSXNNO*A`!h/lM)TQ*re).Lk=g(GdF)k__MXO]S7MFd)fcY1)u_KE5],SCuM\WP&diSjfl_%%f&?j47m1k=5AV!"ChWCEl('O"S`+lGOWi0-LH@O^Z^9\hUTFWZh;)[0OO4GJiTQqQ!Hm;c(&c3o_S&]\&uFi[^\\Km2n2KG#*H(&HHUN+`lH>:F6@J9>=_c1jW'Pm9:29-oBjA?Q6hM3SNh2GD&YodB>X&!sO,[]3F8-NKaWg7Dk\e*_IJ$L#=(YF4D<3T32GBB*gEm>H(:;>4Bt(XAaKg6f7ZgKJG:@rNe0kE2^B'RV6&Y~>endstream +endobj +82 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 606 +>> +stream +GarnT95g:b&AI`dk3,;*B&AYZ*_tuMD%_2b?@"p1L110`!R"AiI:j@O?mfLhLgbJ@a36<3\6+(VWW=_8SDQ#.*;hTH8L4'm=SV6$7P%KlC*6P*mNfM(?3XH>=TaNnb(\tcS0giV#rO+[$!3iMaeai"3rrdcYr[ac`[%1[$'T)#^V(%ECh)ek5*,nQ(e5@[DFX[+e9MLC/U.+)PoBM'"c@RLP2EFALAI`,c=43ep'-IWR;tPj58r8JMRD8ZdJ:;[TocPUP\K-N!(.lD2;V(_0c[!!M7UmRd(Eje""cA-[_GIOT9>mM/lW,a@A!gdQ-YdC/^DLg+`D$2V"F/53UjfH-tbsI4G+'5!&1A(Ld#6jo*Bk]]qkBPHcdq%HP,22YaflqbU=)&K5o:X)_-n2OYT=0(^e[q7t];G],APV5_9SeVA3R@T-Dl#7U=H51XXINj3g9RO!%HQQCkFC%`h@IjH2cK'XSAK\]0~>endstream +endobj +83 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1061 +>> +stream +GasanbAu>u%,Le2YfuK.)87CLP;[:,oGQt,eIOqHhi_8\^$/ceR^``f;J#rO]Y5g123.JhrEQGirP=.b2!Nr`IY6@Lcd]!G6$H8"C?]CZ\DVm'/-q5U$RR:O@;*mjQ5Y4PW)JtbD>]fKrU`mAo3^tKe$H"ls4Z+Z"JH/67c@\9<'_`Fn9h:]qZO5"G/jS8fCCs#`(g6;lC4"!_LZ=a0W7XYuU,TgoYtO5j"NDZs127$2g0@(*lJ1&ti,W-=B7:!&;nu":=ie39V'P:.W7/JsT_/mGRjL]Tma%/5*+.7^p^@!M@<$uF(\Z#0$pRs&^.7k_ligBO3,cEC#*+9U=VkstW_W,)bADW#NrlA[AsYXSi-gO0`5DTW`oA^;\7_p/odBkM[qg,[@rmf8r&7<=MBY]RU)$l,`c3=[u(\1u]"XQl_E@b]sT!,eBI?D-dOVLJ8AkB>s!i*qpr3754Y4,[\:OBgac[g>\lK+VC];9@+$3f.q>MXB<.eupGp_P"W`s+e@G.T*G):M4g;c`dgMl8uZ+!M+&UOl=CBIf_>R-V%&UNqh+^+)k'"7OP\a%MCrh^t!BH-`P/h!C"?_"2'`&04s.H?OY/n*m*8FGEo$.?Q9Ygn"_RVK>O_/+H&fEa-$g!Z7MF]7+C*Q3)V%;2kMCQ!4=fY"Xmjkq+rX:Ol!]&Pa.5U(=*aVPH4^6H'SlDCAs=*%HmCVVsoFQif`)jN-JH+:1lYqB9%`5C,bCS+dNin]IYXGj#J)IA<8SWiR$Z-^cIG4WFij6Ic[T%2F_eu,!a@at,Y/H,X.^E(/~>endstream +endobj +84 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1060 +>> +stream +Gat%!a`>iq&A@rkqO"'._sGQ$+Ub.qa(1d1eDpUop+5k3+amtV>01kKof$lFb5#tts:5.^Jd%39+6m)J--s"0U[1mrr9+A-1R:U@,mGuaolm/$Lq$a`>kKu:0_q!#&&G"iQr+>s-6Z`U],=G$&V2ak\<8i0Q3aIdY#0+c;L)Y^jSTope=SF#2DfFi9OV['#-"BA+UmC'3Xk]m+:<6b+[=0RP+2]9#D0a.($CLb=PWd1?>T3Jg`:>8BA;ESS]9FGh;O%/lWf)_F*UEua+Qi4#ZDCoHs$VTi0\C/,i!B6hnscH:>qNmT&PMIeP8G7&7_4CJ=7;gE[&/H39_jN"Y+dWi&F8ELgaK'0pb^]=<8Xc[\:2c'[(@H$df2YVaAIguDC>`0mfV0i^eXa=.liODnk4h&#+eBPl?eZ@>69Ri8TbX:R5CLY/'acgDL$g\TQ:X-7r[Xndr`qSMDK]tF,8!8>rYV(^j;'=[Q,GuF'_Bb-c/DG\A;hrW\BVS(8qOsXaF-(DQKI.lWZ\D$A_V=sQU,YpA"j*C@*.4U._-$i\jI'F&Y20\p@:+Q?rKtR_f2?."tdG/Ba#BM!U1@Cji1]Ij5h!)qh>bsW0=I3q3b.\T=eF?',4T9+;&-^C.nRb/aL1M2'Gn!!lTTdE&u$-!AfjFi((#k/-an)0V?:"f])IaJ=A]rQc9B'Xr?@D:Gm"`m'l/%^gVRQ9DEkk3oDDO#W[D/k@!g-9=um%3o/+op2%6ftr\SkK\rQ[X!hBZlt4Ti76"9soO\ZIG<^:kS[PS^c:he$s^,L[$I1*'G[g,"NLc\:!qp*ZN5DkO:&uP==Jhd+s(HqWan$YKWqGgWF5FCmZ]3[S7Uo/81OGdVa+`O_+FVN?Xusmo'#'W)3cCIKReJ6'M~>endstream +endobj +85 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 606 +>> +stream +GarnTa_oie&A@B[k3*"'_gOOWEDdTePLs\tks_NggCHfn&.=@AtF$+L;tu:D\5ulO1J?rs%fX9>?!;4KNu=+`AtLX6%lErsAT=r)lEJBKO1&.2(#G8lH]e\p(ZI38g).WMN@glVR9UR%4q@7#T&*k1'p#S-;i)D01k#arJ8PY,"Fi-U8B/VW\OHOX+S%j6S[GH&[&U6eC^o!ds5..c94]&cS#G(;q&f":21"^l\9*^mP5Wfk>W#/Jfo-BHfPc,=)Q4)e,180HWZ!JEO7tVYUD^e0d*G#p6ci,QO?4U7@JNnrZV3F:PpGg/R1A2U$W7:%bEO&%X]2?F4u`T?;V8Nt-P^MD0CUo)@`p?M1#2cIeKN#4c%))uSNHI42/%#RroXendstream +endobj +86 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1060 +>> +stream +GasanbAu>u%,Le2YfuK.)87CLP;[:,oGQt,eIOqHhi_8\^$/ceR^``f;J#rO]Y5g123.JhrEQGirP=.b2!Nr`IY6@Lcd]!G6$H8"C?]CZ\DVm'/-q5U$RR:O@;*mjQ5Y4PW)JtbD>]fKrU`mAo3^tKe$H"ls4Z+Z"JH/67c@\9<'_`Fn9h:]qZO5"G/jS8fCCs#`(g6;lC4"!_LZ=a0W7XYuU,TgoYtO5j"NDZs,Ya^lJe86'B/7!@ego!_.hR&0hWQOFZePK2+_tKHs5AGf_8]%_f]n>DY;adZb+C7/(9X=a)]:f-WVGEg2IdL0#I3Fm4(PDRVfJIahK-]%C'43uM;-]S*7Pm6.X^`ZoQYfa\/;h[/eZ$^8-dVlO[HXdo](gi$BKH6`R8^nrY$gD5jaC%l4\oO;(;D:!"Wr;*c&18'&ZI^HkJb*F1."s-jKhUliPCLiO=h)?M=VJMAup1sdblo]i`G(pg6S\r,1%cD&&2#$289BVeb:m!5jj)?f,)l(ZqWd[Pm[S:'4i8t@/"Ua^.l?A;3DHC][/k27a'7IL*ZWP3WaV@!`S$;N@(t&!oQ0dk7P;lXHf`"T\rHc=+%-i3;J,#M3&d>oGFB41m%*P<>^;Cm1d)e0d)3.Di-P2J^E[9c*Lek_Z!=-#KFFpRP+Q;>_>R^pYP);@5i"LK%^^Ea2@Km>>`PDE;OmMIX=(t:r`=YE0:?j#^.*Pj'ZC(99Csqe]L#5YoU,m=3#hk3A6k3G7:sQ#f#Tkucd8D8RnjNCY2q>Un6!T2tE;&"n[OBa]c"gN`%aO%QqB-lV4+7hQ,XTPBI,X#M953.YDG"Yk20VL&#+U<@QQAu0;&OG>LHA]Ulb_1<4C$^Pp8K>chOWiMGbm3=-3;$gl/I2t'Bu^@#Fu=ab^/ICcs:7X^oEiX`+2*QJ~>endstream +endobj +87 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1060 +>> +stream +Gat%!a`>iq&A@rkqO"'._sGQ$+Ub.qa(1d1eDpUop+5k3+amtV>01kKof$lFb5#tts:5.^Jd%39+6m)J--s"0U[1mrr9+A-1R:U@,mGuaolm/$Lq$a`>kKu:0_q!#&&G"iQr+>s-6Z`U],=G$&V2ak\<8i0Q3aIdY#0+c;L.2BjSTope=SF#2DfFi9OV['#-"BA+UmC'3Xk]m+:<6b+[=0RP+2]9#Ell>($CLb=PWd1?>T3Jg`6Y%BA;ESS]9FGh;O%/lWf)_F*UEua+Qi4#ZDCoHs$VT&=@>^,i!B6hnscH:>qNmT&PMIeP8G7&7_4CJ=7;gE[&/H39_jN"Y+dWi&F8ELgaK'0pb^]=<8Xc[\:2c'[(@H$df2YVaAIguDC>`0mfV0i^eXa=.liODnk4h&#+eBPl?eZ@>69Ri8TbX:R5CLY/'acgDL$g\TQ:X-7r[Xndr`qSMDK]tD9Y!8>rYV(^j;'=[Q,GuF'_Bb-c/DG\A;hrW\BVS(8qOsXaF-(DQKI.lWZ\D$A_V=sQU,YpA"j*C@*.4U._-$i\jI'F&Y20\p@:+Q?rKtR_f2?."tdG/Ba#BM!U1@Cji1]Ij5h!)qh>bsW0=I3q3b.\T=eF?',4T9+;&-^C.nRb/aL1M2'Gn!!lTTdE&u$-!AfjFi((#k/-an)0V?:"f])IaJ=A]rQc9B'Xr?@D:Gm"`m'l/%^gVRQ9DEkk3oDDO#W[D/k@!g-9=um%3o/+op2%6ftr\SkK\rQ[X!hBZlt4Ti76"9soO\ZIG<^:kS[PS^c:he$s^,L[$I1*'G[g,"NLc\:!qp*ZN5DkO:&uP==Jhd+s(HqWan$YKWqGgWF5FCmZ]3[S7Uo/81OGdVa+`O_+FVN?Xusmo'#'W)3cCIKR'O6'D~>endstream +endobj +88 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 606 +>> +stream +GarnT>Aoub'Ro4HSB&!74PqfQm?Vp`]!Y8Fp15mjE>T9A%>Z5$fC.@fP[kdM+O'A"o.^?)K;IbW)W9>eLDpGVKAQ`o7"W1+L!Ta/`%n0k#%E;G:?#L\FVeBqg9D:kOpoE&F&`@%ATk%Q;0cU6"Mk;rK\@XJa>F&P.Ebg*5+SUVr;4;F@NOAMq]'Y3qUJY5Iki)m$e-r;u-NYkfMr]X_@MQ6/?g$h-7IQ]^Cnm@5,t87Z@H9l]ghro'-\!OkHf/TkN.LU%H+f`_3b,8sXNf/,=!(///D0gY(QF%F3YOq,a.&Q))j@Qr"(Odnk"ZeNjg2=c/)?+4_Zn=f0KI(oi)_EV%n"Yn"G!J2iW0U+^KE+Ybd2?k5[Q4"FM1m&i;;4n#j%5CO,R#b0_JF-o;'E0+9oa+?@_T+8H"TYHb-thYWHt&9cT>R\i2PIcm_sFpMWo(dCn@^:BUCb"Wc-(iF$!d(f56SS5dr^!"ceV?WMh+4#LpS''_N?uS*MZ$o>dS;X;<8QI3gl,bbFYFa8B&+VFaaSl7&/)endstream +endobj +89 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1062 +>> +stream +Gasan9lo&K%))O>i0\,R/AEJPPAT$NBm8<6Ro:q]bfIq!9In6FSc&#K]SqdcQNbV%FHmkiD^Z>!UZjXJHuBD$?[EV=erRJ881E="IW8/G'EKkQ"b[b]N[K.e9(/SmQ_JRr4f(6*0hBA^(CZT3=dY2)#"ZuLPCg&W)<^.H)nIuDI8+Q*Hq=0CE4EWp5hOLs>^OE+:.81f0GJJ`R%5Y=,UMq-*]hKT:pZ7D@KFFg:[c#]gS(!1I*RDFm1k$_7S,o>;_0*?1bK(B%tpG)?Qk;p(&2Zjkkbeo:O>s;CB@u'+PT=[g"qAG7UqMImgG10$Q.p$QeVR:k9@1ie;1]BW;:/m(%h0qDc_gI2M:f?30N=P/_RuRnI-GKi)UmrDrGrXe^07L]&/K:8=C,ecZp]+C5JXiM[%g;Y1T+CEXd_;*"_gXT8:g@P!YZ<\K[nW\hT59hr&p8WPtGJ(@>:mr]2n+Z>k(GHEI>F^amqendstream +endobj +90 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1279 +>> +stream +Gatm;9lo&I&A@C2lnQU-0YTc3EU#CGGgaNBPD_*$%*>kF\tu?Fa1o=rOG#$;$J!`$fGY;3fR4:_[hJq%^F]@kPQ7U!S:"k_3+PZiP"<[>i@LJs2'\D9D)DkT'R(0S2?"H&piTVg@YAcq3>eZN&kYIs8kQtNi6`GqB5rD22Jhi?=$pKCJglpB-qG@i%`:!'UdMH6!`=cDJj.D3,WQ5m^6/WElBT,eMTs/YNN_;F^+O:1?Z3!q?4,^a#WYT<(o`:YLj0S,QO1R^pY0Qf`ZkgRsVZ^\nL7t.D5C(JKHQtU^$R'g0I+M'_32Ue$3NN)I9+:%^X&3M#`Qhj;k\_PeN!+\D-V&\gkQOiET30N&]o09n9nl:gW>X8Qf"+PhK.0/Y?.,W7d3aVTGkX5=C9"n/MA_rQHpNK#dlObMCk3-s/kPUCEgD]uP5M)^*/0iGpooAN.H8C#o]fdNG[P9!u6`kqkr[BP":Q@6+k/l*#lB:ofqa6M-9HeR)Yi.CVs2i9OhS,.M"YYc@:-GmOdY>gj54AZ?G+U.itF?G&r`NAi;,ag]I`CZe$-:7*'5r6o.1D!PlLIKq@>=^pl&q_b#:FlT+@[L\USFX4PF+/43dgfF_t6WcsJ&\NnnpA?"*>j8$cYR(b"m.[5X59)GdT)0,P7(gE4).m@7iQ"&gb_RK&5/FA=*l[LPCuTVK1J$;aF&-b]4)/6il5n8f)S3P_s,P](fetn-^fGGsP\hf'\8;bb0mks3UOM31^GoWnBpr8RarL:D5=j8%Gq3[s"9"m^51g*>G`bs'"KrgN:ltbXZVc+q(UoGH)aej_9U<-W`QD8O`GN>*Ho9VJVHX7KL,b3!ZYLGUIAM'EU`2L-1[$ki\Cr]c("i2?oVh.$'5fg$!3F#&_fZoC:BVG5BG^%S:VZS%N`+S<(Engc)[i&fX!&edLjT~>endstream +endobj +91 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 735 +>> +stream +GasIe968f@&AI`dp.-tQ79Vi**D$VjD'j,8D(]'aO:tN.;I_&'^FRtAP<`RZ[\VaX*a0h>dk0SJI1C4a_So&r5Y*[BMCD*"@$pZeop?KJ=9Hc>ND@mMd$;E-CTd^i(e89O&ndSt>!WX%.>GDi[=W*Gejls<]ORh1G_o_]F\+C?0:QV.OPXaDCCm(Lu?'$n&UsZllZ*/[;6qtK>OT^gq!lmLX#fHR#o8fqhn_af-((1sqZdkQM#8E2^O9ta?P2L?U%5:(9BL0qb\G)0NLu&2%e,pUB^0K#pRDY*]1E!KUAJXUHgY\tdr/N0=(i,s1IU2F:QDBtIUhfGFW**>a`K;PPq>'A[8\b2oK]!@$fGC."oL]\76aZ/,A9s3,[$fiURg+K(72?'Ykca[Ft\&f++N\,L8>n(DG&Q+DJ;5k"endstream +endobj +92 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 816 +>> +stream +GasbX>uMXr'Sc)P($C`@P&@ulRnKm;dQ/+OCM,]bX:gi?Ib8IuWP?.p!>29UPT@i,AC#PYkF@2lJe*jUpGKa#%Nd>P:^6_(W#u049/t7E^O%6$1)4+#)*)lb`(k:s2+=Tl!:DkRO'$6u#)PdptadoC<-G:7g5o.=QP&@!-Q>k(ci;Q,W5WC)U$*F^6ksjYj8!YQd.9'>8s5rB_G]o5\YJ.p8a"T`5!K>%-S;W!Qi$sH&!.le//rM_\^?;MlkHQnL*$"PGm2U21;ZI0d[5/dX>drU:@N$e[!b7[2)#i&!%aHM2W@uXQ`C`hhjpG?@bNcGK(e\%VA"kD.%)uS/Q&/kIu:X>ud*nE%LOu\S2=W#e4o`ZqXERfa>21_oT7"?*mUCNo:e#Yqs!?&8d?+0;eTSIVa!1QV@RWZ\q,fhZ0+;ia?PHFR=1\nFd1g:B#@le5.]E>8Q.>pN%`Z>gVqIK&S9_`\sZ]h/Xf6:YpelEh\ea*0;;:!c,(oUK6^Wkq$pn(c00C^tFAZAs?gDG-OT#-VYlq[StJeltDH/4D[SWc*g,Z.f^EpSJISDB&9^lCmO`uZ"7C/Qe;>o26R&_K/X;CoLDp?TBAZ)&`E^jekM9F(G#JmUM"k%2uA_$EJTe!IrBQe#Gfpb_HGOOmF0B@8'T_B7rIma)~>endstream +endobj +93 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 821 +>> +stream +Gat%`9lo#B&;KZOMETB]:omGsa&%qb2UdcGk0V5h!SJmr,F(ujk1=f'#Q^A6M?bt/o"OQV]+Tf'*u]T@'u2MWZV(Xi6(.lj6pQ&%(MW>^O!I])6iflhA6Roin.W_,QX1,aP)++s+P)E@/d52sKcj(W9pIF"L%l&h+'oVgNDM*/;_lR_d(jQ>d%0`jfS\Bs`4'U>u.j&SagJ;8;R]]dOASFouQZ8S@m4q&A%BdDle[O(-K1i^jC7'r4#GD8XXGr_0?n4JLo@:.QchM_\VsR.]frAhfXL%;1!?%?trZ+\[HtgCK\hNqCO%%HY&)es4i`Jh`8Cu,M9';E.ZriaUm1Z:@,HRPOO.C8GROd-qr*5L:>3APJ>eK<&if[:O+s"5fRZ?E:[!9783]t=aJ)h&lU6u!IUGimQM>)E1qU&J5hYWejc^%'n&q+IOo$1Fuc#Lh)jm_+#jKtI^&o_noaa@EH~>endstream +endobj +94 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 814 +>> +stream +GasbX9lo#B&;KZOMETB]:ouCo3g(h(Bep%r2ht-\:(TmOCo=QFe,9'F"WCjNa!BBeRJ=OG31mUmpS$-!W51\3J@Y&<6g*_3\Rph,rHIA;MLu6>%&*Dh]('dpYGO\qK=o;18]O(f,$0([!/YPL5_8q'X6*+?p2_S(nL]0bo9)'N:2(F4C6R$DN)_KSrg*;0?ViB7QtPi7EcuqhBEnOeQJ`-)(hO':hsZ16bA(1"cZ&"Cb,W%opFkUVUG)2f7`8-.W1))`h&hb1PF`YV(hq;t$-!hZa`U2NkRt-qtFRCNYMRGUu',1)`-[VDTt'.%W,0#Ia$Xc?NmH_Ap7?X^Pg(S/?25(L?pnGZU+6E%LOuKrGAd#e9H6Zut?qXMaGG0_S5m4>tKQA,'V_BBSun5ctR!^*_C>ePh)n\85msT:QQ;q\iMTcZ$*'4S`TtI-g2Urgj%&4&\GMm$as63S-8>skaF`R@t'fe@#sbCHo/"jAC:12LB],#=Y"(i6+_Jbd\7rHQbRLmi2,g"$-Wlo?Xo/1U*i.sB)3Xk59]b%pADCRI-S!8u[C!<'/Q\sGkE3oi5MQ1ZqdgW"7uR$Fr%QAGL:E#'VoAR0oXXm'0K-2S^t%m;+ZROC;[l/j0eiDe0CO\f0IA$"NPDWeko;TDITendstream +endobj +95 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 806 +>> +stream +Gasam=]='/&:Vs/fZ04"Wcd$AKQ8n$PX&Ip3kQ<(3!(1$!T=<7'O2O,dhTh27[Bhq99E?drS+**iQ4q\]_VZhT>UR@"u*X!j'8)pTAC!kI*FlArWr&P$atQRiUbI%>C<4Q"Y#R0[U3W#Xb!o)TD+F,nMp;IqT`k1)`.GF49rbQt&9Uh7;d-)Sn($f?Ke*LV`j-R+UD[`:,rC9hDpLVW\GL[HBqIoFl"$e%te<))YK'3tM)*T`H0-OVl^T-H?0esIMq>9e34VGX2X:+<8Z9Q/VYrq)Ao$8%ANA%/<$(V?u("1m:?4Wm0eB's)d,I:s=>l(Z'ii9t'4j=:>P2PlhunPkaEHt],2,Yb]-J.<2AYSt[dl?$/hSV;M%A&c"eFuH%?)'rF?r@8TY8X4tFB$)!Y*pgBYO'**tAt)/r+TMoi:(%2_aLfu[D6hq3RjDZLkPgNkH%QUlh`Utd+'"#ESJ@D[o*2G'DM$/WZ.=tJ@;KLJo_c.r/3<,O2&Op_s8&n#hsgZu,>tQf`Ug34=%F7T!tA<;KuL3Mop^l/\T!*V;endstream +endobj +96 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 804 +>> +stream +GasIe92jS!&AI=/lnN':[GKIHb+i[=&r=`)_o32+&bnY'6)OSVY*9K\'W1E=)Jc2J*kN&=$m1qpG7D>b!M<.::^4lIW#u/!F#YTQ^BZ$^;WS6Vc6Y7J7tj/:=(d.$,UF>gMLd[C81k'&+GCq3DG8S7)5R0=nsJ8F[E;6H`XQF.lSF_,i1(gl*_D>Egffd8H^Gs0E%ObcLEl-@h)t>USZg5Z!fe"5SD0>0VLT'C.bC!ZXfHI;5)an+\qdGkm6:HR5.I#-.+-KRUT^DHY'K@fKONWPq"XJ(q;0!*qC)oWJOeTlT,rT2`m;c!51g(^VpI;4E;eT48gG5KH^GrOg4FHaAS3r,M^jf!bu:-GD'T@.OALMI=Otg^A`6<(gGP!Oj"f?A`o?*Ej>jZP;!99,&eendstream +endobj +97 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 812 +>> +stream +GasbX9iKe#&;KZL'miUlU?^49NhJ_-Q@Y.-*'.=5;&k.';qW@ZN@3:Z+8`eLX<[ua*un]bmA/(;ajMCn_Sa>\K,Ep.MC8LVPZ?8W;k816j(bkOGQZ*lI=J3J=o!?Y7]0*7J]V$6-k-36lQD09pnHg`g,&@m"#_%QrDq\dU86Ei3AoD[WBD#^G3?oF/>jpXUP^)ZFD^`Sr*2YE4KJ2`o0:!QBH?lc4H"ljVLCS)R7MUDL5,q`GiRK/(m.rS'b([fR0S:1lVhfR+Qj.&,a?cI;5DBB8Ig>M11;LMb42)p9,VM=X*q&luH@:f?F)dC.BDe@25c9C:OoM=50$ArEH<(1HSqZR[I0)5/p7J"e)Z7F2t;?<8OfZgaVPhEPKF?YHe+GbIjeZ!:Ls2k`9#s]dsNB+hn&ZXIgZk2O=6VXGh;17-ljdZO#5;lOo.p:&"32g$e]ckRjX)Rc5bl2A\q':'D"A$%pbl`p+#o[P(l1Fj+r?PjW\C_q@-C4plQU+6`Y,7C,91~>endstream +endobj +98 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 806 +>> +stream +Gasam=]='/&:Vs/fZ04"Wcd$AKQ8n$PX&Ip3kQ<(3!(1$!T=<7'O2O,dhTh27[Bhq99E?drS+**iQ4q\]_VZhT>UR@"u*X!j'8)pTAC!kI*FlArWr@X&u]VBfG6;fmc7g2eG_qM@)#l/6pYN1)9$SVMRPd!uV'8.9;:'BA$'3;YE$h+R(6U,7C1M&U*)+b2$"b1Y3$7^cr'fD>3?XX\At^Pqc-C7bj_eREVPWc.4d(./os%?+'-#1<2M(<0'fYVePTFu"RGlq/N2aM)g=R/J`0Xe85H@B't(*.Rc)N=!@Isor"DtnhK&ZJcniqZWU.jPSeJVG\._ID-7qT["(>e!%f.!$o-lqAf(X1-Z.Pk$k!d/+47dQ]n~>endstream +endobj +99 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 804 +>> +stream +GasIe92jS!&AI=/lnN':[GKIHb+i[=&r=`)_o32+&bnY'6)OSVY*9K\'W1E=)Jc2J*kN&=$m1qpG7D>b!M<.::^4lIW#u/!F#YTQ^BZ$^;WS6Vc6Y7J7tj/:=(d.$,UF>gMLd[C81k'&+GCq3DG8S7)5R0=nsJ8F[E;6H`XQF.lSF_,i1(gl*bbHhiJ\CN+]P>O,.9%l<8MY(`kJE+HYoRtq!Ro6"2=^p1b9F5%>C'QE#:jk@#SFYtf/LU$;7pX%Huh1o@g#<-]7-$n9RoMsDf23/c40Pjr1+.jT"hcj2b5K1GrnE@LKdmJ*#pc80!#MVN>'Y:.MY.pGnM<#k1%hg3q>Hk94m-KIB;$HNaH&<9;NT>U"&h:+&bPE*i/=agl]>cR<>Xgg0=M1/e4NI.1$N6bm_SLQ@>F=ep\XuW"QE4]a1U\V1%/\9T"A?hjeOj,Qgm*13AU2Q!s)rZTNoJr5Ii+431;(iS)Rj1AL%A5"[SNa6[gVM:=/"a-AaRiPs3t(WI;d$H]<6V#s8@I=UG@h,>HKLh*DZcs(C5`6[Y;tqMendstream +endobj +100 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 814 +>> +stream +GasbX9lo#B&;KZOMETB]:ouCo3g(h(Bep%r2ht-\:(TmOCo=QFe,9'F"WCjNa!BBeRJ=OG31mUmpS$-!W51\3J@Y&<6g*_3\Rph,rHIA;MLu6>%&*Dh]('dpYGO\qK=o;18]O(f,$0([!/YPL5_8q'X6*+?p2_S(nL]0bo9)'N:2(F4C6R$DN)_KSrg*;0?ViB7TTEi7EcuqhBEnOeQJ`-)(hO':hsZ16bA(1"cZ&"Cb,W%opFkUVUG)2f7`8jW$6l2fu2ZQ*I`J@9jXmVVX-!^'uE4Ca=#r:mrl.f'3t.n5t-7A2J7?9l!r-;*8:@%W'n9SajdoKfOG]>Jn[03&0:H0=pkfnZF8Li)nus$W@_S&9-`JC$WXl=bkam@I0JdH#0!,a7.:IcHbfeJQs.!I8-_[X/?/gE7r_p5!9uUp,/q1TAa0.Gk0*qq:OA5r&al+G,Bk#feldWg%Kjq"e#hu4\X891P"ga1V`$DPTBQ2?HS+&>&ll[KF09O\qXCjMl3o.Z=1roQN:_>$CF\RA_=jD7@l?$0\B-G"7r9NqXL@-&N/=7Z`O79fQ15h=B+.\HqOEPh4Rff.q:0!Pl=f!;^2,F>&QhFi\J$/*ggR[uKKu0IpY(/J7kSi@I=hbIRi:>LU9u9D1Gr+*p??1f8M?e'1=U_Ps3e,,)6pa&p$+gs1UhUlLl2Xendstream +endobj +101 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 806 +>> +stream +Gasam=]='/&:Vs/fZ04"Wcd$AKQ8n$PX&Ip3kQ<(3!(1$!T=<7'O2O,dhTh27[Bhq99E?drS+**iQ4q\]_VZhT>UR@"u*X!j'8)pTAC!kI*FlArWrqJOtUADZK2H.o:oO,`endstream +endobj +102 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 805 +>> +stream +GasIe92jS!&AI=/lnN':[GKIHb+i[=&r=`)_o32+&bnY'6)OSVY*9K\'W1E=)Jc2J*kN&=$m1qpG7D>b!M<.::^4lIW#u/!F#YTQ^BZ$^;WS6Vc6Y7J7tj/:=(d.$,UF>gMLd[C81k'&+GCq3DG8S7)5R0=nsJ8F[E;6H`XQF.lSF_,i1(gl*M!d*Gb5$N)\fRlhM%epkTquQ@sBId-Sg5p458L2^6am/\H^Xj\@!CNpFns@i*)LO%nG3_]6WV44(">>"WT&J34CI?9E>sd>?BkUI2Mi6F:VY_gO8j.I;h"::njj.7UJRn?1Z]W#fF*)naYj0o"Ba2ohui8"-:0c5!9&CN1Z:uIBX0F:SDRHi;1&GPXmFtpFno([0>mMb0Fn7(0)J!R\r-mg.2_;+JAjpZ)jSFbJKZ0[VHk(`auN`NQ''ia`D9*U!QT8,TNn`]S5%qQM]p2A]\\q5%A@0^p)^T5d5pS?*2U&b?_)K;O5qis)45_j=(#`p4qV:0#PlFXDob&=ZAW7A,B6jHb6MbFqn20?.KJpp.oN/f(V)8]^+iAr8/$@1b-t!]%-'IdIB'?G_&[nCg5Q)RCJiHf12<0DFCh5l"kS:`k%4/?D[r3IfVR^584~>endstream +endobj +103 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 824 +>> +stream +Gat=hbBDSn&;KpA`@P^u:p$e#AT"l^4Uh^8(-U>15o9c4;H\Z2:Z%9W"DG(i5$5k:bl?"eOXMLMd.k>Y!D[_232AeWj>3H\#fscs7Gdpl,8lar;a<)jR24F)r2"B2WRlZr,[jq48@9Y)9*$n@+UF8n>np%Z0g:4@K\&V/U(`i3bo#C:6t\bE$D7Q(LA>q$EN>3J.EPJ0<^ZoLjP/nr,Tg<@LWPTSIK9Nf?f,lVL8Pj>UU/;B#KRu057/m0g^^_H'nPWa;j.W2eGn_>U4Hm/$RJbOSJ^Z%E4$AW$5%,VUb=P=HKJ0Ng-@@>$.UFkR1pR'4V14.jqRU;1mhf1GjM'I$Wid/!6\s]6YC4Kstn$;r_9PMVkksZh1[T-?`'/EVRld9hDqi64jrn`P@=hG0[5S9F"p_7ta]im6'/AFQGTO)>p^S4/^*Oqml0e>#uH8!GkD63&_9I$iu^?QF86B4'U\9A$k.iG0s?U3JO0GGrr?j!\(T;q!FqVIb\h\U8l+;tV`77H/NFq>63V8QH:N+hhFa>m!Y0(e\-t?dYalXX=b[)3'_8%l_I2-[%*Xb*kf7b27+?%"lF$nI@0LCs@SqE#[pn0p=2jH];-m`3:BA.T#rpd(,1%E5Kn#[1Q,g97=BRROe6NLU?rk9J(.I2ZW%9-:bGGF&3ocjijST2]%m;,E8lE;&eE2oc_hk)GP+f,6LK_H%h=cOQVMTTeN$`o-al2TWH1-I"M@]@Y!m\t`Nr~>endstream +endobj +104 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 832 +>> +stream +Gat=hbAu;j'Sc?E`ECV_:op-t/ON'4g.XiKc(^D]"2ZJ]P0,+FoCP0YKE+_)`Ig&!jo#/SFVcRD5LKiLNWNn1jaKDL>23g;OWoWKB-hZgc``+Vo5o5("-]@poFcI()F&0nY54LFiPi:u$`$R[Sp6N;DTCIuMElA+BKa1&7oZ5lAQ!28p.-T`OH\ipPrHg`pXm/]A1fgkXBr&%;mfbDlO*L]g7$m6:7#o(f>b=3[Up5U0Y0.]MT,c2gLG'"5g$\(k$in1#e,mU@o&4J?in:C?,o!)d`W#[BYESA[p%nMqm-gb/(U-['(Rgrf7#V%Zrf4']'#`p:=-#lqi2f:fng&/`57LqYXo'L#httUP&!uGkU",cU-KB#86a9LS~>endstream +endobj +105 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 812 +>> +stream +GasbXgN)"%&;KY!MS5gRTNW_d]$.FUbqoRY>]b#H"CW!l87`C1H2=ZH+[D6ZiW0LO]`5b(Y!aGLLW85,)W3H-c^,=oK7!l&&-;SA>i`TU4d&[1Agrh#9;VlQ.=Mti^[rG+PU)3c%$XMDjAJ5P;@(/#c;Xt2?B!2Q$fNs72phq)\7Q.gJ"e_A*!O]@/&QhIZ+/?*&k+R0c>)S#Sm2`N:\*K;&"*87jqf_%dJ/`CEHujb*hIf)5=,8Sq,'uAjE@J]WbiR'WY8mU!M8Z]^Hk9B2q0@;'KpLe&T&YXk_*]8ThGfQaW:^6&9A2+W!Xjh%3GCZo>6ciRC8#bD&Qc+gGY._c<%stMmR-VI2blHfLY#mTeob;Xjnl;iN`1`-'OR%X8tJ?_g_Ap7L:dZY4#V48s1,mP\dW5+"dCT,dpGWH3a)odhV)/qL-J/KY9L+OrSj@N8VKC+mZ0K\!`+&?&Q;7#XMgDU'H4f8I@7HOJ_`D0RN(&K:HH&_cP/b>h\!5*XeTKfF`s"Z5WO8K3dZ>PP=]3+JkZSJtp-j-qIAJ)4P2C03l)?97[fl-Y6lk-5G7,]Rj2]%;XVh0Y]KYhIGA,QUP3u>&^->'iqRd<`rLV%d(I2)6!51'07c9XgW~>endstream +endobj +106 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 812 +>> +stream +GasbXgN)"%&;KY!MS5gRTNW_d]$.FUbqoRY>]b#H"CW!l87`C1H2=ZH+[D6ZiW0M:HN/K0Psce3LW85,)W3H-c^,=oK7!l&&-;SA>i`TU4d&[1Agrh#9;VlQ.=Mti^[rG+PU)3c%$XMDjAJ5P;@(/#c;Xt2?Hg_<$gBN?2q\L1\7Q.'51(5ZNWNn1Pp)`:/8d>N7$10:ZPr\L-We4WPC.WR""$6fq#q171qr!T>b58\LM'uc:QRe-IM>a>[2j!l.0A$KQ6mL#W;k6[6j(U<(TBs#lGQeCJErce2i)/EL3f\YU1[4IU(%5=SPY;$PY%RRfE7fM@SMCaiX*f2^igdeNC*mjbg6RH#,]DVWH%W?m^qZ5L:A^eHYr,NA%2m>&TMM&%iagKUZ_V8`$48I?N;a[h^D2k'sLH-&^0)0WE61^?BA"1ojm^Nn+-Qg2u3DiCA%S2[XJIPcV:oea1F;D<$(c00C^tFAFAs?gDDIJYO:RXlmCoGg_b2RVgC(ec7DZF'>5=<8R(EgaVQuidQ_e???/(Q?cC>!8]jCclZ8AJ!h+<7t(PB=Z8dZ?#981=W(FHP_%S`Z3],8RhC\GN.6,>lo4i+p5%44U@=DFRu9[g;aJ;i6=I9_Z$lecSI=%?'._mA:%kHJ_s!Z$O&FiQ#C:k#eq6>O~>endstream +endobj +107 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 812 +>> +stream +GasbXgN)"%&;KY!MS5gRTNW_d]$.FUbqoRY>]b#H"CW!l87`C1H2=ZH+[D6ZiW0LO]`5b(Y!aGLLW85,)W3H-c^,=oK7!l&&-;SA>i`TU4d&[1Agrh#9;VlQ.=Mti^[rG+PU)3c%$XMDjAJ5P;@(/#c;Xt2?B!2Q$fNs72phq)\7Q.gJ"e_A*!O]@/&QhIZ+/?*&k+R0c>)S#Sm2`N:\*K;&"*87jqf_%dJ/`CEHujb*hIf)5=,8Sq,'uAjE@J]WbiR'WY8mU!Kl^O^Hk9B2q0@;'KpLe&T&YXk_*]8ThGfQaW:^6&9A2+W!Xjh%3GCZo>6ciRC8#bD&Qc+gGY._c<%u*#(4b8q_jhoZ&uud6YWQV>,tST_diL&OjUtT24a!iHguc'=("*#pVnA/%VBAVC]dVri7'a`0_aCEl`-[9J7FEhc:pY+6bp+9V/;+ThH%/b(e1\$m@p^4Et#gBo6+^^"`eI"oei__Xe/d%_I_33kkoH4ff-,jDMj(KiQ8LVjhfbbr&a`'GuI)8oPKSX\q`9[BJ0((0L>;q!FqVIbjMtRV'dA%90#jA9+FLS:k8dQf2/MjnT5OM2N/O61>lt8!Ad?R$sQi0aHNJ6#2:S>@!8nI5G#5-U1W/$[P\$nHVOq_MotqIMOh&%/+uVpnf%E*>38OB!-n5T5^u`JrafD8*r-7QA_e'ZG-Th`An>di;$Loras(B*Ce?Ca1]HKAZJY0KfHX:lM8E2_DCuP::'D(C$&-nn`qg/*FtR#E:!@]l2;+Ho%X7C.q^CN"I%^3M]LbJJ~>endstream +endobj +108 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 825 +>> +stream +Gat=h9lo#B&;KZOMETB]:ol=n3[RR7Bep2!2ht-\:(X)V%k4''$lq.s)Ht[mlN\gDS6^LE6T5mIA/M?*!;i:2[f>$.rc@M9,,J^.]]4hGCD]b4O46k5@FD1OC(9aL80+@7K;@^2#-u+rri-2jO8IM3`R&m&YFcP@h)"9^N4+Ri9R[e?$$+='q0Vg1o=!&h]XlL6qjFX@3S6j!Hb<$C7i_X;9YVj6-25lV.Q%au:%ZCEM_9TX^ZP_&1.X#)kuce%fnaabT@`:6a1i!tlkY@"C3neS8#VSV7ghA&c"e39sDfN05a0Q51q?UoB%(DTWiaSfH+<-SL=Tg$[Y_"9?=\e,k9AaG8<'S[6uaq^6]8p&0@loVNr8H2![kG?>X[AR:TBH1kW_h#q/qZ2@C0D/endstream +endobj +109 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 816 +>> +stream +Gat$u9iKe#&A@7.]OT*7C45p<#R/qh$j>R1k\r85OpLtOAVWtToj'!i,Uj^JO0,[1^$k@C?#`8SoC*f&^e'R4k8[_LT7SSjOC-osn,;[ZPj:;g_,@7$VJ(tR8oXC0=$q$E#oO*r=j48&$5KpG9^&U\&u/ch09H&")2m+oR>>B#"NWgM;D:ZB7)@-\5@7@E@&-Z:dY*ufkhdFg$r2lT_:9i$56q!%N\J,VP>[sDSD=UfI*4_tImAJ@;:`;F@oFk7coIr""m)-MK<&)YOYWnF'aN6NZ(6FY>J[L7U=q)i$^BZ&_?*3)f:-H(U*n>BHTIhP\.&QE42-&kRg9OA#m'Vq/5P`K0#8dP#%`%emu*(+lD<5&?2bEB5i"Nos^Fgc/(CZk@"-2`1\k^m25^>8QD7/]mr&6e?G)@oJ]U&AO1im*qqDd#doXWP5L+)D[H.e/4dK+,(W_=;j,l`E%5(c"-@sfk:.$rFn>lTicD2a^^=*c'C/Q*pfgI-8#X'Mp8nO#XD5TAW"8)nntj%a/o7II1r?f`rTrF+)#>='SK_pCUA%=+&od8m7cQ=Z[aEYlHm;,;ihHPFNKtImSH@Gsq*_:G~>endstream +endobj +110 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 824 +>> +stream +Gat=(9iKe#&A@7.lnN':=Pq[A$FFN8&e^N5_o32+&b-*k*A[-M]2Csd;ReQT=C^`5hqPWPU6+;#j85MO36gCVJc]MF9n?F*,B-ZXdkLXLX$KXH0Wl7+UPRu/5Qt$k_W99K$0,?NcQE\U%8lHTKI,D-#3_\H'F72/Uu70h:Y-:>(ho^9Wf^EfrL9"o_:_C<\G?Bhhh188NaOiXj'5iZSrX(_^LpmrH\C`.TWE4ha2V']U/O`[1og-`BX^2m43cV`m1X`$f(?1l^?$-ek7nEf-_(8HV\ob1S8"])k#/EWLM`m=0JgXur)7FtLakLt\/j@CompH^[T!pf-g:@G\.77TNV:N<,:OW71`63UD'WWRsHjb$464m%JVa6'2Z_"o?+lmp9XPM5P@gQHi9&m5EPqd4R"?/.g_d0-.(\(Nfc0\$gY^;!K.tJ*[b]<2/n(;!Y/OLUj,;WhHZPe[9^)G-_u;RQ@=[API?VPC;mO^X#5Q`s6p?!DF_4_#~>endstream +endobj +111 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 791 +>> +stream +Gas1]92jS!&AI=/lnN(-C;$_o.F=r'8k<1s*A/[9*.]222PfHdGGTtSUsO?qNO@2`O'RT/Je*k0=TpM'i8Zg$arjmg'gt<1!G>R(=-'.VW`0!j\R\1fW:6]no!qhSUa0AR1!iB%aeaLpU_&4$SZ*7!]pPEX)U]S!2VAC0\7#ebI:?(s*!).Q0>`%HTt&'4'2;AabUVg`T3R=M:U8C0GF8@HAS3]In`5FGEBZLSN';[35!X8rfhk#fBKO.%.0@mG8s9Z@RX]8[0u-](Kb>l0:9Eh5#dKTk$8(!"cnB8bjNOSkCP.7r8Z4olb+p^>p&HLlW%%L/FWee>i7M+a_GBJZ[rD(%if8HdgU2C\Dkf+nK:^$N+X5H)YO,.4$O_k7Y(jL[0XT]]QO,Q4KTm[LMha*Y*1N4t,5]BZ*+&;G$2j4!Tc[(M-YolD*X"V8>85MgVP#sY>;gQ1p$1FX/mK<;'Y"fNp84%keN<*R96h6okktYb)*:(~>endstream +endobj +112 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 807 +>> +stream +GasbXgJZc[&;KZF'RQ6'7((=k,nt%A1*n1u(EIB%;&g/iW9fV3Vsd4a+\?+>n\c@3YlDJ1B^m\Q=EZ,[jq4cpeVhV18oK&;8/rXqE(p(nX)4_Af4-d0WIU@17+(@T"Ro(TZJj>XR/@e5k:hG6pm,u@EI'eiIeo4UJF!EVN@uC80>>'\Vucqjba+J*(Q_>POLK@b)j8[Y$[-&O?d\M]]*^G##/`p[bP9C4)Ec(9fB0iS;ue0EbX+=1C:Emp(^uO3rF*22e=_m4nOG^2l*>a:W3?UG#43?1lk.&.[G57Vr[^-_0bH@i8cF*CfaO+8^mpUh19+)$1Yd7Q:7F@6Ai@.O/2Ne.T,ZN]NXLHR?p"l)n<,?5H`auqgL]'jp8Q2]uTo^X%&dI)CDddgr7mA'%,beo*A%"5p$qnkO'T:-2]+k]b]df=@N:IVY^FJAG4QQP)+b9Qjbe*%`??Wi%!%[61aL7)%*ph%\dM5=O-8-App-H[oeooAXK)LT,LE;RI,oY+>g0>j`S-^+:&IPReMUa5tD-se@lBpe\BX66\*7!E/pKkr,pd":$hnMJ]~>endstream +endobj +113 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 805 +>> +stream +GasJP9iKe#&;KZL'miUlU0?I*&IPmZ)$n1Bd,AFH`=_kiPoVXAf6='EOJFRi-e;C_pO2ehPpmu'd@F`b1Bfn:ml9FM\Z.(^&QcQkTfr!OUdCYb,eaDDfj1P>n<`$MnroQc$.nCj:@3j.F6U*!S+.^#rX*S=\UJ^O43g61tT;;,Gs,G,UD"#ZR^hRUhe\q+"Kt""Ya'.&!C#fXf@[:clL3&CL1\rCTGNB20bI%0R?.:kLNf8RX=+"/,j,:4Wr+_'Gel@p]lV-P,TT?7t!@YjKPO=60]*LJgVJO8R!]8tM[utFWV(4F]pm6Xp:9^)?M73;LMUu)I1-j>Jo[k@M#6bYd/_8K<&D=S*BLCF3jV@rmQ&!Jpc6/lVP-VOu1/7'af4a-"4$KnePh-Hh?>19-S,Z4^_Ir^p)LN5d@9#?`hs)laL>u`$hgos3iK:Z6Ag`)^"pO1@JQ3H.a@N!N_f`,1SU&q9c@H.p[_=n++mM?,*HKYeIO$bI^<[j8ZASUeuugF0.?m%NWgq%A++;X*oHI)o:oHpi+_;`LYOiD`To6]sI1&O>l]]hI!P44=C~>endstream +endobj +114 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 784 +>> +stream +GarnU92jS!&AI=/lnN':[GK=D$FFN8&r=`)_o32+&bnY'6`0eXY*9K\1rL&CXHiL+lq.sIHt[i`f)R0YHp4Gn)<B%jK.ggFbBV&Vs1ZRUiAEreE"["_J#V8uRD(EP?W>oLAC%ZtR-?^U^&"1T(kfN=KPYUD@8dPJX'H*Mh3">C!a#%.5(W:#%eb7A#$g:huOX3)H#l@B_GDk`!#IVLTj@FrT9I#qmqO8BqmJ,'hqcVP5]W!:J-hCB*&ui?DKa42.!tNYH&<9;XlP!B&h;9.A]_#[f#jH6TlDoJb@kN%lX_J!#!5j6oTLa28*d/4@!8d9IQCS6ZC7nVeX?IlCb[FO/0Sq5.lG=e=)*e\jXp5`%XA;;HM9endstream +endobj +115 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 812 +>> +stream +Gat$u9iKe#&A@7.lnN(-C4075OVDKX1*mKuc?-Q5U,X@rTX#_>IXP9i#Y>pEN@3:Z]A!#QmB.i_psAfMY5j:pHp";l).YOrJdBFMi%43mmL`0)W`(%/94e=0.K1#dJ*ti0.7k@P)(:[]aeaLpU_&4$XfW3_]bmAm%cIjgf?jmt\7#fm5;=&^7f]@CMr7C_'K6ji;+)pF<^HcJjC34WP)V*/_rSid4+dQmYAZE;kJOXldAJYN#KRr/3smD%h"J!-'nPQ_;j.W22#lJ@@Xr1074Q`A3jGio+S8_(/!O^g6G9C],%jXs8fJI<9L93*:aUn4AG:TeLcGWeW!Xdf%358"^ea84m344>STiZ"=PpZW>NA=a@dCJm[bd]uQjaX4AiireLOcdY_Z`S*'>Q0H#Qf-R-m]8o)>*rIjE&C=kLS=D/IbqKYNA'n?!j2\JSD0J4L4Dqc$9+"mbHjc>L0*77Z2L0BGSN,<;EKKF09RWffiR8n`<[gotP5AWX5.A^lrXNK#JeeMHh2eFtKm+*p>D1f67&l2":T@7"Y;<%';A`N7qWh!B_FV2k@h=d,EDAD_aWn%FfanU]P(^+)ZS~>endstream +endobj +116 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 624 +>> +stream +GarnT968Q9&AJ$ClnNT/6E@SACM=-,%^_)I',O"Mj'WgFS]OQSI90&+-D@ieelZ,CpXg2^Vh++0ZN7S[iVbV8$HSQaMCHVb@$51&1?MCPB7N"AKi^)MH7[9(Ah@\,>Y$*THGd,>$6%8`0qf,DC7&W_^Ao)!HY3!)RGcL$!>Nkn""">).!0$Za$%BB_f_OT=7kegY)5EMoq/Mu*T.O/6Wur7CV?$a`\T81mV-sYj5XFH6CaU.3g+:CS9Du8$O+[TB$k9/%ng2Yj]TT%rgfA)4?PK^(g:Pp!5^do2/OZ#,OLl:mnP/:;O6M$Dn)Hs#.4P5I92T&p_ORjLK=ilUYEBD\%dg3-dTf:WO`6IlUP((mj`-?nA-_A>3;a1#B=[Y]Lr@4-]CCR8,~>endstream +endobj +117 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 642 +>> +stream +GarnT9lnc;&A@sBlnNT/6E>$ECMfoPL)p`O%n-jE)&L^,Yhh&c[=U8LV3oV"9+B+&N%_smGgFSTSI$p^&4#d@4(+3W84$RYGhbsY3?5NP=]2\__>WK?jSH0PI/O,QDj,2E6b&\9QVrgH7aoKVO6%n.be7sq2A**m0!rm@EZ$&%%1g#Sj+l8ML2OV;QR>steJcQ2oib8(*V7/.?EL[uRGOe"UtH'RPNJ1VBnm,-:nWbY(6+&W^D$c$/de3?G:D[GijksThbh&e&CrS_N,W(X',G*N\#q.C;]LDT7dKA39g[_Ji>,:A99<6%!uRn&jpmj^GR\uD$iKmR:"'.N_a+XVt+p4C,QkZnosHc%GC[FsFWS([kkbs?S8F`[NJB>9c#9q)e[g>s^*r&jg(mPW(t4J;HS%e&a_~>endstream +endobj +118 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 625 +>> +stream +GarnT968Q9&AJ$ClnNT/6E@SACM=-,%^_)I',O"Mj5:bnS]OQS4Y&O8P7Xh#23q;?4a)OpBjgdd?NXQrnFdUu"lr%BW0ZgXc)0;a91VfO1_CM&a4VhYuZN`6A/u0(e]jY)Z"`)IW0qf,DC7&W_^Ao)!HY3!)RGcL$!>Nkn""">).(!QEa$%BB_fSG*ccI=he2UAV#hc8<`WijLk^_endstream +endobj +119 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 642 +>> +stream +GarnT9lo#B&A@sBm#blaN!j>&=DsRm>/;,a;G?<2;?aBXibk*0+7c/1Ff@i:6Y]EdO?Q^4(Xd[n/c8+l#l.9<#oiUZpk04&Tfs:lbMs?H##4a.tK5,h?*HgAkFL^`UXlmY!a7TfD'F2-Ck=jIW+o)AHA#9(n4"K?t2o)MC#K'Gs7K4r75pUFAR:$VahXb25VqiZ7)gr?jEj]4p33BL?&g/XN.3!Q1\8_>(!DT0p6FeB8N-IC2O"CV?$5DTBEZGYm_n?D_qO3,s+.lDV7jF4qd)/ef^DR73lZfI\r](0;ALq"kb(:[uq5U?eaQ!!qnXf!L^0:Fs=]kP_Aj9L:aK?hO]'Nl[3RB%U1"?`7$*X&LV\C=[(B[6eWQ+`fTsc%MTms$l$!lNTrcCJW8Wk@k3+2/\>E[-[Ji3e)#%:D/BbAa2U$QG]OG)Vf&YErTr+p]r=rI]j6)mbg3&2EW:Z=8-?.6(8L4r~>endstream +endobj +120 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 624 +>> +stream +GarnT968Q9&AJ$ClnNT/6E@SACM=-,%^_)I',O"Mj'WgFS]OQS4Y%h$P7Xh#23q;?4a)OpBjgddDZHq]G^G@!!qIY1@LDZfR,lqmN&fD-).63Si>'Ul*Xf=K=UQ,c(X`SnhCpOhJd/S[9^%,*)Wk2F0>PR!Ssb"M-Fi\7!6'$JJ4Teb$=+P0EDLSiE833]M-0qUVlRGobuHt+nepSNdsM4,\=\27;VbYTB%(rGni)Z6+MW^\HYo\5,Xi;+Ou+a]U]1R#0b;,UWJiS=FWRPHJKBu_KJG:HaWZFo6^mfI6uTr"Namn/1'r%!Wf_q>+/ke8\Gm>n"0ag3^]+08Q"W8,~>endstream +endobj +121 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 640 +>> +stream +GarnT>BA4X'RnB3302]0eie@ehc^DFG-ltU-XWT!(_!C@@@6$*pZqrq5YNNHA1uj-S42@X@s\/["5Mu,G)UqQncb[q$M$7qjk8OM3Rl%d?qtIq'n$Ns(8`1Z)Dj3%U_."J@9RCLCX>[.TmK-Abd)mT^dWLobQ47@0"hf]la_5T,S?,kAf94\6"7mn\7NsKZ8E%3YOUKEha"o-r$nul]Ua,-'h.I[f!HQ\rZ>Ic4:'!'1.jtmPab/6u-/3Oj%"4-'d4>00C<*HFoO.>qAbK3[&Xq>gkn(Oendstream +endobj +122 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 626 +>> +stream +GarnT968Q9&AJ$CI)jU%#d(1``N>sc"?OmVVC+!N.)@&]i&]>Tr-DC9l6[ZV@r!Wtp3Z.`+F-f[IU<1Y-!oI?8>2Q+[*U4>0e0LoR4-//_EnsI;-rj1q/Me7b8M31;WUrqGq2R+1tF?a$Y9g6VfA[I@"HaL0PVTh[u2"W2U69sEZBJ.s5B@Re3#KDO6TrI-NN68@17'#j,;lEdj+uFOPe/%Np#Sd~>endstream +endobj +123 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 644 +>> +stream +GarnT9lo#B&A@sBm#blaN!j>&=DsRm>/;,a;G?<2;?aBXibk*0+7c/1Ff@i:6Y]EdO?Q^4(Xd[n/c8+l#l.9<#oiUZpk04&Tfs:lbMs?H##4a.tK5,h?*HgAot"^`UXlmY!a7TfD'F2-Ck=jIW+o)AHA#9(n4"K?t2o)MC#K'Gs7K4r75pUFAR:$VahXb25Vql5eqor?jEj]4p33BL?&g/XN.3"iI+<_>(!DT0p6FeB8N-IC2O"CV?$5DTBEZGYm_n?D_qO3,s+.lDV7jF4qd)/ef^DR73lZfI\r](0;ALq"kb(:[uq5U?eaQ!!qnXf!L^0:Fs=]kP_Aj9L:aK?hO]'Nl\1YLTmtH8BJW(Ld#(F3t1PXU>>btWg9.p_R=:C:i)_3:;cmd9S/AUY]VMu+UW6Q2'"!%ZXe?2~>endstream +endobj +124 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 624 +>> +stream +GarnT968Q9&AJ$ClnNT/6E@SACM=-,%^_)I',O"Mj'WgFS]OQS4Y%h$P7Xh#2:gf7Xb=Kh@JYFk!3UBfH]*CUng0r<$M$9GjOp/a3Rl%d?qtIq(%m;&$a]S1$Q9m!dKm)60J0\a#..9%k_#QIk#oP;i$,gHArk4?QX0rjp"VW:OpFTF=2spCQT/qDDOIi,XF\dJe_Tl[.\D1c%.hMR5(PHDcb<#NDQbFol+7K%)ou*B?UU3n[o71MU50i3RMOu3s21n)#N;%L7[_1U%oj]:gB6pMMJ1XN?d^X(=e_d,@tNKWoL+,10o9'Ro:PVFK7qWA5_E+PO9dSpHn!M>fG,5HWap[q='TeupQ&_lY.g[QoY9IEcB+#-Cqmu"#5Dm%Mbf6ld\cif6B3H7s\5Se)#%:kL]((LlM)IGXW0%a([H8Gn+?SK!`Yh_(7ehk,56jf)6-M+Z7@?!i-Unendstream +endobj +125 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 642 +>> +stream +GarnT9lo#B&A@sBm#blaN!j>&=DsRm>/;,a;G?<2;?aBXibk*0+7c/1Ff@i:6Y]EdO?Q^4(Xd[n/c8+l#l.9<#oiUZpk04&Tfs:lbMs?H##4a.tK5,h?*HgAot#^`UXlmY!a7TfD'F2-Ck=jIW+o)AHA#9(n4"K?t2o)MC#K'Gs7K4r75pUFAR:$VahXb25VqqAnX*r?jEj]4p33BL?&g/XN.3%E"sD_>(!DT0p6FeB8N-IC2O"CV?$5DTBEZGYm_n?D_qO3,s+.lDV7jF4qd)/ef^DR70KEh,4noEL$'I^J?TW'Mgk<\rQ%YJ?Y&J9jkRlVkNgZ9g+r&hP,pHQ`S1a%,G5Z-l`~>endstream +endobj +126 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 614 +>> +stream +GarnT92jS!&AJ$ClnN&U1%V`gP'3f<\A6ERJ6SXmp/6ha8ms:'8u>EA^$i+c2_o`$a45%oN7K0ak!,IE?U;AlOD<@.p.@'M?uEOeM,0EI/tsdpWRa0RGcL$!L1pD""">)-o>MZa,XViiOEIE'!i=3*\M=WOG+jL]X=W8CBStdYM'O#bpHN_81Bo;n_N?eZsNhc&3?2\Z@d-O*Jendstream +endobj +127 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 624 +>> +stream +GarnT968Q9&AJ$ClnNUZ6E@T*[5E=HlX_ts`A$HSQaMCHVb@@Ut[1?MCPB7N"AKi^)MH7[9(AIW<`>Y$*THGd,>$J(l8@R:TkC7&W_^Ao)!HY*c@RGcL$!>Nkn""">).(!QE`rj:%_f$@92#;]@(%WOfPKG;;;!4P;!Z4*lISUaP-g[lQL,_iUA8QFMH]F\*:h\r^lj45YUac.m2Neak3KCfhFnMf;6G!VB="UJNU''ufDVE@q;uKseTdA6QkI,^Dh/:]+8$%HXN+CLc/HLiD??eU%nodgM]3'eI4!A`Wf?cPFOJ7A*O$i4._D5ca"$k5<1l@M:CWI`=QNn@HQN->D5HgKnkc-LhjhN0&j*piHmAUYO\M#1Q%q_TGm$Q=BRg]~>endstream +endobj +128 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 900 +>> +stream +Gat$ugJZc[&:Ml+lm(mS_ReHMKE?!O[+l(@@)%6J,79Z$0aB1aJDqCUMp\^?af&1,!g7QFEe.SO^D+u.N%@Ll'#kZ=1fm(c.A-\j"CZ=)gI88:LSZme1Muhq%49NGt!%k]1i9ADD7O(Q(P,7BDJXrjTj2o,D0ff%1(RL?F&B8[8Ia,D_g-7]lI/[;sJDq&rO$R?BgN.4*7A)]\e0MpOo7(icaan#V$RJbO^!Oc7:insOL*bQT8CuBgka>A+V%"/5nq?-R6^\WK-MpIbJXBB7%o%[J7YAaP]kM\3>PDEIY?dpZ@S?B*?(,0Cf=FN^5M+m/%7E46e_m^iSB.XR@!&=*MN+fCLY?;M;cD#LLRHP/hpur5YIP3fAh"8eg6nF7hf[fK$f=#oVZ[LP%P!HRYB_Vq,?F-?XkHR5i5D&+fWpO-mV-Rdg4e!^gN@NuVlkD$h&(H"K.kp^4g/KE6D/+\\0NX&Bl)U+j6sSFQJ/#>^1W7Hlk_t?cFp48%T=flK6Z#&$>.%ifbh(#g0"!Gd2j2aH6YR+Z/1i]&f(8Z:WpKDLu#:>N!!7=Gt8#bYX@8(9jmGWrKCBB!"V'Q9P[MZPP=sO'I*p\=m4TOTK#Nl>]PouD#i=MNMe[k?"C",4_V=A6PF\3$$t=EmeFNL4rJ,]`@[Q,;Q^g@>-GgbE+U/t.BQsccH#K8m(IVs9XT589VLF\nqPA(!!SnkVrQGi$?r5(r.FfUCHD9L)^&Ia8_GeJUNJh4_Z5_J!@EO%-<:-sj\rendstream +endobj +xref +0 129 +0000000000 65535 f +0000000061 00000 n +0000000102 00000 n +0000000209 00000 n +0000000321 00000 n +0000000526 00000 n +0000000731 00000 n +0000000936 00000 n +0000001141 00000 n +0000001346 00000 n +0000001551 00000 n +0000001757 00000 n +0000001963 00000 n +0000002169 00000 n +0000002375 00000 n +0000002581 00000 n +0000002787 00000 n +0000002993 00000 n +0000003199 00000 n +0000003405 00000 n +0000003611 00000 n +0000003817 00000 n +0000004023 00000 n +0000004229 00000 n +0000004435 00000 n +0000004641 00000 n +0000004847 00000 n +0000005053 00000 n +0000005259 00000 n +0000005465 00000 n +0000005671 00000 n +0000005877 00000 n +0000006083 00000 n +0000006289 00000 n +0000006495 00000 n +0000006701 00000 n +0000006907 00000 n +0000007114 00000 n +0000007321 00000 n +0000007528 00000 n +0000007735 00000 n +0000007942 00000 n +0000008149 00000 n +0000008356 00000 n +0000008563 00000 n +0000008770 00000 n +0000008977 00000 n +0000009184 00000 n +0000009391 00000 n +0000009598 00000 n +0000009805 00000 n +0000010012 00000 n +0000010219 00000 n +0000010426 00000 n +0000010633 00000 n +0000010840 00000 n +0000011047 00000 n +0000011254 00000 n +0000011461 00000 n +0000011668 00000 n +0000011875 00000 n +0000012082 00000 n +0000012289 00000 n +0000012496 00000 n +0000012703 00000 n +0000012910 00000 n +0000012980 00000 n +0000013261 00000 n +0000013755 00000 n +0000015318 00000 n +0000016765 00000 n +0000018256 00000 n +0000019737 00000 n +0000021133 00000 n +0000022705 00000 n +0000024262 00000 n +0000025828 00000 n +0000026589 00000 n +0000027903 00000 n +0000028715 00000 n +0000029726 00000 n +0000030857 00000 n +0000032009 00000 n +0000032706 00000 n +0000033859 00000 n +0000035011 00000 n +0000035708 00000 n +0000036860 00000 n +0000038012 00000 n +0000038709 00000 n +0000039863 00000 n +0000041234 00000 n +0000042060 00000 n +0000042967 00000 n +0000043879 00000 n +0000044784 00000 n +0000045681 00000 n +0000046576 00000 n +0000047479 00000 n +0000048376 00000 n +0000049271 00000 n +0000050177 00000 n +0000051075 00000 n +0000051972 00000 n +0000052888 00000 n +0000053812 00000 n +0000054716 00000 n +0000055620 00000 n +0000056524 00000 n +0000057441 00000 n +0000058349 00000 n +0000059265 00000 n +0000060148 00000 n +0000061047 00000 n +0000061944 00000 n +0000062820 00000 n +0000063724 00000 n +0000064440 00000 n +0000065174 00000 n +0000065891 00000 n +0000066625 00000 n +0000067341 00000 n +0000068073 00000 n +0000068791 00000 n +0000069527 00000 n +0000070243 00000 n +0000070977 00000 n +0000071683 00000 n +0000072399 00000 n +trailer +<< +/ID +[] +% ReportLab generated PDF document -- digest (opensource) + +/Info 66 0 R +/Root 65 0 R +/Size 129 +>> +startxref +73391 +%%EOF diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..2e2e2e8a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +Flask==3.1.1 +Flask-Login==0.6.3 +Flask-SQLAlchemy==3.1.1 +psycopg[binary]==3.2.9 +gunicorn==23.0.0 +reportlab==4.4.2 diff --git a/start.command b/start.command new file mode 100755 index 00000000..f13907e0 --- /dev/null +++ b/start.command @@ -0,0 +1,4 @@ +#!/bin/bash +cd "$(dirname "$0")" +docker compose up -d --build +echo "Validation Suite V2: http://localhost:5003" diff --git a/stop.command b/stop.command new file mode 100755 index 00000000..39db4df6 --- /dev/null +++ b/stop.command @@ -0,0 +1,3 @@ +#!/bin/bash +cd "$(dirname "$0")" +docker compose down