workpeg 0.96.2__tar.gz → 0.96.4__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.
- {workpeg-0.96.2/src/workpeg.egg-info → workpeg-0.96.4}/PKG-INFO +1 -1
- {workpeg-0.96.2 → workpeg-0.96.4}/pyproject.toml +1 -1
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/runtime/ai.js +80 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/runtime/scaffold.js +90 -4
- {workpeg-0.96.2 → workpeg-0.96.4/src/workpeg.egg-info}/PKG-INFO +1 -1
- {workpeg-0.96.2 → workpeg-0.96.4}/LICENSE +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/MANIFEST.in +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/README.md +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/setup.cfg +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/__init__.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/build.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/cdn.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/cli.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/config.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/context.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/create_new.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/run.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/runtime.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/submit.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/__init__.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/functions/Dockerfile +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/functions/LICENSE +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/functions/README.md +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/functions/app/__init__.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/functions/app/main.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/templates/functions/requirements.txt +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/__init__.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/actions.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/app.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/build.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/compiler/__init__.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/compiler/ast_parser.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/compiler/ir.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/compiler/js_generator.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/create.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/fake_cloud.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/minify.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/runtime/pegment.css +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/runtime/workpeg-runtime.js +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/scaffold.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/serve.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/state.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/validators.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/watcher.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/__init__.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/base.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/canvas.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/display.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/forms.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/futures.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/gestures.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/interactive.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/ui/widgets/layout.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg/utils.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg.egg-info/SOURCES.txt +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg.egg-info/dependency_links.txt +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg.egg-info/entry_points.txt +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg.egg-info/requires.txt +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/src/workpeg.egg-info/top_level.txt +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_build.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_cdn.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_cdn_publish.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_changelog.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_changelog_guard.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_cli.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_config.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_context.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_create_new.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_release_script.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_run.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_runtime.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_submit.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_utils.py +0 -0
- {workpeg-0.96.2 → workpeg-0.96.4}/tests/test_watch_pipeline.py +0 -0
|
@@ -1091,6 +1091,81 @@
|
|
|
1091
1091
|
}
|
|
1092
1092
|
|
|
1093
1093
|
// ── composer (shared by landing + bottom bar) ──────────────────────────
|
|
1094
|
+
// ── composer message history — ↑/↓ recall the user's past messages ───────
|
|
1095
|
+
// The user's own messages in this conversation, oldest → newest: the recall
|
|
1096
|
+
// history the composer's ↑/↓ walk (like a shell prompt's up-arrow).
|
|
1097
|
+
function userHistory() {
|
|
1098
|
+
var out = [];
|
|
1099
|
+
for (var i = 0; i < S.messages.length; i++) {
|
|
1100
|
+
var m = S.messages[i];
|
|
1101
|
+
if (m && !m.is_agent_response && String(m.content || "").length) {
|
|
1102
|
+
out.push(String(m.content));
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
return out;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
// Step a history: dir -1 = older, +1 = newer. idx === hist.length is the live
|
|
1109
|
+
// draft (past the newest). Returns the new index and the text to show. Pure.
|
|
1110
|
+
function stepHistory(hist, idx, dir, draft) {
|
|
1111
|
+
var next = idx + dir;
|
|
1112
|
+
if (next < 0) return { idx: 0, text: hist[0] };
|
|
1113
|
+
if (next >= hist.length) return { idx: hist.length, text: draft };
|
|
1114
|
+
return { idx: next, text: hist[next] };
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// Whether the collapsed caret sits on the composer's first / last visual line
|
|
1118
|
+
// — so ↑/↓ recall history only at the edges and otherwise move the caret
|
|
1119
|
+
// within a multi-line message. Fails open (both edges) with no live
|
|
1120
|
+
// selection/layout (e.g. tests).
|
|
1121
|
+
function caretEdges(input) {
|
|
1122
|
+
try {
|
|
1123
|
+
var sel = window.getSelection();
|
|
1124
|
+
var r = sel && sel.rangeCount ? sel.getRangeAt(0) : null;
|
|
1125
|
+
if (!r) return { first: true, last: true };
|
|
1126
|
+
if (!r.collapsed) return { first: false, last: false };
|
|
1127
|
+
var cr = r.getBoundingClientRect();
|
|
1128
|
+
var br = input.getBoundingClientRect();
|
|
1129
|
+
if (!cr || (!cr.top && !cr.bottom && !cr.height)) {
|
|
1130
|
+
return { first: true, last: true };
|
|
1131
|
+
}
|
|
1132
|
+
var line = cr.height || 20;
|
|
1133
|
+
return {
|
|
1134
|
+
first: cr.top - br.top < line * 0.75,
|
|
1135
|
+
last: br.bottom - cr.bottom < line * 0.75
|
|
1136
|
+
};
|
|
1137
|
+
} catch (e) { return { first: true, last: true }; }
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
function setComposerText(input, text) {
|
|
1141
|
+
input.innerText = text || "";
|
|
1142
|
+
input.focus();
|
|
1143
|
+
placeCaretEnd(input);
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
// ↑/↓ handler: walk the user's past messages, saving the in-progress draft so
|
|
1147
|
+
// stepping past the newest restores it. Guarded by caretEdges so multi-line
|
|
1148
|
+
// editing still moves the caret line by line.
|
|
1149
|
+
function recallHistory(input, e) {
|
|
1150
|
+
var dir = e.key === "ArrowUp" ? -1 : 1;
|
|
1151
|
+
var edge = caretEdges(input);
|
|
1152
|
+
if (dir < 0 && !edge.first) return;
|
|
1153
|
+
if (dir > 0 && !edge.last) return;
|
|
1154
|
+
var hist = userHistory();
|
|
1155
|
+
if (!hist.length) return;
|
|
1156
|
+
var idx = input._histIdx;
|
|
1157
|
+
if (idx == null) {
|
|
1158
|
+
if (dir > 0) return; // ↓ with nothing recalled → default
|
|
1159
|
+
input._histDraft = input.innerText || "";
|
|
1160
|
+
idx = hist.length; // start at the draft, one past the newest
|
|
1161
|
+
}
|
|
1162
|
+
var step = stepHistory(hist, idx, dir, input._histDraft || "");
|
|
1163
|
+
if (e.preventDefault) e.preventDefault();
|
|
1164
|
+
if (step.idx === idx) return; // already at the oldest — no-op
|
|
1165
|
+
input._histIdx = step.idx >= hist.length ? null : step.idx;
|
|
1166
|
+
setComposerText(input, step.text);
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1094
1169
|
function buildComposer(placeholder) {
|
|
1095
1170
|
var input = el("div", "chat-input", {
|
|
1096
1171
|
attrs: { contenteditable: "true", "data-placeholder": placeholder,
|
|
@@ -1100,8 +1175,12 @@
|
|
|
1100
1175
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
1101
1176
|
e.preventDefault();
|
|
1102
1177
|
submitFromInput(input);
|
|
1178
|
+
} else if (e.key === "ArrowUp" || e.key === "ArrowDown") {
|
|
1179
|
+
recallHistory(input, e);
|
|
1103
1180
|
}
|
|
1104
1181
|
});
|
|
1182
|
+
// Typing exits history-recall (what's in the box becomes the new draft).
|
|
1183
|
+
input.addEventListener("input", function () { input._histIdx = null; });
|
|
1105
1184
|
enableComposerMarkdown(input);
|
|
1106
1185
|
|
|
1107
1186
|
// Buttons use the SHARED pegment .btn system (so the AI surface and the SDK
|
|
@@ -1170,6 +1249,7 @@
|
|
|
1170
1249
|
var text = (input.innerText || "").trim();
|
|
1171
1250
|
if (!text || S.sending) return;
|
|
1172
1251
|
input.innerHTML = "";
|
|
1252
|
+
input._histIdx = null; // the sent message becomes the newest history
|
|
1173
1253
|
send(text);
|
|
1174
1254
|
}
|
|
1175
1255
|
|
|
@@ -320,6 +320,27 @@
|
|
|
320
320
|
});
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
+
// Fade a scrollable list's bottom edge while it overflows (a "more below"
|
|
324
|
+
// hint), lifting the fade once scrolled to the end — the .has-overflow /
|
|
325
|
+
// .at-bottom classes the STYLES rules key off. The first check runs after
|
|
326
|
+
// the next frame, so it measures once the popup is in the DOM.
|
|
327
|
+
function attachListFade(list) {
|
|
328
|
+
function update() {
|
|
329
|
+
var overflow = list.scrollHeight > list.clientHeight + 1;
|
|
330
|
+
list.classList.toggle("has-overflow", overflow);
|
|
331
|
+
var atBottom =
|
|
332
|
+
list.scrollTop + list.clientHeight >= list.scrollHeight - 1;
|
|
333
|
+
list.classList.toggle("at-bottom", atBottom);
|
|
334
|
+
}
|
|
335
|
+
list.addEventListener("scroll", update);
|
|
336
|
+
if (typeof requestAnimationFrame === "function") {
|
|
337
|
+
requestAnimationFrame(update);
|
|
338
|
+
} else {
|
|
339
|
+
setTimeout(update, 0);
|
|
340
|
+
}
|
|
341
|
+
return update;
|
|
342
|
+
}
|
|
343
|
+
|
|
323
344
|
// ── the business switcher (rail foot) ────────────────────────────────────
|
|
324
345
|
function avatarEl(size, email, initials) {
|
|
325
346
|
var box = el("span", "wps-avatar", { attrs: { role: "img" } });
|
|
@@ -374,11 +395,65 @@
|
|
|
374
395
|
(opts.chevron ? el("span", "wps-dd-chevron", { children: [
|
|
375
396
|
icon("chevron-right", 14, "thin")] }) : null)
|
|
376
397
|
],
|
|
377
|
-
on: { click: function () {
|
|
398
|
+
on: { click: function (e) {
|
|
399
|
+
closePanel();
|
|
400
|
+
// An action row (e.g. Log out) supersedes its href: preventDefault so
|
|
401
|
+
// neither the browser nor the runtime's link router navigates the
|
|
402
|
+
// fallback href, then run the handler.
|
|
403
|
+
if (opts.onClick) {
|
|
404
|
+
if (e && e.preventDefault) e.preventDefault();
|
|
405
|
+
opts.onClick(e);
|
|
406
|
+
}
|
|
407
|
+
} }
|
|
378
408
|
});
|
|
379
409
|
return row;
|
|
380
410
|
}
|
|
381
411
|
|
|
412
|
+
// Log out — mirrors space's handlelogOut: DELETE the token (the server drops
|
|
413
|
+
// the HttpOnly access/refresh cookies), wipe the readable auth cookies, then
|
|
414
|
+
// bounce to the accounts login (the same redirect the auth gate uses). A
|
|
415
|
+
// direct credentialed fetch — the workpeg.* client's allowlist (tables /
|
|
416
|
+
// rows / CDN) intentionally won't reach /users/token/.
|
|
417
|
+
function logout() {
|
|
418
|
+
var api = String(WP().apiBase || "https://api.workpeg.com")
|
|
419
|
+
.replace(/\/+$/, "");
|
|
420
|
+
var finish = function () {
|
|
421
|
+
clearAuthCookies();
|
|
422
|
+
if (typeof WP()._redirectToLogin === "function") {
|
|
423
|
+
WP()._redirectToLogin();
|
|
424
|
+
} else {
|
|
425
|
+
var base = String(WP().accountsBase || "https://accounts.workpeg.com")
|
|
426
|
+
.replace(/\/+$/, "");
|
|
427
|
+
var ns = (WP()._pegNamespace && WP()._pegNamespace()) || "";
|
|
428
|
+
var ep = (window.location && window.location.pathname) || "/";
|
|
429
|
+
window.location.href = base + "/login?peg=" +
|
|
430
|
+
encodeURIComponent(ns) + "&ep=" + encodeURIComponent(ep);
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
try {
|
|
434
|
+
fetch(api + "/v1/users/token/", {
|
|
435
|
+
method: "DELETE", credentials: "include"
|
|
436
|
+
}).then(finish, finish); // log out client-side even if the call fails
|
|
437
|
+
} catch (e) {
|
|
438
|
+
finish();
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Expire the readable auth cookies (the HttpOnly access/refresh are dropped
|
|
443
|
+
// by the DELETE). setCookie scopes them to the parent .workpeg.* domain, so
|
|
444
|
+
// clear them there too; on a non-Workpeg host just clear the current host.
|
|
445
|
+
function clearAuthCookies() {
|
|
446
|
+
if (typeof document === "undefined") return;
|
|
447
|
+
var host = (window.location && window.location.hostname) || "";
|
|
448
|
+
var at = host.indexOf("workpeg");
|
|
449
|
+
var domainAttr = at >= 0 ? "; domain=." + host.slice(at) : "";
|
|
450
|
+
var past = "; expires=Thu, 01 Jan 1970 00:00:00 GMT";
|
|
451
|
+
["access_ttl", "cachedBusiness"].forEach(function (name) {
|
|
452
|
+
document.cookie = name + "=; path=/" + past;
|
|
453
|
+
if (domainAttr) document.cookie = name + "=; path=/" + domainAttr + past;
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
382
457
|
function workspacePopup() {
|
|
383
458
|
var listKids = (S.businesses || []).map(workspaceRow);
|
|
384
459
|
var help = el("div", "wps-dd-row", {
|
|
@@ -396,15 +471,17 @@
|
|
|
396
471
|
] }));
|
|
397
472
|
} }
|
|
398
473
|
});
|
|
474
|
+
var wsList = el("div", "wps-ws-list", { children: listKids });
|
|
475
|
+
attachListFade(wsList);
|
|
399
476
|
return el("div", "wps-ws-popup", { children: [
|
|
400
|
-
|
|
477
|
+
wsList,
|
|
401
478
|
popupLink("Add new business", "plus", bizHref("/new")),
|
|
402
479
|
el("div", "wps-dd-hr"),
|
|
403
480
|
popupLink("Profile", "user", bizHref("/profile")),
|
|
404
481
|
popupLink("Settings", "settings", bizHref("/settings")),
|
|
405
482
|
el("div", "wps-dd-hr"),
|
|
406
483
|
help,
|
|
407
|
-
popupLink("Log out", "logout", "/login")
|
|
484
|
+
popupLink("Log out", "logout", "/login", { onClick: logout })
|
|
408
485
|
] });
|
|
409
486
|
}
|
|
410
487
|
|
|
@@ -779,7 +856,7 @@
|
|
|
779
856
|
"align-items:stretch}",
|
|
780
857
|
".wps-header{position:sticky;top:0;display:flex;align-items:center;",
|
|
781
858
|
"width:100%;box-sizing:border-box;z-index:5;margin-bottom:18px;",
|
|
782
|
-
"padding:
|
|
859
|
+
"padding:4px 2px 0 var(--pg-collapse-pl-hdr);",
|
|
783
860
|
"transition:padding-left 0.18s " + EASE + "}",
|
|
784
861
|
".wps-logo-wrap{flex-grow:var(--pg-collapse-flex);flex-shrink:1;",
|
|
785
862
|
"flex-basis:0;min-width:0;overflow:hidden;",
|
|
@@ -872,7 +949,16 @@
|
|
|
872
949
|
".wps-ws-list{max-height:calc(3.5 * 40px + 3 * 8px);overflow-y:auto;",
|
|
873
950
|
"scrollbar-width:thin;",
|
|
874
951
|
"scrollbar-color:rgba(128, 128, 128, 0.15) transparent;",
|
|
952
|
+
"--fade-size:24px;",
|
|
875
953
|
"display:flex;flex-direction:column;gap:8px;margin-bottom:1px}",
|
|
954
|
+
/* Fade the list's bottom edge while it overflows (a "more below" hint);
|
|
955
|
+
drop the fade at the end. has-overflow / at-bottom are toggled by
|
|
956
|
+
attachListFade — mirrors the static-scaffold reference. */
|
|
957
|
+
".wps-ws-list.has-overflow{-webkit-mask-image:linear-gradient(to bottom,",
|
|
958
|
+
"#000 calc(100% - var(--fade-size)),transparent);mask-image:linear-",
|
|
959
|
+
"gradient(to bottom,#000 calc(100% - var(--fade-size)),transparent)}",
|
|
960
|
+
".wps-ws-list.has-overflow.at-bottom{-webkit-mask-image:none;",
|
|
961
|
+
"mask-image:none}",
|
|
876
962
|
".wps-ws-row{display:flex;align-items:center;gap:8px;padding:6px;",
|
|
877
963
|
"border-radius:8px;cursor:pointer;width:100%;box-sizing:border-box;",
|
|
878
964
|
"transition:background 0.18s " + EASE + "}",
|
|
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
|