|
|
"use strict"; |
|
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
|
exports.ReplayPath = void 0; |
|
|
class ReplayPath { |
|
|
static parse(replayPathStr) { |
|
|
const [serializedCount, serializedChanges] = replayPathStr.split(':'); |
|
|
const counts = this.parseCounts(serializedCount); |
|
|
const changes = this.parseChanges(serializedChanges); |
|
|
return this.parseOccurences(counts, changes); |
|
|
} |
|
|
static stringify(replayPath) { |
|
|
const occurences = this.countOccurences(replayPath); |
|
|
const serializedCount = this.stringifyCounts(occurences); |
|
|
const serializedChanges = this.stringifyChanges(occurences); |
|
|
return `${serializedCount}:${serializedChanges}`; |
|
|
} |
|
|
static intToB64(n) { |
|
|
if (n < 26) |
|
|
return String.fromCharCode(n + 65); |
|
|
if (n < 52) |
|
|
return String.fromCharCode(n + 97 - 26); |
|
|
if (n < 62) |
|
|
return String.fromCharCode(n + 48 - 52); |
|
|
return String.fromCharCode(n === 62 ? 43 : 47); |
|
|
} |
|
|
static b64ToInt(c) { |
|
|
if (c >= 'a') |
|
|
return c.charCodeAt(0) - 97 + 26; |
|
|
if (c >= 'A') |
|
|
return c.charCodeAt(0) - 65; |
|
|
if (c >= '0') |
|
|
return c.charCodeAt(0) - 48 + 52; |
|
|
return c === '+' ? 62 : 63; |
|
|
} |
|
|
static countOccurences(replayPath) { |
|
|
return replayPath.reduce((counts, cur) => { |
|
|
if (counts.length === 0 || counts[counts.length - 1].count === 64 || counts[counts.length - 1].value !== cur) |
|
|
counts.push({ value: cur, count: 1 }); |
|
|
else |
|
|
counts[counts.length - 1].count += 1; |
|
|
return counts; |
|
|
}, []); |
|
|
} |
|
|
static parseOccurences(counts, changes) { |
|
|
const replayPath = []; |
|
|
for (let idx = 0; idx !== counts.length; ++idx) { |
|
|
const count = counts[idx]; |
|
|
const value = changes[idx]; |
|
|
for (let num = 0; num !== count; ++num) |
|
|
replayPath.push(value); |
|
|
} |
|
|
return replayPath; |
|
|
} |
|
|
static stringifyChanges(occurences) { |
|
|
let serializedChanges = ''; |
|
|
for (let idx = 0; idx < occurences.length; idx += 6) { |
|
|
const changesInt = occurences |
|
|
.slice(idx, idx + 6) |
|
|
.reduceRight((prev, cur) => prev * 2 + (cur.value ? 1 : 0), 0); |
|
|
serializedChanges += this.intToB64(changesInt); |
|
|
} |
|
|
return serializedChanges; |
|
|
} |
|
|
static parseChanges(serializedChanges) { |
|
|
const changesInt = serializedChanges.split('').map((c) => this.b64ToInt(c)); |
|
|
const changes = []; |
|
|
for (let idx = 0; idx !== changesInt.length; ++idx) { |
|
|
let current = changesInt[idx]; |
|
|
for (let n = 0; n !== 6; ++n, current >>= 1) { |
|
|
changes.push(current % 2 === 1); |
|
|
} |
|
|
} |
|
|
return changes; |
|
|
} |
|
|
static stringifyCounts(occurences) { |
|
|
return occurences.map(({ count }) => this.intToB64(count - 1)).join(''); |
|
|
} |
|
|
static parseCounts(serializedCount) { |
|
|
return serializedCount.split('').map((c) => this.b64ToInt(c) + 1); |
|
|
} |
|
|
} |
|
|
exports.ReplayPath = ReplayPath; |
|
|
|