lambda-erp 0.7.1__tar.gz → 0.8.0__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.7.1 → lambda_erp-0.8.0}/PKG-INFO +1 -1
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/main.py +2 -1
- lambda_erp-0.8.0/api/routers/availability.py +154 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/frontend/src/api/client.ts +57 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/pyproject.toml +1 -1
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/.gitignore +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/LICENSE +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/README.md +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/__init__.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/attachments.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/auth.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/bootstrap.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/chat.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/demo_limits.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/deps.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/errors.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/oauth.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/pdf.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/providers.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/remarks_md.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/routers/__init__.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/routers/accounting.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/routers/admin.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/routers/analytics.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/routers/bank_reconciliation.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/routers/chat_api.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/routers/documents.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/routers/masters.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/routers/mcp.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/routers/proposals.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/routers/reports.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/routers/setup.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/services.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/templates/document.html +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/api/templates/proposal.html +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/docs/agents/README.md +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/frontend/LICENSE +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/frontend/README.md +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/__init__.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/__init__.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/bank_transaction.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/budget.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/chart_of_accounts.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/general_ledger.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/journal_entry.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/payment_entry.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/pos_invoice.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/purchase_invoice.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/revaluation.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/sales_invoice.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/setup/__init__.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/setup/engine.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/setup/pack.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/setup/packs/__init__.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/setup/packs/ch.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/setup/packs/de_common.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/setup/packs/de_skr03.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/setup/packs/de_skr04.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/setup/packs/generic.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/setup/profiles.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/setup/spine.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/accounting/subscription.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/assets/__init__.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/assets/asset.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/assets/reservation.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/buying/__init__.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/buying/purchase_order.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/controllers/__init__.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/controllers/currency.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/controllers/defaults.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/controllers/pricing_rule.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/controllers/taxes_and_totals.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/database.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/exceptions.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/hooks.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/model.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/selling/__init__.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/selling/proposal.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/selling/quotation.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/selling/sales_order.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/simulation.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/stock/__init__.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/stock/delivery_note.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/stock/purchase_receipt.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/stock/stock_entry.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/stock/stock_ledger.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/lambda_erp/utils.py +0 -0
- {lambda_erp-0.7.1 → lambda_erp-0.8.0}/terraform/README.md +0 -0
|
@@ -19,7 +19,7 @@ from api.auth import router as auth_router, COOKIE_NAME, decode_token
|
|
|
19
19
|
from api.oauth import router as oauth_router
|
|
20
20
|
from api.attachments import router as attachments_router
|
|
21
21
|
from api.chat import chat_websocket, router as chat_router
|
|
22
|
-
from api.routers import admin, documents, masters, reports, setup as setup_router, bank_reconciliation, analytics, accounting, proposals, chat_api, mcp
|
|
22
|
+
from api.routers import admin, documents, masters, reports, setup as setup_router, bank_reconciliation, analytics, accounting, proposals, chat_api, mcp, availability
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
def load_plugins() -> None:
|
|
@@ -106,6 +106,7 @@ app.include_router(attachments_router, prefix="/api")
|
|
|
106
106
|
app.include_router(documents.router, prefix="/api")
|
|
107
107
|
app.include_router(proposals.router, prefix="/api")
|
|
108
108
|
app.include_router(masters.router, prefix="/api")
|
|
109
|
+
app.include_router(availability.router, prefix="/api")
|
|
109
110
|
app.include_router(reports.router, prefix="/api")
|
|
110
111
|
app.include_router(analytics.router, prefix="/api")
|
|
111
112
|
app.include_router(setup_router.router, prefix="/api")
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Rental availability endpoint.
|
|
2
|
+
|
|
3
|
+
Exposes the Reservation availability engine (lambda_erp/assets/reservation.py)
|
|
4
|
+
over REST so the booking form can check "is this free?" before saving and the
|
|
5
|
+
fleet calendar can render free vs booked. Read-only — posts nothing.
|
|
6
|
+
|
|
7
|
+
See docs/RENTAL_UI_PLAN.md (Phase 1). The overlap rule itself lives in one
|
|
8
|
+
place (reservation.overlapping_reservations); this router only surfaces it.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from fastapi import APIRouter, Depends, Query, HTTPException
|
|
12
|
+
|
|
13
|
+
from lambda_erp.database import get_db
|
|
14
|
+
from lambda_erp.exceptions import ValidationError
|
|
15
|
+
from lambda_erp.assets.reservation import (
|
|
16
|
+
pool_capacity,
|
|
17
|
+
committed_qty,
|
|
18
|
+
available_qty,
|
|
19
|
+
available_assets,
|
|
20
|
+
overlapping_reservations,
|
|
21
|
+
)
|
|
22
|
+
from api.auth import require_role
|
|
23
|
+
|
|
24
|
+
router = APIRouter(
|
|
25
|
+
prefix="/availability",
|
|
26
|
+
tags=["availability"],
|
|
27
|
+
dependencies=[Depends(require_role("viewer"))],
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@router.get("")
|
|
32
|
+
def check_availability(
|
|
33
|
+
item_code: str = Query(..., description="Item (machine type) to check."),
|
|
34
|
+
from_datetime: str = Query(..., alias="from", description="Window start (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)."),
|
|
35
|
+
to_datetime: str = Query(..., alias="to", description="Window end; half-open [from, to)."),
|
|
36
|
+
warehouse: str | None = Query(None, description="Optional yard/warehouse to scope the pool."),
|
|
37
|
+
exclude: str | None = Query(None, description="Reservation name to ignore (editing an existing hire)."),
|
|
38
|
+
):
|
|
39
|
+
"""Availability of an item over a window: total pool, how many are committed,
|
|
40
|
+
how many are free, and which specific units are pickable.
|
|
41
|
+
|
|
42
|
+
- `available_qty` counts free capacity (pooled + pinned commitments both
|
|
43
|
+
reduce it).
|
|
44
|
+
- `available_assets` are the units with no overlapping commitment of their
|
|
45
|
+
own — what dispatch assigns from. A unit can be absent from this list yet
|
|
46
|
+
`available_qty` still be > 0 (a pooled booking reduced the count without
|
|
47
|
+
naming a unit); the form should respect both.
|
|
48
|
+
"""
|
|
49
|
+
db = get_db()
|
|
50
|
+
try:
|
|
51
|
+
capacity = pool_capacity(db, item_code, warehouse)
|
|
52
|
+
committed = committed_qty(db, item_code, warehouse, from_datetime, to_datetime, exclude)
|
|
53
|
+
avail_qty = available_qty(db, item_code, warehouse, from_datetime, to_datetime, exclude)
|
|
54
|
+
units = available_assets(db, item_code, warehouse, from_datetime, to_datetime, exclude)
|
|
55
|
+
overlap = overlapping_reservations(
|
|
56
|
+
db, from_dt=from_datetime, to_dt=to_datetime,
|
|
57
|
+
item_code=item_code, warehouse=warehouse, exclude=exclude,
|
|
58
|
+
)
|
|
59
|
+
except ValidationError as e:
|
|
60
|
+
raise HTTPException(status_code=422, detail=str(e))
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
"item_code": item_code,
|
|
64
|
+
"warehouse": warehouse,
|
|
65
|
+
"from": from_datetime,
|
|
66
|
+
"to": to_datetime,
|
|
67
|
+
"capacity": capacity,
|
|
68
|
+
"committed": committed,
|
|
69
|
+
"available_qty": avail_qty,
|
|
70
|
+
"available": avail_qty > 0,
|
|
71
|
+
"available_assets": [
|
|
72
|
+
{
|
|
73
|
+
"name": a.get("name"),
|
|
74
|
+
"asset_tag": a.get("asset_tag"),
|
|
75
|
+
"warehouse": a.get("warehouse"),
|
|
76
|
+
"status": a.get("status"),
|
|
77
|
+
"meter_reading": a.get("meter_reading"),
|
|
78
|
+
}
|
|
79
|
+
for a in units
|
|
80
|
+
],
|
|
81
|
+
"overlapping": overlap,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@router.get("/calendar")
|
|
86
|
+
def calendar_feed(
|
|
87
|
+
from_datetime: str = Query(..., alias="from", description="Window start (YYYY-MM-DD or with time)."),
|
|
88
|
+
to_datetime: str = Query(..., alias="to", description="Window end; half-open [from, to)."),
|
|
89
|
+
warehouse: str | None = Query(None, description="Optional yard/warehouse to scope both lanes and bars."),
|
|
90
|
+
item_code: str | None = Query(None, description="Optional item (machine type) to scope to."),
|
|
91
|
+
):
|
|
92
|
+
"""Feed for the fleet availability timeline: the asset lanes (rows) plus the
|
|
93
|
+
reservations that occupy them within the window (bars).
|
|
94
|
+
|
|
95
|
+
- `assets` are the active, non-retired units (optionally scoped by yard /
|
|
96
|
+
item) — the timeline's Y axis.
|
|
97
|
+
- `reservations` are the blocking hires overlapping [from, to) — the bars —
|
|
98
|
+
via the single canonical overlap rule (overlapping_reservations), enriched
|
|
99
|
+
with the party for a bar label. Pooled bookings (no `asset`) carry a null
|
|
100
|
+
`asset`; the caller renders them on an item lane or a "pool" row.
|
|
101
|
+
"""
|
|
102
|
+
db = get_db()
|
|
103
|
+
|
|
104
|
+
asset_filters: dict = {"disabled": 0}
|
|
105
|
+
if warehouse:
|
|
106
|
+
asset_filters["warehouse"] = warehouse
|
|
107
|
+
if item_code:
|
|
108
|
+
asset_filters["item_code"] = item_code
|
|
109
|
+
assets = [
|
|
110
|
+
{
|
|
111
|
+
"name": a.get("name"),
|
|
112
|
+
"asset_tag": a.get("asset_tag"),
|
|
113
|
+
"item_code": a.get("item_code"),
|
|
114
|
+
"warehouse": a.get("warehouse"),
|
|
115
|
+
"status": a.get("status"),
|
|
116
|
+
"meter_reading": a.get("meter_reading"),
|
|
117
|
+
}
|
|
118
|
+
for a in db.get_all("Asset", filters=asset_filters, fields=["*"], order_by="item_code, asset_tag")
|
|
119
|
+
if a.get("status") != "Retired"
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
rows = overlapping_reservations(
|
|
124
|
+
db, from_dt=from_datetime, to_dt=to_datetime,
|
|
125
|
+
item_code=item_code, warehouse=warehouse,
|
|
126
|
+
)
|
|
127
|
+
except ValidationError as e:
|
|
128
|
+
raise HTTPException(status_code=422, detail=str(e))
|
|
129
|
+
|
|
130
|
+
reservations = []
|
|
131
|
+
for r in rows:
|
|
132
|
+
extra = db.get_value("Reservation", r["name"], ["party_type", "party", "purpose"]) or {}
|
|
133
|
+
reservations.append({
|
|
134
|
+
"name": r.get("name"),
|
|
135
|
+
"item_code": r.get("item_code"),
|
|
136
|
+
"asset": r.get("asset"),
|
|
137
|
+
"warehouse": r.get("warehouse"),
|
|
138
|
+
"qty": r.get("qty"),
|
|
139
|
+
"from_datetime": r.get("from_datetime"),
|
|
140
|
+
"to_datetime": r.get("to_datetime"),
|
|
141
|
+
"status": r.get("status"),
|
|
142
|
+
"party_type": extra.get("party_type"),
|
|
143
|
+
"party": extra.get("party"),
|
|
144
|
+
"purpose": extra.get("purpose"),
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
"from": from_datetime,
|
|
149
|
+
"to": to_datetime,
|
|
150
|
+
"warehouse": warehouse,
|
|
151
|
+
"item_code": item_code,
|
|
152
|
+
"assets": assets,
|
|
153
|
+
"reservations": reservations,
|
|
154
|
+
}
|
|
@@ -70,6 +70,56 @@ function qs(params?: Record<string, string | number | undefined>) {
|
|
|
70
70
|
return s ? `?${s}` : "";
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// --- Rental types (asset availability + fleet calendar feed) ---
|
|
74
|
+
export interface AvailabilityAsset {
|
|
75
|
+
name: string;
|
|
76
|
+
asset_tag: string | null;
|
|
77
|
+
warehouse: string | null;
|
|
78
|
+
status: string | null;
|
|
79
|
+
meter_reading: number | null;
|
|
80
|
+
}
|
|
81
|
+
export interface AvailabilityResult {
|
|
82
|
+
item_code: string;
|
|
83
|
+
warehouse: string | null;
|
|
84
|
+
from: string;
|
|
85
|
+
to: string;
|
|
86
|
+
capacity: number;
|
|
87
|
+
committed: number;
|
|
88
|
+
available_qty: number;
|
|
89
|
+
available: boolean;
|
|
90
|
+
available_assets: AvailabilityAsset[];
|
|
91
|
+
overlapping: unknown[];
|
|
92
|
+
}
|
|
93
|
+
export interface CalendarAsset {
|
|
94
|
+
name: string;
|
|
95
|
+
asset_tag: string | null;
|
|
96
|
+
item_code: string | null;
|
|
97
|
+
warehouse: string | null;
|
|
98
|
+
status: string | null;
|
|
99
|
+
meter_reading: number | null;
|
|
100
|
+
}
|
|
101
|
+
export interface CalendarReservation {
|
|
102
|
+
name: string;
|
|
103
|
+
item_code: string | null;
|
|
104
|
+
asset: string | null;
|
|
105
|
+
warehouse: string | null;
|
|
106
|
+
qty: number | null;
|
|
107
|
+
from_datetime: string;
|
|
108
|
+
to_datetime: string;
|
|
109
|
+
status: string | null;
|
|
110
|
+
party_type: string | null;
|
|
111
|
+
party: string | null;
|
|
112
|
+
purpose: string | null;
|
|
113
|
+
}
|
|
114
|
+
export interface FleetCalendarFeed {
|
|
115
|
+
from: string;
|
|
116
|
+
to: string;
|
|
117
|
+
warehouse: string | null;
|
|
118
|
+
item_code: string | null;
|
|
119
|
+
assets: CalendarAsset[];
|
|
120
|
+
reservations: CalendarReservation[];
|
|
121
|
+
}
|
|
122
|
+
|
|
73
123
|
export const api = {
|
|
74
124
|
// Generic request (used by sidebar for chat sessions)
|
|
75
125
|
request,
|
|
@@ -256,6 +306,13 @@ export const api = {
|
|
|
256
306
|
stockBalance: (params?: Record<string, string>) =>
|
|
257
307
|
request<{ rows: any[] }>(`/reports/stock-balance${qs(params)}`),
|
|
258
308
|
|
|
309
|
+
// --- Rentals: availability + fleet calendar (docs/RENTAL_UI_PLAN.md) ---
|
|
310
|
+
availability: (params: { item_code: string; from: string; to: string; warehouse?: string; exclude?: string }) =>
|
|
311
|
+
request<AvailabilityResult>(`/availability${qs(params)}`),
|
|
312
|
+
|
|
313
|
+
fleetCalendar: (params: { from: string; to: string; warehouse?: string; item_code?: string }) =>
|
|
314
|
+
request<FleetCalendarFeed>(`/availability/calendar${qs(params)}`),
|
|
315
|
+
|
|
259
316
|
dashboardSummary: (company?: string) =>
|
|
260
317
|
request<any>(`/reports/dashboard-summary${qs({ company })}`),
|
|
261
318
|
|
|
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
|
|
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
|