const fs = require('fs') const child_process = require('child_process') global.stdin = () => { const out = fs.readFileSync(0).toString() return out.tryParseJSON() } Object.prototype.map = function(cb) { return cb(this) } Object.prototype.apply = Object.prototype.map String.prototype.lines = function() { let res = this.split("\n") return res.at(-1) === '' ? res.slice(0, -1) : res } String.prototype.reverse = function() { return this.split('').reverse().join('') } String.prototype.includesAny = function(strings) { if (!(strings instanceof Array)) throw new TypeError('strings must be an Array') return strings.some(x => this.includes(x)) } String.prototype.tryParseJSON = function() { const str = this.trim() if ( (str.at(0) === '{' && str.at(-1) === '}') || (str.at(0) === '[' && str.at(-1) === ']') ) { try { return JSON.parse(str) } catch (err) { return this.toString() } } return this.toString() } Buffer.prototype.tryParseJSON = function() { const out = this.toString().tryParseJSON() if (typeof out === 'string') { return this } else { return out } } global.exec = (command, args, options) => { const res = child_process.spawnSync(command, args, options) res.stdout = res.stdout?.tryParseJSON() res.stderr = res.stderr?.tryParseJSON() res.orFail = function() { if (res.status !== 0) { const cmd = [ command, ...((args && Array.isArray(args)) ? args : []) ].join(' ') throw new Error(`command '${cmd}' exited with code ${res.status}`) } } return res } global.execnc = (command, args, options) => { if (!options) options = {} if (!options.stdio) options.stdio = 'inherit' return exec(command, args, options) } /* wow it's almost like it's my own package and i can include whatever garbage i want :) */ /* not writing a test for that tho */ global.apkindex = input => { if (!input) input = stdin() return input .split("\n\n") .filter(str => str.length) .map(x => Object.fromEntries(x.lines().map(e => [e.at(0), e.slice(2)]))) .map(pkg => ({ ...pkg, S: Number(pkg.S), I: Number(pkg.I), t: new Date(Number(pkg.t) * 1000), i: pkg.i?.split(' '), D: pkg.D?.split(' '), p: pkg.p?.split(' ') })) .map(Object.prune) } Array.prototype.sum = function(def = 0) { return this.reduce((a, b) => a + b, def) } Array.prototype.product = function(def = 1) { return this.reduce((a, b) => a * b, def) } Array.prototype.sortNum = function(getter = (x => x)) { return this.sort((a, b) => getter(a) - getter(b)) } Array.prototype.partition = function(compareFn) { const a = [] const b = [] this.forEach((elem, i, arr) => { if (compareFn(elem, i, arr)) { a.push(elem) } else { b.push(elem) } }) return [a, b] } Array.prototype.chunks = function(chunkSize) { // inspired by https://stackoverflow.com/questions/8495687/split-array-into-chunks#comment84212474_8495740 return new Array(Math.ceil(this.length / chunkSize)) .fill() .map((_, i) => this.slice(i * chunkSize, (i + 1) * chunkSize)) } Array.prototype.transpose = function() { return new Array(this[0].length).fill().map((_, i) => this.map(x => x[i])) } Array.prototype.shuffle = function() { // borrowed from https://stackoverflow.com/a/12646864 for (let i = this.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [this[i], this[j]] = [this[j], this[i]]; } } Set.prototype.union = function(other) { if (!other || !(other instanceof Set)) throw new TypeError('other must be a Set') return new Set([...this, ...other]) } Set.prototype.intersection = function(other) { if (!other || !(other instanceof Set)) throw new TypeError('other must be a Set') return new Set([...this].filter(el => other.has(el))) } Set.prototype.difference = function(other) { if (!other || !(other instanceof Set)) throw new TypeError('other must be a Set') return new Set([...this].filter(el => !other.has(el))) } Set.prototype.at = function(index) { return [...this].at(index) } global.matrix = function(x, y, elem) { return new Array(y).fill().map(() => new Array(x).fill().map((_, i) => { if (typeof elem === 'function') { return elem(i) } else { return elem } })) } Number.prototype.toXY = function(width) { if (!(width && typeof width === 'number')) throw new TypeError('width must be a Number') return [ this % width, Math.floor(this / width) ] } global.sed = function(filename, cb) { let content = fs.readFileSync(filename, 'utf-8') content = cb(content) fs.writeFileSync(filename, content, 'utf-8') } Object.prune = function(obj) { if (typeof obj !== 'object') throw new TypeError('obj must be an object') for (let key of Object.keys(obj)) { if (obj[key] === undefined) { delete obj[key] } } return obj }