first commit
This commit is contained in:
commit
0f6382b992
|
|
@ -0,0 +1,23 @@
|
|||
/lib
|
||||
/Lib
|
||||
/Scripts
|
||||
/include
|
||||
/pip-wheel-metadata
|
||||
/pyvenv.cfg
|
||||
/venv
|
||||
/Scripts
|
||||
/include
|
||||
/pip-wheel-metadata
|
||||
/pyvenv.cfg
|
||||
pyvenv.cfg
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
*.pyw
|
||||
*.pyz
|
||||
*.pywz
|
||||
*.pyzw
|
||||
*.pyzwz
|
||||
*.pyzwzw
|
||||
*.pyzwzwz
|
||||
*.log
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
code_name,code_description,data_type,car_id,alias_name,manufacturer
|
||||
ACK_WHD1,TACHO1 설정 차륜경,데이터,5,우진200량-3단계,Woojin
|
||||
ACK_WHD2,TACHO2 설정 차륜경,데이터,5,우진200량-3단계,Woojin
|
||||
ADOL,왼쪽 출입문 열림명령,데이터,5,우진200량-3단계,Woojin
|
||||
ADOR,오른쪽 출입문 열림명령,데이터,5,우진200량-3단계,Woojin
|
||||
ATO_EB_REQ,ATO 비상제동 요구,데이터,5,우진200량-3단계,Woojin
|
||||
ATO_LIMITSPEED,ATO 제한속도,데이터,5,우진200량-3단계,Woojin
|
||||
ATO_ERR_MSG,ATO 에러 메시지,데이터,5,우진200량-3단계,Woojin
|
||||
ATO_ERR_DETECT,ATO 에러 검지,데이터,5,우진200량-3단계,Woojin
|
||||
ATO_START_BTN,출발 버튼 취급,데이터,5,우진200량-3단계,Woojin
|
||||
ATC_CARRIER_F,ATC 캐리어 주파수,데이터,5,우진200량-3단계,Woojin
|
||||
ATC_CODE,ATC 코드,데이터,5,우진200량-3단계,Woojin
|
||||
ATC_CODE_CARRIER_F,ATC 코드 캐리어 주파수,데이터,5,우진200량-3단계,Woojin
|
||||
ATC_CODE_F,ATC 코드 주파수,데이터,5,우진200량-3단계,Woojin
|
||||
ATC_ERR_MSG,ATC 에러 메시지,데이터,5,우진200량-3단계,Woojin
|
||||
ATC_STATUS,ATC 상태,데이터,5,우진200량-3단계,Woojin
|
||||
ATC_SWVER,ATC SW 버전,데이터,5,우진200량-3단계,Woojin
|
||||
AUTO,운전모드 AUTO,데이터,5,우진200량-3단계,Woojin
|
||||
DIAGNOSTIC_ERR_MSG,다이그노스틱 에러 메시지,데이터,5,우진200량-3단계,Woojin
|
||||
DOORMOD,출입문 모드,데이터,5,우진200량-3단계,Woojin
|
||||
DOOR_CLOSE,출입문 닫힘,데이터,5,우진200량-3단계,Woojin
|
||||
DOOR_CLOSE_WARNING,출입문 닫힘 경고,데이터,5,우진200량-3단계,Woojin
|
||||
DOOR_OPEN,출입문 열림,데이터,5,우진200량-3단계,Woojin
|
||||
DO_ZVR,ZVR 출력,데이터,5,우진200량-3단계,Woojin
|
||||
DO_EDL,EDL 출력,데이터,5,우진200량-3단계,Woojin
|
||||
DO_EDR,EDR 출력,데이터,5,우진200량-3단계,Woojin
|
||||
DO_FSB,FSB 출력,데이터,5,우진200량-3단계,Woojin
|
||||
DO_EBP,EB(+) 출력,데이터,5,우진200량-3단계,Woojin
|
||||
DO_EBM,EB(-) 출력,데이터,5,우진200량-3단계,Woojin
|
||||
DSTN,TWC 종착역,데이터,5,우진200량-3단계,Woojin
|
||||
DTG,남은거리,데이터,5,우진200량-3단계,Woojin
|
||||
FA,운전모드 FA,데이터,5,우진200량-3단계,Woojin
|
||||
F1,ATC 캐리어 F1,데이터,5,우진200량-3단계,Woojin
|
||||
F2,ATC 캐리어 F2,데이터,5,우진200량-3단계,Woojin
|
||||
F3,ATC 캐리어 F3,데이터,5,우진200량-3단계,Woojin
|
||||
F4,ATC 캐리어 F4,데이터,5,우진200량-3단계,Woojin
|
||||
FAIL_ATCR,ATCR 통신 실패,데이터,5,우진200량-3단계,Woojin
|
||||
FAIL_ATOC,ATOC 통신실패,데이터,5,우진200량-3단계,Woojin
|
||||
FAIL_TACHO1,TACHO1 통신실패,데이터,5,우진200량-3단계,Woojin
|
||||
FAIL_TACHO2,TACHO2 통신실패,데이터,5,우진200량-3단계,Woojin
|
||||
FAIL_TCMS,TCMS 통신실패,데이터,5,우진200량-3단계,Woojin
|
||||
FORMNO,편성 번호,데이터,5,우진200량-3단계,Woojin
|
||||
FMC,운전모드 FMC,데이터,5,우진200량-3단계,Woojin
|
||||
HCR,선두차 지정,데이터,5,우진200량-3단계,Woojin
|
||||
INTERFACE_ERR_MSG,인터페이스 에러 메시지,데이터,5,우진200량-3단계,Woojin
|
||||
INCHING,정위치 정밀제어,데이터,5,우진200량-3단계,Woojin
|
||||
IPDT_NG,이니셜PDT NG,데이터,5,우진200량-3단계,Woojin
|
||||
IPDT_OK,이니셜PDT OK,데이터,5,우진200량-3단계,Woojin
|
||||
KUR,KEY UP RELAY,데이터,5,우진200량-3단계,Woojin
|
||||
LIMITSPEED,ATC 제한속도,데이터,5,우진200량-3단계,Woojin
|
||||
LIMIT_DRIVE,가속제한,데이터,5,우진200량-3단계,Woojin
|
||||
MARKER,PG 마커,데이터,5,우진200량-3단계,Woojin
|
||||
MASCON_BR,마스콘 제동,데이터,5,우진200량-3단계,Woojin
|
||||
MASCON_DR,마스콘 추진,데이터,5,우진200량-3단계,Woojin
|
||||
MASCON_EB,마스콘 비상,데이터,5,우진200량-3단계,Woojin
|
||||
MASCON_NEU,마스콘 중립,데이터,5,우진200량-3단계,Woojin
|
||||
MCS,운전모드 MCS,데이터,5,우진200량-3단계,Woojin
|
||||
MPDT_NG,매뉴얼PDT NG,데이터,5,우진200량-3단계,Woojin
|
||||
MPDT_OK,매뉴얼PDT OK,데이터,5,우진200량-3단계,Woojin
|
||||
MPDT_START,매뉴얼PDT START,데이터,5,우진200량-3단계,Woojin
|
||||
NEXTDOOR,다음역 출입문 방향,데이터,5,우진200량-3단계,Woojin
|
||||
NOMAL,평상모드,데이터,5,우진200량-3단계,Woojin
|
||||
NSTN,TWC 다음역,데이터,5,우진200량-3단계,Woojin
|
||||
OVER_SPD_WARNING,과속 경고,데이터,5,우진200량-3단계,Woojin
|
||||
OSC_F0_OK,OSC 상시주파수 OK,데이터,5,우진200량-3단계,Woojin
|
||||
OSC_F,OSC 주파수,데이터,5,우진200량-3단계,Woojin
|
||||
OV_STOP2,70이상 초과,데이터,5,우진200량-3단계,Woojin
|
||||
PRE_BRAKE,사전제동,데이터,5,우진200량-3단계,Woojin
|
||||
PWM_VALUE,PWM 값,데이터,5,우진200량-3단계,Woojin
|
||||
PSD_OPEN,PSD 열림,데이터,5,우진200량-3단계,Woojin
|
||||
PSD_CLOSE,PSD 닫힘,데이터,5,우진200량-3단계,Woojin
|
||||
PSTN,TWC 현재역,데이터,5,우진200량-3단계,Woojin
|
||||
RECOVERY,회복모드,데이터,5,우진200량-3단계,Woojin
|
||||
REVERSINGROD_ FWD,역전기 전진,데이터,5,우진200량-3단계,Woojin
|
||||
REVERSINGROD_ NEU,역전기 중립,데이터,5,우진200량-3단계,Woojin
|
||||
REVERSINGROD_RVS,역전기 후진,데이터,5,우진200량-3단계,Woojin
|
||||
SEQ,시퀀스 넘버,데이터,5,우진200량-3단계,Woojin
|
||||
SH_STOP2,70이상 미달,데이터,5,우진200량-3단계,Woojin
|
||||
START_ENABLE,출발 허용 조건,데이터,5,우진200량-3단계,Woojin
|
||||
SYSTEM_ACTIVE,장치 상태,데이터,5,우진200량-3단계,Woojin
|
||||
TRAINSPEED,열차 속도,데이터,5,우진200량-3단계,Woojin
|
||||
TRAINSPEED_A,TACHO1 속도,데이터,5,우진200량-3단계,Woojin
|
||||
TRAINSPEED_B,TACHO2 속도,데이터,5,우진200량-3단계,Woojin
|
||||
TRAINNO,열 번,데이터,5,우진200량-3단계,Woojin
|
||||
TASC,타스크,데이터,5,우진200량-3단계,Woojin
|
||||
TASC_DB,가상 타스크,데이터,5,우진200량-3단계,Woojin
|
||||
TACHO_DIR_A,TACHO1 방향,데이터,5,우진200량-3단계,Woojin
|
||||
TACHO_DIR_B,TACHO2 방향,데이터,5,우진200량-3단계,Woojin
|
||||
TCMSDOOR,TCMS 출입문 정보,데이터,5,우진200량-3단계,Woojin
|
||||
TC1,1호차,데이터,5,우진200량-3단계,Woojin
|
||||
TC2,8호차,데이터,5,우진200량-3단계,Woojin
|
||||
TRAC_BR,추진 명령,데이터,5,우진200량-3단계,Woojin
|
||||
TRAC_CS,타행 명령,데이터,5,우진200량-3단계,Woojin
|
||||
TRAC_DR,제동 명령,데이터,5,우진200량-3단계,Woojin
|
||||
TRAINBERTH,정위치 정차,데이터,5,우진200량-3단계,Woojin
|
||||
TCR,꼬리차 지정,데이터,5,우진200량-3단계,Woojin
|
||||
TIME,시간,데이터,5,우진200량-3단계,Woojin
|
||||
TWCT_ENABLE,TWC 송신 허용,데이터,5,우진200량-3단계,Woojin
|
||||
WHEELCHECK,차륜경 검증,데이터,5,우진200량-3단계,Woojin
|
||||
WRONGDOOR,TWC 출입문 방향불일치,데이터,5,우진200량-3단계,Woojin
|
||||
YARD,운전모드 YARD,데이터,5,우진200량-3단계,Woojin
|
||||
ADC(Automatic Close Door),출입문 자동 닫힘 제어 명령,약어,5,우진200량-3단계,Woojin
|
||||
ADOL(Automatic Open Left Door),"왼쪽 출입문 자동 열림 제어 명령(MCS, AUTO, FA)",약어,5,우진200량-3단계,Woojin
|
||||
ADOR(Automatic Open Right Door),"오른쪽 출입문 자동 열림 제어 명령(MCS, AUTO, FA)",약어,5,우진200량-3단계,Woojin
|
||||
ATO EB REQ(ATO Emergency Brake Request),ATO 비상제동 요청,약어,5,우진200량-3단계,Woojin
|
||||
BR(Brake Relay),제동 릴레이,약어,5,우진200량-3단계,Woojin
|
||||
DR(Drive Relay),추진 릴레이,약어,5,우진200량-3단계,Woojin
|
||||
CS(Coast),타행,약어,5,우진200량-3단계,Woojin
|
||||
CSC(Constant Control Speed),정속 운행,약어,5,우진200량-3단계,Woojin
|
||||
DCW(Door Close Warning),출입문 닫힘 경고,약어,5,우진200량-3단계,Woojin
|
||||
DIA1 ACK(Ack for Wheel DIA1 Value),차륜경 설정 1값의 인정,약어,5,우진200량-3단계,Woojin
|
||||
DIA2 ACK(Ack for Wheel DIA2 Value),차륜경 설정 2값의 인정,약어,5,우진200량-3단계,Woojin
|
||||
EB(Emergency Brake),비상제동,약어,5,우진200량-3단계,Woojin
|
||||
EDL(Enable Door Left),왼쪽 출입문 열림 가능,약어,5,우진200량-3단계,Woojin
|
||||
EDR(Enable Door Right),오른쪽 출입문 열림 가능,약어,5,우진200량-3단계,Woojin
|
||||
FSB(Full Service Brake),상용만제동,약어,5,우진200량-3단계,Woojin
|
||||
HCR(Head Control Relay),선두차 지정 입력신호,약어,5,우진200량-3단계,Woojin
|
||||
INCHING(Inching),정밀 제어 동작,약어,5,우진200량-3단계,Woojin
|
||||
INITIAL PDT(Initial PDT),장치 기동 시 자동 PDT 시험,약어,5,우진200량-3단계,Woojin
|
||||
KUR(Key Up Relay),키 업 릴레이(불용),약어,5,우진200량-3단계,Woojin
|
||||
MANUAL PDT(Manual PDT),수동 PDT 시험,약어,5,우진200량-3단계,Woojin
|
||||
OSC(OSC Relay),OSC 안테나 선택 릴레이(1계/2계),약어,5,우진200량-3단계,Woojin
|
||||
OvrSPD Warning(Over Speed Warining),ATC 과속 경고,약어,5,우진200량-3단계,Woojin
|
||||
SEL(Start Enable Lamp),AUTO 출발버튼 램프,약어,5,우진200량-3단계,Woojin
|
||||
SYSTEM ACTIVE(System Active),"1,2계 시스템 중 주 계(MAIN)를 표현",약어,5,우진200량-3단계,Woojin
|
||||
TACHO DIR#A(Tacho Direction A),DI#A에 입력되는 전방 TACHO 방향(ON:FWD / OFF:RVS),약어,5,우진200량-3단계,Woojin
|
||||
TACHO DIR#B(Tacho Direction B),DI#B에 입력되는 후방 TACHO 방향(ON:FWD / OFF:RVS),약어,5,우진200량-3단계,Woojin
|
||||
TASC(Train Automatic Stop Control),TASC 제어모드,약어,5,우진200량-3단계,Woojin
|
||||
TASC DB(Train Automatic Stop Control Data Base),DB TASC 제어모드,약어,5,우진200량-3단계,Woojin
|
||||
TCR(Tale Control Relay),후미차 지정 입력신호,약어,5,우진200량-3단계,Woojin
|
||||
TRAIN BERTH(Train Berth),정위치 정차,약어,5,우진200량-3단계,Woojin
|
||||
TWCT x Enable(TWC TX Enable),TWCT 차상>지상 송신 허용,약어,5,우진200량-3단계,Woojin
|
||||
WRONG Door(TWC Door Direction Wrong),지상 출입문 방향 정보와 차상 출입문 방향 정보가 다를 때 알림,약어,5,우진200량-3단계,Woojin
|
||||
가속제한(Acceleration Limitation),추진 중 정해진 속도코드보다 목표속도를 제한하여 제동 충격 방지,약어,5,우진200량-3단계,Woojin
|
||||
사전제동(Pre-Braking),운행 간 속도코드 변환 지점에 맞춰 사전에 제동하여 충격 방지,약어,5,우진200량-3단계,Woojin
|
||||
|
Binary file not shown.
|
|
@ -0,0 +1,37 @@
|
|||
1호선 고장코드 (Flask + HTMX, Supabase)
|
||||
|
||||
실행 방법
|
||||
|
||||
1) 의존성 설치 (venv 권장)
|
||||
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
2) 환경변수 설정
|
||||
|
||||
```
|
||||
# Windows PowerShell 예시
|
||||
$env:SUPABASE_URL="http://192.168.0.180:54321" # 로컬 도커 기본 포트
|
||||
$env:SUPABASE_ANON_KEY="<ANON_KEY>"
|
||||
```
|
||||
|
||||
3) 서버 실행
|
||||
|
||||
```
|
||||
python app.py
|
||||
```
|
||||
|
||||
브라우저에서 http://localhost:5000 접속
|
||||
|
||||
기능
|
||||
- Supabase의 `public.Falut_Code_Table`에서 필터/검색
|
||||
- 항목 클릭 시 모달 상세 표시
|
||||
- 다크모드 토글
|
||||
|
||||
비고
|
||||
- 로컬 SQLite 및 `/api/meta`, `/api/db` 기반 동기화는 제거됨
|
||||
- Supabase 접속 실패 시 안내 메시지를 화면에 표시
|
||||
- 사내망 주소/포트 방화벽 허용 필요 (예: 54321, 8000 등 구성에 따라 상이)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,542 @@
|
|||
import os
|
||||
from typing import Optional, List, Dict
|
||||
import httpx
|
||||
|
||||
from flask import Flask, g, render_template, request, abort
|
||||
from urllib.parse import urlencode
|
||||
from dotenv import load_dotenv
|
||||
|
||||
|
||||
|
||||
APP_NAME = "1호선 고장코드"
|
||||
|
||||
|
||||
def create_app() -> Flask:
|
||||
app = Flask(__name__)
|
||||
app.config.update(TEMPLATES_AUTO_RELOAD=True)
|
||||
|
||||
# 환경변수 로드 및 Supabase 기본값 설정
|
||||
load_dotenv()
|
||||
# 기본: Kong 프록시(8000) 또는 사용자가 지정한 URL
|
||||
app.config.setdefault("SUPABASE_URL", os.environ.get("SUPABASE_URL", "http://192.168.0.180:8000"))
|
||||
app.config.setdefault("SUPABASE_ANON_KEY", os.environ.get("SUPABASE_ANON_KEY", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzU4NTUxNjY2LCJleHAiOjQxMDI0NDQ4MDB9.jMCGL3Q-N2o_l7JQE_HrO7Uoct86CMgLsVxpabisG4I"))
|
||||
# Kong Basic Auth(선택)
|
||||
app.config.setdefault("SUPABASE_BASIC_USER", os.environ.get("SUPABASE_BASIC_USER", ""))
|
||||
app.config.setdefault("SUPABASE_BASIC_PASSWORD", os.environ.get("SUPABASE_BASIC_PASSWORD", ""))
|
||||
|
||||
# 더 이상 SQLite 초기화/연결을 사용하지 않음 (Supabase만 사용)
|
||||
|
||||
# PostgREST(REST) 클라이언트 빌더
|
||||
def build_pg_client() -> httpx.Client:
|
||||
base = app.config["SUPABASE_URL"].rstrip("/") + "/rest/v1"
|
||||
basic_user = app.config.get("SUPABASE_BASIC_USER") or ""
|
||||
basic_pass = app.config.get("SUPABASE_BASIC_PASSWORD") or ""
|
||||
headers = {
|
||||
"apikey": app.config.get("SUPABASE_ANON_KEY", ""),
|
||||
"Accept-Profile": "public",
|
||||
"Content-Profile": "public",
|
||||
}
|
||||
auth = httpx.BasicAuth(basic_user, basic_pass) if basic_user else None
|
||||
if not auth and app.config.get("SUPABASE_ANON_KEY"):
|
||||
headers["Authorization"] = f"Bearer {app.config['SUPABASE_ANON_KEY']}"
|
||||
return httpx.Client(base_url=base, headers=headers, auth=auth, timeout=10)
|
||||
|
||||
def pg_unique(col: str) -> List[str]:
|
||||
with build_pg_client() as c:
|
||||
r = c.get("/Fault_Code_Table", params={"select": col})
|
||||
r.raise_for_status()
|
||||
vals = [row.get(col) for row in (r.json() or []) if row.get(col)]
|
||||
seen: Dict[str, bool] = {}
|
||||
out: List[str] = []
|
||||
for v in vals:
|
||||
if v not in seen:
|
||||
seen[v] = True
|
||||
out.append(v)
|
||||
return out
|
||||
|
||||
def pg_unique_from(table: str, col: str) -> List[str]:
|
||||
"""지정 테이블에서 고유값 리스트를 반환한다."""
|
||||
with build_pg_client() as c:
|
||||
r = c.get(f"/{table}", params={"select": col})
|
||||
r.raise_for_status()
|
||||
vals = [row.get(col) for row in (r.json() or []) if row.get(col)]
|
||||
seen: Dict[str, bool] = {}
|
||||
out: List[str] = []
|
||||
for v in vals:
|
||||
if v not in seen:
|
||||
seen[v] = True
|
||||
out.append(v)
|
||||
return out
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template(
|
||||
"index.html",
|
||||
app_name=APP_NAME,
|
||||
)
|
||||
|
||||
# 기존 SQLite 기반 라우트 제거됨
|
||||
|
||||
@app.route("/modal/close")
|
||||
def modal_close():
|
||||
return ""
|
||||
|
||||
@app.route("/health")
|
||||
def health():
|
||||
return {"status": "ok"}
|
||||
|
||||
# 빈 파비콘 응답으로 404 제거
|
||||
@app.route("/favicon.ico")
|
||||
def favicon():
|
||||
return ("", 204, {"Content-Type": "image/x-icon"})
|
||||
|
||||
# 브라우저/툴 호환을 위해 루트 경로에도 매니페스트 노출 (정적 파일 경로 사용 권장)
|
||||
# 더 이상 /api/* 동기화 엔드포인트 제공하지 않음
|
||||
|
||||
# ----------------- Supabase 기반 라우트 -----------------
|
||||
@app.route("/sb/tabs")
|
||||
def sb_tabs():
|
||||
try:
|
||||
with build_pg_client() as c:
|
||||
r1 = c.get("/Fault_Code_Table", params={"select": "manufacturer"})
|
||||
r1.raise_for_status()
|
||||
vals1 = [row.get("manufacturer") for row in (r1.json() or []) if row.get("manufacturer")]
|
||||
vals2: List[str] = []
|
||||
for path in ("/Signals", "/signals"):
|
||||
try:
|
||||
r2 = c.get(path, params={"select": "manufacturer"})
|
||||
r2.raise_for_status()
|
||||
vals2 = [row.get("manufacturer") for row in (r2.json() or []) if row.get("manufacturer")]
|
||||
break
|
||||
except httpx.HTTPError:
|
||||
continue
|
||||
vals = vals1 + vals2
|
||||
seen: Dict[str, bool] = {}
|
||||
manufacturers: List[str] = []
|
||||
for v in vals:
|
||||
if v not in seen:
|
||||
seen[v] = True
|
||||
manufacturers.append(v)
|
||||
return render_template("partials/sb_tabs.html", manufacturers=manufacturers)
|
||||
except Exception as e:
|
||||
return render_template(
|
||||
"partials/sb_error.html",
|
||||
error_message=str(e),
|
||||
supabase_url=app.config.get("SUPABASE_URL"),
|
||||
)
|
||||
@app.route("/sb")
|
||||
def sb_home():
|
||||
try:
|
||||
# ---- MMI 코드 분기 ----
|
||||
if request.args.get("section", "fault").strip() == "mmicode":
|
||||
PAGE_SIZE = 50
|
||||
page = int(request.args.get("page", "0"))
|
||||
offset = page * PAGE_SIZE
|
||||
|
||||
# 셀렉트박스/검색 필드
|
||||
with build_pg_client() as c:
|
||||
# 제조사
|
||||
res = c.get("/MMI_Code", params={"select": "manufacturer"})
|
||||
res.raise_for_status()
|
||||
manufacturers = sorted({row.get("manufacturer") for row in (res.json() or []) if row.get("manufacturer")})
|
||||
# 차량분류(alias_name)
|
||||
res2 = c.get("/MMI_Code", params={"select": "alias_name"})
|
||||
res2.raise_for_status()
|
||||
alias_names = sorted({row.get("alias_name") for row in (res2.json() or []) if row.get("alias_name")})
|
||||
|
||||
selected_manufacturer = request.args.get("manufacturer", "").strip()
|
||||
selected_alias_name = request.args.get("alias_name", "").strip()
|
||||
q = request.args.get("q", "").strip()
|
||||
group_code = request.args.get("group_code", "").strip().lower() == "on"
|
||||
# MMI 쿼리
|
||||
params = {
|
||||
"select": "id,code_name,code_description,data_type,car_id,alias_name,manufacturer",
|
||||
"order": "code_name.asc",
|
||||
"limit": str(PAGE_SIZE),
|
||||
"offset": str(offset),
|
||||
}
|
||||
if selected_manufacturer:
|
||||
params["manufacturer"] = f"eq.{selected_manufacturer}"
|
||||
if selected_alias_name:
|
||||
params["alias_name"] = f"eq.{selected_alias_name}"
|
||||
if q:
|
||||
# 여러 컬럼에 대해 ilike filter
|
||||
params["or"] = f"(code_name.ilike.*{q}*,code_description.ilike.*{q}*,alias_name.ilike.*{q}*)"
|
||||
|
||||
with build_pg_client() as c:
|
||||
res = c.get("/MMI_Code", params=params)
|
||||
res.raise_for_status()
|
||||
rows = res.json() or []
|
||||
# dedup if group_code on
|
||||
if group_code:
|
||||
seen = set()
|
||||
dedup = []
|
||||
for r in rows:
|
||||
code = r.get("code_name")
|
||||
if code and code not in seen:
|
||||
seen.add(code)
|
||||
dedup.append(r)
|
||||
rows = dedup
|
||||
|
||||
query_params = request.args.to_dict()
|
||||
if "page" in query_params:
|
||||
del query_params["page"]
|
||||
query_params_string = urlencode(query_params)
|
||||
|
||||
# 템플릿 렌더 및 선택 파라미터 전달
|
||||
return render_template(
|
||||
"partials/sb_mmi_list.html",
|
||||
rows=rows,
|
||||
manufacturers=manufacturers,
|
||||
alias_names=alias_names,
|
||||
selected_manufacturer=selected_manufacturer,
|
||||
selected_alias_name=selected_alias_name,
|
||||
q=q,
|
||||
group_code="on" if group_code else "off",
|
||||
section="mmicode",
|
||||
page=page,
|
||||
page_size=PAGE_SIZE,
|
||||
query_params_string=query_params_string,
|
||||
)
|
||||
|
||||
# ---- 기존(고장코드/TCMS) ----
|
||||
mf_fault = pg_unique("manufacturer")
|
||||
mf_signal = pg_unique_from("Signals", "manufacturer")
|
||||
seen_mf: Dict[str, bool] = {}
|
||||
manufacturers: List[str] = []
|
||||
for v in (mf_fault + mf_signal):
|
||||
if v and v not in seen_mf:
|
||||
seen_mf[v] = True
|
||||
manufacturers.append(v)
|
||||
|
||||
devices = pg_unique("device")
|
||||
car_types = pg_unique("car_type")
|
||||
car_ids = pg_unique("car_id")
|
||||
# alias_name 필터는 제작사에 따라 값 제한: 우진/로템/다대 포함
|
||||
all_alias = pg_unique("alias_name")
|
||||
selected_manufacturer = request.args.get("manufacturer", "").strip()
|
||||
def alias_allowed(name: str) -> bool:
|
||||
if not name:
|
||||
return False
|
||||
low = name.lower()
|
||||
if selected_manufacturer.lower() == "woojin":
|
||||
return ("우진" in name) or ("woojin" in low)
|
||||
if selected_manufacturer.lower() == "rotem":
|
||||
return ("로템" in name) or ("다대" in name) or ("rotem" in low)
|
||||
return True
|
||||
alias_names = [a for a in all_alias if alias_allowed(a)]
|
||||
signal_classifications = pg_unique_from("Signals", "classification")
|
||||
|
||||
# 선택값 처리 (쿼리스트링에 manufacturer 키가 있으면 빈 문자열이라도 그대로 유지)
|
||||
if "manufacturer" in request.args:
|
||||
selected_manufacturer = (request.args.get("manufacturer") or "").strip()
|
||||
else:
|
||||
selected_manufacturer = manufacturers[0] if manufacturers else ""
|
||||
|
||||
# 다른 필터의 현재 선택값 유지
|
||||
selected_device = request.args.get("device", "").strip()
|
||||
selected_car_type = request.args.get("car_type", "").strip()
|
||||
selected_alias_name = request.args.get("alias_name", "").strip()
|
||||
selected_classification = request.args.get("classification", "").strip()
|
||||
q = request.args.get("q", "").strip()
|
||||
section = request.args.get("section", "fault").strip() or "fault"
|
||||
|
||||
return render_template(
|
||||
"partials/sb_manufacturer.html",
|
||||
manufacturers=manufacturers,
|
||||
devices=devices,
|
||||
car_types=car_types,
|
||||
car_ids=car_ids,
|
||||
alias_names=alias_names,
|
||||
signal_classifications=signal_classifications,
|
||||
selected_manufacturer=selected_manufacturer,
|
||||
selected_device=selected_device,
|
||||
selected_car_type=selected_car_type,
|
||||
selected_alias_name=selected_alias_name,
|
||||
selected_classification=selected_classification,
|
||||
q=q,
|
||||
section=section,
|
||||
)
|
||||
except Exception as e:
|
||||
return render_template(
|
||||
"partials/sb_error.html",
|
||||
error_message=str(e),
|
||||
supabase_url=app.config.get("SUPABASE_URL"),
|
||||
)
|
||||
|
||||
@app.route("/sb/faults/list")
|
||||
def sb_faults_list():
|
||||
try:
|
||||
PAGE_SIZE = 50
|
||||
page = int(request.args.get("page", "0"))
|
||||
offset = page * PAGE_SIZE
|
||||
|
||||
manufacturer = request.args.get("manufacturer", "").strip()
|
||||
device = request.args.get("device", "").strip()
|
||||
car_type = request.args.get("car_type", "").strip()
|
||||
car_id = request.args.get("car_id", "").strip()
|
||||
alias_name = request.args.get("alias_name", "").strip()
|
||||
q = request.args.get("q", "").strip()
|
||||
section = request.args.get("section", "fault").strip()
|
||||
params: Dict[str, str] = {
|
||||
"select": "f_code,f_code_num,f_name,manufacturer,device,car_type,car_id,fault_detail,alias_name",
|
||||
"order": "f_code.asc",
|
||||
"limit": str(PAGE_SIZE),
|
||||
"offset": str(offset),
|
||||
}
|
||||
if manufacturer:
|
||||
params["manufacturer"] = f"eq.{manufacturer}"
|
||||
if device:
|
||||
params["device"] = f"eq.{device}"
|
||||
if car_type:
|
||||
params["car_type"] = f"eq.{car_type}"
|
||||
if car_id:
|
||||
params["car_id"] = f"eq.{car_id}"
|
||||
if alias_name:
|
||||
params["alias_name"] = f"eq.{alias_name}"
|
||||
if q:
|
||||
params["or"] = f"(f_code.ilike.*{q}*,f_name.ilike.*{q}*)"
|
||||
|
||||
with build_pg_client() as c:
|
||||
r = c.get("/Fault_Code_Table", params=params)
|
||||
r.raise_for_status()
|
||||
rows = r.json() or []
|
||||
# 그룹핑 옵션: 같은 f_code를 첫 항목만 남김
|
||||
group_code = request.args.get("group_code", "").strip().lower()
|
||||
if group_code == "on":
|
||||
seen: Dict[str, bool] = {}
|
||||
dedup: List[Dict] = []
|
||||
for r in rows:
|
||||
code = r.get("f_code")
|
||||
if code and code not in seen:
|
||||
seen[code] = True
|
||||
dedup.append(r)
|
||||
rows = dedup
|
||||
|
||||
query_params = request.args.to_dict()
|
||||
if "page" in query_params:
|
||||
del query_params["page"]
|
||||
query_params_string = urlencode(query_params)
|
||||
|
||||
return render_template(
|
||||
"partials/sb_fault_list.html",
|
||||
rows=rows,
|
||||
page=page,
|
||||
page_size=PAGE_SIZE,
|
||||
query_params_string=query_params_string,
|
||||
)
|
||||
except Exception as e:
|
||||
return render_template(
|
||||
"partials/sb_error.html",
|
||||
error_message=str(e),
|
||||
supabase_url=app.config.get("SUPABASE_URL"),
|
||||
)
|
||||
|
||||
@app.route("/sb/faults/<string:f_code>")
|
||||
def sb_fault_detail(f_code: str):
|
||||
try:
|
||||
params = {
|
||||
"select": "f_code,f_code_num,f_name,car_type,f_class,grade,device,fault_detail,fault_reaction,fault_detection,fault_clear,fault_action,fault_schematics,car_id,manufacturer",
|
||||
"f_code": f"eq.{f_code}",
|
||||
"limit": "1",
|
||||
}
|
||||
with build_pg_client() as c:
|
||||
r = c.get("/Fault_Code_Table", params=params)
|
||||
r.raise_for_status()
|
||||
rows = r.json() or []
|
||||
if not rows:
|
||||
abort(404)
|
||||
row = rows[0]
|
||||
return render_template("partials/sb_fault_detail.html", row=row)
|
||||
except Exception as e:
|
||||
return render_template(
|
||||
"partials/sb_error.html",
|
||||
error_message=str(e),
|
||||
supabase_url=app.config.get("SUPABASE_URL"),
|
||||
)
|
||||
|
||||
# ----------------- Signals (TCMS) -----------------
|
||||
@app.route("/sb/signals/list")
|
||||
def sb_signals_list():
|
||||
try:
|
||||
PAGE_SIZE = 50
|
||||
page = int(request.args.get("page", "0"))
|
||||
offset = page * PAGE_SIZE
|
||||
|
||||
manufacturer = request.args.get("manufacturer", "").strip()
|
||||
classification = request.args.get("classification", "").strip()
|
||||
q = request.args.get("q", "").strip()
|
||||
alias_name = request.args.get("alias_name", "").strip()
|
||||
|
||||
params: Dict[str, str] = {
|
||||
"select": "id,sig_num,signal_abbreviation,signal_description,status_value,manufacturer,classification,alias_name",
|
||||
"order": "sig_num.asc",
|
||||
"limit": str(PAGE_SIZE),
|
||||
"offset": str(offset),
|
||||
}
|
||||
if manufacturer:
|
||||
params["manufacturer"] = f"eq.{manufacturer}"
|
||||
if classification:
|
||||
params["classification"] = f"eq.{classification}"
|
||||
if alias_name:
|
||||
params["alias_name"] = f"eq.{alias_name}"
|
||||
if q:
|
||||
params["or"] = f"(signal_abbreviation.ilike.*{q}*,signal_description.ilike.*{q}*)"
|
||||
|
||||
with build_pg_client() as c:
|
||||
rows = []
|
||||
last_error: Exception | None = None
|
||||
for path in ("/Signals", "/signals"):
|
||||
try:
|
||||
r = c.get(path, params=params)
|
||||
r.raise_for_status()
|
||||
rows = r.json() or []
|
||||
last_error = None
|
||||
break
|
||||
except Exception as e:
|
||||
last_error = e
|
||||
rows = []
|
||||
continue
|
||||
if last_error and not rows:
|
||||
raise last_error
|
||||
# TCMS도 group_code=on이면 sig_num/dedup(또는 id?)
|
||||
group_code = request.args.get("group_code", "").strip().lower()
|
||||
if group_code == "on":
|
||||
seen: Dict[str, bool] = {}
|
||||
dedup: List[Dict] = []
|
||||
for r in rows:
|
||||
code = r.get("id")
|
||||
if code and code not in seen:
|
||||
seen[code] = True
|
||||
dedup.append(r)
|
||||
rows = dedup
|
||||
|
||||
query_params = request.args.to_dict()
|
||||
if "page" in query_params:
|
||||
del query_params["page"]
|
||||
query_params_string = urlencode(query_params)
|
||||
|
||||
return render_template(
|
||||
"partials/sb_signal_list.html",
|
||||
rows=rows,
|
||||
page=page,
|
||||
page_size=PAGE_SIZE,
|
||||
query_params_string=query_params_string,
|
||||
)
|
||||
except Exception as e:
|
||||
return render_template(
|
||||
"partials/sb_error.html",
|
||||
error_message=str(e),
|
||||
supabase_url=app.config.get("SUPABASE_URL"),
|
||||
)
|
||||
|
||||
@app.route("/sb/signals/<string:item_id>")
|
||||
def sb_signal_detail(item_id: str):
|
||||
try:
|
||||
params = {
|
||||
"select": "id,sig_num,signal_abbreviation,signal_description,status_value,manufacturer,classification,alias_name,original_data,created_at,updated_at",
|
||||
"id": f"eq.{item_id}",
|
||||
"limit": "1",
|
||||
}
|
||||
with build_pg_client() as c:
|
||||
rows = []
|
||||
last_error: Exception | None = None
|
||||
for path in ("/Signals", "/signals"):
|
||||
try:
|
||||
r = c.get(path, params=params)
|
||||
r.raise_for_status()
|
||||
rows = r.json() or []
|
||||
last_error = None
|
||||
break
|
||||
except Exception as e:
|
||||
last_error = e
|
||||
rows = []
|
||||
continue
|
||||
if last_error and not rows:
|
||||
raise last_error
|
||||
if not rows:
|
||||
abort(404)
|
||||
row = rows[0]
|
||||
return render_template("partials/sb_signal_detail.html", row=row)
|
||||
except Exception as e:
|
||||
return render_template(
|
||||
"partials/sb_error.html",
|
||||
error_message=str(e),
|
||||
supabase_url=app.config.get("SUPABASE_URL"),
|
||||
)
|
||||
|
||||
@app.route("/sb/health")
|
||||
def sb_health():
|
||||
try:
|
||||
with build_pg_client() as c:
|
||||
r = c.get("/Fault_Code_Table", params={"select": "f_code", "limit": "1"})
|
||||
r.raise_for_status()
|
||||
return {"sb": "ok", "url": app.config.get("SUPABASE_URL")}
|
||||
except Exception as e:
|
||||
return {"sb": "error", "url": app.config.get("SUPABASE_URL"), "error": str(e)}
|
||||
|
||||
# 간단한 Signals 테스트 엔드포인트: 상위 5개 레코드를 JSON으로 반환
|
||||
@app.route("/sb/signals/test")
|
||||
def sb_signals_test():
|
||||
try:
|
||||
params = {
|
||||
"select": "uuid,sig_num,signal_abbreviation,manufacturer,classification,alias_name",
|
||||
"order": "sig_num.asc",
|
||||
"limit": "5",
|
||||
}
|
||||
with build_pg_client() as c:
|
||||
rows = []
|
||||
used_path = None
|
||||
last_error = None
|
||||
for path in ("/Signals", "/signals"):
|
||||
try:
|
||||
r = c.get(path, params=params)
|
||||
r.raise_for_status()
|
||||
rows = r.json() or []
|
||||
used_path = path
|
||||
last_error = None
|
||||
break
|
||||
except Exception as e:
|
||||
last_error = str(e)
|
||||
rows = []
|
||||
continue
|
||||
if last_error and not rows:
|
||||
return {"ok": False, "url": app.config.get("SUPABASE_URL"), "tried": ["/Signals", "/signals"], "error": last_error}, 500
|
||||
return {"ok": True, "url": app.config.get("SUPABASE_URL"), "path": used_path, "rows": rows}
|
||||
except Exception as e:
|
||||
return {"ok": False, "url": app.config.get("SUPABASE_URL"), "error": str(e)}, 500
|
||||
|
||||
# 상세 디버그: 두 경로 각각의 상태/본문을 그대로 반환
|
||||
@app.route("/sb/signals/debug")
|
||||
def sb_signals_debug():
|
||||
try:
|
||||
out = []
|
||||
with build_pg_client() as c:
|
||||
for path in ("/Signals", "/signals"):
|
||||
try:
|
||||
r = c.get(path, params={"select": "*", "limit": "5"})
|
||||
ct = r.headers.get("content-type", "")
|
||||
body = None
|
||||
try:
|
||||
body = r.json()
|
||||
except Exception:
|
||||
body = r.text
|
||||
out.append({
|
||||
"path": path,
|
||||
"status": r.status_code,
|
||||
"content_type": ct,
|
||||
"body": body,
|
||||
})
|
||||
except httpx.HTTPError as e:
|
||||
out.append({"path": path, "error": str(e)})
|
||||
return {"ok": True, "url": app.config.get("SUPABASE_URL"), "results": out}
|
||||
except Exception as e:
|
||||
return {"ok": False, "url": app.config.get("SUPABASE_URL"), "error": str(e)}, 500
|
||||
|
||||
return app
|
||||
|
||||
|
||||
app = create_app()
|
||||
if __name__ == "__main__":
|
||||
port = int(os.environ.get("PORT", "5000"))
|
||||
app.run(host="0.0.0.0", port=port, debug=True)
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import groovy.xml.MarkupBuilder
|
||||
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
}
|
||||
|
||||
def twaManifest = [
|
||||
applicationId: 'cc.m1tcloud.tr.twa',
|
||||
hostName: 'tr.m1tcloud.cc', // The domain being opened in the TWA.
|
||||
launchUrl: '/', // The start path for the TWA. Must be relative to the domain.
|
||||
name: 'FaultCode_Line1', // The application name.
|
||||
launcherName: 'F_Code', // The name shown on the Android Launcher.
|
||||
themeColor: '#0F172A', // The color used for the status bar.
|
||||
themeColorDark: '#000000', // The color used for the dark status bar.
|
||||
navigationColor: '#000000', // The color used for the navigation bar.
|
||||
navigationColorDark: '#000000', // The color used for the dark navbar.
|
||||
navigationDividerColor: '#000000', // The navbar divider color.
|
||||
navigationDividerColorDark: '#000000', // The dark navbar divider color.
|
||||
backgroundColor: '#0F172A', // The color used for the splash screen background.
|
||||
enableNotifications: true, // Set to true to enable notification delegation.
|
||||
// Every shortcut must include the following fields:
|
||||
// - name: String that will show up in the shortcut.
|
||||
// - short_name: Shorter string used if |name| is too long.
|
||||
// - url: Absolute path of the URL to launch the app with (e.g '/create').
|
||||
// - icon: Name of the resource in the drawable folder to use as an icon.
|
||||
shortcuts: [],
|
||||
// The duration of fade out animation in milliseconds to be played when removing splash screen.
|
||||
splashScreenFadeOutDuration: 300,
|
||||
generatorApp: 'bubblewrap-cli', // Application that generated the Android Project
|
||||
// The fallback strategy for when Trusted Web Activity is not available. Possible values are
|
||||
// 'customtabs' and 'webview'.
|
||||
fallbackType: 'customtabs',
|
||||
enableSiteSettingsShortcut: 'true',
|
||||
orientation: 'default',
|
||||
]
|
||||
|
||||
android {
|
||||
compileSdkVersion 36
|
||||
namespace "cc.m1tcloud.tr.twa"
|
||||
defaultConfig {
|
||||
applicationId "cc.m1tcloud.tr.twa"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 35
|
||||
versionCode 1
|
||||
versionName "1"
|
||||
|
||||
// The name for the application
|
||||
resValue "string", "appName", twaManifest.name
|
||||
|
||||
// The name for the application on the Android Launcher
|
||||
resValue "string", "launcherName", twaManifest.launcherName
|
||||
|
||||
// The URL that will be used when launching the TWA from the Android Launcher
|
||||
def launchUrl = "https://" + twaManifest.hostName + twaManifest.launchUrl
|
||||
resValue "string", "launchUrl", launchUrl
|
||||
|
||||
|
||||
|
||||
|
||||
// The URL the Web Manifest for the Progressive Web App that the TWA points to. This
|
||||
// is used by Chrome OS and Meta Quest to open the Web version of the PWA instead of
|
||||
// the TWA, as it will probably give a better user experience for non-mobile devices.
|
||||
resValue "string", "webManifestUrl", 'https://tr.m1tcloud.cc/manifest.webmanifest'
|
||||
|
||||
|
||||
|
||||
// This is used by Meta Quest.
|
||||
resValue "string", "fullScopeUrl", 'https://tr.m1tcloud.cc/'
|
||||
|
||||
|
||||
|
||||
|
||||
// The hostname is used when building the intent-filter, so the TWA is able to
|
||||
// handle Intents to open host url of the application.
|
||||
resValue "string", "hostName", twaManifest.hostName
|
||||
|
||||
// This attribute sets the status bar color for the TWA. It can be either set here or in
|
||||
// `res/values/colors.xml`. Setting in both places is an error and the app will not
|
||||
// compile. If not set, the status bar color defaults to #FFFFFF - white.
|
||||
resValue "color", "colorPrimary", twaManifest.themeColor
|
||||
|
||||
// This attribute sets the dark status bar color for the TWA. It can be either set here or in
|
||||
// `res/values/colors.xml`. Setting in both places is an error and the app will not
|
||||
// compile. If not set, the status bar color defaults to #000000 - white.
|
||||
resValue "color", "colorPrimaryDark", twaManifest.themeColorDark
|
||||
|
||||
// This attribute sets the navigation bar color for the TWA. It can be either set here or
|
||||
// in `res/values/colors.xml`. Setting in both places is an error and the app will not
|
||||
// compile. If not set, the navigation bar color defaults to #FFFFFF - white.
|
||||
resValue "color", "navigationColor", twaManifest.navigationColor
|
||||
|
||||
// This attribute sets the dark navigation bar color for the TWA. It can be either set here
|
||||
// or in `res/values/colors.xml`. Setting in both places is an error and the app will not
|
||||
// compile. If not set, the navigation bar color defaults to #000000 - black.
|
||||
resValue "color", "navigationColorDark", twaManifest.navigationColorDark
|
||||
|
||||
// This attribute sets the navbar divider color for the TWA. It can be either
|
||||
// set here or in `res/values/colors.xml`. Setting in both places is an error and the app
|
||||
// will not compile. If not set, the divider color defaults to #00000000 - transparent.
|
||||
resValue "color", "navigationDividerColor", twaManifest.navigationDividerColor
|
||||
|
||||
// This attribute sets the dark navbar divider color for the TWA. It can be either
|
||||
// set here or in `res/values/colors.xml`. Setting in both places is an error and the
|
||||
//app will not compile. If not set, the divider color defaults to #000000 - black.
|
||||
resValue "color", "navigationDividerColorDark", twaManifest.navigationDividerColorDark
|
||||
|
||||
// Sets the color for the background used for the splash screen when launching the
|
||||
// Trusted Web Activity.
|
||||
resValue "color", "backgroundColor", twaManifest.backgroundColor
|
||||
|
||||
// Defines a provider authority for the Splash Screen
|
||||
resValue "string", "providerAuthority", twaManifest.applicationId + '.fileprovider'
|
||||
|
||||
// The enableNotification resource is used to enable or disable the
|
||||
// TrustedWebActivityService, by changing the android:enabled and android:exported
|
||||
// attributes
|
||||
resValue "bool", "enableNotification", twaManifest.enableNotifications.toString()
|
||||
|
||||
twaManifest.shortcuts.eachWithIndex { shortcut, index ->
|
||||
resValue "string", "shortcut_name_$index", "$shortcut.name"
|
||||
resValue "string", "shortcut_short_name_$index", "$shortcut.short_name"
|
||||
}
|
||||
|
||||
// The splashScreenFadeOutDuration resource is used to set the duration of fade out animation in milliseconds
|
||||
// to be played when removing splash screen. The default is 0 (no animation).
|
||||
resValue "integer", "splashScreenFadeOutDuration", twaManifest.splashScreenFadeOutDuration.toString()
|
||||
|
||||
resValue "string", "generatorApp", twaManifest.generatorApp
|
||||
|
||||
resValue "string", "fallbackType", twaManifest.fallbackType
|
||||
|
||||
resValue "bool", "enableSiteSettingsShortcut", twaManifest.enableSiteSettingsShortcut
|
||||
resValue "string", "orientation", twaManifest.orientation
|
||||
|
||||
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
lintOptions {
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
}
|
||||
|
||||
task generateShorcutsFile {
|
||||
assert twaManifest.shortcuts.size() < 5, "You can have at most 4 shortcuts."
|
||||
twaManifest.shortcuts.eachWithIndex { s, i ->
|
||||
assert s.name != null, 'Missing `name` in shortcut #' + i
|
||||
assert s.short_name != null, 'Missing `short_name` in shortcut #' + i
|
||||
assert s.url != null, 'Missing `icon` in shortcut #' + i
|
||||
assert s.icon != null, 'Missing `url` in shortcut #' + i
|
||||
}
|
||||
|
||||
def shortcutsFile = new File("$projectDir/src/main/res/xml", "shortcuts.xml")
|
||||
|
||||
def xmlWriter = new StringWriter()
|
||||
def xmlMarkup = new MarkupBuilder(new IndentPrinter(xmlWriter, " ", true))
|
||||
|
||||
xmlMarkup
|
||||
.'shortcuts'('xmlns:android': 'http://schemas.android.com/apk/res/android') {
|
||||
twaManifest.shortcuts.eachWithIndex { s, i ->
|
||||
'shortcut'(
|
||||
'android:shortcutId': 'shortcut' + i,
|
||||
'android:enabled': 'true',
|
||||
'android:icon': '@drawable/' + s.icon,
|
||||
'android:shortcutShortLabel': '@string/shortcut_short_name_' + i,
|
||||
'android:shortcutLongLabel': '@string/shortcut_name_' + i) {
|
||||
'intent'(
|
||||
'android:action': 'android.intent.action.MAIN',
|
||||
'android:targetPackage': twaManifest.applicationId,
|
||||
'android:targetClass': twaManifest.applicationId + '.LauncherActivity',
|
||||
'android:data': s.url)
|
||||
'categories'('android:name': 'android.intent.category.LAUNCHER')
|
||||
}
|
||||
}
|
||||
}
|
||||
shortcutsFile.text = xmlWriter.toString() + '\n'
|
||||
}
|
||||
|
||||
preBuild.dependsOn(generateShorcutsFile)
|
||||
|
||||
repositories {
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
|
||||
implementation 'com.google.androidbrowserhelper:locationdelegation:1.1.2'
|
||||
|
||||
implementation 'com.google.androidbrowserhelper:androidbrowserhelper:2.6.2'
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
<!--
|
||||
Copyright 2019 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- The "package" attribute is rewritten by the Gradle build with the value of applicationId.
|
||||
It is still required here, as it is used to derive paths, for instance when referring
|
||||
to an Activity by ".MyActivity" instead of the full name. If more Activities are added to the
|
||||
application, the package attribute will need to reflect the correct path in order to use
|
||||
the abbreviated format. -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="cc.m1tcloud.tr.twa">
|
||||
|
||||
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<application
|
||||
android:name="Application"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/appName"
|
||||
|
||||
android:manageSpaceActivity="com.google.androidbrowserhelper.trusted.ManageDataLauncherActivity"
|
||||
|
||||
android:supportsRtl="true"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar">
|
||||
|
||||
<meta-data
|
||||
android:name="asset_statements"
|
||||
android:resource="@string/assetStatements" />
|
||||
|
||||
|
||||
<meta-data
|
||||
android:name="web_manifest_url"
|
||||
android:value="@string/webManifestUrl" />
|
||||
|
||||
|
||||
<meta-data
|
||||
android:name="twa_generator"
|
||||
android:value="@string/generatorApp" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<activity android:name="com.google.androidbrowserhelper.trusted.ManageDataLauncherActivity"
|
||||
android:exported="false"
|
||||
android:enabled="true"
|
||||
android:excludeFromRecents="true">
|
||||
<meta-data
|
||||
android:name="android.support.customtabs.trusted.MANAGE_SPACE_URL"
|
||||
android:value="@string/launchUrl" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
||||
<activity android:name="LauncherActivity"
|
||||
android:alwaysRetainTaskState="true"
|
||||
android:label="@string/launcherName"
|
||||
android:exported="true">
|
||||
<meta-data android:name="android.support.customtabs.trusted.DEFAULT_URL"
|
||||
android:value="@string/launchUrl" />
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.customtabs.trusted.STATUS_BAR_COLOR"
|
||||
android:resource="@color/colorPrimary" />
|
||||
|
||||
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.customtabs.trusted.STATUS_BAR_COLOR_DARK"
|
||||
android:resource="@color/colorPrimaryDark" />
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.customtabs.trusted.NAVIGATION_BAR_COLOR"
|
||||
android:resource="@color/navigationColor" />
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.customtabs.trusted.NAVIGATION_BAR_COLOR_DARK"
|
||||
android:resource="@color/navigationColorDark" />
|
||||
|
||||
<meta-data
|
||||
android:name="androix.browser.trusted.NAVIGATION_BAR_DIVIDER_COLOR"
|
||||
android:resource="@color/navigationDividerColor" />
|
||||
|
||||
<meta-data
|
||||
android:name="androix.browser.trusted.NAVIGATION_BAR_DIVIDER_COLOR_DARK"
|
||||
android:resource="@color/navigationDividerColorDark" />
|
||||
|
||||
<meta-data android:name="android.support.customtabs.trusted.SPLASH_IMAGE_DRAWABLE"
|
||||
android:resource="@drawable/splash"/>
|
||||
|
||||
<meta-data android:name="android.support.customtabs.trusted.SPLASH_SCREEN_BACKGROUND_COLOR"
|
||||
android:resource="@color/backgroundColor"/>
|
||||
|
||||
<meta-data android:name="android.support.customtabs.trusted.SPLASH_SCREEN_FADE_OUT_DURATION"
|
||||
android:value="@integer/splashScreenFadeOutDuration"/>
|
||||
|
||||
<meta-data android:name="android.support.customtabs.trusted.FILE_PROVIDER_AUTHORITY"
|
||||
android:value="@string/providerAuthority"/>
|
||||
|
||||
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" />
|
||||
|
||||
<meta-data android:name="android.support.customtabs.trusted.FALLBACK_STRATEGY"
|
||||
android:value="@string/fallbackType" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<meta-data android:name="android.support.customtabs.trusted.SCREEN_ORIENTATION"
|
||||
android:value="@string/orientation"/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<data android:scheme="https"
|
||||
android:host="@string/hostName"
|
||||
|
||||
/>
|
||||
</intent-filter>
|
||||
|
||||
|
||||
|
||||
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.androidbrowserhelper.trusted.FocusActivity" />
|
||||
|
||||
<activity android:name="com.google.androidbrowserhelper.trusted.WebViewFallbackActivity"
|
||||
android:configChanges="orientation|screenSize" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="@string/providerAuthority"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/filepaths" />
|
||||
</provider>
|
||||
|
||||
<service
|
||||
android:name=".DelegationService"
|
||||
android:enabled="@bool/enableNotification"
|
||||
android:exported="@bool/enableNotification">
|
||||
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.customtabs.trusted.SMALL_ICON"
|
||||
android:resource="@drawable/ic_notification_icon" />
|
||||
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.support.customtabs.trusted.TRUSTED_WEB_ACTIVITY_SERVICE"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
|
||||
<activity android:name="com.google.androidbrowserhelper.trusted.NotificationPermissionRequestActivity" />
|
||||
|
||||
|
||||
|
||||
<activity android:name=
|
||||
"com.google.androidbrowserhelper.locationdelegation.PermissionRequestActivity"/>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cc.m1tcloud.tr.twa;
|
||||
|
||||
|
||||
|
||||
public class Application extends android.app.Application {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package cc.m1tcloud.tr.twa;
|
||||
|
||||
|
||||
import com.google.androidbrowserhelper.locationdelegation.LocationDelegationExtraCommandHandler;
|
||||
|
||||
|
||||
public class DelegationService extends
|
||||
com.google.androidbrowserhelper.trusted.DelegationService {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
|
||||
registerExtraCommandHandler(new LocationDelegationExtraCommandHandler());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cc.m1tcloud.tr.twa;
|
||||
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
|
||||
|
||||
public class LauncherActivity
|
||||
extends com.google.androidbrowserhelper.trusted.LauncherActivity {
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// Setting an orientation crashes the app due to the transparent background on Android 8.0
|
||||
// Oreo and below. We only set the orientation on Oreo and above. This only affects the
|
||||
// splash screen and Chrome will still respect the orientation.
|
||||
// See https://github.com/GoogleChromeLabs/bubblewrap/issues/496 for details.
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
} else {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Uri getLaunchingUrl() {
|
||||
// Get the original launch Url.
|
||||
Uri uri = super.getLaunchingUrl();
|
||||
|
||||
|
||||
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<!--
|
||||
Copyright 2020 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:inset="2dp">
|
||||
<aapt:attr name="android:drawable">
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="@color/shortcut_background" />
|
||||
<size android:width="44dp" android:height="44dp" />
|
||||
</shape>
|
||||
</aapt:attr>
|
||||
</inset>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<!--
|
||||
Copyright 2020 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<color name="shortcut_background">#F5F5F5</color>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2021 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
|
||||
<!--
|
||||
The "fullscreen" and "fullscreen-sticky" TWA manifest values correspond to "immersive" and "sticky-immersive"
|
||||
AndroidManifest values.
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
This variable below expresses the relationship between the app and the site,
|
||||
as documented in the TWA documentation at
|
||||
https://developers.google.com/web/updates/2017/10/using-twa#set_up_digital_asset_links_in_an_android_app
|
||||
and is injected into the AndroidManifest.xml
|
||||
-->
|
||||
<string name="assetStatements">
|
||||
[{
|
||||
\"relation\": [\"delegate_permission/common.handle_all_urls\"],
|
||||
\"target\": {
|
||||
\"namespace\": \"web\",
|
||||
\"site\": \"https://tr.m1tcloud.cc\"
|
||||
}
|
||||
}]
|
||||
|
||||
</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<!--
|
||||
Copyright 2019 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<paths>
|
||||
<files-path path="twa_splash/" name="twa_splash" />
|
||||
</paths>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<!--
|
||||
Copyright 2019 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<shortcuts xmlns:android='http://schemas.android.com/apk/res/android' />
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.9.1'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,14 @@
|
|||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
android.useAndroidX=true
|
||||
Binary file not shown.
|
|
@ -0,0 +1,7 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
Flask==3.0.3
|
||||
itsdangerous>=2.1
|
||||
Jinja2>=3.1
|
||||
Werkzeug>=3.0
|
||||
htmx
|
||||
# htmx==1.9.12 ; python_version>='0' # (note) for reference only, loaded via CDN
|
||||
|
||||
supabase>=2.4.0
|
||||
python-dotenv>=1.0.1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1 @@
|
|||
include ':app'
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 192 KiB |
|
|
@ -0,0 +1,89 @@
|
|||
(function(){
|
||||
// 테마 자동/토글
|
||||
const THEME_KEY = 'theme-preference';
|
||||
const themeToggle = document.getElementById('themeToggle');
|
||||
|
||||
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const getPreferredTheme = () => localStorage.getItem(THEME_KEY) || 'auto';
|
||||
|
||||
const resolveTheme = (pref) => {
|
||||
if (pref === 'dark' || pref === 'light') return pref;
|
||||
return prefersDark && prefersDark.matches ? 'dark' : 'light';
|
||||
};
|
||||
|
||||
const applyTheme = (themePref) => {
|
||||
const theme = resolveTheme(themePref);
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
const meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', theme === 'dark' ? '#0b1220' : '#ffffff');
|
||||
};
|
||||
|
||||
applyTheme(getPreferredTheme());
|
||||
prefersDark && prefersDark.addEventListener('change', () => applyTheme(getPreferredTheme()));
|
||||
|
||||
if (themeToggle) {
|
||||
themeToggle.addEventListener('click', () => {
|
||||
const now = getPreferredTheme();
|
||||
const next = now === 'dark' ? 'light' : now === 'light' ? 'auto' : 'dark';
|
||||
localStorage.setItem(THEME_KEY, next);
|
||||
applyTheme(next);
|
||||
});
|
||||
}
|
||||
|
||||
// htmx modal 지원
|
||||
document.body.addEventListener('htmx:afterSwap', (e) => {
|
||||
if (e.target.id === 'modal') {
|
||||
const dlg = e.target;
|
||||
if (typeof dlg.showModal === 'function') dlg.showModal();
|
||||
}
|
||||
});
|
||||
document.body.addEventListener('click', (e) => {
|
||||
const dlg = document.getElementById('modal');
|
||||
if (dlg && e.target === dlg) {
|
||||
dlg.close();
|
||||
dlg.innerHTML = '';
|
||||
}
|
||||
});
|
||||
|
||||
// 탭 선택 상태 토글 (상단 섹션/서브탭)
|
||||
document.addEventListener('click', (e) => {
|
||||
const sectionTabBtn = e.target.closest('#topSections .tab-button');
|
||||
const topTabBtn = e.target.closest('#tabs .tab-button');
|
||||
const subTabBtn = e.target.closest('#subtabs .tab-button');
|
||||
|
||||
// 상단 섹션 탭: 선택 상태 토글
|
||||
if (sectionTabBtn) {
|
||||
document.querySelectorAll('#topSections .tab-button')
|
||||
.forEach(x => x.setAttribute('aria-selected', 'false'));
|
||||
sectionTabBtn.setAttribute('aria-selected', 'true');
|
||||
}
|
||||
|
||||
// 상단 제조사 탭: 섹션 값 전달 + 선택 상태 토글
|
||||
if (topTabBtn) {
|
||||
const sectionRoot = document.getElementById('currentSectionRoot');
|
||||
if (sectionRoot) topTabBtn.setAttribute('hx-vals', JSON.stringify({ section: sectionRoot.value }));
|
||||
|
||||
document.querySelectorAll('#tabs .tab-button')
|
||||
.forEach(x => x.setAttribute('aria-selected', 'false'));
|
||||
topTabBtn.setAttribute('aria-selected', 'true');
|
||||
}
|
||||
|
||||
// 하위 서브탭: 선택 상태 토글
|
||||
if (subTabBtn) {
|
||||
document.querySelectorAll('#subtabs .tab-button')
|
||||
.forEach(x => x.setAttribute('aria-selected', 'false'));
|
||||
subTabBtn.setAttribute('aria-selected', 'true');
|
||||
}
|
||||
});
|
||||
|
||||
// PWA 등록
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/static/sw.js').catch(()=>{});
|
||||
});
|
||||
}
|
||||
|
||||
// 로컬 SQLite / PWA 동기화 제거됨 (Supabase 직접 조회)
|
||||
})();
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
// OPFS 기반 WebAssembly SQLite (sql.js) 초기화 및 동기화
|
||||
// 가벼운 전체 파일 교체 방식. 향후 Supabase 연동 시 증분 동기화로 확장 가능.
|
||||
|
||||
const DB = (() => {
|
||||
let SQL, db, ready;
|
||||
const OPFS_FILE = 'faults.db';
|
||||
const STORE_KEY = 'db-version';
|
||||
|
||||
async function ensureSqlJs() {
|
||||
if (SQL) return SQL;
|
||||
// sql.js CDN
|
||||
const module = await window.initSqlJs({ locateFile: f => `https://sql.js.org/dist/${f}` });
|
||||
SQL = module;
|
||||
return SQL;
|
||||
}
|
||||
|
||||
async function readFromOpfs() {
|
||||
if (!('storage' in navigator) || !('getDirectory' in navigator.storage)) return null;
|
||||
try {
|
||||
const root = await navigator.storage.getDirectory();
|
||||
const handle = await root.getFileHandle(OPFS_FILE, { create: false }).catch(() => null);
|
||||
if (!handle) return null;
|
||||
const file = await handle.getFile();
|
||||
return new Uint8Array(await file.arrayBuffer());
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
async function writeToOpfs(bytes) {
|
||||
if (!('storage' in navigator) || !('getDirectory' in navigator.storage)) return;
|
||||
const root = await navigator.storage.getDirectory();
|
||||
const handle = await root.getFileHandle(OPFS_FILE, { create: true });
|
||||
const w = await handle.createWritable();
|
||||
await w.write(bytes);
|
||||
await w.close();
|
||||
}
|
||||
|
||||
async function init() {
|
||||
if (ready) return ready;
|
||||
ready = (async () => {
|
||||
await ensureSqlJs();
|
||||
// 1) OPFS에서 기존 DB 로드
|
||||
const bytes = await readFromOpfs();
|
||||
if (bytes) {
|
||||
db = new SQL.Database(bytes);
|
||||
} else {
|
||||
// 없으면 서버에서 부트스트랩 DB 다운로드
|
||||
const buf = await fetch('/api/db').then(r => r.arrayBuffer());
|
||||
db = new SQL.Database(new Uint8Array(buf));
|
||||
await persist();
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
return ready;
|
||||
}
|
||||
|
||||
async function persist() {
|
||||
const data = db.export();
|
||||
await writeToOpfs(data);
|
||||
}
|
||||
|
||||
async function syncIfNeeded() {
|
||||
// 서버 버전 확인 후 다르면 교체
|
||||
try {
|
||||
const remoteMeta = await fetch('/api/meta').then(r => r.json());
|
||||
const localMeta = getLocalMeta();
|
||||
if (!localMeta || Number(remoteMeta.version) > Number(localMeta.version)) {
|
||||
const buf = await fetch('/api/db').then(r => r.arrayBuffer());
|
||||
db = new SQL.Database(new Uint8Array(buf));
|
||||
await persist();
|
||||
setLocalMeta(remoteMeta);
|
||||
return true;
|
||||
}
|
||||
} catch {}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getLocalMeta() {
|
||||
try { return JSON.parse(localStorage.getItem(STORE_KEY)); } catch { return null; }
|
||||
}
|
||||
function setLocalMeta(meta) {
|
||||
localStorage.setItem(STORE_KEY, JSON.stringify(meta));
|
||||
}
|
||||
|
||||
function query(sql, params = []) {
|
||||
const stmt = db.prepare(sql);
|
||||
stmt.bind(params);
|
||||
const rows = [];
|
||||
while (stmt.step()) rows.push(stmt.getAsObject());
|
||||
stmt.free();
|
||||
return rows;
|
||||
}
|
||||
|
||||
return { init, syncIfNeeded, query, persist };
|
||||
})();
|
||||
|
||||
window.DB = DB;
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "1호선 고장코드",
|
||||
"short_name": "고장코드",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#0f172a",
|
||||
"theme_color": "#0f172a",
|
||||
"lang": "ko",
|
||||
"icons": [
|
||||
{"src": "/static/icons/icon-192.png", "sizes": "192x192", "type": "image/png"},
|
||||
{"src": "/static/icons/icon-512.png", "sizes": "512x512", "type": "image/png"}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
|
||||
// We are modularizing this manually because the current modularize setting in Emscripten has some issues:
|
||||
// https://github.com/kripken/emscripten/issues/5820
|
||||
// In addition, When you use emcc's modularization, it still expects to export a global object called `Module`,
|
||||
// which is able to be used/called before the WASM is loaded.
|
||||
// The modularization below exports a promise that loads and resolves to the actual sql.js module.
|
||||
// That way, this module can't be used before the WASM is finished loading.
|
||||
|
||||
// We are going to define a function that a user will call to start loading initializing our Sql.js library
|
||||
// However, that function might be called multiple times, and on subsequent calls, we don't actually want it to instantiate a new instance of the Module
|
||||
// Instead, we want to return the previously loaded module
|
||||
|
||||
// TODO: Make this not declare a global if used in the browser
|
||||
var initSqlJsPromise = undefined;
|
||||
|
||||
var initSqlJs = function (moduleConfig) {
|
||||
|
||||
if (initSqlJsPromise){
|
||||
return initSqlJsPromise;
|
||||
}
|
||||
// If we're here, we've never called this function before
|
||||
initSqlJsPromise = new Promise(function (resolveModule, reject) {
|
||||
|
||||
// We are modularizing this manually because the current modularize setting in Emscripten has some issues:
|
||||
// https://github.com/kripken/emscripten/issues/5820
|
||||
|
||||
// The way to affect the loading of emcc compiled modules is to create a variable called `Module` and add
|
||||
// properties to it, like `preRun`, `postRun`, etc
|
||||
// We are using that to get notified when the WASM has finished loading.
|
||||
// Only then will we return our promise
|
||||
|
||||
// If they passed in a moduleConfig object, use that
|
||||
// Otherwise, initialize Module to the empty object
|
||||
var Module = typeof moduleConfig !== 'undefined' ? moduleConfig : {};
|
||||
|
||||
// EMCC only allows for a single onAbort function (not an array of functions)
|
||||
// So if the user defined their own onAbort function, we remember it and call it
|
||||
var originalOnAbortFunction = Module['onAbort'];
|
||||
Module['onAbort'] = function (errorThatCausedAbort) {
|
||||
reject(new Error(errorThatCausedAbort));
|
||||
if (originalOnAbortFunction){
|
||||
originalOnAbortFunction(errorThatCausedAbort);
|
||||
}
|
||||
};
|
||||
|
||||
Module['postRun'] = Module['postRun'] || [];
|
||||
Module['postRun'].push(function () {
|
||||
// When Emscripted calls postRun, this promise resolves with the built Module
|
||||
resolveModule(Module);
|
||||
});
|
||||
|
||||
// There is a section of code in the emcc-generated code below that looks like this:
|
||||
// (Note that this is lowercase `module`)
|
||||
// if (typeof module !== 'undefined') {
|
||||
// module['exports'] = Module;
|
||||
// }
|
||||
// When that runs, it's going to overwrite our own modularization export efforts in shell-post.js!
|
||||
// The only way to tell emcc not to emit it is to pass the MODULARIZE=1 or MODULARIZE_INSTANCE=1 flags,
|
||||
// but that carries with it additional unnecessary baggage/bugs we don't want either.
|
||||
// So, we have three options:
|
||||
// 1) We undefine `module`
|
||||
// 2) We remember what `module['exports']` was at the beginning of this function and we restore it later
|
||||
// 3) We write a script to remove those lines of code as part of the Make process.
|
||||
//
|
||||
// Since those are the only lines of code that care about module, we will undefine it. It's the most straightforward
|
||||
// of the options, and has the side effect of reducing emcc's efforts to modify the module if its output were to change in the future.
|
||||
// That's a nice side effect since we're handling the modularization efforts ourselves
|
||||
module = undefined;
|
||||
|
||||
// The emcc-generated code and shell-post.js code goes below,
|
||||
// meaning that all of it runs inside of this promise. If anything throws an exception, our promise will abort
|
||||
var f;f||=typeof Module !== 'undefined' ? Module : {};"use strict";
|
||||
f.onRuntimeInitialized=function(){function a(g,l){switch(typeof l){case "boolean":mc(g,l?1:0);break;case "number":nc(g,l);break;case "string":oc(g,l,-1,-1);break;case "object":if(null===l)lb(g);else if(null!=l.length){var n=aa(l,ba);pc(g,n,l.length,-1);ca(n)}else Aa(g,"Wrong API use : tried to return a value of an unknown type ("+l+").",-1);break;default:lb(g)}}function b(g,l){for(var n=[],t=0;t<g;t+=1){var w=m(l+4*t,"i32"),z=qc(w);if(1===z||2===z)w=rc(w);else if(3===z)w=sc(w);else if(4===z){z=w;
|
||||
w=tc(z);z=uc(z);for(var N=new Uint8Array(w),L=0;L<w;L+=1)N[L]=p[z+L];w=N}else w=null;n.push(w)}return n}function c(g,l){this.La=g;this.db=l;this.Ja=1;this.fb=[]}function d(g,l){this.db=l;l=da(g)+1;this.Ya=ea(l);if(null===this.Ya)throw Error("Unable to allocate memory for the SQL string");fa(g,q,this.Ya,l);this.eb=this.Ya;this.Ua=this.ib=null}function e(g){this.filename="dbfile_"+(4294967295*Math.random()>>>0);if(null!=g){var l=this.filename,n="/",t=l;n&&(n="string"==typeof n?n:ha(n),t=l?u(n+"/"+l):
|
||||
n);l=ia(!0,!0);t=ja(t,(void 0!==l?l:438)&4095|32768,0);if(g){if("string"==typeof g){n=Array(g.length);for(var w=0,z=g.length;w<z;++w)n[w]=g.charCodeAt(w);g=n}ka(t,l|146);n=la(t,577);ma(n,g,0,g.length,0);na(n);ka(t,l)}}this.handleError(r(this.filename,h));this.db=m(h,"i32");ob(this.db);this.Za={};this.Na={}}var h=x(4),k=f.cwrap,r=k("sqlite3_open","number",["string","number"]),y=k("sqlite3_close_v2","number",["number"]),v=k("sqlite3_exec","number",["number","string","number","number","number"]),F=k("sqlite3_changes",
|
||||
"number",["number"]),H=k("sqlite3_prepare_v2","number",["number","string","number","number","number"]),pb=k("sqlite3_sql","string",["number"]),vc=k("sqlite3_normalized_sql","string",["number"]),qb=k("sqlite3_prepare_v2","number",["number","number","number","number","number"]),wc=k("sqlite3_bind_text","number",["number","number","number","number","number"]),rb=k("sqlite3_bind_blob","number",["number","number","number","number","number"]),xc=k("sqlite3_bind_double","number",["number","number","number"]),
|
||||
yc=k("sqlite3_bind_int","number",["number","number","number"]),zc=k("sqlite3_bind_parameter_index","number",["number","string"]),Ac=k("sqlite3_step","number",["number"]),Bc=k("sqlite3_errmsg","string",["number"]),Cc=k("sqlite3_column_count","number",["number"]),Dc=k("sqlite3_data_count","number",["number"]),Ec=k("sqlite3_column_double","number",["number","number"]),sb=k("sqlite3_column_text","string",["number","number"]),Fc=k("sqlite3_column_blob","number",["number","number"]),Gc=k("sqlite3_column_bytes",
|
||||
"number",["number","number"]),Hc=k("sqlite3_column_type","number",["number","number"]),Ic=k("sqlite3_column_name","string",["number","number"]),Jc=k("sqlite3_reset","number",["number"]),Kc=k("sqlite3_clear_bindings","number",["number"]),Lc=k("sqlite3_finalize","number",["number"]),tb=k("sqlite3_create_function_v2","number","number string number number number number number number number".split(" ")),qc=k("sqlite3_value_type","number",["number"]),tc=k("sqlite3_value_bytes","number",["number"]),sc=k("sqlite3_value_text",
|
||||
"string",["number"]),uc=k("sqlite3_value_blob","number",["number"]),rc=k("sqlite3_value_double","number",["number"]),nc=k("sqlite3_result_double","",["number","number"]),lb=k("sqlite3_result_null","",["number"]),oc=k("sqlite3_result_text","",["number","string","number","number"]),pc=k("sqlite3_result_blob","",["number","number","number","number"]),mc=k("sqlite3_result_int","",["number","number"]),Aa=k("sqlite3_result_error","",["number","string","number"]),ub=k("sqlite3_aggregate_context","number",
|
||||
["number","number"]),ob=k("RegisterExtensionFunctions","number",["number"]);c.prototype.bind=function(g){if(!this.La)throw"Statement closed";this.reset();return Array.isArray(g)?this.wb(g):null!=g&&"object"===typeof g?this.xb(g):!0};c.prototype.step=function(){if(!this.La)throw"Statement closed";this.Ja=1;var g=Ac(this.La);switch(g){case 100:return!0;case 101:return!1;default:throw this.db.handleError(g);}};c.prototype.rb=function(g){null==g&&(g=this.Ja,this.Ja+=1);return Ec(this.La,g)};c.prototype.Ab=
|
||||
function(g){null==g&&(g=this.Ja,this.Ja+=1);g=sb(this.La,g);if("function"!==typeof BigInt)throw Error("BigInt is not supported");return BigInt(g)};c.prototype.Bb=function(g){null==g&&(g=this.Ja,this.Ja+=1);return sb(this.La,g)};c.prototype.getBlob=function(g){null==g&&(g=this.Ja,this.Ja+=1);var l=Gc(this.La,g);g=Fc(this.La,g);for(var n=new Uint8Array(l),t=0;t<l;t+=1)n[t]=p[g+t];return n};c.prototype.get=function(g,l){l=l||{};null!=g&&this.bind(g)&&this.step();g=[];for(var n=Dc(this.La),t=0;t<n;t+=
|
||||
1)switch(Hc(this.La,t)){case 1:var w=l.useBigInt?this.Ab(t):this.rb(t);g.push(w);break;case 2:g.push(this.rb(t));break;case 3:g.push(this.Bb(t));break;case 4:g.push(this.getBlob(t));break;default:g.push(null)}return g};c.prototype.getColumnNames=function(){for(var g=[],l=Cc(this.La),n=0;n<l;n+=1)g.push(Ic(this.La,n));return g};c.prototype.getAsObject=function(g,l){g=this.get(g,l);l=this.getColumnNames();for(var n={},t=0;t<l.length;t+=1)n[l[t]]=g[t];return n};c.prototype.getSQL=function(){return pb(this.La)};
|
||||
c.prototype.getNormalizedSQL=function(){return vc(this.La)};c.prototype.run=function(g){null!=g&&this.bind(g);this.step();return this.reset()};c.prototype.nb=function(g,l){null==l&&(l=this.Ja,this.Ja+=1);g=oa(g);var n=aa(g,ba);this.fb.push(n);this.db.handleError(wc(this.La,l,n,g.length-1,0))};c.prototype.vb=function(g,l){null==l&&(l=this.Ja,this.Ja+=1);var n=aa(g,ba);this.fb.push(n);this.db.handleError(rb(this.La,l,n,g.length,0))};c.prototype.mb=function(g,l){null==l&&(l=this.Ja,this.Ja+=1);this.db.handleError((g===
|
||||
(g|0)?yc:xc)(this.La,l,g))};c.prototype.yb=function(g){null==g&&(g=this.Ja,this.Ja+=1);rb(this.La,g,0,0,0)};c.prototype.ob=function(g,l){null==l&&(l=this.Ja,this.Ja+=1);switch(typeof g){case "string":this.nb(g,l);return;case "number":this.mb(g,l);return;case "bigint":this.nb(g.toString(),l);return;case "boolean":this.mb(g+0,l);return;case "object":if(null===g){this.yb(l);return}if(null!=g.length){this.vb(g,l);return}}throw"Wrong API use : tried to bind a value of an unknown type ("+g+").";};c.prototype.xb=
|
||||
function(g){var l=this;Object.keys(g).forEach(function(n){var t=zc(l.La,n);0!==t&&l.ob(g[n],t)});return!0};c.prototype.wb=function(g){for(var l=0;l<g.length;l+=1)this.ob(g[l],l+1);return!0};c.prototype.reset=function(){this.freemem();return 0===Kc(this.La)&&0===Jc(this.La)};c.prototype.freemem=function(){for(var g;void 0!==(g=this.fb.pop());)ca(g)};c.prototype.free=function(){this.freemem();var g=0===Lc(this.La);delete this.db.Za[this.La];this.La=0;return g};d.prototype.next=function(){if(null===
|
||||
this.Ya)return{done:!0};null!==this.Ua&&(this.Ua.free(),this.Ua=null);if(!this.db.db)throw this.gb(),Error("Database closed");var g=pa(),l=x(4);qa(h);qa(l);try{this.db.handleError(qb(this.db.db,this.eb,-1,h,l));this.eb=m(l,"i32");var n=m(h,"i32");if(0===n)return this.gb(),{done:!0};this.Ua=new c(n,this.db);this.db.Za[n]=this.Ua;return{value:this.Ua,done:!1}}catch(t){throw this.ib=ra(this.eb),this.gb(),t;}finally{sa(g)}};d.prototype.gb=function(){ca(this.Ya);this.Ya=null};d.prototype.getRemainingSQL=
|
||||
function(){return null!==this.ib?this.ib:ra(this.eb)};"function"===typeof Symbol&&"symbol"===typeof Symbol.iterator&&(d.prototype[Symbol.iterator]=function(){return this});e.prototype.run=function(g,l){if(!this.db)throw"Database closed";if(l){g=this.prepare(g,l);try{g.step()}finally{g.free()}}else this.handleError(v(this.db,g,0,0,h));return this};e.prototype.exec=function(g,l,n){if(!this.db)throw"Database closed";var t=pa(),w=null;try{var z=ta(g),N=x(4);for(g=[];0!==m(z,"i8");){qa(h);qa(N);this.handleError(qb(this.db,
|
||||
z,-1,h,N));var L=m(h,"i32");z=m(N,"i32");if(0!==L){var K=null;w=new c(L,this);for(null!=l&&w.bind(l);w.step();)null===K&&(K={columns:w.getColumnNames(),values:[]},g.push(K)),K.values.push(w.get(null,n));w.free()}}return g}catch(O){throw w&&w.free(),O;}finally{sa(t)}};e.prototype.each=function(g,l,n,t,w){"function"===typeof l&&(t=n,n=l,l=void 0);g=this.prepare(g,l);try{for(;g.step();)n(g.getAsObject(null,w))}finally{g.free()}if("function"===typeof t)return t()};e.prototype.prepare=function(g,l){qa(h);
|
||||
this.handleError(H(this.db,g,-1,h,0));g=m(h,"i32");if(0===g)throw"Nothing to prepare";var n=new c(g,this);null!=l&&n.bind(l);return this.Za[g]=n};e.prototype.iterateStatements=function(g){return new d(g,this)};e.prototype["export"]=function(){Object.values(this.Za).forEach(function(l){l.free()});Object.values(this.Na).forEach(ua);this.Na={};this.handleError(y(this.db));var g=va(this.filename);this.handleError(r(this.filename,h));this.db=m(h,"i32");ob(this.db);return g};e.prototype.close=function(){null!==
|
||||
this.db&&(Object.values(this.Za).forEach(function(g){g.free()}),Object.values(this.Na).forEach(ua),this.Na={},this.handleError(y(this.db)),wa("/"+this.filename),this.db=null)};e.prototype.handleError=function(g){if(0===g)return null;g=Bc(this.db);throw Error(g);};e.prototype.getRowsModified=function(){return F(this.db)};e.prototype.create_function=function(g,l){Object.prototype.hasOwnProperty.call(this.Na,g)&&(ua(this.Na[g]),delete this.Na[g]);var n=xa(function(t,w,z){w=b(w,z);try{var N=l.apply(null,
|
||||
w)}catch(L){Aa(t,L,-1);return}a(t,N)},"viii");this.Na[g]=n;this.handleError(tb(this.db,g,l.length,1,0,n,0,0,0));return this};e.prototype.create_aggregate=function(g,l){var n=l.init||function(){return null},t=l.finalize||function(K){return K},w=l.step;if(!w)throw"An aggregate function must have a step function in "+g;var z={};Object.hasOwnProperty.call(this.Na,g)&&(ua(this.Na[g]),delete this.Na[g]);l=g+"__finalize";Object.hasOwnProperty.call(this.Na,l)&&(ua(this.Na[l]),delete this.Na[l]);var N=xa(function(K,
|
||||
O,Ua){var X=ub(K,1);Object.hasOwnProperty.call(z,X)||(z[X]=n());O=b(O,Ua);O=[z[X]].concat(O);try{z[X]=w.apply(null,O)}catch(Nc){delete z[X],Aa(K,Nc,-1)}},"viii"),L=xa(function(K){var O=ub(K,1);try{var Ua=t(z[O])}catch(X){delete z[O];Aa(K,X,-1);return}a(K,Ua);delete z[O]},"vi");this.Na[g]=N;this.Na[l]=L;this.handleError(tb(this.db,g,w.length-1,1,0,0,N,L,0));return this};f.Database=e};
|
||||
var ya=Object.assign({},f),za="./this.program",Ba="object"==typeof window,Ca="function"==typeof importScripts,Da="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,A="",Ea,Fa,Ga;
|
||||
if(Da){var fs=require("fs"),Ha=require("path");A=Ca?Ha.dirname(A)+"/":__dirname+"/";Ea=(a,b)=>{a=Ia(a)?new URL(a):Ha.normalize(a);return fs.readFileSync(a,b?void 0:"utf8")};Ga=a=>{a=Ea(a,!0);a.buffer||(a=new Uint8Array(a));return a};Fa=(a,b,c,d=!0)=>{a=Ia(a)?new URL(a):Ha.normalize(a);fs.readFile(a,d?void 0:"utf8",(e,h)=>{e?c(e):b(d?h.buffer:h)})};!f.thisProgram&&1<process.argv.length&&(za=process.argv[1].replace(/\\/g,"/"));process.argv.slice(2);"undefined"!=typeof module&&(module.exports=f);f.inspect=
|
||||
()=>"[Emscripten Module object]"}else if(Ba||Ca)Ca?A=self.location.href:"undefined"!=typeof document&&document.currentScript&&(A=document.currentScript.src),A=0!==A.indexOf("blob:")?A.substr(0,A.replace(/[?#].*/,"").lastIndexOf("/")+1):"",Ea=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.send(null);return b.responseText},Ca&&(Ga=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),Fa=(a,b,c)=>{var d=new XMLHttpRequest;d.open("GET",
|
||||
a,!0);d.responseType="arraybuffer";d.onload=()=>{200==d.status||0==d.status&&d.response?b(d.response):c()};d.onerror=c;d.send(null)};var Ja=f.print||console.log.bind(console),B=f.printErr||console.error.bind(console);Object.assign(f,ya);ya=null;f.thisProgram&&(za=f.thisProgram);var Ka;f.wasmBinary&&(Ka=f.wasmBinary);"object"!=typeof WebAssembly&&C("no native wasm support detected");var La,Ma=!1,p,q,Na,D,E,Oa,Pa;
|
||||
function Qa(){var a=La.buffer;f.HEAP8=p=new Int8Array(a);f.HEAP16=Na=new Int16Array(a);f.HEAPU8=q=new Uint8Array(a);f.HEAPU16=new Uint16Array(a);f.HEAP32=D=new Int32Array(a);f.HEAPU32=E=new Uint32Array(a);f.HEAPF32=Oa=new Float32Array(a);f.HEAPF64=Pa=new Float64Array(a)}var Ra=[],Sa=[],Ta=[];function Va(){var a=f.preRun.shift();Ra.unshift(a)}var G=0,Wa=null,Xa=null;
|
||||
function C(a){f.onAbort?.(a);a="Aborted("+a+")";B(a);Ma=!0;throw new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");}var Ya=a=>a.startsWith("data:application/octet-stream;base64,"),Ia=a=>a.startsWith("file://"),Za;Za="sql-wasm.wasm";if(!Ya(Za)){var $a=Za;Za=f.locateFile?f.locateFile($a,A):A+$a}function ab(a){if(a==Za&&Ka)return new Uint8Array(Ka);if(Ga)return Ga(a);throw"both async and sync fetching of the wasm failed";}
|
||||
function bb(a){if(!Ka&&(Ba||Ca)){if("function"==typeof fetch&&!Ia(a))return fetch(a,{credentials:"same-origin"}).then(b=>{if(!b.ok)throw"failed to load wasm binary file at '"+a+"'";return b.arrayBuffer()}).catch(()=>ab(a));if(Fa)return new Promise((b,c)=>{Fa(a,d=>b(new Uint8Array(d)),c)})}return Promise.resolve().then(()=>ab(a))}function cb(a,b,c){return bb(a).then(d=>WebAssembly.instantiate(d,b)).then(d=>d).then(c,d=>{B(`failed to asynchronously prepare wasm: ${d}`);C(d)})}
|
||||
function db(a,b){var c=Za;Ka||"function"!=typeof WebAssembly.instantiateStreaming||Ya(c)||Ia(c)||Da||"function"!=typeof fetch?cb(c,a,b):fetch(c,{credentials:"same-origin"}).then(d=>WebAssembly.instantiateStreaming(d,a).then(b,function(e){B(`wasm streaming compile failed: ${e}`);B("falling back to ArrayBuffer instantiation");return cb(c,a,b)}))}var I,J,eb=a=>{for(;0<a.length;)a.shift()(f)};
|
||||
function m(a,b="i8"){b.endsWith("*")&&(b="*");switch(b){case "i1":return p[a>>0];case "i8":return p[a>>0];case "i16":return Na[a>>1];case "i32":return D[a>>2];case "i64":C("to do getValue(i64) use WASM_BIGINT");case "float":return Oa[a>>2];case "double":return Pa[a>>3];case "*":return E[a>>2];default:C(`invalid type for getValue: ${b}`)}}
|
||||
function qa(a){var b="i32";b.endsWith("*")&&(b="*");switch(b){case "i1":p[a>>0]=0;break;case "i8":p[a>>0]=0;break;case "i16":Na[a>>1]=0;break;case "i32":D[a>>2]=0;break;case "i64":C("to do setValue(i64) use WASM_BIGINT");case "float":Oa[a>>2]=0;break;case "double":Pa[a>>3]=0;break;case "*":E[a>>2]=0;break;default:C(`invalid type for setValue: ${b}`)}}
|
||||
var fb="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0,M=(a,b,c)=>{var d=b+c;for(c=b;a[c]&&!(c>=d);)++c;if(16<c-b&&a.buffer&&fb)return fb.decode(a.subarray(b,c));for(d="";b<c;){var e=a[b++];if(e&128){var h=a[b++]&63;if(192==(e&224))d+=String.fromCharCode((e&31)<<6|h);else{var k=a[b++]&63;e=224==(e&240)?(e&15)<<12|h<<6|k:(e&7)<<18|h<<12|k<<6|a[b++]&63;65536>e?d+=String.fromCharCode(e):(e-=65536,d+=String.fromCharCode(55296|e>>10,56320|e&1023))}}else d+=String.fromCharCode(e)}return d},
|
||||
ra=(a,b)=>a?M(q,a,b):"",gb=(a,b)=>{for(var c=0,d=a.length-1;0<=d;d--){var e=a[d];"."===e?a.splice(d,1):".."===e?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c;c--)a.unshift("..");return a},u=a=>{var b="/"===a.charAt(0),c="/"===a.substr(-1);(a=gb(a.split("/").filter(d=>!!d),!b).join("/"))||b||(a=".");a&&c&&(a+="/");return(b?"/":"")+a},hb=a=>{var b=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(a).slice(1);a=b[0];b=b[1];if(!a&&!b)return".";b&&=b.substr(0,b.length-1);return a+
|
||||
b},ib=a=>{if("/"===a)return"/";a=u(a);a=a.replace(/\/$/,"");var b=a.lastIndexOf("/");return-1===b?a:a.substr(b+1)},jb=()=>{if("object"==typeof crypto&&"function"==typeof crypto.getRandomValues)return c=>crypto.getRandomValues(c);if(Da)try{var a=require("crypto");if(a.randomFillSync)return c=>a.randomFillSync(c);var b=a.randomBytes;return c=>(c.set(b(c.byteLength)),c)}catch(c){}C("initRandomDevice")},kb=a=>(kb=jb())(a);
|
||||
function mb(){for(var a="",b=!1,c=arguments.length-1;-1<=c&&!b;c--){b=0<=c?arguments[c]:"/";if("string"!=typeof b)throw new TypeError("Arguments to path.resolve must be strings");if(!b)return"";a=b+"/"+a;b="/"===b.charAt(0)}a=gb(a.split("/").filter(d=>!!d),!b).join("/");return(b?"/":"")+a||"."}
|
||||
var nb=[],da=a=>{for(var b=0,c=0;c<a.length;++c){var d=a.charCodeAt(c);127>=d?b++:2047>=d?b+=2:55296<=d&&57343>=d?(b+=4,++c):b+=3}return b},fa=(a,b,c,d)=>{if(!(0<d))return 0;var e=c;d=c+d-1;for(var h=0;h<a.length;++h){var k=a.charCodeAt(h);if(55296<=k&&57343>=k){var r=a.charCodeAt(++h);k=65536+((k&1023)<<10)|r&1023}if(127>=k){if(c>=d)break;b[c++]=k}else{if(2047>=k){if(c+1>=d)break;b[c++]=192|k>>6}else{if(65535>=k){if(c+2>=d)break;b[c++]=224|k>>12}else{if(c+3>=d)break;b[c++]=240|k>>18;b[c++]=128|k>>
|
||||
12&63}b[c++]=128|k>>6&63}b[c++]=128|k&63}}b[c]=0;return c-e};function oa(a,b){var c=Array(da(a)+1);a=fa(a,c,0,c.length);b&&(c.length=a);return c}var vb=[];function wb(a,b){vb[a]={input:[],output:[],Xa:b};xb(a,yb)}
|
||||
var yb={open(a){var b=vb[a.node.rdev];if(!b)throw new P(43);a.tty=b;a.seekable=!1},close(a){a.tty.Xa.fsync(a.tty)},fsync(a){a.tty.Xa.fsync(a.tty)},read(a,b,c,d){if(!a.tty||!a.tty.Xa.sb)throw new P(60);for(var e=0,h=0;h<d;h++){try{var k=a.tty.Xa.sb(a.tty)}catch(r){throw new P(29);}if(void 0===k&&0===e)throw new P(6);if(null===k||void 0===k)break;e++;b[c+h]=k}e&&(a.node.timestamp=Date.now());return e},write(a,b,c,d){if(!a.tty||!a.tty.Xa.jb)throw new P(60);try{for(var e=0;e<d;e++)a.tty.Xa.jb(a.tty,b[c+
|
||||
e])}catch(h){throw new P(29);}d&&(a.node.timestamp=Date.now());return e}},zb={sb(){a:{if(!nb.length){var a=null;if(Da){var b=Buffer.alloc(256),c=0,d=process.stdin.fd;try{c=fs.readSync(d,b)}catch(e){if(e.toString().includes("EOF"))c=0;else throw e;}0<c?a=b.slice(0,c).toString("utf-8"):a=null}else"undefined"!=typeof window&&"function"==typeof window.prompt?(a=window.prompt("Input: "),null!==a&&(a+="\n")):"function"==typeof readline&&(a=readline(),null!==a&&(a+="\n"));if(!a){a=null;break a}nb=oa(a,!0)}a=
|
||||
nb.shift()}return a},jb(a,b){null===b||10===b?(Ja(M(a.output,0)),a.output=[]):0!=b&&a.output.push(b)},fsync(a){a.output&&0<a.output.length&&(Ja(M(a.output,0)),a.output=[])},Mb(){return{Ib:25856,Kb:5,Hb:191,Jb:35387,Gb:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},Nb(){return 0},Ob(){return[24,80]}},Ab={jb(a,b){null===b||10===b?(B(M(a.output,0)),a.output=[]):0!=b&&a.output.push(b)},fsync(a){a.output&&0<a.output.length&&(B(M(a.output,0)),a.output=[])}};
|
||||
function Bb(a,b){var c=a.Ia?a.Ia.length:0;c>=b||(b=Math.max(b,c*(1048576>c?2:1.125)>>>0),0!=c&&(b=Math.max(b,256)),c=a.Ia,a.Ia=new Uint8Array(b),0<a.Ma&&a.Ia.set(c.subarray(0,a.Ma),0))}
|
||||
var Q={Qa:null,Ra(){return Q.createNode(null,"/",16895,0)},createNode(a,b,c,d){if(24576===(c&61440)||4096===(c&61440))throw new P(63);Q.Qa||(Q.Qa={dir:{node:{Pa:Q.Ga.Pa,Oa:Q.Ga.Oa,lookup:Q.Ga.lookup,ab:Q.Ga.ab,rename:Q.Ga.rename,unlink:Q.Ga.unlink,rmdir:Q.Ga.rmdir,readdir:Q.Ga.readdir,symlink:Q.Ga.symlink},stream:{Ta:Q.Ha.Ta}},file:{node:{Pa:Q.Ga.Pa,Oa:Q.Ga.Oa},stream:{Ta:Q.Ha.Ta,read:Q.Ha.read,write:Q.Ha.write,lb:Q.Ha.lb,bb:Q.Ha.bb,cb:Q.Ha.cb}},link:{node:{Pa:Q.Ga.Pa,Oa:Q.Ga.Oa,readlink:Q.Ga.readlink},
|
||||
stream:{}},pb:{node:{Pa:Q.Ga.Pa,Oa:Q.Ga.Oa},stream:Cb}});c=Db(a,b,c,d);R(c.mode)?(c.Ga=Q.Qa.dir.node,c.Ha=Q.Qa.dir.stream,c.Ia={}):32768===(c.mode&61440)?(c.Ga=Q.Qa.file.node,c.Ha=Q.Qa.file.stream,c.Ma=0,c.Ia=null):40960===(c.mode&61440)?(c.Ga=Q.Qa.link.node,c.Ha=Q.Qa.link.stream):8192===(c.mode&61440)&&(c.Ga=Q.Qa.pb.node,c.Ha=Q.Qa.pb.stream);c.timestamp=Date.now();a&&(a.Ia[b]=c,a.timestamp=c.timestamp);return c},Lb(a){return a.Ia?a.Ia.subarray?a.Ia.subarray(0,a.Ma):new Uint8Array(a.Ia):new Uint8Array(0)},
|
||||
Ga:{Pa(a){var b={};b.dev=8192===(a.mode&61440)?a.id:1;b.ino=a.id;b.mode=a.mode;b.nlink=1;b.uid=0;b.gid=0;b.rdev=a.rdev;R(a.mode)?b.size=4096:32768===(a.mode&61440)?b.size=a.Ma:40960===(a.mode&61440)?b.size=a.link.length:b.size=0;b.atime=new Date(a.timestamp);b.mtime=new Date(a.timestamp);b.ctime=new Date(a.timestamp);b.zb=4096;b.blocks=Math.ceil(b.size/b.zb);return b},Oa(a,b){void 0!==b.mode&&(a.mode=b.mode);void 0!==b.timestamp&&(a.timestamp=b.timestamp);if(void 0!==b.size&&(b=b.size,a.Ma!=b))if(0==
|
||||
b)a.Ia=null,a.Ma=0;else{var c=a.Ia;a.Ia=new Uint8Array(b);c&&a.Ia.set(c.subarray(0,Math.min(b,a.Ma)));a.Ma=b}},lookup(){throw Eb[44];},ab(a,b,c,d){return Q.createNode(a,b,c,d)},rename(a,b,c){if(R(a.mode)){try{var d=Fb(b,c)}catch(h){}if(d)for(var e in d.Ia)throw new P(55);}delete a.parent.Ia[a.name];a.parent.timestamp=Date.now();a.name=c;b.Ia[c]=a;b.timestamp=a.parent.timestamp;a.parent=b},unlink(a,b){delete a.Ia[b];a.timestamp=Date.now()},rmdir(a,b){var c=Fb(a,b),d;for(d in c.Ia)throw new P(55);delete a.Ia[b];
|
||||
a.timestamp=Date.now()},readdir(a){var b=[".",".."],c;for(c of Object.keys(a.Ia))b.push(c);return b},symlink(a,b,c){a=Q.createNode(a,b,41471,0);a.link=c;return a},readlink(a){if(40960!==(a.mode&61440))throw new P(28);return a.link}},Ha:{read(a,b,c,d,e){var h=a.node.Ia;if(e>=a.node.Ma)return 0;a=Math.min(a.node.Ma-e,d);if(8<a&&h.subarray)b.set(h.subarray(e,e+a),c);else for(d=0;d<a;d++)b[c+d]=h[e+d];return a},write(a,b,c,d,e,h){b.buffer===p.buffer&&(h=!1);if(!d)return 0;a=a.node;a.timestamp=Date.now();
|
||||
if(b.subarray&&(!a.Ia||a.Ia.subarray)){if(h)return a.Ia=b.subarray(c,c+d),a.Ma=d;if(0===a.Ma&&0===e)return a.Ia=b.slice(c,c+d),a.Ma=d;if(e+d<=a.Ma)return a.Ia.set(b.subarray(c,c+d),e),d}Bb(a,e+d);if(a.Ia.subarray&&b.subarray)a.Ia.set(b.subarray(c,c+d),e);else for(h=0;h<d;h++)a.Ia[e+h]=b[c+h];a.Ma=Math.max(a.Ma,e+d);return d},Ta(a,b,c){1===c?b+=a.position:2===c&&32768===(a.node.mode&61440)&&(b+=a.node.Ma);if(0>b)throw new P(28);return b},lb(a,b,c){Bb(a.node,b+c);a.node.Ma=Math.max(a.node.Ma,b+c)},
|
||||
bb(a,b,c,d,e){if(32768!==(a.node.mode&61440))throw new P(43);a=a.node.Ia;if(e&2||a.buffer!==p.buffer){if(0<c||c+b<a.length)a.subarray?a=a.subarray(c,c+b):a=Array.prototype.slice.call(a,c,c+b);c=!0;b=65536*Math.ceil(b/65536);(e=Gb(65536,b))?(q.fill(0,e,e+b),b=e):b=0;if(!b)throw new P(48);p.set(a,b)}else c=!1,b=a.byteOffset;return{Db:b,ub:c}},cb(a,b,c,d){Q.Ha.write(a,b,0,d,c,!1);return 0}}},ia=(a,b)=>{var c=0;a&&(c|=365);b&&(c|=146);return c},Hb=null,Ib={},Jb=[],Kb=1,S=null,Lb=!0,P=null,Eb={};
|
||||
function T(a,b={}){a=mb(a);if(!a)return{path:"",node:null};b=Object.assign({qb:!0,kb:0},b);if(8<b.kb)throw new P(32);a=a.split("/").filter(k=>!!k);for(var c=Hb,d="/",e=0;e<a.length;e++){var h=e===a.length-1;if(h&&b.parent)break;c=Fb(c,a[e]);d=u(d+"/"+a[e]);c.Va&&(!h||h&&b.qb)&&(c=c.Va.root);if(!h||b.Sa)for(h=0;40960===(c.mode&61440);)if(c=Mb(d),d=mb(hb(d),c),c=T(d,{kb:b.kb+1}).node,40<h++)throw new P(32);}return{path:d,node:c}}
|
||||
function ha(a){for(var b;;){if(a===a.parent)return a=a.Ra.tb,b?"/"!==a[a.length-1]?`${a}/${b}`:a+b:a;b=b?`${a.name}/${b}`:a.name;a=a.parent}}function Nb(a,b){for(var c=0,d=0;d<b.length;d++)c=(c<<5)-c+b.charCodeAt(d)|0;return(a+c>>>0)%S.length}function Ob(a){var b=Nb(a.parent.id,a.name);if(S[b]===a)S[b]=a.Wa;else for(b=S[b];b;){if(b.Wa===a){b.Wa=a.Wa;break}b=b.Wa}}
|
||||
function Fb(a,b){var c;if(c=(c=Pb(a,"x"))?c:a.Ga.lookup?0:2)throw new P(c,a);for(c=S[Nb(a.id,b)];c;c=c.Wa){var d=c.name;if(c.parent.id===a.id&&d===b)return c}return a.Ga.lookup(a,b)}function Db(a,b,c,d){a=new Qb(a,b,c,d);b=Nb(a.parent.id,a.name);a.Wa=S[b];return S[b]=a}function R(a){return 16384===(a&61440)}function Rb(a){var b=["r","w","rw"][a&3];a&512&&(b+="w");return b}
|
||||
function Pb(a,b){if(Lb)return 0;if(!b.includes("r")||a.mode&292){if(b.includes("w")&&!(a.mode&146)||b.includes("x")&&!(a.mode&73))return 2}else return 2;return 0}function Sb(a,b){try{return Fb(a,b),20}catch(c){}return Pb(a,"wx")}function Tb(a,b,c){try{var d=Fb(a,b)}catch(e){return e.Ka}if(a=Pb(a,"wx"))return a;if(c){if(!R(d.mode))return 54;if(d===d.parent||"/"===ha(d))return 10}else if(R(d.mode))return 31;return 0}function Ub(){for(var a=0;4096>=a;a++)if(!Jb[a])return a;throw new P(33);}
|
||||
function U(a){a=Jb[a];if(!a)throw new P(8);return a}function Vb(a,b=-1){Wb||(Wb=function(){this.$a={}},Wb.prototype={},Object.defineProperties(Wb.prototype,{object:{get(){return this.node},set(c){this.node=c}},flags:{get(){return this.$a.flags},set(c){this.$a.flags=c}},position:{get(){return this.$a.position},set(c){this.$a.position=c}}}));a=Object.assign(new Wb,a);-1==b&&(b=Ub());a.fd=b;return Jb[b]=a}var Cb={open(a){a.Ha=Ib[a.node.rdev].Ha;a.Ha.open?.(a)},Ta(){throw new P(70);}};
|
||||
function xb(a,b){Ib[a]={Ha:b}}function Xb(a,b){var c="/"===b,d=!b;if(c&&Hb)throw new P(10);if(!c&&!d){var e=T(b,{qb:!1});b=e.path;e=e.node;if(e.Va)throw new P(10);if(!R(e.mode))throw new P(54);}b={type:a,Pb:{},tb:b,Cb:[]};a=a.Ra(b);a.Ra=b;b.root=a;c?Hb=a:e&&(e.Va=b,e.Ra&&e.Ra.Cb.push(b))}function ja(a,b,c){var d=T(a,{parent:!0}).node;a=ib(a);if(!a||"."===a||".."===a)throw new P(28);var e=Sb(d,a);if(e)throw new P(e);if(!d.Ga.ab)throw new P(63);return d.Ga.ab(d,a,b,c)}
|
||||
function V(a,b){return ja(a,(void 0!==b?b:511)&1023|16384,0)}function Yb(a,b,c){"undefined"==typeof c&&(c=b,b=438);ja(a,b|8192,c)}function Zb(a,b){if(!mb(a))throw new P(44);var c=T(b,{parent:!0}).node;if(!c)throw new P(44);b=ib(b);var d=Sb(c,b);if(d)throw new P(d);if(!c.Ga.symlink)throw new P(63);c.Ga.symlink(c,b,a)}function $b(a){var b=T(a,{parent:!0}).node;a=ib(a);var c=Fb(b,a),d=Tb(b,a,!0);if(d)throw new P(d);if(!b.Ga.rmdir)throw new P(63);if(c.Va)throw new P(10);b.Ga.rmdir(b,a);Ob(c)}
|
||||
function wa(a){var b=T(a,{parent:!0}).node;if(!b)throw new P(44);a=ib(a);var c=Fb(b,a),d=Tb(b,a,!1);if(d)throw new P(d);if(!b.Ga.unlink)throw new P(63);if(c.Va)throw new P(10);b.Ga.unlink(b,a);Ob(c)}function Mb(a){a=T(a).node;if(!a)throw new P(44);if(!a.Ga.readlink)throw new P(28);return mb(ha(a.parent),a.Ga.readlink(a))}function ac(a,b){a=T(a,{Sa:!b}).node;if(!a)throw new P(44);if(!a.Ga.Pa)throw new P(63);return a.Ga.Pa(a)}function bc(a){return ac(a,!0)}
|
||||
function ka(a,b){a="string"==typeof a?T(a,{Sa:!0}).node:a;if(!a.Ga.Oa)throw new P(63);a.Ga.Oa(a,{mode:b&4095|a.mode&-4096,timestamp:Date.now()})}function cc(a,b){if(0>b)throw new P(28);a="string"==typeof a?T(a,{Sa:!0}).node:a;if(!a.Ga.Oa)throw new P(63);if(R(a.mode))throw new P(31);if(32768!==(a.mode&61440))throw new P(28);var c=Pb(a,"w");if(c)throw new P(c);a.Ga.Oa(a,{size:b,timestamp:Date.now()})}
|
||||
function la(a,b,c){if(""===a)throw new P(44);if("string"==typeof b){var d={r:0,"r+":2,w:577,"w+":578,a:1089,"a+":1090}[b];if("undefined"==typeof d)throw Error(`Unknown file open mode: ${b}`);b=d}c=b&64?("undefined"==typeof c?438:c)&4095|32768:0;if("object"==typeof a)var e=a;else{a=u(a);try{e=T(a,{Sa:!(b&131072)}).node}catch(h){}}d=!1;if(b&64)if(e){if(b&128)throw new P(20);}else e=ja(a,c,0),d=!0;if(!e)throw new P(44);8192===(e.mode&61440)&&(b&=-513);if(b&65536&&!R(e.mode))throw new P(54);if(!d&&(c=
|
||||
e?40960===(e.mode&61440)?32:R(e.mode)&&("r"!==Rb(b)||b&512)?31:Pb(e,Rb(b)):44))throw new P(c);b&512&&!d&&cc(e,0);b&=-131713;e=Vb({node:e,path:ha(e),flags:b,seekable:!0,position:0,Ha:e.Ha,Fb:[],error:!1});e.Ha.open&&e.Ha.open(e);!f.logReadFiles||b&1||(dc||={},a in dc||(dc[a]=1));return e}function na(a){if(null===a.fd)throw new P(8);a.hb&&(a.hb=null);try{a.Ha.close&&a.Ha.close(a)}catch(b){throw b;}finally{Jb[a.fd]=null}a.fd=null}
|
||||
function ec(a,b,c){if(null===a.fd)throw new P(8);if(!a.seekable||!a.Ha.Ta)throw new P(70);if(0!=c&&1!=c&&2!=c)throw new P(28);a.position=a.Ha.Ta(a,b,c);a.Fb=[]}function fc(a,b,c,d,e){if(0>d||0>e)throw new P(28);if(null===a.fd)throw new P(8);if(1===(a.flags&2097155))throw new P(8);if(R(a.node.mode))throw new P(31);if(!a.Ha.read)throw new P(28);var h="undefined"!=typeof e;if(!h)e=a.position;else if(!a.seekable)throw new P(70);b=a.Ha.read(a,b,c,d,e);h||(a.position+=b);return b}
|
||||
function ma(a,b,c,d,e){if(0>d||0>e)throw new P(28);if(null===a.fd)throw new P(8);if(0===(a.flags&2097155))throw new P(8);if(R(a.node.mode))throw new P(31);if(!a.Ha.write)throw new P(28);a.seekable&&a.flags&1024&&ec(a,0,2);var h="undefined"!=typeof e;if(!h)e=a.position;else if(!a.seekable)throw new P(70);b=a.Ha.write(a,b,c,d,e,void 0);h||(a.position+=b);return b}
|
||||
function va(a){var b="binary";if("utf8"!==b&&"binary"!==b)throw Error(`Invalid encoding type "${b}"`);var c;var d=la(a,d||0);a=ac(a).size;var e=new Uint8Array(a);fc(d,e,0,a,0);"utf8"===b?c=M(e,0):"binary"===b&&(c=e);na(d);return c}function gc(){P||(P=function(a,b){this.name="ErrnoError";this.node=b;this.Eb=function(c){this.Ka=c};this.Eb(a);this.message="FS error"},P.prototype=Error(),P.prototype.constructor=P,[44].forEach(a=>{Eb[a]=new P(a);Eb[a].stack="<generic error, no stack>"}))}var hc;
|
||||
function ic(a,b,c){a=u("/dev/"+a);var d=ia(!!b,!!c);jc||=64;var e=jc++<<8|0;xb(e,{open(h){h.seekable=!1},close(){c?.buffer?.length&&c(10)},read(h,k,r,y){for(var v=0,F=0;F<y;F++){try{var H=b()}catch(pb){throw new P(29);}if(void 0===H&&0===v)throw new P(6);if(null===H||void 0===H)break;v++;k[r+F]=H}v&&(h.node.timestamp=Date.now());return v},write(h,k,r,y){for(var v=0;v<y;v++)try{c(k[r+v])}catch(F){throw new P(29);}y&&(h.node.timestamp=Date.now());return v}});Yb(a,d,e)}var jc,W={},Wb,dc;
|
||||
function kc(a,b,c){if("/"===b.charAt(0))return b;a=-100===a?"/":U(a).path;if(0==b.length){if(!c)throw new P(44);return a}return u(a+"/"+b)}
|
||||
function lc(a,b,c){try{var d=a(b)}catch(h){if(h&&h.node&&u(b)!==u(ha(h.node)))return-54;throw h;}D[c>>2]=d.dev;D[c+4>>2]=d.mode;E[c+8>>2]=d.nlink;D[c+12>>2]=d.uid;D[c+16>>2]=d.gid;D[c+20>>2]=d.rdev;J=[d.size>>>0,(I=d.size,1<=+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[c+24>>2]=J[0];D[c+28>>2]=J[1];D[c+32>>2]=4096;D[c+36>>2]=d.blocks;a=d.atime.getTime();b=d.mtime.getTime();var e=d.ctime.getTime();J=[Math.floor(a/1E3)>>>0,(I=Math.floor(a/1E3),1<=
|
||||
+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[c+40>>2]=J[0];D[c+44>>2]=J[1];E[c+48>>2]=a%1E3*1E3;J=[Math.floor(b/1E3)>>>0,(I=Math.floor(b/1E3),1<=+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[c+56>>2]=J[0];D[c+60>>2]=J[1];E[c+64>>2]=b%1E3*1E3;J=[Math.floor(e/1E3)>>>0,(I=Math.floor(e/1E3),1<=+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[c+72>>2]=J[0];
|
||||
D[c+76>>2]=J[1];E[c+80>>2]=e%1E3*1E3;J=[d.ino>>>0,(I=d.ino,1<=+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[c+88>>2]=J[0];D[c+92>>2]=J[1];return 0}var Mc=void 0;function Oc(){var a=D[+Mc>>2];Mc+=4;return a}
|
||||
var Pc=(a,b)=>b+2097152>>>0<4194305-!!a?(a>>>0)+4294967296*b:NaN,Qc=[0,31,60,91,121,152,182,213,244,274,305,335],Rc=[0,31,59,90,120,151,181,212,243,273,304,334],Sc=a=>{var b=da(a)+1,c=ea(b);c&&fa(a,q,c,b);return c},Tc={},Vc=()=>{if(!Uc){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:za||"./this.program"},b;for(b in Tc)void 0===Tc[b]?delete a[b]:a[b]=Tc[b];
|
||||
var c=[];for(b in a)c.push(`${b}=${a[b]}`);Uc=c}return Uc},Uc,ta=a=>{var b=da(a)+1,c=x(b);fa(a,q,c,b);return c},Wc=(a,b,c,d)=>{var e={string:v=>{var F=0;null!==v&&void 0!==v&&0!==v&&(F=ta(v));return F},array:v=>{var F=x(v.length);p.set(v,F);return F}};a=f["_"+a];var h=[],k=0;if(d)for(var r=0;r<d.length;r++){var y=e[c[r]];y?(0===k&&(k=pa()),h[r]=y(d[r])):h[r]=d[r]}c=a.apply(null,h);return c=function(v){0!==k&&sa(k);return"string"===b?v?M(q,v):"":"boolean"===b?!!v:v}(c)},ba=0,aa=(a,b)=>{b=1==b?x(a.length):
|
||||
ea(a.length);a.subarray||a.slice||(a=new Uint8Array(a));q.set(a,b);return b},Xc,Yc=[],Y,ua=a=>{Xc.delete(Y.get(a));Y.set(a,null);Yc.push(a)},xa=(a,b)=>{if(!Xc){Xc=new WeakMap;var c=Y.length;if(Xc)for(var d=0;d<0+c;d++){var e=Y.get(d);e&&Xc.set(e,d)}}if(c=Xc.get(a)||0)return c;if(Yc.length)c=Yc.pop();else{try{Y.grow(1)}catch(r){if(!(r instanceof RangeError))throw r;throw"Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.";}c=Y.length-1}try{Y.set(c,a)}catch(r){if(!(r instanceof TypeError))throw r;if("function"==
|
||||
typeof WebAssembly.Function){d=WebAssembly.Function;e={i:"i32",j:"i64",f:"f32",d:"f64",e:"externref",p:"i32"};for(var h={parameters:[],results:"v"==b[0]?[]:[e[b[0]]]},k=1;k<b.length;++k)h.parameters.push(e[b[k]]);b=new d(h,a)}else{d=[1];e=b.slice(0,1);b=b.slice(1);h={i:127,p:127,j:126,f:125,d:124,e:111};d.push(96);k=b.length;128>k?d.push(k):d.push(k%128|128,k>>7);for(k=0;k<b.length;++k)d.push(h[b[k]]);"v"==e?d.push(0):d.push(1,h[e]);b=[0,97,115,109,1,0,0,0,1];e=d.length;128>e?b.push(e):b.push(e%128|
|
||||
128,e>>7);b.push.apply(b,d);b.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);b=new WebAssembly.Module(new Uint8Array(b));b=(new WebAssembly.Instance(b,{e:{f:a}})).exports.f}Y.set(c,b)}Xc.set(a,c);return c};function Qb(a,b,c,d){a||=this;this.parent=a;this.Ra=a.Ra;this.Va=null;this.id=Kb++;this.name=b;this.mode=c;this.Ga={};this.Ha={};this.rdev=d}
|
||||
Object.defineProperties(Qb.prototype,{read:{get:function(){return 365===(this.mode&365)},set:function(a){a?this.mode|=365:this.mode&=-366}},write:{get:function(){return 146===(this.mode&146)},set:function(a){a?this.mode|=146:this.mode&=-147}}});gc();S=Array(4096);Xb(Q,"/");V("/tmp");V("/home");V("/home/web_user");
|
||||
(function(){V("/dev");xb(259,{read:()=>0,write:(d,e,h,k)=>k});Yb("/dev/null",259);wb(1280,zb);wb(1536,Ab);Yb("/dev/tty",1280);Yb("/dev/tty1",1536);var a=new Uint8Array(1024),b=0,c=()=>{0===b&&(b=kb(a).byteLength);return a[--b]};ic("random",c);ic("urandom",c);V("/dev/shm");V("/dev/shm/tmp")})();
|
||||
(function(){V("/proc");var a=V("/proc/self");V("/proc/self/fd");Xb({Ra(){var b=Db(a,"fd",16895,73);b.Ga={lookup(c,d){var e=U(+d);c={parent:null,Ra:{tb:"fake"},Ga:{readlink:()=>e.path}};return c.parent=c}};return b}},"/proc/self/fd")})();
|
||||
var $c={a:(a,b,c,d)=>{C(`Assertion failed: ${a?M(q,a):""}, at: `+[b?b?M(q,b):"":"unknown filename",c,d?d?M(q,d):"":"unknown function"])},h:function(a,b){try{return a=a?M(q,a):"",ka(a,b),0}catch(c){if("undefined"==typeof W||"ErrnoError"!==c.name)throw c;return-c.Ka}},H:function(a,b,c){try{b=b?M(q,b):"";b=kc(a,b);if(c&-8)return-28;var d=T(b,{Sa:!0}).node;if(!d)return-44;a="";c&4&&(a+="r");c&2&&(a+="w");c&1&&(a+="x");return a&&Pb(d,a)?-2:0}catch(e){if("undefined"==typeof W||"ErrnoError"!==e.name)throw e;
|
||||
return-e.Ka}},i:function(a,b){try{var c=U(a);ka(c.node,b);return 0}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return-d.Ka}},g:function(a){try{var b=U(a).node;var c="string"==typeof b?T(b,{Sa:!0}).node:b;if(!c.Ga.Oa)throw new P(63);c.Ga.Oa(c,{timestamp:Date.now()});return 0}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return-d.Ka}},b:function(a,b,c){Mc=c;try{var d=U(a);switch(b){case 0:var e=Oc();if(0>e)return-28;for(;Jb[e];)e++;return Vb(d,e).fd;case 1:case 2:return 0;
|
||||
case 3:return d.flags;case 4:return e=Oc(),d.flags|=e,0;case 5:return e=Oc(),Na[e+0>>1]=2,0;case 6:case 7:return 0;case 16:case 8:return-28;case 9:return D[Zc()>>2]=28,-1;default:return-28}}catch(h){if("undefined"==typeof W||"ErrnoError"!==h.name)throw h;return-h.Ka}},f:function(a,b){try{var c=U(a);return lc(ac,c.path,b)}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return-d.Ka}},n:function(a,b,c){b=Pc(b,c);try{if(isNaN(b))return 61;var d=U(a);if(0===(d.flags&2097155))throw new P(28);
|
||||
cc(d.node,b);return 0}catch(e){if("undefined"==typeof W||"ErrnoError"!==e.name)throw e;return-e.Ka}},C:function(a,b){try{if(0===b)return-28;var c=da("/")+1;if(b<c)return-68;fa("/",q,a,b);return c}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return-d.Ka}},F:function(a,b){try{return a=a?M(q,a):"",lc(bc,a,b)}catch(c){if("undefined"==typeof W||"ErrnoError"!==c.name)throw c;return-c.Ka}},z:function(a,b,c){try{return b=b?M(q,b):"",b=kc(a,b),b=u(b),"/"===b[b.length-1]&&(b=b.substr(0,
|
||||
b.length-1)),V(b,c),0}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return-d.Ka}},E:function(a,b,c,d){try{b=b?M(q,b):"";var e=d&256;b=kc(a,b,d&4096);return lc(e?bc:ac,b,c)}catch(h){if("undefined"==typeof W||"ErrnoError"!==h.name)throw h;return-h.Ka}},y:function(a,b,c,d){Mc=d;try{b=b?M(q,b):"";b=kc(a,b);var e=d?Oc():0;return la(b,c,e).fd}catch(h){if("undefined"==typeof W||"ErrnoError"!==h.name)throw h;return-h.Ka}},w:function(a,b,c,d){try{b=b?M(q,b):"";b=kc(a,b);if(0>=d)return-28;
|
||||
var e=Mb(b),h=Math.min(d,da(e)),k=p[c+h];fa(e,q,c,d+1);p[c+h]=k;return h}catch(r){if("undefined"==typeof W||"ErrnoError"!==r.name)throw r;return-r.Ka}},v:function(a){try{return a=a?M(q,a):"",$b(a),0}catch(b){if("undefined"==typeof W||"ErrnoError"!==b.name)throw b;return-b.Ka}},G:function(a,b){try{return a=a?M(q,a):"",lc(ac,a,b)}catch(c){if("undefined"==typeof W||"ErrnoError"!==c.name)throw c;return-c.Ka}},r:function(a,b,c){try{return b=b?M(q,b):"",b=kc(a,b),0===c?wa(b):512===c?$b(b):C("Invalid flags passed to unlinkat"),
|
||||
0}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return-d.Ka}},q:function(a,b,c){try{b=b?M(q,b):"";b=kc(a,b,!0);if(c){var d=E[c>>2]+4294967296*D[c+4>>2],e=D[c+8>>2];h=1E3*d+e/1E6;c+=16;d=E[c>>2]+4294967296*D[c+4>>2];e=D[c+8>>2];k=1E3*d+e/1E6}else var h=Date.now(),k=h;a=h;var r=T(b,{Sa:!0}).node;r.Ga.Oa(r,{timestamp:Math.max(a,k)});return 0}catch(y){if("undefined"==typeof W||"ErrnoError"!==y.name)throw y;return-y.Ka}},l:function(a,b,c){a=new Date(1E3*Pc(a,b));D[c>>2]=a.getSeconds();
|
||||
D[c+4>>2]=a.getMinutes();D[c+8>>2]=a.getHours();D[c+12>>2]=a.getDate();D[c+16>>2]=a.getMonth();D[c+20>>2]=a.getFullYear()-1900;D[c+24>>2]=a.getDay();b=a.getFullYear();D[c+28>>2]=(0!==b%4||0===b%100&&0!==b%400?Rc:Qc)[a.getMonth()]+a.getDate()-1|0;D[c+36>>2]=-(60*a.getTimezoneOffset());b=(new Date(a.getFullYear(),6,1)).getTimezoneOffset();var d=(new Date(a.getFullYear(),0,1)).getTimezoneOffset();D[c+32>>2]=(b!=d&&a.getTimezoneOffset()==Math.min(d,b))|0},j:function(a,b,c,d,e,h,k,r){e=Pc(e,h);try{if(isNaN(e))return 61;
|
||||
var y=U(d);if(0!==(b&2)&&0===(c&2)&&2!==(y.flags&2097155))throw new P(2);if(1===(y.flags&2097155))throw new P(2);if(!y.Ha.bb)throw new P(43);var v=y.Ha.bb(y,a,e,b,c);var F=v.Db;D[k>>2]=v.ub;E[r>>2]=F;return 0}catch(H){if("undefined"==typeof W||"ErrnoError"!==H.name)throw H;return-H.Ka}},k:function(a,b,c,d,e,h,k){h=Pc(h,k);try{if(isNaN(h))return 61;var r=U(e);if(c&2){if(32768!==(r.node.mode&61440))throw new P(43);if(!(d&2)){var y=q.slice(a,a+b);r.Ha.cb&&r.Ha.cb(r,y,h,b,d)}}}catch(v){if("undefined"==
|
||||
typeof W||"ErrnoError"!==v.name)throw v;return-v.Ka}},s:(a,b,c)=>{function d(y){return(y=y.toTimeString().match(/\(([A-Za-z ]+)\)$/))?y[1]:"GMT"}var e=(new Date).getFullYear(),h=new Date(e,0,1),k=new Date(e,6,1);e=h.getTimezoneOffset();var r=k.getTimezoneOffset();E[a>>2]=60*Math.max(e,r);D[b>>2]=Number(e!=r);a=d(h);b=d(k);a=Sc(a);b=Sc(b);r<e?(E[c>>2]=a,E[c+4>>2]=b):(E[c>>2]=b,E[c+4>>2]=a)},d:()=>Date.now(),t:()=>2147483648,c:()=>performance.now(),o:a=>{var b=q.length;a>>>=0;if(2147483648<a)return!1;
|
||||
for(var c=1;4>=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);var e=Math;d=Math.max(a,d);a:{e=(e.min.call(e,2147483648,d+(65536-d%65536)%65536)-La.buffer.byteLength+65535)/65536;try{La.grow(e);Qa();var h=1;break a}catch(k){}h=void 0}if(h)return!0}return!1},A:(a,b)=>{var c=0;Vc().forEach((d,e)=>{var h=b+c;e=E[a+4*e>>2]=h;for(h=0;h<d.length;++h)p[e++>>0]=d.charCodeAt(h);p[e>>0]=0;c+=d.length+1});return 0},B:(a,b)=>{var c=Vc();E[a>>2]=c.length;var d=0;c.forEach(e=>d+=e.length+1);E[b>>2]=d;return 0},
|
||||
e:function(a){try{var b=U(a);na(b);return 0}catch(c){if("undefined"==typeof W||"ErrnoError"!==c.name)throw c;return c.Ka}},p:function(a,b){try{var c=U(a);p[b>>0]=c.tty?2:R(c.mode)?3:40960===(c.mode&61440)?7:4;Na[b+2>>1]=0;J=[0,(I=0,1<=+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[b+8>>2]=J[0];D[b+12>>2]=J[1];J=[0,(I=0,1<=+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[b+16>>2]=J[0];D[b+20>>2]=J[1];
|
||||
return 0}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return d.Ka}},x:function(a,b,c,d){try{a:{var e=U(a);a=b;for(var h,k=b=0;k<c;k++){var r=E[a>>2],y=E[a+4>>2];a+=8;var v=fc(e,p,r,y,h);if(0>v){var F=-1;break a}b+=v;if(v<y)break;"undefined"!==typeof h&&(h+=v)}F=b}E[d>>2]=F;return 0}catch(H){if("undefined"==typeof W||"ErrnoError"!==H.name)throw H;return H.Ka}},m:function(a,b,c,d,e){b=Pc(b,c);try{if(isNaN(b))return 61;var h=U(a);ec(h,b,d);J=[h.position>>>0,(I=h.position,1<=+Math.abs(I)?
|
||||
0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[e>>2]=J[0];D[e+4>>2]=J[1];h.hb&&0===b&&0===d&&(h.hb=null);return 0}catch(k){if("undefined"==typeof W||"ErrnoError"!==k.name)throw k;return k.Ka}},D:function(a){try{var b=U(a);return b.Ha?.fsync?b.Ha.fsync(b):0}catch(c){if("undefined"==typeof W||"ErrnoError"!==c.name)throw c;return c.Ka}},u:function(a,b,c,d){try{a:{var e=U(a);a=b;for(var h,k=b=0;k<c;k++){var r=E[a>>2],y=E[a+4>>2];a+=8;var v=ma(e,p,r,y,h);if(0>v){var F=
|
||||
-1;break a}b+=v;"undefined"!==typeof h&&(h+=v)}F=b}E[d>>2]=F;return 0}catch(H){if("undefined"==typeof W||"ErrnoError"!==H.name)throw H;return H.Ka}}},Z=function(){function a(c){Z=c.exports;La=Z.I;Qa();Y=Z.Aa;Sa.unshift(Z.J);G--;f.monitorRunDependencies?.(G);0==G&&(null!==Wa&&(clearInterval(Wa),Wa=null),Xa&&(c=Xa,Xa=null,c()));return Z}var b={a:$c};G++;f.monitorRunDependencies?.(G);if(f.instantiateWasm)try{return f.instantiateWasm(b,a)}catch(c){return B(`Module.instantiateWasm callback failed with error: ${c}`),
|
||||
!1}db(b,function(c){a(c.instance)});return{}}();f._sqlite3_free=a=>(f._sqlite3_free=Z.K)(a);f._sqlite3_value_text=a=>(f._sqlite3_value_text=Z.L)(a);var Zc=()=>(Zc=Z.M)();f._sqlite3_prepare_v2=(a,b,c,d,e)=>(f._sqlite3_prepare_v2=Z.N)(a,b,c,d,e);f._sqlite3_step=a=>(f._sqlite3_step=Z.O)(a);f._sqlite3_reset=a=>(f._sqlite3_reset=Z.P)(a);f._sqlite3_exec=(a,b,c,d,e)=>(f._sqlite3_exec=Z.Q)(a,b,c,d,e);f._sqlite3_finalize=a=>(f._sqlite3_finalize=Z.R)(a);
|
||||
f._sqlite3_column_name=(a,b)=>(f._sqlite3_column_name=Z.S)(a,b);f._sqlite3_column_text=(a,b)=>(f._sqlite3_column_text=Z.T)(a,b);f._sqlite3_column_type=(a,b)=>(f._sqlite3_column_type=Z.U)(a,b);f._sqlite3_errmsg=a=>(f._sqlite3_errmsg=Z.V)(a);f._sqlite3_clear_bindings=a=>(f._sqlite3_clear_bindings=Z.W)(a);f._sqlite3_value_blob=a=>(f._sqlite3_value_blob=Z.X)(a);f._sqlite3_value_bytes=a=>(f._sqlite3_value_bytes=Z.Y)(a);f._sqlite3_value_double=a=>(f._sqlite3_value_double=Z.Z)(a);
|
||||
f._sqlite3_value_int=a=>(f._sqlite3_value_int=Z._)(a);f._sqlite3_value_type=a=>(f._sqlite3_value_type=Z.$)(a);f._sqlite3_result_blob=(a,b,c,d)=>(f._sqlite3_result_blob=Z.aa)(a,b,c,d);f._sqlite3_result_double=(a,b)=>(f._sqlite3_result_double=Z.ba)(a,b);f._sqlite3_result_error=(a,b,c)=>(f._sqlite3_result_error=Z.ca)(a,b,c);f._sqlite3_result_int=(a,b)=>(f._sqlite3_result_int=Z.da)(a,b);f._sqlite3_result_int64=(a,b,c)=>(f._sqlite3_result_int64=Z.ea)(a,b,c);
|
||||
f._sqlite3_result_null=a=>(f._sqlite3_result_null=Z.fa)(a);f._sqlite3_result_text=(a,b,c,d)=>(f._sqlite3_result_text=Z.ga)(a,b,c,d);f._sqlite3_aggregate_context=(a,b)=>(f._sqlite3_aggregate_context=Z.ha)(a,b);f._sqlite3_column_count=a=>(f._sqlite3_column_count=Z.ia)(a);f._sqlite3_data_count=a=>(f._sqlite3_data_count=Z.ja)(a);f._sqlite3_column_blob=(a,b)=>(f._sqlite3_column_blob=Z.ka)(a,b);f._sqlite3_column_bytes=(a,b)=>(f._sqlite3_column_bytes=Z.la)(a,b);
|
||||
f._sqlite3_column_double=(a,b)=>(f._sqlite3_column_double=Z.ma)(a,b);f._sqlite3_bind_blob=(a,b,c,d,e)=>(f._sqlite3_bind_blob=Z.na)(a,b,c,d,e);f._sqlite3_bind_double=(a,b,c)=>(f._sqlite3_bind_double=Z.oa)(a,b,c);f._sqlite3_bind_int=(a,b,c)=>(f._sqlite3_bind_int=Z.pa)(a,b,c);f._sqlite3_bind_text=(a,b,c,d,e)=>(f._sqlite3_bind_text=Z.qa)(a,b,c,d,e);f._sqlite3_bind_parameter_index=(a,b)=>(f._sqlite3_bind_parameter_index=Z.ra)(a,b);f._sqlite3_sql=a=>(f._sqlite3_sql=Z.sa)(a);
|
||||
f._sqlite3_normalized_sql=a=>(f._sqlite3_normalized_sql=Z.ta)(a);f._sqlite3_changes=a=>(f._sqlite3_changes=Z.ua)(a);f._sqlite3_close_v2=a=>(f._sqlite3_close_v2=Z.va)(a);f._sqlite3_create_function_v2=(a,b,c,d,e,h,k,r,y)=>(f._sqlite3_create_function_v2=Z.wa)(a,b,c,d,e,h,k,r,y);f._sqlite3_open=(a,b)=>(f._sqlite3_open=Z.xa)(a,b);var ea=f._malloc=a=>(ea=f._malloc=Z.ya)(a),ca=f._free=a=>(ca=f._free=Z.za)(a);f._RegisterExtensionFunctions=a=>(f._RegisterExtensionFunctions=Z.Ba)(a);
|
||||
var Gb=(a,b)=>(Gb=Z.Ca)(a,b),pa=()=>(pa=Z.Da)(),sa=a=>(sa=Z.Ea)(a),x=a=>(x=Z.Fa)(a);f.stackAlloc=x;f.stackSave=pa;f.stackRestore=sa;f.cwrap=(a,b,c,d)=>{var e=!c||c.every(h=>"number"===h||"boolean"===h);return"string"!==b&&e&&!d?f["_"+a]:function(){return Wc(a,b,c,arguments)}};f.addFunction=xa;f.removeFunction=ua;f.UTF8ToString=ra;f.ALLOC_NORMAL=ba;f.allocate=aa;f.allocateUTF8OnStack=ta;var ad;Xa=function bd(){ad||cd();ad||(Xa=bd)};
|
||||
function cd(){function a(){if(!ad&&(ad=!0,f.calledRun=!0,!Ma)){f.noFSInit||hc||(hc=!0,gc(),f.stdin=f.stdin,f.stdout=f.stdout,f.stderr=f.stderr,f.stdin?ic("stdin",f.stdin):Zb("/dev/tty","/dev/stdin"),f.stdout?ic("stdout",null,f.stdout):Zb("/dev/tty","/dev/stdout"),f.stderr?ic("stderr",null,f.stderr):Zb("/dev/tty1","/dev/stderr"),la("/dev/stdin",0),la("/dev/stdout",1),la("/dev/stderr",1));Lb=!1;eb(Sa);if(f.onRuntimeInitialized)f.onRuntimeInitialized();if(f.postRun)for("function"==typeof f.postRun&&
|
||||
(f.postRun=[f.postRun]);f.postRun.length;){var b=f.postRun.shift();Ta.unshift(b)}eb(Ta)}}if(!(0<G)){if(f.preRun)for("function"==typeof f.preRun&&(f.preRun=[f.preRun]);f.preRun.length;)Va();eb(Ra);0<G||(f.setStatus?(f.setStatus("Running..."),setTimeout(function(){setTimeout(function(){f.setStatus("")},1);a()},1)):a())}}if(f.preInit)for("function"==typeof f.preInit&&(f.preInit=[f.preInit]);0<f.preInit.length;)f.preInit.pop()();cd();
|
||||
|
||||
|
||||
// The shell-pre.js and emcc-generated code goes above
|
||||
return Module;
|
||||
}); // The end of the promise being returned
|
||||
|
||||
return initSqlJsPromise;
|
||||
} // The end of our initSqlJs function
|
||||
|
||||
// This bit below is copied almost exactly from what you get when you use the MODULARIZE=1 flag with emcc
|
||||
// However, we don't want to use the emcc modularization. See shell-pre.js
|
||||
if (typeof exports === 'object' && typeof module === 'object'){
|
||||
module.exports = initSqlJs;
|
||||
// This will allow the module to be used in ES6 or CommonJS
|
||||
module.exports.default = initSqlJs;
|
||||
}
|
||||
else if (typeof define === 'function' && define['amd']) {
|
||||
define([], function() { return initSqlJs; });
|
||||
}
|
||||
else if (typeof exports === 'object'){
|
||||
exports["Module"] = initSqlJs;
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,192 @@
|
|||
|
||||
// We are modularizing this manually because the current modularize setting in Emscripten has some issues:
|
||||
// https://github.com/kripken/emscripten/issues/5820
|
||||
// In addition, When you use emcc's modularization, it still expects to export a global object called `Module`,
|
||||
// which is able to be used/called before the WASM is loaded.
|
||||
// The modularization below exports a promise that loads and resolves to the actual sql.js module.
|
||||
// That way, this module can't be used before the WASM is finished loading.
|
||||
|
||||
// We are going to define a function that a user will call to start loading initializing our Sql.js library
|
||||
// However, that function might be called multiple times, and on subsequent calls, we don't actually want it to instantiate a new instance of the Module
|
||||
// Instead, we want to return the previously loaded module
|
||||
|
||||
// TODO: Make this not declare a global if used in the browser
|
||||
var initSqlJsPromise = undefined;
|
||||
|
||||
var initSqlJs = function (moduleConfig) {
|
||||
|
||||
if (initSqlJsPromise){
|
||||
return initSqlJsPromise;
|
||||
}
|
||||
// If we're here, we've never called this function before
|
||||
initSqlJsPromise = new Promise(function (resolveModule, reject) {
|
||||
|
||||
// We are modularizing this manually because the current modularize setting in Emscripten has some issues:
|
||||
// https://github.com/kripken/emscripten/issues/5820
|
||||
|
||||
// The way to affect the loading of emcc compiled modules is to create a variable called `Module` and add
|
||||
// properties to it, like `preRun`, `postRun`, etc
|
||||
// We are using that to get notified when the WASM has finished loading.
|
||||
// Only then will we return our promise
|
||||
|
||||
// If they passed in a moduleConfig object, use that
|
||||
// Otherwise, initialize Module to the empty object
|
||||
var Module = typeof moduleConfig !== 'undefined' ? moduleConfig : {};
|
||||
|
||||
// EMCC only allows for a single onAbort function (not an array of functions)
|
||||
// So if the user defined their own onAbort function, we remember it and call it
|
||||
var originalOnAbortFunction = Module['onAbort'];
|
||||
Module['onAbort'] = function (errorThatCausedAbort) {
|
||||
reject(new Error(errorThatCausedAbort));
|
||||
if (originalOnAbortFunction){
|
||||
originalOnAbortFunction(errorThatCausedAbort);
|
||||
}
|
||||
};
|
||||
|
||||
Module['postRun'] = Module['postRun'] || [];
|
||||
Module['postRun'].push(function () {
|
||||
// When Emscripted calls postRun, this promise resolves with the built Module
|
||||
resolveModule(Module);
|
||||
});
|
||||
|
||||
// There is a section of code in the emcc-generated code below that looks like this:
|
||||
// (Note that this is lowercase `module`)
|
||||
// if (typeof module !== 'undefined') {
|
||||
// module['exports'] = Module;
|
||||
// }
|
||||
// When that runs, it's going to overwrite our own modularization export efforts in shell-post.js!
|
||||
// The only way to tell emcc not to emit it is to pass the MODULARIZE=1 or MODULARIZE_INSTANCE=1 flags,
|
||||
// but that carries with it additional unnecessary baggage/bugs we don't want either.
|
||||
// So, we have three options:
|
||||
// 1) We undefine `module`
|
||||
// 2) We remember what `module['exports']` was at the beginning of this function and we restore it later
|
||||
// 3) We write a script to remove those lines of code as part of the Make process.
|
||||
//
|
||||
// Since those are the only lines of code that care about module, we will undefine it. It's the most straightforward
|
||||
// of the options, and has the side effect of reducing emcc's efforts to modify the module if its output were to change in the future.
|
||||
// That's a nice side effect since we're handling the modularization efforts ourselves
|
||||
module = undefined;
|
||||
|
||||
// The emcc-generated code and shell-post.js code goes below,
|
||||
// meaning that all of it runs inside of this promise. If anything throws an exception, our promise will abort
|
||||
var f;f||=typeof Module !== 'undefined' ? Module : {};"use strict";
|
||||
f.onRuntimeInitialized=function(){function a(g,l){switch(typeof l){case "boolean":mc(g,l?1:0);break;case "number":nc(g,l);break;case "string":oc(g,l,-1,-1);break;case "object":if(null===l)lb(g);else if(null!=l.length){var n=aa(l,ba);pc(g,n,l.length,-1);ca(n)}else Aa(g,"Wrong API use : tried to return a value of an unknown type ("+l+").",-1);break;default:lb(g)}}function b(g,l){for(var n=[],t=0;t<g;t+=1){var w=m(l+4*t,"i32"),z=qc(w);if(1===z||2===z)w=rc(w);else if(3===z)w=sc(w);else if(4===z){z=w;
|
||||
w=tc(z);z=uc(z);for(var N=new Uint8Array(w),L=0;L<w;L+=1)N[L]=p[z+L];w=N}else w=null;n.push(w)}return n}function c(g,l){this.La=g;this.db=l;this.Ja=1;this.fb=[]}function d(g,l){this.db=l;l=da(g)+1;this.Ya=ea(l);if(null===this.Ya)throw Error("Unable to allocate memory for the SQL string");fa(g,q,this.Ya,l);this.eb=this.Ya;this.Ua=this.ib=null}function e(g){this.filename="dbfile_"+(4294967295*Math.random()>>>0);if(null!=g){var l=this.filename,n="/",t=l;n&&(n="string"==typeof n?n:ha(n),t=l?u(n+"/"+l):
|
||||
n);l=ia(!0,!0);t=ja(t,(void 0!==l?l:438)&4095|32768,0);if(g){if("string"==typeof g){n=Array(g.length);for(var w=0,z=g.length;w<z;++w)n[w]=g.charCodeAt(w);g=n}ka(t,l|146);n=la(t,577);ma(n,g,0,g.length,0);na(n);ka(t,l)}}this.handleError(r(this.filename,h));this.db=m(h,"i32");ob(this.db);this.Za={};this.Na={}}var h=x(4),k=f.cwrap,r=k("sqlite3_open","number",["string","number"]),y=k("sqlite3_close_v2","number",["number"]),v=k("sqlite3_exec","number",["number","string","number","number","number"]),F=k("sqlite3_changes",
|
||||
"number",["number"]),H=k("sqlite3_prepare_v2","number",["number","string","number","number","number"]),pb=k("sqlite3_sql","string",["number"]),vc=k("sqlite3_normalized_sql","string",["number"]),qb=k("sqlite3_prepare_v2","number",["number","number","number","number","number"]),wc=k("sqlite3_bind_text","number",["number","number","number","number","number"]),rb=k("sqlite3_bind_blob","number",["number","number","number","number","number"]),xc=k("sqlite3_bind_double","number",["number","number","number"]),
|
||||
yc=k("sqlite3_bind_int","number",["number","number","number"]),zc=k("sqlite3_bind_parameter_index","number",["number","string"]),Ac=k("sqlite3_step","number",["number"]),Bc=k("sqlite3_errmsg","string",["number"]),Cc=k("sqlite3_column_count","number",["number"]),Dc=k("sqlite3_data_count","number",["number"]),Ec=k("sqlite3_column_double","number",["number","number"]),sb=k("sqlite3_column_text","string",["number","number"]),Fc=k("sqlite3_column_blob","number",["number","number"]),Gc=k("sqlite3_column_bytes",
|
||||
"number",["number","number"]),Hc=k("sqlite3_column_type","number",["number","number"]),Ic=k("sqlite3_column_name","string",["number","number"]),Jc=k("sqlite3_reset","number",["number"]),Kc=k("sqlite3_clear_bindings","number",["number"]),Lc=k("sqlite3_finalize","number",["number"]),tb=k("sqlite3_create_function_v2","number","number string number number number number number number number".split(" ")),qc=k("sqlite3_value_type","number",["number"]),tc=k("sqlite3_value_bytes","number",["number"]),sc=k("sqlite3_value_text",
|
||||
"string",["number"]),uc=k("sqlite3_value_blob","number",["number"]),rc=k("sqlite3_value_double","number",["number"]),nc=k("sqlite3_result_double","",["number","number"]),lb=k("sqlite3_result_null","",["number"]),oc=k("sqlite3_result_text","",["number","string","number","number"]),pc=k("sqlite3_result_blob","",["number","number","number","number"]),mc=k("sqlite3_result_int","",["number","number"]),Aa=k("sqlite3_result_error","",["number","string","number"]),ub=k("sqlite3_aggregate_context","number",
|
||||
["number","number"]),ob=k("RegisterExtensionFunctions","number",["number"]);c.prototype.bind=function(g){if(!this.La)throw"Statement closed";this.reset();return Array.isArray(g)?this.wb(g):null!=g&&"object"===typeof g?this.xb(g):!0};c.prototype.step=function(){if(!this.La)throw"Statement closed";this.Ja=1;var g=Ac(this.La);switch(g){case 100:return!0;case 101:return!1;default:throw this.db.handleError(g);}};c.prototype.rb=function(g){null==g&&(g=this.Ja,this.Ja+=1);return Ec(this.La,g)};c.prototype.Ab=
|
||||
function(g){null==g&&(g=this.Ja,this.Ja+=1);g=sb(this.La,g);if("function"!==typeof BigInt)throw Error("BigInt is not supported");return BigInt(g)};c.prototype.Bb=function(g){null==g&&(g=this.Ja,this.Ja+=1);return sb(this.La,g)};c.prototype.getBlob=function(g){null==g&&(g=this.Ja,this.Ja+=1);var l=Gc(this.La,g);g=Fc(this.La,g);for(var n=new Uint8Array(l),t=0;t<l;t+=1)n[t]=p[g+t];return n};c.prototype.get=function(g,l){l=l||{};null!=g&&this.bind(g)&&this.step();g=[];for(var n=Dc(this.La),t=0;t<n;t+=
|
||||
1)switch(Hc(this.La,t)){case 1:var w=l.useBigInt?this.Ab(t):this.rb(t);g.push(w);break;case 2:g.push(this.rb(t));break;case 3:g.push(this.Bb(t));break;case 4:g.push(this.getBlob(t));break;default:g.push(null)}return g};c.prototype.getColumnNames=function(){for(var g=[],l=Cc(this.La),n=0;n<l;n+=1)g.push(Ic(this.La,n));return g};c.prototype.getAsObject=function(g,l){g=this.get(g,l);l=this.getColumnNames();for(var n={},t=0;t<l.length;t+=1)n[l[t]]=g[t];return n};c.prototype.getSQL=function(){return pb(this.La)};
|
||||
c.prototype.getNormalizedSQL=function(){return vc(this.La)};c.prototype.run=function(g){null!=g&&this.bind(g);this.step();return this.reset()};c.prototype.nb=function(g,l){null==l&&(l=this.Ja,this.Ja+=1);g=oa(g);var n=aa(g,ba);this.fb.push(n);this.db.handleError(wc(this.La,l,n,g.length-1,0))};c.prototype.vb=function(g,l){null==l&&(l=this.Ja,this.Ja+=1);var n=aa(g,ba);this.fb.push(n);this.db.handleError(rb(this.La,l,n,g.length,0))};c.prototype.mb=function(g,l){null==l&&(l=this.Ja,this.Ja+=1);this.db.handleError((g===
|
||||
(g|0)?yc:xc)(this.La,l,g))};c.prototype.yb=function(g){null==g&&(g=this.Ja,this.Ja+=1);rb(this.La,g,0,0,0)};c.prototype.ob=function(g,l){null==l&&(l=this.Ja,this.Ja+=1);switch(typeof g){case "string":this.nb(g,l);return;case "number":this.mb(g,l);return;case "bigint":this.nb(g.toString(),l);return;case "boolean":this.mb(g+0,l);return;case "object":if(null===g){this.yb(l);return}if(null!=g.length){this.vb(g,l);return}}throw"Wrong API use : tried to bind a value of an unknown type ("+g+").";};c.prototype.xb=
|
||||
function(g){var l=this;Object.keys(g).forEach(function(n){var t=zc(l.La,n);0!==t&&l.ob(g[n],t)});return!0};c.prototype.wb=function(g){for(var l=0;l<g.length;l+=1)this.ob(g[l],l+1);return!0};c.prototype.reset=function(){this.freemem();return 0===Kc(this.La)&&0===Jc(this.La)};c.prototype.freemem=function(){for(var g;void 0!==(g=this.fb.pop());)ca(g)};c.prototype.free=function(){this.freemem();var g=0===Lc(this.La);delete this.db.Za[this.La];this.La=0;return g};d.prototype.next=function(){if(null===
|
||||
this.Ya)return{done:!0};null!==this.Ua&&(this.Ua.free(),this.Ua=null);if(!this.db.db)throw this.gb(),Error("Database closed");var g=pa(),l=x(4);qa(h);qa(l);try{this.db.handleError(qb(this.db.db,this.eb,-1,h,l));this.eb=m(l,"i32");var n=m(h,"i32");if(0===n)return this.gb(),{done:!0};this.Ua=new c(n,this.db);this.db.Za[n]=this.Ua;return{value:this.Ua,done:!1}}catch(t){throw this.ib=ra(this.eb),this.gb(),t;}finally{sa(g)}};d.prototype.gb=function(){ca(this.Ya);this.Ya=null};d.prototype.getRemainingSQL=
|
||||
function(){return null!==this.ib?this.ib:ra(this.eb)};"function"===typeof Symbol&&"symbol"===typeof Symbol.iterator&&(d.prototype[Symbol.iterator]=function(){return this});e.prototype.run=function(g,l){if(!this.db)throw"Database closed";if(l){g=this.prepare(g,l);try{g.step()}finally{g.free()}}else this.handleError(v(this.db,g,0,0,h));return this};e.prototype.exec=function(g,l,n){if(!this.db)throw"Database closed";var t=pa(),w=null;try{var z=ta(g),N=x(4);for(g=[];0!==m(z,"i8");){qa(h);qa(N);this.handleError(qb(this.db,
|
||||
z,-1,h,N));var L=m(h,"i32");z=m(N,"i32");if(0!==L){var K=null;w=new c(L,this);for(null!=l&&w.bind(l);w.step();)null===K&&(K={columns:w.getColumnNames(),values:[]},g.push(K)),K.values.push(w.get(null,n));w.free()}}return g}catch(O){throw w&&w.free(),O;}finally{sa(t)}};e.prototype.each=function(g,l,n,t,w){"function"===typeof l&&(t=n,n=l,l=void 0);g=this.prepare(g,l);try{for(;g.step();)n(g.getAsObject(null,w))}finally{g.free()}if("function"===typeof t)return t()};e.prototype.prepare=function(g,l){qa(h);
|
||||
this.handleError(H(this.db,g,-1,h,0));g=m(h,"i32");if(0===g)throw"Nothing to prepare";var n=new c(g,this);null!=l&&n.bind(l);return this.Za[g]=n};e.prototype.iterateStatements=function(g){return new d(g,this)};e.prototype["export"]=function(){Object.values(this.Za).forEach(function(l){l.free()});Object.values(this.Na).forEach(ua);this.Na={};this.handleError(y(this.db));var g=va(this.filename);this.handleError(r(this.filename,h));this.db=m(h,"i32");ob(this.db);return g};e.prototype.close=function(){null!==
|
||||
this.db&&(Object.values(this.Za).forEach(function(g){g.free()}),Object.values(this.Na).forEach(ua),this.Na={},this.handleError(y(this.db)),wa("/"+this.filename),this.db=null)};e.prototype.handleError=function(g){if(0===g)return null;g=Bc(this.db);throw Error(g);};e.prototype.getRowsModified=function(){return F(this.db)};e.prototype.create_function=function(g,l){Object.prototype.hasOwnProperty.call(this.Na,g)&&(ua(this.Na[g]),delete this.Na[g]);var n=xa(function(t,w,z){w=b(w,z);try{var N=l.apply(null,
|
||||
w)}catch(L){Aa(t,L,-1);return}a(t,N)},"viii");this.Na[g]=n;this.handleError(tb(this.db,g,l.length,1,0,n,0,0,0));return this};e.prototype.create_aggregate=function(g,l){var n=l.init||function(){return null},t=l.finalize||function(K){return K},w=l.step;if(!w)throw"An aggregate function must have a step function in "+g;var z={};Object.hasOwnProperty.call(this.Na,g)&&(ua(this.Na[g]),delete this.Na[g]);l=g+"__finalize";Object.hasOwnProperty.call(this.Na,l)&&(ua(this.Na[l]),delete this.Na[l]);var N=xa(function(K,
|
||||
O,Ua){var X=ub(K,1);Object.hasOwnProperty.call(z,X)||(z[X]=n());O=b(O,Ua);O=[z[X]].concat(O);try{z[X]=w.apply(null,O)}catch(Nc){delete z[X],Aa(K,Nc,-1)}},"viii"),L=xa(function(K){var O=ub(K,1);try{var Ua=t(z[O])}catch(X){delete z[O];Aa(K,X,-1);return}a(K,Ua);delete z[O]},"vi");this.Na[g]=N;this.Na[l]=L;this.handleError(tb(this.db,g,w.length-1,1,0,0,N,L,0));return this};f.Database=e};
|
||||
var ya=Object.assign({},f),za="./this.program",Ba="object"==typeof window,Ca="function"==typeof importScripts,Da="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,A="",Ea,Fa,Ga;
|
||||
if(Da){var fs=require("fs"),Ha=require("path");A=Ca?Ha.dirname(A)+"/":__dirname+"/";Ea=(a,b)=>{a=Ia(a)?new URL(a):Ha.normalize(a);return fs.readFileSync(a,b?void 0:"utf8")};Ga=a=>{a=Ea(a,!0);a.buffer||(a=new Uint8Array(a));return a};Fa=(a,b,c,d=!0)=>{a=Ia(a)?new URL(a):Ha.normalize(a);fs.readFile(a,d?void 0:"utf8",(e,h)=>{e?c(e):b(d?h.buffer:h)})};!f.thisProgram&&1<process.argv.length&&(za=process.argv[1].replace(/\\/g,"/"));process.argv.slice(2);"undefined"!=typeof module&&(module.exports=f);f.inspect=
|
||||
()=>"[Emscripten Module object]"}else if(Ba||Ca)Ca?A=self.location.href:"undefined"!=typeof document&&document.currentScript&&(A=document.currentScript.src),A=0!==A.indexOf("blob:")?A.substr(0,A.replace(/[?#].*/,"").lastIndexOf("/")+1):"",Ea=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.send(null);return b.responseText},Ca&&(Ga=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),Fa=(a,b,c)=>{var d=new XMLHttpRequest;d.open("GET",
|
||||
a,!0);d.responseType="arraybuffer";d.onload=()=>{200==d.status||0==d.status&&d.response?b(d.response):c()};d.onerror=c;d.send(null)};var Ja=f.print||console.log.bind(console),B=f.printErr||console.error.bind(console);Object.assign(f,ya);ya=null;f.thisProgram&&(za=f.thisProgram);var Ka;f.wasmBinary&&(Ka=f.wasmBinary);"object"!=typeof WebAssembly&&C("no native wasm support detected");var La,Ma=!1,p,q,Na,D,E,Oa,Pa;
|
||||
function Qa(){var a=La.buffer;f.HEAP8=p=new Int8Array(a);f.HEAP16=Na=new Int16Array(a);f.HEAPU8=q=new Uint8Array(a);f.HEAPU16=new Uint16Array(a);f.HEAP32=D=new Int32Array(a);f.HEAPU32=E=new Uint32Array(a);f.HEAPF32=Oa=new Float32Array(a);f.HEAPF64=Pa=new Float64Array(a)}var Ra=[],Sa=[],Ta=[];function Va(){var a=f.preRun.shift();Ra.unshift(a)}var G=0,Wa=null,Xa=null;
|
||||
function C(a){f.onAbort?.(a);a="Aborted("+a+")";B(a);Ma=!0;throw new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");}var Ya=a=>a.startsWith("data:application/octet-stream;base64,"),Ia=a=>a.startsWith("file://"),Za;Za="sql-wasm.wasm";if(!Ya(Za)){var $a=Za;Za=f.locateFile?f.locateFile($a,A):A+$a}function ab(a){if(a==Za&&Ka)return new Uint8Array(Ka);if(Ga)return Ga(a);throw"both async and sync fetching of the wasm failed";}
|
||||
function bb(a){if(!Ka&&(Ba||Ca)){if("function"==typeof fetch&&!Ia(a))return fetch(a,{credentials:"same-origin"}).then(b=>{if(!b.ok)throw"failed to load wasm binary file at '"+a+"'";return b.arrayBuffer()}).catch(()=>ab(a));if(Fa)return new Promise((b,c)=>{Fa(a,d=>b(new Uint8Array(d)),c)})}return Promise.resolve().then(()=>ab(a))}function cb(a,b,c){return bb(a).then(d=>WebAssembly.instantiate(d,b)).then(d=>d).then(c,d=>{B(`failed to asynchronously prepare wasm: ${d}`);C(d)})}
|
||||
function db(a,b){var c=Za;Ka||"function"!=typeof WebAssembly.instantiateStreaming||Ya(c)||Ia(c)||Da||"function"!=typeof fetch?cb(c,a,b):fetch(c,{credentials:"same-origin"}).then(d=>WebAssembly.instantiateStreaming(d,a).then(b,function(e){B(`wasm streaming compile failed: ${e}`);B("falling back to ArrayBuffer instantiation");return cb(c,a,b)}))}var I,J,eb=a=>{for(;0<a.length;)a.shift()(f)};
|
||||
function m(a,b="i8"){b.endsWith("*")&&(b="*");switch(b){case "i1":return p[a>>0];case "i8":return p[a>>0];case "i16":return Na[a>>1];case "i32":return D[a>>2];case "i64":C("to do getValue(i64) use WASM_BIGINT");case "float":return Oa[a>>2];case "double":return Pa[a>>3];case "*":return E[a>>2];default:C(`invalid type for getValue: ${b}`)}}
|
||||
function qa(a){var b="i32";b.endsWith("*")&&(b="*");switch(b){case "i1":p[a>>0]=0;break;case "i8":p[a>>0]=0;break;case "i16":Na[a>>1]=0;break;case "i32":D[a>>2]=0;break;case "i64":C("to do setValue(i64) use WASM_BIGINT");case "float":Oa[a>>2]=0;break;case "double":Pa[a>>3]=0;break;case "*":E[a>>2]=0;break;default:C(`invalid type for setValue: ${b}`)}}
|
||||
var fb="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0,M=(a,b,c)=>{var d=b+c;for(c=b;a[c]&&!(c>=d);)++c;if(16<c-b&&a.buffer&&fb)return fb.decode(a.subarray(b,c));for(d="";b<c;){var e=a[b++];if(e&128){var h=a[b++]&63;if(192==(e&224))d+=String.fromCharCode((e&31)<<6|h);else{var k=a[b++]&63;e=224==(e&240)?(e&15)<<12|h<<6|k:(e&7)<<18|h<<12|k<<6|a[b++]&63;65536>e?d+=String.fromCharCode(e):(e-=65536,d+=String.fromCharCode(55296|e>>10,56320|e&1023))}}else d+=String.fromCharCode(e)}return d},
|
||||
ra=(a,b)=>a?M(q,a,b):"",gb=(a,b)=>{for(var c=0,d=a.length-1;0<=d;d--){var e=a[d];"."===e?a.splice(d,1):".."===e?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c;c--)a.unshift("..");return a},u=a=>{var b="/"===a.charAt(0),c="/"===a.substr(-1);(a=gb(a.split("/").filter(d=>!!d),!b).join("/"))||b||(a=".");a&&c&&(a+="/");return(b?"/":"")+a},hb=a=>{var b=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(a).slice(1);a=b[0];b=b[1];if(!a&&!b)return".";b&&=b.substr(0,b.length-1);return a+
|
||||
b},ib=a=>{if("/"===a)return"/";a=u(a);a=a.replace(/\/$/,"");var b=a.lastIndexOf("/");return-1===b?a:a.substr(b+1)},jb=()=>{if("object"==typeof crypto&&"function"==typeof crypto.getRandomValues)return c=>crypto.getRandomValues(c);if(Da)try{var a=require("crypto");if(a.randomFillSync)return c=>a.randomFillSync(c);var b=a.randomBytes;return c=>(c.set(b(c.byteLength)),c)}catch(c){}C("initRandomDevice")},kb=a=>(kb=jb())(a);
|
||||
function mb(){for(var a="",b=!1,c=arguments.length-1;-1<=c&&!b;c--){b=0<=c?arguments[c]:"/";if("string"!=typeof b)throw new TypeError("Arguments to path.resolve must be strings");if(!b)return"";a=b+"/"+a;b="/"===b.charAt(0)}a=gb(a.split("/").filter(d=>!!d),!b).join("/");return(b?"/":"")+a||"."}
|
||||
var nb=[],da=a=>{for(var b=0,c=0;c<a.length;++c){var d=a.charCodeAt(c);127>=d?b++:2047>=d?b+=2:55296<=d&&57343>=d?(b+=4,++c):b+=3}return b},fa=(a,b,c,d)=>{if(!(0<d))return 0;var e=c;d=c+d-1;for(var h=0;h<a.length;++h){var k=a.charCodeAt(h);if(55296<=k&&57343>=k){var r=a.charCodeAt(++h);k=65536+((k&1023)<<10)|r&1023}if(127>=k){if(c>=d)break;b[c++]=k}else{if(2047>=k){if(c+1>=d)break;b[c++]=192|k>>6}else{if(65535>=k){if(c+2>=d)break;b[c++]=224|k>>12}else{if(c+3>=d)break;b[c++]=240|k>>18;b[c++]=128|k>>
|
||||
12&63}b[c++]=128|k>>6&63}b[c++]=128|k&63}}b[c]=0;return c-e};function oa(a,b){var c=Array(da(a)+1);a=fa(a,c,0,c.length);b&&(c.length=a);return c}var vb=[];function wb(a,b){vb[a]={input:[],output:[],Xa:b};xb(a,yb)}
|
||||
var yb={open(a){var b=vb[a.node.rdev];if(!b)throw new P(43);a.tty=b;a.seekable=!1},close(a){a.tty.Xa.fsync(a.tty)},fsync(a){a.tty.Xa.fsync(a.tty)},read(a,b,c,d){if(!a.tty||!a.tty.Xa.sb)throw new P(60);for(var e=0,h=0;h<d;h++){try{var k=a.tty.Xa.sb(a.tty)}catch(r){throw new P(29);}if(void 0===k&&0===e)throw new P(6);if(null===k||void 0===k)break;e++;b[c+h]=k}e&&(a.node.timestamp=Date.now());return e},write(a,b,c,d){if(!a.tty||!a.tty.Xa.jb)throw new P(60);try{for(var e=0;e<d;e++)a.tty.Xa.jb(a.tty,b[c+
|
||||
e])}catch(h){throw new P(29);}d&&(a.node.timestamp=Date.now());return e}},zb={sb(){a:{if(!nb.length){var a=null;if(Da){var b=Buffer.alloc(256),c=0,d=process.stdin.fd;try{c=fs.readSync(d,b)}catch(e){if(e.toString().includes("EOF"))c=0;else throw e;}0<c?a=b.slice(0,c).toString("utf-8"):a=null}else"undefined"!=typeof window&&"function"==typeof window.prompt?(a=window.prompt("Input: "),null!==a&&(a+="\n")):"function"==typeof readline&&(a=readline(),null!==a&&(a+="\n"));if(!a){a=null;break a}nb=oa(a,!0)}a=
|
||||
nb.shift()}return a},jb(a,b){null===b||10===b?(Ja(M(a.output,0)),a.output=[]):0!=b&&a.output.push(b)},fsync(a){a.output&&0<a.output.length&&(Ja(M(a.output,0)),a.output=[])},Mb(){return{Ib:25856,Kb:5,Hb:191,Jb:35387,Gb:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},Nb(){return 0},Ob(){return[24,80]}},Ab={jb(a,b){null===b||10===b?(B(M(a.output,0)),a.output=[]):0!=b&&a.output.push(b)},fsync(a){a.output&&0<a.output.length&&(B(M(a.output,0)),a.output=[])}};
|
||||
function Bb(a,b){var c=a.Ia?a.Ia.length:0;c>=b||(b=Math.max(b,c*(1048576>c?2:1.125)>>>0),0!=c&&(b=Math.max(b,256)),c=a.Ia,a.Ia=new Uint8Array(b),0<a.Ma&&a.Ia.set(c.subarray(0,a.Ma),0))}
|
||||
var Q={Qa:null,Ra(){return Q.createNode(null,"/",16895,0)},createNode(a,b,c,d){if(24576===(c&61440)||4096===(c&61440))throw new P(63);Q.Qa||(Q.Qa={dir:{node:{Pa:Q.Ga.Pa,Oa:Q.Ga.Oa,lookup:Q.Ga.lookup,ab:Q.Ga.ab,rename:Q.Ga.rename,unlink:Q.Ga.unlink,rmdir:Q.Ga.rmdir,readdir:Q.Ga.readdir,symlink:Q.Ga.symlink},stream:{Ta:Q.Ha.Ta}},file:{node:{Pa:Q.Ga.Pa,Oa:Q.Ga.Oa},stream:{Ta:Q.Ha.Ta,read:Q.Ha.read,write:Q.Ha.write,lb:Q.Ha.lb,bb:Q.Ha.bb,cb:Q.Ha.cb}},link:{node:{Pa:Q.Ga.Pa,Oa:Q.Ga.Oa,readlink:Q.Ga.readlink},
|
||||
stream:{}},pb:{node:{Pa:Q.Ga.Pa,Oa:Q.Ga.Oa},stream:Cb}});c=Db(a,b,c,d);R(c.mode)?(c.Ga=Q.Qa.dir.node,c.Ha=Q.Qa.dir.stream,c.Ia={}):32768===(c.mode&61440)?(c.Ga=Q.Qa.file.node,c.Ha=Q.Qa.file.stream,c.Ma=0,c.Ia=null):40960===(c.mode&61440)?(c.Ga=Q.Qa.link.node,c.Ha=Q.Qa.link.stream):8192===(c.mode&61440)&&(c.Ga=Q.Qa.pb.node,c.Ha=Q.Qa.pb.stream);c.timestamp=Date.now();a&&(a.Ia[b]=c,a.timestamp=c.timestamp);return c},Lb(a){return a.Ia?a.Ia.subarray?a.Ia.subarray(0,a.Ma):new Uint8Array(a.Ia):new Uint8Array(0)},
|
||||
Ga:{Pa(a){var b={};b.dev=8192===(a.mode&61440)?a.id:1;b.ino=a.id;b.mode=a.mode;b.nlink=1;b.uid=0;b.gid=0;b.rdev=a.rdev;R(a.mode)?b.size=4096:32768===(a.mode&61440)?b.size=a.Ma:40960===(a.mode&61440)?b.size=a.link.length:b.size=0;b.atime=new Date(a.timestamp);b.mtime=new Date(a.timestamp);b.ctime=new Date(a.timestamp);b.zb=4096;b.blocks=Math.ceil(b.size/b.zb);return b},Oa(a,b){void 0!==b.mode&&(a.mode=b.mode);void 0!==b.timestamp&&(a.timestamp=b.timestamp);if(void 0!==b.size&&(b=b.size,a.Ma!=b))if(0==
|
||||
b)a.Ia=null,a.Ma=0;else{var c=a.Ia;a.Ia=new Uint8Array(b);c&&a.Ia.set(c.subarray(0,Math.min(b,a.Ma)));a.Ma=b}},lookup(){throw Eb[44];},ab(a,b,c,d){return Q.createNode(a,b,c,d)},rename(a,b,c){if(R(a.mode)){try{var d=Fb(b,c)}catch(h){}if(d)for(var e in d.Ia)throw new P(55);}delete a.parent.Ia[a.name];a.parent.timestamp=Date.now();a.name=c;b.Ia[c]=a;b.timestamp=a.parent.timestamp;a.parent=b},unlink(a,b){delete a.Ia[b];a.timestamp=Date.now()},rmdir(a,b){var c=Fb(a,b),d;for(d in c.Ia)throw new P(55);delete a.Ia[b];
|
||||
a.timestamp=Date.now()},readdir(a){var b=[".",".."],c;for(c of Object.keys(a.Ia))b.push(c);return b},symlink(a,b,c){a=Q.createNode(a,b,41471,0);a.link=c;return a},readlink(a){if(40960!==(a.mode&61440))throw new P(28);return a.link}},Ha:{read(a,b,c,d,e){var h=a.node.Ia;if(e>=a.node.Ma)return 0;a=Math.min(a.node.Ma-e,d);if(8<a&&h.subarray)b.set(h.subarray(e,e+a),c);else for(d=0;d<a;d++)b[c+d]=h[e+d];return a},write(a,b,c,d,e,h){b.buffer===p.buffer&&(h=!1);if(!d)return 0;a=a.node;a.timestamp=Date.now();
|
||||
if(b.subarray&&(!a.Ia||a.Ia.subarray)){if(h)return a.Ia=b.subarray(c,c+d),a.Ma=d;if(0===a.Ma&&0===e)return a.Ia=b.slice(c,c+d),a.Ma=d;if(e+d<=a.Ma)return a.Ia.set(b.subarray(c,c+d),e),d}Bb(a,e+d);if(a.Ia.subarray&&b.subarray)a.Ia.set(b.subarray(c,c+d),e);else for(h=0;h<d;h++)a.Ia[e+h]=b[c+h];a.Ma=Math.max(a.Ma,e+d);return d},Ta(a,b,c){1===c?b+=a.position:2===c&&32768===(a.node.mode&61440)&&(b+=a.node.Ma);if(0>b)throw new P(28);return b},lb(a,b,c){Bb(a.node,b+c);a.node.Ma=Math.max(a.node.Ma,b+c)},
|
||||
bb(a,b,c,d,e){if(32768!==(a.node.mode&61440))throw new P(43);a=a.node.Ia;if(e&2||a.buffer!==p.buffer){if(0<c||c+b<a.length)a.subarray?a=a.subarray(c,c+b):a=Array.prototype.slice.call(a,c,c+b);c=!0;b=65536*Math.ceil(b/65536);(e=Gb(65536,b))?(q.fill(0,e,e+b),b=e):b=0;if(!b)throw new P(48);p.set(a,b)}else c=!1,b=a.byteOffset;return{Db:b,ub:c}},cb(a,b,c,d){Q.Ha.write(a,b,0,d,c,!1);return 0}}},ia=(a,b)=>{var c=0;a&&(c|=365);b&&(c|=146);return c},Hb=null,Ib={},Jb=[],Kb=1,S=null,Lb=!0,P=null,Eb={};
|
||||
function T(a,b={}){a=mb(a);if(!a)return{path:"",node:null};b=Object.assign({qb:!0,kb:0},b);if(8<b.kb)throw new P(32);a=a.split("/").filter(k=>!!k);for(var c=Hb,d="/",e=0;e<a.length;e++){var h=e===a.length-1;if(h&&b.parent)break;c=Fb(c,a[e]);d=u(d+"/"+a[e]);c.Va&&(!h||h&&b.qb)&&(c=c.Va.root);if(!h||b.Sa)for(h=0;40960===(c.mode&61440);)if(c=Mb(d),d=mb(hb(d),c),c=T(d,{kb:b.kb+1}).node,40<h++)throw new P(32);}return{path:d,node:c}}
|
||||
function ha(a){for(var b;;){if(a===a.parent)return a=a.Ra.tb,b?"/"!==a[a.length-1]?`${a}/${b}`:a+b:a;b=b?`${a.name}/${b}`:a.name;a=a.parent}}function Nb(a,b){for(var c=0,d=0;d<b.length;d++)c=(c<<5)-c+b.charCodeAt(d)|0;return(a+c>>>0)%S.length}function Ob(a){var b=Nb(a.parent.id,a.name);if(S[b]===a)S[b]=a.Wa;else for(b=S[b];b;){if(b.Wa===a){b.Wa=a.Wa;break}b=b.Wa}}
|
||||
function Fb(a,b){var c;if(c=(c=Pb(a,"x"))?c:a.Ga.lookup?0:2)throw new P(c,a);for(c=S[Nb(a.id,b)];c;c=c.Wa){var d=c.name;if(c.parent.id===a.id&&d===b)return c}return a.Ga.lookup(a,b)}function Db(a,b,c,d){a=new Qb(a,b,c,d);b=Nb(a.parent.id,a.name);a.Wa=S[b];return S[b]=a}function R(a){return 16384===(a&61440)}function Rb(a){var b=["r","w","rw"][a&3];a&512&&(b+="w");return b}
|
||||
function Pb(a,b){if(Lb)return 0;if(!b.includes("r")||a.mode&292){if(b.includes("w")&&!(a.mode&146)||b.includes("x")&&!(a.mode&73))return 2}else return 2;return 0}function Sb(a,b){try{return Fb(a,b),20}catch(c){}return Pb(a,"wx")}function Tb(a,b,c){try{var d=Fb(a,b)}catch(e){return e.Ka}if(a=Pb(a,"wx"))return a;if(c){if(!R(d.mode))return 54;if(d===d.parent||"/"===ha(d))return 10}else if(R(d.mode))return 31;return 0}function Ub(){for(var a=0;4096>=a;a++)if(!Jb[a])return a;throw new P(33);}
|
||||
function U(a){a=Jb[a];if(!a)throw new P(8);return a}function Vb(a,b=-1){Wb||(Wb=function(){this.$a={}},Wb.prototype={},Object.defineProperties(Wb.prototype,{object:{get(){return this.node},set(c){this.node=c}},flags:{get(){return this.$a.flags},set(c){this.$a.flags=c}},position:{get(){return this.$a.position},set(c){this.$a.position=c}}}));a=Object.assign(new Wb,a);-1==b&&(b=Ub());a.fd=b;return Jb[b]=a}var Cb={open(a){a.Ha=Ib[a.node.rdev].Ha;a.Ha.open?.(a)},Ta(){throw new P(70);}};
|
||||
function xb(a,b){Ib[a]={Ha:b}}function Xb(a,b){var c="/"===b,d=!b;if(c&&Hb)throw new P(10);if(!c&&!d){var e=T(b,{qb:!1});b=e.path;e=e.node;if(e.Va)throw new P(10);if(!R(e.mode))throw new P(54);}b={type:a,Pb:{},tb:b,Cb:[]};a=a.Ra(b);a.Ra=b;b.root=a;c?Hb=a:e&&(e.Va=b,e.Ra&&e.Ra.Cb.push(b))}function ja(a,b,c){var d=T(a,{parent:!0}).node;a=ib(a);if(!a||"."===a||".."===a)throw new P(28);var e=Sb(d,a);if(e)throw new P(e);if(!d.Ga.ab)throw new P(63);return d.Ga.ab(d,a,b,c)}
|
||||
function V(a,b){return ja(a,(void 0!==b?b:511)&1023|16384,0)}function Yb(a,b,c){"undefined"==typeof c&&(c=b,b=438);ja(a,b|8192,c)}function Zb(a,b){if(!mb(a))throw new P(44);var c=T(b,{parent:!0}).node;if(!c)throw new P(44);b=ib(b);var d=Sb(c,b);if(d)throw new P(d);if(!c.Ga.symlink)throw new P(63);c.Ga.symlink(c,b,a)}function $b(a){var b=T(a,{parent:!0}).node;a=ib(a);var c=Fb(b,a),d=Tb(b,a,!0);if(d)throw new P(d);if(!b.Ga.rmdir)throw new P(63);if(c.Va)throw new P(10);b.Ga.rmdir(b,a);Ob(c)}
|
||||
function wa(a){var b=T(a,{parent:!0}).node;if(!b)throw new P(44);a=ib(a);var c=Fb(b,a),d=Tb(b,a,!1);if(d)throw new P(d);if(!b.Ga.unlink)throw new P(63);if(c.Va)throw new P(10);b.Ga.unlink(b,a);Ob(c)}function Mb(a){a=T(a).node;if(!a)throw new P(44);if(!a.Ga.readlink)throw new P(28);return mb(ha(a.parent),a.Ga.readlink(a))}function ac(a,b){a=T(a,{Sa:!b}).node;if(!a)throw new P(44);if(!a.Ga.Pa)throw new P(63);return a.Ga.Pa(a)}function bc(a){return ac(a,!0)}
|
||||
function ka(a,b){a="string"==typeof a?T(a,{Sa:!0}).node:a;if(!a.Ga.Oa)throw new P(63);a.Ga.Oa(a,{mode:b&4095|a.mode&-4096,timestamp:Date.now()})}function cc(a,b){if(0>b)throw new P(28);a="string"==typeof a?T(a,{Sa:!0}).node:a;if(!a.Ga.Oa)throw new P(63);if(R(a.mode))throw new P(31);if(32768!==(a.mode&61440))throw new P(28);var c=Pb(a,"w");if(c)throw new P(c);a.Ga.Oa(a,{size:b,timestamp:Date.now()})}
|
||||
function la(a,b,c){if(""===a)throw new P(44);if("string"==typeof b){var d={r:0,"r+":2,w:577,"w+":578,a:1089,"a+":1090}[b];if("undefined"==typeof d)throw Error(`Unknown file open mode: ${b}`);b=d}c=b&64?("undefined"==typeof c?438:c)&4095|32768:0;if("object"==typeof a)var e=a;else{a=u(a);try{e=T(a,{Sa:!(b&131072)}).node}catch(h){}}d=!1;if(b&64)if(e){if(b&128)throw new P(20);}else e=ja(a,c,0),d=!0;if(!e)throw new P(44);8192===(e.mode&61440)&&(b&=-513);if(b&65536&&!R(e.mode))throw new P(54);if(!d&&(c=
|
||||
e?40960===(e.mode&61440)?32:R(e.mode)&&("r"!==Rb(b)||b&512)?31:Pb(e,Rb(b)):44))throw new P(c);b&512&&!d&&cc(e,0);b&=-131713;e=Vb({node:e,path:ha(e),flags:b,seekable:!0,position:0,Ha:e.Ha,Fb:[],error:!1});e.Ha.open&&e.Ha.open(e);!f.logReadFiles||b&1||(dc||={},a in dc||(dc[a]=1));return e}function na(a){if(null===a.fd)throw new P(8);a.hb&&(a.hb=null);try{a.Ha.close&&a.Ha.close(a)}catch(b){throw b;}finally{Jb[a.fd]=null}a.fd=null}
|
||||
function ec(a,b,c){if(null===a.fd)throw new P(8);if(!a.seekable||!a.Ha.Ta)throw new P(70);if(0!=c&&1!=c&&2!=c)throw new P(28);a.position=a.Ha.Ta(a,b,c);a.Fb=[]}function fc(a,b,c,d,e){if(0>d||0>e)throw new P(28);if(null===a.fd)throw new P(8);if(1===(a.flags&2097155))throw new P(8);if(R(a.node.mode))throw new P(31);if(!a.Ha.read)throw new P(28);var h="undefined"!=typeof e;if(!h)e=a.position;else if(!a.seekable)throw new P(70);b=a.Ha.read(a,b,c,d,e);h||(a.position+=b);return b}
|
||||
function ma(a,b,c,d,e){if(0>d||0>e)throw new P(28);if(null===a.fd)throw new P(8);if(0===(a.flags&2097155))throw new P(8);if(R(a.node.mode))throw new P(31);if(!a.Ha.write)throw new P(28);a.seekable&&a.flags&1024&&ec(a,0,2);var h="undefined"!=typeof e;if(!h)e=a.position;else if(!a.seekable)throw new P(70);b=a.Ha.write(a,b,c,d,e,void 0);h||(a.position+=b);return b}
|
||||
function va(a){var b="binary";if("utf8"!==b&&"binary"!==b)throw Error(`Invalid encoding type "${b}"`);var c;var d=la(a,d||0);a=ac(a).size;var e=new Uint8Array(a);fc(d,e,0,a,0);"utf8"===b?c=M(e,0):"binary"===b&&(c=e);na(d);return c}function gc(){P||(P=function(a,b){this.name="ErrnoError";this.node=b;this.Eb=function(c){this.Ka=c};this.Eb(a);this.message="FS error"},P.prototype=Error(),P.prototype.constructor=P,[44].forEach(a=>{Eb[a]=new P(a);Eb[a].stack="<generic error, no stack>"}))}var hc;
|
||||
function ic(a,b,c){a=u("/dev/"+a);var d=ia(!!b,!!c);jc||=64;var e=jc++<<8|0;xb(e,{open(h){h.seekable=!1},close(){c?.buffer?.length&&c(10)},read(h,k,r,y){for(var v=0,F=0;F<y;F++){try{var H=b()}catch(pb){throw new P(29);}if(void 0===H&&0===v)throw new P(6);if(null===H||void 0===H)break;v++;k[r+F]=H}v&&(h.node.timestamp=Date.now());return v},write(h,k,r,y){for(var v=0;v<y;v++)try{c(k[r+v])}catch(F){throw new P(29);}y&&(h.node.timestamp=Date.now());return v}});Yb(a,d,e)}var jc,W={},Wb,dc;
|
||||
function kc(a,b,c){if("/"===b.charAt(0))return b;a=-100===a?"/":U(a).path;if(0==b.length){if(!c)throw new P(44);return a}return u(a+"/"+b)}
|
||||
function lc(a,b,c){try{var d=a(b)}catch(h){if(h&&h.node&&u(b)!==u(ha(h.node)))return-54;throw h;}D[c>>2]=d.dev;D[c+4>>2]=d.mode;E[c+8>>2]=d.nlink;D[c+12>>2]=d.uid;D[c+16>>2]=d.gid;D[c+20>>2]=d.rdev;J=[d.size>>>0,(I=d.size,1<=+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[c+24>>2]=J[0];D[c+28>>2]=J[1];D[c+32>>2]=4096;D[c+36>>2]=d.blocks;a=d.atime.getTime();b=d.mtime.getTime();var e=d.ctime.getTime();J=[Math.floor(a/1E3)>>>0,(I=Math.floor(a/1E3),1<=
|
||||
+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[c+40>>2]=J[0];D[c+44>>2]=J[1];E[c+48>>2]=a%1E3*1E3;J=[Math.floor(b/1E3)>>>0,(I=Math.floor(b/1E3),1<=+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[c+56>>2]=J[0];D[c+60>>2]=J[1];E[c+64>>2]=b%1E3*1E3;J=[Math.floor(e/1E3)>>>0,(I=Math.floor(e/1E3),1<=+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[c+72>>2]=J[0];
|
||||
D[c+76>>2]=J[1];E[c+80>>2]=e%1E3*1E3;J=[d.ino>>>0,(I=d.ino,1<=+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[c+88>>2]=J[0];D[c+92>>2]=J[1];return 0}var Mc=void 0;function Oc(){var a=D[+Mc>>2];Mc+=4;return a}
|
||||
var Pc=(a,b)=>b+2097152>>>0<4194305-!!a?(a>>>0)+4294967296*b:NaN,Qc=[0,31,60,91,121,152,182,213,244,274,305,335],Rc=[0,31,59,90,120,151,181,212,243,273,304,334],Sc=a=>{var b=da(a)+1,c=ea(b);c&&fa(a,q,c,b);return c},Tc={},Vc=()=>{if(!Uc){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:za||"./this.program"},b;for(b in Tc)void 0===Tc[b]?delete a[b]:a[b]=Tc[b];
|
||||
var c=[];for(b in a)c.push(`${b}=${a[b]}`);Uc=c}return Uc},Uc,ta=a=>{var b=da(a)+1,c=x(b);fa(a,q,c,b);return c},Wc=(a,b,c,d)=>{var e={string:v=>{var F=0;null!==v&&void 0!==v&&0!==v&&(F=ta(v));return F},array:v=>{var F=x(v.length);p.set(v,F);return F}};a=f["_"+a];var h=[],k=0;if(d)for(var r=0;r<d.length;r++){var y=e[c[r]];y?(0===k&&(k=pa()),h[r]=y(d[r])):h[r]=d[r]}c=a.apply(null,h);return c=function(v){0!==k&&sa(k);return"string"===b?v?M(q,v):"":"boolean"===b?!!v:v}(c)},ba=0,aa=(a,b)=>{b=1==b?x(a.length):
|
||||
ea(a.length);a.subarray||a.slice||(a=new Uint8Array(a));q.set(a,b);return b},Xc,Yc=[],Y,ua=a=>{Xc.delete(Y.get(a));Y.set(a,null);Yc.push(a)},xa=(a,b)=>{if(!Xc){Xc=new WeakMap;var c=Y.length;if(Xc)for(var d=0;d<0+c;d++){var e=Y.get(d);e&&Xc.set(e,d)}}if(c=Xc.get(a)||0)return c;if(Yc.length)c=Yc.pop();else{try{Y.grow(1)}catch(r){if(!(r instanceof RangeError))throw r;throw"Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.";}c=Y.length-1}try{Y.set(c,a)}catch(r){if(!(r instanceof TypeError))throw r;if("function"==
|
||||
typeof WebAssembly.Function){d=WebAssembly.Function;e={i:"i32",j:"i64",f:"f32",d:"f64",e:"externref",p:"i32"};for(var h={parameters:[],results:"v"==b[0]?[]:[e[b[0]]]},k=1;k<b.length;++k)h.parameters.push(e[b[k]]);b=new d(h,a)}else{d=[1];e=b.slice(0,1);b=b.slice(1);h={i:127,p:127,j:126,f:125,d:124,e:111};d.push(96);k=b.length;128>k?d.push(k):d.push(k%128|128,k>>7);for(k=0;k<b.length;++k)d.push(h[b[k]]);"v"==e?d.push(0):d.push(1,h[e]);b=[0,97,115,109,1,0,0,0,1];e=d.length;128>e?b.push(e):b.push(e%128|
|
||||
128,e>>7);b.push.apply(b,d);b.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);b=new WebAssembly.Module(new Uint8Array(b));b=(new WebAssembly.Instance(b,{e:{f:a}})).exports.f}Y.set(c,b)}Xc.set(a,c);return c};function Qb(a,b,c,d){a||=this;this.parent=a;this.Ra=a.Ra;this.Va=null;this.id=Kb++;this.name=b;this.mode=c;this.Ga={};this.Ha={};this.rdev=d}
|
||||
Object.defineProperties(Qb.prototype,{read:{get:function(){return 365===(this.mode&365)},set:function(a){a?this.mode|=365:this.mode&=-366}},write:{get:function(){return 146===(this.mode&146)},set:function(a){a?this.mode|=146:this.mode&=-147}}});gc();S=Array(4096);Xb(Q,"/");V("/tmp");V("/home");V("/home/web_user");
|
||||
(function(){V("/dev");xb(259,{read:()=>0,write:(d,e,h,k)=>k});Yb("/dev/null",259);wb(1280,zb);wb(1536,Ab);Yb("/dev/tty",1280);Yb("/dev/tty1",1536);var a=new Uint8Array(1024),b=0,c=()=>{0===b&&(b=kb(a).byteLength);return a[--b]};ic("random",c);ic("urandom",c);V("/dev/shm");V("/dev/shm/tmp")})();
|
||||
(function(){V("/proc");var a=V("/proc/self");V("/proc/self/fd");Xb({Ra(){var b=Db(a,"fd",16895,73);b.Ga={lookup(c,d){var e=U(+d);c={parent:null,Ra:{tb:"fake"},Ga:{readlink:()=>e.path}};return c.parent=c}};return b}},"/proc/self/fd")})();
|
||||
var $c={a:(a,b,c,d)=>{C(`Assertion failed: ${a?M(q,a):""}, at: `+[b?b?M(q,b):"":"unknown filename",c,d?d?M(q,d):"":"unknown function"])},h:function(a,b){try{return a=a?M(q,a):"",ka(a,b),0}catch(c){if("undefined"==typeof W||"ErrnoError"!==c.name)throw c;return-c.Ka}},H:function(a,b,c){try{b=b?M(q,b):"";b=kc(a,b);if(c&-8)return-28;var d=T(b,{Sa:!0}).node;if(!d)return-44;a="";c&4&&(a+="r");c&2&&(a+="w");c&1&&(a+="x");return a&&Pb(d,a)?-2:0}catch(e){if("undefined"==typeof W||"ErrnoError"!==e.name)throw e;
|
||||
return-e.Ka}},i:function(a,b){try{var c=U(a);ka(c.node,b);return 0}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return-d.Ka}},g:function(a){try{var b=U(a).node;var c="string"==typeof b?T(b,{Sa:!0}).node:b;if(!c.Ga.Oa)throw new P(63);c.Ga.Oa(c,{timestamp:Date.now()});return 0}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return-d.Ka}},b:function(a,b,c){Mc=c;try{var d=U(a);switch(b){case 0:var e=Oc();if(0>e)return-28;for(;Jb[e];)e++;return Vb(d,e).fd;case 1:case 2:return 0;
|
||||
case 3:return d.flags;case 4:return e=Oc(),d.flags|=e,0;case 5:return e=Oc(),Na[e+0>>1]=2,0;case 6:case 7:return 0;case 16:case 8:return-28;case 9:return D[Zc()>>2]=28,-1;default:return-28}}catch(h){if("undefined"==typeof W||"ErrnoError"!==h.name)throw h;return-h.Ka}},f:function(a,b){try{var c=U(a);return lc(ac,c.path,b)}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return-d.Ka}},n:function(a,b,c){b=Pc(b,c);try{if(isNaN(b))return 61;var d=U(a);if(0===(d.flags&2097155))throw new P(28);
|
||||
cc(d.node,b);return 0}catch(e){if("undefined"==typeof W||"ErrnoError"!==e.name)throw e;return-e.Ka}},C:function(a,b){try{if(0===b)return-28;var c=da("/")+1;if(b<c)return-68;fa("/",q,a,b);return c}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return-d.Ka}},F:function(a,b){try{return a=a?M(q,a):"",lc(bc,a,b)}catch(c){if("undefined"==typeof W||"ErrnoError"!==c.name)throw c;return-c.Ka}},z:function(a,b,c){try{return b=b?M(q,b):"",b=kc(a,b),b=u(b),"/"===b[b.length-1]&&(b=b.substr(0,
|
||||
b.length-1)),V(b,c),0}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return-d.Ka}},E:function(a,b,c,d){try{b=b?M(q,b):"";var e=d&256;b=kc(a,b,d&4096);return lc(e?bc:ac,b,c)}catch(h){if("undefined"==typeof W||"ErrnoError"!==h.name)throw h;return-h.Ka}},y:function(a,b,c,d){Mc=d;try{b=b?M(q,b):"";b=kc(a,b);var e=d?Oc():0;return la(b,c,e).fd}catch(h){if("undefined"==typeof W||"ErrnoError"!==h.name)throw h;return-h.Ka}},w:function(a,b,c,d){try{b=b?M(q,b):"";b=kc(a,b);if(0>=d)return-28;
|
||||
var e=Mb(b),h=Math.min(d,da(e)),k=p[c+h];fa(e,q,c,d+1);p[c+h]=k;return h}catch(r){if("undefined"==typeof W||"ErrnoError"!==r.name)throw r;return-r.Ka}},v:function(a){try{return a=a?M(q,a):"",$b(a),0}catch(b){if("undefined"==typeof W||"ErrnoError"!==b.name)throw b;return-b.Ka}},G:function(a,b){try{return a=a?M(q,a):"",lc(ac,a,b)}catch(c){if("undefined"==typeof W||"ErrnoError"!==c.name)throw c;return-c.Ka}},r:function(a,b,c){try{return b=b?M(q,b):"",b=kc(a,b),0===c?wa(b):512===c?$b(b):C("Invalid flags passed to unlinkat"),
|
||||
0}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return-d.Ka}},q:function(a,b,c){try{b=b?M(q,b):"";b=kc(a,b,!0);if(c){var d=E[c>>2]+4294967296*D[c+4>>2],e=D[c+8>>2];h=1E3*d+e/1E6;c+=16;d=E[c>>2]+4294967296*D[c+4>>2];e=D[c+8>>2];k=1E3*d+e/1E6}else var h=Date.now(),k=h;a=h;var r=T(b,{Sa:!0}).node;r.Ga.Oa(r,{timestamp:Math.max(a,k)});return 0}catch(y){if("undefined"==typeof W||"ErrnoError"!==y.name)throw y;return-y.Ka}},l:function(a,b,c){a=new Date(1E3*Pc(a,b));D[c>>2]=a.getSeconds();
|
||||
D[c+4>>2]=a.getMinutes();D[c+8>>2]=a.getHours();D[c+12>>2]=a.getDate();D[c+16>>2]=a.getMonth();D[c+20>>2]=a.getFullYear()-1900;D[c+24>>2]=a.getDay();b=a.getFullYear();D[c+28>>2]=(0!==b%4||0===b%100&&0!==b%400?Rc:Qc)[a.getMonth()]+a.getDate()-1|0;D[c+36>>2]=-(60*a.getTimezoneOffset());b=(new Date(a.getFullYear(),6,1)).getTimezoneOffset();var d=(new Date(a.getFullYear(),0,1)).getTimezoneOffset();D[c+32>>2]=(b!=d&&a.getTimezoneOffset()==Math.min(d,b))|0},j:function(a,b,c,d,e,h,k,r){e=Pc(e,h);try{if(isNaN(e))return 61;
|
||||
var y=U(d);if(0!==(b&2)&&0===(c&2)&&2!==(y.flags&2097155))throw new P(2);if(1===(y.flags&2097155))throw new P(2);if(!y.Ha.bb)throw new P(43);var v=y.Ha.bb(y,a,e,b,c);var F=v.Db;D[k>>2]=v.ub;E[r>>2]=F;return 0}catch(H){if("undefined"==typeof W||"ErrnoError"!==H.name)throw H;return-H.Ka}},k:function(a,b,c,d,e,h,k){h=Pc(h,k);try{if(isNaN(h))return 61;var r=U(e);if(c&2){if(32768!==(r.node.mode&61440))throw new P(43);if(!(d&2)){var y=q.slice(a,a+b);r.Ha.cb&&r.Ha.cb(r,y,h,b,d)}}}catch(v){if("undefined"==
|
||||
typeof W||"ErrnoError"!==v.name)throw v;return-v.Ka}},s:(a,b,c)=>{function d(y){return(y=y.toTimeString().match(/\(([A-Za-z ]+)\)$/))?y[1]:"GMT"}var e=(new Date).getFullYear(),h=new Date(e,0,1),k=new Date(e,6,1);e=h.getTimezoneOffset();var r=k.getTimezoneOffset();E[a>>2]=60*Math.max(e,r);D[b>>2]=Number(e!=r);a=d(h);b=d(k);a=Sc(a);b=Sc(b);r<e?(E[c>>2]=a,E[c+4>>2]=b):(E[c>>2]=b,E[c+4>>2]=a)},d:()=>Date.now(),t:()=>2147483648,c:()=>performance.now(),o:a=>{var b=q.length;a>>>=0;if(2147483648<a)return!1;
|
||||
for(var c=1;4>=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);var e=Math;d=Math.max(a,d);a:{e=(e.min.call(e,2147483648,d+(65536-d%65536)%65536)-La.buffer.byteLength+65535)/65536;try{La.grow(e);Qa();var h=1;break a}catch(k){}h=void 0}if(h)return!0}return!1},A:(a,b)=>{var c=0;Vc().forEach((d,e)=>{var h=b+c;e=E[a+4*e>>2]=h;for(h=0;h<d.length;++h)p[e++>>0]=d.charCodeAt(h);p[e>>0]=0;c+=d.length+1});return 0},B:(a,b)=>{var c=Vc();E[a>>2]=c.length;var d=0;c.forEach(e=>d+=e.length+1);E[b>>2]=d;return 0},
|
||||
e:function(a){try{var b=U(a);na(b);return 0}catch(c){if("undefined"==typeof W||"ErrnoError"!==c.name)throw c;return c.Ka}},p:function(a,b){try{var c=U(a);p[b>>0]=c.tty?2:R(c.mode)?3:40960===(c.mode&61440)?7:4;Na[b+2>>1]=0;J=[0,(I=0,1<=+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[b+8>>2]=J[0];D[b+12>>2]=J[1];J=[0,(I=0,1<=+Math.abs(I)?0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[b+16>>2]=J[0];D[b+20>>2]=J[1];
|
||||
return 0}catch(d){if("undefined"==typeof W||"ErrnoError"!==d.name)throw d;return d.Ka}},x:function(a,b,c,d){try{a:{var e=U(a);a=b;for(var h,k=b=0;k<c;k++){var r=E[a>>2],y=E[a+4>>2];a+=8;var v=fc(e,p,r,y,h);if(0>v){var F=-1;break a}b+=v;if(v<y)break;"undefined"!==typeof h&&(h+=v)}F=b}E[d>>2]=F;return 0}catch(H){if("undefined"==typeof W||"ErrnoError"!==H.name)throw H;return H.Ka}},m:function(a,b,c,d,e){b=Pc(b,c);try{if(isNaN(b))return 61;var h=U(a);ec(h,b,d);J=[h.position>>>0,(I=h.position,1<=+Math.abs(I)?
|
||||
0<I?+Math.floor(I/4294967296)>>>0:~~+Math.ceil((I-+(~~I>>>0))/4294967296)>>>0:0)];D[e>>2]=J[0];D[e+4>>2]=J[1];h.hb&&0===b&&0===d&&(h.hb=null);return 0}catch(k){if("undefined"==typeof W||"ErrnoError"!==k.name)throw k;return k.Ka}},D:function(a){try{var b=U(a);return b.Ha?.fsync?b.Ha.fsync(b):0}catch(c){if("undefined"==typeof W||"ErrnoError"!==c.name)throw c;return c.Ka}},u:function(a,b,c,d){try{a:{var e=U(a);a=b;for(var h,k=b=0;k<c;k++){var r=E[a>>2],y=E[a+4>>2];a+=8;var v=ma(e,p,r,y,h);if(0>v){var F=
|
||||
-1;break a}b+=v;"undefined"!==typeof h&&(h+=v)}F=b}E[d>>2]=F;return 0}catch(H){if("undefined"==typeof W||"ErrnoError"!==H.name)throw H;return H.Ka}}},Z=function(){function a(c){Z=c.exports;La=Z.I;Qa();Y=Z.Aa;Sa.unshift(Z.J);G--;f.monitorRunDependencies?.(G);0==G&&(null!==Wa&&(clearInterval(Wa),Wa=null),Xa&&(c=Xa,Xa=null,c()));return Z}var b={a:$c};G++;f.monitorRunDependencies?.(G);if(f.instantiateWasm)try{return f.instantiateWasm(b,a)}catch(c){return B(`Module.instantiateWasm callback failed with error: ${c}`),
|
||||
!1}db(b,function(c){a(c.instance)});return{}}();f._sqlite3_free=a=>(f._sqlite3_free=Z.K)(a);f._sqlite3_value_text=a=>(f._sqlite3_value_text=Z.L)(a);var Zc=()=>(Zc=Z.M)();f._sqlite3_prepare_v2=(a,b,c,d,e)=>(f._sqlite3_prepare_v2=Z.N)(a,b,c,d,e);f._sqlite3_step=a=>(f._sqlite3_step=Z.O)(a);f._sqlite3_reset=a=>(f._sqlite3_reset=Z.P)(a);f._sqlite3_exec=(a,b,c,d,e)=>(f._sqlite3_exec=Z.Q)(a,b,c,d,e);f._sqlite3_finalize=a=>(f._sqlite3_finalize=Z.R)(a);
|
||||
f._sqlite3_column_name=(a,b)=>(f._sqlite3_column_name=Z.S)(a,b);f._sqlite3_column_text=(a,b)=>(f._sqlite3_column_text=Z.T)(a,b);f._sqlite3_column_type=(a,b)=>(f._sqlite3_column_type=Z.U)(a,b);f._sqlite3_errmsg=a=>(f._sqlite3_errmsg=Z.V)(a);f._sqlite3_clear_bindings=a=>(f._sqlite3_clear_bindings=Z.W)(a);f._sqlite3_value_blob=a=>(f._sqlite3_value_blob=Z.X)(a);f._sqlite3_value_bytes=a=>(f._sqlite3_value_bytes=Z.Y)(a);f._sqlite3_value_double=a=>(f._sqlite3_value_double=Z.Z)(a);
|
||||
f._sqlite3_value_int=a=>(f._sqlite3_value_int=Z._)(a);f._sqlite3_value_type=a=>(f._sqlite3_value_type=Z.$)(a);f._sqlite3_result_blob=(a,b,c,d)=>(f._sqlite3_result_blob=Z.aa)(a,b,c,d);f._sqlite3_result_double=(a,b)=>(f._sqlite3_result_double=Z.ba)(a,b);f._sqlite3_result_error=(a,b,c)=>(f._sqlite3_result_error=Z.ca)(a,b,c);f._sqlite3_result_int=(a,b)=>(f._sqlite3_result_int=Z.da)(a,b);f._sqlite3_result_int64=(a,b,c)=>(f._sqlite3_result_int64=Z.ea)(a,b,c);
|
||||
f._sqlite3_result_null=a=>(f._sqlite3_result_null=Z.fa)(a);f._sqlite3_result_text=(a,b,c,d)=>(f._sqlite3_result_text=Z.ga)(a,b,c,d);f._sqlite3_aggregate_context=(a,b)=>(f._sqlite3_aggregate_context=Z.ha)(a,b);f._sqlite3_column_count=a=>(f._sqlite3_column_count=Z.ia)(a);f._sqlite3_data_count=a=>(f._sqlite3_data_count=Z.ja)(a);f._sqlite3_column_blob=(a,b)=>(f._sqlite3_column_blob=Z.ka)(a,b);f._sqlite3_column_bytes=(a,b)=>(f._sqlite3_column_bytes=Z.la)(a,b);
|
||||
f._sqlite3_column_double=(a,b)=>(f._sqlite3_column_double=Z.ma)(a,b);f._sqlite3_bind_blob=(a,b,c,d,e)=>(f._sqlite3_bind_blob=Z.na)(a,b,c,d,e);f._sqlite3_bind_double=(a,b,c)=>(f._sqlite3_bind_double=Z.oa)(a,b,c);f._sqlite3_bind_int=(a,b,c)=>(f._sqlite3_bind_int=Z.pa)(a,b,c);f._sqlite3_bind_text=(a,b,c,d,e)=>(f._sqlite3_bind_text=Z.qa)(a,b,c,d,e);f._sqlite3_bind_parameter_index=(a,b)=>(f._sqlite3_bind_parameter_index=Z.ra)(a,b);f._sqlite3_sql=a=>(f._sqlite3_sql=Z.sa)(a);
|
||||
f._sqlite3_normalized_sql=a=>(f._sqlite3_normalized_sql=Z.ta)(a);f._sqlite3_changes=a=>(f._sqlite3_changes=Z.ua)(a);f._sqlite3_close_v2=a=>(f._sqlite3_close_v2=Z.va)(a);f._sqlite3_create_function_v2=(a,b,c,d,e,h,k,r,y)=>(f._sqlite3_create_function_v2=Z.wa)(a,b,c,d,e,h,k,r,y);f._sqlite3_open=(a,b)=>(f._sqlite3_open=Z.xa)(a,b);var ea=f._malloc=a=>(ea=f._malloc=Z.ya)(a),ca=f._free=a=>(ca=f._free=Z.za)(a);f._RegisterExtensionFunctions=a=>(f._RegisterExtensionFunctions=Z.Ba)(a);
|
||||
var Gb=(a,b)=>(Gb=Z.Ca)(a,b),pa=()=>(pa=Z.Da)(),sa=a=>(sa=Z.Ea)(a),x=a=>(x=Z.Fa)(a);f.stackAlloc=x;f.stackSave=pa;f.stackRestore=sa;f.cwrap=(a,b,c,d)=>{var e=!c||c.every(h=>"number"===h||"boolean"===h);return"string"!==b&&e&&!d?f["_"+a]:function(){return Wc(a,b,c,arguments)}};f.addFunction=xa;f.removeFunction=ua;f.UTF8ToString=ra;f.ALLOC_NORMAL=ba;f.allocate=aa;f.allocateUTF8OnStack=ta;var ad;Xa=function bd(){ad||cd();ad||(Xa=bd)};
|
||||
function cd(){function a(){if(!ad&&(ad=!0,f.calledRun=!0,!Ma)){f.noFSInit||hc||(hc=!0,gc(),f.stdin=f.stdin,f.stdout=f.stdout,f.stderr=f.stderr,f.stdin?ic("stdin",f.stdin):Zb("/dev/tty","/dev/stdin"),f.stdout?ic("stdout",null,f.stdout):Zb("/dev/tty","/dev/stdout"),f.stderr?ic("stderr",null,f.stderr):Zb("/dev/tty1","/dev/stderr"),la("/dev/stdin",0),la("/dev/stdout",1),la("/dev/stderr",1));Lb=!1;eb(Sa);if(f.onRuntimeInitialized)f.onRuntimeInitialized();if(f.postRun)for("function"==typeof f.postRun&&
|
||||
(f.postRun=[f.postRun]);f.postRun.length;){var b=f.postRun.shift();Ta.unshift(b)}eb(Ta)}}if(!(0<G)){if(f.preRun)for("function"==typeof f.preRun&&(f.preRun=[f.preRun]);f.preRun.length;)Va();eb(Ra);0<G||(f.setStatus?(f.setStatus("Running..."),setTimeout(function(){setTimeout(function(){f.setStatus("")},1);a()},1)):a())}}if(f.preInit)for("function"==typeof f.preInit&&(f.preInit=[f.preInit]);0<f.preInit.length;)f.preInit.pop()();cd();
|
||||
|
||||
|
||||
// The shell-pre.js and emcc-generated code goes above
|
||||
return Module;
|
||||
}); // The end of the promise being returned
|
||||
|
||||
return initSqlJsPromise;
|
||||
} // The end of our initSqlJs function
|
||||
|
||||
// This bit below is copied almost exactly from what you get when you use the MODULARIZE=1 flag with emcc
|
||||
// However, we don't want to use the emcc modularization. See shell-pre.js
|
||||
if (typeof exports === 'object' && typeof module === 'object'){
|
||||
module.exports = initSqlJs;
|
||||
// This will allow the module to be used in ES6 or CommonJS
|
||||
module.exports.default = initSqlJs;
|
||||
}
|
||||
else if (typeof define === 'function' && define['amd']) {
|
||||
define([], function() { return initSqlJs; });
|
||||
}
|
||||
else if (typeof exports === 'object'){
|
||||
exports["Module"] = initSqlJs;
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,41 @@
|
|||
/* 기본 커스텀 스타일: PicoCSS 위에 얹기 */
|
||||
:root{
|
||||
--brand: #2563eb;
|
||||
--bg-elev: color-mix(in oklab, var(--pico-background-color), black 6%);
|
||||
}
|
||||
|
||||
html, body { height: 100%; }
|
||||
body { background: var(--pico-background-color); }
|
||||
|
||||
.tabs, .subtabs { display:flex; gap:.5rem; margin-bottom: .75rem; }
|
||||
.tabs.seg, .subtabs.seg{ background: var(--bg-elev); padding:.25rem; border-radius: .8rem; box-shadow: inset 0 1px 0 rgba(255,255,255,.06), inset 0 -1px 0 rgba(0,0,0,.25); }
|
||||
.tab-button { border: 0; background: transparent; padding:.5rem .9rem; border-radius: .6rem; transition: all .15s ease; }
|
||||
.tab-button[aria-selected="true"]{ background: var(--brand); color:white; box-shadow: 0 2px 8px color-mix(in oklab, var(--brand), black 40%); }
|
||||
.tab-button[aria-selected="false"]{ color: #111; }
|
||||
[data-theme="dark"] .tab-button[aria-selected="false"]{ color: #d1d5db; }
|
||||
.tab-button.small{ padding:.35rem .7rem; font-size:.95rem; }
|
||||
|
||||
.grid{ display:grid; grid-template-columns: 1fr; gap: .75rem; }
|
||||
@media (min-width: 720px){
|
||||
.grid{ grid-template-columns: 1fr 1fr; }
|
||||
}
|
||||
|
||||
.card-list .item{ cursor:pointer; border:1px solid var(--pico-muted-border-color); padding:.9rem; border-radius:.9rem; background: var(--bg-elev); }
|
||||
.card-list .item header{ display:flex; align-items:baseline; gap:.75rem; }
|
||||
.card-list .item .code{ font-weight:700; min-width:116px; color: var(--brand); }
|
||||
.card-list .item .title{ font-weight:600; }
|
||||
.card-list .item:hover{ border-color: var(--brand); box-shadow: 0 4px 20px rgba(0,0,0,.35); transform: translateY(-1px); }
|
||||
|
||||
.modal-card header{ display:flex; justify-content:space-between; align-items:center; gap:1rem; }
|
||||
.modal-card .content{ max-height:min(68vh, 600px); overflow:auto; }
|
||||
.prewrap{ white-space:pre-wrap; }
|
||||
|
||||
dialog::backdrop{ backdrop-filter: blur(2px); }
|
||||
dialog{ border: none; border-radius: 12px; padding: 0; }
|
||||
.modal-card{ padding: 1rem 1.25rem; }
|
||||
|
||||
/* iOS PWA safe-area */
|
||||
:root { --safe-top: env(safe-area-inset-top); --safe-bottom: env(safe-area-inset-bottom); }
|
||||
body { padding-bottom: var(--safe-bottom); }
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
const CACHE_NAME = 'faultcodes-v1';
|
||||
const ASSETS = [
|
||||
'/',
|
||||
'/static/styles.css',
|
||||
'/static/app.js',
|
||||
'/static/manifest.webmanifest'
|
||||
];
|
||||
|
||||
self.addEventListener('install', (e) => {
|
||||
e.waitUntil((async () => {
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
await cache.addAll(ASSETS);
|
||||
})());
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (e) => {
|
||||
e.waitUntil((async () => {
|
||||
const keys = await caches.keys();
|
||||
await Promise.all(keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k)));
|
||||
})());
|
||||
self.clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (e) => {
|
||||
const req = e.request;
|
||||
if (req.method !== 'GET') return;
|
||||
e.respondWith((async () => {
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
const cached = await cache.match(req);
|
||||
if (cached) return cached;
|
||||
try {
|
||||
const fresh = await fetch(req);
|
||||
if (fresh && fresh.ok) cache.put(req, fresh.clone());
|
||||
return fresh;
|
||||
} catch {
|
||||
return cached || Response.error();
|
||||
}
|
||||
})());
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<!doctype html>
|
||||
<html lang="ko" data-theme="auto">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>{{ app_name }}</title>
|
||||
<link rel="icon" href="data:,">
|
||||
<link rel="manifest" href="/static/manifest.webmanifest">
|
||||
<meta name="theme-color" content="#0f172a">
|
||||
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@2.0.6/css/pico.min.css">
|
||||
<link rel="stylesheet" href="/static/styles.css">
|
||||
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
|
||||
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
|
||||
<script defer src="/static/app.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="container">
|
||||
<nav>
|
||||
<ul>
|
||||
<li><strong>{{ app_name }}</strong></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<button class="contrast" id="themeToggle" aria-label="테마 전환">🌙</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<div class="tabs seg" id="topSections" role="tablist">
|
||||
<button class="tab-button" aria-selected="true"
|
||||
hx-get="/sb?section=fault"
|
||||
hx-include="#sbManufacturer"
|
||||
hx-target="#tabPanel" hx-swap="innerHTML">고장코드</button>
|
||||
<button class="tab-button" aria-selected="false"
|
||||
hx-get="/sb?section=tcms"
|
||||
hx-include="#sbManufacturer"
|
||||
hx-target="#tabPanel" hx-swap="innerHTML">TCMS 코드</button>
|
||||
<button class="tab-button" aria-selected="false"
|
||||
hx-get="/sb?section=mmicode"
|
||||
hx-include="#sbManufacturer"
|
||||
hx-target="#tabPanel" hx-swap="innerHTML">MMI 코드</button>
|
||||
<button class="tab-button" aria-selected="false"
|
||||
hx-get="/sb?section=emergency"
|
||||
hx-include="#sbManufacturer"
|
||||
hx-target="#tabPanel" hx-swap="innerHTML">응급조치요령</button>
|
||||
</div>
|
||||
|
||||
<section id="tabPanel" hx-get="/sb" hx-trigger="load" hx-swap="innerHTML">
|
||||
<!-- 제조사 탭 컨텐츠 로드 -->
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<dialog id="modal"></dialog>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<article class="modal-card">
|
||||
<header>
|
||||
<h3>[{{ row.code }}] {{ row.title }}</h3>
|
||||
<button class="outline" _="on click call document.getElementById('modal').close() then put '' into #modal">닫기</button>
|
||||
</header>
|
||||
<section class="content">
|
||||
<p><strong>제조사</strong>: {{ row.manufacturer_name }}{% if row.category_name %} · <strong>타입</strong>: {{ row.category_name }}{% endif %}</p>
|
||||
<hr>
|
||||
<h5>고장 상세</h5>
|
||||
<p class="prewrap">{{ row.details or '—' }}</p>
|
||||
<h5>반응</h5>
|
||||
<p class="prewrap">{{ row.action or '—' }}</p>
|
||||
<h5>검지 조건</h5>
|
||||
<p class="prewrap">{{ row.condition or '—' }}</p>
|
||||
</section>
|
||||
</article>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<div class="list">
|
||||
{% if rows %}
|
||||
{% for r in rows %}
|
||||
<article class="item" hx-get="/faults/{{ r.id }}" hx-target="#modal" hx-swap="innerHTML show:top">
|
||||
<header>
|
||||
<div class="code">{{ r.code }}</div>
|
||||
<div class="title">{{ r.title }}</div>
|
||||
</header>
|
||||
<footer>
|
||||
<small>{{ r.category_name or '분류없음' }}</small>
|
||||
</footer>
|
||||
</article>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p>검색 결과가 없습니다.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<section _="on load set #currentSectionRoot.value to '{{ section }}' then if '{{ section }}' != 'fault' then call (function(){ const btn = document.querySelector(`#subtabs .tab-button[data-section='{{ section }}']`); if(btn){ document.querySelectorAll('#subtabs .tab-button').forEach(x=>x.removeAttribute('aria-selected')); btn.setAttribute('aria-selected','true'); } })() end">
|
||||
<div class="subtabs seg" id="subtabs" role="tablist">
|
||||
<button class="tab-button small" data-section="fault" aria-selected="{{ 'true' if section=='fault' else 'false' }}"
|
||||
hx-get="/faults/list?manufacturer={{ manufacturer.slug }}§ion=fault"
|
||||
hx-target="#faultList"
|
||||
_="on click call document.querySelectorAll('#subtabs .tab-button').forEach(x => x.removeAttribute('aria-selected')); then me.setAttribute('aria-selected','true'); then set #currentSection.value to 'fault'; then set #currentSectionRoot.value to 'fault'">
|
||||
고장코드
|
||||
</button>
|
||||
<button class="tab-button small" data-section="tcms" aria-selected="{{ 'true' if section=='tcms' else 'false' }}"
|
||||
hx-get="/faults/list?manufacturer={{ manufacturer.slug }}§ion=tcms"
|
||||
hx-target="#faultList"
|
||||
_="on click call document.querySelectorAll('#subtabs .tab-button').forEach(x => x.removeAttribute('aria-selected')); then me.setAttribute('aria-selected','true'); then set #currentSection.value to 'tcms'; then set #currentSectionRoot.value to 'tcms'">
|
||||
TCMS 코드
|
||||
</button>
|
||||
<button class="tab-button small" data-section="emergency" aria-selected="{{ 'true' if section=='emergency' else 'false' }}"
|
||||
hx-get="/faults/list?manufacturer={{ manufacturer.slug }}§ion=emergency"
|
||||
hx-target="#faultList"
|
||||
_="on click call document.querySelectorAll('#subtabs .tab-button').forEach(x => x.removeAttribute('aria-selected')); then me.setAttribute('aria-selected','true'); then set #currentSection.value to 'emergency'; then set #currentSectionRoot.value to 'emergency'">
|
||||
응급조치요령
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label for="categorySelect">장치분류 선택</label>
|
||||
<select id="categorySelect"
|
||||
hx-get="/faults/list?manufacturer={{ manufacturer.slug }}"
|
||||
hx-include="#searchBox, #currentSection"
|
||||
hx-target="#faultList"
|
||||
hx-params="*"
|
||||
hx-trigger="change">
|
||||
<option value="">전체</option>
|
||||
{% for c in categories|sort(attribute='name') %}
|
||||
<option value="{{ c.id }}">{{ c.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="searchBox">검색어</label>
|
||||
<input id="searchBox" name="q" placeholder="검색어 입력"
|
||||
hx-get="/faults/list?manufacturer={{ manufacturer.slug }}"
|
||||
hx-trigger="keyup changed delay:200ms, search"
|
||||
hx-target="#faultList"
|
||||
hx-include="#categorySelect, #currentSection"
|
||||
>
|
||||
<input type="hidden" id="currentSection" name="section" value="fault">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="faultList" class="card-list" hx-get="/faults/list?manufacturer={{ manufacturer.slug }}§ion={{ section }}" hx-trigger="load">
|
||||
<!-- 리스트 -->
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<article class="card">
|
||||
<header>
|
||||
<strong>Supabase 연결 오류</strong>
|
||||
</header>
|
||||
<p class="prewrap">{{ error_message }}</p>
|
||||
{% if supabase_url %}
|
||||
<p>
|
||||
<small>확인: {{ supabase_url }} 가 내부망에서 접근 가능한지 확인해 주세요.</small>
|
||||
</p>
|
||||
{% endif %}
|
||||
</article>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<article class="modal-card">
|
||||
<header>
|
||||
<h3>[{{ row.f_code }}] {{ row.f_name }}</h3>
|
||||
<button class="outline" _="on click call document.getElementById('modal').close() then put '' into #modal">닫기</button>
|
||||
</header>
|
||||
<section class="content">
|
||||
<p>
|
||||
<strong>제작사</strong>: {{ row.manufacturer or '—' }}
|
||||
{% if row.device %} · <strong>장치</strong>: {{ row.device }}{% endif %}
|
||||
{% if row.car_type %} · <strong>호차</strong>: {{ row.car_type }}{% endif %}
|
||||
{% if row.car_id %} · <strong>차량분류</strong>: {{ row.car_id }}{% endif %}
|
||||
</p>
|
||||
<hr>
|
||||
<h5>고장등급(리스트)</h5>
|
||||
<p class="prewrap">{{ row.f_class or '—' }}</p>
|
||||
<h5>고장등급(해설)</h5>
|
||||
<p class="prewrap">{{ row.grade or '—' }}</p>
|
||||
<h5>고장상세</h5>
|
||||
<p class="prewrap">{{ row.fault_detail or '—' }}</p>
|
||||
<h5>고장반응</h5>
|
||||
<p class="prewrap">{{ row.fault_reaction or '—' }}</p>
|
||||
<h5>검지조건</h5>
|
||||
<p class="prewrap">{{ row.fault_detection or '—' }}</p>
|
||||
<h5>소거조건</h5>
|
||||
<p class="prewrap">{{ row.fault_clear or '—' }}</p>
|
||||
<h5>조치방법</h5>
|
||||
<p class="prewrap">{{ row.fault_action or '—' }}</p>
|
||||
<h5>회로도면</h5>
|
||||
<p class="prewrap">{{ row.fault_schematics or '—' }}</p>
|
||||
</section>
|
||||
</article>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<div class="list" {% if page > 0 %} style="display:contents;" {% endif %}>
|
||||
{% for r in rows %}
|
||||
<article class="item" hx-get="/sb/faults/{{ r.f_code }}" hx-target="#modal" hx-swap="innerHTML show:top">
|
||||
<header>
|
||||
<div class="code">{{ r.f_code }}</div>
|
||||
<div class="title">{{ r.f_name }} {% if r.fault_detail %}<span title="고장상세 있음">🔎</span>{% endif %}</div>
|
||||
</header>
|
||||
<footer>
|
||||
<small>{{ r.manufacturer or '—' }}{% if r.device %} · {{ r.device }}{% endif %}{% if r.car_type %} · {{ r.car_type }}{% endif %}{% if r.alias_name %} · {{ r.alias_name }}{% endif %}</small>
|
||||
</footer>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if rows|length >= page_size %}
|
||||
<div class="load-more-trigger"
|
||||
hx-get="/sb/faults/list?page={{ page + 1 }}&{{ query_params_string }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-trigger="revealed">
|
||||
<article class="item placeholder">Loading...</article>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
<section>
|
||||
<div class="filter-row" style="display: flex; flex-wrap: wrap; gap: 0.7rem; align-items: end; margin-bottom: 1rem;">
|
||||
<div style="flex: 1; min-width:160px;">
|
||||
<label for="sbManufacturer">제작사</label>
|
||||
<select id="sbManufacturer" name="manufacturer" hx-get="/sb" hx-include="this" hx-target="#tabPanel" hx-params="*" hx-trigger="change">
|
||||
<option value="" {% if selected_manufacturer=='' %}selected{% endif %}>전체</option>
|
||||
{% for m in manufacturers %}
|
||||
<option value="{{ m }}" {% if m==selected_manufacturer %}selected{% endif %}>{{ m }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% if section == "tcms" %}
|
||||
<div style="flex: 1; min-width:140px;">
|
||||
<label for="sbClassification">분류</label>
|
||||
<select id="sbClassification"
|
||||
hx-get="/sb/signals/list"
|
||||
hx-include="#sbManufacturer, #sbClassification, #sbAliasName, #sbSearch, #sbGroupCode"
|
||||
hx-target="#sbList"
|
||||
hx-params="*"
|
||||
hx-trigger="change">
|
||||
<option value="" {% if selected_classification=='' %}selected{% endif %}>전체</option>
|
||||
{% for cl in signal_classifications %}
|
||||
<option value="{{ cl }}" {% if cl==selected_classification %}selected{% endif %}>{{ cl }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div style="flex:1; min-width:140px;">
|
||||
<label for="sbAliasName">차량분류</label>
|
||||
<select id="sbAliasName" name="alias_name" hx-get="/sb/signals/list" hx-include="#sbManufacturer, #sbClassification, #sbAliasName, #sbSearch, #sbGroupCode" hx-target="#sbList" hx-params="*" hx-trigger="change">
|
||||
<option value="" {% if selected_alias_name=='' %}selected{% endif %}>전체</option>
|
||||
{% for an in alias_names %}
|
||||
<option value="{{ an }}" {% if an==selected_alias_name %}selected{% endif %}>{{ an }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="flex: 1; min-width:140px;">
|
||||
<label for="sbDevice">장치분류</label>
|
||||
<select id="sbDevice" name="device" hx-get="/sb/faults/list" hx-include="#sbManufacturer, #sbDevice, #sbCarType, #sbAliasName, #sbSearch, #sbGroupCode" hx-target="#sbList" hx-params="*" hx-trigger="change">
|
||||
<option value="" {% if selected_device=='' %}selected{% endif %}>전체</option>
|
||||
{% for d in devices|sort %}
|
||||
<option value="{{ d }}" {% if d==selected_device %}selected{% endif %}>{{ d }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div style="flex: 1; min-width:100px;">
|
||||
<label for="sbCarType">호차</label>
|
||||
<select id="sbCarType" name="car_type" hx-get="/sb/faults/list" hx-include="#sbManufacturer, #sbDevice, #sbCarType, #sbAliasName, #sbSearch, #sbGroupCode" hx-target="#sbList" hx-params="*" hx-trigger="change">
|
||||
<option value="" {% if selected_car_type=='' %}selected{% endif %}>전체</option>
|
||||
{% for ct in car_types %}
|
||||
<option value="{{ ct }}" {% if ct==selected_car_type %}selected{% endif %}>{{ ct }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div style="flex:1; min-width:140px;">
|
||||
<label for="sbAliasName">차량분류</label>
|
||||
<select id="sbAliasName" name="alias_name" hx-get="/sb/faults/list" hx-include="#sbManufacturer, #sbDevice, #sbCarType, #sbAliasName, #sbSearch, #sbGroupCode" hx-target="#sbList" hx-params="*" hx-trigger="change">
|
||||
<option value="" {% if selected_alias_name=='' %}selected{% endif %}>전체</option>
|
||||
{% for an in alias_names %}
|
||||
<option value="{{ an }}" {% if an==selected_alias_name %}selected{% endif %}>{{ an }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="search-row" style="display:flex; align-items:center; gap:1rem; margin-bottom:1.2rem;">
|
||||
<div style="flex:4;">
|
||||
<label for="sbSearch">검색어</label>
|
||||
<input id="sbSearch" name="q" value="{{ q }}" placeholder="{% if section=='tcms' %}약어/설명 검색{% else %}코드/고장명 검색{% endif %}"
|
||||
hx-get="{% if section=='tcms' %}/sb/signals/list{% else %}/sb/faults/list{% endif %}"
|
||||
hx-trigger="keyup changed delay:200ms, search"
|
||||
hx-target="#sbList"
|
||||
hx-include="#sbManufacturer, #sbDevice, #sbCarType, #sbAliasName, #sbClassification, #sbSearch, #sbGroupCode">
|
||||
</div>
|
||||
<div style="flex:1; min-width:110px; text-align:right; align-self:end;">
|
||||
<label for="sbGroupCode" style="margin-bottom:.45em;display:flex;align-items:center;gap:.4em;justify-content:flex-end;">
|
||||
<input type="checkbox" id="sbGroupCode" name="group_code" value="on"
|
||||
hx-get="{% if section=='tcms' %}/sb/signals/list{% else %}/sb/faults/list{% endif %}"
|
||||
hx-target="#sbList"
|
||||
hx-include="#sbManufacturer, #sbDevice, #sbCarType, #sbAliasName, #sbClassification, #sbSearch, #sbGroupCode"
|
||||
hx-trigger="change" {% if selected_group_code=='on' %}checked{% endif %}>
|
||||
코드 묶기
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if section == 'tcms' %}
|
||||
<div id="sbList" class="card-list"
|
||||
hx-get="/sb/signals/list"
|
||||
hx-trigger="load"
|
||||
hx-include="#sbManufacturer, #sbClassification, #sbAliasName, #sbSearch, #sbGroupCode">
|
||||
<!-- Signals 리스트 -->
|
||||
</div>
|
||||
{% else %}
|
||||
<div id="sbList" class="card-list"
|
||||
hx-get="/sb/faults/list"
|
||||
hx-trigger="load"
|
||||
hx-include="#sbManufacturer, #sbDevice, #sbCarType, #sbAliasName, #sbSearch, #sbGroupCode">
|
||||
<!-- Faults 리스트 -->
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<section>
|
||||
<div class="filter-row" style="display: flex; flex-wrap: wrap; gap: 0.7rem; align-items: end; margin-bottom: 1rem;">
|
||||
<div style="flex: 1; min-width:160px;">
|
||||
<label for="mmiManufacturer">제작사</label>
|
||||
<select id="mmiManufacturer" name="manufacturer"
|
||||
hx-get="/sb?section=mmicode"
|
||||
hx-include="#mmiManufacturer,#mmiAliasName,#mmiSearch,#mmiGroupCode"
|
||||
hx-target="#tabPanel" hx-params="*" hx-trigger="change">
|
||||
<option value="" {% if selected_manufacturer=='' %}selected{% endif %}>전체</option>
|
||||
{% for m in manufacturers %}
|
||||
<option value="{{ m }}" {% if m==selected_manufacturer %}selected{% endif %}>{{ m }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div style="flex:1; min-width:130px;">
|
||||
<label for="mmiAliasName">차량분류</label>
|
||||
<select id="mmiAliasName" name="alias_name"
|
||||
hx-get="/sb?section=mmicode"
|
||||
hx-include="#mmiManufacturer,#mmiAliasName,#mmiSearch,#mmiGroupCode"
|
||||
hx-target="#tabPanel" hx-params="*" hx-trigger="change">
|
||||
<option value="" {% if selected_alias_name=='' %}selected{% endif %}>전체</option>
|
||||
{% for an in alias_names %}
|
||||
<option value="{{ an }}" {% if an==selected_alias_name %}selected{% endif %}>{{ an }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-row" style="display:flex; align-items:center; gap:1rem; margin-bottom:1.2rem;">
|
||||
<div style="flex:4;">
|
||||
<label for="mmiSearch">검색어</label>
|
||||
<input id="mmiSearch" name="q" value="{{ q }}" placeholder="코드/설명/차량 검색"
|
||||
hx-get="/sb?section=mmicode"
|
||||
hx-trigger="keyup changed delay:200ms, search"
|
||||
hx-target="#tabPanel"
|
||||
hx-include="#mmiManufacturer,#mmiAliasName,#mmiSearch,#mmiGroupCode">
|
||||
</div>
|
||||
<div style="flex:1; min-width:110px; text-align:right; align-self:end;">
|
||||
<label for="mmiGroupCode" style="margin-bottom:.45em;display:flex;align-items:center;gap:.4em;justify-content:flex-end;">
|
||||
<input type="checkbox" id="mmiGroupCode" name="group_code" value="on"
|
||||
hx-get="/sb?section=mmicode"
|
||||
hx-target="#tabPanel"
|
||||
hx-include="#mmiManufacturer,#mmiAliasName,#mmiSearch,#mmiGroupCode"
|
||||
hx-trigger="change" {% if group_code=='on' %}checked{% endif %}>
|
||||
코드 묶기
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list" {% if page > 0 %} style="display:contents;" {% endif %}>
|
||||
{% if rows %}
|
||||
{% for r in rows %}
|
||||
<article class="item">
|
||||
<header>
|
||||
<div class="code">{{ r.code_name }}</div>
|
||||
<div class="title">{{ r.code_description or '' }}</div>
|
||||
</header>
|
||||
<footer>
|
||||
<small>{{ r.manufacturer or '—' }}{% if r.alias_name %} · {{ r.alias_name }}{% endif %}{% if r.data_type %} · {{ r.data_type }}{% endif %}{% if r.car_id %} · {{ r.car_id }}{% endif %}</small>
|
||||
</footer>
|
||||
</article>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p>검색 결과가 없습니다.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% if rows|length >= page_size %}
|
||||
<div class="load-more-trigger"
|
||||
hx-get="/sb?section=mmicode&page={{ page + 1 }}&{{ query_params_string }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-trigger="revealed">
|
||||
<article class="item placeholder">Loading...</article>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<article class="modal-card">
|
||||
<header>
|
||||
<h3>[{{ row.sig_num }}] {{ row.signal_abbreviation }}</h3>
|
||||
<button class="outline" _="on click call document.getElementById('modal').close() then put '' into #modal">닫기</button>
|
||||
</header>
|
||||
<section class="content">
|
||||
<p>
|
||||
<strong>제작사</strong>: {{ row.manufacturer or '—' }}
|
||||
{% if row.classification %} · <strong>분류</strong>: {{ row.classification }}{% endif %}
|
||||
{% if row.alias_name %} · <strong>별칭</strong>: {{ row.alias_name }}{% endif %}
|
||||
</p>
|
||||
<hr>
|
||||
<h5>설명</h5>
|
||||
<p class="prewrap">{{ row.signal_description or '—' }}</p>
|
||||
<h5>상태값</h5>
|
||||
<p class="prewrap">{{ row.status_value or '—' }}</p>
|
||||
<h5>원본 데이터</h5>
|
||||
<p class="prewrap">{{ row.original_data or '—' }}</p>
|
||||
<h5>생성/수정</h5>
|
||||
<p class="prewrap">{{ row.created_at or '—' }} / {{ row.updated_at or '—' }}</p>
|
||||
</section>
|
||||
</article>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<div class="list" {% if page > 0 %} style="display:contents;" {% endif %}>
|
||||
{% if rows %}
|
||||
{% for r in rows %}
|
||||
<article class="item" hx-get="/sb/signals/{{ r.id }}" hx-target="#modal" hx-swap="innerHTML show:top">
|
||||
<header>
|
||||
<div class="code">{{ r.sig_num }}</div>
|
||||
<div class="title">{{ r.signal_abbreviation }}</div>
|
||||
</header>
|
||||
<footer>
|
||||
<small>{{ r.manufacturer or '—' }}{% if r.classification %} · {{ r.classification }}{% endif %}{% if r.alias_name %} · {{ r.alias_name }}{% endif %}</small>
|
||||
</footer>
|
||||
</article>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p>검색 결과가 없습니다.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if rows|length >= page_size %}
|
||||
<div class="load-more-trigger"
|
||||
hx-get="/sb/signals/list?page={{ page + 1 }}&{{ query_params_string }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-trigger="revealed">
|
||||
<article class="item placeholder">Loading...</article>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<div></div>
|
||||
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
import argparse
|
||||
import os
|
||||
import sqlite3
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
|
||||
def find_col(columns: List[str], candidates: List[str]) -> Optional[str]:
|
||||
lowered = {c.lower(): c for c in columns}
|
||||
for name in candidates:
|
||||
if name.lower() in lowered:
|
||||
return lowered[name.lower()]
|
||||
return None
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Import fault codes into local data.db from external SQLite table")
|
||||
parser.add_argument("--src-db", default="fault_codes.db", help="source sqlite file path")
|
||||
parser.add_argument("--src-table", default="fault_code_list", help="source table name")
|
||||
parser.add_argument("--manufacturer", default="woojin", help="manufacturer slug (woojin|rotem)")
|
||||
parser.add_argument("--default-section", default="fault", help="default section if missing (fault|tcms|emergency)")
|
||||
parser.add_argument("--truncate", action="store_true", help="delete existing faults for manufacturer before import")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# destination DB (our app)
|
||||
try:
|
||||
from app import DATABASE_PATH # type: ignore
|
||||
except Exception:
|
||||
DATABASE_PATH = os.path.join(os.path.dirname(__file__), "..", "data.db")
|
||||
|
||||
dest_path = os.path.abspath(DATABASE_PATH)
|
||||
src_path = os.path.abspath(args.src_db)
|
||||
|
||||
if not os.path.exists(src_path):
|
||||
raise SystemExit(f"Source DB not found: {src_path}")
|
||||
|
||||
src = sqlite3.connect(src_path)
|
||||
src.row_factory = sqlite3.Row
|
||||
dst = sqlite3.connect(dest_path)
|
||||
dst.row_factory = sqlite3.Row
|
||||
dst.execute("PRAGMA foreign_keys = ON")
|
||||
|
||||
cur = src.execute(f"SELECT * FROM {args.src_table}")
|
||||
rows = cur.fetchall()
|
||||
if not rows:
|
||||
print("No rows in source table.")
|
||||
return
|
||||
|
||||
columns = rows[0].keys()
|
||||
code_col = find_col(columns, ["code", "Code", "fault_code", "고장코드", "CODE"]) or "code"
|
||||
title_col = find_col(columns, ["title", "name", "f.Name", "f_name", "고장명", "fName"]) or None
|
||||
details_col = find_col(columns, ["details", "detail", "고장상세", "desc", "설명"]) # optional
|
||||
action_col = find_col(columns, ["action", "조치", "응급조치", "response", "반응"]) # optional
|
||||
cond_col = find_col(columns, ["condition", "검지조건", "조건"]) # optional
|
||||
category_col = find_col(columns, ["category", "cat", "장치분류", "system", "type"]) # optional
|
||||
section_col = find_col(columns, ["section", "섹션", "tab", "kind"]) # optional
|
||||
|
||||
print("Column mapping:")
|
||||
print(" code ->", code_col)
|
||||
print(" title ->", title_col)
|
||||
print(" details ->", details_col)
|
||||
print(" action ->", action_col)
|
||||
print(" condition ->", cond_col)
|
||||
print(" category ->", category_col)
|
||||
print(" section ->", section_col, f"(default={args.default_section})")
|
||||
|
||||
# manufacturer ensure
|
||||
m = dst.execute("SELECT id FROM manufacturer WHERE slug=?", (args.manufacturer.lower(),)).fetchone()
|
||||
if not m:
|
||||
name = "우진" if args.manufacturer.lower() == "woojin" else "로템"
|
||||
dst.execute("INSERT INTO manufacturer (slug, name) VALUES (?, ?)", (args.manufacturer.lower(), name))
|
||||
m_id = dst.execute("SELECT last_insert_rowid() AS id").fetchone()[0]
|
||||
else:
|
||||
m_id = m["id"]
|
||||
|
||||
if args.truncate:
|
||||
dst.execute("DELETE FROM fault WHERE manufacturer_id=?", (m_id,))
|
||||
dst.execute("DELETE FROM category WHERE manufacturer_id=?", (m_id,))
|
||||
|
||||
# existing categories map
|
||||
cat_map: Dict[str, int] = {}
|
||||
for r in dst.execute("SELECT id, name FROM category WHERE manufacturer_id=?", (m_id,)):
|
||||
cat_map[r["name"]] = r["id"]
|
||||
|
||||
def ensure_category(name: Optional[str]) -> Optional[int]:
|
||||
if not name:
|
||||
return None
|
||||
name = str(name).strip()
|
||||
if name == "":
|
||||
return None
|
||||
if name in cat_map:
|
||||
return cat_map[name]
|
||||
dst.execute("INSERT INTO category (manufacturer_id, name) VALUES (?, ?)", (m_id, name))
|
||||
cid = dst.execute("SELECT last_insert_rowid() AS id").fetchone()[0]
|
||||
cat_map[name] = cid
|
||||
return cid
|
||||
|
||||
def get_value(r: sqlite3.Row, key: Optional[str]):
|
||||
if not key:
|
||||
return None
|
||||
for k in r.keys():
|
||||
if k.lower() == key.lower():
|
||||
return r[k]
|
||||
return None
|
||||
|
||||
batch: List[tuple] = []
|
||||
for row in rows:
|
||||
code = str(get_value(row, code_col) or "").strip()
|
||||
title = str(get_value(row, title_col) or "").strip()
|
||||
details = str(get_value(row, details_col) or "").strip()
|
||||
action = str(get_value(row, action_col) or "").strip()
|
||||
cond = str(get_value(row, cond_col) or "").strip()
|
||||
category_val = get_value(row, category_col)
|
||||
category_val = (str(category_val).strip() if category_val is not None else None)
|
||||
section_val = get_value(row, section_col)
|
||||
section = (str(section_val).strip().lower() if section_val is not None else args.default_section)
|
||||
if section not in ("fault", "tcms", "emergency"):
|
||||
section = args.default_section
|
||||
|
||||
cat_id = ensure_category(category_val)
|
||||
batch.append((m_id, cat_id, section, code, title, details, action, cond))
|
||||
|
||||
dst.executemany(
|
||||
"INSERT INTO fault (manufacturer_id, category_id, section, code, title, details, action, condition) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
batch,
|
||||
)
|
||||
|
||||
# bump meta version
|
||||
dst.execute("UPDATE meta SET version = version + 1, updated_at = datetime('now') WHERE id = 1")
|
||||
if dst.total_changes == 0:
|
||||
dst.execute("INSERT OR REPLACE INTO meta (id, version, updated_at) VALUES (1, 1, datetime('now'))")
|
||||
|
||||
dst.commit()
|
||||
src.close()
|
||||
dst.close()
|
||||
print(f"Imported {len(batch)} rows into {dest_path} for manufacturer '{args.manufacturer.lower()}'.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"packageId": "cc.m1tcloud.tr.twa",
|
||||
"host": "tr.m1tcloud.cc",
|
||||
"name": "FaultCode_Line1",
|
||||
"launcherName": "F_Code",
|
||||
"display": "standalone",
|
||||
"themeColor": "#0F172A",
|
||||
"themeColorDark": "#000000",
|
||||
"navigationColor": "#000000",
|
||||
"navigationColorDark": "#000000",
|
||||
"navigationDividerColor": "#000000",
|
||||
"navigationDividerColorDark": "#000000",
|
||||
"backgroundColor": "#0F172A",
|
||||
"enableNotifications": true,
|
||||
"startUrl": "/",
|
||||
"iconUrl": "https://tr.m1tcloud.cc/static/icons/icon-512.png",
|
||||
"splashScreenFadeOutDuration": 300,
|
||||
"signingKey": {
|
||||
"path": "D:\\py\\htmx_test\\android.keystore",
|
||||
"alias": "android"
|
||||
},
|
||||
"appVersionName": "1",
|
||||
"appVersionCode": 1,
|
||||
"shortcuts": [],
|
||||
"generatorApp": "bubblewrap-cli",
|
||||
"webManifestUrl": "https://tr.m1tcloud.cc/manifest.webmanifest",
|
||||
"fallbackType": "customtabs",
|
||||
"features": {
|
||||
"locationDelegation": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"alphaDependencies": {
|
||||
"enabled": false
|
||||
},
|
||||
"enableSiteSettingsShortcut": true,
|
||||
"isChromeOSOnly": false,
|
||||
"isMetaQuest": false,
|
||||
"fullScopeUrl": "https://tr.m1tcloud.cc/",
|
||||
"minSdkVersion": 21,
|
||||
"orientation": "default",
|
||||
"fingerprints": [],
|
||||
"additionalTrustedOrigins": [],
|
||||
"retainedBundles": [],
|
||||
"protocolHandlers": [],
|
||||
"fileHandlers": [],
|
||||
"launchHandlerClientMode": "",
|
||||
"displayOverride": [],
|
||||
"appVersion": "1"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue