mirror of
https://github.com/Av0idD4rk/packmate.git
synced 2026-10-25 07:29:25 +00:00
Сменил реализацию hexdump, добавил настройку ширины в байтах
This commit is contained in:
parent
b1401579f9
commit
567946ac2a
@ -2,45 +2,73 @@
|
|||||||
<div>
|
<div>
|
||||||
<div>#{{id}} at {{new Date(timestamp * 1000).toLocaleDateString('ru-RU', {month: '2-digit', day: '2-digit', hour:'2-digit', minute: '2-digit', second: '2-digit'})}}</div>
|
<div>#{{id}} at {{new Date(timestamp * 1000).toLocaleDateString('ru-RU', {month: '2-digit', day: '2-digit', hour:'2-digit', minute: '2-digit', second: '2-digit'})}}</div>
|
||||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
<pre :id="'hexdump-' + id"></pre>
|
<pre>{{ hexdata }}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import {Hexdump,} from '@/components/hexdump.js' // Why the fuck is this working, Babel?!?!
|
// import {Hexdump,} from '@/components/hexdump.js' // Why the fuck is this working, Babel?!?!
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Packet',
|
name: 'Packet',
|
||||||
props: ['id', 'content', 'timestamp',],
|
props: ['id', 'content', 'timestamp',],
|
||||||
mounted() {
|
methods: {
|
||||||
// const dataString = decodeURIComponent(escape(atob(this.$props.content)));
|
hexdump(buffer, blockSize) {
|
||||||
const dataString = atob(this.$props.content);
|
blockSize = parseInt(blockSize, 10) || 16;
|
||||||
this.hex = new Hexdump(dataString, { // TODO: в настройки
|
let lines = [];
|
||||||
container: 'hexdump-' + this.$props.id,
|
const hex = "0123456789ABCDEF";
|
||||||
base: 'hex',
|
for (let b = 0; b < buffer.length; b += blockSize) {
|
||||||
width: 16,
|
let block = buffer.slice(b, Math.min(b + blockSize, buffer.length));
|
||||||
ascii: false,
|
let addr = ("0000" + b.toString(10)).slice(-4);
|
||||||
byteGrouping: 1,
|
let codes = block.split('').map(function (ch) {
|
||||||
html: false,
|
let code = ch.charCodeAt(0);
|
||||||
lineNumber: true,
|
return " " + hex[(0xF0 & code) >> 4] + hex[0x0F & code];
|
||||||
nonPrintable: '?',
|
}).join("");
|
||||||
style: {
|
codes += " ".repeat(blockSize - block.length);
|
||||||
lineNumberLeft: '',
|
// eslint-disable-next-line no-control-regex
|
||||||
lineNumberRight: ':',
|
let chars = block.replace(/[\x00-\x1F\x20]/g, '.');
|
||||||
stringLeft: '|',
|
chars += " ".repeat(blockSize - block.length);
|
||||||
stringRight: '|',
|
lines.push(addr + " " + codes + " " + chars);
|
||||||
hexLeft: '',
|
}
|
||||||
hexRight: '',
|
return lines.join("\n");
|
||||||
hexNull: '.g',
|
},
|
||||||
stringNull: ' ',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
computed: {
|
||||||
delete this.hex;
|
hexdata() {
|
||||||
|
// const dataString = decodeURIComponent(escape(atob(this.$props.content)));
|
||||||
|
const dataString = atob(this.$props.content);
|
||||||
|
return this.hexdump(dataString, this.$store.state.hexdumpBlockSize);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
// mounted() {
|
||||||
|
//
|
||||||
|
// this.hex = new Hexdump(dataString, { // TODO: в настройки
|
||||||
|
// container: 'hexdump-' + this.$props.id,
|
||||||
|
// base: 'hex',
|
||||||
|
// width: 16,
|
||||||
|
// ascii: false,
|
||||||
|
// byteGrouping: 1,
|
||||||
|
// html: false,
|
||||||
|
// // endian: 'little',
|
||||||
|
// lineNumber: true,
|
||||||
|
// nonPrintable: '?',
|
||||||
|
// style: {
|
||||||
|
// lineNumberLeft: '',
|
||||||
|
// lineNumberRight: ':',
|
||||||
|
// stringLeft: '|',
|
||||||
|
// stringRight: '|',
|
||||||
|
// hexLeft: '',
|
||||||
|
// hexRight: '',
|
||||||
|
// hexNull: '.g',
|
||||||
|
// stringNull: ' ',
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// beforeDestroy() {
|
||||||
|
// delete this.hex;
|
||||||
|
// },
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -15,6 +15,10 @@
|
|||||||
<label for="inputApiPassword">Пароль</label>
|
<label for="inputApiPassword">Пароль</label>
|
||||||
<input type="password" class="form-control" id="inputApiPassword" v-model="apiPassword">
|
<input type="password" class="form-control" id="inputApiPassword" v-model="apiPassword">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="inputHexdumpBlockSize">Ширина блока HEX</label>
|
||||||
|
<input type="number" class="form-control" id="inputHexdumpBlockSize" v-model="hexdumpBlockSize">
|
||||||
|
</div>
|
||||||
<button type="submit" @click.prevent="$emit('close')" class="btn btn-primary">
|
<button type="submit" @click.prevent="$emit('close')" class="btn btn-primary">
|
||||||
Закрыть
|
Закрыть
|
||||||
</button>
|
</button>
|
||||||
@ -65,6 +69,14 @@ export default {
|
|||||||
this.$store.commit('setApiPassword', value);
|
this.$store.commit('setApiPassword', value);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hexdumpBlockSize: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.hexdumpBlockSize;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.$store.commit('setHexdumpBlockSize', value);
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,398 +0,0 @@
|
|||||||
// Hexdump.js 0.1.1
|
|
||||||
// (c) 2011 Dustin Willis Webber
|
|
||||||
// Hexdump is freely distributable under the MIT license.
|
|
||||||
// For all details and documentation:
|
|
||||||
// http://github.com/mephux/hexdump.js
|
|
||||||
|
|
||||||
// Hexdump Initializer
|
|
||||||
// data => The string payload.
|
|
||||||
// options => hexdump configurations
|
|
||||||
export function Hexdump(data, options) {
|
|
||||||
const self = this;
|
|
||||||
self.hexdump = [];
|
|
||||||
self.hex = false;
|
|
||||||
self.options = {
|
|
||||||
container: options.container || ''
|
|
||||||
, width: options.width || 16
|
|
||||||
, byteGrouping: options.byteGrouping || 0
|
|
||||||
, ascii: options.ascii
|
|
||||||
, lineNumber: options.lineNumber
|
|
||||||
, endian: options.endian || 'big'
|
|
||||||
, html: options.html
|
|
||||||
, base: options.base || 'hexadecimal'
|
|
||||||
, nonPrintable: options.nonPrintable || '.'
|
|
||||||
, style: {
|
|
||||||
lineNumberLeft: options.style.lineNumberLeft || ''
|
|
||||||
, lineNumberRight: options.style.lineNumberRight || ':'
|
|
||||||
, stringLeft: options.style.stringLeft || '|'
|
|
||||||
, stringRight: options.style.stringRight || '|'
|
|
||||||
, hexLeft: options.style.hexLeft || ''
|
|
||||||
, hexRight: options.style.hexRight || ''
|
|
||||||
, hexNull: options.style.hexNull || '.'
|
|
||||||
, stringNull: options.style.stringNull || ' ',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (self.options.base === 'hex') {
|
|
||||||
self.hex = true;
|
|
||||||
} else if (self.options.base === 'hexadecimal') {
|
|
||||||
self.hex = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for the line number option and turn it off
|
|
||||||
// if not set unless it has been explicitly turned
|
|
||||||
// off by the user.
|
|
||||||
const ln = self.options.lineNumber;
|
|
||||||
if (typeof ln == "undefined" || ln == null) {
|
|
||||||
self.options.lineNumber = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const askey = self.options.ascii;
|
|
||||||
if (typeof askey == "undefined" || askey == null) {
|
|
||||||
self.options.ascii = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const html = self.options.html;
|
|
||||||
if (typeof html == "undefined" || html == null) {
|
|
||||||
self.options.html = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.endian !== ('little' || 'big')) {
|
|
||||||
self.endian = 'big';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure spacing is within proper range.
|
|
||||||
if (self.options.byteGrouping > data.length) {
|
|
||||||
self.options.byteGrouping = data.length;
|
|
||||||
}
|
|
||||||
self.options.byteGrouping--;
|
|
||||||
|
|
||||||
// Make sure width is within proper range.
|
|
||||||
if (self.options.width > data.length) {
|
|
||||||
self.options.width = data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base padding
|
|
||||||
self.padding = {
|
|
||||||
hex: 4,
|
|
||||||
dec: 5,
|
|
||||||
bin: 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Base conversion logic
|
|
||||||
switch (self.options.base) {
|
|
||||||
case 'hexadecimal':
|
|
||||||
case 'hex':
|
|
||||||
case 16:
|
|
||||||
self.setNullPadding(self.padding.hex);
|
|
||||||
self.baseConvert = function (characters) {
|
|
||||||
|
|
||||||
for (let i = 0; i < characters.length; i++) {
|
|
||||||
return self.addPadding(characters[i].charCodeAt(0).toString(16), self.padding.hex);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case 'decimal':
|
|
||||||
case 'dec':
|
|
||||||
case 10:
|
|
||||||
self.setNullPadding(self.padding.dec);
|
|
||||||
self.baseConvert = function (characters) {
|
|
||||||
|
|
||||||
for (let i = 0; i < characters.length; i++) {
|
|
||||||
return self.addPadding(characters[i].charCodeAt(0), self.padding.dec);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case 'binary':
|
|
||||||
case 'bin':
|
|
||||||
case 2:
|
|
||||||
self.setNullPadding(self.padding.bin);
|
|
||||||
self.baseConvert = function (characters) {
|
|
||||||
for (let i = 0; i < characters.length; i++) {
|
|
||||||
let ddx = characters[i].charCodeAt(0), r = "";
|
|
||||||
|
|
||||||
for (let bbx = 0; bbx < 8; bbx++) {
|
|
||||||
r = (ddx % 2) + r;
|
|
||||||
ddx = Math.floor(ddx / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.addPadding(r, self.padding.bin);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
self.options.base = 'hex';
|
|
||||||
self.hex = true;
|
|
||||||
|
|
||||||
self.setNullPadding(self.padding.hex);
|
|
||||||
self.baseConvert = function (characters) {
|
|
||||||
|
|
||||||
for (let i = 0; i < characters.length; i++) {
|
|
||||||
return self.addPadding(characters[i].charCodeAt(0).toString(16), self.padding.hex);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const regex = new RegExp('.{1,' + this.options.width + '}', 'g');
|
|
||||||
|
|
||||||
self.data = data.match(regex);
|
|
||||||
|
|
||||||
self.nullCount = (self.options.width - self.data[self.data.length - 1].length);
|
|
||||||
|
|
||||||
self.hexCounter = 0;
|
|
||||||
|
|
||||||
self.stringCounter = 0;
|
|
||||||
|
|
||||||
for (let i = 0; i < self.data.length; i++) {
|
|
||||||
const tempData = self.process(self.data[i]);
|
|
||||||
|
|
||||||
self.hexdump.push({
|
|
||||||
data: tempData.data,
|
|
||||||
string: tempData.string,
|
|
||||||
length: self.data[i].length,
|
|
||||||
missing: (self.options.width - self.data[i].length),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
self.dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
Hexdump.prototype.dump = function () {
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
self.output = '';
|
|
||||||
for (let i = 0; i < self.hexdump.length; i++) {
|
|
||||||
|
|
||||||
if (self.options.lineNumber) {
|
|
||||||
let tempLineNumberStyle = '';
|
|
||||||
tempLineNumberStyle += self.options.style.lineNumberLeft;
|
|
||||||
|
|
||||||
const currentLineCount = (i * self.options.width); //.toString(16);
|
|
||||||
const temLineCount = 8 - currentLineCount.toString().length;
|
|
||||||
for (let l = 0; l < temLineCount; l++) {
|
|
||||||
tempLineNumberStyle += '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
tempLineNumberStyle += currentLineCount;
|
|
||||||
tempLineNumberStyle += self.options.style.lineNumberRight + ' ';
|
|
||||||
|
|
||||||
if (self.options.html) {
|
|
||||||
self.output += '<span id="line-number">' + tempLineNumberStyle + '</span>';
|
|
||||||
} else {
|
|
||||||
self.output += tempLineNumberStyle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let spacingCount = 0;
|
|
||||||
// var breakPoint = Math.floor(self.options.width / 2);
|
|
||||||
|
|
||||||
self.output += self.options.style.hexLeft;
|
|
||||||
|
|
||||||
for (let x = 0; x < self.hexdump[i].data.length; x++) {
|
|
||||||
|
|
||||||
if (spacingCount === self.options.byteGrouping) {
|
|
||||||
if (x === self.hexdump[i].data.length - 1) {
|
|
||||||
self.output += self.hexdump[i].data[x];
|
|
||||||
} else {
|
|
||||||
self.output += self.hexdump[i].data[x] + ' ';
|
|
||||||
}
|
|
||||||
spacingCount = 0;
|
|
||||||
} else {
|
|
||||||
self.output += self.hexdump[i].data[x];
|
|
||||||
spacingCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.output += self.options.style.hexRight;
|
|
||||||
|
|
||||||
self.appendString(self.hexdump[i]);
|
|
||||||
self.output += "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
const hexdump_container = document.getElementById(this.options.container);
|
|
||||||
hexdump_container.innerHTML = this.output;
|
|
||||||
};
|
|
||||||
|
|
||||||
Hexdump.prototype.appendString = function (data) {
|
|
||||||
const self = this;
|
|
||||||
self.output += ' ' + self.options.style.stringLeft;
|
|
||||||
self.output += data.string;
|
|
||||||
self.output += self.options.style.stringRight;
|
|
||||||
};
|
|
||||||
|
|
||||||
Hexdump.prototype.splitNulls = function (code) {
|
|
||||||
const split = [];
|
|
||||||
let buffer = "";
|
|
||||||
|
|
||||||
if (code && code.length > 2) {
|
|
||||||
for (let cc = 0; cc < code.length; cc++) {
|
|
||||||
const tempi = cc + 1;
|
|
||||||
|
|
||||||
if (tempi % 2 === 0) {
|
|
||||||
|
|
||||||
buffer += code[cc].toString();
|
|
||||||
split.push(buffer);
|
|
||||||
|
|
||||||
buffer = "";
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
buffer += code[cc].toString();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return split;
|
|
||||||
};
|
|
||||||
|
|
||||||
Hexdump.prototype.process = function (data) {
|
|
||||||
let i;
|
|
||||||
let splitHexWidth;
|
|
||||||
let y;
|
|
||||||
let split;
|
|
||||||
let code;
|
|
||||||
const self = this;
|
|
||||||
const stringArray = [];
|
|
||||||
const hexArray = [];
|
|
||||||
|
|
||||||
for (i = 0; i < data.length; i++) {
|
|
||||||
if (self.options.html) {
|
|
||||||
|
|
||||||
code = self.baseConvert(data[i]);
|
|
||||||
|
|
||||||
if (self.hex) {
|
|
||||||
split = self.splitNulls(code);
|
|
||||||
|
|
||||||
for (y = 0; y < split.length; y++) {
|
|
||||||
hexArray.push('<span data-hex-id="' + self.hexCounter + '">' +
|
|
||||||
split[y] + '</span>');
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
hexArray.push('<span data-hex-id="' + self.hexCounter + '">' +
|
|
||||||
code + '</span>');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
stringArray.push('<span data-string-id="' + self.hexCounter + '">' +
|
|
||||||
self.checkForNonPrintable(data[i]) + '</span>');
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
code = self.baseConvert(data[i]);
|
|
||||||
|
|
||||||
if (self.hex) {
|
|
||||||
split = self.splitNulls(code);
|
|
||||||
|
|
||||||
for (y = 0; y < split.length; y++) {
|
|
||||||
hexArray.push(split[y]);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
hexArray.push(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
stringArray.push(self.checkForNonPrintable(data[i]));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
self.hexCounter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.hex) {
|
|
||||||
splitHexWidth = self.options.width * 2;
|
|
||||||
} else {
|
|
||||||
splitHexWidth = self.options.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hexArray.length < splitHexWidth) {
|
|
||||||
const amount = (splitHexWidth - hexArray.length);
|
|
||||||
|
|
||||||
for (i = 0; i < amount; i++) {
|
|
||||||
let nullHex = '';
|
|
||||||
|
|
||||||
if (self.options.html) {
|
|
||||||
nullHex = '<span data-hex-null="true">' + self.options.style.hexNull + '</span>';
|
|
||||||
} else {
|
|
||||||
nullHex = self.options.style.hexNull;
|
|
||||||
}
|
|
||||||
|
|
||||||
hexArray.push(nullHex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stringArray.length < self.options.width) {
|
|
||||||
const stringAmount = self.options.width - stringArray.length;
|
|
||||||
for (i = 0; i < stringAmount; i++) {
|
|
||||||
let nullString = '';
|
|
||||||
|
|
||||||
if (self.options.html) {
|
|
||||||
nullString = '<span data-string-null="true">' + self.options.style.stringNull + '</span>';
|
|
||||||
} else {
|
|
||||||
nullString = self.options.style.stringNull;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
stringArray.push(nullString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {data: hexArray, string: stringArray.join(''),};
|
|
||||||
};
|
|
||||||
|
|
||||||
Hexdump.prototype.setNullPadding = function (padding) {
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
const hexNull = self.options.style.hexNull[0];
|
|
||||||
self.options.style.hexNull = "";
|
|
||||||
|
|
||||||
if (self.hex) {
|
|
||||||
padding = padding / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let p = 0; p < padding; p++) {
|
|
||||||
self.options.style.hexNull += hexNull;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Hexdump.prototype.addPadding = function (ch, padding) {
|
|
||||||
const self = this, length = ch.toString().length;
|
|
||||||
let pad = '';
|
|
||||||
|
|
||||||
for (let i = 0; i < (padding - length); i++) {
|
|
||||||
pad += '0'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.options.endian === 'big') {
|
|
||||||
return pad + ch;
|
|
||||||
} else {
|
|
||||||
return ch + pad;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Hexdump.prototype.checkForNonPrintable = function (character) {
|
|
||||||
const self = this;
|
|
||||||
const c = character.charCodeAt(0).toString(16);
|
|
||||||
|
|
||||||
// noinspection EqualityComparisonWithCoercionJS
|
|
||||||
if (c == 0x9) {
|
|
||||||
return '.'
|
|
||||||
} else { // noinspection EqualityComparisonWithCoercionJS
|
|
||||||
if (c == 0x7F) {
|
|
||||||
return '.'
|
|
||||||
} else if (c.length > 2 && self.options.ascii) {
|
|
||||||
return '.'
|
|
||||||
} else {
|
|
||||||
return character;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@ -9,11 +9,13 @@ export default new Vuex.Store({
|
|||||||
apiUrl: 'http://127.0.0.1/api',
|
apiUrl: 'http://127.0.0.1/api',
|
||||||
apiLogin: 'BinaryBears',
|
apiLogin: 'BinaryBears',
|
||||||
apiPassword: '123456',
|
apiPassword: '123456',
|
||||||
|
hexdumpBlockSize: 16,
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
setApiUrl: (state, payload) => state.apiUrl = payload,
|
setApiUrl: (state, payload) => state.apiUrl = payload,
|
||||||
setApiLogin: (state, payload) => state.apiLogin = payload,
|
setApiLogin: (state, payload) => state.apiLogin = payload,
|
||||||
setApiPassword: (state, payload) => state.apiPassword = payload,
|
setApiPassword: (state, payload) => state.apiPassword = payload,
|
||||||
|
setHexdumpBlockSize: (state, payload) => state.hexdumpBlockSize = payload,
|
||||||
},
|
},
|
||||||
plugins: [createPersistedState(),],
|
plugins: [createPersistedState(),],
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user