1export class Semaphore { 2 constructor(initialPermits = 1) { 3 this.permits = initialPermits; 4 this.queue = []; 5 } 6 7 async acquire() { 8 return new Promise((resolve) => { 9 if (this.permits > 0) { 10 this.permits--; 11 resolve(); 12 } else { 13 this.queue.push(resolve); 14 } 15 }); 16 } 17 18 release() { 19 if (this.queue.length > 0) { 20 const resolve = this.queue.shift(); 21 resolve(); 22 } else { 23 this.permits++; 24 } 25 } 26} 27 28export class MovingByteRate { 29 constructor(windowSize = 1) { 30 this.windowSize = windowSize * 5000; // Window size in milliseconds 31 this.bytes = []; // Stores timestamps and byte counts for window 32 } 33 34 addBytes(bytes) { 35 this.bytes.push({ timestamp: Date.now(), bytes }); 36 } 37 38 getByteRate() { 39 const now = Date.now(); 40 this.bytes = this.bytes.filter(entry => now - entry.timestamp <= this.windowSize); // Filter out old entries 41 42 const totalBytes = this.bytes.reduce((sum, entry) => sum + entry.bytes, 0); 43 const elapsedTime = Math.min(this.windowSize, now - this.bytes[0]?.timestamp || 0); // Consider window limit or actual time 44 return totalBytes / (elapsedTime / 1000); // Average in bytes/second 45 } 46} 47 48 49export class Utility { 50 /** 51 * Format bytes as human-readable text. 52 * 53 * @param bytes Number of bytes. 54 * @param si True to use metric (SI) units, aka powers of 1000. False to use 55 * binary (IEC), aka powers of 1024. 56 * @param dp Number of decimal places to display. 57 * 58 * @return Formatted string. 59 */ 60 static humanFileSize(bytes, si = false, dp = 1) { 61 const thresh = si ? 1000 : 1024; 62 63 if (Math.abs(bytes) < thresh) { 64 return bytes + ' B'; 65 } 66 67 const units = si 68 ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] 69 : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']; 70 let u = -1; 71 const r = 10 ** dp; 72 73 do { 74 bytes /= thresh; 75 ++u; 76 } while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1); 77 78 79 return bytes.toFixed(dp) + ' ' + units[u]; 80 } 81 82 static sleep(ms) { 83 return new Promise(resolve => setTimeout(resolve, ms)); 84 } 85 86 static appendUint8Array(accumulationBuffer, dataToAppend) { 87 // Create a new Uint8Array with sufficient capacity to hold both arrays 88 const newBuffer = new Uint8Array(accumulationBuffer.byteLength + dataToAppend.byteLength); 89 90 // Copy the existing accumulation buffer into the new buffer 91 newBuffer.set(accumulationBuffer); 92 93 // Copy the new data to append into the new buffer, starting at the offset where the accumulation buffer ends 94 newBuffer.set(dataToAppend, accumulationBuffer.byteLength); 95 96 // Return the new combined buffer, which becomes the new accumulation buffer 97 return newBuffer; 98 } 99} 100
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.