claude-scope 0.8.34 → 0.8.36
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.
- package/dist/claude-scope.cjs +166 -43
- package/package.json +1 -1
package/dist/claude-scope.cjs
CHANGED
|
@@ -2414,12 +2414,12 @@ var init_widget_types = __esm({
|
|
|
2414
2414
|
});
|
|
2415
2415
|
|
|
2416
2416
|
// src/providers/usage-parser.ts
|
|
2417
|
-
var
|
|
2417
|
+
var import_fs, import_readline, UsageParser;
|
|
2418
2418
|
var init_usage_parser = __esm({
|
|
2419
2419
|
"src/providers/usage-parser.ts"() {
|
|
2420
2420
|
"use strict";
|
|
2421
|
-
|
|
2422
|
-
|
|
2421
|
+
import_fs = require("fs");
|
|
2422
|
+
import_readline = require("readline");
|
|
2423
2423
|
UsageParser = class {
|
|
2424
2424
|
/**
|
|
2425
2425
|
* Parse the last assistant message with usage data from transcript
|
|
@@ -2429,30 +2429,55 @@ var init_usage_parser = __esm({
|
|
|
2429
2429
|
* @returns ContextUsage or null if not found
|
|
2430
2430
|
*/
|
|
2431
2431
|
async parseLastUsage(transcriptPath) {
|
|
2432
|
-
if (!(0,
|
|
2432
|
+
if (!(0, import_fs.existsSync)(transcriptPath)) {
|
|
2433
2433
|
return null;
|
|
2434
2434
|
}
|
|
2435
2435
|
try {
|
|
2436
2436
|
const lines = await this.readAllLines(transcriptPath);
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2437
|
+
let mostRecentUsage = null;
|
|
2438
|
+
let mostRecentTimestamp = null;
|
|
2439
|
+
let hasAnyTimestamp = false;
|
|
2440
|
+
for (const line of lines) {
|
|
2441
|
+
const entry = this.parseLineForUsage(line);
|
|
2442
|
+
if (entry) {
|
|
2443
|
+
const entryTime = this.parseTimestamp(line);
|
|
2444
|
+
if (entryTime) {
|
|
2445
|
+
hasAnyTimestamp = true;
|
|
2446
|
+
if (!mostRecentTimestamp || entryTime > mostRecentTimestamp) {
|
|
2447
|
+
mostRecentUsage = entry;
|
|
2448
|
+
mostRecentTimestamp = entryTime;
|
|
2449
|
+
}
|
|
2450
|
+
} else if (!hasAnyTimestamp) {
|
|
2451
|
+
mostRecentUsage = entry;
|
|
2452
|
+
}
|
|
2441
2453
|
}
|
|
2442
2454
|
}
|
|
2443
|
-
return
|
|
2455
|
+
return mostRecentUsage;
|
|
2444
2456
|
} catch {
|
|
2445
2457
|
return null;
|
|
2446
2458
|
}
|
|
2447
2459
|
}
|
|
2460
|
+
/**
|
|
2461
|
+
* Parse timestamp from a transcript line
|
|
2462
|
+
*/
|
|
2463
|
+
parseTimestamp(line) {
|
|
2464
|
+
try {
|
|
2465
|
+
const entry = JSON.parse(line);
|
|
2466
|
+
if (entry.timestamp) {
|
|
2467
|
+
return new Date(entry.timestamp);
|
|
2468
|
+
}
|
|
2469
|
+
} catch {
|
|
2470
|
+
}
|
|
2471
|
+
return null;
|
|
2472
|
+
}
|
|
2448
2473
|
/**
|
|
2449
2474
|
* Read all lines from transcript file
|
|
2450
2475
|
*/
|
|
2451
2476
|
async readAllLines(transcriptPath) {
|
|
2452
2477
|
const lines = [];
|
|
2453
2478
|
try {
|
|
2454
|
-
const fileStream = (0,
|
|
2455
|
-
const rl = (0,
|
|
2479
|
+
const fileStream = (0, import_fs.createReadStream)(transcriptPath, { encoding: "utf-8" });
|
|
2480
|
+
const rl = (0, import_readline.createInterface)({
|
|
2456
2481
|
input: fileStream,
|
|
2457
2482
|
crlfDelay: Infinity
|
|
2458
2483
|
});
|
|
@@ -2466,6 +2491,92 @@ var init_usage_parser = __esm({
|
|
|
2466
2491
|
}
|
|
2467
2492
|
return lines;
|
|
2468
2493
|
}
|
|
2494
|
+
/**
|
|
2495
|
+
* Parse cumulative cache tokens from all assistant messages in transcript
|
|
2496
|
+
*
|
|
2497
|
+
* Handles two transcript formats:
|
|
2498
|
+
* 1. Per-message format: cache_read varies per message (e.g., 2048, 4096) → sum all
|
|
2499
|
+
* 2. Cumulative format: cache_read is already cumulative (e.g., 165376) → use last
|
|
2500
|
+
*
|
|
2501
|
+
* @param transcriptPath - Path to the JSONL transcript file
|
|
2502
|
+
* @returns Object with cumulative cacheRead and cacheCreation, or null if not found
|
|
2503
|
+
*/
|
|
2504
|
+
async parseCumulativeCache(transcriptPath) {
|
|
2505
|
+
if (!(0, import_fs.existsSync)(transcriptPath)) {
|
|
2506
|
+
return null;
|
|
2507
|
+
}
|
|
2508
|
+
try {
|
|
2509
|
+
const lines = await this.readAllLines(transcriptPath);
|
|
2510
|
+
const cacheEntries = [];
|
|
2511
|
+
for (const line of lines) {
|
|
2512
|
+
const entry = this.parseLineForCache(line);
|
|
2513
|
+
if (entry) {
|
|
2514
|
+
const timestamp = this.parseTimestamp(line);
|
|
2515
|
+
cacheEntries.push({
|
|
2516
|
+
cacheRead: entry.cacheRead,
|
|
2517
|
+
cacheCreation: entry.cacheCreation,
|
|
2518
|
+
timestamp: timestamp?.toISOString() || ""
|
|
2519
|
+
});
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
if (cacheEntries.length === 0) {
|
|
2523
|
+
return null;
|
|
2524
|
+
}
|
|
2525
|
+
let isCumulativeFormat = false;
|
|
2526
|
+
if (cacheEntries.length > 1) {
|
|
2527
|
+
let nonDecreasingCount = 0;
|
|
2528
|
+
for (let i = 1; i < cacheEntries.length; i++) {
|
|
2529
|
+
if (cacheEntries[i].cacheRead >= cacheEntries[i - 1].cacheRead) {
|
|
2530
|
+
nonDecreasingCount++;
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
isCumulativeFormat = nonDecreasingCount / (cacheEntries.length - 1) >= 0.8;
|
|
2534
|
+
}
|
|
2535
|
+
let cumulativeCacheRead;
|
|
2536
|
+
let cumulativeCacheCreation;
|
|
2537
|
+
if (isCumulativeFormat) {
|
|
2538
|
+
const lastEntry = cacheEntries[cacheEntries.length - 1];
|
|
2539
|
+
cumulativeCacheRead = lastEntry.cacheRead;
|
|
2540
|
+
cumulativeCacheCreation = lastEntry.cacheCreation;
|
|
2541
|
+
} else {
|
|
2542
|
+
cumulativeCacheRead = cacheEntries.reduce((sum, e) => sum + e.cacheRead, 0);
|
|
2543
|
+
cumulativeCacheCreation = cacheEntries.reduce((sum, e) => sum + e.cacheCreation, 0);
|
|
2544
|
+
}
|
|
2545
|
+
if (cumulativeCacheRead === 0 && cumulativeCacheCreation === 0) {
|
|
2546
|
+
return null;
|
|
2547
|
+
}
|
|
2548
|
+
return {
|
|
2549
|
+
cacheRead: cumulativeCacheRead,
|
|
2550
|
+
cacheCreation: cumulativeCacheCreation
|
|
2551
|
+
};
|
|
2552
|
+
} catch {
|
|
2553
|
+
return null;
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
/**
|
|
2557
|
+
* Parse a single transcript line for cache data
|
|
2558
|
+
* Returns null if line is not an assistant message with usage
|
|
2559
|
+
*/
|
|
2560
|
+
parseLineForCache(line) {
|
|
2561
|
+
try {
|
|
2562
|
+
const entry = JSON.parse(line);
|
|
2563
|
+
if (entry.type !== "assistant") {
|
|
2564
|
+
return null;
|
|
2565
|
+
}
|
|
2566
|
+
const usage = entry.message?.usage;
|
|
2567
|
+
if (!usage) {
|
|
2568
|
+
return null;
|
|
2569
|
+
}
|
|
2570
|
+
const cacheRead = usage.cache_read_input_tokens ?? 0;
|
|
2571
|
+
const cacheCreation = usage.cache_creation_input_tokens ?? 0;
|
|
2572
|
+
if (cacheRead === 0 && cacheCreation === 0) {
|
|
2573
|
+
return null;
|
|
2574
|
+
}
|
|
2575
|
+
return { cacheRead, cacheCreation };
|
|
2576
|
+
} catch {
|
|
2577
|
+
return null;
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2469
2580
|
/**
|
|
2470
2581
|
* Parse a single transcript line for usage data
|
|
2471
2582
|
* Returns null if line is not an assistant message with usage
|
|
@@ -2480,14 +2591,15 @@ var init_usage_parser = __esm({
|
|
|
2480
2591
|
if (!usage) {
|
|
2481
2592
|
return null;
|
|
2482
2593
|
}
|
|
2483
|
-
if (typeof usage.input_tokens !== "number" || typeof usage.output_tokens !== "number"
|
|
2594
|
+
if (typeof usage.input_tokens !== "number" || typeof usage.output_tokens !== "number") {
|
|
2484
2595
|
return null;
|
|
2485
2596
|
}
|
|
2486
2597
|
return {
|
|
2487
2598
|
input_tokens: usage.input_tokens,
|
|
2488
2599
|
output_tokens: usage.output_tokens,
|
|
2489
2600
|
cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,
|
|
2490
|
-
cache_read_input_tokens: usage.cache_read_input_tokens
|
|
2601
|
+
cache_read_input_tokens: usage.cache_read_input_tokens ?? 0
|
|
2602
|
+
// Default to 0 if missing
|
|
2491
2603
|
};
|
|
2492
2604
|
} catch {
|
|
2493
2605
|
return null;
|
|
@@ -2498,11 +2610,11 @@ var init_usage_parser = __esm({
|
|
|
2498
2610
|
});
|
|
2499
2611
|
|
|
2500
2612
|
// src/storage/cache-manager.ts
|
|
2501
|
-
var
|
|
2613
|
+
var import_node_fs, import_node_os2, import_node_path2, DEFAULT_CACHE_PATH, DEFAULT_EXPIRY_MS, CacheManager;
|
|
2502
2614
|
var init_cache_manager = __esm({
|
|
2503
2615
|
"src/storage/cache-manager.ts"() {
|
|
2504
2616
|
"use strict";
|
|
2505
|
-
|
|
2617
|
+
import_node_fs = require("node:fs");
|
|
2506
2618
|
import_node_os2 = require("node:os");
|
|
2507
2619
|
import_node_path2 = require("node:path");
|
|
2508
2620
|
DEFAULT_CACHE_PATH = `${(0, import_node_os2.homedir)()}/.config/claude-scope/cache.json`;
|
|
@@ -2575,11 +2687,11 @@ var init_cache_manager = __esm({
|
|
|
2575
2687
|
* Load cache from file
|
|
2576
2688
|
*/
|
|
2577
2689
|
loadCache() {
|
|
2578
|
-
if (!(0,
|
|
2690
|
+
if (!(0, import_node_fs.existsSync)(this.cachePath)) {
|
|
2579
2691
|
return { sessions: {}, version: 1 };
|
|
2580
2692
|
}
|
|
2581
2693
|
try {
|
|
2582
|
-
const content = (0,
|
|
2694
|
+
const content = (0, import_node_fs.readFileSync)(this.cachePath, "utf-8");
|
|
2583
2695
|
return JSON.parse(content);
|
|
2584
2696
|
} catch {
|
|
2585
2697
|
return { sessions: {}, version: 1 };
|
|
@@ -2590,7 +2702,7 @@ var init_cache_manager = __esm({
|
|
|
2590
2702
|
*/
|
|
2591
2703
|
saveCache(cache) {
|
|
2592
2704
|
try {
|
|
2593
|
-
(0,
|
|
2705
|
+
(0, import_node_fs.writeFileSync)(this.cachePath, JSON.stringify(cache, null, 2), "utf-8");
|
|
2594
2706
|
} catch {
|
|
2595
2707
|
}
|
|
2596
2708
|
}
|
|
@@ -2600,8 +2712,8 @@ var init_cache_manager = __esm({
|
|
|
2600
2712
|
ensureCacheDir() {
|
|
2601
2713
|
try {
|
|
2602
2714
|
const dir = (0, import_node_path2.dirname)(this.cachePath);
|
|
2603
|
-
if (!(0,
|
|
2604
|
-
(0,
|
|
2715
|
+
if (!(0, import_node_fs.existsSync)(dir)) {
|
|
2716
|
+
(0, import_node_fs.mkdirSync)(dir, { recursive: true });
|
|
2605
2717
|
}
|
|
2606
2718
|
} catch {
|
|
2607
2719
|
}
|
|
@@ -2773,6 +2885,8 @@ var init_cache_metrics_widget = __esm({
|
|
|
2773
2885
|
lastSessionId;
|
|
2774
2886
|
cachedUsage;
|
|
2775
2887
|
// Cache parsed usage within render cycle
|
|
2888
|
+
cachedCumulativeCache;
|
|
2889
|
+
// Cumulative cache for session
|
|
2776
2890
|
constructor(theme) {
|
|
2777
2891
|
super();
|
|
2778
2892
|
this.theme = theme ?? DEFAULT_THEME;
|
|
@@ -2794,9 +2908,14 @@ var init_cache_metrics_widget = __esm({
|
|
|
2794
2908
|
/**
|
|
2795
2909
|
* Calculate cache metrics from context usage data
|
|
2796
2910
|
* Returns zero metrics if no usage data is available (widget should always be visible)
|
|
2911
|
+
*
|
|
2912
|
+
* @param usage - Current usage data (for total tokens calculation)
|
|
2913
|
+
* @param cumulativeCache - Cumulative cache data for the session (optional)
|
|
2797
2914
|
*/
|
|
2798
|
-
calculateMetrics(usage) {
|
|
2799
|
-
|
|
2915
|
+
calculateMetrics(usage, cumulativeCache) {
|
|
2916
|
+
const cacheRead = cumulativeCache?.cacheRead ?? usage?.cache_read_input_tokens ?? 0;
|
|
2917
|
+
const cacheWrite = cumulativeCache?.cacheCreation ?? usage?.cache_creation_input_tokens ?? 0;
|
|
2918
|
+
if (!usage && !cumulativeCache) {
|
|
2800
2919
|
return {
|
|
2801
2920
|
cacheRead: 0,
|
|
2802
2921
|
cacheWrite: 0,
|
|
@@ -2805,10 +2924,8 @@ var init_cache_metrics_widget = __esm({
|
|
|
2805
2924
|
savings: 0
|
|
2806
2925
|
};
|
|
2807
2926
|
}
|
|
2808
|
-
const
|
|
2809
|
-
const
|
|
2810
|
-
const inputTokens = usage.input_tokens ?? 0;
|
|
2811
|
-
const outputTokens = usage.output_tokens ?? 0;
|
|
2927
|
+
const inputTokens = usage?.input_tokens ?? 0;
|
|
2928
|
+
const outputTokens = usage?.output_tokens ?? 0;
|
|
2812
2929
|
const totalInputTokens = cacheRead + cacheWrite + inputTokens;
|
|
2813
2930
|
const totalTokens = totalInputTokens + outputTokens;
|
|
2814
2931
|
const hitRate = totalInputTokens > 0 ? Math.min(100, Math.round(cacheRead / totalInputTokens * 100)) : 0;
|
|
@@ -2845,18 +2962,21 @@ var init_cache_metrics_widget = __esm({
|
|
|
2845
2962
|
});
|
|
2846
2963
|
}
|
|
2847
2964
|
}
|
|
2848
|
-
|
|
2965
|
+
const hasRealUsage = usage && ((usage.input_tokens ?? 0) > 0 || (usage.output_tokens ?? 0) > 0 || (usage.cache_read_input_tokens ?? 0) > 0 || (usage.cache_creation_input_tokens ?? 0) > 0);
|
|
2966
|
+
if (!usage || !hasRealUsage) {
|
|
2849
2967
|
this.cachedUsage = await this.usageParser.parseLastUsage(data.transcript_path);
|
|
2850
2968
|
} else {
|
|
2851
2969
|
this.cachedUsage = void 0;
|
|
2852
2970
|
}
|
|
2971
|
+
this.cachedCumulativeCache = await this.usageParser.parseCumulativeCache(data.transcript_path);
|
|
2853
2972
|
}
|
|
2854
2973
|
/**
|
|
2855
2974
|
* Render the cache metrics display
|
|
2856
2975
|
*/
|
|
2857
2976
|
renderWithData(data, _context) {
|
|
2858
2977
|
let usage = data.context_window?.current_usage;
|
|
2859
|
-
|
|
2978
|
+
const hasRealUsage = usage && ((usage.input_tokens ?? 0) > 0 || (usage.output_tokens ?? 0) > 0 || (usage.cache_read_input_tokens ?? 0) > 0 || (usage.cache_creation_input_tokens ?? 0) > 0);
|
|
2979
|
+
if ((!usage || !hasRealUsage) && this.cachedUsage) {
|
|
2860
2980
|
usage = this.cachedUsage;
|
|
2861
2981
|
}
|
|
2862
2982
|
if (!usage) {
|
|
@@ -2865,7 +2985,8 @@ var init_cache_metrics_widget = __esm({
|
|
|
2865
2985
|
usage = cached.usage;
|
|
2866
2986
|
}
|
|
2867
2987
|
}
|
|
2868
|
-
const
|
|
2988
|
+
const cumulativeCacheToUse = this.cachedCumulativeCache;
|
|
2989
|
+
const metrics = this.calculateMetrics(usage, cumulativeCacheToUse);
|
|
2869
2990
|
if (!metrics) {
|
|
2870
2991
|
return null;
|
|
2871
2992
|
}
|
|
@@ -3416,7 +3537,8 @@ var init_context_widget = __esm({
|
|
|
3416
3537
|
});
|
|
3417
3538
|
}
|
|
3418
3539
|
}
|
|
3419
|
-
|
|
3540
|
+
const hasRealUsage = current_usage && ((current_usage.input_tokens ?? 0) > 0 || (current_usage.output_tokens ?? 0) > 0 || (current_usage.cache_read_input_tokens ?? 0) > 0 || (current_usage.cache_creation_input_tokens ?? 0) > 0);
|
|
3541
|
+
if (!current_usage || !hasRealUsage) {
|
|
3420
3542
|
this.cachedUsage = await this.usageParser.parseLastUsage(data.transcript_path);
|
|
3421
3543
|
} else {
|
|
3422
3544
|
this.cachedUsage = void 0;
|
|
@@ -3425,7 +3547,8 @@ var init_context_widget = __esm({
|
|
|
3425
3547
|
renderWithData(data, _context) {
|
|
3426
3548
|
const { current_usage, context_window_size } = data.context_window;
|
|
3427
3549
|
let usage = current_usage;
|
|
3428
|
-
|
|
3550
|
+
const hasRealUsage = usage && ((usage.input_tokens ?? 0) > 0 || (usage.output_tokens ?? 0) > 0 || (usage.cache_read_input_tokens ?? 0) > 0 || (usage.cache_creation_input_tokens ?? 0) > 0);
|
|
3551
|
+
if ((!usage || !hasRealUsage) && this.cachedUsage) {
|
|
3429
3552
|
usage = this.cachedUsage;
|
|
3430
3553
|
}
|
|
3431
3554
|
if (!usage) {
|
|
@@ -26259,8 +26382,8 @@ init_renderer();
|
|
|
26259
26382
|
init_widget_registry();
|
|
26260
26383
|
|
|
26261
26384
|
// src/providers/transcript-provider.ts
|
|
26262
|
-
var
|
|
26263
|
-
var
|
|
26385
|
+
var import_node_fs2 = require("node:fs");
|
|
26386
|
+
var import_node_readline = require("node:readline");
|
|
26264
26387
|
var TranscriptProvider = class {
|
|
26265
26388
|
MAX_TOOLS = 20;
|
|
26266
26389
|
/**
|
|
@@ -26269,13 +26392,13 @@ var TranscriptProvider = class {
|
|
|
26269
26392
|
* @returns Array of tool entries, limited to last 20
|
|
26270
26393
|
*/
|
|
26271
26394
|
async parseTools(transcriptPath) {
|
|
26272
|
-
if (!(0,
|
|
26395
|
+
if (!(0, import_node_fs2.existsSync)(transcriptPath)) {
|
|
26273
26396
|
return [];
|
|
26274
26397
|
}
|
|
26275
26398
|
const toolMap = /* @__PURE__ */ new Map();
|
|
26276
26399
|
try {
|
|
26277
|
-
const fileStream = (0,
|
|
26278
|
-
const rl = (0,
|
|
26400
|
+
const fileStream = (0, import_node_fs2.createReadStream)(transcriptPath, { encoding: "utf-8" });
|
|
26401
|
+
const rl = (0, import_node_readline.createInterface)({
|
|
26279
26402
|
input: fileStream,
|
|
26280
26403
|
crlfDelay: Infinity
|
|
26281
26404
|
});
|
|
@@ -26554,13 +26677,13 @@ async function routeCommand(command) {
|
|
|
26554
26677
|
}
|
|
26555
26678
|
|
|
26556
26679
|
// src/config/config-loader.ts
|
|
26557
|
-
var
|
|
26680
|
+
var import_node_fs4 = require("node:fs");
|
|
26558
26681
|
var import_promises2 = require("node:fs/promises");
|
|
26559
26682
|
var import_node_os4 = require("node:os");
|
|
26560
26683
|
var import_node_path4 = require("node:path");
|
|
26561
26684
|
|
|
26562
26685
|
// src/config/default-config-generator.ts
|
|
26563
|
-
var
|
|
26686
|
+
var import_node_fs3 = require("node:fs");
|
|
26564
26687
|
var import_node_os3 = require("node:os");
|
|
26565
26688
|
var import_node_path3 = require("node:path");
|
|
26566
26689
|
function getDefaultConfigPath() {
|
|
@@ -26568,15 +26691,15 @@ function getDefaultConfigPath() {
|
|
|
26568
26691
|
}
|
|
26569
26692
|
async function ensureDefaultConfig() {
|
|
26570
26693
|
const configPath = getDefaultConfigPath();
|
|
26571
|
-
if ((0,
|
|
26694
|
+
if ((0, import_node_fs3.existsSync)(configPath)) {
|
|
26572
26695
|
return;
|
|
26573
26696
|
}
|
|
26574
26697
|
const configDir = (0, import_node_path3.join)((0, import_node_os3.homedir)(), ".claude-scope");
|
|
26575
|
-
if (!(0,
|
|
26576
|
-
(0,
|
|
26698
|
+
if (!(0, import_node_fs3.existsSync)(configDir)) {
|
|
26699
|
+
(0, import_node_fs3.mkdirSync)(configDir, { recursive: true });
|
|
26577
26700
|
}
|
|
26578
26701
|
const defaultConfig = generateRichLayout("balanced", "dracula");
|
|
26579
|
-
(0,
|
|
26702
|
+
(0, import_node_fs3.writeFileSync)(configPath, JSON.stringify(defaultConfig, null, 2), "utf-8");
|
|
26580
26703
|
}
|
|
26581
26704
|
|
|
26582
26705
|
// src/config/config-loader.ts
|
|
@@ -26589,7 +26712,7 @@ function getConfigPath() {
|
|
|
26589
26712
|
async function loadWidgetConfig() {
|
|
26590
26713
|
const configPath = getConfigPath();
|
|
26591
26714
|
await ensureDefaultConfig();
|
|
26592
|
-
if (!(0,
|
|
26715
|
+
if (!(0, import_node_fs4.existsSync)(configPath)) {
|
|
26593
26716
|
return null;
|
|
26594
26717
|
}
|
|
26595
26718
|
try {
|