mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-18 05:33:54 +01:00
Corporation Research Trees are now properly saved
This commit is contained in:
parent
376e520a60
commit
fb9676e04e
@ -21,7 +21,9 @@
|
||||
}
|
||||
|
||||
.Treant > .researched {
|
||||
background-color: #444;
|
||||
background-color: #666;
|
||||
pointer-events: none;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.Treant > .locked > div {
|
||||
|
762
dist/engine.bundle.js
vendored
762
dist/engine.bundle.js
vendored
File diff suppressed because it is too large
Load Diff
4
dist/engine.css
vendored
4
dist/engine.css
vendored
@ -2169,7 +2169,9 @@ button {
|
||||
font-size: 12px; }
|
||||
|
||||
.Treant > .researched {
|
||||
background-color: #444; }
|
||||
background-color: #666;
|
||||
pointer-events: none;
|
||||
font-size: 16px; }
|
||||
|
||||
.Treant > .locked > div {
|
||||
color: red;
|
||||
|
@ -119,6 +119,7 @@ function Industry(params={}) {
|
||||
this.type = params.type ? params.type : 0;
|
||||
|
||||
this.sciResearch = new Material({name: "Scientific Research"});
|
||||
this.researched = {}; // Object of acquired Research. Keys = research name
|
||||
|
||||
//A map of the NAME of materials required to create produced materials to
|
||||
//how many are needed to produce 1 unit of produced materials
|
||||
@ -1163,44 +1164,65 @@ Industry.prototype.getMarketFactor = function(mat) {
|
||||
|
||||
// Returns a boolean indicating whether this Industry has the specified Research
|
||||
Industry.prototype.hasResearch = function(name) {
|
||||
return (this.researched[name] === true);
|
||||
}
|
||||
|
||||
Industry.prototype.updateResearchTree = function() {
|
||||
const researchTree = IndustryResearchTrees[this.type];
|
||||
return (researchTree.researched[name] != null);
|
||||
|
||||
// Since ResearchTree data isnt saved, we'll update the Research Tree data
|
||||
// based on the stored 'researched' property in the Industry object
|
||||
if (Object.keys(researchTree.researched).length !== Object.keys(this.researched).length) {
|
||||
console.log("Updating Corporation Research Tree Data");
|
||||
for (let research in this.researched) {
|
||||
researchTree.research(research);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get multipliers from Research
|
||||
Industry.prototype.getAdvertisingMultiplier = function() {
|
||||
this.updateResearchTree();
|
||||
return IndustryResearchTrees[this.type].getAdvertisingMultiplier();
|
||||
}
|
||||
|
||||
Industry.prototype.getEmployeeChaMultiplier = function() {
|
||||
this.updateResearchTree();
|
||||
return IndustryResearchTrees[this.type].getEmployeeChaMultiplier();
|
||||
}
|
||||
|
||||
Industry.prototype.getEmployeeCreMultiplier = function() {
|
||||
this.updateResearchTree();
|
||||
return IndustryResearchTrees[this.type].getEmployeeCreMultiplier();
|
||||
}
|
||||
|
||||
Industry.prototype.getEmployeeEffMultiplier = function() {
|
||||
this.updateResearchTree();
|
||||
return IndustryResearchTrees[this.type].getEmployeeEffMultiplier();
|
||||
}
|
||||
|
||||
Industry.prototype.getEmployeeIntMultiplier = function() {
|
||||
this.updateResearchTree();
|
||||
return IndustryResearchTrees[this.type].getEmployeeIntMultiplier();
|
||||
}
|
||||
|
||||
Industry.prototype.getProductionMultiplier = function() {
|
||||
this.updateResearchTree();
|
||||
return IndustryResearchTrees[this.type].getProductionMultiplier();
|
||||
}
|
||||
|
||||
Industry.prototype.getSalesMultiplier = function() {
|
||||
this.updateResearchTree();
|
||||
return IndustryResearchTrees[this.type].getSalesMultiplier();
|
||||
}
|
||||
|
||||
Industry.prototype.getScientificResearchMultiplier = function() {
|
||||
this.updateResearchTree();
|
||||
return IndustryResearchTrees[this.type].getScientificResearchMultiplier();
|
||||
}
|
||||
|
||||
Industry.prototype.getStorageMultiplier = function() {
|
||||
this.updateResearchTree();
|
||||
return IndustryResearchTrees[this.type].getStorageMultiplier();
|
||||
}
|
||||
|
||||
@ -1214,8 +1236,10 @@ Industry.prototype.createResearchBox = function() {
|
||||
researchTreeBox = null;
|
||||
}
|
||||
|
||||
this.updateResearchTree();
|
||||
const researchTree = IndustryResearchTrees[this.type];
|
||||
|
||||
|
||||
// Create the popup first, so that the tree diagram can be added to it
|
||||
// This is handled by Treant
|
||||
researchTreeBox = createPopup(boxId, [], { backgroundColor: "black" });
|
||||
@ -1257,8 +1281,8 @@ Industry.prototype.createResearchBox = function() {
|
||||
this.sciResearch.qty -= research.cost;
|
||||
|
||||
// Get the Node from the Research Tree and set its 'researched' property
|
||||
const node = researchTree.findNode(allResearch[i]);
|
||||
node.researched = true;
|
||||
researchTree.research(allResearch[i]);
|
||||
this.researched[allResearch[i]] = true;
|
||||
|
||||
return this.createResearchBox();
|
||||
} else {
|
||||
@ -3630,13 +3654,18 @@ Corporation.prototype.displayCorporationOverviewContent = function() {
|
||||
"per second before taxes.";
|
||||
const txt = createElement("p", { innerHTML: descText, });
|
||||
|
||||
let allocateBtn;
|
||||
const dividendPercentInput = createElement("input", {
|
||||
margin: "5px",
|
||||
placeholder: "Dividend %",
|
||||
type: "number",
|
||||
onkeyup: (e) => {
|
||||
e.preventDefault();
|
||||
if (e.keyCode === 13) {allocateBtn.click();}
|
||||
}
|
||||
});
|
||||
|
||||
const allocateBtn = createElement("button", {
|
||||
allocateBtn = createElement("button", {
|
||||
class: "std-button",
|
||||
display: "inline-block",
|
||||
innerText: "Allocate Dividend Percentage",
|
||||
@ -3653,17 +3682,14 @@ Corporation.prototype.displayCorporationOverviewContent = function() {
|
||||
}
|
||||
});
|
||||
|
||||
const cancelBtn = createElement("button", {
|
||||
const cancelBtn = createPopupCloseButton(popupId, {
|
||||
class: "std-button",
|
||||
display: "inline-block",
|
||||
innerText: "Cancel",
|
||||
clickListener: () => {
|
||||
removeElementById(popupId);
|
||||
return false;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
createPopup(popupId, [txt, dividendPercentInput, allocateBtn, cancelBtn]);
|
||||
dividendPercentInput.focus();
|
||||
},
|
||||
});
|
||||
companyManagementPanel.appendChild(issueDividends);
|
||||
@ -3971,7 +3997,10 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
|
||||
fontSize:"14px",
|
||||
}));
|
||||
industryOverviewUpgrades.appendChild(createElement("br", {}));
|
||||
for (var i = 0; i < numUpgrades; ++i) {
|
||||
for (let i = 0; i < numUpgrades; ++i) {
|
||||
if (division.hasResearch("AutoBrew") && i == 0) {
|
||||
continue; // AutoBrew disables Coffee upgrades, which is index 0
|
||||
}
|
||||
(function(i, corp, division, office) {
|
||||
var upgrade = IndustryUpgrades[i.toString()];
|
||||
if (upgrade == null) {
|
||||
@ -4300,72 +4329,74 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
|
||||
industryEmployeePanel.appendChild(industryOfficeUpgradeSizeButton);
|
||||
|
||||
//Throw Office Party
|
||||
industryEmployeePanel.appendChild(createElement("a", {
|
||||
class:"a-link-button", display:"inline-block", innerText:"Throw Party",
|
||||
fontSize:"13px",
|
||||
tooltip:"Throw an office party to increase your employee's morale and happiness",
|
||||
clickListener:()=>{
|
||||
var popupId = "cmpy-mgmt-throw-office-party-popup";
|
||||
var txt = createElement("p", {
|
||||
innerText:"Enter the amount of money you would like to spend PER EMPLOYEE " +
|
||||
"on this office party"
|
||||
});
|
||||
var totalCostTxt = createElement("p", {
|
||||
innerText:"Throwing this party will cost a total of $0"
|
||||
});
|
||||
var confirmBtn;
|
||||
var input = createElement("input", {
|
||||
type:"number", margin:"5px", placeholder:"$ / employee",
|
||||
inputListener:()=>{
|
||||
if (isNaN(input.value) || input.value < 0) {
|
||||
totalCostTxt.innerText = "Invalid value entered!"
|
||||
} else {
|
||||
var totalCost = input.value * office.employees.length;
|
||||
totalCostTxt.innerText = "Throwing this party will cost a total of " + numeralWrapper.format(totalCost, '$0.000a');
|
||||
}
|
||||
},
|
||||
onkeyup:(e)=>{
|
||||
e.preventDefault();
|
||||
if (e.keyCode === 13) {confirmBtn.click();}
|
||||
}
|
||||
});
|
||||
confirmBtn = createElement("a", {
|
||||
class:"a-link-button",
|
||||
display:"inline-block",
|
||||
innerText:"Throw Party",
|
||||
clickListener:()=>{
|
||||
if (isNaN(input.value) || input.value < 0) {
|
||||
dialogBoxCreate("Invalid value entered");
|
||||
} else {
|
||||
var totalCost = input.value * office.employees.length;
|
||||
if (this.funds.lt(totalCost)) {
|
||||
dialogBoxCreate("You don't have enough company funds to throw this party!");
|
||||
if (!division.hasResearch("AutoPartyManager")) {
|
||||
industryEmployeePanel.appendChild(createElement("a", {
|
||||
class:"a-link-button", display:"inline-block", innerText:"Throw Party",
|
||||
fontSize:"13px",
|
||||
tooltip:"Throw an office party to increase your employee's morale and happiness",
|
||||
clickListener:()=>{
|
||||
var popupId = "cmpy-mgmt-throw-office-party-popup";
|
||||
var txt = createElement("p", {
|
||||
innerText:"Enter the amount of money you would like to spend PER EMPLOYEE " +
|
||||
"on this office party"
|
||||
});
|
||||
var totalCostTxt = createElement("p", {
|
||||
innerText:"Throwing this party will cost a total of $0"
|
||||
});
|
||||
var confirmBtn;
|
||||
var input = createElement("input", {
|
||||
type:"number", margin:"5px", placeholder:"$ / employee",
|
||||
inputListener:()=>{
|
||||
if (isNaN(input.value) || input.value < 0) {
|
||||
totalCostTxt.innerText = "Invalid value entered!"
|
||||
} else {
|
||||
this.funds = this.funds.minus(totalCost);
|
||||
var mult;
|
||||
for (var fooit = 0; fooit < office.employees.length; ++fooit) {
|
||||
mult = office.employees[fooit].throwParty(input.value);
|
||||
}
|
||||
dialogBoxCreate("You threw a party for the office! The morale and happiness " +
|
||||
"of each employee increased by " + formatNumber((mult-1) * 100, 2) + "%.");
|
||||
removeElementById(popupId);
|
||||
var totalCost = input.value * office.employees.length;
|
||||
totalCostTxt.innerText = "Throwing this party will cost a total of " + numeralWrapper.format(totalCost, '$0.000a');
|
||||
}
|
||||
},
|
||||
onkeyup:(e)=>{
|
||||
e.preventDefault();
|
||||
if (e.keyCode === 13) {confirmBtn.click();}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
var cancelBtn = createElement("a", {
|
||||
class:"a-link-button",
|
||||
display:"inline-block",
|
||||
innerText:"Cancel",
|
||||
clickListener:()=>{
|
||||
removeElementById(popupId);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
createPopup(popupId, [txt, totalCostTxt, input, confirmBtn, cancelBtn]);
|
||||
}
|
||||
}));
|
||||
});
|
||||
confirmBtn = createElement("a", {
|
||||
class:"a-link-button",
|
||||
display:"inline-block",
|
||||
innerText:"Throw Party",
|
||||
clickListener:()=>{
|
||||
if (isNaN(input.value) || input.value < 0) {
|
||||
dialogBoxCreate("Invalid value entered");
|
||||
} else {
|
||||
var totalCost = input.value * office.employees.length;
|
||||
if (this.funds.lt(totalCost)) {
|
||||
dialogBoxCreate("You don't have enough company funds to throw this party!");
|
||||
} else {
|
||||
this.funds = this.funds.minus(totalCost);
|
||||
var mult;
|
||||
for (var fooit = 0; fooit < office.employees.length; ++fooit) {
|
||||
mult = office.employees[fooit].throwParty(input.value);
|
||||
}
|
||||
dialogBoxCreate("You threw a party for the office! The morale and happiness " +
|
||||
"of each employee increased by " + formatNumber((mult-1) * 100, 2) + "%.");
|
||||
removeElementById(popupId);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
var cancelBtn = createElement("a", {
|
||||
class:"a-link-button",
|
||||
display:"inline-block",
|
||||
innerText:"Cancel",
|
||||
clickListener:()=>{
|
||||
removeElementById(popupId);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
createPopup(popupId, [txt, totalCostTxt, input, confirmBtn, cancelBtn]);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
industryEmployeeManagementUI = createElement("div", {});
|
||||
industryEmployeeInfo = createElement("p", {margin:"4px", padding:"4px"});
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { ResearchTree } from "./ResearchTree";
|
||||
import { BaseResearchTree,
|
||||
getBaseResearchTreeCopy } from "./data/BaseResearchTree";
|
||||
import { getBaseResearchTreeCopy } from "./data/BaseResearchTree";
|
||||
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
|
||||
import { Reviver } from "../../utils/JSONReviver";
|
||||
|
||||
interface IIndustryMap<T> {
|
||||
Energy: T;
|
||||
Utilities: T;
|
||||
@ -105,7 +106,7 @@ export const IndustryDescriptions: IIndustryMap<string> = {
|
||||
|
||||
// Map of available Research for each Industry. This data is held in a
|
||||
// ResearchTree object
|
||||
export const IndustryResearchTrees: IIndustryMap<ResearchTree> = {
|
||||
export let IndustryResearchTrees: IIndustryMap<ResearchTree> = {
|
||||
Energy: getBaseResearchTreeCopy(),
|
||||
Utilities: getBaseResearchTreeCopy(),
|
||||
Agriculture: getBaseResearchTreeCopy(),
|
||||
@ -121,3 +122,7 @@ export const IndustryResearchTrees: IIndustryMap<ResearchTree> = {
|
||||
Healthcare: getBaseResearchTreeCopy(),
|
||||
RealEstate: getBaseResearchTreeCopy(),
|
||||
}
|
||||
|
||||
export function loadIndustryResearchTrees(saveString: string): void {
|
||||
IndustryResearchTrees = JSON.parse(saveString, Reviver);
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
// Each Node in the Research Trees only holds the name(s) of Research,
|
||||
// not an actual Research object. The name can be used to obtain a reference
|
||||
// to the corresponding Research object using the ResearchMap
|
||||
|
||||
import { Research } from "./Research";
|
||||
import { ResearchMap } from "./ResearchMap";
|
||||
|
||||
@ -17,6 +16,7 @@ interface IConstructorParams {
|
||||
}
|
||||
|
||||
export class Node {
|
||||
|
||||
// All child Nodes in the tree
|
||||
// The Research held in this Node is a prerequisite for all Research in
|
||||
// child Nodes
|
||||
@ -37,7 +37,7 @@ export class Node {
|
||||
// Name of the Research held in this Node
|
||||
text: string = "";
|
||||
|
||||
constructor(p: IConstructorParams) {
|
||||
constructor(p: IConstructorParams = {cost: 0, text: ""}) {
|
||||
if (ResearchMap[p.text] == null) {
|
||||
throw new Error(`Invalid Research name used when constructing ResearchTree Node: ${p.text}`);
|
||||
}
|
||||
@ -112,6 +112,7 @@ export class Node {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A ResearchTree defines all available Research in an Industry
|
||||
// The root node in a Research Tree must always be the "Hi-Tech R&D Laboratory"
|
||||
export class ResearchTree {
|
||||
|
@ -5,9 +5,6 @@ import { ResearchMap } from "../ResearchMap";
|
||||
import { ResearchTree,
|
||||
Node } from "../ResearchTree";
|
||||
|
||||
|
||||
export const BaseResearchTree: ResearchTree = new ResearchTree();
|
||||
|
||||
function makeNode(name: string): Node {
|
||||
const research: Research | null = ResearchMap[name];
|
||||
if (research == null) {
|
||||
@ -17,43 +14,46 @@ function makeNode(name: string): Node {
|
||||
return new Node({ text: research.name, cost: research.cost });
|
||||
}
|
||||
|
||||
const rootNode: Node = makeNode("Hi-Tech R&D Laboratory");
|
||||
const autoBrew: Node = makeNode("AutoBrew");
|
||||
const autoParty: Node = makeNode("AutoPartyManager");
|
||||
const autoDrugs: Node = makeNode("Automatic Drug Administration");
|
||||
const cph4: Node = makeNode("CPH4 Injections");
|
||||
const drones: Node = makeNode("Drones");
|
||||
const dronesAssembly: Node = makeNode("Drones - Assembly");
|
||||
const dronesTransport: Node = makeNode("Drones - Transport");
|
||||
const goJuice: Node = makeNode("Go-Juice");
|
||||
const joywire: Node = makeNode("JoyWire");
|
||||
const marketta1: Node = makeNode("Market-TA.I");
|
||||
const marketta2: Node = makeNode("Market-TA.II");
|
||||
const overclock: Node = makeNode("Overclock");
|
||||
const scAssemblers: Node = makeNode("Self-Correcting Assemblers");
|
||||
const stimu: Node = makeNode("Sti.mu");
|
||||
|
||||
autoDrugs.addChild(goJuice);
|
||||
autoDrugs.addChild(cph4);
|
||||
|
||||
drones.addChild(dronesAssembly);
|
||||
drones.addChild(dronesTransport);
|
||||
|
||||
marketta1.addChild(marketta2);
|
||||
|
||||
overclock.addChild(stimu);
|
||||
|
||||
rootNode.addChild(autoBrew);
|
||||
rootNode.addChild(autoParty);
|
||||
rootNode.addChild(autoDrugs);
|
||||
rootNode.addChild(drones);
|
||||
rootNode.addChild(joywire);
|
||||
rootNode.addChild(marketta1);
|
||||
rootNode.addChild(overclock);
|
||||
rootNode.addChild(scAssemblers);
|
||||
|
||||
BaseResearchTree.setRoot(rootNode);
|
||||
|
||||
export function getBaseResearchTreeCopy(): ResearchTree {
|
||||
return Object.assign(Object.create(Object.getPrototypeOf(BaseResearchTree)), BaseResearchTree);
|
||||
const baseResearchTree: ResearchTree = new ResearchTree();
|
||||
|
||||
const rootNode: Node = makeNode("Hi-Tech R&D Laboratory");
|
||||
const autoBrew: Node = makeNode("AutoBrew");
|
||||
const autoParty: Node = makeNode("AutoPartyManager");
|
||||
const autoDrugs: Node = makeNode("Automatic Drug Administration");
|
||||
const cph4: Node = makeNode("CPH4 Injections");
|
||||
const drones: Node = makeNode("Drones");
|
||||
const dronesAssembly: Node = makeNode("Drones - Assembly");
|
||||
const dronesTransport: Node = makeNode("Drones - Transport");
|
||||
const goJuice: Node = makeNode("Go-Juice");
|
||||
const joywire: Node = makeNode("JoyWire");
|
||||
const marketta1: Node = makeNode("Market-TA.I");
|
||||
const marketta2: Node = makeNode("Market-TA.II");
|
||||
const overclock: Node = makeNode("Overclock");
|
||||
const scAssemblers: Node = makeNode("Self-Correcting Assemblers");
|
||||
const stimu: Node = makeNode("Sti.mu");
|
||||
|
||||
autoDrugs.addChild(goJuice);
|
||||
autoDrugs.addChild(cph4);
|
||||
|
||||
drones.addChild(dronesAssembly);
|
||||
drones.addChild(dronesTransport);
|
||||
|
||||
marketta1.addChild(marketta2);
|
||||
|
||||
overclock.addChild(stimu);
|
||||
|
||||
rootNode.addChild(autoBrew);
|
||||
rootNode.addChild(autoParty);
|
||||
rootNode.addChild(autoDrugs);
|
||||
rootNode.addChild(drones);
|
||||
rootNode.addChild(joywire);
|
||||
rootNode.addChild(marketta1);
|
||||
rootNode.addChild(overclock);
|
||||
rootNode.addChild(scAssemblers);
|
||||
|
||||
baseResearchTree.setRoot(rootNode);
|
||||
|
||||
return baseResearchTree;
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ import {loadAliases, loadGlobalAliases,
|
||||
Aliases, GlobalAliases} from "./Alias";
|
||||
import {Companies, loadCompanies} from "./Company/Companies";
|
||||
import {CompanyPosition} from "./Company/CompanyPosition";
|
||||
import { IndustryResearchTrees,
|
||||
loadIndustryResearchTrees } from "./Corporation/IndustryData";
|
||||
import {CONSTANTS} from "./Constants";
|
||||
import {Engine} from "./engine";
|
||||
import { Factions,
|
||||
@ -36,19 +38,20 @@ import Decimal from "decimal.js";
|
||||
let saveObject = new BitburnerSaveObject();
|
||||
|
||||
function BitburnerSaveObject() {
|
||||
this.PlayerSave = "";
|
||||
this.AllServersSave = "";
|
||||
this.CompaniesSave = "";
|
||||
this.FactionsSave = "";
|
||||
this.SpecialServerIpsSave = "";
|
||||
this.AliasesSave = "";
|
||||
this.GlobalAliasesSave = "";
|
||||
this.MessagesSave = "";
|
||||
this.StockMarketSave = "";
|
||||
this.SettingsSave = "";
|
||||
this.FconfSettingsSave = "";
|
||||
this.VersionSave = "";
|
||||
this.AllGangsSave = "";
|
||||
this.PlayerSave = "";
|
||||
this.AllServersSave = "";
|
||||
this.CompaniesSave = "";
|
||||
this.FactionsSave = "";
|
||||
this.SpecialServerIpsSave = "";
|
||||
this.AliasesSave = "";
|
||||
this.GlobalAliasesSave = "";
|
||||
this.MessagesSave = "";
|
||||
this.StockMarketSave = "";
|
||||
this.SettingsSave = "";
|
||||
this.FconfSettingsSave = "";
|
||||
this.VersionSave = "";
|
||||
this.AllGangsSave = "";
|
||||
this.CorporationResearchTreesSave = "";
|
||||
}
|
||||
|
||||
BitburnerSaveObject.prototype.saveGame = function(db) {
|
||||
@ -260,6 +263,7 @@ function loadImportedGame(saveObj, saveString) {
|
||||
var tempMessages = null;
|
||||
var tempStockMarket = null;
|
||||
var tempAllGangs = null;
|
||||
let tempCorporationResearchTrees = null;
|
||||
|
||||
//Check to see if the imported save file can be parsed. If any
|
||||
//errors are caught it will fail
|
||||
@ -332,7 +336,8 @@ function loadImportedGame(saveObj, saveString) {
|
||||
try {
|
||||
loadAllGangs(tempSaveObj.AllGangsSave);
|
||||
} catch(e) {
|
||||
console.log("ERROR: Failed to parse AllGangsSave: " + e);
|
||||
console.error(`Failed to parse AllGangsSave: {e}`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
|
Loading…
Reference in New Issue
Block a user