lambda-erp 0.1.25__tar.gz → 0.1.27__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/PKG-INFO +1 -1
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/chat.py +15 -3
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/pdf.py +6 -0
- lambda_erp-0.1.27/api/remarks_md.py +91 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/templates/document.html +13 -2
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/pyproject.toml +1 -1
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/.gitignore +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/LICENSE +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/README.md +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/__init__.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/attachments.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/auth.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/bootstrap.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/demo_limits.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/deps.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/errors.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/main.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/providers.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/routers/__init__.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/routers/accounting.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/routers/admin.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/routers/analytics.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/routers/bank_reconciliation.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/routers/documents.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/routers/masters.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/routers/proposals.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/routers/reports.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/routers/setup.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/services.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/api/templates/proposal.html +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/docs/agents/README.md +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/frontend/README.md +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/frontend/src/api/client.ts +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/__init__.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/accounting/__init__.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/accounting/bank_transaction.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/accounting/budget.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/accounting/chart_of_accounts.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/accounting/general_ledger.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/accounting/journal_entry.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/accounting/payment_entry.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/accounting/pos_invoice.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/accounting/purchase_invoice.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/accounting/revaluation.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/accounting/sales_invoice.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/accounting/subscription.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/buying/__init__.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/buying/purchase_order.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/controllers/__init__.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/controllers/currency.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/controllers/defaults.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/controllers/pricing_rule.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/controllers/taxes_and_totals.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/database.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/exceptions.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/hooks.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/model.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/selling/__init__.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/selling/proposal.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/selling/quotation.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/selling/sales_order.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/simulation.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/stock/__init__.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/stock/delivery_note.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/stock/purchase_receipt.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/stock/stock_entry.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/stock/stock_ledger.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/lambda_erp/utils.py +0 -0
- {lambda_erp-0.1.25 → lambda_erp-0.1.27}/terraform/README.md +0 -0
|
@@ -603,7 +603,7 @@ TOOLS = [
|
|
|
603
603
|
"type": "function",
|
|
604
604
|
"function": {
|
|
605
605
|
"name": "get_master_fields",
|
|
606
|
-
"description": "List the available columns of a master type (customer, supplier, item, ...). Call this
|
|
606
|
+
"description": "List the available columns of a master type (customer, supplier, item, ...). Call this WHENEVER you're unsure which columns exist: before passing `fields` to search_masters, and before building a `data` payload for create_master/update_master when you're not certain a field exists or where a value belongs (e.g. a contact person, a tax id, a payment term). It lets you target real fields instead of guessing — or wrongly concluding a value can't be stored. Returns: `fields` (all columns), `default_search_fields` (what search_masters searches when `fields` is omitted), and `bulk_text_fields` (large text columns searched only when named in `fields`).",
|
|
607
607
|
"parameters": {
|
|
608
608
|
"type": "object",
|
|
609
609
|
"properties": {
|
|
@@ -628,8 +628,10 @@ TOOLS = [
|
|
|
628
628
|
"**Account fields:** name (REQUIRED — full account id, conventionally \"<account_name> - <company abbr>\", e.g. \"Marketing Expenses - LAMB\"), account_name (required), company (required), root_type (Asset/Liability/Equity/Income/Expense), report_type (\"Balance Sheet\" or \"Profit and Loss\"), account_type (e.g. Receivable, Payable, Bank, Cash, Stock, Tax), parent_account, account_currency, is_group (0/1).\n"
|
|
629
629
|
"**Cost Center fields:** name (REQUIRED — e.g. \"Marketing - LAMB\"), cost_center_name (required), company (required), parent_cost_center, is_group (0/1).\n\n"
|
|
630
630
|
"zip_code is free text (e.g. \"8400\", \"ZH 8400\", \"59123\"), never numeric.\n"
|
|
631
|
+
"When the user names a contact person at a customer (e.g. \"Kontakt/Ansprechpartner ist Marlene Voss, 079 123 45 67\"), put the person's name in contact_person and their phone/email in contact_phone/contact_email — NOT in the company-level phone/email. There is no separate contact tool; contact-person data lives on these Customer columns, so never claim you cannot store a contact person.\n"
|
|
631
632
|
"Supplier example: {\"master_type\":\"supplier\",\"data\":{\"supplier_name\":\"Schlafteq\",\"email\":\"jacob@schlafteq.ch\",\"phone\":\"+1 555-0104\",\"address\":\"145 Harbor Rd\",\"city\":\"Seattle\",\"zip_code\":\"98101\",\"country\":\"US\",\"tax_id\":\"98-7654321\"}}\n"
|
|
632
|
-
"Item example (custom code): {\"master_type\":\"item\",\"data\":{\"item_code\":\"SVC-SPARK\",\"item_name\":\"Spark\",\"item_group\":\"Services\",\"is_stock_item\":0,\"standard_rate\":310}}"
|
|
633
|
+
"Item example (custom code): {\"master_type\":\"item\",\"data\":{\"item_code\":\"SVC-SPARK\",\"item_name\":\"Spark\",\"item_group\":\"Services\",\"is_stock_item\":0,\"standard_rate\":310}}\n"
|
|
634
|
+
"Customer example (with contact person): {\"master_type\":\"customer\",\"data\":{\"customer_name\":\"Foglio AG\",\"address\":\"Seeweg 12\",\"city\":\"Bramblewick\",\"zip_code\":\"9999\",\"contact_person\":\"Marlene Voss\",\"contact_phone\":\"079 123 45 67\"}}"
|
|
633
635
|
),
|
|
634
636
|
"parameters": {
|
|
635
637
|
"type": "object",
|
|
@@ -1268,7 +1270,8 @@ def _handle_create_master(args):
|
|
|
1268
1270
|
if ignored:
|
|
1269
1271
|
result["_warning"] = (
|
|
1270
1272
|
f"These fields were IGNORED because they are not valid columns on the {master_type}: "
|
|
1271
|
-
f"{ignored}.
|
|
1273
|
+
f"{ignored}. Call get_master_fields(master_type=\"{master_type}\") to see the real columns, "
|
|
1274
|
+
f"then retry mapping those values onto valid field names."
|
|
1272
1275
|
)
|
|
1273
1276
|
return result
|
|
1274
1277
|
|
|
@@ -1705,6 +1708,14 @@ Shape — note it does NOT use `items`:
|
|
|
1705
1708
|
|
|
1706
1709
|
To build one: ensure each offer already exists as its own Quotation (create them first if needed), then call create_document with doctype "proposal" and a data object whose `quotations` array references those quotations by name. Do NOT submit it; link the user to the PDF at `/api/documents/proposal/<name>/pdf` (and the editor at `/app/proposal/<name>`).
|
|
1707
1710
|
|
|
1711
|
+
### Notes / Terms markup (the `remarks` field)
|
|
1712
|
+
The `remarks` (Notes / Terms) field on quotations, sales orders, and invoices renders on the PDF with a small markup vocabulary, so when a user dictates offer notes, conditions, recurring services, or a sign-off you can compose a polished closing block instead of a flat paragraph. Put this ONLY in `remarks` (never in item descriptions):
|
|
1713
|
+
- `# Heading` at the start of a line -> bold heading
|
|
1714
|
+
- `*italic*` or `_italic_` -> italic; `**bold**` -> bold
|
|
1715
|
+
- `>> Period | Amount` at the start of a line -> a right-aligned price line that sits beside the heading/description above it; use it for separately- or recurring-billed items, e.g. `>> Monatlich | CHF 380.—`
|
|
1716
|
+
- Separate blocks with a blank line; a single newline is just a line break.
|
|
1717
|
+
Plain text (no special characters) still renders fine, so only reach for the markup when it improves a customer-facing note.
|
|
1718
|
+
|
|
1708
1719
|
### Purchase Cycle
|
|
1709
1720
|
Purchase Order → Purchase Receipt (receiving) / Purchase Invoice (billing) → Payment Entry
|
|
1710
1721
|
|
|
@@ -1863,6 +1874,7 @@ If the user refers to something by its human name ("bill them 8 hours of project
|
|
|
1863
1874
|
- Same for customers, suppliers, warehouses, etc. — `search_masters` is **case-insensitive** and falls back to **fuzzy matching for misspellings**, so a typo'd name ("Meynex") still resolves. Trust its results instead of concluding "not found" after one narrow try.
|
|
1864
1875
|
- **Prefer narrowing with `fields`** whenever you know the attribute: search a customer by city with `fields=["city"]`, by email with `fields=["contact_email"]`, etc. It's faster and avoids false matches from unrelated columns. Omitting `fields` searches all standard text fields (a good fallback when you're unsure where the value lives), but large free-text columns (e.g. item `description`) are only searched when you name them explicitly in `fields`.
|
|
1865
1876
|
- **Don't guess column names** — call `get_master_fields(master_type=...)` first to see the real columns (and which are searched by default), then pass the exact names to `search_masters` `fields`. This also tells you which large text fields (like `description`) you must name explicitly to search.
|
|
1877
|
+
- **When unsure where a value belongs, discover the schema — don't guess or give up.** Before a `create_master`/`update_master` where you're not certain a field exists or which column fits (the user gives a contact person, a VAT/tax id, a payment term, an IBAN, …), call `get_master_fields(master_type=...)` and map the value onto the real column. Never tell the user you can't store something without checking the fields first — the master usually has a column for it (e.g. a customer's contact person goes in `contact_person`/`contact_phone`/`contact_email`, not the company-level `phone`/`email`).
|
|
1866
1878
|
|
|
1867
1879
|
When you list masters back to the user (items on an invoice, customers on a report), include the key in parentheses so follow-ups are unambiguous. Example: "Project Management (SVC-005) — 16 Hour".
|
|
1868
1880
|
|
|
@@ -6,6 +6,7 @@ from jinja2 import Environment, FileSystemLoader, ChoiceLoader
|
|
|
6
6
|
from weasyprint import HTML
|
|
7
7
|
from lambda_erp.database import get_db
|
|
8
8
|
from api.services import load_document
|
|
9
|
+
from api.remarks_md import render_remarks
|
|
9
10
|
|
|
10
11
|
TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), "templates")
|
|
11
12
|
|
|
@@ -201,6 +202,11 @@ def generate_pdf(doctype_slug: str, name: str) -> bytes:
|
|
|
201
202
|
taxes=taxes,
|
|
202
203
|
show_warehouse=doctype in SHOW_WAREHOUSE,
|
|
203
204
|
page_size=page_size,
|
|
205
|
+
# Notes / Terms rendered from a small markup subset (headings, bold/
|
|
206
|
+
# italic, right-aligned price lines) into safe HTML; templates style the
|
|
207
|
+
# emitted classes. Falls back to plain `doc.remarks` if a template
|
|
208
|
+
# doesn't use it. See api/remarks_md.py.
|
|
209
|
+
remarks_html=render_remarks(doc.get("remarks")),
|
|
204
210
|
)
|
|
205
211
|
|
|
206
212
|
# Let deployment plugins augment the context (e.g. a Swiss QR-bill image for
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Lightweight markup for the Notes / Terms (`remarks`) block on documents.
|
|
2
|
+
|
|
3
|
+
`remarks` is free text the user types on a document (quotation, sales order,
|
|
4
|
+
invoice, …), but on the PDF it often wants to read like a real offer: italic
|
|
5
|
+
asides, bold service headings, and a right-aligned recurring-price line beside a
|
|
6
|
+
description. Rather than pulling in a full Markdown dependency we support a tiny,
|
|
7
|
+
predictable subset and render it to **safe** HTML. `generate_pdf()` exposes the
|
|
8
|
+
result as `remarks_html`; templates render it with `| safe` and style the emitted
|
|
9
|
+
class names (`.rm-block`, `.rm-h`, `.rm-p`, `.rm-amt`) however they like — so a
|
|
10
|
+
branded template can restyle the same markup without changing this converter.
|
|
11
|
+
|
|
12
|
+
Syntax (authored in the same textarea, also what the chat assistant emits):
|
|
13
|
+
blank line -> separates blocks (a float stays beside its block)
|
|
14
|
+
# Heading -> bold heading line (leading #'s stripped)
|
|
15
|
+
*italic* _italic_ -> italic
|
|
16
|
+
**bold** -> bold
|
|
17
|
+
>> Monatlich | CHF 380.— -> right-aligned price box (period over amount),
|
|
18
|
+
floated beside the block's heading/description
|
|
19
|
+
Everything is HTML-escaped first, so user text can't inject markup.
|
|
20
|
+
"""
|
|
21
|
+
import html
|
|
22
|
+
import re
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _inline(text):
|
|
26
|
+
"""Escape, then apply inline **bold** / *italic* / _italic_."""
|
|
27
|
+
out = html.escape(text)
|
|
28
|
+
out = re.sub(r"\*\*(.+?)\*\*", r"<strong>\1</strong>", out)
|
|
29
|
+
out = re.sub(r"\*(.+?)\*", r"<em>\1</em>", out)
|
|
30
|
+
out = re.sub(r"_(.+?)_", r"<em>\1</em>", out)
|
|
31
|
+
return out
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _price(line):
|
|
35
|
+
"""`>> period | amount` -> a right-floated box with period over amount."""
|
|
36
|
+
body = line.lstrip()[2:].strip() # drop the leading '>>'
|
|
37
|
+
if "|" in body:
|
|
38
|
+
period, amount = (p.strip() for p in body.split("|", 1))
|
|
39
|
+
else:
|
|
40
|
+
period, amount = "", body
|
|
41
|
+
parts = []
|
|
42
|
+
if period:
|
|
43
|
+
parts.append(f'<div class="rm-amt-period">{_inline(period)}</div>')
|
|
44
|
+
if amount:
|
|
45
|
+
parts.append(f'<div class="rm-amt-val">{_inline(amount)}</div>')
|
|
46
|
+
return f'<div class="rm-amt">{"".join(parts)}</div>'
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _block(lines):
|
|
50
|
+
"""Render one block (lines between blank lines) to HTML.
|
|
51
|
+
|
|
52
|
+
Price line(s) are emitted first and floated right so they sit beside the
|
|
53
|
+
heading/description that follow, matching a typical offer layout.
|
|
54
|
+
"""
|
|
55
|
+
price_html = ""
|
|
56
|
+
body = ""
|
|
57
|
+
para = []
|
|
58
|
+
|
|
59
|
+
def flush_para():
|
|
60
|
+
nonlocal body, para
|
|
61
|
+
if para:
|
|
62
|
+
body += '<div class="rm-p">' + "<br>".join(_inline(p) for p in para) + "</div>"
|
|
63
|
+
para = []
|
|
64
|
+
|
|
65
|
+
for raw in lines:
|
|
66
|
+
stripped = raw.lstrip()
|
|
67
|
+
if stripped.startswith(">>"):
|
|
68
|
+
flush_para()
|
|
69
|
+
price_html += _price(raw)
|
|
70
|
+
elif stripped.startswith("#"):
|
|
71
|
+
flush_para()
|
|
72
|
+
heading = stripped.lstrip("#").strip()
|
|
73
|
+
body += f'<div class="rm-h">{_inline(heading)}</div>'
|
|
74
|
+
else:
|
|
75
|
+
para.append(raw)
|
|
76
|
+
flush_para()
|
|
77
|
+
return f'<div class="rm-block">{price_html}{body}</div>'
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def render_remarks(text):
|
|
81
|
+
"""Convert the remarks free text to safe styled HTML (or '' if empty)."""
|
|
82
|
+
if not text or not text.strip():
|
|
83
|
+
return ""
|
|
84
|
+
text = text.replace("\r\n", "\n").replace("\r", "\n")
|
|
85
|
+
blocks = []
|
|
86
|
+
for raw_block in re.split(r"\n[ \t]*\n", text):
|
|
87
|
+
lines = raw_block.split("\n")
|
|
88
|
+
if not any(l.strip() for l in lines):
|
|
89
|
+
continue
|
|
90
|
+
blocks.append(_block(lines))
|
|
91
|
+
return "".join(blocks)
|
|
@@ -48,6 +48,15 @@
|
|
|
48
48
|
|
|
49
49
|
.footer { margin-top: 30px; padding-top: 10px; border-top: 1px solid #e5e7eb; font-size: 7.5pt; color: #999; text-align: center; }
|
|
50
50
|
.remarks { margin-top: 15px; padding: 8px; background: #fefce8; border-radius: 4px; font-size: 8pt; color: #713f12; }
|
|
51
|
+
/* Structured notes (remarks_html). A template can restyle these freely. */
|
|
52
|
+
.remarks .rm-block { overflow: hidden; margin-bottom: 8px; }
|
|
53
|
+
.remarks .rm-block:last-child { margin-bottom: 0; }
|
|
54
|
+
.remarks .rm-h { font-weight: 700; }
|
|
55
|
+
.remarks .rm-h + .rm-p, .remarks .rm-p + .rm-p { margin-top: 2px; }
|
|
56
|
+
.remarks .rm-amt { float: right; text-align: right; margin: 0 0 4px 16px; }
|
|
57
|
+
.remarks .rm-amt-val { white-space: nowrap; }
|
|
58
|
+
.remarks em { font-style: italic; }
|
|
59
|
+
.remarks strong { font-weight: 700; }
|
|
51
60
|
</style>
|
|
52
61
|
</head>
|
|
53
62
|
<body>
|
|
@@ -182,8 +191,10 @@
|
|
|
182
191
|
</div>
|
|
183
192
|
|
|
184
193
|
{# ---- Remarks ---- #}
|
|
185
|
-
{% if
|
|
186
|
-
<div class="remarks">
|
|
194
|
+
{% if remarks_html is defined and remarks_html %}
|
|
195
|
+
<div class="remarks">{{ remarks_html | safe }}</div>
|
|
196
|
+
{% elif doc.remarks %}
|
|
197
|
+
<div class="remarks" style="white-space: pre-line;">
|
|
187
198
|
<strong>Remarks:</strong> {{ doc.remarks }}
|
|
188
199
|
</div>
|
|
189
200
|
{% endif %}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|