fix: stabilize ToolApp back gesture stack

This commit is contained in:
7015725
2026-05-22 12:30:50 +08:00
parent 83249ab534
commit 736212fd80
3 changed files with 95 additions and 22 deletions

View File

@@ -545,6 +545,7 @@ FloatBallAppWM.prototype.closeToolApp = function() {
this.state.toolAppActive = false; this.state.toolAppActive = false;
this.state.toolAppRoute = null; this.state.toolAppRoute = null;
this.state.toolAppNavStack = []; this.state.toolAppNavStack = [];
try { this.bumpToolAppStackVersion(); } catch(eStackClose) {}
this.state.settingsGroupKey = null; this.state.settingsGroupKey = null;
this.state.settingsHomeSelectedItemId = null; this.state.settingsHomeSelectedItemId = null;
this.hideViewerPanel(); this.hideViewerPanel();
@@ -554,6 +555,8 @@ FloatBallAppWM.prototype.closeToolApp = function() {
this.state.toolAppBackPreviewView = null; this.state.toolAppBackPreviewView = null;
this.state.toolAppBackPreviewRoute = null; this.state.toolAppBackPreviewRoute = null;
this.state.toolAppBackPreviewReady = false; this.state.toolAppBackPreviewReady = false;
this.state.toolAppBackPreviewStackVersion = null;
this.state.toolAppBackPreviewEntryKey = null;
try { if (this.hideToolAppScreenBackStrips) this.hideToolAppScreenBackStrips(); } catch (eStrip) {} try { if (this.hideToolAppScreenBackStrips) this.hideToolAppScreenBackStrips(); } catch (eStrip) {}
this.state.toolAppTitleView = null; this.state.toolAppTitleView = null;
this.state.toolAppBackButton = null; this.state.toolAppBackButton = null;
@@ -571,6 +574,8 @@ FloatBallAppWM.prototype.clearToolAppBackPreview = function(resetCurrent) {
this.state.toolAppBackPreviewView = null; this.state.toolAppBackPreviewView = null;
this.state.toolAppBackPreviewRoute = null; this.state.toolAppBackPreviewRoute = null;
this.state.toolAppBackPreviewReady = false; this.state.toolAppBackPreviewReady = false;
this.state.toolAppBackPreviewStackVersion = null;
this.state.toolAppBackPreviewEntryKey = null;
if (resetCurrent && root) { if (resetCurrent && root) {
try { root.animate().cancel(); } catch (eCancelRoot) {} try { root.animate().cancel(); } catch (eCancelRoot) {}
try { root.setTranslationX(0); root.setAlpha(1); root.setScaleX(1); root.setScaleY(1); } catch (eRoot) {} try { root.setTranslationX(0); root.setAlpha(1); root.setScaleX(1); root.setScaleY(1); } catch (eRoot) {}
@@ -611,6 +616,64 @@ FloatBallAppWM.prototype.hasToolAppBackTarget = function() {
return false; return false;
}; };
FloatBallAppWM.prototype.cloneToolAppSnapshotValue = function(v, depth) {
try {
if (depth === undefined || depth === null) depth = 0;
if (depth > 4) return null;
if (v === null || v === undefined) return v;
var t = typeof v;
if (t === "string" || t === "number" || t === "boolean") return v;
if (v instanceof java.lang.String) return String(v);
if (v instanceof java.lang.Number) return Number(v);
if (v instanceof java.lang.Boolean) return Boolean(v);
var tag = Object.prototype.toString.call(v);
if (tag === "[object Array]") {
var arr = [];
for (var i = 0; i < v.length; i++) arr.push(this.cloneToolAppSnapshotValue(v[i], depth + 1));
return arr;
}
if (t === "object") {
// 只深拷贝普通 JS 对象,避免把 Android View / Java 对象枚举进页面栈快照。
if (tag !== "[object Object]") return String(v);
var out = {};
for (var k in v) {
try {
if (!v.hasOwnProperty || v.hasOwnProperty(k)) out[k] = this.cloneToolAppSnapshotValue(v[k], depth + 1);
} catch(eKey) {}
}
return out;
}
} catch(e) {}
return null;
};
FloatBallAppWM.prototype.getToolAppStackVersion = function() {
try {
var v = Number(this.state.toolAppNavStackVersion || 0);
if (isNaN(v) || v < 0) v = 0;
this.state.toolAppNavStackVersion = v;
return v;
} catch(e) {}
return 0;
};
FloatBallAppWM.prototype.bumpToolAppStackVersion = function() {
try {
var v = this.getToolAppStackVersion ? this.getToolAppStackVersion() : Number(this.state.toolAppNavStackVersion || 0);
v = v + 1;
if (v > 1000000000) v = 1;
this.state.toolAppNavStackVersion = v;
this.clearToolAppBackPreview(false);
return v;
} catch(e) {}
return 0;
};
FloatBallAppWM.prototype.getToolAppSnapshotKey = function(entry) {
try { return JSON.stringify(entry || {}); } catch(e) {}
return String(entry && entry.route || "");
};
FloatBallAppWM.prototype.captureToolAppPageSnapshot = function(route) { FloatBallAppWM.prototype.captureToolAppPageSnapshot = function(route) {
var r = this.isToolAppRoute(route) ? String(route) : (this.isToolAppRoute(this.state.toolAppRoute) ? String(this.state.toolAppRoute) : "settings"); var r = this.isToolAppRoute(route) ? String(route) : (this.isToolAppRoute(this.state.toolAppRoute) ? String(this.state.toolAppRoute) : "settings");
var s = this.state || {}; var s = this.state || {};
@@ -622,13 +685,15 @@ FloatBallAppWM.prototype.captureToolAppPageSnapshot = function(route) {
editingSchemaIndex: (s.editingSchemaIndex !== undefined) ? s.editingSchemaIndex : null, editingSchemaIndex: (s.editingSchemaIndex !== undefined) ? s.editingSchemaIndex : null,
keepBtnEditorState: !!s.keepBtnEditorState, keepBtnEditorState: !!s.keepBtnEditorState,
keepSchemaEditorState: !!s.keepSchemaEditorState, keepSchemaEditorState: !!s.keepSchemaEditorState,
settingsHomeSelectedCategoryId: (s.settingsHomeSelectedCategoryId !== undefined) ? s.settingsHomeSelectedCategoryId : null,
toolAppSubRoute: (s.toolAppSubRoute !== undefined) ? s.toolAppSubRoute : null, toolAppSubRoute: (s.toolAppSubRoute !== undefined) ? s.toolAppSubRoute : null,
toolAppSubPage: (s.toolAppSubPage !== undefined) ? s.toolAppSubPage : null, toolAppSubPage: (s.toolAppSubPage !== undefined) ? s.toolAppSubPage : null,
toolAppSubKey: (s.toolAppSubKey !== undefined) ? s.toolAppSubKey : null, toolAppSubKey: (s.toolAppSubKey !== undefined) ? s.toolAppSubKey : null,
toolAppSubPayload: (s.toolAppSubPayload !== undefined) ? s.toolAppSubPayload : null toolAppSubPayload: (s.toolAppSubPayload !== undefined) ? this.cloneToolAppSnapshotValue(s.toolAppSubPayload, 0) : null,
toolAppPayload: (s.toolAppPayload !== undefined) ? this.cloneToolAppSnapshotValue(s.toolAppPayload, 0) : null
}; };
if (r !== "settings_group") entry.settingsGroupKey = ""; if (r !== "settings_group") entry.settingsGroupKey = "";
if (r !== "settings") entry.settingsHomeSelectedItemId = null; if (r !== "settings") { entry.settingsHomeSelectedItemId = null; entry.settingsHomeSelectedCategoryId = null; }
if (r !== "btn_editor") { entry.editingButtonIndex = null; entry.keepBtnEditorState = false; } if (r !== "btn_editor") { entry.editingButtonIndex = null; entry.keepBtnEditorState = false; }
if (r !== "schema_editor") { entry.editingSchemaIndex = null; entry.keepSchemaEditorState = false; } if (r !== "schema_editor") { entry.editingSchemaIndex = null; entry.keepSchemaEditorState = false; }
return entry; return entry;
@@ -645,6 +710,7 @@ FloatBallAppWM.prototype.applyToolAppPageSnapshot = function(entry) {
this.state.toolAppRoute = r; this.state.toolAppRoute = r;
this.state.settingsGroupKey = (entry.settingsGroupKey !== undefined && entry.settingsGroupKey !== null) ? String(entry.settingsGroupKey) : ""; this.state.settingsGroupKey = (entry.settingsGroupKey !== undefined && entry.settingsGroupKey !== null) ? String(entry.settingsGroupKey) : "";
this.state.settingsHomeSelectedItemId = (entry.settingsHomeSelectedItemId !== undefined) ? entry.settingsHomeSelectedItemId : null; this.state.settingsHomeSelectedItemId = (entry.settingsHomeSelectedItemId !== undefined) ? entry.settingsHomeSelectedItemId : null;
this.state.settingsHomeSelectedCategoryId = (entry.settingsHomeSelectedCategoryId !== undefined) ? entry.settingsHomeSelectedCategoryId : null;
this.state.editingButtonIndex = (entry.editingButtonIndex !== undefined) ? entry.editingButtonIndex : null; this.state.editingButtonIndex = (entry.editingButtonIndex !== undefined) ? entry.editingButtonIndex : null;
this.state.editingSchemaIndex = (entry.editingSchemaIndex !== undefined) ? entry.editingSchemaIndex : null; this.state.editingSchemaIndex = (entry.editingSchemaIndex !== undefined) ? entry.editingSchemaIndex : null;
this.state.keepBtnEditorState = !!entry.keepBtnEditorState; this.state.keepBtnEditorState = !!entry.keepBtnEditorState;
@@ -652,7 +718,8 @@ FloatBallAppWM.prototype.applyToolAppPageSnapshot = function(entry) {
this.state.toolAppSubRoute = (entry.toolAppSubRoute !== undefined) ? entry.toolAppSubRoute : null; this.state.toolAppSubRoute = (entry.toolAppSubRoute !== undefined) ? entry.toolAppSubRoute : null;
this.state.toolAppSubPage = (entry.toolAppSubPage !== undefined) ? entry.toolAppSubPage : null; this.state.toolAppSubPage = (entry.toolAppSubPage !== undefined) ? entry.toolAppSubPage : null;
this.state.toolAppSubKey = (entry.toolAppSubKey !== undefined) ? entry.toolAppSubKey : null; this.state.toolAppSubKey = (entry.toolAppSubKey !== undefined) ? entry.toolAppSubKey : null;
this.state.toolAppSubPayload = (entry.toolAppSubPayload !== undefined) ? entry.toolAppSubPayload : null; this.state.toolAppSubPayload = (entry.toolAppSubPayload !== undefined) ? this.cloneToolAppSnapshotValue(entry.toolAppSubPayload, 0) : null;
this.state.toolAppPayload = (entry.toolAppPayload !== undefined) ? this.cloneToolAppSnapshotValue(entry.toolAppPayload, 0) : null;
return true; return true;
} catch(e) { safeLog(this.L, 'w', "apply tool app snapshot fail: " + String(e)); } } catch(e) { safeLog(this.L, 'w', "apply tool app snapshot fail: " + String(e)); }
return false; return false;
@@ -668,10 +735,12 @@ FloatBallAppWM.prototype.cloneToolAppPageSnapshot = function(entry) {
editingSchemaIndex: (entry.editingSchemaIndex !== undefined) ? entry.editingSchemaIndex : null, editingSchemaIndex: (entry.editingSchemaIndex !== undefined) ? entry.editingSchemaIndex : null,
keepBtnEditorState: !!entry.keepBtnEditorState, keepBtnEditorState: !!entry.keepBtnEditorState,
keepSchemaEditorState: !!entry.keepSchemaEditorState, keepSchemaEditorState: !!entry.keepSchemaEditorState,
settingsHomeSelectedCategoryId: (entry.settingsHomeSelectedCategoryId !== undefined) ? entry.settingsHomeSelectedCategoryId : null,
toolAppSubRoute: (entry.toolAppSubRoute !== undefined) ? entry.toolAppSubRoute : null, toolAppSubRoute: (entry.toolAppSubRoute !== undefined) ? entry.toolAppSubRoute : null,
toolAppSubPage: (entry.toolAppSubPage !== undefined) ? entry.toolAppSubPage : null, toolAppSubPage: (entry.toolAppSubPage !== undefined) ? entry.toolAppSubPage : null,
toolAppSubKey: (entry.toolAppSubKey !== undefined) ? entry.toolAppSubKey : null, toolAppSubKey: (entry.toolAppSubKey !== undefined) ? entry.toolAppSubKey : null,
toolAppSubPayload: (entry.toolAppSubPayload !== undefined) ? entry.toolAppSubPayload : null toolAppSubPayload: (entry.toolAppSubPayload !== undefined) ? this.cloneToolAppSnapshotValue(entry.toolAppSubPayload, 0) : null,
toolAppPayload: (entry.toolAppPayload !== undefined) ? this.cloneToolAppSnapshotValue(entry.toolAppPayload, 0) : null
}; };
}; };
@@ -783,7 +852,7 @@ FloatBallAppWM.prototype.buildToolAppPreviewBody = function(entry) {
FloatBallAppWM.prototype.prepareToolAppBackPreview = function(edge) { FloatBallAppWM.prototype.prepareToolAppBackPreview = function(edge) {
try { try {
if (this.state.toolAppBackPreviewReady) return true; var stackVersion = this.getToolAppStackVersion ? this.getToolAppStackVersion() : Number(this.state.toolAppNavStackVersion || 0);
var root = this.state.toolAppRoot; var root = this.state.toolAppRoot;
var body = this.state.toolAppBody; var body = this.state.toolAppBody;
var prevEntry = this.getToolAppPreviousStackEntry(); var prevEntry = this.getToolAppPreviousStackEntry();
@@ -793,6 +862,12 @@ FloatBallAppWM.prototype.prepareToolAppBackPreview = function(edge) {
isPaneBack = true; isPaneBack = true;
} }
if (!root || !body || !prevEntry || !prevEntry.route) return false; if (!root || !body || !prevEntry || !prevEntry.route) return false;
prevEntry = this.cloneToolAppPageSnapshot ? this.cloneToolAppPageSnapshot(prevEntry) : prevEntry;
var prevEntryKey = this.getToolAppSnapshotKey ? this.getToolAppSnapshotKey(prevEntry) : String(prevEntry.route || "settings");
if (this.state.toolAppBackPreviewReady) {
if (this.state.toolAppBackPreviewStackVersion === stackVersion && this.state.toolAppBackPreviewEntryKey === prevEntryKey) return true;
this.clearToolAppBackPreview(false);
}
var prevRoute = isPaneBack ? "settings:pane" : String(prevEntry.route || "settings"); var prevRoute = isPaneBack ? "settings:pane" : String(prevEntry.route || "settings");
var oldPaneItem = null; var oldPaneItem = null;
var hasOldPaneItem = false; var hasOldPaneItem = false;
@@ -825,6 +900,8 @@ FloatBallAppWM.prototype.prepareToolAppBackPreview = function(edge) {
this.state.toolAppBackPreviewView = prevBody; this.state.toolAppBackPreviewView = prevBody;
this.state.toolAppBackPreviewRoute = prevRoute; this.state.toolAppBackPreviewRoute = prevRoute;
this.state.toolAppBackPreviewReady = true; this.state.toolAppBackPreviewReady = true;
this.state.toolAppBackPreviewStackVersion = stackVersion;
this.state.toolAppBackPreviewEntryKey = prevEntryKey;
return true; return true;
} catch (e) { } catch (e) {
safeLog(this.L, 'w', "prepare tool app back preview fail: " + String(e)); safeLog(this.L, 'w', "prepare tool app back preview fail: " + String(e));
@@ -1245,21 +1322,12 @@ FloatBallAppWM.prototype.isToolAppBackInteractiveView = function(v) {
try { if (v instanceof android.widget.CompoundButton) return true; } catch(eComp) {} try { if (v instanceof android.widget.CompoundButton) return true; } catch(eComp) {}
try { if (v instanceof android.widget.Switch) return true; } catch(eSw) {} try { if (v instanceof android.widget.Switch) return true; } catch(eSw) {}
try { if (v instanceof android.widget.EditText) return true; } catch(eEdit) {} try { if (v instanceof android.widget.EditText) return true; } catch(eEdit) {}
try { if (v instanceof android.widget.Button) return true; } catch(eBtn) {}
try { if (v instanceof android.widget.AbsListView) return true; } catch(eAbs) {}
try { if (v instanceof android.widget.ListView) return true; } catch(eList) {}
try { if (v instanceof android.widget.HorizontalScrollView) return true; } catch(eHsv) {} try { if (v instanceof android.widget.HorizontalScrollView) return true; } catch(eHsv) {}
try { // 普通 Button / 卡片 / 垂直列表 item 不在 DOWN 阶段屏蔽返回;强横滑由 root 在 MOVE 阶段接管。
var rvCls = java.lang.Class.forName("androidx.recyclerview.widget.RecyclerView"); // 垂直 ListView/RecyclerView 也不作为 blocker保证列表上下滑正常且强横滑可返回。
if (rvCls && rvCls.isInstance(v)) return true;
} catch(eRv1) {}
try {
var rvCls2 = java.lang.Class.forName("android.support.v7.widget.RecyclerView");
if (rvCls2 && rvCls2.isInstance(v)) return true;
} catch(eRv2) {}
// 不把所有 clickable/longClickable 都当成阻断项ToolHub 大量卡片/容器为了 ripple 都会 setClickable(true) // 不把所有 clickable/longClickable 都当成阻断项ToolHub 大量卡片/容器为了 ripple 都会 setClickable(true)
// 若在 surface 横滑模式下阻断它们,几乎整页都会 rootBackBlocked=true导致滑动返回一直触发不了。 // 若在 surface 横滑模式下阻断它们,几乎整页都会 rootBackBlocked=true导致滑动返回一直触发不了。
// DOWN 已经放行给子控件,只有超过横滑阈值后才拦截,所以保留按钮/Switch/SeekBar/EditText/列表等强交互控件即可 // DOWN 已经放行给子控件,只有超过横滑阈值后才拦截;这里只保留 SeekBar/Switch/EditText/HorizontalScrollView 等强交互控件。
/* try { if (v.isClickable && v.isClickable()) return true; } catch(eClick) {} */ /* try { if (v.isClickable && v.isClickable()) return true; } catch(eClick) {} */
/* try { if (v.isLongClickable && v.isLongClickable()) return true; } catch(eLong) {} */ /* try { if (v.isLongClickable && v.isLongClickable()) return true; } catch(eLong) {} */
} catch(e) {} } catch(e) {}
@@ -1674,6 +1742,7 @@ FloatBallAppWM.prototype.showToolApp = function(route, resetStack) {
} }
if (resetStack || !this.state.toolAppNavStack || !this.state.toolAppNavStack.length) { if (resetStack || !this.state.toolAppNavStack || !this.state.toolAppNavStack.length) {
this.state.toolAppNavStack = [this.makeToolAppStackEntry(r)]; this.state.toolAppNavStack = [this.makeToolAppStackEntry(r)];
try { this.bumpToolAppStackVersion(); } catch(eStackInit) {}
} }
var raw = this.buildPanelView(r); var raw = this.buildPanelView(r);
@@ -1716,8 +1785,9 @@ FloatBallAppWM.prototype.pushToolAppPage = function(route) {
if (this.state.toolAppNavStack.length <= 0) { if (this.state.toolAppNavStack.length <= 0) {
this.state.toolAppNavStack.push(this.makeToolAppStackEntry(this.state.toolAppRoute || "settings")); this.state.toolAppNavStack.push(this.makeToolAppStackEntry(this.state.toolAppRoute || "settings"));
} }
var nextEntry = this.makeToolAppStackEntry(route); var nextEntry = this.cloneToolAppPageSnapshot ? this.cloneToolAppPageSnapshot(this.makeToolAppStackEntry(route)) : this.makeToolAppStackEntry(route);
this.state.toolAppNavStack.push(nextEntry); this.state.toolAppNavStack.push(nextEntry);
try { this.bumpToolAppStackVersion(); } catch(eStackPush) {}
if (this.applyToolAppPageSnapshot) this.applyToolAppPageSnapshot(nextEntry); if (this.applyToolAppPageSnapshot) this.applyToolAppPageSnapshot(nextEntry);
this.showToolApp(route, false); this.showToolApp(route, false);
}; };
@@ -1732,6 +1802,7 @@ FloatBallAppWM.prototype.replaceToolAppPage = function(route) {
var entry = this.makeToolAppStackEntry(route); var entry = this.makeToolAppStackEntry(route);
if (!this.state.toolAppNavStack || !this.state.toolAppNavStack.length) this.state.toolAppNavStack = [entry]; if (!this.state.toolAppNavStack || !this.state.toolAppNavStack.length) this.state.toolAppNavStack = [entry];
else this.state.toolAppNavStack[this.state.toolAppNavStack.length - 1] = entry; else this.state.toolAppNavStack[this.state.toolAppNavStack.length - 1] = entry;
try { this.bumpToolAppStackVersion(); } catch(eStackReplace) {}
if (this.applyToolAppPageSnapshot) this.applyToolAppPageSnapshot(entry); if (this.applyToolAppPageSnapshot) this.applyToolAppPageSnapshot(entry);
this.showToolApp(route, false); this.showToolApp(route, false);
}; };
@@ -1745,6 +1816,7 @@ FloatBallAppWM.prototype.popToolAppPage = function(reason) {
this.state.settingsHomeSelectedItemId = null; this.state.settingsHomeSelectedItemId = null;
if (this.state.toolAppNavStack && this.state.toolAppNavStack.length > 0) { if (this.state.toolAppNavStack && this.state.toolAppNavStack.length > 0) {
this.state.toolAppNavStack[this.state.toolAppNavStack.length - 1] = this.makeToolAppStackEntry("settings"); this.state.toolAppNavStack[this.state.toolAppNavStack.length - 1] = this.makeToolAppStackEntry("settings");
try { this.bumpToolAppStackVersion(); } catch(eStackPane) {}
} }
this.showToolApp("settings", false); this.showToolApp("settings", false);
return true; return true;
@@ -1755,6 +1827,7 @@ FloatBallAppWM.prototype.popToolAppPage = function(reason) {
return true; return true;
} }
this.state.toolAppNavStack.pop(); this.state.toolAppNavStack.pop();
try { this.bumpToolAppStackVersion(); } catch(eStackPop) {}
var top = this.state.toolAppNavStack[this.state.toolAppNavStack.length - 1]; var top = this.state.toolAppNavStack[this.state.toolAppNavStack.length - 1];
var target = this.cloneToolAppPageSnapshot ? this.cloneToolAppPageSnapshot(top) : top; var target = this.cloneToolAppPageSnapshot ? this.cloneToolAppPageSnapshot(top) : top;
var nextRoute = target && target.route ? String(target.route) : "settings"; var nextRoute = target && target.route ? String(target.route) : "settings";

View File

@@ -58,8 +58,8 @@
"size": 304993 "size": 304993
}, },
"th_15_extra.js": { "th_15_extra.js": {
"sha256": "09b47453362f4394b0ea200a0e5775d15cae60e5ca9784b5c6f2eaf3c890242d", "sha256": "380272c10e117c2ad09216709d3f7bd3a54ab97b3fa6ce5594ab5fdd252aa48e",
"size": 125364 "size": 129287
}, },
"th_16_entry.js": { "th_16_entry.js": {
"sha256": "6c59d9891cd010647f84c3db93f1cf95c7bbfb758470ea21044bf72eb8ff73d1", "sha256": "6c59d9891cd010647f84c3db93f1cf95c7bbfb758470ea21044bf72eb8ff73d1",
@@ -68,5 +68,5 @@
}, },
"keyId": "toolhub-targets-2026-rsa3072", "keyId": "toolhub-targets-2026-rsa3072",
"schema": 2, "schema": 2,
"version": 20260522011606 "version": 20260522043019
} }

View File

@@ -1 +1 @@
B9marjK9C0psm0E8hNucZxC7/jxz/v+y3bnG8O601Mc/s/qy3WODyi3gn8Wof6USLOY74oLPIm+oF57+np+zqJi33relqSNWfdx/+7Oj62hO44d6r5u6IJo4mW7YTLo6cKSRpvRGnf3NxL9hhOcbNeojVr4dTR3AOVGEI05TquHM6EmK21+1H9odxnjo2m9WnSHraCaXnmdrudZUir10W/4MZx9AzVawJjITDsGBvJbEDPmGYHspvWZx9J589YlmT42zWz3nG5tBiuRXvKRbhSEX92LBIOe6zvfMP887qM8eOWHx0V0IyqVf5eyIbUavAlXVJl4lp28Z/OWnWyKVDg1onI9gqteahhPodpH7z9r8ASzuOLjxzZ31MT/NpO3ZyvqWgOhxgsuXHRuvEqQPhyhBcjjifV3dp8DIAy6AMJRQ3zRtrVtVOY9EoG1cc4TdjCKky8Wte4L7rJlUR12mli4sI63Y2lGJ3XwQYztkKQea+D/5jr0I692YYh+CaM1/ n3ojvi067byhyd0l6vNsePByOJ/dN9Hoa16nhD/9nuU3f0pnNTKjGDS+iHDlO9V2MOsRPRjTlzYR0inJJZaMh2sSjzCmcAOapxqkm2XwItOrtYjgk3yNBO7AwcXH5sYDUXGZ2Tsx95z7dS3sLNyavVUSAKyO3ygzTSQL7EgfWu3LumIiATrHPHL71jvbJRfG1tVUilWF3VYZMyULOJievgCApeX6h4xRgh0eCdgtbn6bDlH4E1gHbapQ+beYKDD2GL1H9msuwyzehxUM4QZVrtOwXHVlCHL4x9Kidm35wMp4H21XCr7UD6N2oRvUsXoEtI6Ugj8dN2Ilvbz0/GO4Nf/v522xbFsPZBj06kD2qiGGJ6ztT3KkfVBv53GRBhN+v/aGimO8ww/YtnUn6njTcF36Mnh98CvE/9BXENU98TYA0zWNOop5WxlyHXOf6rQ3ivMYnsbKzvOX5LrX8uExJawjpUvsoY7ahUJ+h6TDPcyB6Fl3644MKq5ukXgVm1jI