first commit
This commit is contained in:
676
node_modules/lottie-web/player/js/utils/DataManager.js
generated
vendored
Normal file
676
node_modules/lottie-web/player/js/utils/DataManager.js
generated
vendored
Normal file
@@ -0,0 +1,676 @@
|
||||
import { getWebWorker } from '../main';
|
||||
|
||||
const dataManager = (function () {
|
||||
var _counterId = 1;
|
||||
var processes = [];
|
||||
var workerFn;
|
||||
var workerInstance;
|
||||
var workerProxy = {
|
||||
onmessage: function () {
|
||||
|
||||
},
|
||||
postMessage: function (path) {
|
||||
workerFn({
|
||||
data: path,
|
||||
});
|
||||
},
|
||||
};
|
||||
var _workerSelf = {
|
||||
postMessage: function (data) {
|
||||
workerProxy.onmessage({
|
||||
data: data,
|
||||
});
|
||||
},
|
||||
};
|
||||
function createWorker(fn) {
|
||||
if (window.Worker && window.Blob && getWebWorker()) {
|
||||
var blob = new Blob(['var _workerSelf = self; self.onmessage = ', fn.toString()], { type: 'text/javascript' });
|
||||
// var blob = new Blob(['self.onmessage = ', fn.toString()], { type: 'text/javascript' });
|
||||
var url = URL.createObjectURL(blob);
|
||||
return new Worker(url);
|
||||
}
|
||||
workerFn = fn;
|
||||
return workerProxy;
|
||||
}
|
||||
|
||||
function setupWorker() {
|
||||
if (!workerInstance) {
|
||||
workerInstance = createWorker(function workerStart(e) {
|
||||
function dataFunctionManager() {
|
||||
function completeLayers(layers, comps) {
|
||||
var layerData;
|
||||
var i;
|
||||
var len = layers.length;
|
||||
var j;
|
||||
var jLen;
|
||||
var k;
|
||||
var kLen;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
layerData = layers[i];
|
||||
if (('ks' in layerData) && !layerData.completed) {
|
||||
layerData.completed = true;
|
||||
if (layerData.hasMask) {
|
||||
var maskProps = layerData.masksProperties;
|
||||
jLen = maskProps.length;
|
||||
for (j = 0; j < jLen; j += 1) {
|
||||
if (maskProps[j].pt.k.i) {
|
||||
convertPathsToAbsoluteValues(maskProps[j].pt.k);
|
||||
} else {
|
||||
kLen = maskProps[j].pt.k.length;
|
||||
for (k = 0; k < kLen; k += 1) {
|
||||
if (maskProps[j].pt.k[k].s) {
|
||||
convertPathsToAbsoluteValues(maskProps[j].pt.k[k].s[0]);
|
||||
}
|
||||
if (maskProps[j].pt.k[k].e) {
|
||||
convertPathsToAbsoluteValues(maskProps[j].pt.k[k].e[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layerData.ty === 0) {
|
||||
layerData.layers = findCompLayers(layerData.refId, comps);
|
||||
completeLayers(layerData.layers, comps);
|
||||
} else if (layerData.ty === 4) {
|
||||
completeShapes(layerData.shapes);
|
||||
} else if (layerData.ty === 5) {
|
||||
completeText(layerData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function completeChars(chars, assets) {
|
||||
if (chars) {
|
||||
var i = 0;
|
||||
var len = chars.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
if (chars[i].t === 1) {
|
||||
// var compData = findComp(chars[i].data.refId, assets);
|
||||
chars[i].data.layers = findCompLayers(chars[i].data.refId, assets);
|
||||
// chars[i].data.ip = 0;
|
||||
// chars[i].data.op = 99999;
|
||||
// chars[i].data.st = 0;
|
||||
// chars[i].data.sr = 1;
|
||||
// chars[i].w = compData.w;
|
||||
// chars[i].data.ks = {
|
||||
// a: { k: [0, 0, 0], a: 0 },
|
||||
// p: { k: [0, -compData.h, 0], a: 0 },
|
||||
// r: { k: 0, a: 0 },
|
||||
// s: { k: [100, 100], a: 0 },
|
||||
// o: { k: 100, a: 0 },
|
||||
// };
|
||||
completeLayers(chars[i].data.layers, assets);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findComp(id, comps) {
|
||||
var i = 0;
|
||||
var len = comps.length;
|
||||
while (i < len) {
|
||||
if (comps[i].id === id) {
|
||||
return comps[i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function findCompLayers(id, comps) {
|
||||
var comp = findComp(id, comps);
|
||||
if (comp) {
|
||||
if (!comp.layers.__used) {
|
||||
comp.layers.__used = true;
|
||||
return comp.layers;
|
||||
}
|
||||
return JSON.parse(JSON.stringify(comp.layers));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function completeShapes(arr) {
|
||||
var i;
|
||||
var len = arr.length;
|
||||
var j;
|
||||
var jLen;
|
||||
for (i = len - 1; i >= 0; i -= 1) {
|
||||
if (arr[i].ty === 'sh') {
|
||||
if (arr[i].ks.k.i) {
|
||||
convertPathsToAbsoluteValues(arr[i].ks.k);
|
||||
} else {
|
||||
jLen = arr[i].ks.k.length;
|
||||
for (j = 0; j < jLen; j += 1) {
|
||||
if (arr[i].ks.k[j].s) {
|
||||
convertPathsToAbsoluteValues(arr[i].ks.k[j].s[0]);
|
||||
}
|
||||
if (arr[i].ks.k[j].e) {
|
||||
convertPathsToAbsoluteValues(arr[i].ks.k[j].e[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (arr[i].ty === 'gr') {
|
||||
completeShapes(arr[i].it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function convertPathsToAbsoluteValues(path) {
|
||||
var i;
|
||||
var len = path.i.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
path.i[i][0] += path.v[i][0];
|
||||
path.i[i][1] += path.v[i][1];
|
||||
path.o[i][0] += path.v[i][0];
|
||||
path.o[i][1] += path.v[i][1];
|
||||
}
|
||||
}
|
||||
|
||||
function checkVersion(minimum, animVersionString) {
|
||||
var animVersion = animVersionString ? animVersionString.split('.') : [100, 100, 100];
|
||||
if (minimum[0] > animVersion[0]) {
|
||||
return true;
|
||||
} if (animVersion[0] > minimum[0]) {
|
||||
return false;
|
||||
}
|
||||
if (minimum[1] > animVersion[1]) {
|
||||
return true;
|
||||
} if (animVersion[1] > minimum[1]) {
|
||||
return false;
|
||||
}
|
||||
if (minimum[2] > animVersion[2]) {
|
||||
return true;
|
||||
} if (animVersion[2] > minimum[2]) {
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var checkText = (function () {
|
||||
var minimumVersion = [4, 4, 14];
|
||||
|
||||
function updateTextLayer(textLayer) {
|
||||
var documentData = textLayer.t.d;
|
||||
textLayer.t.d = {
|
||||
k: [
|
||||
{
|
||||
s: documentData,
|
||||
t: 0,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function iterateLayers(layers) {
|
||||
var i;
|
||||
var len = layers.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
if (layers[i].ty === 5) {
|
||||
updateTextLayer(layers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return function (animationData) {
|
||||
if (checkVersion(minimumVersion, animationData.v)) {
|
||||
iterateLayers(animationData.layers);
|
||||
if (animationData.assets) {
|
||||
var i;
|
||||
var len = animationData.assets.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
if (animationData.assets[i].layers) {
|
||||
iterateLayers(animationData.assets[i].layers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
var checkChars = (function () {
|
||||
var minimumVersion = [4, 7, 99];
|
||||
return function (animationData) {
|
||||
if (animationData.chars && !checkVersion(minimumVersion, animationData.v)) {
|
||||
var i;
|
||||
var len = animationData.chars.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
var charData = animationData.chars[i];
|
||||
if (charData.data && charData.data.shapes) {
|
||||
completeShapes(charData.data.shapes);
|
||||
charData.data.ip = 0;
|
||||
charData.data.op = 99999;
|
||||
charData.data.st = 0;
|
||||
charData.data.sr = 1;
|
||||
charData.data.ks = {
|
||||
p: { k: [0, 0], a: 0 },
|
||||
s: { k: [100, 100], a: 0 },
|
||||
a: { k: [0, 0], a: 0 },
|
||||
r: { k: 0, a: 0 },
|
||||
o: { k: 100, a: 0 },
|
||||
};
|
||||
if (!animationData.chars[i].t) {
|
||||
charData.data.shapes.push(
|
||||
{
|
||||
ty: 'no',
|
||||
}
|
||||
);
|
||||
charData.data.shapes[0].it.push(
|
||||
{
|
||||
p: { k: [0, 0], a: 0 },
|
||||
s: { k: [100, 100], a: 0 },
|
||||
a: { k: [0, 0], a: 0 },
|
||||
r: { k: 0, a: 0 },
|
||||
o: { k: 100, a: 0 },
|
||||
sk: { k: 0, a: 0 },
|
||||
sa: { k: 0, a: 0 },
|
||||
ty: 'tr',
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
var checkPathProperties = (function () {
|
||||
var minimumVersion = [5, 7, 15];
|
||||
|
||||
function updateTextLayer(textLayer) {
|
||||
var pathData = textLayer.t.p;
|
||||
if (typeof pathData.a === 'number') {
|
||||
pathData.a = {
|
||||
a: 0,
|
||||
k: pathData.a,
|
||||
};
|
||||
}
|
||||
if (typeof pathData.p === 'number') {
|
||||
pathData.p = {
|
||||
a: 0,
|
||||
k: pathData.p,
|
||||
};
|
||||
}
|
||||
if (typeof pathData.r === 'number') {
|
||||
pathData.r = {
|
||||
a: 0,
|
||||
k: pathData.r,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function iterateLayers(layers) {
|
||||
var i;
|
||||
var len = layers.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
if (layers[i].ty === 5) {
|
||||
updateTextLayer(layers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return function (animationData) {
|
||||
if (checkVersion(minimumVersion, animationData.v)) {
|
||||
iterateLayers(animationData.layers);
|
||||
if (animationData.assets) {
|
||||
var i;
|
||||
var len = animationData.assets.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
if (animationData.assets[i].layers) {
|
||||
iterateLayers(animationData.assets[i].layers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
var checkColors = (function () {
|
||||
var minimumVersion = [4, 1, 9];
|
||||
|
||||
function iterateShapes(shapes) {
|
||||
var i;
|
||||
var len = shapes.length;
|
||||
var j;
|
||||
var jLen;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
if (shapes[i].ty === 'gr') {
|
||||
iterateShapes(shapes[i].it);
|
||||
} else if (shapes[i].ty === 'fl' || shapes[i].ty === 'st') {
|
||||
if (shapes[i].c.k && shapes[i].c.k[0].i) {
|
||||
jLen = shapes[i].c.k.length;
|
||||
for (j = 0; j < jLen; j += 1) {
|
||||
if (shapes[i].c.k[j].s) {
|
||||
shapes[i].c.k[j].s[0] /= 255;
|
||||
shapes[i].c.k[j].s[1] /= 255;
|
||||
shapes[i].c.k[j].s[2] /= 255;
|
||||
shapes[i].c.k[j].s[3] /= 255;
|
||||
}
|
||||
if (shapes[i].c.k[j].e) {
|
||||
shapes[i].c.k[j].e[0] /= 255;
|
||||
shapes[i].c.k[j].e[1] /= 255;
|
||||
shapes[i].c.k[j].e[2] /= 255;
|
||||
shapes[i].c.k[j].e[3] /= 255;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
shapes[i].c.k[0] /= 255;
|
||||
shapes[i].c.k[1] /= 255;
|
||||
shapes[i].c.k[2] /= 255;
|
||||
shapes[i].c.k[3] /= 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function iterateLayers(layers) {
|
||||
var i;
|
||||
var len = layers.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
if (layers[i].ty === 4) {
|
||||
iterateShapes(layers[i].shapes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return function (animationData) {
|
||||
if (checkVersion(minimumVersion, animationData.v)) {
|
||||
iterateLayers(animationData.layers);
|
||||
if (animationData.assets) {
|
||||
var i;
|
||||
var len = animationData.assets.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
if (animationData.assets[i].layers) {
|
||||
iterateLayers(animationData.assets[i].layers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
var checkShapes = (function () {
|
||||
var minimumVersion = [4, 4, 18];
|
||||
|
||||
function completeClosingShapes(arr) {
|
||||
var i;
|
||||
var len = arr.length;
|
||||
var j;
|
||||
var jLen;
|
||||
for (i = len - 1; i >= 0; i -= 1) {
|
||||
if (arr[i].ty === 'sh') {
|
||||
if (arr[i].ks.k.i) {
|
||||
arr[i].ks.k.c = arr[i].closed;
|
||||
} else {
|
||||
jLen = arr[i].ks.k.length;
|
||||
for (j = 0; j < jLen; j += 1) {
|
||||
if (arr[i].ks.k[j].s) {
|
||||
arr[i].ks.k[j].s[0].c = arr[i].closed;
|
||||
}
|
||||
if (arr[i].ks.k[j].e) {
|
||||
arr[i].ks.k[j].e[0].c = arr[i].closed;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (arr[i].ty === 'gr') {
|
||||
completeClosingShapes(arr[i].it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function iterateLayers(layers) {
|
||||
var layerData;
|
||||
var i;
|
||||
var len = layers.length;
|
||||
var j;
|
||||
var jLen;
|
||||
var k;
|
||||
var kLen;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
layerData = layers[i];
|
||||
if (layerData.hasMask) {
|
||||
var maskProps = layerData.masksProperties;
|
||||
jLen = maskProps.length;
|
||||
for (j = 0; j < jLen; j += 1) {
|
||||
if (maskProps[j].pt.k.i) {
|
||||
maskProps[j].pt.k.c = maskProps[j].cl;
|
||||
} else {
|
||||
kLen = maskProps[j].pt.k.length;
|
||||
for (k = 0; k < kLen; k += 1) {
|
||||
if (maskProps[j].pt.k[k].s) {
|
||||
maskProps[j].pt.k[k].s[0].c = maskProps[j].cl;
|
||||
}
|
||||
if (maskProps[j].pt.k[k].e) {
|
||||
maskProps[j].pt.k[k].e[0].c = maskProps[j].cl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layerData.ty === 4) {
|
||||
completeClosingShapes(layerData.shapes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return function (animationData) {
|
||||
if (checkVersion(minimumVersion, animationData.v)) {
|
||||
iterateLayers(animationData.layers);
|
||||
if (animationData.assets) {
|
||||
var i;
|
||||
var len = animationData.assets.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
if (animationData.assets[i].layers) {
|
||||
iterateLayers(animationData.assets[i].layers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
function completeData(animationData) {
|
||||
if (animationData.__complete) {
|
||||
return;
|
||||
}
|
||||
checkColors(animationData);
|
||||
checkText(animationData);
|
||||
checkChars(animationData);
|
||||
checkPathProperties(animationData);
|
||||
checkShapes(animationData);
|
||||
completeLayers(animationData.layers, animationData.assets);
|
||||
completeChars(animationData.chars, animationData.assets);
|
||||
animationData.__complete = true;
|
||||
}
|
||||
|
||||
function completeText(data) {
|
||||
if (data.t.a.length === 0 && !('m' in data.t.p)) {
|
||||
// data.singleShape = true;
|
||||
}
|
||||
}
|
||||
|
||||
var moduleOb = {};
|
||||
moduleOb.completeData = completeData;
|
||||
moduleOb.checkColors = checkColors;
|
||||
moduleOb.checkChars = checkChars;
|
||||
moduleOb.checkPathProperties = checkPathProperties;
|
||||
moduleOb.checkShapes = checkShapes;
|
||||
moduleOb.completeLayers = completeLayers;
|
||||
|
||||
return moduleOb;
|
||||
}
|
||||
if (!_workerSelf.dataManager) {
|
||||
_workerSelf.dataManager = dataFunctionManager();
|
||||
}
|
||||
|
||||
if (!_workerSelf.assetLoader) {
|
||||
_workerSelf.assetLoader = (function () {
|
||||
function formatResponse(xhr) {
|
||||
// using typeof doubles the time of execution of this method,
|
||||
// so if available, it's better to use the header to validate the type
|
||||
var contentTypeHeader = xhr.getResponseHeader('content-type');
|
||||
if (contentTypeHeader && xhr.responseType === 'json' && contentTypeHeader.indexOf('json') !== -1) {
|
||||
return xhr.response;
|
||||
}
|
||||
if (xhr.response && typeof xhr.response === 'object') {
|
||||
return xhr.response;
|
||||
} if (xhr.response && typeof xhr.response === 'string') {
|
||||
return JSON.parse(xhr.response);
|
||||
} if (xhr.responseText) {
|
||||
return JSON.parse(xhr.responseText);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function loadAsset(path, fullPath, callback, errorCallback) {
|
||||
var response;
|
||||
var xhr = new XMLHttpRequest();
|
||||
// set responseType after calling open or IE will break.
|
||||
try {
|
||||
// This crashes on Android WebView prior to KitKat
|
||||
xhr.responseType = 'json';
|
||||
} catch (err) {} // eslint-disable-line no-empty
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
response = formatResponse(xhr);
|
||||
callback(response);
|
||||
} else {
|
||||
try {
|
||||
response = formatResponse(xhr);
|
||||
callback(response);
|
||||
} catch (err) {
|
||||
if (errorCallback) {
|
||||
errorCallback(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
try {
|
||||
// Hack to workaround banner validation
|
||||
xhr.open(['G', 'E', 'T'].join(''), path, true);
|
||||
} catch (error) {
|
||||
// Hack to workaround banner validation
|
||||
xhr.open(['G', 'E', 'T'].join(''), fullPath + '/' + path, true);
|
||||
}
|
||||
xhr.send();
|
||||
}
|
||||
return {
|
||||
load: loadAsset,
|
||||
};
|
||||
}());
|
||||
}
|
||||
|
||||
if (e.data.type === 'loadAnimation') {
|
||||
_workerSelf.assetLoader.load(
|
||||
e.data.path,
|
||||
e.data.fullPath,
|
||||
function (data) {
|
||||
_workerSelf.dataManager.completeData(data);
|
||||
_workerSelf.postMessage({
|
||||
id: e.data.id,
|
||||
payload: data,
|
||||
status: 'success',
|
||||
});
|
||||
},
|
||||
function () {
|
||||
_workerSelf.postMessage({
|
||||
id: e.data.id,
|
||||
status: 'error',
|
||||
});
|
||||
}
|
||||
);
|
||||
} else if (e.data.type === 'complete') {
|
||||
var animation = e.data.animation;
|
||||
_workerSelf.dataManager.completeData(animation);
|
||||
_workerSelf.postMessage({
|
||||
id: e.data.id,
|
||||
payload: animation,
|
||||
status: 'success',
|
||||
});
|
||||
} else if (e.data.type === 'loadData') {
|
||||
_workerSelf.assetLoader.load(
|
||||
e.data.path,
|
||||
e.data.fullPath,
|
||||
function (data) {
|
||||
_workerSelf.postMessage({
|
||||
id: e.data.id,
|
||||
payload: data,
|
||||
status: 'success',
|
||||
});
|
||||
},
|
||||
function () {
|
||||
_workerSelf.postMessage({
|
||||
id: e.data.id,
|
||||
status: 'error',
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
workerInstance.onmessage = function (event) {
|
||||
var data = event.data;
|
||||
var id = data.id;
|
||||
var process = processes[id];
|
||||
processes[id] = null;
|
||||
if (data.status === 'success') {
|
||||
process.onComplete(data.payload);
|
||||
} else if (process.onError) {
|
||||
process.onError();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function createProcess(onComplete, onError) {
|
||||
_counterId += 1;
|
||||
var id = 'processId_' + _counterId;
|
||||
processes[id] = {
|
||||
onComplete: onComplete,
|
||||
onError: onError,
|
||||
};
|
||||
return id;
|
||||
}
|
||||
|
||||
function loadAnimation(path, onComplete, onError) {
|
||||
setupWorker();
|
||||
var processId = createProcess(onComplete, onError);
|
||||
workerInstance.postMessage({
|
||||
type: 'loadAnimation',
|
||||
path: path,
|
||||
fullPath: window.location.origin + window.location.pathname,
|
||||
id: processId,
|
||||
});
|
||||
}
|
||||
|
||||
function loadData(path, onComplete, onError) {
|
||||
setupWorker();
|
||||
var processId = createProcess(onComplete, onError);
|
||||
workerInstance.postMessage({
|
||||
type: 'loadData',
|
||||
path: path,
|
||||
fullPath: window.location.origin + window.location.pathname,
|
||||
id: processId,
|
||||
});
|
||||
}
|
||||
|
||||
function completeAnimation(anim, onComplete, onError) {
|
||||
setupWorker();
|
||||
var processId = createProcess(onComplete, onError);
|
||||
workerInstance.postMessage({
|
||||
type: 'complete',
|
||||
animation: anim,
|
||||
id: processId,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
loadAnimation: loadAnimation,
|
||||
loadData: loadData,
|
||||
completeAnimation: completeAnimation,
|
||||
};
|
||||
}());
|
||||
|
||||
export default dataManager;
|
Reference in New Issue
Block a user