copy files

This commit is contained in:
2023-08-05 12:12:18 +00:00
parent 421d75f665
commit b88fdf85e1
66 changed files with 3852 additions and 5 deletions
+2
View File
@@ -29,6 +29,7 @@
"dotenv": "^16.3.1",
"eventemitter3": "^5.0.1",
"express": "^4.18.2",
"express-session": "^1.17.3",
"ky": "^0.33.3",
"lodash-es": "^4.17.21",
"pinia": "^2.1.4",
@@ -43,6 +44,7 @@
"@tsconfig/node18": "^18.2.0",
"@types/bootstrap": "^5.2.6",
"@types/express": "^4.17.17",
"@types/express-session": "^1.17.7",
"@types/lodash-es": "^4.17.8",
"@types/node": "^18.17.0",
"@vitejs/plugin-vue": "^4.2.3",
+50
View File
@@ -38,6 +38,9 @@ dependencies:
express:
specifier: ^4.18.2
version: 4.18.2
express-session:
specifier: ^1.17.3
version: 1.17.3
ky:
specifier: ^0.33.3
version: 0.33.3
@@ -76,6 +79,9 @@ devDependencies:
'@types/express':
specifier: ^4.17.17
version: 4.17.17
'@types/express-session':
specifier: ^1.17.7
version: 1.17.7
'@types/lodash-es':
specifier: ^4.17.8
version: 4.17.8
@@ -550,6 +556,12 @@ packages:
'@types/send': 0.17.1
dev: true
/@types/express-session@1.17.7:
resolution: {integrity: sha512-L25080PBYoRLu472HY/HNCxaXY8AaGgqGC8/p/8+BYMhG0RDOLQ1wpXOpAzr4Gi5TGozTKyJv5BVODM5UNyVMw==}
dependencies:
'@types/express': 4.17.17
dev: true
/@types/express@4.17.17:
resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==}
dependencies:
@@ -1311,6 +1323,11 @@ packages:
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
dev: false
/cookie@0.4.2:
resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==}
engines: {node: '>= 0.6'}
dev: false
/cookie@0.5.0:
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
engines: {node: '>= 0.6'}
@@ -1784,6 +1801,22 @@ packages:
strip-final-newline: 3.0.0
dev: true
/express-session@1.17.3:
resolution: {integrity: sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==}
engines: {node: '>= 0.8.0'}
dependencies:
cookie: 0.4.2
cookie-signature: 1.0.6
debug: 2.6.9
depd: 2.0.0
on-headers: 1.0.2
parseurl: 1.3.3
safe-buffer: 5.2.1
uid-safe: 2.1.5
transitivePeerDependencies:
- supports-color
dev: false
/express@4.18.2:
resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==}
engines: {node: '>= 0.10.0'}
@@ -2674,6 +2707,11 @@ packages:
ee-first: 1.1.1
dev: false
/on-headers@1.0.2:
resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==}
engines: {node: '>= 0.8'}
dev: false
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
@@ -2907,6 +2945,11 @@ packages:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
/random-bytes@1.0.0:
resolution: {integrity: sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==}
engines: {node: '>= 0.8'}
dev: false
/range-parser@1.2.1:
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
engines: {node: '>= 0.6'}
@@ -3520,6 +3563,13 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
/uid-safe@2.1.5:
resolution: {integrity: sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==}
engines: {node: '>= 0.8'}
dependencies:
random-bytes: 1.0.0
dev: false
/unbox-primitive@1.0.2:
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
dependencies:
+13
View File
@@ -0,0 +1,13 @@
import "dotenv/config";
import { DataSource } from "typeorm";
export const AppDataSource = new DataSource({
type: "mysql",
host: process.env.DB_HOST,
database: "db/database.sqlite",
synchronize: true,
logging: false,
entities: [],
migrations: [],
subscribers: [],
})
+9
View File
@@ -0,0 +1,9 @@
declare namespace NodeJS {
interface ProcessEnv {
NODE_ENV: 'development' | 'production';
GAME_DB_SERVER: string;
GAME_DB_DATABASE: string;
GAME_DB_USER: string;
GAME_DB_PASSWORD: string;
}
}
+1079
View File
@@ -0,0 +1,1079 @@
/* tslint:disable */
/**
* AUTO-GENERATED FILE @ 2023-08-05 12:06:36 - DO NOT EDIT!
*
* This file was automatically generated by schemats v.3.0.3
* $ schemats generate -c mysql://username:password@127.0.0.1/hidche_hwe -C -t board -t city -t comment -t diplomacy -t emperior -t event -t general -t general_access_log -t general_record -t general_turn -t hall -t message -t nation -t nation_env -t nation_turn -t ng_auction -t ng_auction_bid -t ng_betting -t ng_diplomacy -t ng_games -t ng_history -t ng_old_generals -t ng_old_nations -t plock -t rank_data -t reserved_open -t select_npc_token -t select_pool -t statistic -t storage -t tournament -t troop -t user_record -t vote -t vote_comment -t world_history -s hidche_hwe
*
*/
export type EnumTarget = 'MONTH' | 'OCCUPY_CITY' | 'DESTROY_NATION' | 'PRE_MONTH' | 'UNITED';
export type EnumAuctionType = 'buyRice' | 'sellRice' | 'uniqueItem';
export type EnumReqResource = 'gold' | 'rice' | 'inheritPoint';
export type EnumLogType = 'action' | 'battle_brief' | 'battle' | 'history';
export type EnumMsgType = 'private' | 'national' | 'public' | 'diplomacy';
export type EnumPermission = 'normal' | 'auditor' | 'ambassador';
export type EnumType = 'GAME' | 'ETC' | 'TOURNAMENT';
export type EnumState = 'proposed' | 'activated' | 'cancelled' | 'replaced';
export namespace BoardFields {
export type no = number;
export type nationNo = number;
export type isSecret = boolean;
export type date = Date;
export type generalNo = number;
export type author = string;
export type authorIcon = string | null;
export type title = string;
export type text = string;
}
export interface Board {
no: BoardFields.no;
nationNo: BoardFields.nationNo;
isSecret: BoardFields.isSecret;
date: BoardFields.date;
generalNo: BoardFields.generalNo;
author: BoardFields.author;
authorIcon: BoardFields.authorIcon;
title: BoardFields.title;
text: BoardFields.text;
}
export namespace CityFields {
export type city = number;
export type name = string;
export type level = number;
export type nation = number;
export type supply = number;
export type front = number;
export type pop = number;
export type popMax = number;
export type agri = number;
export type agriMax = number;
export type comm = number;
export type commMax = number;
export type secu = number;
export type secuMax = number;
export type trust = number;
export type trade = number | null;
export type dead = number;
export type def = number;
export type defMax = number;
export type wall = number;
export type wallMax = number;
export type officerSet = number;
export type state = number;
export type region = number;
export type term = number;
export type conflict = string;
}
export interface City {
city: CityFields.city;
name: CityFields.name;
level: CityFields.level;
nation: CityFields.nation;
supply: CityFields.supply;
front: CityFields.front;
pop: CityFields.pop;
popMax: CityFields.popMax;
agri: CityFields.agri;
agriMax: CityFields.agriMax;
comm: CityFields.comm;
commMax: CityFields.commMax;
secu: CityFields.secu;
secuMax: CityFields.secuMax;
trust: CityFields.trust;
trade: CityFields.trade;
dead: CityFields.dead;
def: CityFields.def;
defMax: CityFields.defMax;
wall: CityFields.wall;
wallMax: CityFields.wallMax;
officerSet: CityFields.officerSet;
state: CityFields.state;
region: CityFields.region;
term: CityFields.term;
conflict: CityFields.conflict;
}
export namespace CommentFields {
export type no = number;
export type nationNo = number;
export type isSecret = boolean;
export type date = Date;
export type documentNo = number;
export type generalNo = number;
export type author = string;
export type text = string;
}
export interface Comment {
no: CommentFields.no;
nationNo: CommentFields.nationNo;
isSecret: CommentFields.isSecret;
date: CommentFields.date;
documentNo: CommentFields.documentNo;
generalNo: CommentFields.generalNo;
author: CommentFields.author;
text: CommentFields.text;
}
export namespace DiplomacyFields {
export type no = number;
export type me = number;
export type you = number;
export type state = number | null;
export type term = number | null;
export type dead = number | null;
export type showing = Date | null;
}
export interface Diplomacy {
no: DiplomacyFields.no;
me: DiplomacyFields.me;
you: DiplomacyFields.you;
state: DiplomacyFields.state;
term: DiplomacyFields.term;
dead: DiplomacyFields.dead;
showing: DiplomacyFields.showing;
}
export namespace EmperiorFields {
export type no = number;
export type serverId = string | null;
export type phase = string | null;
export type nationCount = string | null;
export type nationName = string | null;
export type nationHist = string | null;
export type genCount = string | null;
export type personalHist = string | null;
export type specialHist = string | null;
export type name = string | null;
export type type = string | null;
export type color = string | null;
export type year = number | null;
export type month = number | null;
export type power = number | null;
export type gennum = number | null;
export type citynum = number | null;
export type pop = string | null;
export type poprate = string | null;
export type gold = number | null;
export type rice = number | null;
export type l12Name = string | null;
export type l12Pic = string | null;
export type l11Name = string | null;
export type l11Pic = string | null;
export type l10Name = string | null;
export type l10Pic = string | null;
export type l9Name = string | null;
export type l9Pic = string | null;
export type l8Name = string | null;
export type l8Pic = string | null;
export type l7Name = string | null;
export type l7Pic = string | null;
export type l6Name = string | null;
export type l6Pic = string | null;
export type l5Name = string | null;
export type l5Pic = string | null;
export type tiger = string | null;
export type eagle = string | null;
export type gen = string | null;
export type history = string | null;
export type aux = string | null;
}
export interface Emperior {
no: EmperiorFields.no;
serverId: EmperiorFields.serverId;
phase: EmperiorFields.phase;
nationCount: EmperiorFields.nationCount;
nationName: EmperiorFields.nationName;
nationHist: EmperiorFields.nationHist;
genCount: EmperiorFields.genCount;
personalHist: EmperiorFields.personalHist;
specialHist: EmperiorFields.specialHist;
name: EmperiorFields.name;
type: EmperiorFields.type;
color: EmperiorFields.color;
year: EmperiorFields.year;
month: EmperiorFields.month;
power: EmperiorFields.power;
gennum: EmperiorFields.gennum;
citynum: EmperiorFields.citynum;
pop: EmperiorFields.pop;
poprate: EmperiorFields.poprate;
gold: EmperiorFields.gold;
rice: EmperiorFields.rice;
l12Name: EmperiorFields.l12Name;
l12Pic: EmperiorFields.l12Pic;
l11Name: EmperiorFields.l11Name;
l11Pic: EmperiorFields.l11Pic;
l10Name: EmperiorFields.l10Name;
l10Pic: EmperiorFields.l10Pic;
l9Name: EmperiorFields.l9Name;
l9Pic: EmperiorFields.l9Pic;
l8Name: EmperiorFields.l8Name;
l8Pic: EmperiorFields.l8Pic;
l7Name: EmperiorFields.l7Name;
l7Pic: EmperiorFields.l7Pic;
l6Name: EmperiorFields.l6Name;
l6Pic: EmperiorFields.l6Pic;
l5Name: EmperiorFields.l5Name;
l5Pic: EmperiorFields.l5Pic;
tiger: EmperiorFields.tiger;
eagle: EmperiorFields.eagle;
gen: EmperiorFields.gen;
history: EmperiorFields.history;
aux: EmperiorFields.aux;
}
export namespace EventFields {
export type id = number;
export type target = EnumTarget;
export type priority = number;
export type condition = string;
export type action = string;
}
export interface Event {
id: EventFields.id;
target: EventFields.target;
priority: EventFields.priority;
condition: EventFields.condition;
action: EventFields.action;
}
export namespace GeneralFields {
export type no = number;
export type owner = number;
export type npcmsg = string | null;
export type npc = number;
export type npcOrg = number | null;
export type affinity = number | null;
export type bornyear = number | null;
export type deadyear = number | null;
export type newmsg = number | null;
export type picture = string;
export type imgsvr = number;
export type name = string;
export type ownerName = string | null;
export type nation = number;
export type city = number;
export type troop = number;
export type leadership = number;
export type leadershipExp = number;
export type strength = number;
export type strengthExp = number;
export type intel = number;
export type intelExp = number;
export type injury = number;
export type experience = number;
export type dedication = number;
export type dex1 = number;
export type dex2 = number;
export type dex3 = number;
export type dex4 = number;
export type dex5 = number;
export type officerLevel = number;
export type officerCity = number;
export type permission = EnumPermission | null;
export type gold = number;
export type rice = number;
export type crew = number;
export type crewtype = number;
export type train = number;
export type atmos = number;
export type weapon = string;
export type book = string;
export type horse = string;
export type item = string;
export type turntime = Date;
export type recentWar = Date | null;
export type makelimit = number | null;
export type killturn = number | null;
export type block = number | null;
export type dedlevel = number | null;
export type explevel = number | null;
export type age = number | null;
export type startage = number | null;
export type belong = number | null;
export type betray = number | null;
export type personal = string;
export type special = string;
export type specage = number | null;
export type special2 = string;
export type specage2 = number | null;
export type defenceTrain = number | null;
export type tnmt = number | null;
export type myset = number | null;
export type tournament = number | null;
export type newvote = number | null;
export type lastTurn = string;
export type aux = string;
export type penalty = string | null;
}
export interface General {
no: GeneralFields.no;
owner: GeneralFields.owner;
npcmsg: GeneralFields.npcmsg;
npc: GeneralFields.npc;
npcOrg: GeneralFields.npcOrg;
affinity: GeneralFields.affinity;
bornyear: GeneralFields.bornyear;
deadyear: GeneralFields.deadyear;
newmsg: GeneralFields.newmsg;
picture: GeneralFields.picture;
imgsvr: GeneralFields.imgsvr;
name: GeneralFields.name;
ownerName: GeneralFields.ownerName;
nation: GeneralFields.nation;
city: GeneralFields.city;
troop: GeneralFields.troop;
leadership: GeneralFields.leadership;
leadershipExp: GeneralFields.leadershipExp;
strength: GeneralFields.strength;
strengthExp: GeneralFields.strengthExp;
intel: GeneralFields.intel;
intelExp: GeneralFields.intelExp;
injury: GeneralFields.injury;
experience: GeneralFields.experience;
dedication: GeneralFields.dedication;
dex1: GeneralFields.dex1;
dex2: GeneralFields.dex2;
dex3: GeneralFields.dex3;
dex4: GeneralFields.dex4;
dex5: GeneralFields.dex5;
officerLevel: GeneralFields.officerLevel;
officerCity: GeneralFields.officerCity;
permission: GeneralFields.permission;
gold: GeneralFields.gold;
rice: GeneralFields.rice;
crew: GeneralFields.crew;
crewtype: GeneralFields.crewtype;
train: GeneralFields.train;
atmos: GeneralFields.atmos;
weapon: GeneralFields.weapon;
book: GeneralFields.book;
horse: GeneralFields.horse;
item: GeneralFields.item;
turntime: GeneralFields.turntime;
recentWar: GeneralFields.recentWar;
makelimit: GeneralFields.makelimit;
killturn: GeneralFields.killturn;
block: GeneralFields.block;
dedlevel: GeneralFields.dedlevel;
explevel: GeneralFields.explevel;
age: GeneralFields.age;
startage: GeneralFields.startage;
belong: GeneralFields.belong;
betray: GeneralFields.betray;
personal: GeneralFields.personal;
special: GeneralFields.special;
specage: GeneralFields.specage;
special2: GeneralFields.special2;
specage2: GeneralFields.specage2;
defenceTrain: GeneralFields.defenceTrain;
tnmt: GeneralFields.tnmt;
myset: GeneralFields.myset;
tournament: GeneralFields.tournament;
newvote: GeneralFields.newvote;
lastTurn: GeneralFields.lastTurn;
aux: GeneralFields.aux;
penalty: GeneralFields.penalty;
}
export namespace GeneralAccessLogFields {
export type id = number;
export type generalId = number;
export type userId = number | null;
export type lastRefresh = Date | null;
export type refresh = number;
export type refreshTotal = number;
export type refreshScore = number;
export type refreshScoreTotal = number;
}
export interface GeneralAccessLog {
id: GeneralAccessLogFields.id;
generalId: GeneralAccessLogFields.generalId;
userId: GeneralAccessLogFields.userId;
lastRefresh: GeneralAccessLogFields.lastRefresh;
refresh: GeneralAccessLogFields.refresh;
refreshTotal: GeneralAccessLogFields.refreshTotal;
refreshScore: GeneralAccessLogFields.refreshScore;
refreshScoreTotal: GeneralAccessLogFields.refreshScoreTotal;
}
export namespace GeneralRecordFields {
export type id = number;
export type generalId = number;
export type logType = EnumLogType;
export type year = number;
export type month = number;
export type text = string;
}
export interface GeneralRecord {
id: GeneralRecordFields.id;
generalId: GeneralRecordFields.generalId;
logType: GeneralRecordFields.logType;
year: GeneralRecordFields.year;
month: GeneralRecordFields.month;
text: GeneralRecordFields.text;
}
export namespace GeneralTurnFields {
export type id = number;
export type generalId = number;
export type turnIdx = number;
export type action = string;
export type arg = string | null;
export type brief = string | null;
}
export interface GeneralTurn {
id: GeneralTurnFields.id;
generalId: GeneralTurnFields.generalId;
turnIdx: GeneralTurnFields.turnIdx;
action: GeneralTurnFields.action;
arg: GeneralTurnFields.arg;
brief: GeneralTurnFields.brief;
}
export namespace HallFields {
export type id = number;
export type serverId = string;
export type season = number;
export type scenario = number;
export type generalNo = number;
export type type = string;
export type value = number;
export type owner = number | null;
export type aux = string;
}
export interface Hall {
id: HallFields.id;
serverId: HallFields.serverId;
season: HallFields.season;
scenario: HallFields.scenario;
generalNo: HallFields.generalNo;
type: HallFields.type;
value: HallFields.value;
owner: HallFields.owner;
aux: HallFields.aux;
}
export namespace MessageFields {
export type id = number;
export type mailbox = number;
export type type = EnumMsgType;
export type src = number;
export type dest = number;
export type time = Date;
export type validUntil = Date;
export type message = string;
}
export interface Message {
id: MessageFields.id;
mailbox: MessageFields.mailbox;
type: MessageFields.type;
src: MessageFields.src;
dest: MessageFields.dest;
time: MessageFields.time;
validUntil: MessageFields.validUntil;
message: MessageFields.message;
}
export namespace NationFields {
export type nation = number;
export type name = string;
export type color = string;
export type capital = number | null;
export type capset = number | null;
export type gennum = number | null;
export type gold = number | null;
export type rice = number | null;
export type bill = number | null;
export type rate = number | null;
export type rateTmp = number | null;
export type secretlimit = number | null;
export type chiefSet = number;
export type scout = number | null;
export type war = number | null;
export type strategicCmdLimit = number | null;
export type surlimit = number | null;
export type tech = number | null;
export type power = number | null;
export type spy = string;
export type level = number | null;
export type type = string;
export type aux = string;
}
export interface Nation {
nation: NationFields.nation;
name: NationFields.name;
color: NationFields.color;
capital: NationFields.capital;
capset: NationFields.capset;
gennum: NationFields.gennum;
gold: NationFields.gold;
rice: NationFields.rice;
bill: NationFields.bill;
rate: NationFields.rate;
rateTmp: NationFields.rateTmp;
secretlimit: NationFields.secretlimit;
chiefSet: NationFields.chiefSet;
scout: NationFields.scout;
war: NationFields.war;
strategicCmdLimit: NationFields.strategicCmdLimit;
surlimit: NationFields.surlimit;
tech: NationFields.tech;
power: NationFields.power;
spy: NationFields.spy;
level: NationFields.level;
type: NationFields.type;
aux: NationFields.aux;
}
export namespace NationEnvFields {
export type id = number;
export type namespace = number;
export type key = string;
export type value = string;
}
export interface NationEnv {
id: NationEnvFields.id;
namespace: NationEnvFields.namespace;
key: NationEnvFields.key;
value: NationEnvFields.value;
}
export namespace NationTurnFields {
export type id = number;
export type nationId = number;
export type officerLevel = number;
export type turnIdx = number;
export type action = string;
export type arg = string | null;
export type brief = string | null;
}
export interface NationTurn {
id: NationTurnFields.id;
nationId: NationTurnFields.nationId;
officerLevel: NationTurnFields.officerLevel;
turnIdx: NationTurnFields.turnIdx;
action: NationTurnFields.action;
arg: NationTurnFields.arg;
brief: NationTurnFields.brief;
}
export namespace NgAuctionFields {
export type id = number;
export type type = EnumAuctionType;
export type finished = Buffer;
export type target = string | null;
export type hostGeneralId = number;
export type reqResource = EnumReqResource;
export type openDate = Date;
export type closeDate = Date;
export type detail = string;
}
export interface NgAuction {
id: NgAuctionFields.id;
type: NgAuctionFields.type;
finished: NgAuctionFields.finished;
target: NgAuctionFields.target;
hostGeneralId: NgAuctionFields.hostGeneralId;
reqResource: NgAuctionFields.reqResource;
openDate: NgAuctionFields.openDate;
closeDate: NgAuctionFields.closeDate;
detail: NgAuctionFields.detail;
}
export namespace NgAuctionBidFields {
export type no = number;
export type auctionId = number;
export type owner = number | null;
export type generalId = number;
export type amount = number;
export type date = Date;
export type aux = string;
}
export interface NgAuctionBid {
no: NgAuctionBidFields.no;
auctionId: NgAuctionBidFields.auctionId;
owner: NgAuctionBidFields.owner;
generalId: NgAuctionBidFields.generalId;
amount: NgAuctionBidFields.amount;
date: NgAuctionBidFields.date;
aux: NgAuctionBidFields.aux;
}
export namespace NgBettingFields {
export type id = number;
export type bettingId = number;
export type generalId = number;
export type userId = number | null;
export type bettingType = string;
export type amount = number;
}
export interface NgBetting {
id: NgBettingFields.id;
bettingId: NgBettingFields.bettingId;
generalId: NgBettingFields.generalId;
userId: NgBettingFields.userId;
bettingType: NgBettingFields.bettingType;
amount: NgBettingFields.amount;
}
export namespace NgDiplomacyFields {
export type no = number;
export type srcNationId = number;
export type destNationId = number;
export type prevNo = number | null;
export type state = EnumState;
export type textBrief = string;
export type textDetail = string;
export type date = Date;
export type srcSigner = number;
export type destSigner = number | null;
export type aux = string | null;
}
export interface NgDiplomacy {
no: NgDiplomacyFields.no;
srcNationId: NgDiplomacyFields.srcNationId;
destNationId: NgDiplomacyFields.destNationId;
prevNo: NgDiplomacyFields.prevNo;
state: NgDiplomacyFields.state;
textBrief: NgDiplomacyFields.textBrief;
textDetail: NgDiplomacyFields.textDetail;
date: NgDiplomacyFields.date;
srcSigner: NgDiplomacyFields.srcSigner;
destSigner: NgDiplomacyFields.destSigner;
aux: NgDiplomacyFields.aux;
}
export namespace NgGamesFields {
export type id = number;
export type serverId = string;
export type date = Date;
export type winnerNation = number | null;
export type map = string | null;
export type season = number;
export type scenario = number;
export type scenarioName = string;
export type env = string;
}
export interface NgGames {
id: NgGamesFields.id;
serverId: NgGamesFields.serverId;
date: NgGamesFields.date;
winnerNation: NgGamesFields.winnerNation;
map: NgGamesFields.map;
season: NgGamesFields.season;
scenario: NgGamesFields.scenario;
scenarioName: NgGamesFields.scenarioName;
env: NgGamesFields.env;
}
export namespace NgHistoryFields {
export type no = number;
export type serverId = string;
export type year = number | null;
export type month = number | null;
export type map = string | null;
export type globalHistory = string | null;
export type globalAction = string | null;
export type nations = string | null;
}
export interface NgHistory {
no: NgHistoryFields.no;
serverId: NgHistoryFields.serverId;
year: NgHistoryFields.year;
month: NgHistoryFields.month;
map: NgHistoryFields.map;
globalHistory: NgHistoryFields.globalHistory;
globalAction: NgHistoryFields.globalAction;
nations: NgHistoryFields.nations;
}
export namespace NgOldGeneralsFields {
export type id = number;
export type serverId = string;
export type generalNo = number;
export type owner = number | null;
export type name = string;
export type lastYearmonth = number;
export type turntime = Date;
export type data = string;
}
export interface NgOldGenerals {
id: NgOldGeneralsFields.id;
serverId: NgOldGeneralsFields.serverId;
generalNo: NgOldGeneralsFields.generalNo;
owner: NgOldGeneralsFields.owner;
name: NgOldGeneralsFields.name;
lastYearmonth: NgOldGeneralsFields.lastYearmonth;
turntime: NgOldGeneralsFields.turntime;
data: NgOldGeneralsFields.data;
}
export namespace NgOldNationsFields {
export type id = number;
export type serverId = string;
export type nation = number;
export type data = string;
export type date = Date;
}
export interface NgOldNations {
id: NgOldNationsFields.id;
serverId: NgOldNationsFields.serverId;
nation: NgOldNationsFields.nation;
data: NgOldNationsFields.data;
date: NgOldNationsFields.date;
}
export namespace PlockFields {
export type no = number;
export type type = EnumType;
export type plock = number;
export type locktime = Date;
}
export interface Plock {
no: PlockFields.no;
type: PlockFields.type;
plock: PlockFields.plock;
locktime: PlockFields.locktime;
}
export namespace RankDataFields {
export type id = number;
export type nationId = number;
export type generalId = number;
export type type = string;
export type value = number;
}
export interface RankData {
id: RankDataFields.id;
nationId: RankDataFields.nationId;
generalId: RankDataFields.generalId;
type: RankDataFields.type;
value: RankDataFields.value;
}
export namespace ReservedOpenFields {
export type id = number;
export type options = string | null;
export type date = Date | null;
}
export interface ReservedOpen {
id: ReservedOpenFields.id;
options: ReservedOpenFields.options;
date: ReservedOpenFields.date;
}
export namespace SelectNpcTokenFields {
export type id = number;
export type owner = number;
export type validUntil = Date;
export type pickMoreFrom = Date;
export type pickResult = string;
export type nonce = number;
}
export interface SelectNpcToken {
id: SelectNpcTokenFields.id;
owner: SelectNpcTokenFields.owner;
validUntil: SelectNpcTokenFields.validUntil;
pickMoreFrom: SelectNpcTokenFields.pickMoreFrom;
pickResult: SelectNpcTokenFields.pickResult;
nonce: SelectNpcTokenFields.nonce;
}
export namespace SelectPoolFields {
export type id = number;
export type uniqueName = string;
export type owner = number | null;
export type generalId = number | null;
export type reservedUntil = Date | null;
export type info = string;
}
export interface SelectPool {
id: SelectPoolFields.id;
uniqueName: SelectPoolFields.uniqueName;
owner: SelectPoolFields.owner;
generalId: SelectPoolFields.generalId;
reservedUntil: SelectPoolFields.reservedUntil;
info: SelectPoolFields.info;
}
export namespace StatisticFields {
export type no = number;
export type year = number | null;
export type month = number | null;
export type nationCount = number | null;
export type nationName = string | null;
export type nationHist = string | null;
export type genCount = string | null;
export type personalHist = string | null;
export type specialHist = string | null;
export type powerHist = string | null;
export type crewtype = string | null;
export type etc = string | null;
export type aux = string | null;
}
export interface Statistic {
no: StatisticFields.no;
year: StatisticFields.year;
month: StatisticFields.month;
nationCount: StatisticFields.nationCount;
nationName: StatisticFields.nationName;
nationHist: StatisticFields.nationHist;
genCount: StatisticFields.genCount;
personalHist: StatisticFields.personalHist;
specialHist: StatisticFields.specialHist;
powerHist: StatisticFields.powerHist;
crewtype: StatisticFields.crewtype;
etc: StatisticFields.etc;
aux: StatisticFields.aux;
}
export namespace StorageFields {
export type id = number;
export type namespace = string;
export type key = string;
export type value = string;
}
export interface Storage {
id: StorageFields.id;
namespace: StorageFields.namespace;
key: StorageFields.key;
value: StorageFields.value;
}
export namespace TournamentFields {
export type seq = number;
export type no = number | null;
export type npc = number | null;
export type name = string | null;
export type w = string | null;
export type b = string | null;
export type h = string | null;
export type leadership = number | null;
export type strength = number | null;
export type intel = number | null;
export type lvl = number | null;
export type grp = number | null;
export type grpNo = number | null;
export type win = number | null;
export type draw = number | null;
export type lose = number | null;
export type gl = number | null;
export type prmt = number | null;
}
export interface Tournament {
seq: TournamentFields.seq;
no: TournamentFields.no;
npc: TournamentFields.npc;
name: TournamentFields.name;
w: TournamentFields.w;
b: TournamentFields.b;
h: TournamentFields.h;
leadership: TournamentFields.leadership;
strength: TournamentFields.strength;
intel: TournamentFields.intel;
lvl: TournamentFields.lvl;
grp: TournamentFields.grp;
grpNo: TournamentFields.grpNo;
win: TournamentFields.win;
draw: TournamentFields.draw;
lose: TournamentFields.lose;
gl: TournamentFields.gl;
prmt: TournamentFields.prmt;
}
export namespace TroopFields {
export type troopLeader = number;
export type nation = number;
export type name = string;
}
export interface Troop {
troopLeader: TroopFields.troopLeader;
nation: TroopFields.nation;
name: TroopFields.name;
}
export namespace UserRecordFields {
export type id = number;
export type userId = number;
export type serverId = string;
export type logType = string;
export type year = number;
export type month = number;
export type date = Date | null;
export type text = string;
}
export interface UserRecord {
id: UserRecordFields.id;
userId: UserRecordFields.userId;
serverId: UserRecordFields.serverId;
logType: UserRecordFields.logType;
year: UserRecordFields.year;
month: UserRecordFields.month;
date: UserRecordFields.date;
text: UserRecordFields.text;
}
export namespace VoteFields {
export type id = number;
export type voteId = number;
export type generalId = number;
export type nationId = number;
export type selection = string;
}
export interface Vote {
id: VoteFields.id;
voteId: VoteFields.voteId;
generalId: VoteFields.generalId;
nationId: VoteFields.nationId;
selection: VoteFields.selection;
}
export namespace VoteCommentFields {
export type id = number;
export type voteId = number;
export type generalId = number;
export type nationId = number;
export type generalName = string;
export type nationName = string;
export type text = string;
export type date = Date | null;
}
export interface VoteComment {
id: VoteCommentFields.id;
voteId: VoteCommentFields.voteId;
generalId: VoteCommentFields.generalId;
nationId: VoteCommentFields.nationId;
generalName: VoteCommentFields.generalName;
nationName: VoteCommentFields.nationName;
text: VoteCommentFields.text;
date: VoteCommentFields.date;
}
export namespace WorldHistoryFields {
export type id = number;
export type nationId = number;
export type year = number;
export type month = number;
export type text = string;
}
export interface WorldHistory {
id: WorldHistoryFields.id;
nationId: WorldHistoryFields.nationId;
year: WorldHistoryFields.year;
month: WorldHistoryFields.month;
text: WorldHistoryFields.text;
}
+45 -1
View File
@@ -1,8 +1,17 @@
import 'reflect-metadata';
import { BasicQueryDTO } from './api/index.js';
import { validate } from 'class-validator';
import express, { Request, Response } from "express"
import { AppDataSource } from "./data_source"
import dotenv from "dotenv";
import session from "express-session";
import path from 'node:path';
export async function test(){
dotenv.config({
path: `.env.server.${process.env.NODE_ENV}`
});
export async function test() {
console.log("Hello World!");
const dto = new BasicQueryDTO();
@@ -17,4 +26,39 @@ export async function test(){
await test();
AppDataSource.initialize().then(async () => {
// create express app
const app = express()
app.use(bodyParser.json())
app.use(session({
secret: ownConfig.sessionSecret,
resave: false,
saveUninitialized: false,
}))
app.set('etag', false);
initPKIjs();
app.use('/', rootRouter);
await fs.mkdir(certDirPath, { recursive: true });
if (!existsSync(rootSignKeyPath)) {
console.info('generate sign key');
generateRootSignKey();
}
if (!existsSync(rootCertPath)) {
console.info('generate root certificate');
await generateRootCertificateEasy();
}
// start express server
app.listen(ownConfig.port)
console.log(`Express server has started on port ${ownConfig.port}`)
}).catch(error => console.log(error))
export default {};
+26
View File
@@ -0,0 +1,26 @@
export function APIPathGen<T, V>(
obj: T,
callback: (path: string[], tail: V, pathParam?: Record<string, string | number>) => unknown,
pathParam?: Record<string, string | number>
): T;
export function StrVar<PathType extends string>(paramKey: string): <NextCall>(next: NextCall) => {
[v in PathType]: NextCall
};
export function NumVar<NextCall>(paramKey: string, next: NextCall): {
[v: number]: NextCall
};
/*
const apiPath = {
SomePath: someFunc,
User: StrVar<'a'|'b'>('name')({
Update: someFunc,
Delete: someFunc,
}),
NationInfo: NumVar('id', {
show: someFunc
})
}
*/
+68
View File
@@ -0,0 +1,68 @@
export function APIPathGen(obj, callback, path, pathParams) {
return new Proxy(obj, {
get(target, key) {
let nextPath;
if (path === undefined) {
nextPath = [key.toString()];
}
else {
nextPath = [...path, key.toString()];
}
if (pathParams !== undefined) {
pathParams = { ...pathParams };
}
const varType = target.__nextVarType;
let varKey = target.__nextVarKey;
let next;
if (varType !== undefined && varKey !== undefined) {
if(varType == 'number'){
if(key != Number(key)){
throw `${key} is not ${varType}`;
}
key = Number(key);
}
else if ((typeof key) !== varType) {
throw `${key} is not ${varType}, but ${typeof key}`;
}
if(pathParams === undefined){
pathParams = {}
}
pathParams[varKey] = key;
nextPath.pop();
next = target.next;
}
else if (key in target) {
next = target[key];
}
else {
throw `${nextPath} is not exists`;
}
if (typeof (next) === 'function') {
return callback(nextPath, next, pathParams);
}
return APIPathGen(next, callback, nextPath, pathParams);
}
})
}
//generic 인자로 '자동'을 주려면 생략해야하므로 2단 호출
export function StrVar(key) {
return (next) => {
return {
__nextVarType: 'string',
__nextVarKey: key,
next
}
}
}
export function NumVar(key, next) {
return {
__nextVarType: 'number',
__nextVarKey: key,
next
}
}
+2
View File
@@ -0,0 +1,2 @@
export type Bytes = ArrayBuffer | DataView | Uint8Array;
export type BytesLike = Bytes | string;
+3
View File
@@ -0,0 +1,3 @@
export type Entries<T> = {
[K in keyof T]: [K, T[K]];
}[keyof T][];
+586
View File
@@ -0,0 +1,586 @@
import { unwrap_err } from "./unwrap_err";
// https://github.com/coxcore/postposition 의 php 버전을 다시 typescript로 재 작성
const KO_START_CODE = 44032;
const KO_FINISH_CODE = 55203;
const HANJA_START_CODE = 0x4e00;
const HANJA_FINISH_CODE = 0xfa0b;
const REG_INVALID_CHAR_W_HANJA = /[^a-zA-Z0-9---\s]+/u;
const REG_INVALID_CHAR = /[^a-zA-Z0-9--\s]+/u;
const REG_TARGET_CHAR = /^[\s\S]*?(\S*)\s*$/u;
const PRE_REG_NORMAL_FIXED = [
"check|[hm]ook|limit",
];
const PRE_REG_SPECIAL_CHAR = [
"[ㄱ-ㄷㅁ-ㅎ]",
"^[036]",
"[^a-zA-Z][036]",
"[a-zA-Z]9",
"^[mn]",
"\\S[mn]e?",
"\\S(?:[aeiom]|lu)b",
"(?:u|\\S[aei]|[^o]o)p",
"(?:^i|[^auh]i|\\Su|[^ei][ae]|[^oi]o)t",
"(?:\\S[iou]|[^e][ae])c?k",
"\\S[aeiou](?:c|ng)",
"foot|go+d|b[ai]g|private",
"^(?:app|kor)",
];
const PRE_REG_SPECIAL_RO = [
"[178ㄹ]",
"^[lr]",
"^\\Sr",
"\\Sle?",
];
const DEFAULT_POSTPOSITION = {
"은": "는",
"이": "가",
"과": "와",
"이나": "나",
"을": "를",
"으로": "로",
"이라": "라",
"이랑": "랑",
};
const JONGSUNG_HANJA = [
0x523b, 0x5374, 0x5404, 0x606a, 0x6164, 0x6bbc, 0x73cf, 0x811a,
0x89ba, 0x89d2, 0x95a3, 0x4f83, 0x520a, 0x58be, 0x5978, 0x59e6,
0x5e72, 0x5e79, 0x61c7, 0x63c0, 0x6746, 0x67ec, 0x687f, 0x6f97,
0x764e, 0x770b, 0x78f5, 0x7a08, 0x7aff, 0x7c21, 0x809d, 0x826e,
0x8271, 0x8aeb, 0x9593, 0x4e6b, 0x559d, 0x66f7, 0x6e34, 0x78a3,
0x7aed, 0x845b, 0x8910, 0x874e, 0x97a8, 0x52d8, 0x574e, 0x582a,
0x5d4c, 0x611f, 0x61be, 0x6221, 0x6562, 0x67d1, 0x6a44, 0x6e1b,
0x7518, 0x75b3, 0x76e3, 0x77b0, 0x7d3a, 0x90af, 0x9451, 0x9452,
0x9f95, 0x5323, 0x5cac, 0x7532, 0x80db, 0x9240, 0x9598, 0x525b,
0x5808, 0x59dc, 0x5ca1, 0x5d17, 0x5eb7, 0x5f3a, 0x5f4a, 0x6177,
0x6c5f, 0x757a, 0x7586, 0x7ce0, 0x7d73, 0x7db1, 0x7f8c, 0x8154,
0x8221, 0x8591, 0x8941, 0x8b1b, 0x92fc, 0x964d, 0x9c47, 0x5580,
0x5ba2, 0x5751, 0xf901, 0x7cb3, 0x7fb9, 0x91b5, 0x4e7e, 0x4ef6,
0x5065, 0x5dfe, 0x5efa, 0x6106, 0x6957, 0x8171, 0x8654, 0x8e47,
0x9375, 0x9a2b, 0x4e5e, 0x5091, 0x6770, 0x6840, 0x5109, 0x528d,
0x5292, 0x6aa2, 0x77bc, 0x9210, 0x9ed4, 0x52ab, 0x602f, 0x8ff2,
0x64ca, 0x683c, 0x6a84, 0x6fc0, 0x8188, 0x89a1, 0x9694, 0x5805,
0x727d, 0x72ac, 0x7504, 0x7d79, 0x7e6d, 0x80a9, 0x898b, 0x8b74,
0x9063, 0x9d51, 0x6289, 0x6c7a, 0x6f54, 0x7d50, 0x7f3a, 0x8a23,
0x517c, 0x614a, 0x7b9d, 0x8b19, 0x9257, 0x938c, 0x4eac, 0x4fd3,
0x501e, 0x50be, 0x5106, 0x52c1, 0x52cd, 0x537f, 0x5770, 0x5883,
0x5e9a, 0x5f91, 0x6176, 0x61ac, 0x64ce, 0x656c, 0x666f, 0x66bb,
0x66f4, 0x6897, 0x6d87, 0x7085, 0x70f1, 0x749f, 0x74a5, 0x74ca,
0x75d9, 0x786c, 0x78ec, 0x7adf, 0x7af6, 0x7d45, 0x7d93, 0x8015,
0x803f, 0x811b, 0x8396, 0x8b66, 0x8f15, 0x9015, 0x93e1, 0x9803,
0x9838, 0x9a5a, 0x9be8, 0x54ed, 0x659b, 0x66f2, 0x688f, 0x7a40,
0x8c37, 0x9d60, 0x56f0, 0x5764, 0x5d11, 0x6606, 0x68b1, 0x68cd,
0x6efe, 0x7428, 0x889e, 0x9be4, 0x6c68, 0xf904, 0x9aa8, 0x4f9b,
0x516c, 0x5171, 0x529f, 0x5b54, 0x5de5, 0x6050, 0x606d, 0x62f1,
0x63a7, 0x653b, 0x73d9, 0x7a7a, 0x86a3, 0x8ca2, 0x978f, 0x4e32,
0x5ed3, 0x69e8, 0x85ff, 0x90ed, 0xf905, 0x51a0, 0x5b98, 0x5bec,
0x6163, 0x68fa, 0x6b3e, 0x704c, 0x742f, 0x74d8, 0x7ba1, 0x7f50,
0x83c5, 0x89c0, 0x8cab, 0x95dc, 0x9928, 0x522e, 0x605d, 0x62ec,
0x9002, 0x4f8a, 0x5149, 0x5321, 0x58d9, 0x5ee3, 0x66e0, 0x6d38,
0x709a, 0x72c2, 0x73d6, 0x7b50, 0x80f1, 0x945b, 0x5b8f, 0x7d18,
0x80b1, 0x8f5f, 0x570b, 0x5c40, 0x83ca, 0x97a0, 0x97ab, 0x9eb4,
0x541b, 0x7a98, 0x7fa4, 0x88d9, 0x8ecd, 0x90e1, 0x5800, 0x5c48,
0x6398, 0x7a9f, 0x5bae, 0x5f13, 0x7a79, 0x7aae, 0x828e, 0x8eac,
0x5026, 0x5238, 0x52f8, 0x5377, 0x5708, 0x62f3, 0x6372, 0x6b0a,
0x6dc3, 0x7737, 0x53a5, 0x7357, 0x8568, 0x8e76, 0x95d5, 0x52fb,
0x5747, 0x7547, 0x7b60, 0x83cc, 0x921e, 0xf908, 0x6a58, 0x514b,
0x524b, 0x5287, 0x621f, 0x68d8, 0x6975, 0x9699, 0x50c5, 0x52a4,
0x52e4, 0x61c3, 0x65a4, 0x6839, 0x69ff, 0x747e, 0x7b4b, 0x82b9,
0x83eb, 0x89b2, 0x8b39, 0x8fd1, 0x9949, 0xf909, 0x4eca, 0x5997,
0x64d2, 0x6611, 0x6a8e, 0x7434, 0x7981, 0x79bd, 0x82a9, 0x887e,
0x887f, 0x895f, 0xf90a, 0x9326, 0x4f0b, 0x53ca, 0x6025, 0x6271,
0x6c72, 0x7d1a, 0x7d66, 0x4e98, 0x5162, 0x77dc, 0x80af, 0x7dca,
0x4f76, 0x5409, 0x62ee, 0x6854, 0x91d1, 0x55ab, 0xf914, 0xf915,
0xf916, 0xf917, 0xf918, 0x8afe, 0xf919, 0xf91a, 0xf91b, 0xf91c,
0x6696, 0xf91d, 0x7156, 0xf91e, 0xf91f, 0x96e3, 0xf920, 0x634f,
0x637a, 0x5357, 0xf921, 0x678f, 0x6960, 0x6e73, 0xf922, 0x7537,
0xf923, 0xf924, 0xf925, 0x7d0d, 0xf926, 0xf927, 0x8872, 0x56ca,
0x5a18, 0xf928, 0xf929, 0xf92a, 0xf92b, 0xf92c, 0xf92e, 0x5e74,
0x649a, 0x79ca, 0x5ff5, 0x606c, 0x62c8, 0x637b, 0x5be7, 0x5bd7,
0xf93b, 0xf93c, 0xf93d, 0xf93e, 0xf93f, 0xf940, 0xf941, 0xf942,
0xf943, 0x6fc3, 0xf944, 0xf945, 0x81bf, 0x8fb2, 0x5ae9, 0x8a25,
0xf952, 0xf953, 0xf954, 0xf955, 0xf956, 0xf957, 0x80fd, 0xf958,
0xf959, 0x533f, 0x6eba, 0x4e39, 0x4eb6, 0x4f46, 0x55ae, 0x5718,
0x58c7, 0x5f56, 0x65b7, 0x65e6, 0x6a80, 0x6bb5, 0x6e4d, 0x77ed,
0x7aef, 0x7c1e, 0x7dde, 0x86cb, 0x8892, 0x9132, 0x935b, 0x64bb,
0x6fbe, 0x737a, 0x75b8, 0x9054, 0x5556, 0x574d, 0x61ba, 0x64d4,
0x66c7, 0x6de1, 0x6e5b, 0x6f6d, 0x6fb9, 0x75f0, 0x8043, 0x81bd,
0x8541, 0x8983, 0x8ac7, 0x8b5a, 0x931f, 0x6c93, 0x7553, 0x7b54,
0x8e0f, 0x905d, 0x5510, 0x5802, 0x5858, 0x5e62, 0x6207, 0x649e,
0x68e0, 0x7576, 0x7cd6, 0x87b3, 0x9ee8, 0x5b85, 0x5fb7, 0x60b3,
0x6bd2, 0x7006, 0x7258, 0x72a2, 0x7368, 0x7763, 0x79bf, 0x7be4,
0x7e9b, 0x8b80, 0x58a9, 0x60c7, 0x6566, 0x65fd, 0x66be, 0x6c8c,
0x711e, 0x71c9, 0x8c5a, 0x9813, 0x4e6d, 0x7a81, 0x4edd, 0x51ac,
0x51cd, 0x52d5, 0x540c, 0x61a7, 0x6771, 0x6850, 0x68df, 0x6d1e,
0x6f7c, 0x75bc, 0x77b3, 0x7ae5, 0x80f4, 0x8463, 0x9285, 0x5c6f,
0x81c0, 0x829a, 0x9041, 0x906f, 0x920d, 0x5f97, 0x5d9d, 0x6a59,
0x71c8, 0x767b, 0x7b49, 0x85e4, 0x8b04, 0x9127, 0x9a30, 0xf95c,
0x6d1b, 0x70d9, 0x73de, 0x7d61, 0x843d, 0xf95d, 0x916a, 0x99f1,
0xf95e, 0x4e82, 0x5375, 0x6b04, 0x6b12, 0x703e, 0x721b, 0x862d,
0x9e1e, 0x524c, 0x8fa3, 0x5d50, 0x64e5, 0x652c, 0x6b16, 0x6feb,
0x7c43, 0x7e9c, 0x85cd, 0x8964, 0x89bd, 0x62c9, 0x81d8, 0x881f,
0x5eca, 0x6717, 0x6d6a, 0x72fc, 0x7405, 0x746f, 0x8782, 0x90de,
0x51b7, 0x63a0, 0x7565, 0x4eae, 0x5006, 0x5169, 0x51c9, 0x6881,
0x6a11, 0x7cae, 0x7cb1, 0x7ce7, 0x826f, 0x8ad2, 0x8f1b, 0x91cf,
0x529b, 0x66c6, 0x6b77, 0x701d, 0x792b, 0x8f62, 0x9742, 0x6190,
0x6200, 0x6523, 0x6f23, 0x7149, 0x7489, 0x7df4, 0x806f, 0x84ee,
0x8f26, 0x9023, 0x934a, 0x51bd, 0x5217, 0x52a3, 0x6d0c, 0x70c8,
0x88c2, 0x5ec9, 0x6582, 0x6bae, 0x6fc2, 0x7c3e, 0x7375, 0x4ee4,
0x4f36, 0x56f9, 0xf95f, 0x5cba, 0x5dba, 0x601c, 0x73b2, 0x7b2d,
0x7f9a, 0x7fce, 0x8046, 0x901e, 0x9234, 0x96f6, 0x9748, 0x9818,
0x9f61, 0x788c, 0x797f, 0x7da0, 0x83c9, 0x9304, 0x9e7f, 0x9e93,
0x8ad6, 0x58df, 0x5f04, 0x6727, 0x7027, 0x74cf, 0x7c60, 0x807e,
0x9f8d, 0x516d, 0x622e, 0x9678, 0x4f96, 0x502b, 0x5d19, 0x6dea,
0x7db8, 0x8f2a, 0x5f8b, 0x6144, 0x6817, 0xf961, 0x9686, 0x52d2,
0x808b, 0x51dc, 0x51cc, 0x695e, 0x7a1c, 0x7dbe, 0x83f1, 0x9675,
0x541d, 0x6f7e, 0x71d0, 0x7498, 0x85fa, 0x8eaa, 0x96a3, 0x9c57,
0x9e9f, 0x6797, 0x6dcb, 0x7433, 0x81e8, 0x9716, 0x782c, 0x7acb,
0x7b20, 0x7c92, 0x5bde, 0x5e55, 0x6f20, 0x819c, 0x83ab, 0x9088,
0x4e07, 0x534d, 0x5a29, 0x5dd2, 0x5f4e, 0x6162, 0x633d, 0x6669,
0x66fc, 0x6eff, 0x6f2b, 0x7063, 0x779e, 0x842c, 0x8513, 0x883b,
0x8f13, 0x9945, 0x9c3b, 0x551c, 0x62b9, 0x672b, 0x6cab, 0x8309,
0x896a, 0x977a, 0x4ea1, 0x5984, 0x5fd8, 0x5fd9, 0x671b, 0x7db2,
0x7f54, 0x8292, 0x832b, 0x83bd, 0x8f1e, 0x9099, 0x8108, 0x8c8a,
0x964c, 0x9a40, 0x9ea5, 0x5b5f, 0x6c13, 0x731b, 0x76f2, 0x76df,
0x840c, 0x51aa, 0x8993, 0x514d, 0x5195, 0x52c9, 0x68c9, 0x6c94,
0x7704, 0x7720, 0x7dbf, 0x7dec, 0x9762, 0x9eb5, 0x6ec5, 0x8511,
0x51a5, 0x540d, 0x547d, 0x660e, 0x669d, 0x6927, 0x6e9f, 0x76bf,
0x7791, 0x8317, 0x84c2, 0x879f, 0x9169, 0x9298, 0x9cf4, 0x6728,
0x6c90, 0x7267, 0x76ee, 0x7766, 0x7a46, 0x9da9, 0x6b7f, 0x6c92,
0x5922, 0x6726, 0x8499, 0x58a8, 0x9ed8, 0x5011, 0x520e, 0x543b,
0x554f, 0x6587, 0x6c76, 0x7d0a, 0x7d0b, 0x805e, 0x868a, 0x9580,
0x96ef, 0x52ff, 0x6c95, 0x7269, 0x5cb7, 0x60b6, 0x610d, 0x61ab,
0x654f, 0x65fb, 0x65fc, 0x6c11, 0x6cef, 0x739f, 0x73c9, 0x7de1,
0x9594, 0x5bc6, 0x871c, 0x8b10, 0x525d, 0x535a, 0x62cd, 0x640f,
0x64b2, 0x6734, 0x6a38, 0x6cca, 0x73c0, 0x749e, 0x7b94, 0x7c95,
0x7e1b, 0x818a, 0x8236, 0x8584, 0x8feb, 0x96f9, 0x99c1, 0x4f34,
0x534a, 0x53cd, 0x53db, 0x62cc, 0x642c, 0x6500, 0x6591, 0x69c3,
0x6cee, 0x6f58, 0x73ed, 0x7554, 0x7622, 0x76e4, 0x76fc, 0x78d0,
0x78fb, 0x792c, 0x7d46, 0x822c, 0x87e0, 0x8fd4, 0x9812, 0x98ef,
0x52c3, 0x62d4, 0x64a5, 0x6e24, 0x6f51, 0x767c, 0x8dcb, 0x91b1,
0x9262, 0x9aee, 0x9b43, 0x5023, 0x508d, 0x574a, 0x59a8, 0x5c28,
0x5e47, 0x5f77, 0x623f, 0x653e, 0x65b9, 0x65c1, 0x6609, 0x678b,
0x699c, 0x6ec2, 0x78c5, 0x7d21, 0x80aa, 0x8180, 0x822b, 0x82b3,
0x84a1, 0x868c, 0x8a2a, 0x8b17, 0x90a6, 0x9632, 0x9f90, 0x4f2f,
0x4f70, 0x5e1b, 0x67cf, 0x6822, 0x767d, 0x767e, 0x9b44, 0x5e61,
0x6a0a, 0x7169, 0x71d4, 0x756a, 0xf964, 0x7e41, 0x8543, 0x85e9,
0x98dc, 0x4f10, 0x7b4f, 0x7f70, 0x95a5, 0x51e1, 0x5e06, 0x68b5,
0x6c3e, 0x6c4e, 0x6cdb, 0x72af, 0x7bc4, 0x8303, 0x6cd5, 0x743a,
0x50fb, 0x5288, 0x58c1, 0x64d8, 0x6a97, 0x74a7, 0x7656, 0x78a7,
0x8617, 0x95e2, 0x9739, 0xf965, 0x535e, 0x5f01, 0x8b8a, 0x8fa8,
0x8faf, 0x908a, 0x5225, 0x77a5, 0x9c49, 0x9f08, 0x4e19, 0x5002,
0x5175, 0x5c5b, 0x5e77, 0x661e, 0x663a, 0x67c4, 0x68c5, 0x70b3,
0x7501, 0x75c5, 0x79c9, 0x7add, 0x8f27, 0x9920, 0x9a08, 0x4f0f,
0x50d5, 0x5310, 0x535c, 0x5b93, 0x5fa9, 0x670d, 0x798f, 0x8179,
0x832f, 0x8514, 0x8907, 0x8986, 0x8f39, 0x8f3b, 0x99a5, 0x9c12,
0x672c, 0x4e76, 0x4ff8, 0x5949, 0x5c01, 0x5cef, 0x5cf0, 0x6367,
0x68d2, 0x70fd, 0x71a2, 0x742b, 0x7e2b, 0x84ec, 0x8702, 0x9022,
0x92d2, 0x9cf3, 0x5317, 0x5206, 0x5429, 0x5674, 0x58b3, 0x5954,
0x596e, 0x5fff, 0x61a4, 0x626e, 0x6610, 0x6c7e, 0x711a, 0x76c6,
0x7c89, 0x7cde, 0x7d1b, 0x82ac, 0x8cc1, 0x96f0, 0xf967, 0x4f5b,
0x5f17, 0x5f7f, 0x62c2, 0x5d29, 0x670b, 0x68da, 0x787c, 0x7e43,
0x9d6c, 0x56ac, 0x5b2a, 0x5f6c, 0x658c, 0x6ab3, 0x6baf, 0x6d5c,
0x6ff1, 0x7015, 0x725d, 0x73ad, 0x8ca7, 0x8cd3, 0x983b, 0x6191,
0x6c37, 0x8058, 0x9a01, 0x524a, 0xf969, 0x6714, 0xf96a, 0x5098,
0x522a, 0x5c71, 0x6563, 0x6c55, 0x73ca, 0x7523, 0x759d, 0x7b97,
0x849c, 0x9178, 0x9730, 0x4e77, 0x6492, 0x6bba, 0x715e, 0x85a9,
0x4e09, 0xf96b, 0x6749, 0x68ee, 0x6e17, 0x829f, 0x8518, 0x886b,
0x63f7, 0x6f81, 0x9212, 0x98af, 0x4e0a, 0x50b7, 0x50cf, 0x511f,
0x5546, 0x55aa, 0x5617, 0x5b40, 0x5c19, 0x5ce0, 0x5e38, 0x5e8a,
0x5ea0, 0x5ec2, 0x60f3, 0x6851, 0x6a61, 0x6e58, 0x723d, 0x7240,
0x72c0, 0x76f8, 0x7965, 0x7bb1, 0x7fd4, 0x88f3, 0x89f4, 0x8a73,
0x8c61, 0x8cde, 0x971c, 0x55c7, 0xf96c, 0x7a61, 0x7d22, 0x8272,
0x7272, 0x751f, 0x7525, 0xf96d, 0x7b19, 0x5915, 0x596d, 0x5e2d,
0x60dc, 0x6614, 0x6673, 0x6790, 0x6c50, 0x6dc5, 0x6f5f, 0x77f3,
0x78a9, 0x84c6, 0x91cb, 0x932b, 0x4ed9, 0x50ca, 0x5148, 0x5584,
0x5b0b, 0x5ba3, 0x6247, 0x657e, 0x65cb, 0x6e32, 0x717d, 0x7401,
0x7444, 0x7487, 0x74bf, 0x766c, 0x79aa, 0x7dda, 0x7e55, 0x7fa8,
0x817a, 0x81b3, 0x8239, 0x861a, 0x87ec, 0x8a75, 0x8de3, 0x9078,
0x9291, 0x9425, 0x994d, 0x9bae, 0x5368, 0x5c51, 0x6954, 0x6cc4,
0x6d29, 0x6e2b, 0x820c, 0x859b, 0x893b, 0x8a2d, 0x8aaa, 0x96ea,
0x9f67, 0x5261, 0x66b9, 0x6bb2, 0x7e96, 0x87fe, 0x8d0d, 0x9583,
0x965d, 0x651d, 0x6d89, 0x71ee, 0xf96e, 0x57ce, 0x59d3, 0x5bac,
0x6027, 0x60fa, 0x6210, 0x661f, 0x665f, 0x7329, 0x73f9, 0x76db,
0x7701, 0x7b6c, 0x8056, 0x8072, 0x8165, 0x8aa0, 0x9192, 0x4fd7,
0x5c6c, 0x675f, 0x6d91, 0x7c9f, 0x7e8c, 0x8b16, 0x8d16, 0x901f,
0x5b6b, 0x5dfd, 0x640d, 0x84c0, 0x905c, 0x98e1, 0x7387, 0x5b8b,
0x609a, 0x677e, 0x6dde, 0x8a1f, 0x8aa6, 0x9001, 0x980c, 0x53d4,
0x587e, 0x5919, 0x5b70, 0x5bbf, 0x6dd1, 0x6f5a, 0x719f, 0x7421,
0x74b9, 0x8085, 0x83fd, 0x5de1, 0x5f87, 0x5faa, 0x6042, 0x65ec,
0x6812, 0x696f, 0x6a53, 0x6b89, 0x6d35, 0x6df3, 0x73e3, 0x76fe,
0x77ac, 0x7b4d, 0x7d14, 0x8123, 0x821c, 0x8340, 0x84f4, 0x8563,
0x8a62, 0x8ac4, 0x9187, 0x931e, 0x9806, 0x99b4, 0x620c, 0x8853,
0x8ff0, 0x9265, 0x5d07, 0x5d27, 0x5d69, 0x745f, 0x819d, 0x8768,
0x6fd5, 0x62fe, 0x7fd2, 0x8936, 0x8972, 0x4e1e, 0x4e58, 0x50e7,
0x52dd, 0x5347, 0x627f, 0x6607, 0x7e69, 0x8805, 0x965e, 0x57f4,
0x5bd4, 0x5f0f, 0x606f, 0x62ed, 0x690d, 0x6b96, 0x6e5c, 0x7184,
0x7bd2, 0x8755, 0x8b58, 0x8efe, 0x98df, 0x98fe, 0x4f38, 0x4f81,
0x4fe1, 0x547b, 0x5a20, 0x5bb8, 0x613c, 0x65b0, 0x6668, 0x71fc,
0x7533, 0x795e, 0x7d33, 0x814e, 0x81e3, 0x8398, 0x85aa, 0x85ce,
0x8703, 0x8a0a, 0x8eab, 0x8f9b, 0xf971, 0x8fc5, 0x5931, 0x5ba4,
0x5be6, 0x6089, 0x5be9, 0x5c0b, 0x5fc3, 0x6c81, 0xf972, 0x6df1,
0x700b, 0x751a, 0x82af, 0x8af6, 0x4ec0, 0x5341, 0xf973, 0x96d9,
0x580a, 0x5cb3, 0x5dbd, 0x5e44, 0x60e1, 0x6115, 0x63e1, 0x6a02,
0x6e25, 0x9102, 0x9354, 0x984e, 0x9c10, 0x9f77, 0x5b89, 0x5cb8,
0x6309, 0x664f, 0x6848, 0x773c, 0x96c1, 0x978d, 0x9854, 0x9b9f,
0x65a1, 0x8b01, 0x8ecb, 0x95bc, 0x5535, 0x5ca9, 0x5dd6, 0x5eb5,
0x6697, 0x764c, 0x83f4, 0x95c7, 0x58d3, 0x62bc, 0x72ce, 0x9d28,
0x4ef0, 0x592e, 0x600f, 0x663b, 0x6b83, 0x79e7, 0x9d26, 0x5384,
0x627c, 0x6396, 0x6db2, 0x7e0a, 0x814b, 0x984d, 0x6afb, 0x7f4c,
0x9daf, 0x9e1a, 0x5f31, 0xf975, 0xf976, 0x7d04, 0x82e5, 0x846f,
0x84bb, 0x85e5, 0x8e8d, 0xf977, 0x4f6f, 0xf978, 0xf979, 0x58e4,
0x5b43, 0x6059, 0x63da, 0x6518, 0x656d, 0x6698, 0xf97a, 0x694a,
0x6a23, 0x6d0b, 0x7001, 0x716c, 0x75d2, 0x760d, 0x79b3, 0x7a70,
0xf97b, 0x7f8a, 0xf97c, 0x8944, 0xf97d, 0x8b93, 0x91c0, 0x967d,
0xf97e, 0x990a, 0x5104, 0x61b6, 0x6291, 0x6a8d, 0x81c6, 0x5043,
0x5830, 0x5f66, 0x7109, 0x8a00, 0x8afa, 0x5b7c, 0x8616, 0x4ffa,
0x513c, 0x56b4, 0x5944, 0x63a9, 0x6df9, 0x5daa, 0x696d, 0x5186,
0x4ea6, 0xf98a, 0x57df, 0x5f79, 0x6613, 0xf98b, 0xf98c, 0x75ab,
0x7e79, 0x8b6f, 0xf98d, 0x9006, 0x9a5b, 0x56a5, 0x5827, 0x59f8,
0x5a1f, 0x5bb4, 0xf98e, 0x5ef6, 0xf98f, 0xf990, 0x6350, 0x633b,
0xf991, 0x693d, 0x6c87, 0x6cbf, 0x6d8e, 0x6d93, 0x6df5, 0x6f14,
0xf992, 0x70df, 0x7136, 0x7159, 0xf993, 0x71c3, 0x71d5, 0xf994,
0x784f, 0x786f, 0xf995, 0x7b75, 0x7de3, 0xf996, 0x7e2f, 0xf997,
0x884d, 0x8edf, 0xf998, 0xf999, 0xf99a, 0x925b, 0xf99b, 0x9cf6,
0xf99c, 0xf99d, 0xf99e, 0x6085, 0x6d85, 0xf99f, 0x71b1, 0xf9a0,
0xf9a1, 0x95b1, 0x53ad, 0xf9a2, 0xf9a3, 0xf9a4, 0x67d3, 0xf9a5,
0x708e, 0x7130, 0x7430, 0x8276, 0x82d2, 0xf9a6, 0x95bb, 0x9ae5,
0x9e7d, 0x66c4, 0xf9a7, 0x71c1, 0x8449, 0xf9a8, 0xf9a9, 0x584b,
0xf9aa, 0xf9ab, 0x5db8, 0x5f71, 0xf9ac, 0x6620, 0x668e, 0x6979,
0x69ae, 0x6c38, 0x6cf3, 0x6e36, 0x6f41, 0x6fda, 0x701b, 0x702f,
0x7150, 0x71df, 0x7370, 0xf9ad, 0x745b, 0xf9ae, 0x74d4, 0x76c8,
0x7a4e, 0x7e93, 0xf9af, 0xf9b0, 0x82f1, 0x8a60, 0x8fce, 0xf9b1,
0x9348, 0xf9b2, 0x9719, 0xf9b3, 0xf9b4, 0x5c4b, 0x6c83, 0x7344,
0x7389, 0x923a, 0x6eab, 0x7465, 0x761f, 0x7a69, 0x7e15, 0x860a,
0x5140, 0x58c5, 0x64c1, 0x74ee, 0x7515, 0x7670, 0x7fc1, 0x9095,
0x96cd, 0x9954, 0x5a49, 0x5b8c, 0x5b9b, 0x68a1, 0x6900, 0x6d63,
0x73a9, 0x7413, 0x742c, 0x7897, 0x7de9, 0x7feb, 0x8118, 0x8155,
0x839e, 0x8c4c, 0x962e, 0x9811, 0x66f0, 0x5f80, 0x65fa, 0x6789,
0x6c6a, 0x738b, 0x617e, 0x6b32, 0x6d74, 0x7e1f, 0x8925, 0x8fb1,
0x4fd1, 0x50ad, 0x5197, 0x52c7, 0x57c7, 0x5889, 0x5bb9, 0x5eb8,
0x6142, 0x6995, 0x6d8c, 0x6e67, 0x6eb6, 0x7194, 0x7462, 0x7528,
0x752c, 0x8073, 0x8338, 0x84c9, 0x8e0a, 0x9394, 0x93de, 0xf9c4,
0x52d6, 0x5f67, 0x65ed, 0x6631, 0x682f, 0x715c, 0x7a36, 0x90c1,
0x980a, 0x4e91, 0xf9c5, 0x6a52, 0x6b9e, 0x6f90, 0x7189, 0x8018,
0x82b8, 0x8553, 0x904b, 0x9695, 0x96f2, 0x97fb, 0x851a, 0x9b31,
0x4e90, 0x718a, 0x96c4, 0x5143, 0x539f, 0x54e1, 0x5713, 0x5712,
0x57a3, 0x5a9b, 0x5ac4, 0x5bc3, 0x6028, 0x613f, 0x63f4, 0x6c85,
0x6d39, 0x6e72, 0x6e90, 0x7230, 0x733f, 0x7457, 0x82d1, 0x8881,
0x8f45, 0x9060, 0xf9c6, 0x9662, 0x9858, 0x9d1b, 0x6708, 0x8d8a,
0x925e, 0xf9d1, 0x5809, 0xf9d2, 0x6bd3, 0x8089, 0x80b2, 0xf9d3,
0xf9d4, 0x5141, 0x596b, 0x5c39, 0xf9d5, 0xf9d6, 0x6f64, 0x73a7,
0x80e4, 0x8d07, 0xf9d7, 0x9217, 0x958f, 0xf9d8, 0xf9d9, 0xf9da,
0xf9db, 0x807f, 0x620e, 0x701c, 0x7d68, 0x878d, 0xf9dc, 0x57a0,
0x6069, 0x6147, 0x6bb7, 0x8abe, 0x9280, 0x96b1, 0x4e59, 0x541f,
0x6deb, 0x852d, 0x9670, 0x97f3, 0x98ee, 0x63d6, 0x6ce3, 0x9091,
0x51dd, 0x61c9, 0x81ba, 0x9df9, 0xf9eb, 0xf9ec, 0x7037, 0x76ca,
0x7fca, 0x7fcc, 0x7ffc, 0x8b1a, 0x4eba, 0x4ec1, 0x5203, 0x5370,
0xf9ed, 0x54bd, 0x56e0, 0x59fb, 0x5bc5, 0x5f15, 0x5fcd, 0x6e6e,
0xf9ee, 0xf9ef, 0x7d6a, 0x8335, 0xf9f0, 0x8693, 0x8a8d, 0xf9f1,
0x976d, 0x9777, 0xf9f2, 0xf9f3, 0x4e00, 0x4f5a, 0x4f7e, 0x58f9,
0x65e5, 0x6ea2, 0x9038, 0x93b0, 0x99b9, 0x4efb, 0x58ec, 0x598a,
0x59d9, 0x6041, 0xf9f4, 0xf9f5, 0x7a14, 0xf9f6, 0x834f, 0x8cc3,
0x5165, 0x5344, 0xf9f7, 0xf9f8, 0xf9f9, 0x4ecd, 0x5269, 0x5b55,
0x82bf, 0x4f5c, 0x52fa, 0x56bc, 0x65ab, 0x6628, 0x707c, 0x70b8,
0x7235, 0x7dbd, 0x828d, 0x914c, 0x96c0, 0x9d72, 0x5b71, 0x68e7,
0x6b98, 0x6f7a, 0x76de, 0x5c91, 0x66ab, 0x6f5b, 0x7bb4, 0x7c2a,
0x8836, 0x96dc, 0x4e08, 0x4ed7, 0x5320, 0x5834, 0x58bb, 0x58ef,
0x596c, 0x5c07, 0x5e33, 0x5e84, 0x5f35, 0x638c, 0x66b2, 0x6756,
0x6a1f, 0x6aa3, 0x6b0c, 0x6f3f, 0x7246, 0xf9fa, 0x7350, 0x748b,
0x7ae0, 0x7ca7, 0x8178, 0x81df, 0x81e7, 0x838a, 0x846c, 0x8523,
0x8594, 0x85cf, 0x88dd, 0x8d13, 0x91ac, 0x9577, 0x969c, 0x722d,
0x7b8f, 0x8acd, 0x931a, 0x52e3, 0x540a, 0x5ae1, 0x5bc2, 0x6458,
0x6575, 0x6ef4, 0x72c4, 0xf9fb, 0x7684, 0x7a4d, 0x7b1b, 0x7c4d,
0x7e3e, 0x7fdf, 0x837b, 0x8b2b, 0x8cca, 0x8d64, 0x8de1, 0x8e5f,
0x8fea, 0x8ff9, 0x9069, 0x93d1, 0x4f43, 0x4f7a, 0x50b3, 0x5168,
0x5178, 0x524d, 0x526a, 0x5861, 0x587c, 0x5960, 0x5c08, 0x5c55,
0x5edb, 0x609b, 0x6230, 0x6813, 0x6bbf, 0x6c08, 0x6fb1, 0x714e,
0x7420, 0x7530, 0x7538, 0x7551, 0x7672, 0x7b4c, 0x7b8b, 0x7bad,
0x7bc6, 0x7e8f, 0x8a6e, 0x8f3e, 0x8f49, 0x923f, 0x9293, 0x9322,
0x942b, 0x96fb, 0x985a, 0x986b, 0x991e, 0x5207, 0x622a, 0x6298,
0x6d59, 0x7664, 0x7aca, 0x7bc0, 0x7d76, 0x5360, 0x5cbe, 0x5e97,
0x6f38, 0x70b9, 0x7c98, 0x9711, 0x9b8e, 0x9ede, 0x63a5, 0x647a,
0x8776, 0x4e01, 0x4e95, 0x4ead, 0x505c, 0x5075, 0x5448, 0x59c3,
0x5b9a, 0x5e40, 0x5ead, 0x5ef7, 0x5f81, 0x60c5, 0x633a, 0x653f,
0x6574, 0x65cc, 0x6676, 0x6678, 0x67fe, 0x6968, 0x6a89, 0x6b63,
0x6c40, 0x6dc0, 0x6de8, 0x6e1f, 0x6e5e, 0x701e, 0x70a1, 0x738e,
0x73fd, 0x753a, 0x775b, 0x7887, 0x798e, 0x7a0b, 0x7a7d, 0x7cbe,
0x7d8e, 0x8247, 0x8a02, 0x8aea, 0x8c9e, 0x912d, 0x914a, 0x91d8,
0x9266, 0x92cc, 0x9320, 0x9706, 0x9756, 0x975c, 0x9802, 0x9f0e,
0x65cf, 0x7c07, 0x8db3, 0x93c3, 0x5b58, 0x5c0a, 0x5352, 0x62d9,
0x731d, 0x5027, 0x5b97, 0x5f9e, 0x60b0, 0x616b, 0x68d5, 0x6dd9,
0x742e, 0x7a2e, 0x7d42, 0x7d9c, 0x7e31, 0x816b, 0x8e2a, 0x8e35,
0x937e, 0x9418, 0x7af9, 0x7ca5, 0x4fca, 0x5101, 0x51c6, 0x57c8,
0x5bef, 0x5cfb, 0x6659, 0x6a3d, 0x6d5a, 0x6e96, 0x6fec, 0x710c,
0x756f, 0x7ae3, 0x8822, 0x9021, 0x9075, 0x96cb, 0x99ff, 0x8301,
0x4e2d, 0x4ef2, 0x8846, 0x91cd, 0x537d, 0x6adb, 0x696b, 0x6c41,
0x847a, 0x589e, 0x618e, 0x66fe, 0x62ef, 0x70dd, 0x7511, 0x75c7,
0x7e52, 0x84b8, 0x8b49, 0x8d08, 0x76f4, 0x7a19, 0x7a37, 0x7e54,
0x8077, 0x5507, 0x55d4, 0x5875, 0x632f, 0x6422, 0x6649, 0x664b,
0x686d, 0x699b, 0x6b84, 0x6d25, 0x6eb1, 0x73cd, 0x7468, 0x74a1,
0x755b, 0x75b9, 0x76e1, 0x771e, 0x778b, 0x79e6, 0x7e09, 0x7e1d,
0x81fb, 0x852f, 0x8897, 0x8a3a, 0x8cd1, 0x8eeb, 0x8fb0, 0x9032,
0x93ad, 0x9663, 0x9673, 0x9707, 0x4f84, 0x53f1, 0x59ea, 0x5ac9,
0x5e19, 0x684e, 0x74c6, 0x75be, 0x79e9, 0x7a92, 0x81a3, 0x86ed,
0x8cea, 0x8dcc, 0x8fed, 0x659f, 0x6715, 0xf9fd, 0x57f7, 0x6f57,
0x7ddd, 0x8f2f, 0x93f6, 0x96c6, 0x5fb5, 0x61f2, 0x6f84, 0x6349,
0x643e, 0x7740, 0x7a84, 0x932f, 0x947f, 0x9f6a, 0x64b0, 0x6faf,
0x71e6, 0x74a8, 0x74da, 0x7ac4, 0x7c12, 0x7e82, 0x7cb2, 0x7e98,
0x8b9a, 0x8d0a, 0x947d, 0x9910, 0x994c, 0x5239, 0x5bdf, 0x64e6,
0x672d, 0x7d2e, 0x50ed, 0x53c3, 0x5879, 0x6158, 0x6159, 0x61fa,
0x65ac, 0x7ad9, 0x8b92, 0x8b96, 0x5009, 0x5021, 0x5275, 0x5531,
0x5a3c, 0x5ee0, 0x5f70, 0x6134, 0x655e, 0x660c, 0x6636, 0x66a2,
0x69cd, 0x6ec4, 0x6f32, 0x7316, 0x7621, 0x7a93, 0x8139, 0x8259,
0x83d6, 0x84bc, 0x518a, 0x67f5, 0x7b56, 0x8cac, 0x501c, 0xf9ff,
0x5254, 0x5c3a, 0x617d, 0x621a, 0x62d3, 0x64f2, 0x65a5, 0x6ecc,
0x7620, 0x810a, 0x8e60, 0x965f, 0x96bb, 0x4edf, 0x5343, 0x5598,
0x5929, 0x5ddd, 0x64c5, 0x6cc9, 0x6dfa, 0x7394, 0x7a7f, 0x821b,
0x85a6, 0x8ce4, 0x8e10, 0x9077, 0x91e7, 0x95e1, 0x9621, 0x97c6,
0x51f8, 0x54f2, 0x5586, 0x5fb9, 0x64a4, 0x6f88, 0x7db4, 0x8f1f,
0x8f4d, 0x9435, 0x50c9, 0x5c16, 0x6cbe, 0x6dfb, 0x751b, 0x77bb,
0x7c3d, 0x7c64, 0x8a79, 0x8ac2, 0x581e, 0x59be, 0x5e16, 0x6377,
0x7252, 0x758a, 0x776b, 0x8adc, 0x8cbc, 0x8f12, 0x5ef3, 0x6674,
0x6df8, 0x807d, 0x83c1, 0x8acb, 0x9751, 0x9bd6, 0x4fc3, 0x56d1,
0x71ed, 0x77d7, 0x8700, 0x89f8, 0x5bf8, 0x5fd6, 0x6751, 0x90a8,
0x53e2, 0x585a, 0x5bf5, 0x60a4, 0x6181, 0x6460, 0x7e3d, 0x8070,
0x8525, 0x9283, 0x64ae, 0x4e11, 0x755c, 0x795d, 0x7afa, 0x7b51,
0x7bc9, 0x7e2e, 0x84c4, 0x8e59, 0x8e74, 0x8ef8, 0x9010, 0x6625,
0x693f, 0x7443, 0x51fa, 0x672e, 0x9edc, 0x5145, 0x5fe0, 0x6c96,
0x87f2, 0x885d, 0x8877, 0x5074, 0x4ec4, 0x53a0, 0x60fb, 0x6e2c,
0x5c64, 0x5247, 0x52c5, 0x98ed, 0x89aa, 0x4e03, 0x67d2, 0x6f06,
0x4fb5, 0x5be2, 0x6795, 0x6c88, 0x6d78, 0x741b, 0x7827, 0x91dd,
0x937c, 0x87c4, 0x79e4, 0x7a31, 0x502c, 0x5353, 0x5544, 0x577c,
0xfa01, 0x6258, 0xfa02, 0x64e2, 0x666b, 0x67dd, 0x6fc1, 0x6fef,
0x7422, 0x7438, 0x8a17, 0x9438, 0x5451, 0x5606, 0x5766, 0x5f48,
0x619a, 0x6b4e, 0x7058, 0x70ad, 0x7dbb, 0x8a95, 0x596a, 0x812b,
0x63a2, 0x7708, 0x803d, 0x8caa, 0x5854, 0x642d, 0x69bb, 0x5b95,
0x5e11, 0x6e6f, 0xfa03, 0x8569, 0xfa04, 0x64c7, 0x6fa4, 0x6491,
0x615f, 0x6876, 0xfa05, 0x75db, 0x7b52, 0x7d71, 0x901a, 0x615d,
0x7279, 0x95d6, 0x5224, 0x5742, 0x677f, 0x7248, 0x74e3, 0x8ca9,
0x8fa6, 0x9211, 0x962a, 0x516b, 0x53ed, 0x634c, 0x5f6d, 0x6f8e,
0x70f9, 0x81a8, 0x610e, 0x4fbf, 0x504f, 0x6241, 0x7247, 0x7bc7,
0x7de8, 0x7fe9, 0x904d, 0x97ad, 0x9a19, 0x8cb6, 0x576a, 0x5e73,
0x67b0, 0x840d, 0x8a55, 0x5e45, 0x66b4, 0x66dd, 0x7011, 0x7206,
0xfa07, 0x54c1, 0x7a1f, 0x6953, 0x8af7, 0x8c4a, 0x98a8, 0x99ae,
0x5339, 0x5f3c, 0x5fc5, 0x6ccc, 0x73cc, 0x7562, 0x758b, 0x7b46,
0x82fe, 0x999d, 0x4e4f, 0x903c, 0x58d1, 0x5b78, 0x8650, 0x8b14,
0x9db4, 0x5bd2, 0x6068, 0x608d, 0x65f1, 0x6c57, 0x6f22, 0x6fa3,
0x701a, 0x7f55, 0x7ff0, 0x9591, 0x9592, 0x9650, 0x97d3, 0x5272,
0x8f44, 0x51fd, 0x542b, 0x54b8, 0x5563, 0x558a, 0x6abb, 0x6db5,
0x7dd8, 0x8266, 0x929c, 0x9677, 0x9e79, 0x5408, 0x54c8, 0x76d2,
0x86e4, 0x95a4, 0x95d4, 0x965c, 0x4ea2, 0x4f09, 0x59ee, 0x5ae6,
0x5df7, 0x6052, 0x6297, 0x676d, 0x6841, 0x6c86, 0x6e2f, 0x7f38,
0x809b, 0x822a, 0xfa08, 0xfa09, 0x9805, 0x52be, 0x6838, 0x5016,
0x5e78, 0x674f, 0x8347, 0x884c, 0x4eab, 0x5411, 0x56ae, 0x73e6,
0x9115, 0x97ff, 0x9909, 0x9957, 0x9999, 0x61b2, 0x6af6, 0x737b,
0x8ed2, 0x6b47, 0x96aa, 0x9a57, 0x5955, 0x7200, 0x8d6b, 0x9769,
0x4fd4, 0x5cf4, 0x5f26, 0x61f8, 0x665b, 0x6ceb, 0x70ab, 0x7384,
0x73b9, 0x73fe, 0x7729, 0x774d, 0x7d43, 0x7d62, 0x7e23, 0x8237,
0x8852, 0xfa0a, 0x8ce2, 0x9249, 0x986f, 0x5b51, 0x7a74, 0x8840,
0x9801, 0x5acc, 0x4fe0, 0x5354, 0x593e, 0x5cfd, 0x633e, 0x6d79,
0x72f9, 0x8105, 0x8107, 0x83a2, 0x92cf, 0x9830, 0x4ea8, 0x5144,
0x5211, 0x578b, 0x5f62, 0x6cc2, 0x6ece, 0x7005, 0x7050, 0x70af,
0x7192, 0x73e9, 0x7469, 0x834a, 0x87a2, 0x8861, 0x9008, 0x90a2,
0x93a3, 0x99a8, 0x60d1, 0x6216, 0x9177, 0x5a5a, 0x660f, 0x6df7,
0x6e3e, 0x743f, 0x9b42, 0x5ffd, 0x60da, 0x7b0f, 0x54c4, 0x5f18,
0x6c5e, 0x6cd3, 0x6d2a, 0x70d8, 0x7d05, 0x8679, 0x8a0c, 0x9d3b,
0xfa0b, 0x64f4, 0x652b, 0x78ba, 0x78bb, 0x7a6b, 0x4e38, 0x559a,
0x5950, 0x5ba6, 0x5e7b, 0x60a3, 0x63db, 0x6b61, 0x6665, 0x6853,
0x6e19, 0x7165, 0x74b0, 0x7d08, 0x9084, 0x9a69, 0x9c25, 0x6d3b,
0x6ed1, 0x733e, 0x8c41, 0x95ca, 0x51f0, 0x5e4c, 0x5fa8, 0x604d,
0x60f6, 0x6130, 0x614c, 0x6643, 0x6644, 0x69a5, 0x6cc1, 0x6e5f,
0x6ec9, 0x6f62, 0x714c, 0x749c, 0x7687, 0x7bc1, 0x7c27, 0x8352,
0x8757, 0x9051, 0x968d, 0x9ec3, 0x5283, 0x7372, 0x5b96, 0x6a6b,
0x9404, 0x52db, 0x52f3, 0x5864, 0x58ce, 0x7104, 0x718f, 0x71fb,
0x85b0, 0x8a13, 0x6688, 0x85a8, 0x55a7, 0x6684, 0x714a, 0x8431,
0x6064, 0x8b4e, 0x9df8, 0x5147, 0x51f6, 0x5308, 0x6d36, 0x80f8,
0x9ed1, 0x6615, 0x6b23, 0x7098, 0x75d5, 0x5403, 0x5c79, 0x7d07,
0x8a16, 0x6b20, 0x6b3d, 0x6b46, 0x5438, 0x6070, 0x6d3d, 0x7fd5,
0x8208, 0x8a70, 0xfa0b
];
const RO_HANJA = [
0x4e6b, 0x559d, 0x66f7, 0x6e34, 0x78a3, 0x7aed, 0x845b, 0x8910,
0x874e, 0x97a8, 0x4e5e, 0x5091, 0x6770, 0x6840, 0x6289, 0x6c7a,
0x6f54, 0x7d50, 0x7f3a, 0x8a23, 0x6c68, 0xf904, 0x9aa8, 0x522e,
0x605d, 0x62ec, 0x9002, 0x5800, 0x5c48, 0x6398, 0x7a9f, 0x53a5,
0x7357, 0x8568, 0x8e76, 0x95d5, 0x6a58, 0xf909, 0x4f76, 0x5409,
0x62ee, 0x6854, 0x634f, 0x637a, 0x8a25, 0x64bb, 0x6fbe, 0x737a,
0x75b8, 0x9054, 0x4e6d, 0x7a81, 0x524c, 0x8fa3, 0x51bd, 0x5217,
0x52a3, 0x6d0c, 0x70c8, 0x88c2, 0x5f8b, 0x6144, 0x6817, 0xf961,
0x551c, 0x62b9, 0x672b, 0x6cab, 0x8309, 0x896a, 0x977a, 0x6ec5,
0x8511, 0x6b7f, 0x6c92, 0x52ff, 0x6c95, 0x7269, 0x5bc6, 0x871c,
0x8b10, 0x52c3, 0x62d4, 0x64a5, 0x6e24, 0x6f51, 0x767c, 0x8dcb,
0x91b1, 0x9262, 0x9aee, 0x9b43, 0x4f10, 0x7b4f, 0x7f70, 0x95a5,
0x5225, 0x77a5, 0x9c49, 0x9f08, 0x4e76, 0xf967, 0x4f5b, 0x5f17,
0x5f7f, 0x62c2, 0x4e77, 0x6492, 0x6bba, 0x715e, 0x85a9, 0x5368,
0x5c51, 0x6954, 0x6cc4, 0x6d29, 0x6e2b, 0x820c, 0x859b, 0x893b,
0x8a2d, 0x8aaa, 0x96ea, 0x9f67, 0x7387, 0x620c, 0x8853, 0x8ff0,
0x9265, 0x745f, 0x819d, 0x8768, 0x5931, 0x5ba4, 0x5be6, 0x6089,
0x65a1, 0x8b01, 0x8ecb, 0x95bc, 0x5b7c, 0x8616, 0xf99c, 0xf99d,
0xf99e, 0x6085, 0x6d85, 0xf99f, 0x71b1, 0xf9a0, 0xf9a1, 0x95b1,
0x5140, 0x66f0, 0x851a, 0x9b31, 0x4e90, 0x6708, 0x8d8a, 0x925e,
0xf9d8, 0xf9d9, 0xf9da, 0xf9db, 0x807f, 0x4e59, 0x4e00, 0x4f5a,
0x4f7e, 0x58f9, 0x65e5, 0x6ea2, 0x9038, 0x93b0, 0x99b9, 0x5207,
0x622a, 0x6298, 0x6d59, 0x7664, 0x7aca, 0x7bc0, 0x7d76, 0x5352,
0x62d9, 0x731d, 0x8301, 0x6adb, 0x4f84, 0x53f1, 0x59ea, 0x5ac9,
0x5e19, 0x684e, 0x74c6, 0x75be, 0x79e9, 0x7a92, 0x81a3, 0x86ed,
0x8cea, 0x8dcc, 0x8fed, 0x5239, 0x5bdf, 0x64e6, 0x672d, 0x7d2e,
0x51f8, 0x54f2, 0x5586, 0x5fb9, 0x64a4, 0x6f88, 0x7db4, 0x8f1f,
0x8f4d, 0x9435, 0x64ae, 0x51fa, 0x672e, 0x9edc, 0x4e03, 0x67d2,
0x6f06, 0x596a, 0x812b, 0x516b, 0x53ed, 0x634c, 0x5339, 0x5f3c,
0x5fc5, 0x6ccc, 0x73cc, 0x7562, 0x758b, 0x7b46, 0x82fe, 0x999d,
0x5272, 0x8f44, 0x6b47, 0x5b51, 0x7a74, 0x8840, 0x9801, 0x5ffd,
0x60da, 0x7b0f, 0x6d3b, 0x6ed1, 0x733e, 0x8c41, 0x95ca, 0x6064,
0x8b4e, 0x9df8, 0x5403, 0x5c79, 0x7d07, 0x8a16, 0x8a70,
];
const regNormalFixed = new RegExp(`/(?:${PRE_REG_NORMAL_FIXED.join('|')})$/iu`);
const regSpecialChar = new RegExp(`/(?:${PRE_REG_SPECIAL_CHAR.join('|')})$/iu`);
const regSpecialRo = new RegExp(`/(?:${PRE_REG_SPECIAL_RO.join('|')})$/iu`);
const jongsungHanja = new Set<number>();
for (const hanjaCode of JONGSUNG_HANJA) {
jongsungHanja.add(hanjaCode);
}
const roHanja = new Set<number>();
for (const hanjaCode of RO_HANJA) {
roHanja.add(hanjaCode);
}
const mapPostPosition = new Map<string, string>();
for (const [key, val] of Object.entries(DEFAULT_POSTPOSITION)) {
mapPostPosition.set(`(${key})${val}`, key);
mapPostPosition.set(key, key);
mapPostPosition.set(val, key);
}
function checkText(text: string, isRo: boolean): boolean {
if (regNormalFixed.test(text)) {
return false;
}
if (regSpecialChar.test(text)) {
return true;
}
if (!isRo && regSpecialRo.test(text)) {
return true;
}
return false;
}
function checkCode(code: number, isRo: boolean): boolean {
const jongsung = (code - KO_START_CODE) % 28;
if (jongsung === 0) {
return false;
}
if (isRo && jongsung === 8) {
return false;
}
return true;
}
export function check(text: string, type: string): boolean {
const htarget = text.replace(REG_INVALID_CHAR_W_HANJA, ' ').replace(REG_TARGET_CHAR, '$1');
if (!htarget) {
return false;
}
const hcode = htarget.charAt(htarget.length - 1).charCodeAt(0);
const isRo = type === '로' || type === '으로';
if (HANJA_START_CODE <= hcode && hcode <= HANJA_FINISH_CODE) {
if (isRo && roHanja.has(hcode)) {
return false;
}
if (jongsungHanja.has(hcode)) {
return true;
}
if (hcode < KO_START_CODE || KO_FINISH_CODE < hcode) {
return false;
}
}
const target = text.replace(REG_INVALID_CHAR, ' ').replace(REG_TARGET_CHAR, '$1');
const code = target.charAt(target.length - 1).charCodeAt(0);
const isKorean = KO_START_CODE <= code && code <= KO_FINISH_CODE;
return isKorean ? checkCode(code, isRo) : checkText(target, isRo);
}
export function pick(text: string|number, wJongsung: string, woJongsung = ''): string {
/* NOTE:원본 코드와 인자 순서가 다름.
* 원본은 pick('바람', '랑', '이랑'); 이었다면 pick('바람', '이랑', '랑'); 으로 바뀜.
* pick('바람', '은', '는'); JosaUtil.pick('바람', '이', '가');처럼 쓰기 위해서임.
*/
if (!text) {
text = '';
} else if(typeof text === 'number'){
text = String(text);
}
if(!woJongsung){
if(!mapPostPosition.has(wJongsung)){
throw `올바르지 않은 조사 지정: ${wJongsung}`;
}
wJongsung = unwrap_err(mapPostPosition.get(wJongsung), Error, `올바르지 않은 조사 지정: ${wJongsung}`);
woJongsung = DEFAULT_POSTPOSITION[wJongsung as keyof typeof DEFAULT_POSTPOSITION];
}
return check(text, wJongsung) ? wJongsung : woJongsung;
}
export function put(text: string, wJongsung: string, woJongsung = ''): string{
return `${text}${pick(text, wJongsung, woJongsung)}`;
}
export function fix(wJongsung: string, woJongsung = ''){
if(!woJongsung){
if(!mapPostPosition.has(wJongsung)){
throw `올바르지 않은 조사 지정: ${wJongsung}`;
}
wJongsung = unwrap_err(mapPostPosition.get(wJongsung), Error, `올바르지 않은 조사 지정: ${wJongsung}`);
woJongsung = DEFAULT_POSTPOSITION[wJongsung as keyof typeof DEFAULT_POSTPOSITION];
}
return function(text: string){
return put(text, wJongsung, woJongsung);
}
}
export function batch(text: string, decorator = ';'){
const regExp = new RegExp(`${decorator}([^${decorator}]+)${decorator}([^${decorator}]*)${decorator}([^${decorator}]+)${decorator}`, 'g');
let matchRes;
let lastIndex = 0;
const result: string[] = [];
while ((matchRes = regExp.exec(text)) !== null) {
const {
0: partAll,
1: body,
2: filler,
3: wJongsung,
index,
} = matchRes;
if(lastIndex != index){
result.push(text.slice(lastIndex, index));
}
result.push(body, filler, pick(body, wJongsung));
lastIndex = index + partAll.length;
}
if(lastIndex != text.length){
result.push(text.slice(lastIndex));
}
return result.join('');
}
+232
View File
@@ -0,0 +1,232 @@
import type { RNG } from "./RNG";
import { sha512 } from 'js-sha512';
import { convertBytesLikeToUint8Array } from "./convertBytesLikeToUint8Array";
import type { BytesLike } from "./BytesLike";
const maxRngSupportBit = 53;
const maxInt = 0x1f_ffff_ffff_ffff; // NOTE: b 0, 10000110011, 11...11
const maxIntMore1 = 0x20_0000_0000_0000n; //NOTE: b 0, 10000110100, 00...00
const maxIntMore1f = Number(maxIntMore1);
export const bufferByteSize = 512 / 8; //SHA512
const intBitMapMask = new Map([
[0x1n, 1],
[0x3n, 2],
[0x7n, 3],
[0xfn, 4],
[0x1fn, 5],
[0x3fn, 6],
[0x7fn, 7],
[0xffn, 8],
[0x1ffn, 9],
[0x3ffn, 10],
[0x7ffn, 11],
[0xfffn, 12],
[0x1fffn, 13],
[0x3fffn, 14],
[0x7fffn, 15],
[0xffffn, 16],
[0x1ffffn, 17],
[0x3ffffn, 18],
[0x7ffffn, 19],
[0xfffffn, 20],
[0x1fffffn, 21],
[0x3fffffn, 22],
[0x7fffffn, 23],
[0xffffffn, 24],
[0x1ffffffn, 25],
[0x3ffffffn, 26],
[0x7ffffffn, 27],
[0xfffffffn, 28],
[0x1fffffffn, 29],
[0x3fffffffn, 30],
[0x7fffffffn, 31],
[0xffffffffn, 32],
[0x1ffffffffn, 33],
[0x3ffffffffn, 34],
[0x7ffffffffn, 35],
[0xfffffffffn, 36],
[0x1fffffffffn, 37],
[0x3fffffffffn, 38],
[0x7fffffffffn, 39],
[0xffffffffffn, 40],
[0x1ffffffffffn, 41],
[0x3ffffffffffn, 42],
[0x7ffffffffffn, 43],
[0xfffffffffffn, 44],
[0x1fffffffffffn, 45],
[0x3fffffffffffn, 46],
[0x7fffffffffffn, 47],
[0xffffffffffffn, 48],
[0x1ffffffffffffn, 49],
[0x3ffffffffffffn, 50],
[0x7ffffffffffffn, 51],
[0xfffffffffffffn, 52],
[0x1fffffffffffffn, 53],
]);
function calcBitMask(n: bigint): bigint {
n |= n >> 1n;
n |= n >> 2n;
n |= n >> 4n;
n |= n >> 8n;
n |= n >> 16n;
n |= n >> 32n;
return n;
}
export class LiteHashDRBG implements RNG {
protected buffer!: ArrayBuffer;
protected bufferIdx!: number;
protected hq: DataView;
protected hqIdxPos: number;
public constructor(protected seed: BytesLike, protected stateIdx = 0, bufferIdx = 0) {
if(bufferIdx < 0){
throw new Error(`bufferIdx ${bufferIdx} < 0`);
}
if(bufferIdx >= bufferByteSize){
throw new Error(`bufferidx ${bufferIdx} >= ${bufferByteSize}`);
}
if(stateIdx < 0){
throw new Error(`stateIdx ${stateIdx} < 0`);
}
const seedU8 = convertBytesLikeToUint8Array(seed);
const hqBuffer = new ArrayBuffer(seedU8.byteLength + 4);
const hqU8 = new Uint8Array(hqBuffer);
hqU8.set(seedU8, 0);
this.hq = new DataView(hqBuffer);
this.hqIdxPos = seedU8.byteLength;
this.genNextBlock();
this.bufferIdx = bufferIdx;
}
protected genNextBlock(): void {
this.hq.setUint32(this.hqIdxPos, this.stateIdx, true);
const digest = sha512.arrayBuffer(this.hq.buffer);
this.buffer = digest;
this.bufferIdx = 0;
this.stateIdx += 1;
}
public getMaxInt(): number {
return maxInt;
}
public nextBytes(bytes: number, baseBytes?: number): Uint8Array {
bytes |= 0;
if (bytes <= 0) {
throw new Error(`${bytes} <= 0`);
}
if (this.bufferIdx + bytes <= bufferByteSize) {
if(baseBytes === undefined || bytes >= baseBytes){
const result = this.buffer.slice(this.bufferIdx, this.bufferIdx + bytes);
this.bufferIdx += bytes;
if (this.bufferIdx === bufferByteSize) {
this.genNextBlock();
}
return new Uint8Array(result);
}
const resultBuffer = new ArrayBuffer(Math.max(bytes, baseBytes));
const result = new Uint8Array(resultBuffer);
result.set(new Uint8Array(this.buffer, this.bufferIdx, bytes));
this.bufferIdx += bytes;
if( this.bufferIdx === bufferByteSize){
this.genNextBlock();
}
return result;
}
const resultBuffer = new ArrayBuffer(baseBytes ? Math.max(bytes, baseBytes) : bytes);
const result = new Uint8Array(resultBuffer);
result.set(new Uint8Array(this.buffer, this.bufferIdx));
let offset = bufferByteSize - this.bufferIdx;
let remain = bytes - offset;
while (remain > bufferByteSize) {
this.genNextBlock();
result.set(new Uint8Array(this.buffer), offset);
offset += bufferByteSize;
remain -= bufferByteSize;
}
this.genNextBlock();
if (remain === 0) {
return result;
}
result.set(new Uint8Array(this.buffer, 0, remain), offset);
this.bufferIdx = remain;
return result;
}
public nextBits(bits: number, baseBytes?: number): Uint8Array {
bits |= 0;
const bytes = (bits + 7) >> 3;
const headBits = bits & 0x7;
const result = this.nextBytes(bytes, baseBytes);
if (headBits === 0) {
return result;
}
result[bytes - 1] &= 0xff >> (8 - headBits);
return result;
}
protected _nextInt(bits: number): bigint{
const buffer = this.nextBits(bits, 8);
const dataView = new DataView(buffer.buffer);
return dataView.getBigUint64(0, true);
}
public nextInt(max?: number): number {
if (max === undefined || max === maxInt) {
return Number(this._nextInt(maxRngSupportBit));
}
if (max > maxInt) {
throw new Error('Over max int');
}
if (max === 0) {
return 0;
}
if (max < 0) {
return -this.nextInt(-max);
}
const mask = calcBitMask(BigInt(max));
const bits = intBitMapMask.get(mask) as number;
let n = Number(this._nextInt(bits));
while (n > max){
n = Number(this._nextInt(bits));
}
return n;
}
public nextFloat1(): number {
// eslint-disable-next-line no-constant-condition
while(true){
const nInt = this._nextInt(maxRngSupportBit + 1);
if(nInt < maxIntMore1){
return Number(nInt) / maxIntMore1f;
}
if(nInt === maxIntMore1){
return 1;
}
}
}
public static build(seed: BytesLike, stateIdx = 0): LiteHashDRBG{
return new LiteHashDRBG(seed, stateIdx);
}
}
+4
View File
@@ -0,0 +1,4 @@
export class NotNullExpected extends TypeError {
public name = 'NotNullExpected';
}
+1
View File
@@ -0,0 +1 @@
export type Nullable<T> = T | null | undefined;
+173
View File
@@ -0,0 +1,173 @@
import type { TurnObj } from "@/defs";
import { clone, isString, range } from "lodash-es";
import { ref, type Ref } from "vue";
import { unwrap } from "./unwrap";
export type TurnObjWithTime = TurnObj & {
time: string;
year?: number;
month?: number;
tooltip?: string;
style?: Record<string, string>;
};
export const getEmptyTurn = (maxTurn: number): TurnObjWithTime[] => Array.from<TurnObjWithTime>({
length: maxTurn,
}).fill({
arg: {},
brief: "",
action: "",
year: undefined,
month: undefined,
time: "",
});
export class QueryActionHelper {
public readonly reservedCommandList: Ref<TurnObjWithTime[]>;
public readonly selectedTurnList: Ref<Set<number>>;
public readonly prevSelectedTurnList: Ref<Set<number>>;
constructor(
protected maxTurn: number,
) {
this.reservedCommandList = ref(getEmptyTurn(maxTurn));
this.selectedTurnList = ref(new Set());
this.prevSelectedTurnList = ref(new Set([0]));
}
toggleTurn(...reqTurnList: number[] | string[]) {
for (let turnIdx of reqTurnList) {
if (isString(turnIdx)) {
turnIdx = parseInt(turnIdx);
}
if (this.selectedTurnList.value.has(turnIdx)) {
this.selectedTurnList.value.delete(turnIdx);
} else {
this.selectedTurnList.value.add(turnIdx);
}
}
}
selectTurn(...reqTurnList: number[] | string[]) {
this.selectedTurnList.value.clear();
for (const turnIdx of reqTurnList) {
if (isString(turnIdx)) {
this.selectedTurnList.value.add(parseInt(turnIdx));
} else {
this.selectedTurnList.value.add(turnIdx);
}
}
}
selectStep(begin: number, step: number) {
this.selectedTurnList.value.clear();
for (const idx of range(0, this.maxTurn)) {
if ((idx - begin) % step == 0) {
this.selectedTurnList.value.add(idx);
}
}
}
selectAll() {
for (let i = 0; i < this.maxTurn; i++) {
this.selectedTurnList.value.add(i);
}
}
getSelectedTurnList(useSort = true): number[] {
let result: number[];
if (this.selectedTurnList.value.size) {
result = Array.from(this.selectedTurnList.value);
}
else if (this.prevSelectedTurnList.value.size) {
result = Array.from(this.prevSelectedTurnList.value);
}
else {
return [0];
}
if (useSort) {
return result.sort((a, b) => a - b);
}
return result;
}
releaseSelectedTurnList() {
if (this.selectedTurnList.value.size > 0) {
this.prevSelectedTurnList.value.clear();
for (const v of this.selectedTurnList.value) {
this.prevSelectedTurnList.value.add(v);
}
this.selectedTurnList.value.clear();
}
}
extractQueryActions(): [number[], TurnObj][] {
const reqTurnList = this.getSelectedTurnList();
const selectedMinTurnIdx = unwrap(Math.min(...reqTurnList));
const buffer = new Map<string, [number[], TurnObj]>();
for (const rawTurnIdx of reqTurnList) {
const turnIdx = rawTurnIdx - selectedMinTurnIdx;
const rawAction = this.reservedCommandList.value[rawTurnIdx]
const actionStr = JSON.stringify([rawAction.action, rawAction.arg]);
if (buffer.has(actionStr)) {
const items = unwrap(buffer.get(actionStr));
items[0].push(turnIdx);
}
else {
buffer.set(actionStr, [[turnIdx], {
action: rawAction.action,
arg: clone(rawAction.arg),
brief: rawAction.brief
}])
}
}
return Array.from(buffer.values());
}
amplifyQueryActions(rawActions: [number[], TurnObj][], reqTurnList: number[]): [number[], TurnObj][] {
if (reqTurnList.length < 1) {
return [];
}
let minQueryIdx = this.maxTurn;
let maxQueryIdx = 0;
for (const [turnList] of rawActions) {
for (const turnIdx of turnList) {
minQueryIdx = Math.min(minQueryIdx, turnIdx);
maxQueryIdx = Math.max(maxQueryIdx, turnIdx);
}
}
const queryLength = maxQueryIdx - minQueryIdx + 1;
const queryTurnList: number[] = [reqTurnList[0]];
for (const reqTurnIdx of reqTurnList) {
const last = queryTurnList[queryTurnList.length - 1];
if (reqTurnIdx < last + queryLength) {
continue;
}
queryTurnList.push(reqTurnIdx);
}
const actions: [number[], TurnObj][] = [];
for (const [baseTurnList, action] of rawActions) {
const subTurnList: number[] = [];
for (const baseTurnIdx of baseTurnList) {
for (const queryTurnIdx of queryTurnList) {
const targetTurn = baseTurnIdx + queryTurnIdx;
if (targetTurn >= this.maxTurn) {
continue;
}
subTurnList.push(baseTurnIdx + queryTurnIdx);
}
}
if (subTurnList.length == 0) {
continue;
}
actions.push([subTurnList, action]);
}
return actions;
}
}
+13
View File
@@ -0,0 +1,13 @@
export interface RNG {
/**
* nextInt()가 반환 가능한 최댓값
*/
getMaxInt(): number;
nextBytes(bytes: number): Uint8Array;
nextBits(bits: number): Uint8Array;
nextInt(max?: number): number;
nextFloat1(): number;
}
+144
View File
@@ -0,0 +1,144 @@
import type { RNG } from './RNG';
export class RandUtil {
constructor(protected rng: RNG) {
}
public nextFloat1(): number {
return this.rng.nextFloat1();
}
public nextRange(min: number, max: number): number {
const range = max - min;
return this.nextFloat1() * (range) + min;
}
public nextRangeInt(min: number, max: number): number {
const range = max - min;
return this.rng.nextInt(range) + min;
}
public nextInt(max?: number): number {
return this.rng.nextInt(max);
}
public nextBit(): boolean {
const view = new DataView(this.rng.nextBits(1) as ArrayBufferLike);
return view.getUint8(0) != 0;
}
public nextBool(prob = 0.5): boolean {
if (prob >= 1) {
return true;
}
if (prob === 0.5){
return this.nextBit();
}
if (prob <= 0){
return false;
}
return this.nextFloat1() < prob;
}
public shuffle<T>(srcArray: T[]): T[] {
const cnt = srcArray.length;
if(cnt === 0){
return [];
}
if (cnt > this.rng.getMaxInt()) {
throw 'Invalid random int range';
}
const result: T[] = Array.from(srcArray);
for (let srcIdx = 0; srcIdx < cnt; srcIdx += 1) {
const destIdx = this.rng.nextInt(cnt - srcIdx - 1) + srcIdx;
if(srcIdx === destIdx){
continue;
}
[result[srcIdx], result[destIdx]] = [result[destIdx], result[srcIdx]];
}
return result;
}
//Object는 integer key에 예외가 있어 shuffleAssoc은 없음
public choice<T>(items: T[] | Record<string | number, T> | Set<T>): T {
if (items instanceof Array) {
if(items.length === 0){
throw new Error('Empty items');
}
const idx = this.rng.nextInt(items.length - 1);
return items[idx];
}
if (items instanceof Set) {
return this.choice(Array.from(items.values()));
}
return items[this.choice(Array.from(Object.keys(items)))];
}
public choiceUsingWeight(items: Record<string | number, number>): string | number {
if(Object.keys(items).length === 0){
throw new Error('Empty items');
}
let sum = 0;
for (const value of Object.values(items)) {
if (value <= 0) {
continue;
}
sum += value;
}
let rd = this.nextFloat1() * sum;
for (const [item, value] of Object.entries(items)) {
if (value <= 0) {
if (rd <= 0) {
return item;
}
continue;
}
if (rd <= value) {
return item;
}
rd -= value;
}
throw new Error('Unreacheable');
}
public choiceUsingWeightPair<T>(items: [T, number][]): T {
if(items.length === 0){
throw new Error('Empty items');
}
let sum = 0;
for (const [, value] of items) {
if (value <= 0) {
continue;
}
sum += value;
}
let rd = this.nextFloat1() * sum;
for (const [item, value] of items) {
if (value <= 0) {
if (rd <= 0) {
return item;
}
continue;
}
if (rd <= value) {
return item;
}
rd -= value;
}
throw new Error('Unreacheable');
}
}
+14
View File
@@ -0,0 +1,14 @@
export class RuntimeError extends Error {
public name = 'RuntimeError';
constructor(public message: string = '') {
super(message);
}
toString(): string {
if (this.message) {
return this.name + ': ' + this.message;
}
else {
return this.name;
}
}
}
+115
View File
@@ -0,0 +1,115 @@
import type { TurnObj } from '@/defs';
import { ref, watch, type Ref } from 'vue';
export class StoredActionsHelper {
public readonly recentActions: Ref<Map<string, TurnObj>>;
public readonly storedActions = ref(new Map<string, [number[], TurnObj][]>());
public readonly clipboard = ref<[number[], TurnObj][] | undefined>(undefined);
public readonly activatedCategory = ref<string>("");
public readonly isEditMode = ref(false);
public readonly recentActionsKey: string;
public readonly storedActionsKey: string;
public readonly clipboardKey: string;
public readonly activatedCategoryKey: string;
public readonly editModeKey: string;
constructor(protected serverNick: string, protected type: 'general' | 'nation', protected mapName: string, protected unitSet: string, protected maxRecent = 10) {
this.recentActions = ref(new Map());
const typeKey = `${serverNick}_${mapName}_${unitSet}_${type}`;
this.recentActionsKey = `${typeKey}RecentActions`;
this.storedActionsKey = `${typeKey}StoredActions`;
this.clipboardKey = `${typeKey}Clipboard`;
this.activatedCategoryKey = `${typeKey}ActivatedCategory`;
this.editModeKey = `${serverNick}_${type}_isEditMode`;
this.loadRecentActions();
this.loadStoredActions();
const rawClipboard = localStorage.getItem(this.clipboardKey);
if (rawClipboard !== null) {
this.clipboard.value = JSON.parse(rawClipboard);
}
watch(this.clipboard, (newValue) => {
localStorage.setItem(this.clipboardKey, JSON.stringify(newValue));
});
const rawActivatedCategory = localStorage.getItem(this.activatedCategoryKey);
if (rawActivatedCategory !== null) {
this.activatedCategory.value = JSON.parse(rawActivatedCategory);
}
watch(this.activatedCategory, (newValue) => {
localStorage.setItem(this.activatedCategoryKey, JSON.stringify(newValue));
});
this.isEditMode.value = localStorage.getItem(this.editModeKey) === '1';
watch(this.isEditMode, (newValue) => {
localStorage.setItem(this.editModeKey, newValue ? '1' : '0')
})
}
loadRecentActions() {
try {
const rawRecentActions = JSON.parse(localStorage.getItem(this.recentActionsKey) ?? '[]') as TurnObj[];
const recentActions = new Map<string, TurnObj>();
for (const action of rawRecentActions) {
const actionKey = JSON.stringify([action.action, action.arg]);
recentActions.set(actionKey, action);
}
this.recentActions.value = recentActions;
}
catch(e){
console.log(`loadRecentActions error ${e}`);
}
}
pushRecentActions(action: TurnObj) {
const actionKey = JSON.stringify([action.action, action.arg]);
if (this.recentActions.value.has(actionKey)) {
this.recentActions.value.delete(actionKey);
}
else if (this.recentActions.value.size > this.maxRecent) {
const firstKey = this.recentActions.value.keys().next().value;
this.recentActions.value.delete(firstKey);
}
this.recentActions.value.set(actionKey, action);
this.saveRecentActions();
}
saveRecentActions() {
localStorage.setItem(this.recentActionsKey, JSON.stringify(Array.from(this.recentActions.value.values())));
}
loadStoredActions() {
try {
const rawValue: [string, [number[], TurnObj][]][] = JSON.parse(
localStorage.getItem(this.storedActionsKey) ?? '[]'
);
this.storedActions.value = new Map(rawValue);
}
catch(e){
console.log(`loadStoredActions error ${e}`);
}
}
setStoredActions(actionKey: string, actions: [number[], TurnObj][]) {
this.storedActions.value.set(actionKey, actions);
console.log(this.storedActions.value);
this.saveStoredActions();
}
deleteStoredActions(actionKey: string) {
if (this.storedActions.value.delete(actionKey)) {
this.saveStoredActions();
}
}
saveStoredActions() {
localStorage.setItem(
this.storedActionsKey,
JSON.stringify(Array.from(this.storedActions.value.entries()))
);
}
}
+41
View File
@@ -0,0 +1,41 @@
import { escapeHtml } from '@/legacy/escapeHtml';
import linkifyStr from 'linkify-string';
/**
* 단순한 Template 함수. <%변수명%>으로 template 가능
* @see https://github.com/krasimir/absurd/blob/master/lib/processors/html/helpers/TemplateEngine.js
* @param {string} html
* @param {object} options
* @returns {string}
*/
export function TemplateEngine(html: string, options: Record<string | number, unknown> = {}): string {
const re = /<%(.+?)%>/g;
const reExp = /(^( )?(var|if|for|else|switch|case|break|{|}|;))(.*)?/g;
const code = ['with(obj) { var r=[];\n'];
let cursor = 0;
const add = function (line: string, js?: boolean) {
js ? code.push(line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') :
code.push(line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');
return add;
};
options.e = escapeHtml;
options.linkifyStr = linkifyStr;
for (; ;) {
const match = re.exec(html);
if (!match) {
break;
}
add(html.slice(cursor, match.index))(match[1], true);
cursor = match.index + match[0].length;
}
add(html.substr(cursor, html.length - cursor));
code.push('return r.join(""); }');
const compiledCode = code.join('').replace(/[\r\t\n]/g, ' ');
try {
return new Function('obj', compiledCode).apply(options, [options]);
} catch (err: unknown) {
console.error(err, " in \n\nCode:\n", code, "\n");
throw err;
}
}
+92
View File
@@ -0,0 +1,92 @@
import { htmlReady } from "@util/htmlReady";
import { unwrap } from "@util/unwrap";
import { keyScreenMode, type ScreenModeType } from "@/defs";
export function auto500px(targetHeight = 700): void {
let deviceWidth = -1;
let viewportMeta!: HTMLMetaElement;
let oldMode: ScreenModeType = 'auto';
function init() {
let _viewPortMeta = document.querySelector<HTMLMetaElement>("meta[name=viewport]");
if (_viewPortMeta) {
viewportMeta = _viewPortMeta;
return;
}
const htmlTag = unwrap(document.querySelector("head"));
_viewPortMeta = document.createElement("meta");
_viewPortMeta.name = 'viewport';
_viewPortMeta.content = 'width=500';
htmlTag.appendChild(_viewPortMeta);
viewportMeta = _viewPortMeta;
}
function adjustViewportWidth() {
const screenMode = (localStorage.getItem(keyScreenMode) as ScreenModeType)??'auto';
if(screenMode != oldMode){
oldMode = screenMode;
deviceWidth = window.screen.availWidth;
if(screenMode == '500px'){
viewportMeta.content = 'width=500';
return;
}
if(screenMode == '1000px'){
viewportMeta.content = 'width=1000';
return;
}
if(screenMode == 'auto'){
deviceWidth = -1;
}
}
if (deviceWidth == window.screen.availWidth) {
return;
}
if(oldMode != 'auto'){
oldMode = 'auto';
adjustViewportWidth();
return;
}
deviceWidth = window.screen.availWidth;
const innerHeight = window.innerHeight;
const selectorHeight = targetHeight;
if (deviceWidth < 500) {
viewportMeta.content = 'width=500';
return;
}
if (innerHeight < selectorHeight) {
const maybeNextWidth = deviceWidth / innerHeight * selectorHeight;
if (maybeNextWidth >= 700) {
viewportMeta.content = 'width=1000';
}
else {
viewportMeta.content = `height=${Math.ceil(selectorHeight)}`;
}
return;
}
else if(deviceWidth >= 700){
viewportMeta.content = 'width=1000';
}
else{
viewportMeta.content = 'width=device-width, initial-scale=1';
}
}
htmlReady(() => {
init();
adjustViewportWidth();
window.addEventListener('scroll', adjustViewportWidth, true);
window.addEventListener('orientationchange', adjustViewportWidth, true);
document.addEventListener('tryChangeScreenMode', adjustViewportWidth, false);
});
}
+7
View File
@@ -0,0 +1,7 @@
import { unwrap } from "@util/unwrap";
export function autoResizeTextarea(e: Event): void {
const el = unwrap(e.target) as HTMLInputElement;
el.style.height = 'auto';
el.style.height = `${el.scrollHeight + 1}px`;
}
+101
View File
@@ -0,0 +1,101 @@
const convListLevel1: Record<string, Record<string, string>> = {
'ㄱ': {
'ㅅ': 'ㄳ',
},
'ㄴ': {
'ㅈ': 'ㄵ',
'ㅎ': 'ㄶ',
},
'ㄹ': {
'ㅂ': 'ㄼ',
'ㄱ': 'ㄺ',
'ㅅ': 'ㄽ',
'ㅁ': 'ㄻ',
'ㅎ': 'ㅀ',
'ㅌ': 'ㄾ',
'ㅍ': 'ㄿ',
},
'ㅂ': {
'ㅅ': 'ㅄ',
},
}
const convListLevel2: Record<string, Record<string, string>> = {
'ㄱ': {
'ㄱ': 'ㄲ',
'ㅅ': 'ㄳ',
},
'ㄴ': {
'ㅈ': 'ㄵ',
'ㅎ': 'ㄶ',
},
'ㄷ': {
'ㄷ': 'ㄸ',
},
'ㄹ': {
'ㅂ': 'ㄼ',
'ㄱ': 'ㄺ',
'ㅅ': 'ㄽ',
'ㅁ': 'ㄻ',
'ㅎ': 'ㅀ',
'ㅌ': 'ㄾ',
'ㅍ': 'ㄿ',
},
'ㅂ': {
'ㅂ': 'ㅃ',
'ㅅ': 'ㅄ',
},
'ㅅ': {
'ㅅ': 'ㅆ',
},
'ㅈ': {
'ㅈ': 'ㅉ',
}
}
function automata초성(text: string, convList: Record<string, Record<string, string>>): string{
const result: string[] = [];
let head: undefined | string = undefined;
for (const ch of text) {
if (head === undefined) {
if(!(ch in convList)){
result.push(ch);
continue;
}
head = ch;
continue;
}
const nextConv = convList[head];
if(ch in nextConv){
result.push(nextConv[ch]);
head = undefined;
continue;
}
result.push(head);
if(!(ch in convList)){
result.push(ch);
head = undefined;
continue;
}
head = ch;
}
if(head !== undefined){
result.push(head);
head = undefined;
}
return result.join('');
}
export function automata초성All(text: string): [string, string]{
return [automata초성(text, convListLevel1), automata초성(text, convListLevel2)];
}
export function automata초성Level1(text: string): string{
return automata초성(text, convListLevel1);
}
export function automata초성Level2(text: string): string {
return automata초성(text, convListLevel2);
}
+274
View File
@@ -0,0 +1,274 @@
import ky from "ky";
import { isArray, isEmpty } from "lodash-es";
export type ValidResponse = {
result: true;
};
export type APIRecoveryType = "login" | "2fa" | "gateway" | "game_login" | "game_quota";
export const APIRecoveryConst = {
Login: 'login',
TwoFactorAuth: '2fa',
Gateway: 'gateway',
GameLogin: 'game_login',
GameQuota: 'game_quota',
} as const;
export type InvalidResponse = {
result: false;
reason: string;
recovery?: APIRecoveryType;
recovery_arg?: string | number;
};
export type RawArgType = Record<string, unknown> | Record<string, unknown>[] | undefined;
interface BasicAPICallT<
ArgType extends RawArgType,
ResultType extends ValidResponse,
ErrorType extends InvalidResponse
> {
(args: ArgType): Promise<ResultType>;
(args: ArgType, returnError: false): Promise<ResultType>;
(args: ArgType, returnError: true): Promise<ResultType | ErrorType>;
}
interface EmptyAPICallT<ResultType extends ValidResponse, ErrorType extends InvalidResponse> {
(): Promise<ResultType>;
(args: undefined): Promise<ResultType>;
(args: undefined, returnError: false): Promise<ResultType>;
(args: undefined, returnError: true): Promise<ResultType | ErrorType>;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ArgTypeOf<T> = T extends APICallT<infer A, any, any> ? A : never;
export type APICallT<
ArgType extends RawArgType,
ResultType extends ValidResponse = ValidResponse,
ErrorType extends InvalidResponse = InvalidResponse
> = ArgType extends undefined ? EmptyAPICallT<ResultType, ErrorType> : BasicAPICallT<ArgType, ResultType, ErrorType>;
type HttpMethod = "get" | "post" | "put" | "patch" | "head" | "delete";
export type APITail = typeof GET | typeof POST | typeof PUT | typeof PATCH | typeof HEAD | typeof DELETE;
const httpMethodMap = new Map<APITail, HttpMethod>([
[GET, "get"],
[POST, "post"],
[PUT, "put"],
[PATCH, "patch"],
[HEAD, "head"],
[DELETE, "delete"],
]);
export function extractHttpMethod(tail: APITail): HttpMethod {
return httpMethodMap.get(tail) ?? "post";
}
const apiTarget = "api.php";
let apiPath = apiTarget;
export function setSammoAPIPrefix(prefix: string) {
apiPath = `${prefix}/${apiTarget}`;
}
export async function callSammoAPI<ResultType extends ValidResponse>(
method: HttpMethod,
path: string | string[],
args: RawArgType,
paramArgs: Record<string, string | number> | undefined
): Promise<ResultType>;
export async function callSammoAPI<ResultType extends ValidResponse>(
method: HttpMethod,
path: string | string[],
args: RawArgType,
paramArgs: Record<string, string | number> | undefined,
returnError: false
): Promise<ResultType>;
export async function callSammoAPI<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(
method: HttpMethod,
path: string | string[],
args: RawArgType,
paramArgs: Record<string, string | number> | undefined,
returnError: true
): Promise<ResultType | ErrorType>;
export async function callSammoAPI<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(
method: HttpMethod,
path: string | string[],
args: RawArgType,
paramArgs: Record<string, string | number> | undefined,
returnError = false
): Promise<ResultType | ErrorType> {
if (isArray(path)) {
path = path.join("/");
}
if (args && isEmpty(args)) {
args = undefined;
}
const result = (await (() => {
if (method == "get") {
return ky(apiPath, {
searchParams: {
...paramArgs,
...(args as typeof paramArgs),
path,
},
method,
headers: {
"content-type": "application/json",
},
timeout: 30000,
retry: 0,
});
}
return ky("api.php", {
searchParams: {
...paramArgs,
path,
},
method,
json: args,
headers: {
"content-type": "application/json",
},
timeout: 30000,
retry: 0,
});
})().json()) as ErrorType | ResultType;
if (!result.result) {
if (returnError) {
return result;
}
throw result.reason;
}
return result;
}
export async function GET<ResultType extends ValidResponse, ArgType extends undefined = undefined>(
args?: ArgType
): Promise<ResultType>;
export async function GET<ResultType extends ValidResponse, ArgType extends undefined = undefined>(
args: ArgType | undefined,
returnError: false
): Promise<ResultType>;
export async function GET<
ResultType extends ValidResponse,
ErrorType extends InvalidResponse,
ArgType extends undefined = undefined
>(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
export async function GET<
ResultType extends ValidResponse,
ErrorType extends InvalidResponse,
ArgType extends undefined = undefined
>(args?: ArgType, returnError = false): Promise<ResultType | ErrorType> {
console.error(`Can't directly call GET. ${args}, ${returnError}. Use auto-generated path API.`);
return callSammoAPI<ResultType, ErrorType>("get", [], args, undefined, true);
}
export async function POST<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(
args?: ArgType
): Promise<ResultType>;
export async function POST<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(
args: ArgType | undefined,
returnError: false
): Promise<ResultType>;
export async function POST<
ResultType extends ValidResponse,
ErrorType extends InvalidResponse,
ArgType extends RawArgType = RawArgType
>(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
export async function POST<
ResultType extends ValidResponse,
ErrorType extends InvalidResponse,
ArgType extends RawArgType = RawArgType
>(args?: ArgType, returnError = false): Promise<ResultType | ErrorType> {
console.error(`Can't directly call POST. ${args}, ${returnError}. Use auto-generated path API.`);
return callSammoAPI<ResultType, ErrorType>("post", [], args, undefined, true);
}
export async function PUT<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(
args?: ArgType
): Promise<ResultType>;
export async function PUT<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(
args: ArgType | undefined,
returnError: false
): Promise<ResultType>;
export async function PUT<
ResultType extends ValidResponse,
ErrorType extends InvalidResponse,
ArgType extends RawArgType = RawArgType
>(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
export async function PUT<
ResultType extends ValidResponse,
ErrorType extends InvalidResponse,
ArgType extends RawArgType = RawArgType
>(args?: ArgType, returnError = false): Promise<ResultType | ErrorType> {
console.error(`Can't directly call PUT. ${args}, ${returnError}. Use auto-generated path API.`);
return callSammoAPI<ResultType, ErrorType>("put", [], args, undefined, true);
}
export async function PATCH<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(
args?: ArgType
): Promise<ResultType>;
export async function PATCH<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(
args: ArgType | undefined,
returnError: false
): Promise<ResultType>;
export async function PATCH<
ResultType extends ValidResponse,
ErrorType extends InvalidResponse,
ArgType extends RawArgType = RawArgType
>(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
export async function PATCH<
ResultType extends ValidResponse,
ErrorType extends InvalidResponse,
ArgType extends RawArgType = RawArgType
>(args?: ArgType, returnError = false): Promise<ResultType | ErrorType> {
console.error(`Can't directly call PATCH. ${args}, ${returnError}. Use auto-generated path API.`);
return callSammoAPI<ResultType, ErrorType>("patch", [], args, undefined, true);
}
export async function HEAD<ResultType extends ValidResponse, ArgType extends undefined = undefined>(
args?: ArgType
): Promise<ResultType>;
export async function HEAD<ResultType extends ValidResponse, ArgType extends undefined = undefined>(
args: ArgType | undefined,
returnError: false
): Promise<ResultType>;
export async function HEAD<
ResultType extends ValidResponse,
ErrorType extends InvalidResponse,
ArgType extends undefined = undefined
>(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
export async function HEAD<
ResultType extends ValidResponse,
ErrorType extends InvalidResponse,
ArgType extends undefined = undefined
>(args?: ArgType, returnError = false): Promise<ResultType | ErrorType> {
console.error(`Can't directly call HEAD. ${args}, ${returnError}. Use auto-generated path API.`);
return callSammoAPI<ResultType, ErrorType>("head", [], args, undefined, true);
}
export async function DELETE<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(
args?: ArgType
): Promise<ResultType>;
export async function DELETE<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(
args: ArgType | undefined,
returnError: false
): Promise<ResultType>;
export async function DELETE<
ResultType extends ValidResponse,
ErrorType extends InvalidResponse,
ArgType extends RawArgType = RawArgType
>(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
export async function DELETE<
ResultType extends ValidResponse,
ErrorType extends InvalidResponse,
ArgType extends RawArgType = RawArgType
>(args?: ArgType, returnError = false): Promise<ResultType | ErrorType> {
console.error(`Can't directly call DELETE. ${args}, ${returnError}. Use auto-generated path API.`);
return callSammoAPI<ResultType, ErrorType>("patch", [], args, undefined, true);
}
+11
View File
@@ -0,0 +1,11 @@
import { combineObject } from "../common_legacy";
export function combineArray<K extends string, V>(array: V[][], columnList: K[]): Record<K, V>[] {
const result: Record<K, V>[] = [];
for (const key of array.keys()) {
const item = array[key];
result[key] = combineObject(item, columnList);
}
return result;
}
@@ -0,0 +1,17 @@
import type { BytesLike } from "./BytesLike";
export function convertBytesLikeToArrayBuffer(data: BytesLike, encodeUTF8 = true): ArrayBuffer{
if (data instanceof ArrayBuffer) {
return data;
}
if (data instanceof Uint8Array) {
return data.buffer;
}
if (typeof(data) === 'string'){
if(encodeUTF8){
return (new TextEncoder()).encode(data);
}
return new Uint8Array(data.split('').map(s=>s.codePointAt(0) as number));
}
return data.buffer;
}
@@ -0,0 +1,17 @@
import type { BytesLike } from "./BytesLike";
export function convertBytesLikeToUint8Array(data: BytesLike, encodeUTF8 = true): Uint8Array {
if (data instanceof Uint8Array) {
return data;
}
if (data instanceof ArrayBuffer) {
return new Uint8Array(data);
}
if (typeof (data) === 'string') {
if(encodeUTF8){
return (new TextEncoder()).encode(data);
}
return new Uint8Array(data.split('').map(s=>s.codePointAt(0) as number));
}
return new Uint8Array(data.buffer);
}
+35
View File
@@ -0,0 +1,35 @@
import { isArray, isString, isNumber, isBoolean } from "lodash-es";
export function convertFormData(values: Record<string, null | number[] | string[] | boolean[] | number | string | boolean>): FormData {
const formData = new FormData();
const simpleConv = (v: unknown, key: string): string => {
if (isString(v)) {
return v;
}
if (isNumber(v)) {
return v.toString();
}
if (isBoolean(v)) {
return v ? 'true' : 'false';
}
if (v === null) {
return '';
}
throw new TypeError(`지원하지 않는 formData Type: ${key}`);
}
for (const [key, value] of Object.entries(values)) {
if (isArray(value)) {
const arrKey = `${key}[]`;
for (const subValue of value) {
formData.append(arrKey, simpleConv(subValue, key));
}
continue;
}
formData.append(key, simpleConv(value, key));
}
return formData;
}
+9
View File
@@ -0,0 +1,9 @@
import type { IDItem } from '@/defs';
export function convertIDArray<T>(array: Iterable<T>): IDItem<T>[] {
const result: IDItem<T>[] = [];
for (const id of array) {
result.push({ id });
}
return result;
}
+10
View File
@@ -0,0 +1,10 @@
export function convertIterableToMap<T extends object, K extends keyof T, V extends T[K] & (string | number | symbol)>(
values: Iterable<T>,
key: K
): Map<V, T> {
const result = new Map<V, T>();
for (const obj of values) {
result.set(obj[key] as V, obj);
}
return result;
}
+9
View File
@@ -0,0 +1,9 @@
import { automata초성All } from "./automata초성";
import { filter초성withAlphabet } from "./filter초성withAlphabet";
export function convertSearch초성(text: string): string[]{
const [filteredTextH, filteredTextA] = filter초성withAlphabet(text.replace(/\s+/g, ""));
const [filteredTextHL1, filteredTextHL2] = automata초성All(filteredTextH);
return [text, filteredTextA, filteredTextH, filteredTextHL1, filteredTextHL2];
}
+9
View File
@@ -0,0 +1,9 @@
export function insertCustomCSS(key = 'sam_customCSS'){
const customCSS = localStorage.getItem(key);
if (customCSS) {
const css = document.createElement('style');
css.innerHTML = customCSS;
console.log(css);
document.getElementsByTagName('head')[0].appendChild(css);
}
}
+7
View File
@@ -0,0 +1,7 @@
export function delay(ms: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, ms);
});
}
+7
View File
@@ -0,0 +1,7 @@
type Entries<T> = {
[K in keyof T]: [K, T[K]];
}[keyof T][];
export function entriesWithType<T extends object>(value: T): Entries<T>{
return Object.entries(value) as unknown as Entries<T>;
}
+4
View File
@@ -0,0 +1,4 @@
export function exportWindow(obj:unknown, objName: string, targetWindow?: unknown):void{
const target:unknown = targetWindow ?? window;
(target as {[v: string]: unknown})[objName] = obj;
}
+17
View File
@@ -0,0 +1,17 @@
export function filter초성(text: string): string {
const = [
"ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ",
"ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"
];
const result: string[] = [];
for (const char of text) {
const code = (char.codePointAt(0) ?? 0) - 44032;
if (0 <= code && code < 11172) {
result.push([~~(code / 588)]);
}
else {
result.push(char);
}
}
return result.join('');
}
+24
View File
@@ -0,0 +1,24 @@
export function filter초성withAlphabet(text: string): [string, string] {
const = [
"ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ",
"ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"
];
const alphabets = [
"r", "R", "s", "e", "E", "f", "a", "q", "Q",
"t", "T", "d", "w", "W", "c", "z", "x", "v", "g"
];
const resultH: string[] = [];
const resultA: string[] = [];
for (const char of text) {
const code = (char.codePointAt(0) ?? 0) - 44032;
if (0 <= code && code < 11172) {
resultH.push([~~(code / 588)]);
resultA.push(alphabets[~~(code / 588)]);
}
else {
resultH.push(char);
resultA.push(char);
}
}
return [resultH.join(''), resultA.join('')];
}
+18
View File
@@ -0,0 +1,18 @@
import { format, formatISO9075 } from 'date-fns';
//const DATE_TIME_FORMAT = 'yyyy-MM-dd HH:mm:ss';
const DATE_TIME_FORMAT_WITH_FRACTION = 'yyyy-MM-dd HH:mm:ss.SSS';
export function formatTime(time: Date, withFraction?:boolean): string;
export function formatTime(time: Date, format:string): string;
export function formatTime(time: Date, withFractionOrFormat:string|boolean = false): string {
if (typeof withFractionOrFormat === "string") {
return format(time, withFractionOrFormat);
}
else if(withFractionOrFormat){
return format(time, DATE_TIME_FORMAT_WITH_FRACTION);
}
else {
return formatISO9075(time);
}
}
+140
View File
@@ -0,0 +1,140 @@
interface Stats { min: number, max: number, total: number };
export function abilityRand(stats: Stats): [number, number, number] {
let leadership = Math.random() * 65 + 10;
let strength = Math.random() * 65 + 10;
let intel = Math.random() * 65 + 10;
const rate = leadership + strength + intel;
leadership = Math.floor((leadership / rate) * stats.total);
strength = Math.floor((strength / rate) * stats.total);
intel = Math.floor((intel / rate) * stats.total);
while (leadership + strength + intel < stats.total) {
leadership += 1;
}
if (
leadership > stats.max ||
strength > stats.max ||
intel > stats.max ||
leadership < stats.min ||
strength < stats.min ||
intel < stats.min
) {
return abilityRand(stats);
}
return [leadership, strength, intel];
}
export function abilityLeadpow(stats: Stats): [number, number, number] {
let leadership = Math.random() * 6;
let strength = Math.random() * 6;
let intel = Math.random() * 1;
const rate = leadership + strength + intel;
leadership = Math.floor((leadership / rate) * stats.total);
strength = Math.floor((strength / rate) * stats.total);
intel = Math.floor((intel / rate) * stats.total);
while (leadership + strength + intel < stats.total) {
strength += 1;
}
if (intel < stats.min) {
leadership -= stats.min - intel;
intel = stats.min;
}
if (leadership > stats.max) {
strength += leadership - stats.max;
leadership = stats.max;
}
if (strength > stats.max) {
leadership += strength - stats.max;
strength = stats.max;
}
if (leadership > stats.max) {
intel += leadership - stats.max;
leadership = stats.max;
}
return [leadership, strength, intel];
}
export function abilityLeadint(stats: Stats): [number, number, number] {
let leadership = Math.random() * 6;
let strength = Math.random() * 1;
let intel = Math.random() * 6;
const rate = leadership + strength + intel;
leadership = Math.floor((leadership / rate) * stats.total);
strength = Math.floor((strength / rate) * stats.total);
intel = Math.floor((intel / rate) * stats.total);
while (leadership + strength + intel < stats.total) {
intel += 1;
}
if (strength < stats.min) {
leadership -= stats.min - strength;
strength = stats.min;
}
if (leadership > stats.max) {
intel += leadership - stats.max;
leadership = stats.max;
}
if (intel > stats.max) {
leadership += intel - stats.max;
intel = stats.max;
}
if (leadership > stats.max) {
strength += leadership - stats.max;
leadership = stats.max;
}
return [leadership, strength, intel];
}
export function abilityPowint(stats: Stats): [number, number, number] {
let leadership = Math.random() * 1;
let strength = Math.random() * 6;
let intel = Math.random() * 6;
const rate = leadership + strength + intel;
leadership = Math.floor((leadership / rate) * stats.total);
strength = Math.floor((strength / rate) * stats.total);
intel = Math.floor((intel / rate) * stats.total);
while (leadership + strength + intel < stats.total) {
intel += 1;
}
if (leadership < stats.min) {
strength -= stats.min - leadership;
leadership = stats.min;
}
if (strength > stats.max) {
intel += strength - stats.max;
strength = stats.max;
}
if (intel > stats.max) {
strength += intel - stats.max;
intel = stats.max;
}
if (strength > stats.max) {
leadership += strength - stats.max;
strength = stats.max;
}
return [leadership, strength, intel];
}
+17
View File
@@ -0,0 +1,17 @@
import { unwrap } from "./unwrap";
//https://stackoverflow.com/questions/36280818/how-to-convert-file-to-base64-in-javascript
export function getBase64FromFileObject(file: File): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
let encoded = unwrap(reader.result).toString().replace(/^data:(.*,)?/, '');
if ((encoded.length % 4) > 0) {
encoded += '='.repeat(4 - (encoded.length % 4));
}
resolve(encoded);
};
reader.onerror = error => reject(error);
});
}
+4
View File
@@ -0,0 +1,4 @@
import { formatTime } from '@util/formatTime';
export function getDateTimeNow(withFraction = false): string {
return formatTime(new Date(), withFraction);
}
+8
View File
@@ -0,0 +1,8 @@
export function getIconPath(imgsvr: boolean | 1 | 0, picture: string): string {
// ../d_shared/common_path.js 필요
if (!imgsvr) {
return `${window.pathConfig.sharedIcon}/${picture}`;
} else {
return `${window.pathConfig.root}/d_pic/${picture}`;
}
}
+8
View File
@@ -0,0 +1,8 @@
export function hexToRgb(hex: string): { r: number; g: number; b: number; } | null {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
+7
View File
@@ -0,0 +1,7 @@
export function htmlReady(fn: () => unknown): void {
if (document.readyState != 'loading') {
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
+17
View File
@@ -0,0 +1,17 @@
import { BootstrapVueNext, BToastPlugin } from "bootstrap-vue-next";
import { Directives } from "bootstrap-vue-next";
import type { App } from "vue";
import Multiselect from "vue-multiselect";
export function installVue3Components<T>(app: App<T>): App<T> {
app.use(BootstrapVueNext).use(BToastPlugin).component('v-multiselect', Multiselect);
for (const [name, directive] of Object.entries(Directives)) {
//BVN 0.7.3 directive 이름 hack
if (!name.startsWith('v')) {
continue;
}
app.directive(name.substring(1), directive);
}
return app;
}
+11
View File
@@ -0,0 +1,11 @@
import { unwrap } from "@util/unwrap";
import { hexToRgb } from "@util/hexToRgb";
export function isBrightColor(color: string): boolean {
const cv = unwrap(hexToRgb(color));
if ((cv.r * 0.299 + cv.g * 0.587 + cv.b * 0.114) > 140) {
return true;
} else {
return false;
}
}
+3
View File
@@ -0,0 +1,3 @@
export function isNotNull<T>(value: T|null|undefined):value is T{
return value !== null && value !== undefined;
}
+3
View File
@@ -0,0 +1,3 @@
export function joinYearMonth(year: number, month: number): number {
return year * 12 + month - 1;
}
+118
View File
@@ -0,0 +1,118 @@
import Schema, { type Rule, type Values } from "async-validator";
import { isArray } from "lodash-es";
import { mergeKVArray } from "@util/mergeKVArray";
import $ from 'jquery';
type Option = {
preParse?: ($target?: JQuery<HTMLElement>)=>void,
postParse?: (values:Record<string, string | string[]>, $target?: JQuery<HTMLElement>)=>[Record<string, string | string[]>, Map<string, string>]
}
type DefaultFormDataType = Record<string, null|number[]|string[]|boolean[]|number|string|boolean>;
export type NamedRules<T extends Record<string, unknown>> = {
[v in keyof T]: Rule
}
export class JQValidateForm<TypedValue extends Values = DefaultFormDataType> {
public readonly validator: Schema;
public readonly inputs: JQuery<HTMLElement>;
constructor(public readonly target: JQuery<HTMLElement>, public readonly rule: NamedRules<TypedValue>, public readonly option?:Option) {
this.validator = new Schema(rule);
this.inputs = target.find(':input');
}
public clearErrMsg():void {
this.inputs.removeClass('is-invalid');
this.inputs.removeClass('is-valid');
this.target.find('.invalid-feedback').detach();
}
public installChangeHandler():this{
this.inputs.on('change', ()=>{
void this.validate();
});
return this;
}
public async validate(): Promise<undefined | TypedValue> {
if(this.option?.preParse !== undefined){
this.option.preParse(this.target);
}
let rawValues = mergeKVArray(this.inputs.serializeArray());
let optMap: Map<string, string>;
if(this.option?.postParse !== undefined){
[rawValues, optMap] = this.option.postParse(rawValues, this.target);
}
else{
optMap = new Map();
}
console.log(rawValues);
const validateResult = await this.validator.validate(rawValues).catch(({fields }) => {
if(fields === undefined){
console.error('validator 에러, 조건 검사 구문을 확인하세요.');
return;
}
this.clearErrMsg();
for(const rawKey of Object.keys(fields)){
let $item: JQuery<HTMLElement>;
const key = rawKey.split('.')[0];
console.log(`ErrorType: ${key}:${rawValues[key]}`);
const errMsg = fields[rawKey][0].message;
if(optMap.has(key)){
$item = this.target.find(optMap.get(key) as string);
}
else if(isArray(rawValues[key])){
$item = this.target.find(`:input[name='${key}[]']`);
}
else{
$item = this.target.find(`:input[name='${key}']`);
}
if($item.length == 0){
continue;
}
const $error = $(`<span>${errMsg}</span>`);
$error.addClass( "invalid-feedback" );
if ("radio" == $item.prop( "type" )) {
const $target = $item.parents( ".btn-group" );
$error.insertAfter( $target );
$target.addClass('is-invalid');
}
else if ("checkbox" == $item.prop( "type" )) {
let $target = $item.parent( "label" );
if($target.parent(".btn-group").length){
$target = $target.parent('.btn-group');
}
$error.insertAfter( $target );
$target.addClass('is-invalid');
} else {
$error.insertAfter( $item );
$item.addClass('is-invalid');
}
}
this.inputs.each(function(){
const name = (this as HTMLInputElement).name;
if(name in fields){
return;
}
this.classList.add('is-valid');
});
return undefined;
});
if(validateResult === undefined){
return undefined;
}
this.clearErrMsg();
this.inputs.addClass('is-valid');
return validateResult as TypedValue;
}
}
+31
View File
@@ -0,0 +1,31 @@
import { mb_strwidth } from "@util/mb_strwidth";
/**
* mb_strimwidth
* @param String
* @param int
* @param int
* @param String
* @return String
* @see http://www.php.net/manual/function.mb-strimwidth.php
*/
export function mb_strimwidth(str: string, start: number, width: number, trimmarker = ''): string {
const trimmakerWidth = mb_strwidth(trimmarker);
const l = str.length;
let trimmedLength = 0;
const trimmedStr: string[] = [];
for (let i = start; i < l; i++) {
const c = str.charAt(i);
const charWidth = mb_strwidth(c);
const next = str.charAt(i + 1);
const nextWidth = mb_strwidth(next);
trimmedLength += charWidth;
trimmedStr.push(c);
if (trimmedLength + trimmakerWidth + nextWidth > width) {
trimmedStr.push(trimmarker);
break;
}
}
return trimmedStr.join('');
}
+24
View File
@@ -0,0 +1,24 @@
//https://gist.github.com/demouth/3217440
/**
* mb_strwidth
* @see http://php.net/manual/function.mb-strwidth.php
*/
export function mb_strwidth(str: string): number {
const l = str.length;
let length = 0;
for (let i = 0; i < l; i++) {
const c = str.charCodeAt(i);
if (0x0000 <= c && c <= 0x0019) {
length += 0;
} else if (0x0020 <= c && c <= 0x1FFF) {
length += 1;
} else if (0x2000 <= c && c <= 0xFF60) {
length += 2;
} else if (0xFF61 <= c && c <= 0xFF9F) {
length += 1;
} else if (0xFFA0 <= c) {
length += 2;
}
}
return length;
}
+20
View File
@@ -0,0 +1,20 @@
import type { ValuesOf } from "@/defs";
import { zip } from "lodash-es";
export function merge2DArrToObjectArr<T extends Record<string, unknown>>(column: (keyof T)[], list: ValuesOf<T>[][]): T[]{
const result: T[] = [];
for(const rawItem of list){
const item: Record<string, unknown> = {};
if(column.length != rawItem.length){
throw `column과 item의 길이가 같지 않습니다: ${column.length} != ${list.length}, ${JSON.stringify(item)}`;
}
for(const [key, value] of zip(column, rawItem)){
item[key as string] = value;
}
result.push(item as T);
}
return result;
}
+35
View File
@@ -0,0 +1,35 @@
import { isString } from "lodash-es";
interface NameValuePair {
name: string,
value: string
}
export function mergeKVArray(array : NameValuePair[]):Record<string, string|string[]>{
const result:Record<string, string|string[]> = {};
for(const {name, value} of array){
if(!isString(name)){
throw new TypeError(`${name} is not string`);
}
if(!isString(value)){
throw new TypeError(`${value} is not string`);
}
if(name === '' || name === '[]'){
continue;
}
if(name.length > 2 && name.slice(-2) == '[]'){
const keyHead = name.slice(0, -2);
if(!(keyHead in result)){
result[keyHead] = [value];
}
else{
(result[keyHead] as string[]).push(value);
}
continue;
}
result[name] = value;
}
return result;
}
+4
View File
@@ -0,0 +1,4 @@
export function nl2br(text: string): string {
return text.replace(/\n/g, "<br>");
}
+5
View File
@@ -0,0 +1,5 @@
export function numberWithCommas(x: number): string {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
+5
View File
@@ -0,0 +1,5 @@
import {parseISO} from 'date-fns';
export function parseTime(dateString: string): Date{
return parseISO(dateString);
}
+3
View File
@@ -0,0 +1,3 @@
export function parseYearMonth(yearMonth: number): [number, number] {
return [(yearMonth / 12) | 0, yearMonth % 12 + 1];
}
+25
View File
@@ -0,0 +1,25 @@
const charList = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
];
export function randStr(len: number): string {
const result = [];
const charListLen = charList.length;
let isStart = true;
while(len > 0){
const randChrIdx = Math.floor(Math.random() * charListLen);
if(isStart){
if(randChrIdx == 0){
continue;
}
isStart = false;
}
result.push(charList[randChrIdx]);
len -= 1;
}
return result.join('');
}
+10
View File
@@ -0,0 +1,10 @@
/** @deprecated */
export function scrollHardTo(elementId: string): void {
const element = document.getElementById(elementId);
if(!element){
return;
}
element.scrollIntoView({
behavior: 'auto',
});
}
+9
View File
@@ -0,0 +1,9 @@
export function scrollToSelector(selector: string): void {
const element = document.querySelector(selector);
if(!element){
return;
}
element.scrollIntoView({
behavior: 'auto',
});
}
+6
View File
@@ -0,0 +1,6 @@
import axios from "axios";
export function setAxiosXMLHttpRequest(): void{
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
//TODO: X-Requested-With 믿지 말자.
}
+18
View File
@@ -0,0 +1,18 @@
import { isInteger, isString } from "lodash-es";
export function simpleSerialize(...values : (string|number)[]): string{
const result = [];
for(const value of values){
if(isString(value)){
result.push(`str(${value.length},${value})`);
continue;
}
if(isInteger(value)){
result.push(`int(${value})`);
continue;
}
const float6 = value.toLocaleString("en-US", {maximumFractionDigits: 6});
result.push(`float(${float6})`);
}
return result.join('|');
}
+9
View File
@@ -0,0 +1,9 @@
import type { Nullable } from "@util/Nullable";
import { NotNullExpected } from "@util/NotNullExpected";
export function unwrap<T>(result: Nullable<T>): T {
if (result === null || result === undefined) {
throw new NotNullExpected();
}
return result;
}
+10
View File
@@ -0,0 +1,10 @@
import type { Nullable } from "@util/Nullable";
import { NotNullExpected } from "@util/NotNullExpected";
export function unwrap_any<T>(result: Nullable<unknown>): T {
if (result === null || result === undefined) {
throw new NotNullExpected();
}
return result as T;
}
+10
View File
@@ -0,0 +1,10 @@
import type { Nullable } from "@util/Nullable";
type ErrType<T> = { new(msg?: string): T }
export function unwrap_err<T, ErrT extends Error>(result: Nullable<T>, errType: ErrType<ErrT>, errMsg?: string): T {
if (result === null || result === undefined) {
throw new errType(errMsg);
}
return result;
}
+4 -4
View File
@@ -1,5 +1,5 @@
{
"files": [],
//"files": [],
"references": [
{
"path": "./tsconfig.node.json"
@@ -12,11 +12,11 @@
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"resolveJsonModule": true,
"noImplicitOverride": true,
//"noImplicitOverride": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
//"noPropertyAccessFromIndexSignature": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
//"verbatimModuleSyntax": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,