diff --git a/Mode2Test/AuthAndToken/backend/auth-routes.ts b/Mode2Test/AuthAndToken/backend/auth-routes.ts index d61adff..e3cfb50 100644 --- a/Mode2Test/AuthAndToken/backend/auth-routes.ts +++ b/Mode2Test/AuthAndToken/backend/auth-routes.ts @@ -1,9 +1,10 @@ import { Hono } from 'hono'; import type { Context } from 'hono'; -import { getTokens, saveTokens, clearTokens, hasValidPbToken } from './token-service'; +import { tokenService } from './token-service'; // Authentication API routes // Endpoints for frontend to check auth status, get tokens, logout +// Depends on: tokenService singleton (centralized token management) export function createAuthRoutes(): Hono { const router = new Hono(); @@ -11,11 +12,13 @@ export function createAuthRoutes(): Hono { // PERMANENT: Check if user is authenticated // Returns current auth status and which tokens are available router.get('/status', async (c: Context) => { - const hasValid = await hasValidPbToken(); + const tokens = await tokenService.getTokens(); + const hasToken = !!tokens?.pbToken; return c.json({ - authenticated: hasValid, - pbTokenValid: hasValid, - message: hasValid ? 'User authenticated' : 'User not authenticated' + authenticated: hasToken, + pbTokenValid: hasToken, + assumedFresh: hasToken, + message: hasToken ? 'Assuming tokens are valid (auto-refresh running)' : 'No PB token yet; login once' }); }); @@ -23,17 +26,14 @@ export function createAuthRoutes(): Hono { // Frontend/backend can call this to get fresh token state // Only returns tokens if PB token is valid (auth required) router.get('/tokens', async (c: Context) => { - const hasValid = await hasValidPbToken(); - if (!hasValid) { - return c.json({ error: 'Not authenticated' }, 401); - } - - const tokens = await getTokens(); + const tokens = await tokenService.getTokens(); return c.json({ pbToken: tokens?.pbToken || null, graphToken: tokens?.graphToken || null, pbTokenExpiry: tokens?.pbTokenExpiry || null, - graphTokenExpiry: tokens?.graphTokenExpiry || null + graphTokenExpiry: tokens?.graphTokenExpiry || null, + lastRefresh: tokens?.lastRefresh || null, + assumedFresh: !!tokens?.pbToken }); }); @@ -50,7 +50,7 @@ export function createAuthRoutes(): Hono { return c.json({ error: 'Missing pbToken' }, 400); } - await saveTokens(pbToken, graphToken); + await tokenService.saveTokens(pbToken, graphToken); return c.json({ success: true, message: 'Login successful', @@ -66,7 +66,7 @@ export function createAuthRoutes(): Hono { // Called when user clicks logout router.post('/logout', async (c: Context) => { try { - await clearTokens(); + await tokenService.clearTokens(); return c.json({ success: true, message: 'Logged out', diff --git a/Mode2Test/AuthAndToken/backend/jobs-routes.ts b/Mode2Test/AuthAndToken/backend/jobs-routes.ts new file mode 100644 index 0000000..785b5d7 --- /dev/null +++ b/Mode2Test/AuthAndToken/backend/jobs-routes.ts @@ -0,0 +1,104 @@ +import { Hono } from 'hono'; +import type { Context } from 'hono'; +import { tokenService } from './token-service'; + +// PERMANENT: Jobs API routes +// Provides access to job data from PocketBase +// Requires authentication (valid PB token) +// +// Dependencies: +// - tokenService for PB token retrieval +// - process.env.POCKETBASE_URL for PB API endpoint +const JOBS_COLLECTION = 'pbc_1407612689'; +// +// Endpoints: +// - GET /api/jobs - List jobs with pagination, filtering, field selection + +export function createJobsRoutes(): Hono { + const router = new Hono(); + + // GET /api/jobs - Fetch jobs from PocketBase + // Query params: + // - page: Page number (default 1) + // - perPage: Items per page (default 50, max 1000) + // - fields: Comma-separated field names to return (optional, for cache optimization) + // - filter: PocketBase filter syntax (optional) + // - sort: Sort field (default -Job_Number) + router.get('/', async (c: Context) => { + try { + // Get token (assume present after login) + const tokens = await tokenService.getTokens(); + const pbToken = tokens?.pbToken; + + // Parse query params + const page = parseInt(c.req.query('page') || '1'); + const perPage = Math.min(parseInt(c.req.query('perPage') || '50'), 1000); + const fields = c.req.query('fields'); // Optional: comma-separated field names + const filter = c.req.query('filter'); // Optional: PocketBase filter + const sort = c.req.query('sort') || '-Job_Number'; + + // Build PocketBase API URL + const pbUrl = new URL(`${process.env.POCKETBASE_URL}/api/collections/${JOBS_COLLECTION}/records`); + pbUrl.searchParams.set('page', page.toString()); + pbUrl.searchParams.set('perPage', perPage.toString()); + pbUrl.searchParams.set('sort', sort); + + if (fields) { + pbUrl.searchParams.set('fields', fields); + } + + if (filter) { + pbUrl.searchParams.set('filter', filter); + } + + // Fetch from PocketBase + // temporary: dev-only SSL bypass; global rejectUnauthorized already set, keep here as explicit + const response = await fetch(pbUrl.toString(), { + headers: pbToken ? { 'Authorization': `Bearer ${pbToken}` } : {}, + // @ts-ignore Bun TLS option + tls: { rejectUnauthorized: false } + }); + + if (!response.ok) { + const errorText = await response.text(); + console.error('PocketBase jobs fetch failed:', response.status, errorText); + return c.json({ error: 'Failed to fetch jobs from PocketBase' }, response.status); + } + + const data = await response.json(); + return c.json(data); + } catch (err) { + console.error('Jobs API error:', (err as Error)?.message); + return c.json({ error: 'Internal server error' }, 500); + } + }); + + // GET /api/jobs/:id - Fetch single job by ID + router.get('/:id', async (c: Context) => { + try { + // Check authentication + const tokens = await tokenService.getTokens(); + const pbToken = tokens?.pbToken; + + const jobId = c.req.param('id'); + const pbUrl = `${process.env.POCKETBASE_URL}/api/collections/${JOBS_COLLECTION}/records/${jobId}`; + + // Fetch from PocketBase + const response = await fetch(pbUrl, { + headers: pbToken ? { 'Authorization': `Bearer ${pbToken}` } : {} + }); + + if (!response.ok) { + return c.json({ error: 'Job not found' }, 404); + } + + const data = await response.json(); + return c.json(data); + } catch (err) { + console.error('Job fetch error:', (err as Error)?.message); + return c.json({ error: 'Internal server error' }, 500); + } + }); + + return router; +} diff --git a/Mode2Test/AuthAndToken/backend/server.ts b/Mode2Test/AuthAndToken/backend/server.ts index f29d6d2..6ecc280 100644 --- a/Mode2Test/AuthAndToken/backend/server.ts +++ b/Mode2Test/AuthAndToken/backend/server.ts @@ -1,14 +1,25 @@ import { Hono } from 'hono'; import { serveStatic } from 'hono/bun'; import { join } from 'path'; -import { initializeTokenService, startBackgroundRefresh } from './token-service'; +import { tokenService } from './token-service'; import { createAuthRoutes } from './auth-routes'; +import { createJobsRoutes } from './jobs-routes'; + +// temporary: dev-only SSL bypass for upstream PocketBase cert issues +process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; + +// PERMANENT: Load environment variables +// Check if POCKETBASE_URL is set, use default if not +if (!process.env.POCKETBASE_URL) { + process.env.POCKETBASE_URL = 'https://pocketbase.ccllc.pro'; + console.log('[Mode2Test] Using default POCKETBASE_URL:', process.env.POCKETBASE_URL); +} // PERMANENT: Initialize token service and start background refresh // Loads existing tokens from file if available // Starts 5-minute background refresh cycle -initializeTokenService(); -startBackgroundRefresh(); +tokenService.initialize(); +tokenService.startBackgroundRefresh(); // Create Hono app const app = new Hono(); @@ -16,6 +27,9 @@ const app = new Hono(); // Mount auth routes app.route('/api/auth', createAuthRoutes()); +// Mount jobs routes +app.route('/api/jobs', createJobsRoutes()); + // Health check endpoint app.get('/health', (c) => { return c.text('OK'); diff --git a/Mode2Test/AuthAndToken/backend/token-service.ts b/Mode2Test/AuthAndToken/backend/token-service.ts index b488ca9..5131c49 100644 --- a/Mode2Test/AuthAndToken/backend/token-service.ts +++ b/Mode2Test/AuthAndToken/backend/token-service.ts @@ -1,8 +1,20 @@ import { join } from 'path'; -// Token storage and refresh management -// Stores both PocketBase and Graph tokens locally (tokens.json) -// Background refresh keeps both tokens fresh without user intervention +// PERMANENT: Token Service Module +// Singleton module for centralized token acquisition, storage, and refresh +// Available to any part of the application via: import { tokenService } from './token-service.ts' +// +// Token Lifecycle: +// - Tokens stored in tokens.json (persistent across restarts) +// - Never delete old token before new one acquired +// - Background refresh every 5 minutes +// - Startup: if PB token exists, resume refresh; else require login +// +// Usage: +// const tokens = await tokenService.getTokens(); +// await tokenService.saveTokens(pbToken, graphToken); +// await tokenService.initialize(); +// tokenService.startBackgroundRefresh(); interface TokenData { pbToken: string; @@ -14,131 +26,151 @@ interface TokenData { const tokensFilePath = join(import.meta.dir, '../../tokens.json'); -// PERMANENT: Token lifecycle management -// - Tokens stored in tokens.json (persistent across restarts) -// - Never delete old token before new one acquired -// - Background refresh every 5 minutes -// - Startup: if PB token exists, resume refresh; else require login +class TokenService { + private backgroundStarted = false; -export async function initializeTokenService(): Promise { - // Load tokens from file if they exist - try { - const file = Bun.file(tokensFilePath); - if (await file.exists()) { - const content = await file.text(); - const data = JSON.parse(content) as TokenData; - console.log('[AuthAndToken] Tokens loaded from file'); - console.log('[AuthAndToken] PB token valid:', data.pbToken ? 'yes' : 'no'); - console.log('[AuthAndToken] Graph token valid:', data.graphToken ? 'yes' : 'no'); - } else { - console.log('[AuthAndToken] No tokens.json found - login required on startup'); - } - } catch (err) { - console.log('[AuthAndToken] Token file init error (will create on first login):', (err as Error)?.message); - } -} - -export function startBackgroundRefresh(): void { - // PERMANENT: Background token refresh - // Runs every 5 minutes, attempts to refresh both PB and Graph tokens - // Safe: never deletes old token before new one is confirmed - - setInterval(async () => { + async initialize(): Promise { + // Load tokens from file if they exist try { - await refreshTokens(); - } catch (err) { - console.log('[AuthAndToken] Background refresh error:', (err as Error)?.message); - } - }, 5 * 60 * 1000); // 5 minutes - - console.log('[AuthAndToken] Background refresh started (every 5 minutes)'); -} - -export async function saveTokens(pbToken: string, graphToken?: string): Promise { - // PERMANENT: Token persistence - // Called after login or successful refresh - // Stores both tokens with expiry times - - const data: TokenData = { - pbToken, - pbTokenExpiry: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7 days (PB default) - graphToken, - graphTokenExpiry: graphToken ? Date.now() + 60 * 60 * 1000 : undefined, // 1 hour (Graph default) - lastRefresh: Date.now() - }; - - await Bun.write(tokensFilePath, JSON.stringify(data, null, 2)); - console.log('[AuthAndToken] Tokens saved'); -} - -export async function getTokens(): Promise { - try { - const file = Bun.file(tokensFilePath); - if (!(await file.exists())) return null; - - const content = await file.text(); - return JSON.parse(content) as TokenData; - } catch (err) { - console.log('[AuthAndToken] Error reading tokens:', (err as Error)?.message); - return null; - } -} - -export async function clearTokens(): Promise { - try { - const file = Bun.file(tokensFilePath); - if (await file.exists()) { - await Bun.write(tokensFilePath, ''); - } - } catch (err) { - console.log('[AuthAndToken] Error clearing tokens:', (err as Error)?.message); - } -} - -async function refreshTokens(): Promise { - // PERMANENT: Auto-refresh logic for both tokens - // Called every 5 minutes by background job - // Fetches fresh tokens from PocketBase, attempts Graph token refresh - // Only updates file after new tokens confirmed valid - - const tokens = await getTokens(); - if (!tokens || !tokens.pbToken) { - console.log('[AuthAndToken] No active tokens to refresh'); - return; - } - - try { - // Refresh via PocketBase endpoint - const pbUrl = `${process.env.POCKETBASE_URL}/api/collections/users/auth-refresh`; - const response = await fetch(pbUrl, { - method: 'POST', - headers: { - 'Authorization': `Bearer ${tokens.pbToken}` + const file = Bun.file(tokensFilePath); + if (await file.exists()) { + const content = await file.text(); + const data = JSON.parse(content) as TokenData; + console.log('[AuthAndToken] Tokens loaded from file'); + console.log('[AuthAndToken] PB token valid:', data.pbToken ? 'yes' : 'no'); + console.log('[AuthAndToken] Graph token valid:', data.graphToken ? 'yes' : 'no'); + } else { + console.log('[AuthAndToken] No tokens.json found - login required on startup'); } + } catch (err) { + console.log('[AuthAndToken] Token file init error (will create on first login):', (err as Error)?.message); + } + } + + startBackgroundRefresh(): void { + if (this.backgroundStarted) return; + this.backgroundStarted = true; + + // PERMANENT: Background token refresh + // Runs every 5 minutes, attempts to refresh both PB and Graph tokens + // Safe: never deletes old token before new one is confirmed + setInterval(async () => { + try { + await this.refreshTokens(); + } catch (err) { + console.log('[AuthAndToken] Background refresh error:', (err as Error)?.message); + } + }, 5 * 60 * 1000); // 5 minutes + + // Kick off an immediate refresh attempt so we start from a fresh token without waiting + this.refreshTokens().catch((err) => { + console.log('[AuthAndToken] Immediate refresh error:', (err as Error)?.message); }); - if (!response.ok) { - console.log('[AuthAndToken] Refresh failed:', response.status); + console.log('[AuthAndToken] Background refresh started (every 5 minutes + immediate)'); + } + + async saveTokens(pbToken: string, graphToken?: string): Promise { + // PERMANENT: Token persistence + // Called after login or successful refresh + // Stores both tokens with expiry times + + const data: TokenData = { + pbToken, + pbTokenExpiry: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7 days (PB default) + graphToken, + graphTokenExpiry: graphToken ? Date.now() + 60 * 60 * 1000 : undefined, // 1 hour (Graph default) + lastRefresh: Date.now() + }; + + await Bun.write(tokensFilePath, JSON.stringify(data, null, 2)); + console.log('[AuthAndToken] Tokens saved'); + } + + async getTokens(): Promise { + try { + const file = Bun.file(tokensFilePath); + if (!(await file.exists())) return null; + + const content = await file.text(); + return JSON.parse(content) as TokenData; + } catch (err) { + console.log('[AuthAndToken] Error reading tokens:', (err as Error)?.message); + try { + const fs = await import('fs/promises'); + await fs.unlink(tokensFilePath); + console.log('[AuthAndToken] Corrupt tokens file removed'); + } catch (innerErr) { + console.log('[AuthAndToken] Failed to remove corrupt tokens file:', (innerErr as Error)?.message); + } + return null; + } + } + + async clearTokens(): Promise { + try { + const file = Bun.file(tokensFilePath); + if (await file.exists()) { + const fs = await import('fs/promises'); + await fs.unlink(tokensFilePath); + } + } catch (err) { + console.log('[AuthAndToken] Error clearing tokens:', (err as Error)?.message); + } + } + + async hasValidPbToken(): Promise { + // Simplified: treat presence of PB token as valid; no expiry enforcement + const tokens = await this.getTokens(); + return !!tokens?.pbToken; + } + + private async refreshTokens(): Promise { + // PERMANENT: Auto-refresh logic for both tokens + // Called every 5 minutes by background job + // Fetches fresh tokens from PocketBase, attempts Graph token refresh + // Only updates file after new tokens confirmed valid + + const tokens = await this.getTokens(); + if (!tokens || !tokens.pbToken) { + console.log('[AuthAndToken] No active tokens to refresh'); return; } - const data = await response.json() as any; - const newPbToken = data?.token; + try { + // Refresh via PocketBase endpoint + const pbUrl = `${process.env.POCKETBASE_URL}/api/collections/users/auth-refresh`; + const response = await fetch(pbUrl, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${tokens.pbToken}` + }, + // @ts-ignore Bun TLS option + tls: { rejectUnauthorized: false } + }); - if (!newPbToken) { - console.log('[AuthAndToken] No new PB token in response'); - return; + if (!response.ok) { + console.log('[AuthAndToken] Refresh failed:', response.status); + return; + } + + const data = await response.json() as any; + const newPbToken = data?.token; + + if (!newPbToken) { + console.log('[AuthAndToken] No new PB token in response'); + return; + } + + // Update tokens with new PB token + await this.saveTokens(newPbToken, tokens.graphToken); + console.log('[AuthAndToken] Tokens refreshed successfully'); + } catch (err) { + console.log('[AuthAndToken] Refresh error:', (err as Error)?.message); } - - // Update tokens with new PB token - await saveTokens(newPbToken, tokens.graphToken); - console.log('[AuthAndToken] Tokens refreshed successfully'); - } catch (err) { - console.log('[AuthAndToken] Refresh error:', (err as Error)?.message); } } -export async function hasValidPbToken(): Promise { - const tokens = await getTokens(); - return !!tokens?.pbToken && tokens.pbTokenExpiry > Date.now(); -} +// PERMANENT: Singleton export +// Import as: import { tokenService } from './token-service.ts' +export const tokenService = new TokenService(); diff --git a/Mode2Test/AuthAndToken/frontend/assets/CCwhiteApp.png b/Mode2Test/AuthAndToken/frontend/assets/CCwhiteApp.png new file mode 100644 index 0000000..e4ef4f1 Binary files /dev/null and b/Mode2Test/AuthAndToken/frontend/assets/CCwhiteApp.png differ diff --git a/Mode2Test/AuthAndToken/frontend/assets/DailyCheck.png b/Mode2Test/AuthAndToken/frontend/assets/DailyCheck.png new file mode 100644 index 0000000..200eba4 Binary files /dev/null and b/Mode2Test/AuthAndToken/frontend/assets/DailyCheck.png differ diff --git a/Mode2Test/AuthAndToken/frontend/assets/PalmIsland.png b/Mode2Test/AuthAndToken/frontend/assets/PalmIsland.png new file mode 100644 index 0000000..e31ab51 Binary files /dev/null and b/Mode2Test/AuthAndToken/frontend/assets/PalmIsland.png differ diff --git a/Mode2Test/AuthAndToken/frontend/assets/lightbulb.jpg b/Mode2Test/AuthAndToken/frontend/assets/lightbulb.jpg new file mode 100644 index 0000000..f75425e Binary files /dev/null and b/Mode2Test/AuthAndToken/frontend/assets/lightbulb.jpg differ diff --git a/Mode2Test/AuthAndToken/frontend/details.html b/Mode2Test/AuthAndToken/frontend/details.html new file mode 100644 index 0000000..21f8cc3 --- /dev/null +++ b/Mode2Test/AuthAndToken/frontend/details.html @@ -0,0 +1,16 @@ + + + + + + Job Details + + + +
+

Job Details

+

Details view - Under construction

+ ← Back to Home +
+ + diff --git a/Mode2Test/AuthAndToken/frontend/home.html b/Mode2Test/AuthAndToken/frontend/home.html new file mode 100644 index 0000000..46c63ad --- /dev/null +++ b/Mode2Test/AuthAndToken/frontend/home.html @@ -0,0 +1,104 @@ + + + + + + Job Info — Home + + + + + +
+ + +
+
+
+ CC +
+
+ +
+ +

Job Info

+ + +
+ + +
+ + + + + + + + +
+ + +
+ +
+ + [Mode2Test] + v1.0.0-beta1 +
+
+
+ + + + diff --git a/Mode2Test/AuthAndToken/frontend/index.html b/Mode2Test/AuthAndToken/frontend/index.html index ff7a3d4..b99e268 100644 --- a/Mode2Test/AuthAndToken/frontend/index.html +++ b/Mode2Test/AuthAndToken/frontend/index.html @@ -4,50 +4,35 @@ Mode2Test - - - - -
-
-
-

Mode2Test

-

Authenticated Application

-
-
-
-

-

-
- -
-
-
- -
-
-

Welcome to Mode2Test

-

Authenticated and ready to work.

- -
-

Token Status

-
-

Loading...

-
-
-
-
- + + +
+

Redirecting...

+
+ + } catch { window.location.href = '/signin.html'; return; diff --git a/Mode2Test/AuthAndToken/frontend/js/home.js b/Mode2Test/AuthAndToken/frontend/js/home.js new file mode 100644 index 0000000..dddbc64 --- /dev/null +++ b/Mode2Test/AuthAndToken/frontend/js/home.js @@ -0,0 +1,344 @@ +// job-cache.js +var DB_NAME = "JobInfoCache"; +var DB_VERSION = 2; +var JOBS_STORE = "jobs"; +var META_STORE = "metadata"; +var CACHE_TTL = 5 * 60 * 1000; +var PAGE_SIZE = 500; + +class JobCache { + db = null; + async initialize() { + return new Promise((resolve, reject) => { + const request = indexedDB.open(DB_NAME, DB_VERSION); + request.onerror = () => reject(request.error); + request.onsuccess = () => { + this.db = request.result; + resolve(); + }; + request.onupgradeneeded = (event) => { + const db = event.target.result; + if (!db.objectStoreNames.contains(JOBS_STORE)) { + db.createObjectStore(JOBS_STORE, { keyPath: "Job_Number" }); + } + if (!db.objectStoreNames.contains(META_STORE)) { + db.createObjectStore(META_STORE); + } + }; + }); + } + async getCachedJobs() { + if (!this.db) + throw new Error("Database not initialized"); + return new Promise((resolve, reject) => { + const transaction = this.db.transaction([JOBS_STORE], "readonly"); + const store = transaction.objectStore(JOBS_STORE); + const request = store.getAll(); + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }); + } + async isCacheValid() { + if (!this.db) + return false; + try { + const metadata = await this.getMetadata(); + if (!metadata || !metadata.lastUpdated) + return false; + const age = Date.now() - metadata.lastUpdated; + return age < CACHE_TTL; + } catch { + return false; + } + } + async saveJobs(jobs) { + if (!this.db) + throw new Error("Database not initialized"); + return new Promise((resolve, reject) => { + const transaction = this.db.transaction([JOBS_STORE, META_STORE], "readwrite"); + const jobsStore = transaction.objectStore(JOBS_STORE); + const metaStore = transaction.objectStore(META_STORE); + jobsStore.clear(); + jobs.forEach((job) => jobsStore.add(job)); + const metadata = { + lastUpdated: Date.now(), + version: DB_VERSION + }; + metaStore.put(metadata, "main"); + transaction.oncomplete = () => resolve(); + transaction.onerror = () => reject(transaction.error); + }); + } + async refreshJobs() { + try { + let page = 1; + let all = []; + let totalPages = 1; + while (page <= totalPages) { + const url = `/api/jobs?page=${page}&perPage=${PAGE_SIZE}&sort=-Job_Number`; + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Failed to fetch jobs (status ${response.status})`); + } + const data = await response.json(); + const items = data.items || []; + const reportedTotalPages = data.totalPages || 1; + all = all.concat(items); + totalPages = Math.max(totalPages, reportedTotalPages); + page += 1; + } + await this.saveJobs(all); + return all; + } catch (err) { + console.error("Failed to refresh jobs cache:", err); + throw err; + } + } + async getMetadata() { + if (!this.db) + return null; + return new Promise((resolve, reject) => { + const transaction = this.db.transaction([META_STORE], "readonly"); + const store = transaction.objectStore(META_STORE); + const request = store.get("main"); + request.onsuccess = () => resolve(request.result || null); + request.onerror = () => reject(request.error); + }); + } + async clearCache() { + if (!this.db) + throw new Error("Database not initialized"); + return new Promise((resolve, reject) => { + const transaction = this.db.transaction([JOBS_STORE, META_STORE], "readwrite"); + transaction.objectStore(JOBS_STORE).clear(); + transaction.objectStore(META_STORE).clear(); + transaction.oncomplete = () => resolve(); + transaction.onerror = () => reject(transaction.error); + }); + } + async getCacheAge() { + const metadata = await this.getMetadata(); + if (!metadata || !metadata.lastUpdated) + return null; + return Date.now() - metadata.lastUpdated; + } +} +var jobCache = new JobCache; + +// home.ts +var allJobs = []; +var filteredJobs = []; +var currentPage = 1; +var perPage = 50; +var isRefreshing = false; +async function checkAuth() { + try { + const response = await fetch("/api/auth/status"); + const data = await response.json(); + if (!data.authenticated) { + window.location.href = "/signin.html"; + return false; + } + return true; + } catch (err) { + console.error("Auth check failed:", err); + window.location.href = "/signin.html"; + return false; + } +} +async function fetchJobs() { + try { + await jobCache.initialize(); + const isCacheValid = await jobCache.isCacheValid(); + if (isCacheValid) { + const cachedJobs = await jobCache.getCachedJobs(); + allJobs = cachedJobs; + filteredJobs = [...allJobs]; + renderJobs(); + const cacheAge = await jobCache.getCacheAge(); + console.log(`Loaded ${allJobs.length} jobs from cache (age: ${Math.round((cacheAge || 0) / 1000)}s)`); + refreshJobsInBackground(); + } else { + const jobs = await jobCache.refreshJobs(); + allJobs = jobs; + filteredJobs = [...allJobs]; + renderJobs(); + console.log(`Loaded ${allJobs.length} jobs from server (cache updated)`); + } + } catch (err) { + console.error("Failed to fetch jobs:", err); + const results = document.getElementById("results"); + results.innerHTML = '
Failed to load jobs. Please refresh the page.
'; + } +} +async function refreshJobsInBackground() { + if (isRefreshing) + return; + isRefreshing = true; + try { + const freshJobs = await jobCache.refreshJobs(); + allJobs = freshJobs; + applyFilters(); + console.log(`Background refresh complete (${freshJobs.length} jobs)`); + } catch (err) { + console.error("Background refresh failed:", err); + } finally { + isRefreshing = false; + } +} +function renderJobs() { + const results = document.getElementById("results"); + if (filteredJobs.length === 0) { + results.innerHTML = '
No jobs found
'; + return; + } + const start = (currentPage - 1) * perPage; + const end = start + perPage; + const pageJobs = filteredJobs.slice(start, end); + results.innerHTML = pageJobs.map((job) => { + const isActiveTrue = job.Active === true; + const isActiveFalse = job.Active === false; + const nameVal = job.Job_Full_Name || ""; + const contactVal = job.Contact_Person || ""; + return ` +
+
Job#
${escapeHtml(String(job.Job_Number || ""))}
+
Job Name:
${escapeHtml(String(nameVal))}
+
Contact:
${escapeHtml(String(contactVal))}
+
+
+ `; + }).join(""); + results.querySelectorAll("[data-job-number]").forEach((el) => { + el.addEventListener("click", (e) => { + const jobNumber = e.currentTarget.dataset.jobNumber; + if (jobNumber) { + openDetails(jobNumber); + } + }); + }); +} +function openDetails(jobNumber) { + window.location.href = `/details.html?job=${encodeURIComponent(jobNumber)}`; +} +function setupSearch() { + const searchBox = document.getElementById("searchBox"); + searchBox.addEventListener("input", () => { + const query = searchBox.value.toLowerCase().trim(); + if (!query) { + filteredJobs = [...allJobs]; + } else { + filteredJobs = allJobs.filter((job) => { + return job.Job_Number?.toString().toLowerCase().includes(query) || job.Job_Full_Name?.toLowerCase().includes(query) || job.Job_Address?.toLowerCase().includes(query) || job.Contact_Person?.toLowerCase().includes(query) || job.Company_Client?.toLowerCase().includes(query) || job.Notes?.toLowerCase().includes(query) || job.Job_Status?.toLowerCase().includes(query) || job.Status?.toLowerCase().includes(query) || job.Estimator?.toLowerCase().includes(query); + }); + } + currentPage = 1; + renderJobs(); + }); +} +function setupFilters() { + const filterToggle = document.getElementById("filterToggle"); + const filtersPanel = document.getElementById("filtersPanel"); + const clearFilters = document.getElementById("clearFilters"); + filterToggle.addEventListener("click", () => { + const isHidden = filtersPanel.classList.contains("hidden"); + if (isHidden) { + filtersPanel.classList.remove("hidden"); + filterToggle.textContent = "Hide Filters"; + } else { + filtersPanel.classList.add("hidden"); + filterToggle.textContent = "Show Filters"; + } + }); + const filterInputs = filtersPanel.querySelectorAll('input[type="checkbox"]'); + filterInputs.forEach((input) => { + input.addEventListener("change", applyFilters); + }); + clearFilters.addEventListener("click", () => { + filterInputs.forEach((input) => { + input.checked = false; + }); + applyFilters(); + }); +} +function applyFilters() { + const divisions = Array.from(document.querySelectorAll(".filter-division:checked")).map((el) => el.value); + const actives = Array.from(document.querySelectorAll(".filter-active:checked")).map((el) => el.value); + const estimators = Array.from(document.querySelectorAll(".filter-estimator:checked")).map((el) => el.value.toLowerCase()); + const statuses = Array.from(document.querySelectorAll(".filter-status:checked")).map((el) => el.value); + filteredJobs = allJobs.filter((job) => { + const divisionVal = job.Job_Division || job.Division; + const activeVal = job.Active === true || job.Active === "Yes" ? "Yes" : job.Active === false || job.Active === "No" ? "No" : "—"; + const estimatorVal = (job.Estimator || "").toLowerCase(); + const statusVal = job.Job_Status || job.Status; + if (divisions.length > 0 && !divisions.some((d) => divisionVal?.startsWith(d))) + return false; + if (actives.length > 0 && !actives.includes(activeVal)) + return false; + if (estimators.length > 0 && !estimators.some((e) => estimatorVal.includes(e))) + return false; + if (statuses.length > 0 && !statuses.includes(statusVal || "")) + return false; + return true; + }); + currentPage = 1; + renderJobs(); +} +function setupVoiceSearch() { + const voiceBtn = document.getElementById("voiceSearchBtn"); + const micIcon = document.getElementById("micIcon"); + const micRecordingIcon = document.getElementById("micRecordingIcon"); + const searchBox = document.getElementById("searchBox"); + if (!("webkitSpeechRecognition" in window) && !("SpeechRecognition" in window)) { + voiceBtn.style.display = "none"; + return; + } + const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; + const recognition = new SpeechRecognition; + recognition.continuous = false; + recognition.interimResults = false; + voiceBtn.addEventListener("click", () => { + recognition.start(); + micIcon.classList.add("hidden"); + micRecordingIcon.classList.remove("hidden"); + }); + recognition.onresult = (event) => { + const transcript = event.results[0][0].transcript; + searchBox.value = transcript; + searchBox.dispatchEvent(new Event("input")); + }; + recognition.onend = () => { + micIcon.classList.remove("hidden"); + micRecordingIcon.classList.add("hidden"); + }; + recognition.onerror = () => { + micIcon.classList.remove("hidden"); + micRecordingIcon.classList.add("hidden"); + }; +} +function setupSignOut() { + const signOutBtn = document.getElementById("signOutBtn"); + signOutBtn.addEventListener("click", async () => { + try { + await fetch("/api/auth/logout", { method: "POST" }); + window.location.href = "/signin.html"; + } catch (err) { + console.error("Sign out failed:", err); + window.location.href = "/signin.html"; + } + }); +} +async function init() { + const isAuthenticated = await checkAuth(); + if (!isAuthenticated) + return; + setupSearch(); + setupFilters(); + setupVoiceSearch(); + setupSignOut(); + await fetchJobs(); +} +function escapeHtml(str) { + return str.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">"); +} +init(); diff --git a/Mode2Test/AuthAndToken/frontend/js/home.ts b/Mode2Test/AuthAndToken/frontend/js/home.ts new file mode 100644 index 0000000..88e933f --- /dev/null +++ b/Mode2Test/AuthAndToken/frontend/js/home.ts @@ -0,0 +1,330 @@ +// PERMANENT: Home view - Jobs listing with zero-delay loading via IndexedDB cache +// Wired to tokenService via backend API routes +// Visual match to Mode1Test but uses new architecture +// +// Dependencies: +// - Backend /api/auth/status for authentication check +// - Backend /api/jobs for job data +// - job-cache.ts for IndexedDB caching +// +// Features: +// - Zero-delay load (displays cached jobs instantly) +// - Background refresh after displaying cache +// - Search with voice support (operates on cached data) +// - Filters (division, active, estimator, status) +// - Pagination +// - Click job to open Details view + +import { jobCache, type JobCard } from './job-cache.js'; + +interface Job { + Job_Number: string; + Job_Name?: string; + Job_Full_Name?: string; + Job_Address?: string; + Job_Division?: string; + Active?: boolean | string; + Status?: string; + Job_Status?: string; + Estimator?: string; + Contact_Person?: string; + Company_Client?: string; + [key: string]: any; +} + +let allJobs: Job[] = []; +let filteredJobs: Job[] = []; +let currentPage = 1; +const perPage = 50; +let isRefreshing = false; + +// Check authentication on page load +async function checkAuth(): Promise { + try { + const response = await fetch('/api/auth/status'); + const data = await response.json(); + + if (!data.authenticated) { + // Redirect to login + window.location.href = '/signin.html'; + return false; + } + + return true; + } catch (err) { + console.error('Auth check failed:', err); + window.location.href = '/signin.html'; + return false; + } +} + +// Fetch jobs from backend (or cache) +async function fetchJobs(): Promise { + try { + // Initialize cache + await jobCache.initialize(); + + // Check if cache is valid + const isCacheValid = await jobCache.isCacheValid(); + + if (isCacheValid) { + // Display cached jobs immediately (zero delay) + const cachedJobs = await jobCache.getCachedJobs(); + allJobs = cachedJobs; + filteredJobs = [...allJobs]; + renderJobs(); + + // Show cache age in console for debugging + const cacheAge = await jobCache.getCacheAge(); + console.log(`Loaded ${allJobs.length} jobs from cache (age: ${Math.round((cacheAge || 0) / 1000)}s)`); + + // Refresh in background (don't block UI) + refreshJobsInBackground(); + } else { + // No valid cache, fetch fresh data (no progress bar) + const jobs = await jobCache.refreshJobs(); + allJobs = jobs; + filteredJobs = [...allJobs]; + + renderJobs(); + console.log(`Loaded ${allJobs.length} jobs from server (cache updated)`); + } + } catch (err) { + console.error('Failed to fetch jobs:', err); + + // Show error message + const results = document.getElementById('results') as HTMLDivElement; + results.innerHTML = '
Failed to load jobs. Please refresh the page.
'; + } +} + +// Background refresh (silent, doesn't interrupt user) +async function refreshJobsInBackground(): Promise { + if (isRefreshing) return; + + isRefreshing = true; + + try { + const freshJobs = await jobCache.refreshJobs(); + + // Update in memory without interrupting user + allJobs = freshJobs; + + // Reapply current filters and search + applyFilters(); + + console.log(`Background refresh complete (${freshJobs.length} jobs)`); + } catch (err) { + console.error('Background refresh failed:', err); + } finally { + isRefreshing = false; + } +} + +// Render jobs to DOM +function renderJobs(): void { + const results = document.getElementById('results') as HTMLDivElement; + + if (filteredJobs.length === 0) { + results.innerHTML = '
No jobs found
'; + return; + } + + const start = (currentPage - 1) * perPage; + const end = start + perPage; + const pageJobs = filteredJobs.slice(start, end); + + results.innerHTML = pageJobs.map(job => { + const isActiveTrue = job.Active === true; + const isActiveFalse = job.Active === false; + const nameVal = job.Job_Full_Name || ''; + const contactVal = job.Contact_Person || ''; + + return ` +
+
Job#
${escapeHtml(String(job.Job_Number||''))}
+
Job Name:
${escapeHtml(String(nameVal))}
+
Contact:
${escapeHtml(String(contactVal))}
+
+
+ `; + }).join(''); + + // Add click handlers + results.querySelectorAll('[data-job-number]').forEach(el => { + el.addEventListener('click', (e) => { + const jobNumber = (e.currentTarget as HTMLElement).dataset.jobNumber; + if (jobNumber) { + openDetails(jobNumber); + } + }); + }); +} + +// Open Details view +function openDetails(jobNumber: string): void { + // Navigate to details view with job number + window.location.href = `/details.html?job=${encodeURIComponent(jobNumber)}`; +} + +// Search functionality +function setupSearch(): void { + const searchBox = document.getElementById('searchBox') as HTMLInputElement; + + searchBox.addEventListener('input', () => { + const query = searchBox.value.toLowerCase().trim(); + + if (!query) { + filteredJobs = [...allJobs]; + } else { + filteredJobs = allJobs.filter(job => { + return ( + job.Job_Number?.toString().toLowerCase().includes(query) || + job.Job_Full_Name?.toLowerCase().includes(query) || + job.Job_Address?.toLowerCase().includes(query) || + job.Contact_Person?.toLowerCase().includes(query) || + job.Company_Client?.toLowerCase().includes(query) || + job.Notes?.toLowerCase().includes(query) || + job.Job_Status?.toLowerCase().includes(query) || + job.Status?.toLowerCase().includes(query) || + job.Estimator?.toLowerCase().includes(query) + ); + }); + } + + currentPage = 1; + renderJobs(); + }); +} + +// Filter functionality +function setupFilters(): void { + const filterToggle = document.getElementById('filterToggle') as HTMLButtonElement; + const filtersPanel = document.getElementById('filtersPanel') as HTMLDivElement; + const clearFilters = document.getElementById('clearFilters') as HTMLButtonElement; + + filterToggle.addEventListener('click', () => { + const isHidden = filtersPanel.classList.contains('hidden'); + if (isHidden) { + filtersPanel.classList.remove('hidden'); + filterToggle.textContent = 'Hide Filters'; + } else { + filtersPanel.classList.add('hidden'); + filterToggle.textContent = 'Show Filters'; + } + }); + + // Apply filters on change + const filterInputs = filtersPanel.querySelectorAll('input[type="checkbox"]'); + filterInputs.forEach(input => { + input.addEventListener('change', applyFilters); + }); + + clearFilters.addEventListener('click', () => { + filterInputs.forEach(input => { + (input as HTMLInputElement).checked = false; + }); + applyFilters(); + }); +} + +function applyFilters(): void { + const divisions = Array.from(document.querySelectorAll('.filter-division:checked')).map(el => (el as HTMLInputElement).value); + const actives = Array.from(document.querySelectorAll('.filter-active:checked')).map(el => (el as HTMLInputElement).value); + const estimators = Array.from(document.querySelectorAll('.filter-estimator:checked')).map(el => (el as HTMLInputElement).value.toLowerCase()); + const statuses = Array.from(document.querySelectorAll('.filter-status:checked')).map(el => (el as HTMLInputElement).value); + + filteredJobs = allJobs.filter(job => { + const divisionVal = job.Job_Division || job.Division; + const activeVal = job.Active === true || job.Active === 'Yes' ? 'Yes' : job.Active === false || job.Active === 'No' ? 'No' : '—'; + const estimatorVal = (job.Estimator || '').toLowerCase(); + const statusVal = job.Job_Status || job.Status; + + if (divisions.length > 0 && !divisions.some(d => divisionVal?.startsWith(d))) return false; + if (actives.length > 0 && !actives.includes(activeVal)) return false; + if (estimators.length > 0 && !estimators.some(e => estimatorVal.includes(e))) return false; + if (statuses.length > 0 && !statuses.includes(statusVal || '')) return false; + return true; + }); + + currentPage = 1; + renderJobs(); +} + +// Voice search +function setupVoiceSearch(): void { + const voiceBtn = document.getElementById('voiceSearchBtn') as HTMLButtonElement; + const micIcon = document.getElementById('micIcon') as SVGElement; + const micRecordingIcon = document.getElementById('micRecordingIcon') as SVGElement; + const searchBox = document.getElementById('searchBox') as HTMLInputElement; + + if (!('webkitSpeechRecognition' in window) && !('SpeechRecognition' in window)) { + voiceBtn.style.display = 'none'; + return; + } + + const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition; + const recognition = new SpeechRecognition(); + recognition.continuous = false; + recognition.interimResults = false; + + voiceBtn.addEventListener('click', () => { + recognition.start(); + micIcon.classList.add('hidden'); + micRecordingIcon.classList.remove('hidden'); + }); + + recognition.onresult = (event: any) => { + const transcript = event.results[0][0].transcript; + searchBox.value = transcript; + searchBox.dispatchEvent(new Event('input')); + }; + + recognition.onend = () => { + micIcon.classList.remove('hidden'); + micRecordingIcon.classList.add('hidden'); + }; + + recognition.onerror = () => { + micIcon.classList.remove('hidden'); + micRecordingIcon.classList.add('hidden'); + }; +} + +// Sign out +function setupSignOut(): void { + const signOutBtn = document.getElementById('signOutBtn') as HTMLButtonElement; + + signOutBtn.addEventListener('click', async () => { + try { + await fetch('/api/auth/logout', { method: 'POST' }); + window.location.href = '/signin.html'; + } catch (err) { + console.error('Sign out failed:', err); + window.location.href = '/signin.html'; + } + }); +} + +// Initialize on page load +async function init(): Promise { + const isAuthenticated = await checkAuth(); + if (!isAuthenticated) return; + + setupSearch(); + setupFilters(); + setupVoiceSearch(); + setupSignOut(); + + await fetchJobs(); +} + +function escapeHtml(str: string): string { + return str + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>'); +} + +// Start +init(); diff --git a/Mode2Test/AuthAndToken/frontend/js/job-cache.js b/Mode2Test/AuthAndToken/frontend/js/job-cache.js new file mode 100644 index 0000000..cbbc625 --- /dev/null +++ b/Mode2Test/AuthAndToken/frontend/js/job-cache.js @@ -0,0 +1,129 @@ +// job-cache.ts +var DB_NAME = "JobInfoCache"; +var DB_VERSION = 2; +var JOBS_STORE = "jobs"; +var META_STORE = "metadata"; +var CACHE_TTL = 5 * 60 * 1000; +var PAGE_SIZE = 500; + +class JobCache { + db = null; + async initialize() { + return new Promise((resolve, reject) => { + const request = indexedDB.open(DB_NAME, DB_VERSION); + request.onerror = () => reject(request.error); + request.onsuccess = () => { + this.db = request.result; + resolve(); + }; + request.onupgradeneeded = (event) => { + const db = event.target.result; + if (!db.objectStoreNames.contains(JOBS_STORE)) { + db.createObjectStore(JOBS_STORE, { keyPath: "Job_Number" }); + } + if (!db.objectStoreNames.contains(META_STORE)) { + db.createObjectStore(META_STORE); + } + }; + }); + } + async getCachedJobs() { + if (!this.db) + throw new Error("Database not initialized"); + return new Promise((resolve, reject) => { + const transaction = this.db.transaction([JOBS_STORE], "readonly"); + const store = transaction.objectStore(JOBS_STORE); + const request = store.getAll(); + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }); + } + async isCacheValid() { + if (!this.db) + return false; + try { + const metadata = await this.getMetadata(); + if (!metadata || !metadata.lastUpdated) + return false; + const age = Date.now() - metadata.lastUpdated; + return age < CACHE_TTL; + } catch { + return false; + } + } + async saveJobs(jobs) { + if (!this.db) + throw new Error("Database not initialized"); + return new Promise((resolve, reject) => { + const transaction = this.db.transaction([JOBS_STORE, META_STORE], "readwrite"); + const jobsStore = transaction.objectStore(JOBS_STORE); + const metaStore = transaction.objectStore(META_STORE); + jobsStore.clear(); + jobs.forEach((job) => jobsStore.add(job)); + const metadata = { + lastUpdated: Date.now(), + version: DB_VERSION + }; + metaStore.put(metadata, "main"); + transaction.oncomplete = () => resolve(); + transaction.onerror = () => reject(transaction.error); + }); + } + async refreshJobs() { + try { + let page = 1; + let all = []; + let totalPages = 1; + while (page <= totalPages) { + const url = `/api/jobs?page=${page}&perPage=${PAGE_SIZE}&sort=-Job_Number`; + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Failed to fetch jobs (status ${response.status})`); + } + const data = await response.json(); + const items = data.items || []; + const reportedTotalPages = data.totalPages || 1; + all = all.concat(items); + totalPages = Math.max(totalPages, reportedTotalPages); + page += 1; + } + await this.saveJobs(all); + return all; + } catch (err) { + console.error("Failed to refresh jobs cache:", err); + throw err; + } + } + async getMetadata() { + if (!this.db) + return null; + return new Promise((resolve, reject) => { + const transaction = this.db.transaction([META_STORE], "readonly"); + const store = transaction.objectStore(META_STORE); + const request = store.get("main"); + request.onsuccess = () => resolve(request.result || null); + request.onerror = () => reject(request.error); + }); + } + async clearCache() { + if (!this.db) + throw new Error("Database not initialized"); + return new Promise((resolve, reject) => { + const transaction = this.db.transaction([JOBS_STORE, META_STORE], "readwrite"); + transaction.objectStore(JOBS_STORE).clear(); + transaction.objectStore(META_STORE).clear(); + transaction.oncomplete = () => resolve(); + transaction.onerror = () => reject(transaction.error); + }); + } + async getCacheAge() { + const metadata = await this.getMetadata(); + if (!metadata || !metadata.lastUpdated) + return null; + return Date.now() - metadata.lastUpdated; + } +} +var jobCache = new JobCache; +export { + jobCache +}; diff --git a/Mode2Test/AuthAndToken/frontend/js/job-cache.ts b/Mode2Test/AuthAndToken/frontend/js/job-cache.ts new file mode 100644 index 0000000..3b69f48 --- /dev/null +++ b/Mode2Test/AuthAndToken/frontend/js/job-cache.ts @@ -0,0 +1,189 @@ +// PERMANENT: IndexedDB cache for jobs data +// Provides lightning-fast job listing with zero-delay loading +// +// Strategy: +// - Display cached jobs instantly on page load (0ms delay) +// - Fetch fresh data in background after displaying cache +// - Cache TTL: 5 minutes (configurable) +// - Stores minimal fields for card display only +// +// Fields cached: Job_Number, Job_Name, Division, Active, Status, Estimator +// +// Usage: +// await jobCache.initialize(); +// const jobs = await jobCache.getCachedJobs(); // Instant +// await jobCache.refreshJobs(); // Background refresh + +export interface JobCard { + Job_Number: string; + Job_Name: string; + Division: string; + Active: string; + Status: string; + Estimator: string; +} + +interface CacheMetadata { + lastUpdated: number; + version: number; +} + +const DB_NAME = 'JobInfoCache'; +const DB_VERSION = 2; // bump to invalidate old minimal-field cache +const JOBS_STORE = 'jobs'; +const META_STORE = 'metadata'; +const CACHE_TTL = 5 * 60 * 1000; // 5 minutes +const PAGE_SIZE = 500; // match Mode1 bulk fetch + +class JobCache { + private db: IDBDatabase | null = null; + + async initialize(): Promise { + return new Promise((resolve, reject) => { + const request = indexedDB.open(DB_NAME, DB_VERSION); + + request.onerror = () => reject(request.error); + request.onsuccess = () => { + this.db = request.result; + resolve(); + }; + + request.onupgradeneeded = (event) => { + const db = (event.target as IDBOpenDBRequest).result; + + // Create jobs store with Job_Number as key + if (!db.objectStoreNames.contains(JOBS_STORE)) { + db.createObjectStore(JOBS_STORE, { keyPath: 'Job_Number' }); + } + + // Create metadata store + if (!db.objectStoreNames.contains(META_STORE)) { + db.createObjectStore(META_STORE); + } + }; + }); + } + + async getCachedJobs(): Promise { + if (!this.db) throw new Error('Database not initialized'); + + return new Promise((resolve, reject) => { + const transaction = this.db!.transaction([JOBS_STORE], 'readonly'); + const store = transaction.objectStore(JOBS_STORE); + const request = store.getAll(); + + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }); + } + + async isCacheValid(): Promise { + if (!this.db) return false; + + try { + const metadata = await this.getMetadata(); + if (!metadata || !metadata.lastUpdated) return false; + + const age = Date.now() - metadata.lastUpdated; + return age < CACHE_TTL; + } catch { + return false; + } + } + + async saveJobs(jobs: JobCard[]): Promise { + if (!this.db) throw new Error('Database not initialized'); + + return new Promise((resolve, reject) => { + const transaction = this.db!.transaction([JOBS_STORE, META_STORE], 'readwrite'); + const jobsStore = transaction.objectStore(JOBS_STORE); + const metaStore = transaction.objectStore(META_STORE); + + // Clear existing jobs + jobsStore.clear(); + + // Save new jobs + jobs.forEach(job => jobsStore.add(job)); + + // Update metadata + const metadata: CacheMetadata = { + lastUpdated: Date.now(), + version: DB_VERSION + }; + metaStore.put(metadata, 'main'); + + transaction.oncomplete = () => resolve(); + transaction.onerror = () => reject(transaction.error); + }); + } + + async refreshJobs(): Promise { + try { + // Fetch fresh data from backend with pagination to mirror Mode1 behavior + let page = 1; + let all: JobCard[] = []; + let totalPages = 1; + + while (page <= totalPages) { + const url = `/api/jobs?page=${page}&perPage=${PAGE_SIZE}&sort=-Job_Number`; + const response = await fetch(url); + + if (!response.ok) { + throw new Error(`Failed to fetch jobs (status ${response.status})`); + } + + const data = await response.json(); + const items: JobCard[] = data.items || []; + const reportedTotalPages = data.totalPages || 1; + + all = all.concat(items); + totalPages = Math.max(totalPages, reportedTotalPages); + page += 1; + } + + // Save to cache + await this.saveJobs(all); + + return all; + } catch (err) { + console.error('Failed to refresh jobs cache:', err); + throw err; + } + } + + async getMetadata(): Promise { + if (!this.db) return null; + + return new Promise((resolve, reject) => { + const transaction = this.db!.transaction([META_STORE], 'readonly'); + const store = transaction.objectStore(META_STORE); + const request = store.get('main'); + + request.onsuccess = () => resolve(request.result || null); + request.onerror = () => reject(request.error); + }); + } + + async clearCache(): Promise { + if (!this.db) throw new Error('Database not initialized'); + + return new Promise((resolve, reject) => { + const transaction = this.db!.transaction([JOBS_STORE, META_STORE], 'readwrite'); + + transaction.objectStore(JOBS_STORE).clear(); + transaction.objectStore(META_STORE).clear(); + + transaction.oncomplete = () => resolve(); + transaction.onerror = () => reject(transaction.error); + }); + } + + async getCacheAge(): Promise { + const metadata = await this.getMetadata(); + if (!metadata || !metadata.lastUpdated) return null; + + return Date.now() - metadata.lastUpdated; + } +} + +export const jobCache = new JobCache(); diff --git a/Mode2Test/AuthAndToken/frontend/manager.html b/Mode2Test/AuthAndToken/frontend/manager.html new file mode 100644 index 0000000..cf0bdbe --- /dev/null +++ b/Mode2Test/AuthAndToken/frontend/manager.html @@ -0,0 +1,16 @@ + + + + + + Manager + + + +
+

Manager

+

Manager view - Under construction

+ ← Back to Home +
+ + diff --git a/Mode2Test/AuthAndToken/frontend/navigator.html b/Mode2Test/AuthAndToken/frontend/navigator.html new file mode 100644 index 0000000..96e9339 --- /dev/null +++ b/Mode2Test/AuthAndToken/frontend/navigator.html @@ -0,0 +1,16 @@ + + + + + + Navigator + + + +
+

Navigator

+

Navigator view - Under construction

+ ← Back to Home +
+ + diff --git a/Mode2Test/AuthAndToken/frontend/signin.html b/Mode2Test/AuthAndToken/frontend/signin.html index cf43b22..85b7b5e 100644 --- a/Mode2Test/AuthAndToken/frontend/signin.html +++ b/Mode2Test/AuthAndToken/frontend/signin.html @@ -48,14 +48,23 @@ console.log('[Auth] Graph token found:', !!graphToken); // Send to backend to store - await fetch('/api/auth/login', { + const saveResponse = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pbToken: authData.token, graphToken: graphToken || undefined }) }); - // Redirect to app immediately - window.location.href = '/index.html'; + if (!saveResponse.ok) { + throw new Error('Failed to save tokens to backend'); + } + + console.log('[Auth] Tokens saved to backend, redirecting to home'); + + // Clear PocketBase local storage to avoid conflicts + pb.authStore.clear(); + + // Redirect to home page + window.location.href = '/home.html'; } catch (err) { document.getElementById('error').textContent = err.message || 'Login failed'; document.getElementById('error').classList.remove('hidden'); @@ -64,10 +73,15 @@ } } - // Check if already logged in - if (pb.authStore.isValid) { - window.location.href = '/index.html'; - } + // Check if already logged in via backend only + fetch('/api/auth/status') + .then(res => res.json()) + .then(data => { + if (data.authenticated) { + window.location.href = '/home.html'; + } + }) + .catch(() => {}); diff --git a/Mode2Test/AuthAndToken/frontend/viewer.html b/Mode2Test/AuthAndToken/frontend/viewer.html new file mode 100644 index 0000000..9ae70fc --- /dev/null +++ b/Mode2Test/AuthAndToken/frontend/viewer.html @@ -0,0 +1,16 @@ + + + + + + Viewer + + + +
+

Viewer

+

Viewer view - Under construction

+ ← Back to Home +
+ + diff --git a/Mode2Test/tokens.json b/Mode2Test/tokens.json index 144a4aa..0b48ccf 100644 --- a/Mode2Test/tokens.json +++ b/Mode2Test/tokens.json @@ -1,7 +1,7 @@ { - "pbToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJfcGJfdXNlcnNfYXV0aF8iLCJleHAiOjE4MDAxOTk4MTksImlkIjoiMWhiaWY5ZGJxbmc4Nmg5IiwicmVmcmVzaGFibGUiOnRydWUsInR5cGUiOiJhdXRoIn0.CqJgLgGfLOk4Wk9ro16MwtVjSMYG2oY4s9GV_tLBvvc", - "pbTokenExpiry": 1769268619806, - "graphToken": "eyJ0eXAiOiJKV1QiLCJub25jZSI6IlBQamVpUk5STGVWbkpNWVJSNHlzVENhMEtlZzJTeEhwOTFLbll6NUxYcGciLCJhbGciOiJSUzI1NiIsIng1dCI6IlBjWDk4R1g0MjBUMVg2c0JEa3poUW1xZ3dNVSIsImtpZCI6IlBjWDk4R1g0MjBUMVg2c0JEa3poUW1xZ3dNVSJ9.eyJhdWQiOiIwMDAwMDAwMy0wMDAwLTAwMDAtYzAwMC0wMDAwMDAwMDAwMDAiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8zZmQ5N2VhNy1iMTI0LTQxZjEtODU1Zi01MmQ4YWMzYjE2YzcvIiwiaWF0IjoxNzY4NjYzNTE5LCJuYmYiOjE3Njg2NjM1MTksImV4cCI6MTc2ODY2ODg3NSwiYWNjdCI6MCwiYWNyIjoiMSIsImFjcnMiOlsicDEiXSwiYWlvIjoiQVpRQWEvOGJBQUFBeTlyZWNsVzErcHErWE5hNXY0MkVrQUhaTEZwbGJ2SVJxZzFGWFprcWphbTR0eXk2dFdUTVFXZXNobGdJUFg2ZThMUXhoV2hrRE5MRDBuNE9mZW03a2QrcE1PM0ZPQTM5WmNFNFZjcWt1cWlTaUx1aFc0UDYyVkErOGV0ekZOOWFhcFdrMlR1T0ZQbVdpbDJEOEJ5QURaZmxFRTU5QkRtRVdsSTNvRkxZc3lvc2YwK1VtNGMyV2xsUTEwVjJQTFlLIiwiYW1yIjpbInB3ZCIsIm1mYSJdLCJhcHBfZGlzcGxheW5hbWUiOiJKb2JfSW5mb19TeW5jIiwiYXBwaWQiOiIzYzg0NmU3MS05NjA5LTQwZTEtYjQ1OC0wZWI4MDVlMjFiOWYiLCJhcHBpZGFjciI6IjEiLCJmYW1pbHlfbmFtZSI6IkV3aW5nIiwiZ2l2ZW5fbmFtZSI6IkFsZm9uc28iLCJpZHR5cCI6InVzZXIiLCJpcGFkZHIiOiIxNzIuNTkuNzIuMjQ4IiwibmFtZSI6IkFsZm9uc28gRXdpbmciLCJvaWQiOiIxYTZlOWQxMC0xMzhhLTQzZTQtYTA5ZS0xZjUwNDYzMTQ4YzkiLCJwbGF0ZiI6IjMiLCJwdWlkIjoiMTAwMzIwMDUxRkVCOEFDMCIsInJoIjoiMS5BVFVBcDM3WlB5U3g4VUdGWDFMWXJEc1d4d01BQUFBQUFBQUF3QUFBQUFBQUFBQmxBVWsxQUEuIiwic2NwIjoiQ2hhbm5lbC5SZWFkQmFzaWMuQWxsIENoYW5uZWxNZW1iZXIuUmVhZC5BbGwgQ2hhbm5lbE1lbWJlci5SZWFkV3JpdGUuQWxsIENoYW5uZWxNZXNzYWdlLkVkaXQgQ2hhbm5lbE1lc3NhZ2UuUmVhZC5BbGwgQ2hhbm5lbE1lc3NhZ2UuUmVhZFdyaXRlIENoYW5uZWxNZXNzYWdlLlNlbmQgQ2hhbm5lbFNldHRpbmdzLlJlYWQuQWxsIENoYW5uZWxTZXR0aW5ncy5SZWFkV3JpdGUuQWxsIENoYXRNZXNzYWdlLlJlYWQgQ2hhdE1lc3NhZ2UuU2VuZCBEaXJlY3RvcnkuQWNjZXNzQXNVc2VyLkFsbCBEaXJlY3RvcnkuUmVhZC5BbGwgRGlyZWN0b3J5LlJlYWRXcml0ZS5BbGwgZW1haWwgRmlsZXMuUmVhZFdyaXRlLkFsbCBHcm91cC5SZWFkLkFsbCBHcm91cC5SZWFkV3JpdGUuQWxsIEdyb3VwLUNvbnZlcnNhdGlvbi5SZWFkLkFsbCBHcm91cC1Db252ZXJzYXRpb24uUmVhZFdyaXRlLkFsbCBHcm91cE1lbWJlci5SZWFkLkFsbCBHcm91cE1lbWJlci5SZWFkV3JpdGUuQWxsIEdyb3VwU2V0dGluZ3MuUmVhZC5BbGwgR3JvdXBTZXR0aW5ncy5SZWFkV3JpdGUuQWxsIHByb2ZpbGUgU2l0ZXMuUmVhZFdyaXRlLkFsbCBUYXNrcy5SZWFkIFRhc2tzLlJlYWQuU2hhcmVkIFRhc2tzLlJlYWRXcml0ZSBUYXNrcy5SZWFkV3JpdGUuU2hhcmVkIFRlYW1zQWN0aXZpdHkuUmVhZCBUZWFtU2V0dGluZ3MuUmVhZC5BbGwgVGVhbVNldHRpbmdzLlJlYWRXcml0ZS5BbGwgVGVhbXNQb2xpY3lVc2VyQXNzaWduLlJlYWRXcml0ZS5BbGwgVXNlci5SZWFkIG9wZW5pZCIsInNpZCI6IjAwMTAzNDhhLTdkYWItNzBlZi1mODdmLWYyNGJhM2M5OTY2YyIsInNpZ25pbl9zdGF0ZSI6WyJrbXNpIl0sInN1YiI6IkFzVnNHelNzVE5hVm5SYk1sQ1p5VnlrWTJYejRIcktEaUVsdXlFWll2U3ciLCJ0ZW5hbnRfcmVnaW9uX3Njb3BlIjoiTkEiLCJ0aWQiOiIzZmQ5N2VhNy1iMTI0LTQxZjEtODU1Zi01MmQ4YWMzYjE2YzciLCJ1bmlxdWVfbmFtZSI6ImFld2luZ0BjYXJkb3phLmNvbnN0cnVjdGlvbiIsInVwbiI6ImFld2luZ0BjYXJkb3phLmNvbnN0cnVjdGlvbiIsInV0aSI6IjhadmQ0dkhBODA2Wmx1dnpJYkhaQUEiLCJ2ZXIiOiIxLjAiLCJ3aWRzIjpbImZlOTMwYmU3LTVlNjItNDdkYi05MWFmLTk4YzNhNDlhMzhiMSIsIjYyZTkwMzk0LTY5ZjUtNDIzNy05MTkwLTAxMjE3NzE0NWUxMCIsIjI5MjMyY2RmLTkzMjMtNDJmZC1hZGUyLTFkMDk3YWYzZTRkZSIsIjY5MDkxMjQ2LTIwZTgtNGE1Ni1hYTRkLTA2NjA3NWIyYTdhOCIsImI3OWZiZjRkLTNlZjktNDY4OS04MTQzLTc2YjE5NGU4NTUwOSJdLCJ4bXNfYWNkIjoxNzYzNDA1ODY0LCJ4bXNfYWN0X2ZjdCI6IjkgMyIsInhtc19mdGQiOiJvV0dWXzgxcHlJQksxWVlOYTJ6ck1sYlJsSENobmg2T1JtZVUwY1Y2d0ZBQmRYTjNaWE4wTXkxa2MyMXoiLCJ4bXNfaWRyZWwiOiIxIDQiLCJ4bXNfc3QiOnsic3ViIjoiQUhmNlFEcUV0ZHZEeXptWjB5TDJ0ZmRJLUltWVJxRlRJUWFMczdiSnZQYyJ9LCJ4bXNfc3ViX2ZjdCI6IjMgMiIsInhtc190Y2R0IjoxNTU4NTQ2MDA3LCJ4bXNfdG50X2ZjdCI6IjMgMiJ9.Dxx8iCgvn4kSLmXSdSKOwCB188jCQsLd-w5XBqNLuxlZXfzp8_DH_XVvZysGcffDrKkquSJ6oYOh4IjMy1ZLBl6lTz44Q3UoWiNZwZChsfNpyfk7lgI9ZnrLJizNFi9hpKOS28_pncT1ZRWJY6pIhs-coLO4_08CqynT3Vq_6LISwm1-rBOWr5A1_cP1An2Rnuu_3PEW8hmFHmMTvbXyIW9xxsExiNlTqr6w5h-dBMcOuzhuqRiDMhKplR8PaZrTdD8TizXAfaCepTyZPPa3rTKEn8jqiKmerit3mcx1H5RCFIgmxygdoTJVxXbEMx1SUfDb2t_M6r_yVjpNXfyqgQ", - "graphTokenExpiry": 1768667419806, - "lastRefresh": 1768663819806 + "pbToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJfcGJfdXNlcnNfYXV0aF8iLCJleHAiOjE4MDAyMTY5MjgsImlkIjoiMWhiaWY5ZGJxbmc4Nmg5IiwicmVmcmVzaGFibGUiOnRydWUsInR5cGUiOiJhdXRoIn0.PCwm9Ac67h_n-lLv1BdzrqXDCsjfkEcWqTcgnwT5cGQ", + "pbTokenExpiry": 1769285728680, + "graphToken": "eyJ0eXAiOiJKV1QiLCJub25jZSI6InRSOVQyM1h4RXhKRHN1YXJuSkdmcmYzd2FDS094TF9xWUkwd2dLUjhMVTQiLCJhbGciOiJSUzI1NiIsIng1dCI6IlBjWDk4R1g0MjBUMVg2c0JEa3poUW1xZ3dNVSIsImtpZCI6IlBjWDk4R1g0MjBUMVg2c0JEa3poUW1xZ3dNVSJ9.eyJhdWQiOiIwMDAwMDAwMy0wMDAwLTAwMDAtYzAwMC0wMDAwMDAwMDAwMDAiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8zZmQ5N2VhNy1iMTI0LTQxZjEtODU1Zi01MmQ4YWMzYjE2YzcvIiwiaWF0IjoxNzY4Njc4Mjk1LCJuYmYiOjE3Njg2NzgyOTUsImV4cCI6MTc2ODY4MjIxMSwiYWNjdCI6MCwiYWNyIjoiMSIsImFjcnMiOlsicDEiXSwiYWlvIjoiQWRRQUsvOGJBQUFBMW1BM04rN1pMMFU5OURDcUtsZ2JiOE1pSlhYRXZOT0dMQ2FjVllmdWZMTVM3b2N1emlvdkVmd1dZQnRBV2VyK0U5bGZxUU9FZ1lVZnBOODAxK2srMXBqOW5NRHlqdHhuRWVkaWI5Q1hZbThTMmFLeVNmZWFaQTFFZVdOa2VqWkduN2ZRQSsxLzE5ckVKcWlqMlRRRWZBMm9RTTlDamwxSE5QbGpGQ05iTHZwcmtETFIrT29CVlM4VlBXZi8zTU00Q1pzQ2ZiZnNRb3FuSGpzUHBUTzdFMzk1Qk5UQVhveXoxL1lRTkFucVhmNHRGajVaMUZVWW9jY1hES0NubEc0NXBmTVMxSHMreE1ZWVdnT3h0MkhJeVE9PSIsImFtciI6WyJyc2EiLCJtZmEiXSwiYXBwX2Rpc3BsYXluYW1lIjoiSm9iX0luZm9fU3luYyIsImFwcGlkIjoiM2M4NDZlNzEtOTYwOS00MGUxLWI0NTgtMGViODA1ZTIxYjlmIiwiYXBwaWRhY3IiOiIxIiwiZGV2aWNlaWQiOiJkZjdmZmUyOC04NDQ2LTQ5NjUtOWNlMC1jNDJiNjIxZmFiYjciLCJmYW1pbHlfbmFtZSI6IkV3aW5nIiwiZ2l2ZW5fbmFtZSI6IkFsZm9uc28iLCJpZHR5cCI6InVzZXIiLCJpcGFkZHIiOiIxNDMuMTA1LjI0Ny4xNDYiLCJuYW1lIjoiQWxmb25zbyBFd2luZyIsIm9pZCI6IjFhNmU5ZDEwLTEzOGEtNDNlNC1hMDllLTFmNTA0NjMxNDhjOSIsInBsYXRmIjoiMyIsInB1aWQiOiIxMDAzMjAwNTFGRUI4QUMwIiwicmgiOiIxLkFUVUFwMzdaUHlTeDhVR0ZYMUxZckRzV3h3TUFBQUFBQUFBQXdBQUFBQUFBQUFCbEFVazFBQS4iLCJzY3AiOiJDaGFubmVsLlJlYWRCYXNpYy5BbGwgQ2hhbm5lbE1lbWJlci5SZWFkLkFsbCBDaGFubmVsTWVtYmVyLlJlYWRXcml0ZS5BbGwgQ2hhbm5lbE1lc3NhZ2UuRWRpdCBDaGFubmVsTWVzc2FnZS5SZWFkLkFsbCBDaGFubmVsTWVzc2FnZS5SZWFkV3JpdGUgQ2hhbm5lbE1lc3NhZ2UuU2VuZCBDaGFubmVsU2V0dGluZ3MuUmVhZC5BbGwgQ2hhbm5lbFNldHRpbmdzLlJlYWRXcml0ZS5BbGwgQ2hhdE1lc3NhZ2UuUmVhZCBDaGF0TWVzc2FnZS5TZW5kIERpcmVjdG9yeS5BY2Nlc3NBc1VzZXIuQWxsIERpcmVjdG9yeS5SZWFkLkFsbCBEaXJlY3RvcnkuUmVhZFdyaXRlLkFsbCBlbWFpbCBGaWxlcy5SZWFkV3JpdGUuQWxsIEdyb3VwLlJlYWQuQWxsIEdyb3VwLlJlYWRXcml0ZS5BbGwgR3JvdXAtQ29udmVyc2F0aW9uLlJlYWQuQWxsIEdyb3VwLUNvbnZlcnNhdGlvbi5SZWFkV3JpdGUuQWxsIEdyb3VwTWVtYmVyLlJlYWQuQWxsIEdyb3VwTWVtYmVyLlJlYWRXcml0ZS5BbGwgR3JvdXBTZXR0aW5ncy5SZWFkLkFsbCBHcm91cFNldHRpbmdzLlJlYWRXcml0ZS5BbGwgcHJvZmlsZSBTaXRlcy5SZWFkV3JpdGUuQWxsIFRhc2tzLlJlYWQgVGFza3MuUmVhZC5TaGFyZWQgVGFza3MuUmVhZFdyaXRlIFRhc2tzLlJlYWRXcml0ZS5TaGFyZWQgVGVhbXNBY3Rpdml0eS5SZWFkIFRlYW1TZXR0aW5ncy5SZWFkLkFsbCBUZWFtU2V0dGluZ3MuUmVhZFdyaXRlLkFsbCBUZWFtc1BvbGljeVVzZXJBc3NpZ24uUmVhZFdyaXRlLkFsbCBVc2VyLlJlYWQgb3BlbmlkIiwic2lkIjoiMDA4ZDJjYjktODU5MS1jMDdkLTVhMjQtYzk2MjhkYzc1ZDIzIiwic2lnbmluX3N0YXRlIjpbImttc2kiXSwic3ViIjoiQXNWc0d6U3NUTmFWblJiTWxDWnlWeWtZMlh6NEhyS0RpRWx1eUVaWXZTdyIsInRlbmFudF9yZWdpb25fc2NvcGUiOiJOQSIsInRpZCI6IjNmZDk3ZWE3LWIxMjQtNDFmMS04NTVmLTUyZDhhYzNiMTZjNyIsInVuaXF1ZV9uYW1lIjoiYWV3aW5nQGNhcmRvemEuY29uc3RydWN0aW9uIiwidXBuIjoiYWV3aW5nQGNhcmRvemEuY29uc3RydWN0aW9uIiwidXRpIjoiVDljb0FWV3ZXVTJTbTBGLUFqS3lBQSIsInZlciI6IjEuMCIsIndpZHMiOlsiZmU5MzBiZTctNWU2Mi00N2RiLTkxYWYtOThjM2E0OWEzOGIxIiwiNjJlOTAzOTQtNjlmNS00MjM3LTkxOTAtMDEyMTc3MTQ1ZTEwIiwiMjkyMzJjZGYtOTMyMy00MmZkLWFkZTItMWQwOTdhZjNlNGRlIiwiNjkwOTEyNDYtMjBlOC00YTU2LWFhNGQtMDY2MDc1YjJhN2E4IiwiYjc5ZmJmNGQtM2VmOS00Njg5LTgxNDMtNzZiMTk0ZTg1NTA5Il0sInhtc19hY2QiOjE3NjM0MDU4NjQsInhtc19hY3RfZmN0IjoiOSAzIiwieG1zX2Z0ZCI6IkYyUXJpNWN3ZEhLQzVuZzFrYjdsU1huX3BlWXFaR3JUT21KeDYyN21LZUVCZFhOM1pYTjBNeTFrYzIxeiIsInhtc19pZHJlbCI6IjggMSIsInhtc19zdCI6eyJzdWIiOiJBSGY2UURxRXRkdkR5em1aMHlMMnRmZEktSW1ZUnFGVElRYUxzN2JKdlBjIn0sInhtc19zdWJfZmN0IjoiMyA2IiwieG1zX3RjZHQiOjE1NTg1NDYwMDcsInhtc190bnRfZmN0IjoiNiAzIn0.UqBTFe_GkrUqp9oHgjO93KtXckuDH91RQ03fV8ZzgUit4Vre1EXctVC-Zm5j5kfSM_6pb99VKasBPAolbIa4U-_J1yGidc81sghJj3Haz048v9_074Ky4Qzl0czNQ7OYTn2N1xKuYeBEzXCMt6Cc8gpGJv372seP0CVTs6ZxFTAfRXw2PvHsrJdiEJQMpMoSLBRC_bF9s223o6PiN3v1XgGbAqwP3WI-0GhtyK5Tnul0WJIH5i9G2sA3DlDAmxFm51RwxZtaeqhYPGNEkHrUQqBkNHeAiZ_VqvmGHyuj-D7E-XHOGkF8bQPCHWVXeLdZJNkOxxBEgqYNBpp2QWBWVg", + "graphTokenExpiry": 1768684528680, + "lastRefresh": 1768680928680 } \ No newline at end of file diff --git a/ModeSwitch/orchestrator.log b/ModeSwitch/orchestrator.log index 6890eee..cd2807d 100644 --- a/ModeSwitch/orchestrator.log +++ b/ModeSwitch/orchestrator.log @@ -1,3 +1,4 @@ +nohup: ignoring input ================================================================================ [ModeSwitch Orchestrator] @@ -7,20 +8,4469 @@ Shared mode port: 3005 Config file: /home/admin/Job-Info-Test/ModeSwitch/activeMode.txt ================================================================================ -[ModeSwitch] Starting Test1Mode (oldTest/) on port 3005... -✓ Test1Mode started successfully on port 3005 - 7 | if (typeof entryNamespace?.default?.fetch === 'function') { - 8 | const server = Bun.serve(entryNamespace.default); - 9 | console.debug(`Started ${server.development ? 'development ' : ''}server: ${server.protocol}://${server.hostname}:${server.port}`); -10 | } -11 | }, reportError); -12 | const server = Bun.serve(entryNamespace.default); - ^ -error: Failed to start server. Is port 3006 in use? - syscall: "listen", - errno: 0, - code: "EADDRINUSE" +[ModeSwitch] Starting Mode2Test (Mode2Test/) on port 3005... +✓ Mode2Test started successfully on port 3005 +Started development server: http://localhost:3006 +[Mode2Test] [AuthAndToken] Background refresh started (every 5 minutes) - at bun:main:12:28 +[Mode2Test] Mode2Test (AuthAndToken) running on http://localhost:3005 + +[Mode2Test] Auth API: /api/auth/* +SignIn page: /signin.html + +[Mode2Test] Started development server: http://localhost:3005 + +[Mode2Test] [AuthAndToken] Tokens loaded from file +[AuthAndToken] PB token valid: yes +[AuthAndToken] Graph token valid: yes + +[ModeSwitch] Starting Mode1Test (Mode1Test/) on port 3005... +✓ Mode1Test started successfully on port 3005 +[Mode1Test] [dotenv@17.2.3] injecting env (0) from .env -- tip: ⚙️ override existing env vars with { override: true } + +[Mode1Test] Started development server: http://localhost:3005 + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[ModeSwitch] Starting Mode2Test (Mode2Test/) on port 3005... +✓ Mode2Test started successfully on port 3005 +[Mode2Test] [AuthAndToken] Background refresh started (every 5 minutes) + +[Mode2Test] Mode2Test (AuthAndToken) running on http://localhost:3005 +Auth API: /api/auth/* +SignIn page: /signin.html + +[Mode2Test] Started development server: http://localhost:3005 + +[Mode2Test] [AuthAndToken] Tokens loaded from file +[AuthAndToken] PB token valid: yes +[AuthAndToken] Graph token valid: yes + +[Mode2Test] [AuthAndToken] Refresh error: fetch() URL is invalid + +[Mode2Test] [AuthAndToken] Refresh error: fetch() URL is invalid + +[Mode2Test] [AuthAndToken] Refresh error: fetch() URL is invalid + +[Mode2Test] [AuthAndToken] Refresh error: fetch() URL is invalid + +[Mode2Test] [AuthAndToken] Refresh error: fetch() URL is invalid + +[Mode2Test] [AuthAndToken] Refresh error: fetch() URL is invalid + +[ModeSwitch] Starting Mode1Test (Mode1Test/) on port 3005... +✓ Mode1Test started successfully on port 3005 +[Mode1Test] [dotenv@17.2.3] injecting env (0) from .env -- tip: ✅ audit secrets and track compliance: https://dotenvx.com/ops + +[Mode1Test] Started development server: http://localhost:3005 + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] [job-files] Request received + +[Mode1Test] [getGraphToken] Header token: eyJ0eXAiOiJKV1QiLCJu... + +[Mode1Test] [getGraphToken] Env token: NOT SET +[getGraphToken] Using: eyJ0eXAiOiJKV1QiLCJu... +[job-files] Token found: eyJ0eXAiOiJKV1QiLCJu... +[job-files] Link: https://czflex.sharepoint.com/sites/Team/Shared Documents/General/Operations [Server]/1 Job Pages/COMMERCIAL/4682 - Bread of Life - Petrovskiy, Toliy +[resolveShareLink] Decoded link: https://czflex.sharepoint.com/sites/Team/Shared Documents/General/Operations [Server]/1 Job Pages/COMMERCIAL/4682 - Bread of Life - Petrovskiy, Toliy + +[Mode1Test] [job-files] Request received +[getGraphToken] Header token: eyJ0eXAiOiJKV1QiLCJu... +[getGraphToken] Env token: NOT SET +[getGraphToken] Using: eyJ0eXAiOiJKV1QiLCJu... +[job-files] Token found: eyJ0eXAiOiJKV1QiLCJu... +[job-files] Link: https://czflex.sharepoint.com/sites/Team/Shared Documents/General/Operations [Server]/1 Job Pages/COMMERCIAL/4682 - Bread of Life - Petrovskiy, Toliy +[resolveShareLink] Decoded link: https://czflex.sharepoint.com/sites/Team/Shared Documents/General/Operations [Server]/1 Job Pages/COMMERCIAL/4682 - Bread of Life - Petrovskiy, Toliy + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed + +[Mode1Test] Redis connection closed -Bun v1.3.2 (Linux x64 baseline)