knowledge(경쟁사): STmate 프로그램 정적분석 인계 — 문서 15·원자료·재현 스크립트

코덱스가 토큰 한도로 중지한 STmate 분석을 이어받아 마무리한 것.
scratch/orca_artifacts 에 있던 산출물을 지식DB 정식 자리로 옮김.

이번에 새로 확정한 것
- 내부 반올림이 은행가 반올림(최근접-짝수)임 — SimpleRoundTo·Ceil·SetRoundMode
  전부 미임포트, 반올림 함수 본체에 부호 처리 없음. 출력 XLSX 의 Excel 사사오입과
  20개 경계 중 10개가 원 단위에서 갈림
- 간접비 항목별 밑수를 RATE 화면 그리드 묶음 제목에서 확정.
  환경보전비 밑수가 직접공사비가 아니라 재료비+직접노무비+산출경비임을 정정
- JB_R 35열 확장 시점이 2020-05-27 이고 기존 1~20열은 한 칸도 안 바뀜
- 원가계산 설정 선택축 83개 전수. 화면 순번과 내부값이 뒤집힌 축 둘 확인
- 문서 13(통제시험 T1~T11)·14(최종 완료 보고서) 신규

원본 C:\경영정보(주) 는 읽기만 함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
This commit is contained in:
2026-09-13 11:24:43 +09:00
co-authored by Claude Opus 5
parent 2ab4c90288
commit 91b2ddea86
44 changed files with 209362 additions and 0 deletions
@@ -0,0 +1,123 @@
# STmate 경쟁 프로그램 분석 — 요약과 읽는 법
> 재구현 상세판(2026-09-13): 00~04는 전체 구조와 데이터 계보, 05~09는 동일 계산 엔진 구현 규칙, 10은 System 전수 장부, 11은 실행모듈에서 복원한 계산 코어, 12는 원가계산 4형식과 RATE표, 13은 남은 경계를 가를 통제시험, 14는 최종 완료 보고서다.
>
> **처음이면 14번(최종 보고서)부터 읽는 것이 빠르다.**
| 문서 | 용도 | Orca 아티팩트 |
|---|---|---|
| 00 분석 요약과 읽는 법 (이 문서) | 전체 인덱스, 결론, Aislo 비교 | https://share.onorca.dev/a/uHEsfWTvedw1 |
| 01 전체 구조 | 실행 기술, 모듈, 파일 흐름, 기능 구조 | https://share.onorca.dev/a/jjxDJTOtRGq7 |
| 02 데이터셋과 파일형식 | DBF 스키마, 프로젝트 패키지, 기준자료, 암호화 경계 | https://share.onorca.dev/a/boO2-Fo4CFNi |
| 03 계산로직과 Aislo 비교 | 확인된 공식, 계층 합산, 단가·제비율 모델, 차이와 권고 | https://share.onorca.dev/a/fyN0SVUu3Oum |
| 04 계산 데이터계보 | 입력 필드 → 계산 → 결과 필드 단계별 추적 | https://share.onorca.dev/a/S1E38cIhGiz6 |
| 05 재구현 판정기준과 근거목록 | 확정등급, 조사 표본, 파이프라인, 중간값 계약 | https://share.onorca.dev/a/8ktCQIIDvMuP |
| 06 규칙1·7 | RATE 좌표, 간접비 순서, 끝전·VAT | https://share.onorca.dev/a/z2v9o5Wfaim0 |
| 07 규칙2·3·4·5 | 직접비 단가, 중기, BDQTY, 자재 채택 | https://share.onorca.dev/a/o0HLxAXG8Lhg |
| 08 규칙6·8·9 | 재계산, 변경설계, 일괄변경 | https://share.onorca.dev/a/z58ZjH9Nu_Pb |
| 09 통합 재구현 명세 | 내부 데이터셋, 계산 순서, 호환 어댑터, 골든시험 | https://share.onorca.dev/a/7eULzjbfyZHM |
| 10 System 186개 파일 분석장부 | 전 파일별 판독 상태, 실제 형식, 핵심 모듈과 기준자료 구조 | https://share.onorca.dev/a/zHj5IbV4dfnL |
| 11 CPM 계산코어 정적분석 | 식 평가, 반올림, 간접비·안전비·변경설계·끝전조정 재구현 명세 | https://share.onorca.dev/a/U6HIpHCbt9XF |
| 12 원가계산 4형식과 RATE표 복원 | 일반·수공·실적일반·실적수공 공식, 화면 열, 내부 선택값 | https://share.onorca.dev/a/y-R9TQqgEFfo |
| 13 통제시험 목록 | 정적 분석으로 못 가르는 경계를 시험 11개로 분리, 우선순위·완료판정 | https://share.onorca.dev/a/lcmxdrG2SWvE |
| 14 최종 분석완료 보고서 | 도달 수준, A등급 확정 목록, 남은 것, 완료 판정 기준, 산출물 | https://share.onorca.dev/a/AmgldP7q_Qzc |
중요: C등급으로 표시한 규칙은 “분석 누락”이 아니라 보유 정적 자료에 입력 전후 대응값이 없거나 레코드가 난독화되어 확정 불가능한 경계다. 문서에는 각 경계를 확정할 STmate 통제 대조시험까지 명시했다. System 폴더는 186/186개 모두 내부 구조까지 판독했으며 미판독 파일은 0개다.
**등급 갱신 이력 (2026-09-13)** — 11·12번의 폼 리소스 복원 결과로 06·08의 다음 판정이 올라갔다.
| 항목 | 이전 | 현재 | 근거 |
|---|---|---|---|
| RATE 네 표의 행·열 라벨 | 미확정 | 그리드별 열 제목·행 수 확정 (남은 것은 시작 좌표) | 12번 §8·§9 |
| 요율 순환 의존성의 STmate 처리 | B | **A** — 고정점 반복 없음, 사용자 수동 확정 | 11번 §8 |
| `RATE_RA.DBF` | C | **A/B** — 실적형식 규모·기간·안전비 그리드 대응 | 12번 §9 |
| 변경설계 간접비 계산모드 | 권고 수준 | **A** — 방법 A/B 공식과 `cBx_CH_BO` 3모드를 코드에서 확인 | 11번 §10, 12번 §10.3 |
| 끝전조정 보존 필드 | 3칸 | **6칸** — 함수·자리수가 설정별로 따로 | 11번 §11, 12번 §10.2 |
| 반올림 음수·절반값 방향 | C | **A** — 최근접-짝수(은행가), 0 대칭. `SetRoundMode` 미사용·`SimpleRoundTo` 미임포트로 확정 | 11번 §4.2 |
| 내부 계산 ↔ 출력 XLSX 반올림 | 같다고 가정 | **다름** — 20개 경계 중 10개가 원 단위에서 갈림 | 11번 §4.2 경계표 |
| 간접비 항목별 밑수 | 추정 서술 | **A** — 화면 그리드 묶음 제목에 공식이 그대로 적혀 있음 | 06번 §3 |
| 환경보전비·보증수수료 밑수 | 직접공사비 | **정정**`재료비+직접노무비+산출경비` (실적형식만 직접공사비) | 06번 §3, 04번 §7 |
| `JB_R` 35열 확장 시점 | "2020 이후" | **2020-05-27 확정** — 기존 1~20열은 한 셀도 안 바뀜 | 10번 §4 |
| `JB_R` 열 의미 | 미상 | **1~5 간접노무비 / 6~10 기타경비** (공종 5개 순서 확정), 21·26 국가유산 | 10번 §4 |
| 원가계산 설정 선택축 | 16축 목록 | **83축 전수** — 공통 29 + 형식별 12/11/16/15 | 12번 §10.1-2 |
분석일: 2026-09-13
대상: `C:\경영정보(주)`
비교 대상: Aislo 저장소의 B08 수량 산출·B09 견적 계산 영역
## 결론
STmate는 **Delphi 6 네이티브 모듈 + Apollo/Six 계열 DBF 저장소 + ZIP 기반 교환 파일**로 구성된 로컬 설계예산 프로그램이다. 핵심 업무 모델은 다음 네 층으로 요약된다.
1. 기초 단가·코드 자료를 시기별 파일로 배포한다.
2. 자재(M)·노임(L)·중기 취득가(S)를 원천으로 시간당 중기사용료(X), 일위대가(B), 단가산출(D)을 조립한다.
3. 공종별 수량에 재료·노무·경비 단가를 곱해 내역 행을 만든다.
4. 행을 공종 계층으로 합산하고 제비율·법정경비·일반관리비·이윤·부가세를 적용한다.
분석의 중심은 특정 프로젝트 금액이 아니라 **값의 출처와 전달 경로**다. STmate는 공통 기초자료에서 자원 단가를 가져오고, 공종별 산출근거가 자원 코드와 품을 참조해 복합단가를 만들며, 프로젝트 수량이 그 단가를 받아 내역금액이 되고, 내역의 비목별 합계가 제비율 계산의 밑수로 전달되는 구조다.
```text
노임·자재·중기 기초자료
→ 출처별 후보단가와 채택단가
→ 일위대가·단가산출(자원코드 × 품, 할증, 기계 Q식)
→ 공종별 재료/노무/경비 단가
→ 프로젝트 수량 × 단가
→ 직접재료비·직접노무비·산출경비
→ 제비율별 고유 밑수 × 적용률
→ 순공사원가 → 일반관리비 → 이윤 → 부가세 → 총공사비
```
## Aislo와의 핵심 비교
| 관점 | STmate | Aislo | 판단 |
|---|---|---|---|
| 제품 범위 | 견적·내역 작성 중심 | 임도 선형·횡단·구조물 수량부터 견적까지 | Aislo가 상류 설계 자동화 범위가 넓다 |
| 실행 구조 | 단일 Windows 데스크톱, 다수 CPM 플러그인 | FastAPI/Python 계산 + TypeScript 웹 UI | Aislo가 배포·협업·감사에 유리, STmate는 오프라인 운영이 단순 |
| 단가 모델 | 코드 기반 계층, 4안·복수 단가 슬롯 | 같은 계층을 명시적 타입과 재귀 계산으로 구현 | 핵심 모델은 유사하나 Aislo가 의미와 오류를 코드로 더 명확히 표현 |
| 저장 형식 | DBF/SMT, 일부 레코드 암호화, STC ZIP | UTF-8 JSON, 매니페스트, SHA-256, 프로젝트 스냅샷 | Aislo가 이식성·검증성·버전 추적에서 우세 |
| 결측 처리 | 데이터 필드에서 0과 미입력의 구분이 불명확한 자리 존재 | 채택 단가가 없으면 오류/경고로 금액 확정을 차단 | Aislo 방식 유지 권장 |
| 재현성 | 프로젝트 파일 안에 단가·제비율 테이블을 함께 보관 | 기준자료 버전과 단가 스냅샷 지문을 기록 | 둘 다 과거 결과 고정 지향, Aislo가 근거 추적을 더 명시화 |
| 계산 투명성 | 결과 DBF에는 성분별 단가·금액이 남음 | 산출 근거·출처·미결·단수 위치를 별도 모델로 제공 | Aislo 우세 |
## 당장 반영할 가치가 높은 점
- STmate의 **프로젝트 한 묶음 교환**은 실용적이다. Aislo도 프로젝트 내보내기에 입력, 채택 단가 스냅샷, 계산 설정, 산출 결과, 매니페스트를 한 파일로 묶으면 장기 보관과 인수인계가 쉬워진다.
- STmate의 **당초/변경 및 최대 4개 안 병렬 필드**는 설계변경 비교에 유용하다. Aislo에는 DB 열을 네 벌 복제하기보다 기존 프로젝트 버전/스냅샷을 이용한 비교 화면이 더 적합하다.
- STmate의 **보고서 서식 데이터화**(`SET_REP`)는 출력물 요구가 많은 실무에 강하다. Aislo도 보고서별 열 이름·폭·표시 여부를 데이터로 관리할 가치가 있다.
- 단가 슬롯은 이미 Aislo가 6개 원천과 채택 슬롯으로 모델링하고 있어 방향이 맞다.
## 문서 구성
전체 13개 문서의 용도와 링크는 맨 위 표에 있다. 읽는 순서는 다음을 권한다.
1. **처음 보는 경우** — 00(이 문서) → 01 전체 구조 → 02 데이터셋
2. **계산을 재구현하려는 경우** — 05 판정기준 → 11 계산코어 → 12 4형식·RATE → 06·07·08 규칙 → 09 통합 명세
3. **파일 하나를 추적하려는 경우** — 10 전수 장부 → `system_inventory.csv`
4. **값의 출처를 따라가려는 경우** — 04 계산 데이터계보
## 분석 경계와 신뢰도
이 분석은 설치 파일과 맛보기 프로젝트를 수정하지 않은 정적 분석이다. 정상 실행을 시도했으나 프로세스가 창을 노출하지 않아 UI 동작은 확인하지 못했다. 암호화된 기준자료는 비밀번호 추측이나 우회를 하지 않았다.
- **확인**: 파일 헤더, DBF 스키마, 평문 레코드, ZIP 목록, 실행 파일 버전 정보, Aislo 소스
- **강한 추론**: 모듈명과 스키마가 함께 가리키는 업무 흐름
- **미확인**: 각 그리드가 `RATE*` 행렬에 적재되는 시작 행 좌표, 구간 경계의 포함 방향(`<`/`<=`), `ROUNDUP`·`MINT`의 음수 방향, 암호화 기준자료의 실제 값, UI 조작 순서
제비율 표의 **화면상 명칭 자체는 더 이상 미확인이 아니다** — 폼 리소스에서 15개 그리드의 열 제목과 행 수를 복원했다(12번 §8).
미확인 항목은 모두 **13번 통제시험 목록**에 시험 단위로 옮겨 놓았다. 어느 시험이 무엇을 확정하는지, 우선순위는 무엇인지가 그 문서에 있다.
## 용어 대조 — 같은 것을 다르게 부르는 자리
문서마다 출처가 달라 용어가 갈리는 곳이 있다. 아래는 **같은 것**이다.
| 이 문서군의 표기 | 같은 뜻의 다른 표기 | 비고 |
|---|---|---|
| 제비율 | 간접비, 경비율 | STmate 화면은 「제비율」 |
| 산출경비 | 직접경비 | 03번만 「직접경비」를 쓴다 |
| 국가유산(수리) | 문화재(수리) | 2024년 법령 개정으로 명칭이 바뀐 같은 공종 |
| 제잡비 표준시장방식 | 제잡비 실적공사방식 | **화면과 내부 이름이 다르다** — 12번 §10.1-3 |
| 산림조합 형식 | 임 협 식 | 부가세 옵션. 역시 화면≠내부 |
| 실적형식 `TA`/`SA` | 표준시장단가 형식 | 같은 것 |
**등급 표기**는 05번 §「확정등급」이 유일한 기준이다 — `A 확정 / B 강한 추정 / C 미확정`. `A/B`는 구조는 확정이나 한 칸이 남은 경우다.
@@ -0,0 +1,106 @@
# STmate 전체 구조 분석
## 1. 제품 식별
- 주 실행 파일: `System\STmate8.Exe`
- 파일 설명: 설계예산시스템
- 제품명: 내역서작성 프로그램
- 회사: 경영정보(주)
- 파일 버전: 26.9.1.0
- 제품 버전: w26.09
- 실행 파일 크기: 145,408바이트
주 실행 파일이 작은 대신 기능 대부분을 `*.CPM` 모듈로 분리했다. CPM은 헤더가 `MZ`인 Windows PE 실행 모듈이므로 단순 데이터 파일이 아니라 동적으로 적재되는 코드 모듈로 판단된다.
## 2. 기술 스택
설치 파일에는 `RTL60.BPL`, `DBRTL60.BPL`, `BDERTL60.BPL`, `designide60.bpl`이 있다. 이는 Delphi 6 런타임/DB 런타임 구성과 일치한다. `Apollo5D6.bpl`, `SDE32/50.DLL`, `SDECDX/NSX/NTX50.DLL`, `IDDBAS32.DLL`, `IDPDX32.DLL`은 DBF·dBase·Paradox 계열 데이터 접근을 뒷받침한다. `RealGrid6*.bpl`은 표 기반 UI를 담당하는 것으로 보인다.
구조는 대략 다음과 같다.
```text
STmate8.Exe
├─ Delphi/Borland 런타임(BPL)
├─ DBF 엔진(Apollo/Six/BDE 계열)
├─ RealGrid 표 UI
├─ ST_CPM/*.CPM 기능 모듈
├─ ST_BSC/* 기준 단가·제비율 배포자료
└─ 프로젝트 폴더(DBF+SMT+INI) ↔ STC 압축 파일
```
## 3. 기능 모듈 분해
파일명에 기반한 기능 구분이다. 괄호 안은 신뢰도다.
| 모듈 | 해석 |
|---|---|
| `ST_Boq.CPM` | 내역서 편집·집계 핵심(높음) |
| `STmateQty8.CPM` | 수량 관련 기능(높음) |
| `ST_EdiLWi.CPM`, `ST_P_iLWi.CPM` | 일위대가 편집·출력(높음) |
| `ST_EdSan.CPM`, `ST_P_San.CPM`, `ST_SanCal.CPM` | 단가산출서 편집·출력·계산(높음) |
| `ST_Jabpum.CPM` | 잡품/자원 자료 관리(중간) |
| `ST_KanJub.CPM` | 간접비·제비율 계산(높음) |
| `ST_P_ConEst.CPM` | 원가계산서 출력(높음) |
| `ST_P_Collect.CPM` | 자원 집계표 출력(높음) |
| `ST_P_Excav.CPM`, `ST_P_Joong.CPM` | 굴착/중기 관련 출력(중간) |
| `ST_P_Nae.CPM`, `ST_P_List.CPM` | 내역·목록 출력(높음) |
| `ST_P_XLS.CPM` | Excel 내보내기(높음) |
| `ST_Prt.CPM` | 공통 인쇄(높음) |
| `ST_U_Archive.CPM` | 프로젝트 압축·보관(높음) |
| `ST_U_ChgAmt.CPM`, `ST_U_ChgCode.CPM` | 단가/코드 일괄 변경(높음) |
| `ST_U_Convert.CPM` | 외부/구형 형식 변환(중간) |
| `ST_U_Merge.CPM`, `ST_U_ConBD.CPM` | 프로젝트·내역 병합(중간) |
| `ST_U_DelCode.CPM`, `ST_U_DelPrj.CPM` | 코드·프로젝트 삭제(높음) |
| `ST_U_Indx.CPM` | 색인 재구축(높음) |
이름이 `Ed`, `P`, `U`로 반복되는 점은 편집(Editor), 출력/인쇄(Print), 유틸리티(Utility) 계열을 접두어로 구분한 플러그인 구조를 시사한다.
## 4. 업무 흐름
정적 자료가 가리키는 전체 흐름은 다음과 같다.
```text
시기별 기준자료
├─ 노임·기계경비
├─ 자재단가
├─ 표준일위대가
├─ 표준시장단가
└─ 제비율
↓ 선택/가져오기
프로젝트 단가 마스터(COSTN/COSTA + SMT)
↓ 코드 참조와 상세 구성
수량/공종 자료(BDQTY, QCODE, KONGJONG)
↓ 수량 × 3성분 단가
내역서(BOQ/BOQ11/BQM)
↓ 계층 소계·제비율
원가계산/집계/보고서(SET_REP 설정)
인쇄·Excel·STC 보관
```
## 5. 프로젝트와 기준자료의 분리
`ST_BSC`는 공급자가 배포하는 시기별 기준자료이고, `STmate 자료\설계자료\실습(맛보기)`는 프로젝트 작업본이다. 프로젝트 STC를 풀면 확장 폴더와 바이트 단위로 동일한 23개 파일이 나온다. 즉 STC는 별도 논리 포맷이 아니라 **프로젝트 디렉터리의 무손실 ZIP 패키지**다.
이 분리는 중요한 설계 원칙을 보여준다.
- 기준자료가 업데이트되어도 프로젝트가 가진 작업본은 독립적으로 보존된다.
- 프로젝트 전달은 단일 파일로 가능하다.
- 계산 결과뿐 아니라 설정·단가·제비율·보고서 설정이 함께 이동한다.
## 6. Aislo 구조와 비교
Aislo는 `B08_Quantity`에서 설계 결과를 공종·자재 인계 데이터로 만들고 `B09_Estimation`에서 단가 계층, 내역서, 법정경비, 원가계산서를 생성한다. STmate가 하나의 데스크톱 프로그램 안에서 표 편집 중심으로 모든 기능을 묶은 반면 Aislo는 다음처럼 책임을 분리한다.
```text
GIS/선형/횡단/구조물(B03~B07)
↓ 명시적 handoff
수량 산출(B08)
↓ work_items + materials
단가·일위대가·내역·원가(B09)
↓ API
웹 UI 및 프로젝트 저장
```
STmate의 장점은 사용자가 프로젝트 폴더만 이해하면 되는 단순한 오프라인 운영이다. Aislo의 장점은 설계와 수량의 자동 연결, 계산 책임 분리, 서버 기반 협업, 테스트 가능한 계산 모듈이다.
@@ -0,0 +1,137 @@
# STmate 데이터셋과 파일 형식 분석
## 1. 파일군 개요
| 확장자 | 수량 | 역할 |
|---|---:|---|
| `.CPM` | 46 | Windows PE 기능 모듈 |
| `.DBF` | 19 | 프로젝트의 구조화 테이블 |
| `.SMT` | 4 | DBF memo 보조 저장소(Six memo) |
| `.STBSC` | 28 | 암호화 ZIP 기반 기준자료 배포 패키지 |
| `.BSC` | 7 | 대형 기준 코드/단가 테이블, 암호화 DBF 계열 |
| `.JB_R` | 27 | 일반 공사 제비율 표 |
| `.JB_RA` | 14 | 표준시장단가용 제비율 표 |
| `.CSTA` | 6 | 표준시장단가 대형 테이블 |
| `.STC` | 1 | 프로젝트 전체 ZIP 패키지 |
## 2. STC 프로젝트 패키지
`실습(맛보기).STC`는 암호화되지 않은 표준 ZIP이다. 내부 파일은 확장된 프로젝트 폴더와 SHA-256 기준으로 모두 동일하다.
```text
QCODE.SMT, Start8x.Ini, BDQTY.DBF, BOQ.DBF, BOQ11.DBF,
BQM.DBF, COSTA.DBF, COSTN.DBF, GRASS.DBF, KONGJONG.DBF,
PRJLST.DBF, QCODE.DBF, RATE*.DBF, SET_REP.DBF, SYSINFO.DBF,
STini.MEM, COSTN.SMT, PRJLST.SMT
```
프로젝트 하나에 입력, 계산 중간물, 결과, 출력 설정이 함께 들어간다. 장점은 보관과 전달이며, 단점은 같은 사실이 여러 파생 테이블에 중복될 수 있다는 점이다.
## 3. 주요 DBF 테이블
### `PRJLST.DBF` — 프로젝트 메타데이터
1개 레코드, 48필드. 프로젝트명·코드·분류와 4개 안별 재료/노무/경비/총액, 메모, 최종 단계, 옵션을 가진다.
주요 필드: `PNUM`, `PNAME`, `PCODE`, `PCLASS`, `MCOST1..4`, `LCOST1..4`, `SCOST1..4`, `TCOST1..4`, `COSTW1..4`, `PRJ_MEMO`, `FINL_LV`, `ACTTYP`, `ACTOPT`.
### `COSTN.DBF` — 단가 제목/마스터
71개 레코드, 101필드. 코드·명칭·규격·단위와 네 안별 총/재료/노무/경비 단가를 저장한다. 6개 가격 원천과 쪽수, 채택 관련 필드도 가진다.
주요 필드:
- 식별: `CODE`, `NAME`, `SIZE`, `UNIT`
- 연결: `BQCODE`, `EQCODE`, `CONTCODE`, `WQCODE`, `JDCODE`
- 성분별 단가: `TAMT1..4`, `LAMT1..4`, `MAMT1..4`, `SAMT1..4`
- 6개 원천/4개 안: `AMT_11..64`, `PG_11..54`
- 표시·분류: `GUN`, `GUN2`, `IFORM`, `ACTTYP`, `EDT_DATE`
본문은 암호화되어 있으나 스키마는 평문이다. memo 내용은 `COSTN.SMT`에 저장된다.
### `COSTA.DBF` — 별도 단가 자료
53필드. 구조가 COSTN의 축약형이며 `CODEA`, `AAMT1..4`, 성분별 단가, 환율/달러 관련 필드를 포함한다. 맛보기에는 레코드가 없다.
### `BOQ11.DBF` — 내역서
36개 레코드, 83필드. 말단 공종과 계층 제목·계·합계를 같은 테이블에 저장한다.
- 식별: `ITNUM`, `NAME1`, `SIZE1`, `UNIT1`, `BDCODE1`
- 수량: `QTY1..4`
- 단가: `TAMT1..4`, `LAMT1..4`, `MAMT1..4`, `SAMT1..4`
- 금액: `T_AMT1..4`, `L_AMT1..4`, `M_AMT1..4`, `S_AMT1..4`
- 계층: `SORTCODE`, `ENDCODE`, `ITM_TYP`
- 특수 수량: `QTY1_B`, `QTY1_N`, `QTY1_O`, `QTY1_H`
`BOQ.DBF`는 같은 스키마의 빈 작업 테이블이고, `BOQ11.DBF`가 맛보기의 실제 내역 판이다.
### `BDQTY.DBF` — 단가/공종별 수량 상세
212개 레코드, 37필드. `BDCODE`, 참조 `CODE`, 명칭·규격·단위, 네 안별 수량(`QTY1..4`), 비율(`RATE`), 원수량·할증 계열(`X_QTY1..3`, `X_HAL1..3`)을 가진다. 본문은 암호화되어 값 자체는 확인하지 않았다.
### `QCODE.DBF` — 수량 코드/식
15필드. `CODE`, `NAME`, `BQCODE`, `QTY0..9`, `IFORM`, `XCODE`로 구성된다. 맛보기에는 레코드가 없으나 수량 계산식 또는 수량 슬롯을 코드화하는 자리로 보인다.
### `KONGJONG.DBF` — 공종 분류
`CODE`, `NAME`, `SIZE` 세 필드의 작은 분류표다.
### `RATE*.DBF` — 제비율 행렬
- `RATE`: 41행 × 10열
- `RATE_A`: 25행 × 10열
- `RATE_B`: 35행 × 10열
- `RATE_M`: 25행 × 10열
- `RATE_R`: 50행 × 35열
- `RATE_RA`: 50행 × 20열
모두 수치 행렬이며 열 이름은 `RATE0..9` 또는 `RATE_01..35`다. 이름·밑수 규칙이 행렬에 함께 담기지 않아 프로그램 코드/화면 정의와 결합되어야 의미가 생긴다. 이 점은 외부 분석과 장기 유지보수에 불리하다.
### `SET_REP.DBF` — 보고서 설정
75개 레코드, 28필드. 보고서 식별자, 명칭, 머리말, 필드 수, 최대 11개 열의 이름과 폭, 페이지 부가설정을 가진다. 맛보기에는 재료비·노무비·경비·일식/견적 목록표 등이 등록되어 있다.
### `SYSINFO.DBF` — 시스템 설정
`PART`, `NUM`, `LOG`, `CHR`, `DATE`의 범용 키-값 구조다. 본문은 암호화되어 있다.
## 4. 암호화와 압축 경계
- STC 프로젝트 패키지: ZIP, 암호화 없음.
- STBSC 기준자료: ZIP 헤더이며 각 엔트리의 암호화 플래그가 켜져 있다. 내부 이름은 `CH_NAME.ST`, `COST.ST`, `info.ST`, `MEM.ST`, `XDET.ST` 등이다.
- DBF: 버전 바이트 `03`인 표는 평문, `06/E5/E6`인 일부 표는 스키마만 읽히고 레코드 본문은 암호화되어 있다. 설치된 Apollo/Six 계열 엔진과 일치하는 현상이다.
- SMT: 헤더에 `SiXMemo`가 확인된다.
암호화는 기준자료 무단 열람 억제와 제품 종속성 유지에는 유리하지만 데이터 이식, 자동 검증, 장애 복구에는 불리하다.
## 5. 시기별 기준자료 체계
폴더 이름이 데이터의 버전 메타데이터 역할을 한다.
- 노임·기계경비: 2025 상/하, 2026 상/하
- 표준시장단가: 2025 상/하, 2026 상/하 및 기관별 변형
- 표준일위대가: 2026 상반기, 건축/기계설비/전기/토목/통신 분리
- 시설공통자재: 2025 상/하, 2026 상반기와 수정판
- 제비율: 2007~2026의 여러 시행일, 일반(`JB_R`)과 표준시장(`JB_RA`) 분리
파일명에는 연도·반기·기관·수정일이 있으나 기계 판독 가능한 매니페스트나 해시 목록은 보이지 않는다.
## 6. Aislo 데이터셋과 비교
Aislo는 `resources/data_cost_input_value`에 JSON 자료와 `_manifest.json`을 둔다. 각 항목에는 `dataset_id`, 시행일, SHA-256, 크기가 있고 미확보·선택대기 값도 별도로 기록한다. 프로젝트가 채택한 단가는 UTF-8 JSON 스냅샷으로 저장하고 다시 읽을 때 해시를 검증한다.
| 속성 | STmate | Aislo |
|---|---|---|
| 구조 표현 | 고정폭 DBF 열 | 명명된 JSON 객체/배열 |
| 문자 인코딩 | CP949 중심 | UTF-8 |
| 버전 | 파일명·내부 날짜 | 매니페스트의 시행일/ID |
| 무결성 | 관찰 가능한 해시 없음 | SHA-256 검증 |
| 결측 | 빈칸/0 혼용 가능 | `None`·미결 목록·오류로 구분 |
| 단가 출처 | AMT/PG 슬롯 | 슬롯 + 출처/근거/provenance |
| 과거 프로젝트 고정 | 프로젝트에 테이블 동봉 | 프로젝트 단가 스냅샷 + 데이터셋 버전 |
| 교환 | 단일 STC | 현재는 구성요소 중심; 단일 패키지 보강 가치 있음 |
권장 방향은 STmate 형식을 모방하는 것이 아니라, Aislo의 명시적 JSON/매니페스트 모델을 유지하면서 **단일 프로젝트 패키지**라는 운영상 장점만 가져오는 것이다.
@@ -0,0 +1,142 @@
# STmate 계산 로직과 Aislo 비교
## 1. 내역 계산의 의미
`BOQ11.DBF`의 말단 행은 프로젝트 수량과 단가 마스터의 성분별 단가가 만나는 지점이다.
```text
총단가 = 재료단가 + 노무단가 + 경비단가
총금액 = 수량 × 총단가
재료금액 = 수량 × 재료단가
노무금액 = 수량 × 노무단가
경비금액 = 수량 × 경비단가
총금액 = 재료금액 + 노무금액 + 경비금액
```
특정 프로젝트의 숫자는 로직 근거로 사용하지 않는다. 단수 처리와 밑수 전달은 STmate가 생성한 여러 실무 XLSX의 셀 수식을 교차해 판단하며, 필드 단위 데이터 계보는 별도 `04_계산_데이터계보.md`에 정리했다.
## 2. 계층 합산
말단 행 위에 제목과 계/합계/총계 행을 같은 테이블에 둔다. `BDCODE`가 행의 성격을 구분한다.
- `B...`, `D...`: 계산 가능한 말단 단가/내역 행
- `T2..T5`: 계층 제목/상위 집계
- `E2..E5`: 계, 합계, 총계, 총합계
- `:`: 페이지 넘김 같은 출력 제어 행
모든 집계는 재료·노무·경비 성분을 따로 합산한 뒤 총액과 맞춘다. 제목·소계 행 자체가 새로운 계산 원천은 아니며, 하위 말단 행 결과를 그룹별로 집계한 파생 결과다.
## 3. 단가 조립 계층
DBF 코드·필드와 모듈 구성을 종합하면 단가 계층은 다음과 같다.
```text
M 자재 ──────────────┐
L 노임 ───────┐ │
S 중기 취득가 ─┴→ X 시간당 중기사용료
├→ B 일위대가 → 내역서
└→ D 단가산출 → 내역서
W 일식/견적 ─────────────────────→ 내역서
```
각 상위 단가는 하위 코드의 수량을 곱해 재료·노무·경비로 나누어 합산하는 참조 모델이다. `COSTN``CODE`, `BQCODE`, `EQCODE`, 다수 `AMT`, `PG` 필드가 이 구조를 뒷받침한다.
이 부분은 Aislo `PriceBook`의 모델과 매우 가깝다. Aislo는 `PriceKind`로 M/L/S/X/B/D/W를 명시하고 `PriceDetail(parent_code, ref_code, quantity)`를 재귀 해석한다. 순환 참조, 상세 없음, 채택 단가 없음은 오류로 중단한다.
## 4. 복수 단가 원천
STmate 설정에는 가격 정보, 물가 자료, 물가 정보, 거래 가격, 유통 물가, 적용 단가가 있고 `COSTN`은 원천별 금액(`AMT_`)과 쪽수(`PG_`)를 가진다. 프로젝트/내역 테이블은 네 벌의 수량·단가·금액 슬롯을 가진다.
두 축을 구분해야 한다.
- **원천 슬롯**: 같은 자재/노임의 여러 조사·공표 단가 중 무엇을 채택할지
- **설계 안 슬롯**: 당초/변경 또는 최대 4개 대안을 나란히 저장
Aislo는 6개 단가 원천과 채택 슬롯을 이미 명시적으로 구현한다. 네 안을 물리 열 네 벌로 복제하지는 않는다. Aislo의 프로젝트 버전 모델로 비교하는 편이 데이터 중복과 열 확장을 피할 수 있다.
## 5. 수량 계산 구조
STmate에는 `BDQTY``QTY1..4`, `X_QTY1..3`, `X_HAL1..3`, `RATE`, 그리고 `QCODE``QTY0..9`, `IFORM`, `XCODE`가 있다. 이는 수량 원값, 할증/비율, 산출식 형태를 저장하는 구조로 보인다. 다만 관련 본문이 암호화되고 UI를 열지 못했으므로 정확한 산식 언어와 평가 순서는 미확인이다.
Aislo는 이 지점에서 제품 성격이 다르다. B03~B07의 지형·선형·횡단·구조물 계산 결과를 B08이 공종별 수량으로 변환하고, 겹침 제거·자연/다짐 상태·구조물 규격·운반거리 같은 의미를 명시적으로 보존한다. STmate 맛보기는 견적 입력 수량을 받는 구조는 보이지만 GIS 설계에서 수량까지의 자동 생성 근거는 확인되지 않는다.
## 6. 제비율과 원가계산
STmate는 시행일별 `JB_R/JB_RA`와 프로젝트 `RATE*.DBF` 행렬을 사용한다. `ST_KanJub.CPM``ST_P_ConEst.CPM`은 간접비 계산과 원가계산서 출력을 담당하는 것으로 보인다. RATE 행렬에는 숫자만 있고 각 행의 명칭, 적용 밑수, 구간 선택 규칙은 프로그램 코드에 결합되어 있다.
Aislo는 반대로 `rates_2026.json`에 변수, 구간, 밑수, 처리 규칙을 명명해 두고 다음 흐름을 코드에서 그대로 드러낸다.
```text
재료비 = 직접재료비 + 간접재료비
직접공사비 = 재료비 + 직접노무비 + 직접경비
간접노무비 = 직접노무비 × 선택 구간율
노무비 = 직접노무비 + 간접노무비
경비 = 직접경비 + 법정경비
순공사원가 = 재료비 + 노무비 + 경비
일반관리비 = 순공사원가 × 구간율
이윤 = ((순공사원가 + 일반관리비) - 재료비) × 이윤율
총원가 = 순공사원가 + 일반관리비 + 이윤
도급공사비 = 총원가 + 부가세
총공사비 = 도급공사비 + 관급자재대 + 폐기물처리비
```
Aislo는 추정가격 구간이 계산 결과에 다시 영향을 주는 순환을 고정점 반복으로 풀고, 구간 진동 시 높은 구간을 택했다는 기록을 남긴다. STmate가 같은 경계를 어떻게 처리하는지는 정적 파일만으로 확인하지 못했다.
## 7. 단수 처리
STmate의 데이터 열은 수량 4자리, 단가 3자리, 제비율 4~6자리 같은 고정 소수 자릿수를 가진다. 그러나 저장 자릿수가 실제 반올림/절사 시점을 증명하지는 않는다.
Aislo는 `Decimal`로 전정밀 계산하고 출력 위치별 단수 규칙을 분리한다.
- 내역 행·제경비 행: 1원 미만 절사
> ⚠ 아래 「반올림」은 출력물(XLSX) 기준이다. STmate **내부** 계산의 `ROUND`는 Excel 사사오입이 아니라 최근접-짝수(은행가)다 — 11번 §4.2.
- 자원 집계표: 1원 단위 반올림
- 일위대가 금액란: 0.1원 미만 절사
- 일위대가 계금: 1원 미만 절사
- 관급자재대 총액: 천원 올림
- 설계서 총액: 천원 미만 절사
이 설계는 DBF 필드 자릿수에 묵시적으로 의존하는 것보다 검증과 변경에 유리하다.
## 8. 실패·결측 처리 비교
STmate의 평문 내역에는 계층 행의 수량/단가가 0으로 채워지고 실제 합계는 금액 필드에만 들어간다. 따라서 0이 정상값인지, 해당 없음인지, 미확보인지 스키마만으로 구별하기 어렵다.
Aislo는 채택 슬롯이 비어 있거나 상세 단가가 없거나 참조가 순환하면 0원으로 확정하지 않고 오류 또는 미결 사유를 남긴다. 경쟁 프로그램과의 호환을 이유로 이 원칙을 약화시키면 안 된다.
## 9. 권고 우선순위
### 우선 1 — 프로젝트 단일 패키지
Aislo의 기존 JSON, 데이터셋 버전, SHA-256, 입력 파일, 계산 설정, 산출 결과를 ZIP 하나로 내보내고 가져오는 기능이 가장 실용적인 차용점이다. STC의 단순한 운영 장점을 얻되 매니페스트와 스키마 버전을 포함해야 한다.
### 우선 2 — 버전 비교 화면
당초/변경 및 대안 비교를 한 화면에서 수량, 단가, 재료/노무/경비, 총액 차이로 보여준다. 저장은 기존 프로젝트 버전/스냅샷을 재사용하고 STmate처럼 모든 열을 네 벌 복제하지 않는다.
### 우선 3 — 출력 서식 메타데이터
보고서별 열 이름, 폭, 표시 여부, 머리말을 데이터로 분리한다. 현재 출력 요구가 실제로 반복될 때만 도입하며 계산 모델과 섞지 않는다.
### 유지해야 할 Aislo 우위
- 설계→수량→견적의 자동 인계
- UTF-8 JSON과 기계 판독 가능한 매니페스트
- 데이터셋/스냅샷 SHA-256
- `Decimal` 기반 계산과 출력 위치별 단수 처리
- 결측 단가를 0원으로 대체하지 않는 보호장치
- 코드·근거·시행일·미결 사유의 provenance
- 계산 모듈별 자동 테스트
## 10. 추가 분석에 필요한 것
정확한 STmate 제비율 매핑과 수량식 언어까지 확인하려면 프로그램 UI가 정상 표시되는 환경 또는 공급자가 제공한 출력 보고서가 필요하다. 다음 자료가 있으면 암호 우회 없이 분석을 확장할 수 있다.
- 맛보기 프로젝트의 내역서·일위대가표·단가산출서·원가계산서 출력 PDF/Excel
- 정상 실행 화면 캡처 또는 화면 녹화
- 서로 다른 입력 수량/거리/할증으로 저장한 두 프로젝트 파일
- 동일 프로젝트의 당초/변경 두 판
두 저장본의 합법적 차분이 있으면 어떤 입력 필드가 어떤 결과 필드에 영향을 주는지 훨씬 정확하게 식별할 수 있다.
@@ -0,0 +1,573 @@
# STmate 계산 데이터 계보 — 어디에서 무엇을 가져와 무엇을 만드는가
## 문서 목적
이 문서는 특정 공사의 값이 아니라 STmate의 **계산 의미와 데이터 이동**을 정리한다. 각 단계마다 입력 출처, 선택·계산 규칙, 결과 저장처, 다음 단계 소비자를 연결한다.
## 1. 전체 계산 파이프라인
```text
[A. 공통 기초자료]
노임 / 자재 / 중기 취득가 / 환율 / 제비율 기준표
[B. 자원별 적용단가]
복수 가격원천 중 채택 + 관급/사급 구분
[C. 품·복합단가 계산]
중기품셈 / 시간당 중기사용료(X) / 일위대가(B)
작업단가·표준시장단가 / 단가산출(D)
= 참조 자원 단가 × 품 + 비율 항목
[D. 프로젝트 공사비 계산]
공종 수량 × 복합단가 → 재료·노무·경비별 내역금액
[E. 직접비 집계]
직접재료비 / 직접노무비 / 산출경비
[F. 간접비 계산]
항목별 밑수 × 조건별 제비율, 행별 절사
[G. 원가계산]
순공사원가 → 일반관리비 → 이윤 → 총원가 → 부가세
[H. 별도 금액과 최종 출력]
관급자재대·조달수수료·폐기물 등 + 보고서/Excel/STC
```
교본도 STmate를 “기초자료~단가계산은 공사 종류와 무관하게 통합관리, 공사비계산~간접비계산은 공사별 독립관리”라고 설명한다. 즉 C까지는 재사용 가능한 단가 라이브러리이고 D 이후가 프로젝트 계산이다.
공식 흐름도에는 계산선과 별도로 `수정 → 검토 → 통합관리`가 전체 단계를 되먹임한다. 따라서 STmate의 계산은 한 번 실행하고 끝나는 선형 배치가 아니라, 기초단가·품·수량·원가계산기준을 고치면 그 값을 참조하는 하위 결과를 재계산하는 의존 그래프다.
## 2. A단계 — 공통 기초자료가 어디에서 오는가
### 입력 원천
| 의미 | 배포/설정 위치 | 프로젝트 저장 대응 |
|---|---|---|
| 노임단가 | `ST_BSC/노임기계/*.STBSC` | `COSTN`의 L 코드 |
| 자재단가 | `ST_BSC/자재단가/*.STBSC`, 물가지·견적 입력 | `COSTN`의 M 코드 |
| 중기 취득가·기계경비 기초 | `ST_BSC/노임기계/*.STBSC` | `COSTN`의 S 코드와 중기 연결 필드 |
| 표준 일위대가 | `ST_BSC/일위대가/*.STBSC` | B 코드와 산출 메모 |
| 표준시장단가 | `ST_BSC/실적단가/*.STBSC` | 실적단가/대안 단가 계열 |
| 제비율 | 시행일별 `JB_R`, `JB_RA` | 프로젝트 `RATE*` 테이블 |
| 환율·단가 조사시점·소수점·계산방식 | 프로젝트 초기화 화면 | `Start8x.Ini`, `COSTN.BQCODE`, 관련 플래그 |
### 의미
STmate는 계산식을 시작하기 전에 “어느 시점의 가격판과 제비율판을 쓸지”를 고른다. 기준자료를 프로젝트 안으로 복사해 두므로 나중에 공통 DB가 갱신되어도 기존 프로젝트 계산판은 유지된다.
## 3. B단계 — 자원별 적용단가를 어떻게 정하는가
### 자재 M 코드
`COSTN` 한 행이 하나의 자재를 나타낸다.
```text
자재 식별
CODE + NAME + SIZE + UNIT + BQCODE
가격 후보
AMT_11 조달가격
AMT_21 물가정보
AMT_31 물가자료
AMT_41 적산정보
AMT_51 견적단가
AMT_61 적용단가
근거
PG_11~PG_51 = 게재 페이지·식별정보
선택
PG_1 = 채택 출처 인덱스
결과
MAMT1 = 계산에 전달되는 재료단가
TAMT1 = 해당 자원의 총단가
```
중요한 경계: 6개 후보를 저장하고 채택 결과를 저장하는 것은 확인됐지만, **자동 최저가·법적 우선순위·사용자 수동선택 중 어느 알고리즘인지 아직 확정되지 않았다**. 관측상 채택 인덱스는 주로 복수 시세가 있는 M 코드에만 의미가 있고 L/S/X/B/D는 대부분 0이다.
### 노임 L 코드
협회 공표 노임 등 단일 기준값을 받아 `LAMT1`에 노무단가로 둔다. 자재처럼 복수 물가지 중 하나를 고르는 구조의 필요성이 작아 채택 인덱스가 관측상 사용되지 않는다.
### 중기 취득가 S 코드
기계의 기초가격과 제원·환율을 받아 경비 자원의 기초가 된다. 그 자체가 공종 단가는 아니며 다음 단계의 시간당 중기사용료 X가 소비한다.
### 관급/사급 분기
관급 플래그가 있는 자재는 도급 내역의 재료단가를 0원 처리하고 자재대와 조달수수료를 총원가 밖에서 별도 집계하는 경로를 탄다. 사급 자재는 채택단가가 일위대가의 재료비로 들어간다.
## 4. C단계 — 단가가 어떻게 조립되는가
### 공통 참조 문법
`COSTN.IFORM``COSTN.SMT`의 산출 메모를 가리킨다. 메모에는 다음 의미가 들어 있다.
| 문법 | 의미 | 가져오는 값 | 만드는 값 |
|---|---|---|---|
| `&M#####M&` | 자재 참조 | M 코드의 채택 재료단가 | 재료비 성분 |
| `&L#####L&` | 노임 참조 | L 코드의 노임단가 | 노무비 성분 |
| `&S#####S&` | 기계/경비 참조 | S 코드의 경비단가 | 경비 성분 |
| `&X#####L/M/S&` | 시간당 중기 참조 | X 코드의 성분별 시간당 단가 | 공종의 노·재·경 성분 |
| `수량'단위'` | 품·원단위 | 품셈 또는 설계조건 | 참조단가에 곱할 계수 |
| `율'%'` | 할증·손료 | 품셈/설계자 선택률 | 지정 밑수에 대한 비율 비용 |
| `Q = ...` | 기계 작업량/시간계수 | 장비 제원·작업조건 | 단위 공종당 장비시간 |
| `:=A01` | 중간 결과 | 앞 계산 결과 | 뒤 수식의 재사용 값 |
### 시간당 중기사용료 X
```text
입력
S: 기계 취득가·손료 기초
L: 운전원 노임
M: 연료·소모재료 단가
장비 제원, 연간/시간 운전 조건, 환율 등
계산
시간당 노무비 + 시간당 재료비 + 시간당 경비
출력
X 코드의 LAMT/MAMT/SAMT 및 TAMT
소비자
일위대가 B 또는 단가산출 D의 기계 행
```
정확한 감가·정비·관리·연료 공식은 설치 데이터만으로 전부 복원되지 않았으므로 현행 품셈의 기계경비 산식을 우선 근거로 보아야 한다.
### 일위대가 B / 단가산출 D
```text
각 상세 행 금액 = 참조 자원 적용단가 × 품(원단위)
재료단가 = Σ(M 참조 × 품) + 재료비 기준 비율항목
노무단가 = Σ(L 참조 × 품) + 노무 할증
경비단가 = Σ(S/X 참조 × 품) + 노무비 등 지정 밑수의 손료
총단가 = 재료단가 + 노무단가 + 경비단가
```
여기서 `B#####` 또는 `D#####` 결과가 하나의 공종 단가가 된다. 핵심은 결과 숫자를 직접 보관하는 것만이 아니라 **어떤 자원 코드에서 얼마의 품을 가져왔는지**가 SMT 산출 메모에 남는다는 점이다.
### 작업단가·표준시장단가 경로
공식 흐름도는 `일위대가``작업단가`를 같은 단가계산의 입력으로 병렬 배치한다. 설치 자료도 표준시장단가를 별도 `CSTA/STBSC`로 공급한다.
```text
일위대가 경로
자재·노임·중기사용료 × 품 → 자원별 상세 전개가 있는 계산단가
작업단가/표준시장단가 경로
기관·공종·규격·시행시점별 공표 단가 → 해당 공종에 직접 연결되는 단가
공통 결과
공종 단가 → 공사수량과 결합 → 공사비
```
따라서 모든 공종을 자원 원단위로 재귀 분해한다고 가정하면 안 된다. 어떤 행은 일위대가로 조립되고 어떤 행은 표준시장/실적 단가를 직접 채택한다. 직접 채택 단가가 재료·노무·경비로 분해되어 제공되는지, 총액만 제공되어 배분하는지는 자료 종류별 확인이 필요하다.
## 5. D단계 — 프로젝트 수량이 단가를 만나는 지점
### 수량 출처
프로젝트의 공종 수량은 `BOQ11.QTY1`에 들어가고, 세부 전개·할증 관련 정보는 `BDQTY`에 있다.
```text
BDQTY.BDCODE ─────────────┐
BDQTY.QTY / X_QTY / X_HAL │ 수량·할증 전개
BDQTY.BIMOK │ 비목 구분
BOQ11.BDCODE1 ───────→ COSTN.CODE 또는 단가 호표
BOQ11.QTY1 ─────→ 프로젝트 적용수량
COSTN 성분별 단가 ───→ BOQ11.LAMT1/MAMT1/SAMT1
```
`BDQTY` 본문은 난독화되어 있어 `X_QTY`가 할증 전 수량이고 `X_HAL`이 할증률이라는 해석은 강한 추정이지만 아직 실기 확인 전이다. 따라서 수량 산식 자체를 STmate에서 가져왔다고 단정할 수 없다.
### 내역 행 계산
```text
BOQ11.L_AMT1 = ROUNDDOWN(QTY1 × LAMT1, 원)
BOQ11.M_AMT1 = ROUNDDOWN(QTY1 × MAMT1, 원)
BOQ11.S_AMT1 = ROUNDDOWN(QTY1 × SAMT1, 원)
BOQ11.T_AMT1 = ROUNDDOWN(QTY1 × TAMT1, 원)
```
이 단수 규칙은 STmate가 출력한 2024~2025년 XLSX 5개 공사지의 셀 수식에서 반복 확인됐다. DBF 자릿수만 보고 추정한 것이 아니다.
### 트리 합산
`BDCODE` 유형이 제목(`T5→T4→T3→T2`), 단가참조 말단(`B/D 코드`), 소계(`E2` 등)를 구분한다. 말단 금액을 재료·노무·경비별로 각각 합산해 공종·공사·공구·총괄 금액을 만든다. `SORTCODE`는 256 간격 정렬키, `ENDCODE`는 제목 블록 끝을 가리키는 포인터 역할로 보인다.
## 6. E단계 — 직접비 결과가 무엇인가
내역의 모든 말단 행을 비목별로 합산하면 다음 세 값이 생긴다.
```text
직접재료비 = Σ BOQ11.M_AMT
직접노무비 = Σ BOQ11.L_AMT
산출경비 = Σ BOQ11.S_AMT
직접공사비 = 직접재료비 + 직접노무비 + 산출경비
```
이 값들은 `PRJLST.MCOST/LCOST/SCOST/TCOST`에 프로젝트 차수별 합계로 저장되고, 동시에 다음 간접비 계산의 밑수가 된다.
## 7. F단계 — 각 제비율이 어느 값을 가져오는가
STmate 출력 XLSX의 수식을 여러 공사지에서 교차한 결과, 데이터 전달 관계는 다음과 같다. 적용률은 프로젝트에 복사된 `RATE*` 기준표에서 공사종류·규모·기간·시행일 조건으로 선택되는 것으로 보인다.
| 결과 항목 | 가져오는 밑수 | 추가 조건/의존 | 결과가 쓰이는 다음 단계 |
|---|---|---|---|
| 간접노무비 | 직접노무비 | 공사규모·기간·종류의 적용률 | 노무비 합계 |
| 노무비 합계 | 직접노무비 + 간접노무비 | — | 산재·고용·기타경비·이윤 |
| 산재보험료 | 노무비 합계 | 건설업 적용률 | 경비 합계 |
| 고용보험료 | 노무비 합계 | 공사조건·등급 | 경비 합계 |
| 건강보험료 | 직접노무비 | 기간 조건 | 경비 합계 |
| 국민연금보험료 | 직접노무비 | 연도·기간 조건 | 경비 합계 |
| 노인장기요양보험료 | 건강보험료 결과 | 연도별 비율 | 경비 합계 |
| 퇴직공제부금 | 직접노무비 | 적용대상 조건 | 경비 합계 |
| 산업안전보건관리비 | 재료비 + 직접노무비 + 도급자설치 관급금액 | 규모 구간, 경우에 따라 기초액 | 경비 합계 |
| 기타경비 | 재료비 + 노무비 합계 *(일반·수공)* / 직접공사비 *(실적)* | 공사규모·기간·종류 | 경비 합계 |
| 환경보전비 | 재료비 + 직접노무비 + 산출경비 *(일반·수공)* / 직접공사비 *(실적일반)* | 공사종류·최소금액 조건 | 경비 합계 |
| 하도급대금·건설기계 보증수수료 | 재료비 + 직접노무비 + 산출경비 | 규모·계약조건 | 경비 합계 |
| 공사이행보증수수료 | (직접공사비 − 기준금액) × 율 + 추가금액, 다시 × 공기(년) | 규모·계약조건 | 경비 합계 |
**2026-09-13 정정** — 환경보전비와 보증수수료의 밑수를 `직접공사비`로 적었던 것을 바로잡았다. RATE 편집 화면(`TWM_KAN_RATE`)의 그리드 묶음 제목에 밑수 공식이 그대로 적혀 있으며, **밑수가 원가계산 형식(`T`/`S`/`TA`/`SA`)에 따라 달라진다.** 항목별 전체 표는 06번 §3에 있다.
각 항목은 `밑수 × 율`을 계산한 뒤 **그 행에서 원 단위 절사**되고, 절사된 정수 결과가 다음 단계 밑수에 전달된다. 마지막에 한 번만 절사하는 구조가 아니다.
> ⚠ 이 문서의 `ROUND`·`ROUNDDOWN`은 **STmate 출력 XLSX의 Excel 수식** 표기다. STmate **내부** Delphi 계산의 `ROUND`는 최근접-짝수(은행가) 반올림이라 정확히 절반인 값에서 결과가 갈린다. 11번 §4.2 경계표를 함께 볼 것.
## 8. G단계 — 원가계산 결과가 만들어지는 순서
```text
재료비 = 직접재료비 + 간접재료비
노무비 = 직접노무비 + 간접노무비
경비 = 산출경비
+ 산재·고용·건강·연금·장기요양 등 법정경비
+ 안전관리비·기타경비·환경보전비·보증수수료 등
순공사원가 = 재료비 + 노무비 + 경비
일반관리비 = ROUNDDOWN(순공사원가 × 적용률, 원)
이윤 = ROUNDDOWN((노무비 + 경비 + 일반관리비) × 적용률, 원)
= ROUNDDOWN((순공사원가 + 일반관리비 - 재료비) × 적용률, 원)
총원가 = 순공사원가 + 일반관리비 + 이윤
부가가치세 = ROUNDDOWN(총원가 × 10%, 원) ± 면세·끝수 조정
도급공사비 = 총원가 + 부가가치세
```
변경설계에서는 접미 1/2/3/4 슬롯이 당초와 변경 1~3차의 수량·단가·금액을 나란히 보존한다. 일부 경비는 변경 시 전체 재계산이 아니라 당초금액과 증감액을 결합하는 예외가 관측되어 항목별 변경 규칙 확인이 필요하다.
## 9. H단계 — 관급자재와 최종 금액
```text
관급자재 순자재대 = 관급 플래그 자재의 수량 × 조달단가 집계
조달수수료 = ROUNDDOWN(관급자재 순자재대 × 수수료율, 원)
관급자재대 총액 = ROUNDUP(순자재대 + 조달수수료, 천원)
총공사비 = 도급공사비 + 관급자재대 총액 (+ 별도 폐기물처리비 등)
```
관급자재대는 총원가 안의 재료비와 중복되면 안 된다. 다만 도급자 설치 관급금액은 산업안전보건관리비의 대상액에는 포함될 수 있으므로 “총원가 밖”과 “모든 계산에서 제외”는 다른 의미다.
## 10. 같은 값도 출력 위치에 따라 단수 처리가 다르다
| 출력 위치 | 처리 |
|---|---|
| 설계내역서 행 금액 | 원 단위 절사 |
| 제경비 각 행 | 원 단위 절사 |
| 조달수수료 | 원 단위 절사 |
| 재료·노무·경비·중기 자원 집계표 | 원 단위 반올림 |
| 관급자재대 총액 | 천원 단위 올림 |
따라서 내역서와 자원 집계표가 같은 원자료를 사용해도 원 단위 합계가 다를 수 있다. 이는 입력 오류가 아니라 출력 위치별 처리 규칙이다.
## 11. STmate와 Aislo의 단계별 대응
| STmate 의미 | STmate 저장 | Aislo 대응 | 비교 |
|---|---|---|---|
| 자원 가격후보와 채택 | `COSTN.AMT_*`, `PG_*`, `T/L/M/SAMT` | `PriceTitle.slots`, `slot_pages`, `adopted_slot` | Aislo가 타입과 결측을 명시 |
| 단가 상세 전개 | `COSTN.SMT` 문자열 문법 | `PriceDetail` 목록 | Aislo가 파싱 없이 구조 자체로 저장 |
| 단가 재귀 참조 | 자원 코드 마커 | `PriceBook.resolve()` | 의미상 동일 |
| 프로젝트 수량 | `BOQ11.QTY`, `BDQTY` | B08 handoff `work_items/materials` | Aislo는 설계 근거와 상태를 더 많이 보존 |
| 내역 3성분 | `LAMT/MAMT/SAMT`, `L/M/S_AMT` | `Money3`, `BillRow` | 의미상 동일 |
| 직접비 합계 | `PRJLST.M/LCOST/SCOST/TCOST` | `DirectCostBreakdown`, `CostInput` | 의미상 동일 |
| 제비율 | 라벨 없는 `RATE*` 행렬 + 프로그램 코드 | 명명된 `rates_2026.json` 처리규칙 | Aislo가 밑수와 조건을 감사 가능하게 노출 |
| 원가계산 | 모듈 내부 + 출력 결과 | `calculate_cost()` 단계별 행 | Aislo가 계산 순서를 직접 검증 가능 |
| 과거 판 고정 | 프로젝트에 DBF 동봉 | 단가 스냅샷 + 데이터셋 버전/해시 | Aislo가 무결성 확인 가능 |
## 12. 비교 결과
STmate에서 가져올 핵심은 숫자나 DBF 형식이 아니다.
1. **공통 단가 라이브러리와 프로젝트 계산을 분리**한다.
2. **모든 파생 단가는 원천 자원 코드와 품을 통해 추적**할 수 있어야 한다.
3. **재료·노무·경비 성분을 계산 전 과정에서 잃지 않는다.**
4. **간접비는 항목마다 밑수가 다르고 계산 순서가 의존적**이다.
5. **단수 처리는 수치 종류가 아니라 결과가 놓이는 표 위치에 묶인다.**
6. **변경설계는 당초값과 변경값의 계보를 보존**해야 한다.
7. **프로젝트가 사용한 기준자료 판을 함께 고정**해야 한다.
Aislo는 1~5와 7을 현재 구조에서 더 명시적으로 구현하고 있다. 추가 가치가 큰 부분은 프로젝트 패키지와 변경설계 비교다. STmate의 라벨 없는 RATE 행렬이나 고정폭 다중차수 열을 그대로 모방할 이유는 없다.
## 13. 아직 확정하면 안 되는 부분
- 자재 6개 후보 중 채택단가를 자동으로 고르는 정확한 알고리즘
- `BDQTY.X_QTY/X_HAL`의 실제 계산 순서와 편집 플래그 의미
- `RATE*` 행·열 전체의 화면 라벨과 구간 인덱스
- 중기 시간당 사용료의 버전별 세부 감가·정비 공식
- 이윤/부가세 끝수 조정의 모든 예외
- 변경설계에서 각 법정경비를 재계산하는지 증감식으로 처리하는지
이 항목은 서로 다른 입력을 저장한 전후 프로젝트 또는 정상 UI 조작 결과가 있어야 인과관계를 확정할 수 있다.
## 14. 누락 감사에서 보강한 자원단가 분기
### 노임은 단순히 L 단가 하나가 아니다
```text
건설업 시중노임
→ 일반 공종의 사람 품
→ 중기 운전사의 운전경비
제조업 조사노임
→ 공장 제작·가공품의 제조원가에만 제한적으로 사용
```
노임 원문에는 직종번호·직종명·적용일뿐 아니라 조사현장 부족 표시 `*`·`**`가 있다. 이 표시는 단가를 바꾸는 계수가 아니라 **신뢰도 메타데이터**다. 연장·야간·휴일·도서오지 가산은 노임 원천값 자체를 바꾸는 것이 아니라 별도의 노임 할증 계산이다. 산림품셈의 경사·작업시기 할증은 다시 그와 다르게 **품(인/단위)에 곱하는 계수**다.
### 자재 수량 할증과 잡재료비는 다른 계산이다
```text
자재 할증
순수량 × (1 + 손실률) → 내역에 투입할 자재수량 증가
잡재료·공구손료
주재료비 × 선택률 → 일위대가의 별도 재료비/경비 행
```
둘을 동시에 같은 자재에 적용할 때도 계산 위치가 다르며 중복 계상 여부를 확인해야 한다. 품셈 항목이 이미 할증을 포함하면 자재 할증을 다시 적용하지 않는다. 잡재료비의 밑수는 하위 일위대가가 품고 온 재료비가 아니라 해당 단계의 **직접 주재료비**여야 중복되지 않는다.
### 관급·사급 외에도 면세 분기가 있다
면세 자재가 있으면 부가가치세를 단순히 `총원가 × 10%`로 끝내지 않고 면세품목 공제·조정이 들어갈 수 있다. STmate 실무 출력에서 조정 사례는 확인됐으나 일반식과 적용 조건은 아직 전수 확정되지 않았다. Aislo 비교 시 “부가세 10%”만으로 완결됐다고 판단하면 안 된다.
## 15. 누락 감사에서 보강한 중기 계산 전체식
기존 계보는 X 코드의 입력·출력만 설명했지만, 실제 중기경비는 다음 네 묶음이다.
```text
시간당 기계손료
= 취득가격 × (시간당 상각비계수 + 정비비계수 + 관리비계수)
시간당 운전경비
= 연료·전력·윤활유 + 운전사 노임 + 정비비 외 소모품비
현장 작업 단가
= (시간당 기계손료 + 시간당 운전경비) ÷ 시간당 작업량 Q
총 기계 관련 원가
= 현장 작업 단가 + 현장 수송비 + 필요 시 분해조립비
```
입력 계보:
| 입력 | 가져오는 곳 | 영향을 받는 결과 |
|---|---|---|
| 국산 표준시가 또는 수입 C.I.F 가격 | 기계 기초자료 | 취득가격 |
| 환율 | 환율및기초자료 | 수입기계 취득가격과 모든 손료 성분 |
| 상각·정비·관리 계수 | 품셈 기계표 | 시간당 기계손료 |
| 지역 유가 | 현장 소재지 기준 유가 | 시간당 연료비 |
| 연료 소비량 | 기종·규격 기초자료 | 시간당 연료비 |
| 운전사 직종 | 기종 분류 | 시간당 노무비 |
| 싸이클 수·1회 작업량·체적환산·효율 | 품셈과 현장조건 | 시간당 작업량 `Q=n·q·f·E` |
| 이동거리·속도·상하차/대기 | 현장 운반조건 | 수송비·운반 단가 |
| 암질·기종·톤급 | 공종/장비 속성 | 손료 보정 여부와 가산률 |
암석작업 보정은 전체 중기사용료가 아니라 원칙적으로 **관리비를 제외한 기계손료**에 붙는다. 전용덤프트럭 18톤 이상과 불도저 19톤 이상은 보정 제외이며 타이어·습지 불도저는 예외다. 이 분기를 빼면 암 공종 장비비를 잘못 계산한다.
또한 운반은 단순한 `거리 × 단가`가 아니다. 작업량 계산에는 적재·주행·하차·회차·대기 싸이클과 도로 상태별 속도, 토량 상태 환산이 들어간다. STmate 산출 메모의 Q식은 이 결과인 “단위수량당 장비시간”을 일위대가에 넘긴다.
## 16. 누락 감사에서 보강한 수량→원가 경계
STmate는 설계기하를 직접 계산하는 시스템이라기보다 **산출된 공종 수량을 금원화하는 시스템**으로 봐야 한다. 따라서 다음 두 계산을 분리한다.
```text
설계수량 계산
도면·측량·구조물 규격 → ㎥/㎡/m/개소 등의 순수량
원가 투입수량 계산
순수량 → 단위 정규화 → 재료손실/품 할증/상태환산 → 내역 수량
```
필수 의미 항목:
- 토량의 자연·흐트러진·다짐 상태와 환산계수
- 수량 표기 자릿수와 합계 자릿수
- 소운반 포함 거리와 초과 운반
- 구조물 공제하지 않는 체적·면적
- 재료 할증이 포함된 품인지 별도 적용인지
- 관급 자재수량과 도급 시공품의 분리
- 같은 공종 안의 토사·리핑암·발파암, 육상·용수, 심도·규격 분기
`BOQ11.QTY` 하나만 비교하면 이 의미가 사라진다. Aislo와의 진짜 비교 단위는 최종 숫자가 아니라 `quantity_basis`, `volume_state`, `variant`, `surcharge`, `source geometry` 같은 수량 계보다.
## 17. 누락 감사에서 보강한 재귀 단가의 계산 순서
상위 단가 안의 비율 행은 일반 자원 참조와 순서가 다르다.
```text
1. 직접 자재 행을 합산 → 직접 주재료비 밑수 확보
2. 직접 사람 품을 합산 → 직접노무비 밑수 확보
3. 품 할인·할증을 노무 품에 적용
4. 잡재료·공구손료를 해당 밑수에 적용
5. 중기 X와 하위 일위대가 B/D를 재귀 해석
6. 재료·노무·경비 성분을 합산
7. 단가표 출력 위치 규칙으로 단수 처리
```
자기 자신을 가리키는 비율 행을 일반 참조처럼 먼저 풀면 순환이 생긴다. 동일한 하위 단가를 여러 상위 공종이 재사용할 수 있으므로 코드 참조 그래프의 순환 검사가 필요하다. STmate는 기초자료를 바꾸면 관련항목 전부를 재계산하는 특성이 교본에 명시되어 있어, 의존 그래프를 따라 파생 단가를 갱신하는 구조임을 뒷받침한다.
## 18. 누락 감사에서 보강한 직접비·자원집계의 이중 결과
같은 상세 내역에서 서로 다른 두 결과 묶음이 나온다.
### 원가 산입 내역
공종별 `수량 × 단가`를 원 단위 절사하여 BOQ에 저장하고 직접재료비·직접노무비·산출경비로 합산한다. 이 값이 원가계산의 밑수다.
### 자원 총괄표
공종별 상세 전개를 자원 코드별로 다시 모아 총 소요량과 금액을 만든다.
```text
자원별 총수량 = Σ(각 공종 수량 × 그 공종의 자원 원단위)
자원별 금액 = ROUND(자원별 총수량 × 채택 자원단가, 원)
```
자원집계는 반올림이고 내역 행은 절사이므로 둘의 합계가 원 단위에서 다를 수 있다. 자원집계 결과를 원가계산의 직접비로 다시 사용하면 STmate와 결과가 어긋나므로 **검산/출력 경로와 원가 산입 경로를 구분**해야 한다.
## 19. 누락 감사에서 보강한 규모·기간 선택과 순환
제비율의 율은 고정 상수가 아니라 최소 다음 조건의 함수다.
```text
적용률 = f(기준 시행일, 공사종류, 추정가격/규모 구간, 공사기간, 업체 등급, 적용대상 여부)
```
주의할 순환:
- 규모 구간을 고르는 기준금액이 원가계산 결과에 의존할 수 있다.
- 산업안전보건관리비는 관급 포함 대상액과 도급금액 조건이 얽힌다.
- 부가세·관급 끝수 보정을 이윤에 역반영한 실무 사례가 있다.
STmate가 이 순환을 푸는 내부 알고리즘은 확인되지 않았다. Aislo는 총원가로 구간이 고정될 때까지 반복하고 진동 시 높은 구간 채택 사실을 남긴다. 두 프로그램 비교에서는 최종률만 보지 말고 **구간 판정에 사용한 기준금액과 반복/보정 방식**을 함께 비교해야 한다.
## 20. 누락 감사에서 보강한 변경설계 계산
접미 1/2/3/4는 단순 대안이 아니라 당초·변경차수 계보로 해석하는 것이 타당하다.
```text
차수별 보존 대상
수량 / 자원 채택단가 / 복합단가 / 비목별 금액 / 관급자재대 / 총공사비
변경 결과
변경차수 금액 - 직전차수 금액 = 증감액
```
하지만 모든 제경비가 “변경판 전체를 처음부터 재계산”되는 것은 아니다. 산업안전보건관리비처럼 당초금액에 변경 증감액을 더하는 실무 방식이 관측됐다. 따라서 Aislo 비교 시 다음 셋을 항목별로 구분해야 한다.
1. 새 밑수와 새 율로 전액 재계산
2. 당초 확정액 + 변경분 계산
3. 사용자 조정액을 별도 반영
## 21. 완전성 체크리스트
| 계산 영역 | 입력 출처 | 핵심 변환 | 출력/다음 소비자 | 현재 확인 수준 |
|---|---|---|---|---|
| 기준판 선택 | STBSC/JB, 초기화 설정 | 시행일·업종·지역 선택 | 프로젝트 기준자료 | 구조 확인, UI 선택법 미확인 |
| 환율 | 기준일·통화별 환율 | 수입기계 C.I.F 가격 환산 | 기계 취득가·손료 | 공식 흐름 확인 |
| 자재 채택 | 6개 가격슬롯·페이지 | 채택 인덱스 선택 | M 적용단가 | 저장 구조 확인, 선택 알고리즘 미확인 |
| 노임 | 건협/제조업 직종표 | 직종 매핑·별도 할증 | L 적용단가 | 의미 확인 |
| 중기 손료 | 취득가·환율·손료계수 | 상각+정비+관리 | X 경비 성분 | 공식 의미 확인, STmate 세부 구현 미확인 |
| 중기 운전비 | 유가·소비량·운전사 | 재료+노무+소모품 | X 재료/노무 성분 | 공식 의미 확인 |
| 시공능력 | n·q·f·E·거리·속도 | Q와 단위당 시간 | B/D 기계 품 | 의미 확인, 전 기종 구현 미확인 |
| 중기품셈 | 기종별 제원·계수·작업조건 | 시공능력·소요시간 산정 | 중기사용료·단가산출 | 공식 단계 확인, STmate 내부표 매핑 미확인 |
| 일위대가 | 자원코드·품·비율행 | 재귀 조립·3성분 합산 | B/D 단가 | SMT 문법 확인 |
| 작업/표준시장단가 | 기관별 공표단가·시행시점 | 공종·규격 매칭 및 직접 채택 | 공종 단가 | 별도 자료경로 확인, 성분배분 미확인 |
| 설계수량 | 도면/수량산출 | 단위·상태·규격 분기 | 순수량 | STmate 밖 상류로 봄 |
| 원가 투입수량 | 순수량·할증·환산 | 적용수량 결정 | BOQ.QTY | 필드 구조 확인, BDQTY 내부 미확인 |
| 내역 행 | 수량·B/D 단가 | 성분별 곱·절사 | BOQ 금액 | 다수 XLSX 수식으로 확인 |
| 계층 합계 | BOQ 말단 금액 | T/E 트리 합산 | 공종·공구·총괄 | 확인 |
| 자원집계 | BOQ+단가 상세 | 코드별 수량 재집계·반올림 | 자원 총괄표 | 다수 XLSX 수식으로 확인 |
| 직접비 | BOQ 3성분 | 말단 성분 합계 | PRJLST 및 제비율 밑수 | 확인 |
| 원가계산기준 | 시행일·공사종류·규모·기간·등급 | 적용 조건과 율 선택 | 간접비 계산 파라미터 | 공식 단계 확인, RATE 인덱스 미확인 |
| 간접비 | 직접비·기간·규모·율 | 항목별 밑수×율·행별 절사 | 경비/노무 합계 | 다수 XLSX 교차 확인 |
| 일반관리·이윤 | 순공사원가·비목합 | 순서 의존 계산 | 총원가 | 확인 |
| 부가세 | 총원가·면세 조정 | 10%·절사·조정 | 도급공사비 | 기본 확인, 예외식 미확인 |
| 관급 | 관급 수량·조달단가 | 수수료 절사·총액 천원 올림 | 총공사비 별도 합산 | 다수 XLSX 교차 확인 |
| 변경설계 | 차수별 값 | 전액/증감/조정 분기 | 변경 총액·증감액 | 슬롯 확인, 항목별 규칙 일부 미확인 |
| 재현·출력 | SET_REP·INI·스냅샷 | 표별 단수·열 구성 | XLSX/인쇄/STC | 구조 확인 |
| 수정·재계산 | 기초단가·품·수량·기준 변경 | 참조 의존성 따라 무효화·재산출 | 관련 단가·공사비·간접비 | 교본 기능 확인, 내부 갱신 범위 미확인 |
이 표에서 `미확인`으로 남은 것은 누락이 아니라 **현재 증거로 확정할 수 없는 경계**다. 특히 자재 자동채택, BDQTY 내부 수량식, 전 기종 중기사용료, 면세·끝수 예외, 변경설계 항목별 처리의 다섯 부분은 실제 조작 전후 차분이 필요하다.
## 22. 공식 STmate 흐름도 역대조 결과
임도 교본의 STmate 전산처리 흐름도를 문서 전체와 역대조했다.
| 공식 흐름도 상자 | 이 문서 대응 | 감사 결과 |
|---|---|---|
| 기초자료: 노임·자재·중기단가·경비 | §2~3, §14 | 포함 |
| 환율 | §2, §15 | 포함 |
| 중기품셈 | §15, §21 | **독립 단계로 보강** |
| 중기사용료 계산 | §4, §15 | 포함 |
| 일위대가 | §4, §17 | 포함 |
| 작업단가 | §4 작업단가 경로 | **별도 경로로 보강** |
| 단가계산 | §4, §17 | 포함 |
| 공사수량 | §5, §16 | 포함 |
| 공사비계산 | §5~6 | 포함 |
| 원가계산기준 | §7, §19, §21 | **입력 단계로 보강** |
| 간접비계산 | §7~8 | 포함 |
| 수정·검토 | §1, 아래 영향전파 | **피드백 루프로 보강** |
| 단가표·중기사용료·단가산출서 | §4 및 출력 경로 | 포함 |
| 수량산출서·설계내역서 | §5, §16 | 포함 |
| 예산서 | §7~10 | 포함 |
### 수정 시 영향 전파
| 수정한 값 | 다시 계산되어야 하는 결과 |
|---|---|
| 자재단가 | 해당 자재를 참조하는 B/D/X → 해당 BOQ 행 → 직접재료비 → 관련 제경비 → 총액 |
| 노임단가 | 해당 L 참조 B/D/X → 직접노무비 → 간접노무비·보험료·기타경비·이윤 → 총액 |
| 유가·환율·중기 취득가 | X 중기사용료 → X를 참조하는 B/D → 산출경비 → 제경비·이윤 → 총액 |
| 품·Q·할증 | 해당 복합단가 → BOQ 행 → 비목별 직접비 → 간접비 → 총액 |
| 공사수량 | 해당 BOQ 행 금액 → 공종합계·직접비 → 간접비 → 총액 |
| 제비율판·기간·규모·등급 | 해당 간접비 행과 그 뒤 순서 의존 항목 → 총액 |
| 관급/사급 플래그 | 도급 재료비·관급자재대·안전관리비 대상액·부가세 경로 → 총액 |
STmate의 경쟁력은 이 영향 전파가 통합 단가 코드와 프로젝트 참조키로 연결된다는 점이다. Aislo 비교에서도 최종 결과 일치만 검사하지 말고 입력 하나를 바꿨을 때 위 하류 결과만 정확히 무효화·재계산되는지 검증해야 한다.
## 23. 두 번째 감사 후 남은 실제 정보 공백
계산 단계 자체는 공식 흐름도 기준으로 모두 문서에 들어왔다. 다만 다음은 “단계 누락”이 아니라 **경쟁 프로그램 내부 규칙이 아직 관찰되지 않은 정보 공백**이다.
1. `RATE*`의 행·열 인덱스가 공사종류·금액구간·기간·등급에 매핑되는 정확한 표
2. 표준시장/작업단가를 BOQ의 재료·노무·경비에 배분하는 규칙
3. 중기 S→X 계산에서 STmate가 쓰는 계수표와 중간 단수 위치
4. `BDQTY`의 순수량→할증수량→비목별 수량 전개 순서
5. 단가 후보를 채택하거나 `적용단가` 슬롯으로 복사하는 UI 알고리즘
6. 기초자료 수정 후 캐시/저장 단가 중 무엇을 자동 갱신하고 무엇을 확정값으로 보존하는지
7. 면세·관급 부가세 끝수와 이윤 역보정의 일반식
8. 변경설계 시 항목별 전액 재계산/증감계산/고정액 유지 규칙
9. 물가변동·일괄 단가변경 모듈이 기준시점과 비교시점 가격을 반영하는 방식
이 아홉 항목을 확인하지 않고 “STmate 계산 로직 완전 복원”이라고 표현하면 안 된다. 정상 실행 화면에서 한 입력만 바꾸어 저장 전후 파일과 출력 수식을 비교하는 실험이 필요하다.
@@ -0,0 +1,59 @@
# STmate 재구현 분석 — 판정기준과 근거 목록
## 목적
이 문서는 화면을 비슷하게 만드는 명세가 아니다. 동일 입력을 넣었을 때 STmate와 같은 중간값과 최종 금액을 내는 계산 엔진을 만들기 위한 증거 장부다.
## 확정등급
| 등급 | 의미 | 구현 처리 |
|---|---|---|
| A 확정 | STC 필드, 5개 STmate XLSX의 실제 수식, 복수 문서가 일치 | 호환 계산식으로 구현 가능 |
| B 강한 추정 | 필드와 출력은 일치하지만 내부 선택 분기 하나가 직접 관찰되지 않음 | 정책 테이블로 분리하고 회귀시험 필요 |
| C 미확정 | 정적 파일에 결과만 있거나 레코드가 난독화되어 분기를 복원하지 못함 | STmate 대조실험 전에는 기본값 확정 금지 |
## 직접 조사한 표본
- STC 7건: 2024년 임도 3건, 2025년 계류보전 1건, 울진 소광 원설계·통합변경·변경1차 3건
- STmate 생성 XLSX 5건: 위 사업 중 대응 가능한 2024/2025 내역서
- STC 안의 DBF: `PRJLST`, `BOQ11`, `BOQ12`, `COSTN`, `BDQTY`, `RATE`, `RATE_M`, `RATE_R`, `RATE_RA`, `SET_REP`
- 단가 구성 메모: `COSTN.SMT`
- 프로그램 모듈·설정: `STmate8.Exe`, `*.CPM`, `Start8x.Ini`
- 원가·품셈 기술자료와 과거 STmate 처리 흐름도
## 관찰된 스키마 변형
- `BOQ11`: 83필드와 94필드가 모두 존재한다.
- `BDQTY`: 37필드와 38필드가 존재한다.
- `COSTN`: 99필드와 101필드가 존재한다.
- `PRJLST`: 47·48·55필드가 존재한다.
- 소광 통합 파일에는 `BOQ11` 90행과 `BOQ12` 89행이 동시에 존재한다. 별도 변경1차 파일에는 `BOQ11`만 115행 존재한다.
따라서 재구현 저장 모델은 DBF 열 순서를 그대로 도메인 모델로 삼으면 안 된다. 파일 버전별 입력 어댑터가 열 이름을 정규화하고, 계산 코어는 `revision_id`가 붙은 동일한 내부 모델을 사용해야 한다.
## 계산 파이프라인
1. 기초자료: 노임·자재 후보가격·중기 기초값·경비·환율을 적재한다.
2. 중기품셈: 작업량 `Q`와 단위당 기계시간 `1/Q`를 산출한다.
3. 중기사용료: 손료·운전경비·운전원·연료 등을 재료/노무/경비 성분으로 분리한다.
4. 단가계산: 일위대가, 작업단가, 표준시장단가, 견적단가를 재료비(`MAMT`)·노무비(`LAMT`)·경비(`SAMT`)와 총계(`TAMT`)로 정규화한다.
5. 내역계산: 설계수량과 세 비용 성분을 곱하고 총계와 상호 검산하여 직접공사비를 집계한다.
6. 간접비계산: 제비율 행을 순차 계산하며 각 행 절사 결과를 다음 행의 기초로 전달한다.
7. 끝전조정·부가세·관급 합계를 계산한다.
8. 차수별 결과를 덮어쓰지 않고 스냅샷으로 보존한다.
## 중간값 보존 원칙
STmate 호환성은 최종 합계만 비교하면 검증할 수 없다. 다음 값을 모두 저장해야 한다.
- 선택 전 6개 자재 후보가격과 출처·페이지
- 채택가격과 선택 방식(자동/수동/직접입력)
- 단가 항목별 원수량, 할증 전 수량, 할증률, 할증 후 수량
- 단가 성분별 원금액과 절사 후 금액
- 내역 행별 재료비·노무비·경비·합계
- 간접비 행별 산정대상액, 요율, 계산 전 값, 절사액, 조정액
- 원설계·변경설계 차수와 이전 스냅샷
## 남은 한계
`BDQTY``SYSINFO` 레코드 본문은 보유 STC에서 난독화되어 있다. 비밀번호 우회나 암호 해제는 하지 않았다. 따라서 BDQTY의 세부 플래그와 UI 이벤트에 따른 자동갱신 범위는 C등급이며, 동일 프로그램 수준의 확정에는 정상 실행되는 STmate에서 통제 입력 대조시험이 필요하다.
@@ -0,0 +1,140 @@
# 내부규칙 1·7 — RATE 매핑, 간접비, 끝전조정
## 1. RATE 계열의 역할
| 테이블 | 크기 | 관찰 의미 | 대응 화면 그리드 (12번 문서 §8·§9) | 등급 |
|---|---:|---|---|---|
| `RATE.DBF` | 41×10 | 구버전·공통 요율 행렬 | 단일 그리드로 특정되지 않음 | B |
| `RATE_M.DBF` | 25×10 | 행자부기준 간접노무비 요율군 | `rGrd_RateM` (14행, 구분·간접노무비) | A/B |
| `RATE_R.DBF` | 50×35 | 일반형식 규모·기간 요율 + 안전·환경·보증 부속표 | `rGrd_Rate_R`, `_R1`, `_R2`, `_Kobo`, `_Anjun`, `_Hwan`, `_Bojng`, `_Hado`, `_Eqip` | B |
| `RATE_RA.DBF` | 50×20 | 실적형식 규모·기간 요율 + 실적 안전비 공식표 | `rGrd_Rate_RA`, `_RA1`, `_An_A`, `_An_A1` | A/B |
7개 STC 모두 네 테이블의 행·열 수와 필드명이 같다. `RATE` 첫 행들은 2024 표본에서 `10.8, 11.3, 11.8, 15.3 ...`, 2025 표본에서 일부가 `11.0, 11.5, 12.0 ...`으로 바뀐다. 즉 이 표는 프로젝트 결과가 아니라 연도/기준표 원본을 프로젝트에 복사해 둔 것으로 보는 것이 타당하다.
`RATE_R`은 첫 행의 21열=13.1, 26열=8.0, 31열=6.0처럼 일부 열만 채워지고 `RATE_RA`는 표본 대부분이 0이다. 희소한 이유는 한 행렬이 위 여러 그리드의 행을 순서대로 이어 붙여 적재하는 구조이기 때문이며, 해당 형식에서 쓰지 않는 구간이 0으로 남는다.
DBF 자체에는 행·열 라벨이 없다. 다만 폼 리소스 복원으로 **각 그리드의 열 제목과 행 수는 확정**됐다(12번 문서 §8). 남은 미확정은 라벨 자체가 아니라 **각 그리드가 행렬의 몇 번째 행부터 적재되는지, 즉 시작 좌표**다. 재구현 시에는 숫자 배열을 하드코딩하지 말고 `rate_standard(year, work_type, cost_item, amount_band, duration_band)`로 명명된 기준 테이블에 옮겨야 한다.
## 2. 요율 선택 입력
요율 하나를 선택하는 최소 입력은 다음과 같다.
- 기준연도·적용시점
- 공사 종류와 발주 유형
- 추정금액 또는 직접공사비 구간
- 공사기간 구간
- 요율 항목(간접노무비, 산재보험료, 안전관리비 등)
- 항목별 적용/제외 플래그
- 사용자 지정률과 조정액
원가계산 설정 화면의 **실제 선택축 16개와 각 선택지의 내부 코드값**은 폼 복원으로 확정됐다(12번 문서 §10·§10.1). 화면 순번과 내부값이 어긋나는 축이 여럿이므로(공사종류 `0,2,4,3,1,5,8,9`, 적용기준 `2,0,1`, 사급비 위치 `3,1,2,0`) 화면 인덱스를 그대로 저장하면 안 된다.
프로젝트 규모는 제비율을 거쳐 총액을 만들고, 총액은 다시 구간 선택에 쓰일 수 있어 순환 의존성이 생긴다.
**STmate가 택한 방식은 확정됐다 — A등급.** 실행모듈 문자열에 "공사규모에 따른 제비율 변경으로 공사규모가 계속 변경되는 무한루프"가 생길 수 있다는 경고와, 그때 일반관리비·이윤 등의 요율을 **사용자가 직접 수정**하라는 안내가 그대로 들어 있다(11번 문서 §8). 즉 STmate는 고정점 반복으로 자동 수렴시키지 않고 **순환이 생기면 사용자 수동 확정으로 넘긴다.**
재구현도 같은 계약을 따른다. ① 명시 입력인 추정금액 구간을 우선 사용하고 ② 자동 재선택은 최대 반복 횟수와 상태 이력으로 순환을 검출하며 ③ 구간이 왕복하면 임의의 한쪽을 택하지 않고 사용자 확정 상태로 전환하고 ④ 확정된 요율·원 표 좌표·사용자 수정 여부를 프로젝트 스냅샷에 보존한다.
## 3. XLSX로 확정되는 계산 순서
5개 STmate XLSX에서 내역 행은 `ROUNDDOWN(수량×단가, 0)`이다. 간접비도 각 행을 원 단위 절사한 뒤 그 절사액이 다음 행 참조에 사용된다. 자원 집계표·일위대가수량금액집계표·중기시간금액집계표는 `ROUND(수량×단가, 0)`를 사용한다. 동일 곱셈이라도 출력 목적에 따라 함수가 다르다.
권장 순서는 다음과 같다.
1. 직접재료비, 직접노무비, 직접경비 및 직접공사비를 내역 행 절사액으로 합산한다.
2. 간접노무비, 노무 기반 보험, 산업안전보건관리비, 환경보전비, 기타경비를 각각 고유 밑수에 요율을 곱해 구한다.
3. 일반관리비 → 이윤 → 부가가치세 → 관급자재 관련 합계 순으로 마무리한다.
### 항목별 밑수 — A등급 (2026-09-13 폼 복원으로 확정)
RATE 편집 화면(`TWM_KAN_RATE`)의 각 그리드는 **묶음 제목에 밑수 공식을 그대로 달고 있다.** 추정이 아니라 화면 문자열이다.
| 항목 | 화면에 적힌 밑수 공식 | 대응 그리드 |
|---|---|---|
| 간접노무비 | `(직접노무비) × 율(%)` | `rGrd_Rate_R1` |
| 기타경비 (일반형식) | `(재료비+노무비) × 율(%)` | `rGrd_Rate_R1` |
| 기타경비 (실적형식) | `직접공사비 × 율` | `rGrd_Rate_RA1` |
| 고용보험료 | `(노무비) × 율` | `rGrd_Rate_Kobo`, `rGrd_Rate_R2` |
| 산업안전보건관리비 (일반) | `(재료비+직접노무비+관급자재) × 율 + 추가금액` | `rGrd_Rate_Anjun` |
| 산업안전보건관리비 (실적) | `(직접공사비+관급자재) × 율 + 추가금액` | `rGrd_Rate_An_A1` |
| 환경보전비 | `(재료비+직접노무비+산출경비) × 율` | `rGrd_Rate_Hwan` |
| 공사이행보증수수료 | `[추가금액 + (직접공사비-기준금액) × 율] × 공기(년)` | `rGrd_Rate_Bojng` |
| 건설하도급대금 지급보증서 발급수수료 | `(재료비+직접노무비+산출경비) × 율` | `rGrd_Rate_Hado` |
| 건설기계대여대금 지급보증서 발급금액 | `(재료비+직접노무비+산출경비) × 율` | `rGrd_Rate_Eqip` |
| 일반관리비 | `(재+노+경) × 율` | `rGrd_Rate_R`, `rGrd_Rate_RA` |
| 이윤 | `(노+경+일) × 율` | `rGrd_Rate_R`, `rGrd_Rate_RA` |
바로잡을 점 셋.
- **환경보전비의 밑수는 직접공사비가 아니다** — `재료비+직접노무비+산출경비`다. 이 문서의 이전 서술을 정정한다.
- **기타경비의 밑수에 간접노무비가 따로 붙지 않는다** — 일반형식은 `재료비+노무비`(노무비는 직접+간접), 실적형식은 `직접공사비`**형식에 따라 밑수 자체가 다르다.**
- **이윤의 밑수는 일반형식에서 `노+경+일`로 확정** — 일반관리비가 밑수에 들어간다. `(소계−재료비)`, `(순공사원가+일반관리비−재료비)`로 적힌 곳들과 같은 식이다.
-**실적형식은 화면 라벨과 복원 공식이 어긋난다.** `rGrd_Rate_RA`의 라벨은 `(노+경+일)*율`인데 12번 §5·§6이 복원한 실적 공식은 `(직접공사비+간접공사비+일반관리비) × 율`**재료비를 포함한다.** 둘 중 어느 쪽이 실제 동작인지는 통제시험 **T11**로 가른다(13번 문서).
`rGrd_RateB`(수공 12행)의 열은 `재 / 직노 / 노 / 재+직노 / 재+노`가 토목·건축 두 열군으로 나뉜다. 수공형식은 **경비 항목마다 이 다섯 밑수 중 하나를 고르는** 구조다.
정확한 포함항목은 사업유형과 XLSX 양식에 따라 달라질 수 있으므로 `base_components`를 항목별 정책 데이터로 보존해야 한다. 하나의 공통 `subtotal * rate` 함수에 항목명을 분기문으로 박아 넣으면 변경설계와 연도 변경에서 깨진다.
## 4. 끝전조정과 세금
실제 XLSX에서 다음 형식이 관찰됐다.
```text
차액 = 기준금액 - ROUNDDOWN(기준금액, -자리수)
세전조정 = ROUND(차액 / 1.1, 0)
조건부조정 = ABS(차액) × IF(조건, 부호 또는 적용값)
최종이윤 = 산식이윤 - 참조조정액들
부가세 = ROUNDDOWN(과세표준 × 세율 / 100, 0) + 별도조정액
관급자재합계 = ROUNDUP(대상합계, -3)
```
핵심은 최종 도급액을 먼저 천원 단위로 자르고 부가세를 다시 구하는 단순 역산이 아니라, 차액의 세전 상당액을 이윤 또는 조정행에 배분하고 부가세 행에도 조정액을 전달한다는 점이다.
실행모듈에서 `[C_AD_AMT]``ROUND` / `ROUNDDOWN` / `ROUNDUP` 세 선택이 모두 확인됐고(11번 문서 §11), 설정 화면에는 간접비·공급가액·도급액·관급(도급자설치)·관급(관급자설치)·총액/이윤보정의 **절사 자리와 함수가 각각 따로** 있다(12번 문서 §10.2). 따라서 전역 반올림 설정 하나로 구현하면 안 되고, 재구현 모델에는 다음 여섯 칸이 필요하다.
```text
raw_amount
rounded_amount
adjustment_amount
adjustment_target
rounding_function
rounding_digits
```
`이윤 보정=0`은 "0원 이윤"이 아니라 이윤보정 미사용 옵션이므로 0과 미설정을 구분해야 한다.
## 5. 의사코드
```text
for cost_item in ordered_indirect_cost_items:
base = sum(already_truncated[item] for item in cost_item.base_components)
raw = base * selected_rate / 100
amount = truncate(raw, cost_item.rounding_digits)
already_truncated[cost_item.code] = amount
target_total = truncate(grand_total_before_adjustment, -target_digits)
difference = grand_total_before_adjustment - target_total
pretax_adjustment = round_half_away_or_excel(difference / (1 + vat_rate), 0)
profit_final = profit_raw - pretax_adjustment - other_adjustments
vat_final = truncate(tax_base * vat_rate, 0) + vat_adjustment
```
Excel `ROUND`의 .5 처리와 Python 기본 `round`는 다를 수 있다. 금액 계산은 이진 부동소수점 대신 10진수와 Excel 호환 반올림 함수를 써야 한다.
## 6. 미확정 항목과 대조시험
폼 리소스 복원으로 아래 두 항목은 이 목록에서 **내려갔다.**
- ~~RATE 네 표의 정확한 행·열 라벨~~ → 그리드별 열 제목·행 수 확정 (12번 문서 §8)
- ~~요율 순환 의존성의 STmate 처리 방식~~ → 사용자 수동 확정으로 확정 (11번 문서 §8)
남은 미확정은 다음과 같다.
- 각 그리드가 `RATE*` 행렬의 **몇 번째 행부터 적재되는지** — 시작 좌표
- 규모 구간 경계의 포함 방향(`<`, `<=`)
- 공사기간 경계 처리 — 화면 목록은 4줄인데 내부값은 `30일 미만`·`37개월 이상`을 포함한 5개로 개수가 어긋남 (12번 문서 §10.1)
- 특정 보험·안전비의 예외 포함항목
- 복합 보험식 `RAT_1`~`RAT_4`, `RAT_KY`의 화면 항목명
시험은 동일 프로젝트를 복제하고 추정금액을 각 경계의 직전/동일/직후로, 기간도 동일하게 바꾼 뒤 선택된 요율과 모든 간접비 행을 비교한다. 이 결과 없이는 시작 좌표 매핑을 A등급으로 올릴 수 없다.
@@ -0,0 +1,100 @@
# 내부규칙 2·3·4·5 — 직접비 단가, 중기, BDQTY, 자재 채택
## 1. 모든 단가의 공통 출력 계약
STmate의 단가 항목은 출처가 달라도 최종적으로 세 비용 성분과 총계를 낸다.
```text
TAMT = MAMT(material) + LAMT(labor) + SAMT(expense)
```
`COSTN.TAMTn/LAMTn/MAMTn/SAMTn`은 차수 n의 총계·노무·재료·경비다. BOQ의 `T_AMT/L_AMT/M_AMT/S_AMT`도 같은 구조다. 바이너리 내부 조건식 `TAMT1<>MAMT1+LAMT1+SAMT1`이 이 관계를 직접 검증한다. 재구현할 때 표준시장단가나 견적단가를 총액 하나로만 저장하면 내역은 맞아도 간접비 산정기초가 달라진다.
## 2. 일위대가·작업단가·표준시장단가
### 입력
- 항목 코드·명칭·규격·단위
- 구성 자원 코드와 유형(재료 M, 노무 L, 중기/경비 X 등)
- 구성 수량 또는 산식
- 할증·보정 전후 수량
- 구성 자원의 채택단가, 재료·노무·경비 성분 및 총계
- 직접 입력 또는 성분 배분값
### 계산
```text
component_amount[k] = quantity_after_adjustment × referenced_unit_component[k]
unit_component[k] = sum(component_amount[k])
```
`COSTN.SMT`에는 `&M00034M&`, `&L00010L&`, `&X00055M&` 같은 참조 토큰과 수량·백분율·산식 문자열이 남는다. 마지막 글자는 참조 항목에서 가져올 성분을 뜻하는 것으로 강하게 추정된다. 따라서 계산기는 메모 표시 문자열이 아니라 토큰을 파싱한 의존 그래프를 먼저 만들고 위상순서로 단가를 계산해야 한다. 순환 참조는 오류로 보고해야 한다.
표준시장단가·작업단가는 일위대가와 병렬 입력이다. 직접 성분이 주어진 경우 그대로 쓰고, 총액만 주어진 경우 STmate와 동일한 성분 배분 자료가 없으면 임의 분배하지 않는다. 총액 전부를 경비로 넣는 편의 구현은 간접비를 바꾸므로 금지한다.
## 3. 중기 시간당 단가
### 계산 단계
```text
hourly_ownership = acquisition_price × (depreciation_factor + maintenance_factor + management_factor)
hourly_fuel = fuel_consumption_per_hour × adopted_fuel_price
hourly_lubricant = lubricant_rule(hourly_fuel or consumption)
hourly_labor = operator_daily_wage / daily_hours × labor_adjustments
hourly_operating = hourly_fuel + hourly_lubricant + hourly_labor + consumables
hourly_machine = hourly_ownership + hourly_operating + transport_hourly + assembly_hourly
production_per_hour Q = n × q × f × E
machine_hours_per_unit = 1 / Q
unit_machine_cost = machine_hours_per_unit × hourly_machine
```
중기 성분 참조 토큰이 M/L/S로 나뉘므로 연료·소모품은 재료, 운전원은 노무, 손료·정비·관리·운반·조립은 경비로 분리하여 상위 단가에 전달해야 한다. 암질 보정은 모든 장비에 일괄 적용하지 않고 제외 장비를 가진 정책으로 처리해야 한다.
XLSX의 `중기시간금액집계표`에서는 시간×중기목록표 단가를 `ROUND(...,0)`한다. 하지만 중기 내부의 각 세부항목 절사 시점은 출력 수식만으로 완전히 확정되지 않았다. 내부 원값, 표시값, 상위 전달값을 분리해 저장해야 한다.
## 4. BDQTY 수량·할증
확인된 필드는 `BDCODE`, `CODE`, `NAME`, `SIZE`, `UNIT`, `QTY1..4`, `DEVD1..4`, `X_QTY1..3`, `X_HAL1..3`, `RATE`, `X_RATE`, `S_RATE`, `PRPT`, `TPRPT`, `PRIN`, `PROUT`, `EQCODE`, `SBMOK` 등이다.
최소 의미 모델은 다음과 같다.
```text
source_quantity # 품셈 또는 사용자가 입력한 원수량
pre_surcharge_qty # X_QTY 계열
surcharge_rate # X_HAL/RATE 계열
post_surcharge_qty # 단가계산에 실제 투입되는 수량
revision_quantity # QTY1..4
waste_or_output # PRIN/PROUT 등 투입·산출 관계
```
재료 수량 할증과 잡재료/공구손료 같은 금액 가산은 다른 연산이다. 전자는 수량을 바꾼 뒤 단가와 곱하고, 후자는 특정 성분 소계에 비율을 곱해 별도 비용행을 만든다. 둘을 하나의 `surcharge` 필드로 합치면 안 된다.
BDQTY 본문은 난독화되어 필드별 실제 값 연결은 C등급이다. 구현 전 대조시험은 하나의 단가에 재료·노무·중기 각 1개만 넣고, 각 할증 입력을 하나씩 바꿔 `QTY`, `X_QTY`, `X_HAL`, 세 비용 성분과 총계 변화를 저장하는 방식이어야 한다.
## 5. 자재 6개 가격과 채택가격
`COSTN`은 차수마다 `AMT_11..AMT_61`처럼 6개 후보가격을 보관하고, 페이지/출처 보조필드 `PG_11..PG_51`, 채택 출처 인덱스 `PG_1..PG_4`, 채택 관련 플래그 `AMT_1..AMT_4`를 가진다. 재료의 최종 채택가는 `MAMT1..4`이며 `TAMT1..4`는 해당 자원의 총단가다.
7개 STC 교차비교 결과:
- 재료 M 항목의 채택가는 파일마다 후보 1~6 중 여러 슬롯과 일치한다.
- 같은 채택가가 여러 후보 슬롯에 중복되어 한 레코드만으로 선택 슬롯을 역추정할 수 없다.
- 2025 소광 표본은 M 43건 중 후보6과 채택가가 일치하는 행이 37건으로 많지만, 다른 후보와도 중복 일치한다.
- 노무 L은 다수 파일에서 후보6과 채택가가 거의 일치한다. 이는 후보6이 범용 “채택/적용” 칸일 가능성을 높이지만 자동선정 규칙 자체를 증명하지는 않는다.
`Start8x.Ini`의 표시명은 설치/기관별로 바뀔 수 있으므로 슬롯 번호에 특정 가격지 이름을 코드로 고정하면 안 된다. 데이터 모델은 다음처럼 출처를 별도 행으로 둔다.
```text
price_candidate(material_id, revision_id, slot_no, source_name, page, observed_price, observed_at)
price_adoption(material_id, revision_id, chosen_slot_no?, adopted_price, method, user_override)
```
자동선정은 현재 C등급이다. 최저가·최신가·특정 슬롯 우선 중 어느 하나라고 단정할 근거가 없다. 동일 구현 전에는 후보 조합을 통제한 STmate 시험이 필수다: 6개 슬롯에 서로 다른 값, 동률, 0, 공란을 배치하고 채택값과 `PG_1` 변화를 기록한다.
## 6. 반올림 경계
- 내역서 행 금액: `ROUNDDOWN(수량×단가,0)` — A
- 자원/일위대가/중기 집계표 행 금액: `ROUND(수량×단가,0)` — A
- 단가 내부 구성행과 성분 소계: 표본별 좌표 추가 대조 필요 — B/C
계산 엔진은 출력표마다 다시 계산하지 말고 동일 원수량·원단가에서 각 보고서의 반올림 정책을 명시적으로 적용해야 한다.
@@ -0,0 +1,98 @@
# 내부규칙 6·8·9 — 재계산, 변경설계, 일괄변경
## 1. 재계산 의존 그래프
재계산 범위는 화면 단위가 아니라 데이터 의존성으로 결정해야 한다.
```text
노임/자재/환율 ─┐
중기 기초값 ────┼→ 중기시간단가 → 일위·작업단가 ─┐
품셈/할증 ──────┘ ├→ 내역 직접비 → 간접비 → VAT/끝전 → 출력
설계수량 ────────────────────────────────────────┘
요율기준 ─────────────────────────────────────────────────→ 간접비 이후
```
### 변경별 최소 무효화 범위
| 변경 | 반드시 다시 계산할 대상 |
|---|---|
| 자재 채택가 | 해당 자재를 참조하는 중기·단가의 모든 상위 노드, 내역, 간접비 |
| 노임 | 해당 직종을 참조하는 중기·단가, 직접·간접노무 기반 비용 |
| 유류·환율 | 해당 중기, 이를 참조하는 단가와 상위 내역 |
| 품셈 수량/할증 | 해당 단가와 상위 단가·내역 |
| 설계수량 | 해당 내역 행과 상위 공종 합계, 간접비. 단가표 자체는 유지 |
| 요율표/규모/기간 | 직접비 유지, 간접비 이후 재계산 |
| 출력 서식 | 계산 캐시 유지, 보고서만 재생성 |
`COSTN.SMT` 참조 토큰은 이 역의존성 인덱스를 만드는 핵심 근거다. 문자열을 계산할 때마다 전수 검색하지 말고 저장 시 `dependency(parent_code, child_code, component)`로 정규화한다.
STmate UI에서 어떤 버튼이 부분계산 또는 전체계산을 수행하는지는 정적 자료로 확정되지 않았다. 그러나 동일 결과를 만드는 데 필요한 최소 범위는 위 표로 명세할 수 있다. 계산 결과에는 입력 버전 해시를 남겨 오래된 캐시가 출력되는 일을 막는다.
## 2. 변경설계 데이터 모델
STC에는 두 형태가 동시에 확인된다.
1. 한 파일 안에 `BOQ11`, `BOQ12`를 함께 저장하는 통합형: 소광 표본은 각각 90행, 89행이다.
2. 변경 차수를 별도 STC로 저장하면서 그 파일의 `BOQ11`을 현재안으로 쓰는 분리형: 소광 변경1차 표본은 115행이다.
또한 `COSTN`과 여러 필드의 접미사 1~4는 원설계와 최대 3개 변경차수의 값을 나란히 담을 수 있다. 따라서 “접미사 n=항상 BOQ1n”으로 기계적으로 가정하지 말고 프로젝트 메타데이터와 실제 존재 테이블을 함께 해석해야 한다.
### STmate의 실제 변경설계 계산모드 — A등급
실행모듈에 간접비 변경분 산식 두 개가 그대로 들어 있다 (11번 문서 §10).
```text
방법 A = C_AMT_B
+ ROUNDDOWN(C_AMT_B × ((C_TAMT_C-C_TAMT_B)/C_TAMT_B), digits)
방법 B = C_AMT_B
+ ROUNDDOWN((C_TAMT_C-C_TAMT_B) × RAT_1, digits)
```
여기에 보험료 사후정산 항목의 **당초금액 직접입력**(직접입력 체크가 없으면 적용 거부)과, 계약 제잡비율 적용 시 간접노무비부터 부가세 직전까지를 `직접비 변경분 × 계약 제잡비율`로 조정하는 경로가 더 있다. 보험료 변경(`cBx_CH_BO`)은 별도로 세 모드를 가진다 (12번 문서 §10.3).
```text
0 직접노무비 × 요율
1 당초액 + 직접노무비 증감 × 요율
2 당초액 + 증감액(비율)
```
**STmate는 각 차수를 전부 독립 재계산하는 한 가지 방식이 아니라, 항목별로 계산모드를 고르는 구조다.**
### 재구현 규칙
- 원설계를 불변 revision 1로 보존한다.
- 변경 시작 시 이전 차수의 단가·수량·요율 선택을 복사한 스냅샷을 만든다.
- 변경한 입력과 자동 재계산 결과를 구분한다.
- 비교표는 `original`, `previous`, `current`, `delta`를 모두 계산한다.
- 삭제 항목은 물리 삭제하지 않고 현재 차수에 0/제외 상태로 남겨 코드 대응을 보존한다.
- 신규 항목은 안정적인 내부 ID와 차수별 표시 순서를 가진다.
- 간접비 항목마다 `recalculated`, `proportional_from_original`(방법 A), `delta_times_rate`(방법 B), `carry_original`, `manual`을 **계산모드 값으로 저장**한다. 절사 비선형성 때문에 모드가 다르면 원 단위 결과가 갈리므로, 모드를 하나로 고정하면 STmate 결과를 재현할 수 없다.
- Aislo 자체 기본값으로는 전 차수 독립 재계산(`recalculated`)을 권장하되, **STmate 호환 모드와 구분해서** 둔다.
## 3. 일괄 단가변경·물가변동
프로그램 모듈명과 필드(`EDT_DATE`, `BQCODE`, 후보가격, 환율 등)로 일괄변경 기능의 존재는 확인되지만 세부 필터와 우선순위는 정적 자료만으로 확정되지 않았다.
동일 프로그램 수준의 안전한 처리 계약은 다음과 같다.
1. 대상 스냅샷을 먼저 확정한다: 차수, 코드 유형, 품목 범위, 가격 출처, 기준일.
2. 각 레코드에 변경 전 후보가·채택가·선택방식과 변경 후 값을 기록한다.
3. 수동 고정값을 자동 변경이 덮을지 정책을 명시한다. 기본적으로 수동고정은 제외한다.
4. 가격을 바꾼 뒤 역의존 그래프로 영향받는 항목만 재계산한다.
5. 변경 전/후 직접비, 간접비, VAT, 총액을 함께 미리보기한다.
6. 확정 시 새 revision으로 원자적으로 저장하며 이전 차수는 보존한다.
물가변동은 단순히 모든 단가에 같은 배율을 곱하는 기능으로 만들면 안 된다. 노무·재료·중기·견적의 기준일과 출처가 다르고, 중기는 연료·노무·손료 성분을 다시 계산해야 하기 때문이다.
## 4. 반드시 필요한 STmate 대조시험
- 같은 자재를 참조하는 단가 2개와 그중 하나를 참조하는 상위 단가를 만든 뒤 자재가 1원 변경
- 설계수량만 변경하여 단가표 불변 여부 확인
- 요율만 변경하여 직접비 불변 여부 확인
- 원설계에서 항목 추가·삭제·수량변경·단가변경을 각각 한 건씩 만들어 변경 STC 저장
- 일괄변경에서 수동 채택가, 0원, 공란, 환율적용 품목이 섞인 표본 실행
- 각 시험 전후 STC의 모든 DBF 필드와 XLSX 모든 계산행 비교
이 시험 전까지 UI 버튼별 재계산 범위, 수동값 우선순위, 물가변동 필터는 C등급이다. 다만 **변경설계 간접비 계산모드 자체는 코드에서 공식을 직접 확인해 A등급**이며(§2), 이 시험의 목적은 "어느 모드가 어느 조건에서 선택되는가"를 가르는 데 있다.
@@ -0,0 +1,131 @@
# STmate 호환 계산 엔진 — 통합 재구현 명세
## 1. 완료 정의
다음 조건을 모두 만족해야 “동일 프로그램을 만들 수 있는 분석”이 완료된다.
- 같은 입력에서 단가의 재료·노무·경비 성분과 그 총계가 각각 일치한다.
- 내역 행, 공종 소계, 직접비, 모든 간접비 행, 이윤, VAT, 관급합계가 각각 일치한다.
- 원설계와 변경설계가 독립 재현되고 차액이 일치한다.
- 출력 목적별 `ROUND`, `ROUNDDOWN`, `ROUNDUP` 차이가 일치한다.
- 기초가격 하나를 바꿀 때 영향받는 항목과 보존되는 항목이 일치한다.
- 자동선택과 수동고정의 우선순위가 일치한다.
최종 총액만 일치하는 것은 합격이 아니다.
## 2. 내부 데이터셋
### 프로젝트와 차수
```text
project(id, name, work_type, owner_type, base_date, duration, estimate_band)
revision(id, project_id, sequence, kind, parent_revision_id, created_at)
```
### 기초가격
```text
resource(id, code, type, name, size, unit)
price_candidate(resource_id, revision_id, slot, source, page, price, date)
price_adoption(resource_id, revision_id, chosen_slot, adopted_price, method, locked)
```
### 단가 구성과 계산 결과
```text
unit_item(id, code, kind, name, size, unit)
unit_component(unit_item_id, revision_id, seq, ref_id, ref_component,
source_qty, pre_surcharge_qty, surcharge_rate, applied_qty, expression)
unit_result(unit_item_id, revision_id, material, labor, expense, total)
dependency(parent_id, child_id, component)
```
### 내역과 간접비
```text
boq_item(id, revision_id, parent_id, seq, code, ref_unit_item_id, design_qty, state)
boq_result(boq_item_id, material_unit, labor_unit, expense_unit, total_unit,
material_amount, labor_amount, expense_amount, total_amount)
rate_standard(year, work_type, cost_code, amount_band, duration_band, rate)
indirect_rule(cost_code, order_no, base_components, rounding_mode, rounding_digits)
indirect_result(revision_id, cost_code, base_amount, rate, raw_amount,
rounded_amount, adjustment_amount)
```
`base_components`는 문자열 수식보다 검증 가능한 코드 목록/연산 트리로 저장한다.
## 3. 계산 순서
```text
validate inputs
select adopted resource prices
build dependency graph; reject cycles
calculate machine hourly rates
calculate unit items in topological order
calculate BOQ leaf rows with BOQ rounding policy
aggregate BOQ tree bottom-up
select rates from project classification
calculate indirect rows in fixed order using already-rounded predecessors
calculate profit/end adjustment/VAT/government-material totals
freeze revision result and generate reports
```
## 4. 숫자 규칙
- 모든 금액·수량·요율은 decimal로 계산한다.
- 입력 원값과 표시 반올림값을 분리한다.
- 내역 행은 원 단위 내림, 자원집계는 원 단위 Excel 반올림, 관급합계는 천원 단위 올림 등 출력별 정책을 코드가 아닌 데이터로 명명한다.
- 간접비 다음 행은 앞 행의 원값이 아니라 절사된 확정액을 참조한다.
- 합계 후 절사와 행별 절사 후 합계를 혼용하지 않는다.
## 5. 호환 어댑터
- STC는 ZIP 컨테이너로 읽고 파일명 대소문자를 무시한다.
- DBF 03/E5/06 변형과 필드 수 차이를 버전 어댑터에서 흡수한다.
- `BOQ11..14`와 접미사 1..4를 revision으로 정규화하되 실제 테이블 존재 여부와 프로젝트 메타데이터로 판정한다.
- `COSTN.SMT` 토큰을 파싱해 구성항목과 의존성을 복원한다.
- 난독화된 `BDQTY`는 합법적으로 확보된 평문/API 또는 STmate 대조실험 결과 없이는 임의 복호화하지 않는다.
## 6. 모듈 경계
화면이나 보고서와 계산 코어를 분리한다. 필요한 모듈은 여섯 개면 충분하다.
1. `stc_adapter`: STC/DBF/SMT를 정규화한다.
2. `price_engine`: 후보가격과 채택을 관리한다.
3. `unit_engine`: BDQTY, 중기, 일위·작업·시장·견적 단가를 계산한다.
4. `boq_engine`: 계층 내역과 직접비를 계산한다.
5. `indirect_engine`: RATE 선택, 제비율, 끝전, VAT를 계산한다.
6. `revision_engine`: 원설계·변경설계 스냅샷과 차이를 관리한다.
별도 규칙 엔진 프레임워크나 범용 수식 언어는 필요 없다. 관찰된 연산 트리와 정책 테이블이면 충분하다.
## 7. 시험 골든셋
각 보유 STC/XLSX 쌍에서 다음 JSON을 추출해 골든셋으로 둔다.
```text
resource adopted prices
unit four-component prices
BOQ quantities and four-component row amounts
indirect row: base/rate/raw/rounded/adjustment
revision comparison
report-specific rounded aggregates
```
시험은 ① 현재 5개 실문서 회귀, ② 경계값 합성시험, ③ STmate 통제 입력 대조시험으로 나눈다. A등급 규칙은 즉시 회귀시험으로 고정하고, B/C등급은 정책 플래그 아래 구현하여 대조결과가 나올 때만 기본값을 확정한다.
## 8. 현재 구현 가능 범위
지금 자료만으로 A등급 구현 가능한 부분은 STC 컨테이너와 주요 스키마, 단가의 재료·노무·경비와 총계 구조, BOQ 계산 및 계층집계, 주요 간접비 흐름, 보고서별 반올림, 변경 차수 보존 구조다.
STmate와 100% 동일하다고 아직 보증할 수 없는 부분은 RATE 좌표 라벨·경계, BDQTY 세부 플래그, 자재 자동채택 우선순위, 중기 내부 절사 시점, UI 명령별 재계산 범위, 일괄변경의 수동값 우선순위다. 이 여섯 항목은 구현상의 사소한 선택이 아니라 결과 금액을 바꾸는 호환성 차단점이다.
## 9. 구현 착수 순서
1. 5개 XLSX에서 골든셋을 추출하고 반올림 함수를 고정한다.
2. COSTN·BOQ 어댑터와 단가 의존 그래프를 구현한다.
3. 직접비와 간접비를 골든셋에 맞춘다.
4. 중기와 자재 후보가격을 연결한다.
5. revision 스냅샷과 변경 비교를 구현한다.
6. 여섯 미확정 항목에 대해 STmate 통제 대조시험을 수행한다.
7. 대조결과를 정책 기본값으로 승격하고 전체 회귀를 다시 통과시킨다.
@@ -0,0 +1,148 @@
# STmate System 186개 파일 분석 장부
분석 대상: `C:\경영정보(주)\System`
기준일: 2026-09-13
판정 원칙: 파일명 추정은 완료로 세지 않으며, 바이너리 내부 근거와 계산 입출력 연결이 확인되어야 `계산 의미 완료`로 판정한다.
## 1. 현재 숫자
| 수준 | 완료 | 남음 | 의미 |
|---|---:|---:|---|
| 전체 파일 등록·SHA-256·크기 | 186 | 0 | 전 파일 변경 추적 가능 |
| 매직·컨테이너/PE/DBF 형식 확인 | 186 | 0 | 파일명 아닌 실제 헤더 기준 |
| 핵심 CPM 내부구조 추출 | 12 | 0 | 우선대상 12개 모두 PE 섹션·import/export·문자열 추출 |
| 전체 파일 내부구조 추출 | 186 | 0 | PE 82, DBF 계열 61, ZIP 28, 기타 포맷 15 |
| 계산 의미 교차검증 완료 파일 | 0 | 186 | 함수 입력→중간값→출력이 모두 확인된 파일은 아직 없음 |
형식별 실제 판정은 PE 82개, ZIP 28개, DBF 계열 61개, 텍스트 8개, BTLF 2개, BTCV·SIxMemo·DOS-MZ·난독화 로그·팁 데이터 각 1개다. 파일별 전체 장부는 함께 생성한 `system_inventory.csv`에 있으며 UTF-8 BOM과 SHA-256을 포함한다.
## 2. 핵심 CPM 12개 1차 정적 분석
모든 모듈은 32비트 Delphi 6 계열 PE이며 `CODE`, `DATA`, `BSS`, `.idata`, `.edata`, `.reloc`, `.rsrc` 섹션을 가진다. 공통적으로 Delphi 런타임, Apollo DBF 엔진 및 내부 모듈 `ST_COM_V.CPM`, `ST_FUNC_C.CPM`, `DP_COMMON.CPM`을 사용한다.
| 모듈 | 확인된 export | 내부 근거로 확인된 역할 | 상태 |
|---|---|---|---|
| `ST_Boq.CPM` | `Edit_Boq`, `Edit_Bqm`, `Add_From_MRG`, `Calc_Kanjub` | BOQ 편집, 병합 입력, 간접비 호출, BDQTY/COSTN/PRJLST 접근 | 내부구조 추출 |
| `ST_EdiLWi.CPM` | `Edit_iLW`, `Calc_Kanjub` | 일위대가 편집, BDQTY 수량·할증 필드 접근 | 내부구조 추출 |
| `ST_KanJub.CPM` | `Edit_KanJub`, `Edit_KanJub_K`, `Edit_Kan_Rate`, `Prn_Kan_Rate`, `Calc_Kanjub` | 제비율 편집·인쇄·계산 | 내부구조 추출 |
| `ST_SanCal.CPM` | `Calq_San`, `Calc_Kanjub` | 단가산출, `GET_ROUND_CUT`, `RoundTo`, 성분 소계 | 내부구조 추출 |
| `STmateQty8.CPM` | `ST_QTY`, `FIND_QCODE`, `Free_Qty`, `Calc_Kanjub` | QTY0~QTY9, IFORM, Excel 수량 가져오기, BOQ 전송 | 내부구조 추출 |
| `ST_P_Joong.CPM` | `Prn_Joong*`, `Calc_Kanjub` | 중기 재료·노무·경비, HalM/HalL/HalS 출력 | 내부구조 추출 |
| `ST_P_Collect.CPM` | `Prn_Col_Dan*`, `Prn_Col_X*`, `Calc_Kanjub` | 단가·중기 자원 역집계, `CON_QTY11.DBF` | 내부구조 추출 |
| `ST_P_ConEst.CPM` | `Prn_Nae_*`, `Prn_Jab_K`, `Calc_Kanjub` | 원가·내역 출력, BOQ11 연동 | 내부구조 추출 |
| `ST_U_ChgAmt.CPM` | `CHANGE_AMT`, `Calc_Kanjub` | COSTN/COSTA 단가 일괄변경 | 내부구조 추출 |
| `ST_U_ChgCode.CPM` | `Chg_Code_*`, `Exec_Change_Code`, `Exec_Replace_Code`, `Tran_SAN_Format` 등 | 코드 일괄·선택 변경, Excel 왕복, CH_CODE 임시표 | 내부구조 추출 |
| `ST_U_ConBD.CPM` | `CON_QTY`, `CON_QTY9`, `CONBD_USD_QTY`, `Calc_Kanjub` | BOQ↔BDQTY 수량 연결, 행유형 필터 | 내부구조 추출 |
| `ST_U_Convert.CPM` | `Conv_BOQ`, `Conv_Equip`, `Conv_ST8_XML`, `Conv_XML_ST8`, `MK_SET_REP` 등 | 구형/ST8/XML/조달 형식 변환, RATE/JB 복사 | 내부구조 추출 |
## 3. 바이너리에서 새로 확정된 계산 규칙
### 단가 성분 관계 — A등급
세 모듈에서 다음 검증 조건식이 그대로 발견됐다.
```text
TAMT1 <> MAMT1 + LAMT1 + SAMT1
```
또한 자원 유형별 검증도 존재한다.
```text
CODE="L" → LAMT1 = TAMT1
CODE="M" → MAMT1 = TAMT1
CODE="S" → SAMT1 = TAMT1
복합/W 코드 → TAMT1 = MAMT1 + LAMT1 + SAMT1
```
따라서 `TAMT`는 네 번째 비용 성분이 아니라 총계다. 기존 05·07·09 문서를 이에 맞게 정정했다.
### 변경설계 산식 템플릿 — 코드 존재 A, 항목 대응 B
12개 모듈 공통 코드에 다음 두 템플릿이 포함돼 있다.
```text
C_AMT_B + ROUNDDOWN(C_AMT_B × ((C_TAMT_C-C_TAMT_B)/C_TAMT_B), 자리)
C_AMT_B + ROUNDDOWN((C_TAMT_C-C_TAMT_B) × RAT_1, 자리)
```
이는 변경금액을 무조건 전체 재계산하는 것이 아니라 당초 확정액에 기초금액 증감률 또는 증감액×요율을 더하는 두 경로가 있음을 확인한다.
### 간접비 산정기초 템플릿 — A등급
바이너리에 다음 원형이 존재한다.
```text
ROUNDDOWN(LAMT × RAT_1, 자리)
ROUNDDOWN((L_AMT + LAB) × RAT_1, 자리)
ROUNDDOWN(C_KUNBO × RAT_1, 자리)
ROUNDDOWN(T_AMT × RAT_1, 0)
ROUNDDOWN((T_AMT - M_AMT) × RAT_1, 0)
ROUNDDOWN(M_AMT × RAT_1, 0)
ROUNDDOWN((M_AMT + L_AMT + S_AMT ...) × RAT_1, ...)
ROUND/ROUNDDOWN/ROUNDUP(C_AD_AMT, -자리)
```
XLSX에서 관찰한 산식이 출력물에 우연히 생긴 것이 아니라 STmate 공통 계산 코드에 들어 있는 템플릿임을 확인했다.
### 복합 보험성 산식 — B등급
다음 중첩 절사식도 확인됐다.
```text
ROUNDDOWN(
ROUNDDOWN(LAMT×RAT_1×RAT_2/100×1.4,0)
+ ROUNDDOWN(LAMT×RAT_KY×RAT_3/100,0)
+ ROUNDDOWN(LAMT×RAT_1×RAT_2/100×RAT_4/100,0),
자리)
```
각 항을 먼저 원 단위 절사한 뒤 합계를 다시 절사한다. `RAT_1..4`, `RAT_KY`의 정확한 비용항목 명칭 연결은 다음 단계에서 RATE/JB와 UI 라벨을 교차해야 한다.
## 4. 제비율 기준파일과 프로젝트 RATE의 관계
확장자와 실제 DBF 구조가 다음처럼 대응한다.
| 배포파일 | DBF 구조 | 보유 개수 | 프로젝트 테이블 |
|---|---|---:|---|
| `JB_1` | 41행 × 10열 | 1 (2011) | `RATE.DBF` |
| `JB_M` | 25행 × 10열 | 1 (2007) | `RATE_M.DBF` |
| `JB_R` 구형 | 50행 × 20열 | 9 (2015 ~ 2020-01-02) | `RATE_R.DBF` |
| `JB_R` 신형 | 50행 × 35열 | 18 (2020-05-27 ~ 2026) | `RATE_R.DBF` |
| `JB_RA` | 50행 × 20열 | 13 (2015 ~ 2026, **확장 없음**) | `RATE_RA.DBF` |
**열 확장 시점은 2020-05-27로 확정됐다.** `2020(상_0102)`이 20열, `2020(상_0527)`이 35열이다. 두 파일의 **1~20열은 500개 셀 중 한 개도 다르지 않다.** 즉 확장은 기존 열을 재배치하지 않고 **뒤에 덧붙인 것**이다. 구형 파일을 읽을 때 열 의미를 바꿔 해석할 필요가 없다.
늘어난 15개 열 가운데 실제로 값이 들어가는 것은 **21, 26, 27, 28, 31** 다섯 개뿐이고, 값이 놓이는 행은 `0~3, 5~8, 10~13, 15~18``48`이다. 2020-05-27은 **국가유산(문화재수리) 공종이 제비율에 들어온 시점**이며, 화면 `rGrd_Rate_R1`의 간접노무비·기타경비가 각각 `국가유산` 열을 하나씩 더 가지는 것과 개수가 맞는다.
### 행렬의 물리 배치 — 실측
- **행은 5행 묶음**이다. 묶음 시작은 `0, 5, 10, 15, 20, 25, 30, 35, 40, 45`이고, 각 묶음은 **값 4행 + 빈 1행**으로 끝난다. 화면 `rGrd_Rate_R1`(20행)·`rGrd_Rate_RA1`(20행)이 `5 공사규모 × 4 공사기간`인 것과 맞는다.
- **열 1~5 = 간접노무비**, **열 6~10 = 기타경비**이며 둘 다 `토목 / 산.설(토목) / 조경 / 건축 / 산.설(건축)` 다섯 공종 순이다. 신형의 **열 21 = 국가유산 간접노무비**, **열 26 = 국가유산 기타경비**다.
- 열 17·18은 짝으로 움직인다(예: `2.28 / 4325`, `2.53 / 3300`). **율과 기초액 한 쌍**으로 읽는 것이 맞다.
- `ST_KanJub.CPM`에는 `RATE_nn` 리터럴이 22개뿐이고 `'RATE_'`·`'RATE'`·`'00'` 조각이 따로 있다. 열 접근은 **문자열을 실행 중에 조립**하므로, 시작 좌표를 코드 상수로 읽어낼 수는 없다.
레코드 전체가 정확히 일치한 실제 사례도 확인됐다.
- 영월 2024: `RATE=2011 JB_1`, `RATE_M=2007 JB_M`, `RATE_R=2023-01-02 JB_R`, `RATE_RA=2023 계열 JB_RA`
- 영덕 2025: `RATE=2011 JB_1`, `RATE_M=2007 JB_M`, `RATE_R=2025-01-01 JB_R`
- 봉화 2024: `RATE_R=2024-03-15 JB_R`
- 울진 2024: `RATE_R=2020-05-27 JB_R`
일치하지 않는 프로젝트 표도 있으며, 이는 사용자 수정·구버전 설치자료·후속 기준 갱신 중 하나다. 특히 소광 2025의 `RATE_R`은 2025-01-01 기준과 5개 셀만 다르다. 따라서 프로젝트 RATE는 단순 외래키가 아니라 기준파일을 복사한 뒤 수정 가능한 스냅샷이다.
## 5. 다음 분석 순서
1. 12개 CPM의 전체 계산 문자열과 Delphi 폼 리소스를 기능별로 분리한다.
2. `ST_KanJub.CPM`의 UI 라벨과 `RAT_*` 자리표시자를 연결한다.
3. 43개 JB 파일을 연도별 셀 차이로 비교해 행·열 의미를 역추적한다.
4. BSC/CSTA의 DBF 스키마와 레코드 난독화 범위를 판정한다.
5. STBSC는 정상 프로그램 로드 전후 생성 파일을 관찰한다.
6. BDQTY·자재채택·변경설계의 통제실험을 수행한다.
## 6. 산출 원자료
- `system_inventory.csv`: 186개 파일 경로·크기·해시·실제 형식·상태
- `core_cpm_static.json`: 핵심 CPM 12개의 PE/import/export/도메인 문자열
- `core_formula_strings.json`: 바이너리에서 검출한 계산식과 포함 모듈
세 파일은 분석 재현용이며 원본 `System` 폴더에는 아무것도 쓰지 않았다.
@@ -0,0 +1,399 @@
# STmate CPM 계산 코어 정적 분석
분석일: 2026-09-13
대상: `C:\경영정보(주)\System` 186개 파일
목적: 화면과 예시 금액을 복제하는 것이 아니라, 같은 입력에서 같은 중간값과 결과를 만드는 계산 엔진을 재구현하기 위한 명세
## 1. 분석 범위와 판정 기준
186개 파일 전부를 SHA-256과 실제 파일 헤더로 식별했다. 파일명 확장자가 아니라 내부 형식으로 분류했으며, PE 모듈은 섹션·가져오기·내보내기·문자열, DBF 계열은 헤더·필드·레코드 상태, ZIP은 엔트리와 암호화 여부까지 읽었다.
계산 핵심 12개 CPM은 export 진입점을 역어셈블하고, 코드가 참조하는 산식 문자열·필드명·화면 설명을 교차 확인했다. 다음 세 등급을 사용한다.
- **A — 직접 확인**: DBF 스키마/레코드, 모듈 export, 실행코드가 참조하는 산식 문자열이 일치한다.
- **B — 강한 추론**: 모듈·필드·화면 설명이 일치하지만 입력/출력 쌍을 동적 실행으로 재현하지 못했다.
- **C — 미확정**: 암호화 기준자료 또는 화면 상태가 필요해 정적 자료만으로 경계를 확정할 수 없다.
정적 분석은 타사 프로그램을 수정하지 않았고 암호화 자료의 암호를 추측하거나 우회하지 않았다.
## 2. 계산 책임 모듈
| 모듈 | 확인된 진입점/문자열 | 재구현 책임 | 등급 |
|---|---|---|---|
| `DP_Common.CPM` | `CALC_STR`, `CALC_STR_PART`, `GET_ROUND_CUT`, `MROUNDUD`, `MROUNDUP`, `MTRUNC`, `MINT` | 식 평가, 자리수 절사·올림·반올림 | A |
| `ST_Func_C.CPM` | `CON_TOT`, `SUM_TOT`, `ZERO_TOT`, `PCN_TO_T`, `OPTIMIZ` | 조건별 집계, 0 정리, 총계 정규화 | A/B |
| `ST_KanJub.CPM` | `Calc_Kanjub`; 간접비 공식 템플릿과 적용기준 편집 문구 | 제비율 선택, 간접비 순차 계산, 추가금액·끝전조정 | A |
| `ST_SanCal.CPM` | `Calq_San`; `GET_ROUND_CUT`; `ROUND(2.45,1)=2.5`, `ROUNDDOWN(2.45,1)=2.4` | 단가산출/일위대가의 재료·노무·경비 산정 | A |
| `ST_Boq.CPM` | 합계 불일치 검사, 수량 소수부 검사, `%` 단위 처리 | 내역서 행 계산과 검증 | A |
| `ST_EdiLWi.CPM` | `TAMT=MAMT+LAMT+SAMT` 검증 | 내역 편집 시 성분 합계 불변조건 | A |
| `ST_EdSan.CPM` | `Edit_EQ_SYNC`, `Edit_SanKun` | 산출근거/장비 동기화와 편집 | B |
| `ST_Jabpum.CPM` | `Edit_Dan`, `Edit_Strg`, `Edt_Hal_Amt`, `Edt_Hal_Rate` | 품·할증·단가 편집 | B |
| `STmateQty8.CPM` | `QTY0`~`QTY9`, 이름/코드로 BOQ 전송 | 외부 수량의 내역 연결 | B |
| `ST_U_ChgAmt.CPM` | 변경금액 공식 문자열 | 당초/변경 금액 재계산 | A |
| `ST_U_ChgCode.CPM` | 전체·추가·선택 코드 변경, Excel 왕복 | 코드 치환 후 종속 계산 갱신 | B |
| `ST_U_ConBD.CPM` | `BOQ`, `BDQTY`, 코드·수량 필터 문자열 | 공종 수량을 내역으로 전개 | B |
같은 공식 문자열이 12개 CPM에 반복되어 있다. 이는 서로 다른 계산식 12개가 아니라 공통 계산 단위가 Delphi 정적 링크 과정에서 여러 모듈에 포함된 흔적으로 판단한다. 재구현에서는 모듈마다 복제하지 않고 하나의 계산 코어로 모아야 한다.
## 3. 금액 필드 불변조건
실행 모듈 세 곳에서 같은 검증식이 발견됐다.
```text
TAMT = MAMT + LAMT + SAMT
```
- `TAMT`: 총금액
- `MAMT`: 재료비
- `LAMT`: 노무비
- `SAMT`: 경비
- 접미사 `1`, `2`: 당초/변경 또는 비교 안의 병렬 슬롯
코드별 추가 불변조건도 있다.
```text
CODE="L" → LAMT=TAMT
CODE="M" → MAMT=TAMT
CODE="S" → SAMT=TAMT
CODE="W" 또는 복합행 → TAMT=MAMT+LAMT+SAMT
```
따라서 총액을 네 번째 독립 비목으로 저장하거나 계산하면 안 된다. 총액은 세 성분의 합이며, 단일 비목행에서는 해당 성분만 총액과 같고 나머지는 0이다. **등급 A**.
## 4. 공통 계산 함수의 의미
### 4.1 식 평가
`CALC_STR`/`CALC_STR_PART`가 식 문자열을 평가한다. `Calc_Kanjub``[LAMT]`, `[RAT_1]` 같은 자리표시자가 포함된 식 템플릿을 만들고, 실제 금액·요율·옵션에 따라 치환한 뒤 평가하는 구조다.
재구현 계약:
```text
evaluate(template, named_values, options)
1. 선택 토큰([+LAB], [+ANJ_B] 등)을 옵션에 따라 포함/제거
2. [이름]을 Decimal 값으로 치환
3. 허용된 산술·비교·ROUND 계열만 평가
4. 임의 코드 실행은 금지
5. 사용한 원본 템플릿과 치환값을 계산 추적에 보존
```
### 4.2 반올림 계열
#### 임포트 실측 — 무엇이 실제로 쓰이는가
`C:\경영정보(주)\System`의 PE 186개 전수를 훑어 수치 런타임 심볼의 실제 임포트를 셌다.
| 런타임 심볼 | STmate 모듈이 임포트하나 | 뜻 |
|---|---|---|
| `@Math@RoundTo$qqrxdxzc` | **예 — 17개 모듈** (`ST_KanJub`, `ST_Boq`, `ST_SanCal`, `ST_EdiLWi`, `ST_EdSan`, `ST_P_Joong`, `ST_Prt`, `ST_P_iLWi`, `ST_Jabpum`, `ST_FindUse`, `ST_Sys`, `STmate.Cpm`, `ST_U_Convert`, `ST_U_ChgCode`, `ST_U_DelCode`, `ST_P_XLS` 등) | 금액 반올림의 실제 원시함수 |
| `@Math@SimpleRoundTo$qqrxdxzc` | **아니오**`RTL60.BPL`만 내보냄 | 0에서 멀어지는 변형을 **쓰지 않음** |
| `@Math@Ceil$qqrxg` | **아니오**`RTL60.BPL`만 | `ROUNDUP``Ceil`로 만들지 않음 |
| `@Math@Floor$qqrxg` | 예 — 18개 모듈, 단 호출은 모듈당 2곳 | 금액 절사 주경로가 아님 |
| `@Math@SetRoundMode` / `GetRoundMode` | **아니오**`RTL60.BPL`만 | FPU 반올림 모드를 **바꾸지 않음** |
| `Set8087CW` / `Default8087CW` / `_control87` | **아니오**`RTL60.BPL`만 | 같음 |
핵심 계산 모듈 6개(`ST_KanJub`, `ST_SanCal`, `ST_Boq`, `ST_EdiLWi`, `ST_P_Joong`, `ST_Prt`)에서 임포트 썽크로 들어가는 `E8 rel32` 호출을 세면 **모듈마다 정확히 `RoundTo` 12곳, `Floor` 2곳**으로 같다. 공용 계산 유닛이 각 CPM에 정적 링크된 구조다.
`ST_KanJub.CPM``0x0043A240`~`0x0043A3DF` 한 함수 안에 `RoundTo` 호출 12곳이 모여 있고, 호출 앞뒤에 `FCHS`(부호반전)나 `FABS`(절대값)가 **하나도 없다.** 즉 음수를 뒤집어 양수로 처리하는 흉내가 없다. 자리수는 `F6 D8`(`neg al`)로 부호만 뒤집어 `RoundTo``ADigit`에 넘긴다.
#### 이로부터 확정되는 것 — A등급
Delphi 6 `Math.RoundTo(v, ADigit)``Round(v / 10^ADigit) * 10^ADigit`이고, `Round`는 **FPU 현재 반올림 모드**를 따른다. STmate가 모드를 바꾸는 호출을 전혀 하지 않으므로 모드는 Delphi 기본값인 **최근접-짝수(은행가 반올림)**로 고정이다. 음수 전용 분기도 없으므로 **0을 기준으로 대칭**이다.
| 원 함수 | 실제 구현 | 음수 | 정확히 절반 | 등급 |
|---|---|---|---|---|
| `MROUNDUD`/`ROUND` | `Math.RoundTo` → FPU 최근접-짝수 | 대칭 | **짝수 쪽**(사사오입 아님) | **A** |
| `MTRUNC`/`ROUNDDOWN` | `Ceil`·`Floor` 미사용, Delphi `Trunc` 관용구(`FNSTCW``FLDCW``FISTP`→복원) | **0 방향** (Excel과 같음) | 해당없음 | B |
| `MROUNDUP`/`ROUNDUP` | `Ceil` 미사용 → 절사 후 나머지 보정 계열 | 미확정 | 해당없음 | B |
| `MINT` | `DP_Common.CPM`에만 존재 | 미확정 | 해당없음 | C |
| `GET_ROUND_CUT` | `DP_Common`·`ST_SanCal`·`ST_U_Convert` — 설정에 따라 위를 고름 | — | — | B |
#### 경계표 — 내부 계산과 STmate 가 뽑은 XLSX 가 갈리는 자리
STmate 출력 XLSX 안의 수식은 **Excel** `ROUND`(0에서 멀어지는 사사오입)이고, 내부 Delphi 계산은 위처럼 **최근접-짝수**다. 같은 값이 두 곳에서 다르게 나온다.
| 입력 | 자리 | STmate 내부 `ROUND` | Excel `ROUND` (출력 XLSX) | 일치 |
|---:|---:|---:|---:|:--:|
| 2.44 | 소수1 | 2.4 | 2.4 | ○ |
| 2.45 | 소수1 | **2.4** | 2.5 | ✗ |
| 2.46 | 소수1 | 2.5 | 2.5 | ○ |
| -2.45 | 소수1 | **-2.4** | -2.5 | ✗ |
| 0.5 | 원 | **0** | 1 | ✗ |
| 1.5 | 원 | 2 | 2 | ○ |
| 2.5 | 원 | **2** | 3 | ✗ |
| 3.5 | 원 | 4 | 4 | ○ |
| -2.5 | 원 | **-2** | -3 | ✗ |
| -3.5 | 원 | -4 | -4 | ○ |
| 1250 | 100원 | **1200** | 1300 | ✗ |
| 1350 | 100원 | 1400 | 1400 | ○ |
| 2500 | 1000원 | **2000** | 3000 | ✗ |
| 3500 | 1000원 | 4000 | 4000 | ○ |
| -2500 | 1000원 | **-2000** | -3000 | ✗ |
시험한 20개 경계 중 **10개가 갈린다**. 재현 스크립트는 이 폴더의 `round_table.py`(경계표), `rounding_symbol_matrix.py`(임포트 실측), `rounding_callsites.py`(썽크 호출 집계), `rounding_dispatcher_dump.py`(함수 바이트 덤프)다.
`2.45`가 소수1자리에서 `2.4`가 되는 이유는 두 겹이다. ① 은행가 반올림이고 ② `RoundTo``IntPower(10,-1)`로 만든 `0.1`이 이진수로 정확하지 않아 `2.45/0.1``24.4999…`가 된다. 따라서 **STmate 호환 모드는 `Decimal` 사사오입으로 흉내 낼 수 없고, 배정밀도 나눗셈까지 그대로 재현해야 한다.**
#### 재구현 지침
- Aislo 자체 계산은 금액형을 `Decimal`로 두고 정책을 명시한다. 자리수 `0`은 원 단위, 음수는 십·백·천원 단위 조정으로 해석한다.
- **STmate 결과와 원 단위까지 맞춰야 하는 자리**에서는 위 배정밀도 경로를 그대로 흉내 내는 `stmate_round(value, digit)`를 따로 두고, 어느 경로로 계산했는지 계산 추적에 남긴다.
- 내부 계산값과 출력 XLSX 값이 원 단위에서 다를 수 있다는 점을 검증 기준에 반영한다. 둘이 다르다고 곧 오류가 아니다.
## 5. 직접비 계산
### 5.1 단가와 금액
각 행은 재료·노무·경비 단가를 별도로 가지며 총단가는 세 성분의 합이다. 내역 금액은 보유 XLSX와 실행모듈 양쪽에서 다음 계약으로 확인된다.
```text
component_amount = ROUNDDOWN(quantity × component_unit_price, configured_digits)
total_amount = material_amount + labor_amount + expense_amount
```
자원·일위대가·중기 집계 출력에는 `ROUND(quantity×unit_price,0)`가 나타나므로, 내역 행의 절사와 집계표의 반올림을 하나로 합치면 안 된다. 계산 자리마다 `rounding_policy`를 명시해야 한다.
### 5.2 수량 표시와 계산값
`ST_Boq.CPM`은 비목 코드가 `M/L/S/W/B/D/X/A` 계열이고 수량 문자열의 소수 마지막 자리가 0이 아닌지 검사하며, `%` 단위행은 별도로 취급한다. 이는 화면 표시 소수점과 내부 계산 수량을 구분하고 있음을 뜻한다. 저장 모델에는 최소한 원수량, 계산수량, 표시자리수를 분리한다. **등급 B**.
## 6. 간접비 공식 템플릿
실행코드가 직접 참조하는 템플릿은 다음 계열이다. 대괄호 이름은 런타임 치환 변수다.
```text
ROUNDDOWN([LAMT] * [RAT_1], digits)
ROUNDDOWN(([L_AMT][+LAB]) * [RAT_1], digits)
ROUNDDOWN([T_AMT] * [RAT_1], digits)
ROUNDDOWN(([M_AMT]+[L_AMT]+[S_AMT]...) * [RAT_1], digits)
ROUNDDOWN([M_AMT] * [RAT_1], 0)
ROUNDDOWN(([T_AMT]-[M_AMT]) * [RAT_1], 0)
ROUNDDOWN(([TAMT]-[LAMT][+ANJ_B][+PMJ_B]+[B_AD_AMT]) * [RAT_1], 0)
```
기본형은 모두 **이미 계산된 밑수 × 요율을 지정 자리에서 절사**한다. `[+...]` 토큰은 특정 항목을 산정기초에 더하거나 빼는 옵션이다. 한 항목의 결과가 다음 항목의 밑수에 들어가므로 순서를 보존해야 한다.
### 6.1 복합 보험/부담금형
다음 중첩식도 코드에 포함돼 있다.
```text
ROUNDDOWN(
ROUNDDOWN([LAMT]*[RAT_1]*[RAT_2]/100*1.4, 0)
+ ROUNDDOWN([LAMT]*[RAT_KY]*[RAT_3]/100, 0)
+ ROUNDDOWN([LAMT]*[RAT_1]*[RAT_2]/100*[RAT_4]/100, 0),
digits
)
```
각 부분을 먼저 원 단위 절사한 뒤 합계를 다시 절사한다. 합계를 한 번에 계산한 뒤 마지막에만 절사하면 결과가 달라진다. 변수의 화면상 정확한 항목 매핑은 C등급이지만 **부분별 절사 순서 자체는 A등급**이다.
### 6.2 확인된 간접비 항목 사전
원가계산 모듈에는 다음 항목이 명시돼 있다.
- 간접노무비, 주휴수당
- 산재보험료, 고용보험료, 건강보험료, 노인장기요양보험료, 연금보험료
- 퇴직공제부금비, 산업안전보건관리비, 건설공사 안전점검비
- 기타경비, 수도광열비, 복리후생비, 소모품·사무용품비, 여비·교통비·통신비, 세금·공과금, 시공도작성비
- 환경보전비, 석면피해구제분담금, 임금채권부담금
- 공사이행보증수수료, 하도급대금지급보증수수료, 건설기계대여금지급보증서수수료
- 고용개선지원비(PS), 고용개선 건강·연금, 고용개선장려금
- 공사보험료/공사손해보험료, 일반관리비, 이윤, 부가가치세
명칭이 존재한다고 모든 프로젝트에 자동 적용되는 것은 아니다. 항목별 `enabled`, `rate_source`, `base_components`, `rounding`, `manual_override`, `stage`를 저장해야 한다.
## 7. 산업안전보건관리비 선택식
화면 설명과 계산 템플릿에서 다음 선택식이 확인된다.
```text
(직·간재 + 직노 + (관급+사급)/1.1 - 내역서안전관리비) × rate
(재료비 + 직노 + (관급+사급)/1.1 - 내역서안전관리비) × rate
(직·간재 + 직노 + 관급/1.1 + 사급재 - 내역서안전관리비) × 3.15% + 기초액
```
세 번째 계열은 다음 비교·상한/하한 선택을 동반한다.
```text
기준식 결과
vs
((직·간재 + 직노 - 내역서안전관리비) × 3.15% + 기초액) × 1.2
```
기존 안전관리비를 차감하지 않는 변형도 존재한다. 관급·사급 처리 옵션은 다음 문자열로 확인된다.
- `관급자재대/1.1`, `관급자재대`
- `사급자재대/1.1`, `사급자재대`
- `관급/1.1+사급재`
- `관급재+사급/1.1`
- `관급재+사급재`
- `(관급+사급)/1.1`
따라서 안전관리비는 고정 공식 하나가 아니라 기준연도·공사종류·재료 공급형태·기존 계상액 포함 여부에 따른 정책 선택이다. 공식 선택 결과와 선택 근거를 결과에 저장해야 한다. 정확한 선택 조건은 RATE 좌표/화면 대조가 필요한 C등급이다.
## 8. 요율 선택 축과 순환 의존성
모듈이 제시하는 선택 축은 다음과 같다.
- 발표기관/기준군: 조달청, 건기연, 행자부
- 편집군: 기본제비율, 실적공사비 적용요율, 행자부기준
- 공사종류: 일반·산업설비·조경·건축, 토목·중건설·특수건설 등
- 공사기간: 30일 미만, 6개월 미만/이하, 7~12개월, 13~36개월, 37개월 이상 등
- 공사규모: 5천만·3억·5억·10억·30억·50억·70억·100억·120억·250억·300억·500억·1,000억·800억 등의 기준군별 구간
- 공사등급: 1~6등급, 7등급 이하
원 프로그램은 “공사규모에 따른 제비율 변경으로 공사규모가 계속 변경되는 무한루프”가 발생할 수 있다고 명시하고, 일반관리비·이윤 등의 요율을 사용자가 직접 수정하도록 안내한다.
따라서 재구현의 안전한 계약은 다음과 같다.
1. 요율 선택의 기준금액과 기준군을 입력값으로 고정한다.
2. 자동 재선택은 최대 반복 횟수와 상태 이력으로 순환을 검출한다.
3. 구간이 왕복하면 임의의 한쪽을 택하지 않고 사용자 확정 상태로 전환한다.
4. 확정된 요율, 원 표 좌표, 사용자 수정 여부를 프로젝트 스냅샷에 보존한다.
## 9. 추가금액과 적용 단계
추가금액은 단순 메모가 아니라 총계 트리의 특정 위치에 삽입된다. 화면 문자열로 다음 단계가 확인됐다.
| 단계 | 삽입 위치 | 합계 영향 |
|---:|---|---|
| 3 | 일반관리비 직전 | 순공사원가의 경비에 포함 |
| 4 | 이윤 이후~공급가액 전 | 공급가액에 포함 |
| 5 | 도급공사비 직전 | 도급공사비에 포함 |
| 6 | 관급자재~총공사비 구간 | 총공사비에 포함 |
별도로 “이윤 이후(공사원가 포함)”, “사급자재비 이후” 위치가 존재한다. 산출경비 직접비에 이미 포함된 금액은 경비금액에 다시 계상하지 않으며, 기성내역서 등록 시 삭제되고 XML 호환규정 변환 대상이 아니라는 경고도 있다.
추가금액은 `amount`, `component`, `insertion_stage`, `include_in_cost_base`, `source`, `conversion_policy`를 가진 독립 행으로 구현해야 한다. **등급 B**.
## 10. 변경설계 공식
코드에 두 가지 공식이 직접 포함돼 있다.
```text
방법 A = C_AMT_B
+ ROUNDDOWN(C_AMT_B × ((C_TAMT_C-C_TAMT_B)/C_TAMT_B), digits)
방법 B = C_AMT_B
+ ROUNDDOWN((C_TAMT_C-C_TAMT_B) × RAT_1, digits)
```
- `C_AMT_B`: 해당 간접비의 당초금액
- `C_TAMT_B`: 기준 직접비/공사비의 당초 합계
- `C_TAMT_C`: 같은 기준의 변경 합계
- `RAT_1`: 항목 요율
방법 A는 당초금액에 전체 증감비율을 적용하고, 방법 B는 증감 기초금액에 항목 요율을 적용한다. 보험료 사후정산 항목은 당초금액과 동일하게 직접 입력하는 옵션도 있다. 직접입력 체크가 없으면 적용을 거부한다.
또 계약 제잡비율 적용 시 간접노무비부터 부가세 직전 항목의 변경분을 `직접비 변경분 × 계약 제잡비율`로 조정하는 기능이 있다. 재구현은 `recalculated`, `proportional_from_original`, `delta_times_rate`, `carry_original`, `manual`을 서로 다른 계산 모드로 저장해야 한다.
## 11. 끝전조정
코드에는 `[C_AD_AMT]`에 대한 다음 선택이 존재한다.
```text
ROUND([C_AD_AMT], -digits)
ROUNDDOWN([C_AD_AMT], -digits)
ROUNDUP([C_AD_AMT], -digits)
```
다른 산출물에서 확인된 흐름은 총액 차액을 세전 상당액과 부가세 조정으로 나눠 이윤 또는 조정행에 전달하는 방식이다. 따라서 다음 값을 분리 보존한다.
```text
raw_amount
rounded_amount
adjustment_amount
adjustment_target
rounding_function
rounding_digits
```
`이윤 보정=0`은 “0원 이윤”이 아니라 이윤보정을 사용하지 않는 옵션이다. 0과 미설정을 구분해야 한다.
## 12. 공종·제외금액 분류
간접비 밑수에서 별도 취급하는 공종/금액 분류가 확인됐다.
- 일반공종
- 안전관리비, 품질관리비
- 미확정설계공종(PS)
- 제비율 적용제외공종
- 기존 시설물 철거·해체·이설 발생분
- 작업설 등 감액 항목
- 매입세
- 직접공사비에 포함되지 않은 제외금액
- 비과세자재대
- 도급자설치/관급자설치 관급자재대
- 도급자설치 관급에 포함된 조달수수료
- 내역서 기존 안전관리비
- 폐기물수수료, 골재사용료
자동 옵션은 내역서에 해당 공종구분을 가진 행이 없으면 선택되지 않는다. 사용자는 다른 내역 금액을 더블클릭으로 밑수에 불러올 수 있다. 즉 밑수는 단순 총계가 아니라 공종 태그로 필터한 합계와 수동 연결값의 조합이다.
## 13. 재구현 데이터 계약
```text
RateStandard
source, effective_date, standard_group, work_type
amount_band, duration_band, grade, item_code
rate, base_formula_id, rounding_policy_id
CostComponent
material, labor, expense, total(derived)
IndirectCostRule
item_code, ordered_stage, enabled
base_component_codes[], include_tags[], exclude_tags[]
formula_template, rate_ref, rounding_ref
manual_override, adjustment_mode
CalculationTrace
rule_id, source_record, source_coordinate
template, substituted_values, raw_result
rounding_function, digits, final_result
user_override, override_reason
```
모든 결과는 “어떤 기준자료의 어느 좌표 → 어떤 밑수 항목 → 어떤 요율 → 어떤 절사 → 어떤 결과”인지 역추적 가능해야 한다. 숫자만 저장하면 다음 연도 기준 변경과 변경설계 재현이 불가능하다.
## 14. 구현 순서
1. `Decimal` 기반 ROUND/ROUNDDOWN/ROUNDUP/MINT 호환 함수를 만든다.
2. `TAMT=MAMT+LAMT+SAMT` 불변조건을 가진 직접비 행 계산기를 만든다.
3. 간접비 규칙을 순서 있는 데이터로 정의하고 선택 토큰을 포함한 제한식 평가기를 만든다.
4. 안전관리비 정책 변형과 관급·사급 VAT 처리 방식을 별도 전략 값으로 둔다.
5. 추가금액 삽입단계와 제비율 제외 태그를 합계 트리에 적용한다.
6. 당초/변경은 값 열 복제가 아니라 두 스냅샷과 계산모드로 처리한다.
7. 끝전조정과 VAT 조정을 마지막 단계에서 수행하고 전후 값을 보존한다.
8. 각 단계에 원본 좌표와 계산 추적을 남긴다.
## 15. 아직 동적 대조가 필요한 경계
다음은 숨기지 않고 미확정으로 남긴다.
1. `RATE`, `RATE_M`, `RATE_R`, `RATE_RA`의 각 행·열과 화면 항목의 완전한 좌표 매핑
2. 금액·기간 구간 경계의 `<`/`<=` 방향
3. ~~음수 및 정확히 절반인 값의 ROUND 처리~~**확정(A)**: 최근접-짝수·0 대칭 (§4.2). 남은 것은 `ROUNDUP`·`MINT`의 음수 방향과 `GET_ROUND_CUT`이 설정값을 어느 함수로 잇는지
4. 각 안전관리비 변형을 선택하는 정확한 기준연도·공사종류 조건
5. 복합 보험식의 `RAT_1`~`RAT_4`, `RAT_KY` 화면 항목명
6. 추가금액 단계 번호 1·2 및 일부 특수 위치의 정확한 합계 영향
7. `CODE=W/B/D/X/A`의 모든 세부 계산 분기
이 일곱 항목은 누락이 아니라 정적 파일만으로 단정하면 오히려 잘못된 구현이 되는 경계다. 동일 프로젝트 복제본에서 한 변수만 바꾸는 통제시험으로 확정해야 한다.
## 16. 재현 시험표
| 시험 | 입력 | 확인 결과 |
|---|---|---|
| 반올림 | ±2.44, ±2.45, ±2.46; digits 1,0,-1 | 네 함수별 기대값 |
| 성분합 | M/L/S 단일행과 복합행 | 총액 불변조건 및 오류 차단 |
| 중간절사 | 절사 전 소수부가 있는 3개 부분식 | 부분별 절사 후 합산 여부 |
| 요율경계 | 각 금액·기간 경계 직전/동일/직후 | 선택 RATE 좌표 |
| 요율순환 | 총액이 인접 구간을 왕복하는 값 | 순환 검출 및 수동확정 |
| 안전비 | 관급/사급, VAT 포함, 기존 안전비 조합 | 선택식과 밑수 |
| 추가금액 | 동일 금액을 단계 3~6에 각각 삽입 | 순공사원가·공급가액·도급액·총액 영향 |
| 변경설계 | 당초/변경 직접비와 요율 독립 변경 | A/B/직접입력 방식별 결과 |
| 끝전 | 양수·음수 차액, 백/천원 단위 | 이윤·VAT 조정 전달 |
이 표를 모두 통과해야 “비슷한 결과”가 아니라 계산 순서와 중간값까지 같은 프로그램이라고 판정할 수 있다.
@@ -0,0 +1,408 @@
# 원가계산 4형식과 RATE 표 구조 복원
분석일: 2026-09-13
직접 근거: `ST_KanJub.CPM`의 Delphi 폼 리소스 `TWM_KANJUB`, `TWM_KAN_RATE`, `TPM_KAN_RATE`
## 1. 복원 방법
PE의 `RT_RCDATA`에 포함된 Delphi 6 바이너리 폼(`TPF0`)을 속성·자식 컨트롤·컬렉션 단위로 파싱했다. 이에 따라 단순 문자열 검색으로는 잃었던 다음 관계를 복원했다.
- 탭 이름과 계산 형식
- 계산서에 표시되는 항목 순서
- 각 항목 옆에 인쇄되는 산정기초 공식
- 요율표 그리드 이름, 행 수, 열 제목
- 자동계산 선택 입력과 추가금액 삽입 위치
이 문서의 화면 문구와 열 구조는 **A등급 직접 확인**이다. DBF 물리 좌표와 화면 셀의 완전한 연결은 일부 B/C등급이다.
## 2. 원가계산의 네 형식
`TWM_KANJUB`에는 네 탭이 있다.
| 내부 접미사 | 탭 | 의미 |
|---|---|---|
| `T` | 일반형식 | 일반 제비율 기반 원가계산 |
| `S` | 수공형식 | 세부 경비 항목을 풀어 계산하는 수공식 |
| `TA` | 실적일반 | 실적공사비 적용의 일반형식 |
| `SA` | 실적수공 | 실적공사비 적용의 수공형식 |
네 형식은 출력 모양만 다른 것이 아니다. 직접공사비/순공사원가의 묶음, 보험료 밑수, 기타경비의 세분 정도, 일반관리비와 이윤의 밑수가 달라진다.
## 3. 일반형식 `T`
### 3.1 계산 순서
```text
나. 순공사원가 = ㄱ + ㄴ + ㄷ
ㄱ. 재료비
ㄴ. 노무비
1) 직접노무비
2) 간접노무비 = 직접노무비 × rate
ㄷ. 경비
1) 내역서경비
2) 산재보험료 = 노무비 × rate
3) 고용보험료 = 노무비 × rate
4) 건강보험료 = 직접노무비 × rate
5) 장기요양보험료 = 건강보험료 × rate
6) 연금보험료 = 직접노무비 × rate
7) 퇴직공제부금비 = 직접노무비 × rate
8) 산업안전보건관리비
9) 안전관리비 = 별도내역
10) 품질관리비 = 별도내역
11) 기타경비 = (재료비 + 노무비) × rate
12) 공사이행수수료 = 기초금액 + (직접공사비 - 기준규모) × rate
13) 하도급대금지급보증수수료 = (재료비 + 직접노무비 + 산출경비) × rate
14) 환경보전비 = (재료비 + 직접노무비 + 산출경비) × rate
15) 건설기계대여금지급보증서수수료 = (재료비 + 직접노무비 + 산출경비) × rate
16) 석면피해구제분담금 = 노무비 × rate
17) 임금채권부담금 = 노무비 × rate
5) 일반관리비 = (순공사원가 + 관리품목자재대) × rate
다. 소계 = 순공사원가 + 일반관리비
6) 이윤 = (소계 - 재료비) × 이윤율 - 보정액
라. 공급가액
부가가치세
공사보험료
작업설 등 감액
사급자재대
비과세자재대
매입세
마. 도급공사비
관급자재대(도급자설치)
사급자재대
관급자재대(관급자설치)
바. 총공사비
```
### 3.2 고용개선지원비
일반형식에는 다음 별도 묶음이 존재한다.
```text
고용개선지원비(PS단가) = 주휴수당 + 사회보험 + 장려금
주휴수당 = 직접노무비 × RAT_1 × RAT_2 × 1.4(제경비)
국민연금·건강보험료 = 직접노무비 × 관련률 × 관련률
```
이는 11번 문서의 중첩 `ROUNDDOWN` 세 부분식과 일치한다. 각 부분은 원 단위 절사 후 합산된다.
## 4. 수공형식 `S`
### 4.1 계산 순서
```text
1. 순공사원가 = 가 + 나 + 다
가. 순공사비
나. 간접노무비 = 직접노무비 × rate
다. 경비
1) 산재보험료 = (직접노무비 + 간접노무비) × rate
2) 고용보험료 = (직접노무비 + 간접노무비) × rate
3) 건강보험료 = 직접노무비 × rate
4) 장기요양보험료 = 건강보험료 × rate
5) 연금보험료 = 직접노무비 × rate
6) 퇴직공제부금비 = 직접노무비 × rate
7) 산업안전보건관리비
8) 안전관리비 = 별도내역
9) 품질관리비 = 별도내역
10) 수도광열비 = (직노 + 간노 + 재료비) × rate
11) 복리후생비 = 같은 밑수 × rate
12) 소모품·사무용품비 = 같은 밑수 × rate
13) 여비·교통비·통신비 = 같은 밑수 × rate
14) 세금·공과금 = 같은 밑수 × rate
15) 폐기물처리비 = 같은 밑수 × rate
16) 도서인쇄비 = 같은 밑수 × rate
17) 지급수수료 = 같은 밑수 × rate
18) 공사이행수수료 = 기초금액 + (직접공사비 - 기준규모) × rate
19) 하도급대금지급보증수수료 = (재료비 + 직노 + 산출경비) × rate
20) 환경보전비 = (재료비 + 직노 + 산출경비) × rate
21) 건설기계대여금지급보증서수수료 = 같은 밑수 × rate
22) 석면피해구제분담금 = (직노 + 간노) × rate
23) 임금채권부담금 = (직노 + 간노) × rate
2. 일반관리비 = (순공사비 + 간접노무비 + 경비) × rate
3. 이윤 = (순공사원가 + 일반관리비 - 재료비) × rate - 보정액
4. 공급가액
5. 도급공사비
6. 총공사비
```
시공도작성비는 `(순공사원가+일반관리비+이윤+사급비) × rate × 별도계수` 형식이다.
## 5. 실적일반 `TA`
실적일반은 직접비와 간접비를 먼저 나눈다.
```text
1. 직접공사비
2. 간접공사비
1) 간접노무비 = 직접노무비 × rate
2) 산재보험료 = 노무비 × rate
3) 고용보험료 = 노무비 × rate
4) 건강보험료 = 직접노무비 × rate
5) 장기요양보험료 = 건강보험료 × rate
6) 연금보험료 = 직접노무비 × rate
7) 퇴직공제부금비 = 직접노무비 × rate
8) 산업안전보건관리비
9) 안전관리비
10) 품질관리비
11) 기타경비 = (재료비 + 노무비) × rate
12) 공사이행수수료
13) 하도급보증수수료 = 직접공사비 × rate
14) 환경보전비 = 직접공사비 × rate
15) 건설기계대여보증수수료 = 직접공사비 × rate
16) 석면분담금 = 노무비 × rate
17) 임금채권부담금 = 노무비 × rate
3. 일반관리비 = (직접공사비 + 간접공사비 + 관리품목자재) × rate
4. 이윤 = (직접공사비 + 간접공사비 + 일반관리비) × rate - 보정액
5. 공급가액
6. 도급공사비
7. 총공사비
```
일반형식 `T`와 달리 하도급·환경·건설기계 보증수수료의 밑수가 직접공사비 전체다.
## 6. 실적수공 `SA`
실적수공은 실적공사비 묶음과 수공 경비 세분을 함께 사용한다.
```text
1. 직접공사비
2. 간접공사비
1) 간접노무비 = 직접노무비 × rate
2) 산재보험료 = (직접노무비 + 간접노무비) × rate
3) 고용보험료 = (직접노무비 + 간접노무비) × rate
4) 건강보험료 = 직접노무비 × rate
5) 장기요양보험료 = 건강보험료 × rate
6) 연금보험료 = 직접노무비 × rate
7) 퇴직공제부금비 = 직접노무비 × rate
9) 산업안전보건관리비
10) 품질관리비
11~18) 수도광열비부터 지급수수료까지 수공 경비
19) 공사이행수수료
20) 하도급보증수수료
21) 환경보전비
22) 건설기계대여보증수수료
22) 석면분담금
23) 임금채권부담금
3. 일반관리비 = (직접공사비 + 간접노무비) × rate
4. 이윤 = (직접공사비 + 간접공사비 + 일반관리비) × rate - 보정액
5. 공급가액
6. 도급공사비
7. 총공사비
```
화면에 22번이 두 번 표시된다. 재구현 데이터 키는 화면 번호가 아니라 고유 항목코드를 써야 한다.
## 7. 네 형식의 핵심 차이
| 규칙 | T | S | TA | SA |
|---|---|---|---|---|
| 산재·고용 밑수 | 노무비 | 직노+간노 | 노무비 | 직노+간노 |
| 기타경비 | 묶음 1개 | 세부 경비 8개 | 묶음 1개 | 세부 경비 8개 |
| 하도급·환경·장비 보증 밑수 | 재+직노+산출경비 | 재+직노+산출경비 | 직접공사비 | 재+직노+산출경비 |
| 일반관리비 밑수 | 순공사원가+관리품목자재 | 순공사비+간노+경비 | 직공비+간접비+관리품목자재 | 직공비+간접노무비 |
| 이윤 밑수 | 소계-재료비 | 순공사원가+일반관리비-재료비 | 직공비+간접비+일반관리비 | 동일 |
따라서 형식을 출력 템플릿으로만 구현하면 안 된다. `calculation_scheme`이 공식 집합과 합계 트리를 선택해야 한다.
## 8. RATE 편집 화면의 실제 표
| 그리드 | 행 수 | 열 제목 | 역할 |
|---|---:|---|---|
| `rGrd_Rate_Kobo` | 7 | 등급, 요율 | 고용보험 등급별 요율 |
| `rGrd_Rate_Anjun` | 4 | 공종, 5억 미만, 5~50억 미만, 추가, 50억 이상, 800억 이상 | 산업안전보건관리비 규모식 |
| `rGrd_Rate_R2` | 6 | 구분, 요율 | 단일 요율 목록 |
| `rGrd_Rate_Hwan` | 7 | 구분, 요율 × 2쌍 | 환경보전비 |
| `rGrd_Rate_Bojng` | 5 | 공종, `[요율+추가]×공기` | 공사이행보증수수료 |
| `rGrd_Rate_Hado` | 6 | 공사규모, 요율 | 하도급대금지급보증수수료 |
| `rGrd_Rate_Eqip` | 6 | 구분, 요율 × 2쌍 | 건설기계대여금 지급보증수수료 |
| `rGrd_Rate_R` | 5 | 공사규모(국가유산), 일반건설, 전문, 국가유산, 이윤 | 일반형식 규모 요율 |
| `rGrd_Rate_R1` | 20 | 공사기간과 토목·산업설비·조경·건축·국가유산 열 2군 | 일반형식 기간 요율 |
| `rGrd_Rate_RA` | 5 | 공사규모, 일반건설, 전문, 이윤 | 실적형식 규모 요율 |
| `rGrd_Rate_RA1` | 20 | 공사기간과 토목·조경·산업설비·건축 열 2군 | 실적형식 기간 요율 |
| `rGrd_Rate_An_A` | 4 | 공사규모 | 실적 안전비 규모 |
| `rGrd_Rate_An_A1` | 16 | 공사종류, 산업안전보건관리비 공식, 비고/규모비율 | 실적 안전비 공식표 |
| `rGrd_RateM` | 14 | 구분, 간접노무비 | 행자부 기준 간접노무비 |
| `rGrd_RateB` | 12 | 구분, 재·직노·노·재+직노·재+노의 두 열군 | 수공 경비별 밑수 요율 |
## 9. JB 파일과 화면 표의 대응
| 파일 | 물리 크기 | 확인된 화면군 | 판정 |
|---|---:|---|---|
| `*.JB_1` | 41행×10열 | 구버전/공통 요율 데이터 | B |
| `*.JB_M` | 25행×10열 | `rGrd_RateM`, 행자부기준 | A/B |
| `*.JB_R` 구형 | 50행×20열 | 일반형식 `Rate_R/Rate_R1` 및 부속표 | B |
| `*.JB_R` 2020 이후 | 50행×35열 | 일반형식에 안전·환경·보증 부속표 확장 | B |
| `*.JB_RA` | 50행×20열 | 실적형식 `Rate_RA/Rate_RA1/An_A/An_A1` | A/B |
DBF 필드는 `RATE0..RATE9` 또는 `RATE_01..RATE_35`, 레코드는 고정 25/41/50행이다.
**폼 패널별 행수 합계가 파일 행수와 맞는다.**
| 폼 패널 | 담은 그리드 | 행수 합 | 같은 행수의 파일 |
|---|---|---:|---|
| `Panel9` (부속표) | Kobo 7 + Anjun 4 + R2 6 + Hwan 7 + Bojng 5 + Hado 6 + Eqip 6 | **41** | `JB_1` 41행 |
| `Panel8` (일반형식) | Rate_R 5 + Rate_R1 20 | **25** | `JB_M` 25행 |
| `Panel22` (실적형식) | Rate_RA 5 + Rate_RA1 20 + An_A 4 + An_A1 16 | **45** | — |
| `sc_Bx_M` | RateM 14 | 14 | — |
| `sc_Bx_B` | RateB 12 | 12 | — |
행수가 맞는 것은 **강한 단서이지 증명은 아니다.** `JB_1`의 실제 값 분포를 보면 빈 행이 `4,5``10,11`에 오는데 `Panel9` 그리드 경계(7·11·17·24·29·35)와는 어긋난다. 두 가지 중 하나다 — ① `JB_1`은 2011년 한 개뿐인 구형이라 현재 폼과 배치가 다르다, ② 적재가 단순 이어붙이기가 아니다.
**확정된 것**(10번 문서에 실측 근거)
- 행은 `0,5,10,…,45`에서 시작하는 **5행 묶음**이며 각 묶음은 값 4행 + 빈 1행이다.
- `JB_R` 열 1~5는 간접노무비, 6~10은 기타경비이고 둘 다 `토목 / 산.설(토목) / 조경 / 건축 / 산.설(건축)` 순이다.
- 2020-05-27 확장으로 **열 21 = 국가유산 간접노무비, 열 26 = 국가유산 기타경비**가 붙었고 기존 1~20열은 한 셀도 바뀌지 않았다.
- `JB_RA`는 43개 전 기간 20열 그대로다. 실적형식에는 국가유산 공종이 없다.
**남은 것** — 각 부속표 그리드(고용보험·환경보전·보증수수료 계열)가 `JB_1`/`JB_R`의 몇 번째 행부터 적재되는지. 열 접근이 실행 중 문자열 조립이라 코드 상수로 읽을 수 없으므로, 저장 이벤트 역추적 또는 통제 동적 시험이 필요하다.
## 10. 계산 설정 입력
원가계산 설정 화면에 다음 16개 선택축이 번호로 존재한다.
1. 기준 유형(화면 첫 항목)
2. 공사의 종류
3. 공사기간
4. 고용보험료
5. 퇴직공제부금비
6. 관급/사급 내용
7. 산업안전보건관리비
8. 환경보전비
9. 건설기계대여금 지급수수료
10. 일반관리비
11. 공급가액 절사기준
12. 부가가치세
13. 사급비 위치
14. 낙찰 방식
15. 이행보증 방식
16. 적용기준
추가 입력에는 조달수수료, 상시근로자 노무비, 내역서 안전관리비, 안전·품질관리비, PQ 공사손해보험요율, 공사이행 기간, 관급자재 분리 여부가 있다. 이 설정 스냅샷 없이는 같은 원본 내역으로도 원가계산 결과를 재현할 수 없다.
### 10.1 실제 선택값 사전
폼의 `Items.Strings`와 내부 `Values.Strings`를 함께 복원했다.
| 설정 | 화면 선택지 | 내부값/주의 |
|---|---|---|
| 제잡비 방식 | 원가계산방식, 표준시장방식 | 내부 명칭은 실적공사방식 |
| 공사종류 | 일반(토목), 조경, 산업설비(토목), 건축, 산업설비(건축), 국가유산수리, 폐기물처리, 소규모용역 | `0,2,4,3,1,5,8,9` — 화면 순번과 내부값이 다름 |
| 적용기준 | 일반(국가계약법), 일반(지방계약법), 행자부기준 | `2,0,1` — 역시 화면 순번과 다름 |
| 고용보험 | 없음, 1~6등급, 7등급 이하 | 등급명 |
| 퇴직공제 | 토목, 준설, 건축, 기타 | 명칭 |
| 안전비 공종 | 건축, 토목, 중건설, 특수건설 | `0,1,3,4` |
| 환경보전 | 없음, 도로, 플랜트, 지하철, 철도, 상하수도, 항만 2종, 댐, 택지, 주택 3종, 조경, 기타토목 | 명칭 |
| 건설기계 보증 | 없음, 일반공사, 전문공사 세부 5군 | `-1,0,1,2,3,4,5` |
| 관급/사급 | 관급/1.1, 관급, 사급/1.1, 사급, 혼합 4종 | 식 문자열 자체가 값 |
| 사급비 위치 | 재료비 포함, 이윤 다음, 도급공사비 직전, 관급자재대 다음 | `3,1,2,0` |
| 부가세 | 공급가액의 10%, 재료비의 10%, 없음, 산림조합 형식, 산림조합 면세품 | 선택 문자열 |
| 낙찰방식 | 종합심사 외, 종합심사 대상, 턴키(대안) | 값 목록 |
| 계약형식 | 일반계약, 최저가·기술제안 | `0,1` |
| 관급 인쇄 | 분리인쇄, 통합인쇄 | `0,1` |
공사기간 축(`cmBx_Kong_Kikan`)은 화면과 내부가 **줄 수부터 다르다.**
```text
화면 Items (4줄) : 6개월이하 | 7개월~12개월이하 | 13개월~36개월이하 | 36개월이상
내부 Values (5값) : 30일 미만 | 6개월이하 | 7개월~12개월이하 | 13개월~36개월이하 | 37개월이상
```
맨 앞 `30일 미만`이 내부에만 있고, 마지막 줄은 화면이 `36개월이상`인데 내부는 `37개월이상`이다. **같은 칸을 두 이름으로 부르는 것이라 36개월 정각이 어느 쪽에 붙는지가 화면만 봐서는 안 갈린다.** 30일 미만의 실제 선택 경로와 36/37개월 경계는 동적 시험 전까지 C등급이다.
이 5구간은 `JB_R`·`JB_RA` 행렬이 **5행 묶음**(시작 행 0,5,10,…,45, 값 4행 + 빈 1행)인 것과 개수가 맞는다. 빈 한 행이 화면에 없는 구간에 해당하는 것으로 보이나, 어느 구간이 비는지는 아직 B등급이다.
### 10.1-2 형식별 선택축 — 전수 83개
설정 폼(`TWM_KANJUB`)에서 선택지를 가진 컴포넌트를 모두 뽑으면 83개다. 전문은 이 폴더의 `settings_axis_map.txt`에 있고, 재현 스크립트는 `settings_axis_map.py`다.
| 묶음 | 축 수 | 자리 |
|---|---:|---|
| 공통 (형식과 무관) | 29 | `Panel1`, `Panel3`, `pnSet_Optn`, `pn_CH_BO`, `tabAdd_BSC` |
| 일반 `T` | 12 | `Pn01_T` ~ `Pn05_T` |
| 수공 `S` | 11 | `Pn01_S` ~ `Pn05_S` |
| 실적일반 `TA` | 16 | `Pn01_TA` ~ `Pn05_TA` |
| 실적수공 `SA` | 15 | `Pn01_SA` ~ `Pn05_SA` |
**형식마다 패널 한 벌을 따로 가진다.** 같은 이름의 축이 `_T`/`_S`/`_TA`/`_SA` 네 벌로 존재하므로, 설정 스냅샷은 **형식별로 따로 저장**해야 한다. 한 벌만 저장하면 형식을 바꿀 때 값이 섞인다.
패널의 쓰임은 공통이다.
| 패널 | 담은 것 |
|---|---|
| `Pn01_x` | 안전관리비 밑수·1.2배 비교, 건강/연금 보험 밑수, (실적만) 노무비·재료비 산정방식 |
| `pn02_x` | 이윤 / 수수료 택일 — **`T``TA`에만 있고 `S`·`SA`에는 없다** |
| `Pn03_x` | 공급가액 절사 자리 |
| `Pn04_x` | 도급공사비/도급예정액 택일, 관급(도급자설치)·관급(관급자설치)의 절사 자리와 절상/반올림/절사 |
| `Pn05_x` | 총액·이윤보정 절사 자리 |
**실적형식(`TA`/`SA`)에만 있는 축 넷**`Ed_C_LTYP_x`(노무비 유형), `Ed_C_RateMxA_x`, `Ed_C_RateMxK_x`(조정계수), `Ed_C_MTYP_x`(재료비 산정방식). 일반·수공에는 아예 없다.
### 10.1-3 화면 순번과 내부값이 어긋나는 축 — 그대로 저장하면 틀리는 자리
| 축 | 화면 순서 | 내부값 순서 |
|---|---|---|
| `cmBx_Kong_Type` 공사종류 | 일반(토목), 조경, 산업설비(토목), 건축, 산업설비(건축), 국가유산수리, 폐기물처리, 소규모용역 | `0, 2, 4, 3, 1, 5, 8, 9` |
| `cmBx_Set_Base` 적용기준 | 일반(국가계약법), 일반(지방계약법), 행자부기준 | `2, 0, 1` |
| `cmBx_Pos_Sagup` 사급비 위치 | 재료비에 포함, 이윤 다음, 도급공사비 직전, 관급자재대 다음 | `3, 1, 2, 0` |
| `cmBx_AnJun_Type` 안전비 공종 | 건축, 토목, 중건설, 특수건설 | `0, 1, 3, 4`**2번이 비어 있다** |
| `cmBx_EQIP` 건설기계 보증 | 없음(국가유산수리) 포함 7줄 | `-1, 0, 1, 2, 3, 4, 5` |
| `Ed_C_MTYP_TA` / `_SA` 재료비 산정 | ① 직접공사비 × 요율 ② 조정계수 입력 | `1, 0`**뒤집혀 있다** |
| `cmBx_AnPum` 안전·품질관리비 | ① 산출경비로 포함 ② 산출경비로 미포함 | `1, 0`**뒤집혀 있다** |
`Ed_C_MTYP``cmBx_AnPum`**화면 순번을 그대로 저장하면 정반대 공식이 걸린다.** 재구현에서 화면 인덱스를 값으로 쓰면 안 되는 이유가 이 두 축에 그대로 드러난다.
`cBx_W_Type`은 화면이 `제잡비 표준시장방식`인데 내부 이름은 `제잡비 실적공사방식`이고, `cmBx_Buga1`은 화면 `(3) 산림조합 형식`이 내부 `(3) 임 협 식`이다. **같은 것을 두 이름으로 부르므로 문서·코드에서 이름으로 대조하면 안 된다.**
### 10.2 절사·절상 선택지
간접비 일괄 절사:
```text
없음, 10원, 100원, 1,000원, 10,000원, 100,000원, 1,000,000원 미만 절사
```
공급가액·도급액·총공사비/이윤보정 자리:
```text
조정 없음 또는 직접입력,
10원, 100원, 1,000원, 10,000원, 100,000원,
1,000,000원, 10,000,000원, 100,000,000원 미만
```
관급자재 조정은 자리수와 함께 `절상/반올림/절사`를 선택한다. 도급액에는 별도의 “도급액 버림없음” 선택이 있다. 즉 하나의 전역 반올림 설정이 아니라 간접비·공급가액·도급액·관급(도급자설치)·관급(관급자설치)·총액/이윤보정 설정을 따로 저장해야 한다.
### 10.3 변경설계와 안전비의 실제 모드
보험료 변경 계산(`cBx_CH_BO`)은 세 모드다.
```text
0 직접노무비 × 요율
1 당초액 + 직접노무비 증감 × 요율
2 당초액 + 증감액(비율)
```
안전비의 1.2배 비교에는 `소수 버림 후 1.2배``소수 버림 전 1.2배`가 따로 있다. 상한비도 `자동계산`, `강제적용`, `적용안함`의 세 모드다. 이 두 옵션은 같은 공식이라도 원 단위 결과를 바꾸므로 계산 추적에 반드시 남긴다.
실적형식의 노무비 산정은 `직접공사비×조정계수` 또는 `내역서 직접노무비`, 재료비 산정은 `직접공사비×요율` 또는 `조정계수 입력` 중 선택한다.
## 11. 추가금액 데이터 형태
추가금액 그리드는 다음 열을 가진다.
```text
추가비용 명칭, 선택, 입력/자동, 금액,
1단계, 2단계, ... 9단계, 최종 합계 위치
```
별도 탭은 `일반관리비 직전`, `이윤~공급가액`, `도급공사비 직전`, `관급자재~총공사비`로 나뉜다. 따라서 추가금액은 단계별 포함 여부를 최대 9개 저장하고 최종 삽입 위치를 갖는 행이다.
## 12. 구현 시 필수 검증
1. 네 형식을 같은 입력으로 계산해 밑수 차이가 표대로 발생하는지 확인한다.
2. 건강보험료를 바꾸면 장기요양보험료만 그 절사 결과를 밑수로 다시 계산하는지 확인한다.
3. 수공형식의 세부 경비 합이 일반형식 기타경비와 자동으로 같다고 가정하지 않는다.
4. 안전비는 상한비율, 기초금액, 1.2배 비교, 기존 안전비 차감의 중간값을 각각 기록한다.
5. 추가금액은 1~9단계 포함 여부에 따라 뒤 항목의 밑수가 달라지는지 확인한다.
6. `1원보정(계산결과+1원)` 옵션을 VAT/공급가액 경계에서 시험한다.
이 문서로 네 계산 형식의 항목 순서와 공식 뼈대는 재구현할 수 있다. 남은 핵심은 JB 행렬의 화면 셀 시작 좌표와 경계 비교 연산이며, 이는 저장 이벤트 역추적 또는 통제 동적 시험으로 확정해야 한다.
@@ -0,0 +1,141 @@
# STmate 통제 대조시험 목록
> 정적 분석만으로는 확정할 수 없는 경계를 **시험 단위로 갈라 놓은 유일한 목록**이다. 05~12번 문서에 흩어져 있던 "미확정·C등급" 항목을 여기로 모았다. 각 문서는 이제 이 목록을 가리킨다.
기준일: 2026-09-13
대상: `C:\경영정보(주)`**원본은 읽기만 한다.** 시험은 프로젝트 **복제본**에서 한다.
## 0. 왜 시험이 필요한가
정적 파일에는 **결과만** 남고 **분기 조건**이 안 남는 자리가 있다. 값을 하나만 바꿔 앞뒤를 대조하면 그 분기가 드러난다. 아래 시험을 다 통과해야 "비슷한 금액"이 아니라 **계산 순서와 중간값까지 같은 엔진**이라고 판정할 수 있다.
## 1. 공통 규칙
1. 시험마다 **한 변수만** 바꾼다. 두 개를 같이 바꾸면 어느 쪽이 결과를 움직였는지 못 가른다.
2. 시험 전후로 STC 안의 **모든 DBF 필드**와 출력 XLSX의 **모든 계산행**을 저장해 대조한다.
3. 원설계를 복제해 쓰고, **설치 폴더와 기준자료 원본에는 쓰지 않는다.**
4. 결과는 `시험ID / 바꾼 값 / 바뀐 필드 / 안 바뀐 필드`로 적는다. **안 바뀐 것도 증거다.**
## 2. 시험 목록
### T1 — 요율 좌표 매핑 (최우선)
| 항목 | 내용 |
|---|---|
| 무엇을 가르나 | 화면 그리드 15개가 `RATE`·`RATE_M`·`RATE_R`·`RATE_RA` 행렬의 **몇 번째 행부터** 적재되는지 |
| 지금 등급 | 열 제목·행 수 **확정(A)** / 시작 행 **미확정** |
| 어떻게 | RATE 편집 화면에서 그리드 한 칸만 눈에 띄는 값(예: `99.99`)으로 고치고 저장 → 프로젝트 `RATE_*.DBF`에서 `99.99`가 앉은 (행, 열)을 찾는다. 그리드마다 첫 칸·마지막 칸 두 번씩 |
| 확정되는 것 | 그리드 → 행렬 좌표의 완전 매핑. `rate_standard()` 기준표를 하드코딩 없이 만들 수 있게 됨 |
| 근거 문서 | 12번 §8·§9, 10번 §4 |
이미 잡아 둔 것 — 행은 `0,5,10,…,45` 시작의 **5행 묶음**, `JB_R` 열 1~5=간접노무비·6~10=기타경비(토목/산설(토목)/조경/건축/산설(건축)), 신형 열 21·26=국가유산. **T1은 나머지 부속표의 시작 행만 남긴 시험이다.**
### T2 — 금액·기간 구간 경계 방향
| 항목 | 내용 |
|---|---|
| 무엇을 가르나 | 구간 경계에서 `<`인지 `<=`인지. 공사기간은 36개월 정각이 어느 칸에 붙는지 |
| 지금 등급 | C |
| 어떻게 | 같은 프로젝트를 복제해 추정금액을 각 경계의 **직전 / 정각 / 직후** 세 값으로 두고, 공사기간도 같은 식으로 둔다. 선택된 요율과 간접비 전 행을 비교 |
| 왜 까다롭나 | 화면 목록은 `…13~36개월이하 / 36개월이상` 4줄인데 내부값은 `30일 미만 … 37개월이상` 5값이다. **같은 칸을 두 이름으로 부른다** |
| 근거 문서 | 12번 §10.1, 06번 §6 |
### T3 — `ROUNDUP`·`MINT`의 음수 방향
| 항목 | 내용 |
|---|---|
| 무엇을 가르나 | 올림·정수화가 음수에서 0에서 멀어지는지, +∞ 쪽인지 |
| 지금 등급 | `ROUND`**확정(A)** — 최근접-짝수·0 대칭. `ROUNDUP`·`MINT`만 남음 |
| 어떻게 | 끝전조정에 음수 차액이 나오는 프로젝트를 만들고 `절상`·`반올림`·`절사`를 차례로 골라 결과를 비교. 값은 `±2.44 / ±2.45 / ±2.46`, 자리 `1, 0, -1` |
| 왜 중요한가 | 내부 계산은 은행가 반올림인데 출력 XLSX 수식은 Excel 사사오입이라 **20개 경계 중 10개가 이미 갈린다** |
| 근거 문서 | 11번 §4.2 |
### T4 — 안전관리비 변형 선택 조건
| 항목 | 내용 |
|---|---|
| 무엇을 가르나 | 어느 기준연도·공사종류에서 어느 안전비 식이 걸리는지, 1.2배 비교와 상한비 모드가 원 단위 결과를 어떻게 바꾸는지 |
| 지금 등급 | 선택지 목록은 **확정(A)**, 선택 조건은 C |
| 어떻게 | 안전비 공종 4가지(`0,1,3,4`**2번이 비어 있다**) × 관급/사급 조합 × `소수 버림 전/후 1.2배` × 상한비 `자동/강제/적용안함`을 돌리고 중간값(상한비율·기초금액·1.2배 비교·기존 안전비 차감)을 각각 기록 |
| 근거 문서 | 12번 §10.3, 11번 §7 |
### T5 — 복합 보험식의 항목명 연결
| 항목 | 내용 |
|---|---|
| 무엇을 가르나 | 중첩 절사식의 `RAT_1`~`RAT_4`, `RAT_KY`가 화면의 어느 비용항목인지 |
| 지금 등급 | 식은 **확정(A)**, 이름 연결은 C |
| 어떻게 | 제비율 화면에서 항목을 하나씩 0으로 만들고 어느 항이 사라지는지 본다 |
| 근거 문서 | 11번 §6.1, 10번 §3 |
### T6 — 추가금액 단계 1·2와 특수 위치
| 항목 | 내용 |
|---|---|
| 무엇을 가르나 | 단계 1·2, `이윤 이후(공사원가 포함)`, `사급자재비 이후`가 어느 합계를 움직이는지 |
| 지금 등급 | 단계 3~6은 확정, 1·2는 C |
| 어떻게 | 같은 금액을 단계 1~9에 하나씩 넣고 순공사원가·공급가액·도급액·총액 넷을 비교 |
| 근거 문서 | 11번 §9, 12번 §11 |
### T7 — `CODE = W/B/D/X/A` 세부 분기
| 항목 | 내용 |
|---|---|
| 무엇을 가르나 | 복합·일위대가·단가산출·중기·기타 코드의 성분 합산 분기 |
| 지금 등급 | `TAMT=MAMT+LAMT+SAMT` 불변조건은 **확정(A)**, 코드별 분기는 C |
| 어떻게 | 코드 유형마다 표본 행을 만들어 성분 단가를 1원씩 움직이고 상위 단가·내역의 반응을 본다 |
| 근거 문서 | 11번 §3·§5 |
### T8 — 재계산 범위와 역의존
| 항목 | 내용 |
|---|---|
| 무엇을 가르나 | UI 버튼별로 부분계산인지 전체계산인지, 수동 고정값을 자동 변경이 덮는지 |
| 지금 등급 | C |
| 어떻게 | ① 같은 자재를 참조하는 단가 2개와 그중 하나를 참조하는 상위 단가를 만든 뒤 자재가 **1원** 변경 ② 설계수량만 변경해 단가표 불변 확인 ③ 요율만 변경해 직접비 불변 확인 |
| 근거 문서 | 08번 §1·§4 |
### T9 — 변경설계 계산모드 선택 조건
| 항목 | 내용 |
|---|---|
| 무엇을 가르나 | 방법 A(당초액 × 전체 증감비율) / 방법 B(증감 기초 × 항목 요율) / 직접입력 / 계약 제잡비율 중 **어느 조건에서 어느 것이 걸리는지** |
| 지금 등급 | 공식 자체는 **확정(A)** — 코드에서 직접 확인. 선택 조건만 C |
| 어떻게 | 원설계에서 항목 추가·삭제·수량변경·단가변경을 각각 한 건씩 만들어 변경 STC로 저장하고, 보험료 변경 모드(`cBx_CH_BO` 0/1/2)를 바꿔 가며 비교 |
| 근거 문서 | 11번 §10, 08번 §2, 12번 §10.3 |
### T10 — 일괄변경·물가변동 필터
| 항목 | 내용 |
|---|---|
| 무엇을 가르나 | 대상 선별 조건과 수동 채택가 보호 여부 |
| 지금 등급 | C |
| 어떻게 | 수동 채택가, 0원, 공란, 환율적용 품목이 섞인 표본으로 일괄변경을 돌리고 각 유형이 바뀌었는지 본다 |
| 근거 문서 | 08번 §3 |
### T11 — 형식 간 밑수 차이 확인
| 항목 | 내용 |
|---|---|
| 무엇을 가르나 | 네 형식(`T`/`S`/`TA`/`SA`)이 같은 입력에서 표대로 다른 밑수를 쓰는지 |
| 지금 등급 | 밑수 공식은 **확정(A)** — 화면 묶음 제목에서 확인. 실제 적용 확인만 남음 |
| 어떻게 | 같은 내역으로 형식만 바꿔 네 번 계산하고 각 간접비 행의 밑수를 대조. 건강보험료를 바꿔 장기요양보험료만 그 절사 결과를 밑수로 다시 계산하는지 확인 |
| 근거 문서 | 12번 §7·§12, 06번 §3 |
## 3. 우선순위
| 순위 | 시험 | 까닭 |
|---:|---|---|
| 1 | **T1** 요율 좌표 | 이것 없이는 기준표를 못 만든다. 다른 시험의 전제 |
| 2 | **T3** 반올림 방향 | 원 단위 차이가 전 항목에 번진다 |
| 3 | **T2** 구간 경계 | 요율 선택 자체가 갈린다 |
| 4 | **T11** 형식별 밑수 | 형식을 잘못 고르면 전부 틀린다 |
| 5 | **T4** 안전관리비 | 금액이 크고 변형이 많다 |
| 6 | T9 · T8 | 변경설계·재계산 |
| 7 | T5 · T6 · T7 · T10 | 나머지 |
## 4. 완료 판정
- T1~T4·T11을 통과하면 **원설계 한 건을 원 단위까지 재현**할 수 있다.
- T8·T9까지 통과하면 **변경설계를 포함해 재현**할 수 있다.
- 전부 통과하면 11번 §16 재현 시험표를 그대로 돌려 **동일 엔진 판정**이 선다.
@@ -0,0 +1,181 @@
# STmate 경쟁 프로그램 분석 — 최종 완료 보고서
분석 기간: 2026-09-12 ~ 2026-09-13
대상: `C:\경영정보(주)` (설치 폴더 `System` 186개 파일 + 프로젝트 STC 7건 + STmate 생성 XLSX 5건)
목적: 화면을 닮게 만드는 것이 아니라, **같은 입력에서 같은 중간값과 같은 최종 금액을 내는 계산 엔진**을 만들 수 있는 수준까지 규칙을 확보하는 것
원본 취급: **읽기만 했다.** 설치 폴더·기준자료·맛보기 프로젝트에 쓰기 없음. 암호 추측·우회 없음.
## 1. 어디까지 왔나
| 층 | 상태 |
|---|---|
| 파일 전수 등록 (경로·크기·SHA-256) | **186 / 186** |
| 실제 형식 판정 (파일명 아닌 헤더 기준) | **186 / 186** — PE 82, DBF 계열 61, ZIP 28, 기타 15 |
| 내부구조 추출 | **186 / 186** — 미판독 0 |
| 핵심 CPM 정적 분석 | **12 / 12** — PE 섹션·import·export·문자열 |
| 화면 폼 리소스 복원 | 제비율 편집·계산설정·인쇄 3벌 |
| 계산 규칙 A등급 확정 | 아래 3장 |
| 남은 경계 | **13번 통제시험 목록**에 시험 11개로 분리 |
**정적 분석으로 갈 수 있는 데까지 갔다.** 남은 것은 분석 누락이 아니라, 정적 파일에 **결과만 남고 분기 조건이 안 남는** 자리다. 그 자리는 값을 하나만 바꿔 앞뒤를 대조하는 통제시험으로만 갈린다.
## 2. STmate 가 무엇인가
Delphi 6 네이티브 모듈 + Apollo/Six 계열 DBF 저장소 + ZIP 기반 교환 파일로 만든 **로컬 설계예산 프로그램**이다. 값의 흐름은 이렇다.
```text
노임·자재·중기 기초자료
→ 출처별 후보단가와 채택단가
→ 일위대가·단가산출 (자원코드 × 품, 할증, 기계 Q식)
→ 공종별 재료/노무/경비 단가
→ 프로젝트 수량 × 단가
→ 직접재료비·직접노무비·산출경비
→ 제비율별 고유 밑수 × 적용률
→ 순공사원가 → 일반관리비 → 이윤 → 부가세 → 총공사비
```
## 3. 확정된 것 — A등급
### 3.1 금액 성분 불변조건
```text
TAMT = MAMT + LAMT + SAMT
CODE="L" → LAMT = TAMT CODE="M" → MAMT = TAMT CODE="S" → SAMT = TAMT
```
세 모듈에서 검증 조건식 `TAMT1 <> MAMT1+LAMT1+SAMT1`이 그대로 발견됐다. **`TAMT`는 네 번째 비용 성분이 아니라 총계다.**
### 3.2 반올림 — 내부는 은행가 반올림
전 PE 186개의 수치 런타임 심볼을 실측했다.
- `Math.RoundTo` 임포트 — 계산 모듈 17개, 모듈마다 호출 정확히 12곳
- `SimpleRoundTo`(0에서 멀어지는 변형)·`Ceil`·`SetRoundMode`·`Set8087CW`**전부 미임포트**
- 반올림 함수 본체에 `FCHS`·`FABS` 없음 → 음수 특별처리 없음
**내부 `ROUND`는 최근접-짝수(은행가) 반올림이고 0을 기준으로 대칭이다.** 사사오입이 아니다.
**STmate가 뽑아 주는 XLSX 안의 수식은 Excel `ROUND`(사사오입)**이므로 내부값과 출력값이 갈린다. 시험한 20개 경계 중 **10개가 원 단위에서 다르다.**
| 값 | 자리 | 내부 | 출력 XLSX |
|---:|---:|---:|---:|
| 2.5 | 원 | 2 | 3 |
| 2,500 | 천원 | 2,000 | 3,000 |
| 2,500 | 천원 | 2,000 | 3,000 |
`2.45`는 한 겹 더 어긋난다 — `RoundTo``IntPower(10,-1)`로 만든 `0.1`이 이진수로 정확하지 않아 `2.45/0.1``24.4999…`가 된다. **`Decimal` 사사오입으로는 STmate 결과를 흉내 낼 수 없다.**
### 3.3 간접비 항목별 밑수
RATE 편집 화면의 그리드 묶음 제목에 **밑수 공식이 그대로 적혀 있다.** 추정이 아니다. 전체 표는 06번 §3에 있고, 정정된 곳은 셋이다.
- 환경보전비 밑수는 직접공사비가 아니라 `재료비+직접노무비+산출경비`*(실적일반만 직접공사비)*
- 기타경비 밑수는 형식에 따라 `재료비+노무비`(일반·수공)와 `직접공사비`(실적)로 갈린다
- 이윤 밑수는 일반형식에서 `노+경+일`이다
### 3.4 원가계산 네 형식
일반 `T` · 수공 `S` · 실적일반 `TA` · 실적수공 `SA`. **출력 템플릿이 아니라 공식 집합과 합계 트리가 통째로 다르다.**
| 규칙 | T | S | TA | SA |
|---|---|---|---|---|
| 산재·고용 밑수 | 노무비 | 직노+간노 | 노무비 | 직노+간노 |
| 기타경비 | 묶음 1개 | 세부 8개 | 묶음 1개 | 세부 8개 |
| 일반관리비 밑수 | 순공사원가+관리품목자재 | 순공사비+간노+경비 | 직공비+간접비+관리품목자재 | 직공비+간접노무비 |
### 3.5 변경설계 계산모드
실행모듈에 산식 두 개가 그대로 있다.
```text
방법 A = C_AMT_B + ROUNDDOWN(C_AMT_B × ((C_TAMT_C-C_TAMT_B)/C_TAMT_B), digits)
방법 B = C_AMT_B + ROUNDDOWN((C_TAMT_C-C_TAMT_B) × RAT_1, digits)
```
여기에 당초금액 직접입력, 계약 제잡비율 적용이 더 있고 보험료 변경은 별도 3모드다. **항목마다 계산모드를 고르는 구조**이므로 모드를 하나로 고정하면 재현할 수 없다.
### 3.6 기준자료 파일 구조
| 파일 | 형태 | 개수 |
|---|---|---:|
| `JB_1` | 41행 × 10열 | 1 (2011) |
| `JB_M` | 25행 × 10열 | 1 (2007) |
| `JB_R` 구형 | 50행 × 20열 | 9 (2015 ~ 2020-01-02) |
| `JB_R` 신형 | 50행 × 35열 | 18 (2020-05-27 ~ 2026) |
| `JB_RA` | 50행 × 20열 | 13 (확장 없음) |
- **확장 시점은 2020-05-27**이고 기존 1~20열은 **500개 셀 중 하나도 바뀌지 않았다.** 구형을 읽을 때 해석을 바꿀 필요가 없다.
- 행은 `0,5,10,…,45` 시작의 **5행 묶음**(값 4행 + 빈 1행)이다. 설정의 공사기간 내부값이 5구간인 것과 개수가 맞는다.
- `JB_R` 열 1~5는 간접노무비, 6~10은 기타경비이고 둘 다 `토목 / 산.설(토목) / 조경 / 건축 / 산.설(건축)` 순이다. 신형 열 21·26이 국가유산이다.
- 프로젝트의 `RATE_*`는 외래키가 아니라 **기준파일을 복사한 뒤 수정 가능한 스냅샷**이다.
### 3.7 계산 설정
설정 폼의 선택축 **83개를 전수 확보**했다 — 공통 29, 일반 12, 수공 11, 실적일반 16, 실적수공 15. **형식마다 패널 한 벌을 따로 가지므로 설정 스냅샷도 형식별로 저장해야 한다.**
화면 순번과 내부값이 어긋나는 축이 7개이고, 그중 `Ed_C_MTYP`(재료비 산정방식)와 `cmBx_AnPum`(안전·품질관리비)은 **순서가 뒤집혀 있어 화면 인덱스를 그대로 저장하면 정반대 공식이 걸린다.**
## 4. 남은 것
전부 **13번 통제시험 목록**에 시험 11개(T1~T11)로 옮겼다. 우선순위 상위 다섯은 이렇다.
| 순위 | 시험 | 무엇을 가르나 |
|---:|---|---|
| 1 | T1 | 화면 그리드가 `RATE*` 행렬의 몇 번째 행부터 적재되는지 |
| 2 | T3 | `ROUNDUP`·`MINT`의 음수 방향 |
| 3 | T2 | 금액·기간 구간 경계의 `<` / `<=` |
| 4 | T11 | 네 형식이 실제로 표대로 다른 밑수를 쓰는지 |
| 5 | T4 | 안전관리비 변형의 선택 조건 |
## 5. 완료 판정 기준
| 단계 | 판정 |
|---|---|
| **정적 분석 완료** | ✅ 달성 — 186/186 판독, 계산 규칙 A등급 확보, 남은 경계를 시험으로 분리 |
| 원설계 재현 | T1·T2·T3·T4·T11 통과 시 — 원 단위까지 일치 |
| 변경설계 포함 재현 | 위 + T8·T9 통과 시 |
| **동일 엔진 판정** | T1~T11 전부 통과 + 11번 §16 재현 시험표 전 항목 통과 |
「비슷한 금액」은 판정 기준이 아니다. **계산 순서와 중간값까지 같아야** 동일 엔진이다.
## 6. Aislo 가 가져갈 것
- **프로젝트 한 묶음 교환** — 입력·채택 단가 스냅샷·계산 설정·산출 결과·매니페스트를 한 파일로
- **보고서 서식 데이터화**(`SET_REP`) — 보고서별 열 이름·폭·표시 여부를 데이터로
- **당초/변경 비교** — DB 열을 네 벌 복제하지 말고 기존 프로젝트 버전·스냅샷으로
- **반올림 정책을 자리마다 명시** — 하나의 전역 설정으로 두면 안 된다. STmate는 간접비·공급가액·도급액·관급 2종·총액/이윤보정을 **따로** 가진다
- **유지할 것** — 채택 단가가 없으면 오류로 금액 확정을 막는 Aislo 방식. STmate는 0과 미입력의 구분이 흐린 자리가 있다
## 7. 산출물
### 문서 15개 (00~14)
전체 인덱스와 링크는 **00번**에 있다.
### 원자료
| 파일 | 내용 |
|---|---|
| `system_inventory.csv` | 186개 파일 경로·크기·SHA-256·실제 형식·상태 |
| `core_cpm_static.json` | 핵심 CPM 12개의 PE/import/export/도메인 문자열 |
| `system_structures.json` | 186개 전 파일 내부구조 |
| `export_disassembly.json` | export 함수 디스어셈블 |
| `core_formula_strings.json` | 바이너리에서 검출한 계산식 |
| `TWM_KANJUB` · `TWM_KAN_RATE` · `TPM_KAN_RATE` (`.dfm`/`.json`) | 복원한 화면 폼 |
| `settings_axis_map.txt` | 설정 선택축 83개 전문 |
### 재현 스크립트
| 스크립트 | 하는 일 |
|---|---|
| `analyze_system.py` | 186개 전수 등록·해시·형식 판정 |
| `evidence_extract.py` · `disassemble_exports.py` | 계산식·export 추출 |
| `parse_dfm.py` | 폼 리소스 → JSON |
| `rounding_symbol_matrix.py` | 반올림 런타임 심볼 임포트 실측 |
| `rounding_callsites.py` | 썽크 경유 호출 자리 집계 |
| `rounding_dispatcher_dump.py` | 반올림 함수 바이트 덤프 |
| `round_table.py` | 내부 ↔ Excel 반올림 경계표 |
| `jb_shapes.py` · `jb_block_map.py` · `jb_expansion_diff.py` | JB 43개 형태·블록·확장 차이 |
| `rate_grid_defs.py` · `settings_axis_map.py` | 폼에서 그리드·선택축 추출 |
모든 스크립트는 `C:\경영정보(주)`**읽기만** 한다.
@@ -0,0 +1,423 @@
{
"CODE=\"W\" .and. (TAMT1<>MAMT1+LAMT1+SAMT1 or TAMT2<>MAMT2+LAMT2+SAMT2)": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM"
],
"CODE=\"W\" .and. TAMT1<>MAMT1+LAMT1+SAMT1": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM"
],
"(SUBSTR(CODE,1,1)$\"LMS\" and (TAMT1<>MAMT1+LAMT1+SAMT1 or TAMT2<>MAMT2+LAMT2+SAMT2)) or (CODE=\"L\" and (LAMT1<>TAMT1 or LAMT2<>TAMT2)) or (CODE=\"M\" and (MAMT1<>TAMT1 or MAMT2<>TAMT2)) or (CODE=\"S\" and (SAMT1<>TAMT1 or SAMT2<>TAMT2))": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM"
],
"(SUBSTR(CODE,1,1)$\"LMS\" and TAMT1<>MAMT1+LAMT1+SAMT1) or (CODE=\"L\" and LAMT1<>TAMT1) or (CODE=\"M\" and MAMT1<>TAMT1) or (CODE=\"S\" and SAMT1<>TAMT1)": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM"
],
"ROUNDDOWN( [LAMT] * [RAT_1], ": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( ([L_AMT][+LAB]) * [RAT_1], ": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"[C_AMT_B]+ROUNDDOWN( [C_AMT_B] * (([C_TAMT_C]-[C_TAMT_B])/[C_TAMT_B]), ": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"+ROUNDDOWN( ": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"[C_AMT_B]+ROUNDDOWN( ([C_TAMT_C]-[C_TAMT_B]) * [RAT_1], ": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( ": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( [C_KUNBO] * [RAT_1], ": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( ([LAMT][+LAB]) * [RAT_1], ": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN(": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"IF(([LAMT]+[M_AMT])>ROUNDDOWN(": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"*[TAMT],0),ROUNDDOWN(": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( ( ": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"IF(([L_AMT]+[M_AMT])>ROUNDDOWN(": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( ((": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( ([TAMT]": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( ([T_AMT]+": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( [T_AMT] * [RAT_1], ": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( [T_AMT] * [RAT_1], 0 )": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( ([T_AMT]-[M_AMT]) * [RAT_1], 0 )": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( ROUNDDOWN([LAMT]*[RAT_1]*[RAT_2]/100*1.4,0) + ROUNDDOWN([LAMT]*[RAT_KY]*[RAT_3]/100,0) + ROUNDDOWN([LAMT]*[RAT_1]*[RAT_2]/100*[RAT_4]/100,0), ": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( ([M_AMT]+[L_AMT]+[S_AMT]": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN([T_AMT] * [RAT_1], 0)": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN([M_AMT] * [RAT_1], 0)": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN(([TAMT]-[LAMT]": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUND( [C_AD_AMT] , -": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN( [C_AD_AMT] , -": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDUP( [C_AD_AMT] , -": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"ROUNDDOWN([T_AMT]": [
"ST_CPM\\ST_Boq.CPM",
"ST_CPM\\ST_EdiLWi.CPM",
"ST_CPM\\ST_KanJub.CPM",
"ST_CPM\\ST_P_Collect.CPM",
"ST_CPM\\ST_P_ConEst.CPM",
"ST_CPM\\ST_P_Joong.CPM",
"ST_CPM\\ST_SanCal.CPM",
"ST_CPM\\ST_U_ChgAmt.CPM",
"ST_CPM\\ST_U_ChgCode.CPM",
"ST_CPM\\ST_U_ConBD.CPM",
"ST_CPM\\ST_U_Convert.CPM",
"ST_CPM\\STmateQty8.CPM"
],
"( SUBSTR(BDCODE1,1,1)$\"MLSW\" .and. \"%\"$UNIT1 ) .or. ( SUBSTR(BDCODE1,1,1)$\"MLSWBDXA\" .and. SUBSTR(STR(QTY1,20,4),LEN(STR(QTY1,20,4)),1)<>\"0\" )": [
"ST_CPM\\ST_Boq.CPM"
],
"(SUBSTR(BDCODE1,1,1)$\"TEC\" or (QTY": [
"ST_CPM\\ST_U_ConBD.CPM"
],
"ROUND(": [
"ST_CPM\\ST_U_Convert.CPM"
]
}
@@ -0,0 +1,565 @@
### 원가계산 설정 — 형식별 선택축
====================================================================================================
## 공통 선택축 29개
■ Cmbx_PORD1_H (Panel1) 2개
0 당초 / 변경 대비인쇄
1 변 경 분 만 인 쇄
■ cBx_K_JeolSa (Panel1) 7개
0 간접비 절사없음
1 간접비 10원미만 절사
2 간접비 100원미만 절사
3 간접비 1,000원미만 절사
4 간접비 10,000원미만 절사
5 간접비 100,000원미만 절사
6 간접비 1,000,000원미만 절사
■ cBx_Chasu (Panel1) 4개
0 원설계
1 1차변경
2 2차변경
3 3차변경
■ cBx_W_Type (Panel1) 2개 ※화면≠내부
0 제잡비 원가계산방식
1 제잡비 표준시장방식 → 내부 `제잡비 실적공사방식`
■ cmBx_Kobo_Type (Panel3) 8개
0 없음
1 1 등급
2 2 등급
3 3 등급
4 4 등급
5 5 등급
6 6 등급
7 7 등급이하
■ cmBx_JAB_TYPE (Panel3) 6개
0 일반 형식
1 토지개발공사 형식
2 인천상수도 형식
3 수자원공사 형식
4 지역난방공사 형식
5 고용개선지원(서울)
■ cmBx_Kong_Type (Panel3) 8개 ※화면≠내부
0 (1) 일반(토목)공사 → 내부 `0`
1 (2) 조경공사 → 내부 `2`
2 (3) 산업설비(토목) → 내부 `4`
3 (4) 건축공사 → 내부 `3`
4 (5) 산업설비(건축) → 내부 `1`
5 (6) 국가유산수리 → 내부 `5`
6 (7) 폐기물처리 → 내부 `8`
7 (8) 소규모용역 → 내부 `9`
■ cmBx_JeolSa (Panel3) 9개
0 총공사비에서 조정
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ cmBx_Buga (Panel3) 5개
0 (0) 공급가액의 10%
1 (1) 재료비의 10%
2 (2) 없음
3 (3) 산림조합 형식
4 (4) 산림조합-면세품
■ cmBx_TBugum (Panel3) 4개
0 토목공사
1 준설공사
2 건축공사
3 기타
■ cmBx_Hwan (Panel3) 15개
0 ◈ 없음(전기, 정보통신, 소방시설, 국가유산수리)
1 ◈ 도로(교량, 터널, 활주로)
2 ◈ 플랜트(발전소, 쓰레기소각로)
3 ◈ 지하철
4 ◈ 철도
5 ◈ 상하수도(폐수, 하수처리장, 정수장)
6 ◈ 항만(오탁, 준설토, 방지막설치필요시(간척, 준설))
7 ◈ 항만(방지막설치불필요시(간척, 준설))
8 ◈ 댐
9 ◈ 택지개발
10 ◈ 주택(재개발, 재건축)
11 ◈ 주택(신축)
12 ◈ 주택(재개발, 재건축, 주택(신축))외 건축
13 ◈ 조경
14 ◈ 기타토목(하천등)
■ cmBx_AnJun_Type (Panel3) 4개 ※화면≠내부
0 건축공사 → 내부 `0`
1 토목공사 → 내부 `1`
2 중건설공사 → 내부 `3`
3 특수건설공사 → 내부 `4`
■ cmBx_Kwan_Sa (Panel3) 8개
0 관급자재대/1.1
1 관급자재대
2 사급자재대/1.1
3 사급자재대
4 관급/1.1+사급재
5 관급재+사급/1.1
6 (관급+사급)/1.1
7 관급재+사급재
■ cmBx_Pos_Sagup (Panel3) 4개 ※화면≠내부
0 재료비에 포함 → 내부 `3`
1 이윤 다음 → 내부 `1`
2 도급공사비 직전 → 내부 `2`
3 관급자재대 다음 → 내부 `0`
■ cmBx_Kun_Type (Panel3) 7개
0 청사(11층이하)
1 청사(12층이상)
2 학교
3 국가유산
4 관람집회시설
5 전시시설
6 기타
■ cmBx_KONGSU (Panel3) 2개 ※화면≠내부
0 일반계약 → 내부 `0`
1 최저가,기술제안 → 내부 `1`
■ cmBx_Set_Base (Panel3) 3개 ※화면≠내부
0 일반(국가계약법) → 내부 `2`
1 일반(지방계약법) → 내부 `0`
2 행자부기준 → 내부 `1`
■ cmBx_Kong_Kikan (Panel3) 4개 ⚠개수불일치(선택지4/내부값5) ※화면≠내부
0 6개월이하 → 내부 `30일 미만`
1 7개월 ~ 12개월이하 → 내부 `6개월이하`
2 13개월 ~ 36개월이하 → 내부 `7개월 ~ 12개월이하`
3 36개월이상 → 내부 `13개월 ~ 36개월이하`
▶ 화면에 없는 내부값: ['37개월이상']
■ cBx_iLBan (Panel3) 2개
0 (주)공사
1 전문공사
■ cmBx_EQIP (Panel3) 7개 ※화면≠내부
0 ◈ 없음(국가유산수리공사) → 내부 `-1`
1 ◈ 일반공사(토목,산업설비,조경,건축) → 내부 `0`
2 ◈ 준설, 포장공사, 토공사, 비계·구조물해제 → 내부 `1`
3 ◈ 상하수도설비, 보링·그라우팅, 수중공사 → 내부 `2`
4 ◈ 석공사, 시설물유지관리, 철근·콘크리트, 가스시설공사(1종) → 내부 `3`
5 ◈ 조경시설물설치, 조경식재, 철도궤도, 도장공사, 철강재설치공사 → 내부 `4`
6 ◈ 기계설비공사업 및 그외 → 내부 `5`
■ cmBx_ANJUN (pnSet_Optn) 2개 ※화면≠내부
0 사용자 수동계산 → 내부 `0`
1 제비율표자동계산 → 내부 `1`
■ cmBx_Buga1 (pnSet_Optn) 5개 ※화면≠내부
0 (0) 공급가액의 10%
1 (1) 재료비의 10%
2 (2) 없음
3 (3) 산림조합 형식 → 내부 `(3) 임 협 식`
4 (4) 산림조합-면세품
■ cmBx_Kwan_Sa1 (pnSet_Optn) 8개
0 관급자재대/1.1
1 관급자재대
2 사급자재대/1.1
3 사급자재대
4 관급/1.1+사급재
5 관급재+사급/1.1
6 (관급+사급)/1.1
7 관급재+사급재
■ cBx_Dog_Jeol (pnSet_Optn) 9개
0 도급액 버림없음
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ cBx_CH_BO (pn_CH_BO) 3개 ※화면≠내부
0 직접노무비 x 요율 → 내부 `0`
1 당초액 + 직노증감x요율 → 내부 `1`
2 당초액 + 증감액(비율) → 내부 `2`
■ cmBx_Anjun_DN (pnSet_Optn) 2개 ※화면≠내부
0 소수 버림 후 1.2배 → 내부 `0`
1 소수 버림 전 1.2배 → 내부 `1`
■ cmBx_AnJun_Type1 (pnSet_Optn) 4개 ※화면≠내부
0 건축공사 → 내부 `0`
1 토목공사 → 내부 `1`
2 중건설공사 → 내부 `3`
3 특수건설공사 → 내부 `4`
■ cmBx_AnPum (pnSet_Optn) 2개 ※화면≠내부
0 산출경비로 포함 → 내부 `1`
1 산출경비로 미포함 → 내부 `0`
■ cmBx_Kwan_Comb (tabAdd_BSC) 2개 ※화면≠내부
0 (0) 분리인쇄 → 내부 `0`
1 (1) 통합인쇄 → 내부 `1`
====================================================================================================
## 일반 T 선택축 12개
■ cBx_Jeol_T (Pn03_T) 9개
0 총공사비에서 조정
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ Ed_C_AnJun_K_T (Pn01_T) 3개
0 없음
1 관급/사급 내용
2 사급자재대
■ Ed_C_AnJun_B_T (Pn01_T) 2개
0
1 의 1.2배
■ Ed_C_KUNBO_T (Pn01_T) 2개 ※화면≠내부
0 ㄴ.1)직노 → 내부 `ㄴ.1)직접노무비`
1 당해 상시근로자노무비
■ Ed_C_YUNBO_T (Pn01_T) 2개 ※화면≠내부
0 ㄴ.1)직노 → 내부 `ㄴ.1)직접노무비`
1 당해 상시근로자노무비
■ Ed_C_IYUN_T (pn02_T) 2개 ※화면≠내부
0 이윤 → 내부 `0`
1 수수료 → 내부 `1`
■ Ed_C_DOGUP_T (Pn04_T) 2개 ※화면≠내부
0 도급공사비 → 내부 `0`
1 도급예정액 → 내부 `1`
■ cBx_KWN_Jeol_T (Pn04_T) 9개
0 절상(절사) 없음
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ cBx_KWN_UPDN_T (Pn04_T) 3개
0 절상
1 반올림
2 절사
■ cBx_KWN_K_Jeol_T (Pn04_T) 9개
0 절상(절사) 없음
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ cBx_KWN_K_UPDN_T (Pn04_T) 3개
0 절상
1 반올림
2 절사
■ cBx_Tot_Jeol_T (Pn05_T) 9개
0 이윤보정액 입력
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
====================================================================================================
## 수공 S 선택축 11개
■ cBx_Jeol_S (Pn03_S) 9개
0 총공사비에서 조정
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ Ed_C_AnJun_K_S (Pn01_S) 2개
0 없음
1 관급/사급 내용
■ Ed_C_AnJun_B_S (Pn01_S) 2개
0
1 의 1.2배
■ Ed_C_KUNBO_S (Pn01_S) 2개 ※화면≠내부
0 ㄴ.1)직노 → 내부 `ㄴ.1)직접노무비`
1 당해 상시근로자노무비
■ Ed_C_YUNBO_S (Pn01_S) 2개 ※화면≠내부
0 ㄴ.1)직노 → 내부 `ㄴ.1)직접노무비`
1 당해 상시근로자노무비
■ Ed_C_DOGUP_S (Pn04_S) 2개 ※화면≠내부
0 도급공사비 → 내부 `0`
1 도급예정액 → 내부 `1`
■ cBx_KWN_Jeol_S (Pn04_S) 9개
0 절상(절사) 없음
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ cBx_KWN_UPDN_S (Pn04_S) 3개
0 절상
1 반올림
2 절사
■ cBx_KWN_K_Jeol_S (Pn04_S) 9개
0 절상(절사) 없음
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ cBx_KWN_K_UPDN_S (Pn04_S) 3개
0 절상
1 반올림
2 절사
■ cBx_Tot_Jeol_S (Pn05_S) 9개
0 이윤보정액 입력
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
====================================================================================================
## 실적일반 TA 선택축 16개
■ cBx_Jeol_TA (Pn03_TA) 9개
0 총공사비에서 조정
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ Ed_C_AnJun_K_TA (Pn01_TA) 3개
0 없음
1 관급/사급 내용
2 사급자재대
■ Ed_C_AnJun_B_TA (Pn01_TA) 2개
0
1 의 1.2배
■ Ed_C_KUNBO_TA (Pn01_TA) 2개 ※화면≠내부
0 ㄴ.1)직노 → 내부 `ㄴ.1)직접노무비`
1 당해 상시근로자노무비
■ Ed_C_YUNBO_TA (Pn01_TA) 2개 ※화면≠내부
0 ㄴ.1)직노 → 내부 `ㄴ.1)직접노무비`
1 당해 상시근로자노무비
■ Ed_C_LTYP_TA (Pn01_TA) 2개
0 노무비 = 직공비 x 조정계수
1 노무비 = 내역서 직접노무비
■ Ed_C_RateMxA_TA (Pn01_TA) 3개
0 상한비 자동계산
1 상한비 강제적용
2 상한비 적용안함
■ Ed_C_RateMxK_TA (Pn01_TA) 3개
0 상한비 자동계산
1 상한비 강제적용
2 상한비 적용안함
■ Ed_C_MTYP_TA (Pn01_TA) 2개 ※화면≠내부
0 직접공사비 * 요율 방식 → 내부 `1`
1 조정계수 입력방식 → 내부 `0`
■ Ed_C_IYUN_TA (pn02_TA) 2개 ※화면≠내부
0 이윤 → 내부 `0`
1 수수료 → 내부 `1`
■ Ed_C_DOGUP_TA (Pn04_TA) 2개 ※화면≠내부
0 도급공사비 → 내부 `0`
1 도급예정액 → 내부 `1`
■ cBx_KWN_Jeol_TA (Pn04_TA) 9개
0 절상(절사) 없음
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ cBx_KWN_UPDN_TA (Pn04_TA) 3개
0 절상
1 반올림
2 절사
■ cBx_KWN_K_Jeol_TA (Pn04_TA) 9개
0 절상(절사) 없음
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ cBx_KWN_K_UPDN_TA (Pn04_TA) 3개
0 절상
1 반올림
2 절사
■ cBx_Tot_Jeol_TA (Pn05_TA) 9개
0 이윤보정액 입력
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
====================================================================================================
## 실적수공 SA 선택축 15개
■ cBx_Jeol_SA (Pn03_SA) 9개
0 총공사비에서 조정
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ Ed_C_AnJun_K_SA (Pn01_SA) 2개
0 없음
1 관급/사급 내용
■ Ed_C_AnJun_B_SA (Pn01_SA) 2개
0
1 의 1.2배
■ Ed_C_KUNBO_SA (Pn01_SA) 2개 ※화면≠내부
0 ㄴ.1)직노 → 내부 `ㄴ.1)직접노무비`
1 당해 상시근로자노무비
■ Ed_C_YUNBO_SA (Pn01_SA) 2개 ※화면≠내부
0 ㄴ.1)직노 → 내부 `ㄴ.1)직접노무비`
1 당해 상시근로자노무비
■ Ed_C_LTYP_SA (Pn01_SA) 2개
0 노무비 = 직공비 x 조정계수
1 노무비 = 내역서 직접노무비
■ Ed_C_RateMxA_SA (Pn01_SA) 3개
0 상한비 자동계산
1 상한비 강제적용
2 상한비 적용안함
■ Ed_C_RateMxK_SA (Pn01_SA) 3개
0 상한비 자동계산
1 상한비 강제적용
2 상한비 적용안함
■ Ed_C_MTYP_SA (Pn01_SA) 2개 ※화면≠내부
0 직접공사비 * 요율 방식 → 내부 `1`
1 조정계수 입력방식 → 내부 `0`
■ Ed_C_DOGUP_SA (Pn04_SA) 2개 ※화면≠내부
0 도급공사비 → 내부 `0`
1 도급예정액 → 내부 `1`
■ cBx_KWN_Jeol_SA (Pn04_SA) 9개
0 절상(절사) 없음
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ cBx_KWN_UPDN_SA (Pn04_SA) 3개
0 절상
1 반올림
2 절사
■ cBx_KWN_K_Jeol_SA (Pn04_SA) 9개
0 절상(절사) 없음
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
■ cBx_KWN_K_UPDN_SA (Pn04_SA) 3개
0 절상
1 반올림
2 절사
■ cBx_Tot_Jeol_SA (Pn05_SA) 9개
0 이윤보정액 입력
1 10원 미만
2 100원 미만
3 1,000원 미만
4 10,000원 미만
5 100,000원 미만
6 1,000,000원 미만
7 10,000,000원 미만
8 100,000,000원 미만
@@ -0,0 +1,503 @@
Call DeactivateFontsInfo before calling this.
Background
Foreground
Foreground@
ctHalfBlock
eoHalfPageScroll
TBdQtyRecP
QTY1
QTY2
QTY3
QTY4
TAMT1
LAMT1
MAMT1
SAMT1
RATE
KWNGP
EQCODE
X_RATE
X_QTY1
X_QTY2
X_QTY3
X_HAL1
X_HAL2
X_HAL3
S_RATE
select
NAG_HAL
ST_MHAL
EQ_LHAL
EQ_MHAL
EQ_SHAL
BDQTY.DBF
LAMT
MAMT
SAMT
TAMT
RATE_L
X_QTY
X_HAL
IFORM
CODE="W" .and. (TAMT1<>MAMT1+LAMT1+SAMT1 or TAMT2<>MAMT2+LAMT2+SAMT2)
CODE="W" .and. TAMT1<>MAMT1+LAMT1+SAMT1
TAMT2
MAMT2
LAMT2
SAMT2
(SUBSTR(CODE,1,1)$"LMS" and (TAMT1<>MAMT1+LAMT1+SAMT1 or TAMT2<>MAMT2+LAMT2+SAMT2)) or (CODE="L" and (LAMT1<>TAMT1 or LAMT2<>TAMT2)) or (CODE="M" and (MAMT1<>TAMT1 or MAMT2<>TAMT2)) or (CODE="S" and (SAMT1<>TAMT1 or SAMT2<>TAMT2))
(SUBSTR(CODE,1,1)$"LMS" and TAMT1<>MAMT1+LAMT1+SAMT1) or (CODE="L" and LAMT1<>TAMT1) or (CODE="M" and MAMT1<>TAMT1) or (CODE="S" and SAMT1<>TAMT1)
BDQTY
S_ADJ
ADJ_L
ADJ_M
ADJ_S
COSTN.DBF
Find_BOQ
Find_BOQ
QTY1_B
QTY1_N
QTY1_H
Calc Boq
CON_USD*.DBF
CON_QTY*.DBF
.DBF
STmateQty8.CPM
ST_QTY
Free_Qty
EQSYNC.DBF
CPM_INFO.DBF
CPM_INFO.SMT
CPM_INFO_$.DBF
KBOQ
PRJLST.DBF
COSTA.DBF
SYSINFO.DBF
Select * from Win32_NetworkAdapterConfiguration Where IPEnabled=TRUE
Excel.Application
Microsoft Excel
Excel
;COSTK.DBF;COSTN1.DBF;BDQTYD.DBF;BDQTYL.DBF;BDQTYM.DBF;BBOQ.DBF;BOQC.DBF;BOQJ.DBF;BOQM.DBF;BRJ.DBF;PRJ.DBF;ITQTY.DBF;MITQTY.DBF;UITQTY.DBF;PRJLST1.DBF;CHANGE.DBF;IMGINFO.DBF;ILWI.DBF;SAN.DBF;PRLMTM.DBF;PRNDB1.DBF;RATE_A.DBF;RATE_B.DBF;SEED.DBF;START.INI;
GrdBoqBigo
C_PSAMT_B
B_PSAMT_B
I_NAG_RATE
ROUNDDOWN( [LAMT] * [RAT_1],
ROUNDDOWN( ([L_AMT][+LAB]) * [RAT_1],
[C_AMT_B]+ROUNDDOWN( [C_AMT_B] * (([C_TAMT_C]-[C_TAMT_B])/[C_TAMT_B]),
[C_TAMT_B]
+ROUNDDOWN(
(([LAMT][+LAB])-
[C_AMT_B]+ROUNDDOWN( ([C_TAMT_C]-[C_TAMT_B]) * [RAT_1],
ROUNDDOWN(
([LAMT][+LAB])
ROUNDDOWN( [C_KUNBO] * [RAT_1],
ROUNDDOWN( ([LAMT][+LAB]) * [RAT_1],
[LAMT][+LAB]
([TAMT])
([LAMT]+[M_AMT]
ROUNDDOWN(
*[TAMT],0)
IF(([LAMT]+[M_AMT])>ROUNDDOWN(
*[TAMT],0),ROUNDDOWN(
*[TAMT],0),([LAMT]+[M_AMT]))
ROUNDDOWN( (
IF(([L_AMT]+[M_AMT])>ROUNDDOWN(
*[TAMT],0),([L_AMT]+[M_AMT]))
ROUNDDOWN( ((
+([TAMT]
ROUNDDOWN( ([TAMT]
ROUNDDOWN( ([T_AMT]+
ROUNDDOWN( [T_AMT] * [RAT_1],
ROUNDDOWN( [T_AMT] * [RAT_1], 0 )
ROUNDDOWN( ([T_AMT]-[M_AMT]) * [RAT_1], 0 )
ROUNDDOWN( ROUNDDOWN([LAMT]*[RAT_1]*[RAT_2]/100*1.4,0) + ROUNDDOWN([LAMT]*[RAT_KY]*[RAT_3]/100,0) + ROUNDDOWN([LAMT]*[RAT_1]*[RAT_2]/100*[RAT_4]/100,0),
ROUNDDOWN( ([M_AMT]+[L_AMT]+[S_AMT]
ROUNDDOWN([T_AMT] * [RAT_1], 0)
ROUNDDOWN([M_AMT] * [RAT_1], 0)
ROUNDDOWN(([TAMT]-[LAMT]
ROUND( [C_AD_AMT] , -
ROUNDDOWN( [C_AD_AMT] , -
ROUNDUP( [C_AD_AMT] , -
ROUNDDOWN([T_AMT]
halH
FormActivate
AddSeparateDirs
Please insert last disk in set
Please insert disk volume %.1d of %.1d
Please insert disk volume %.1d
TBackgroundLayout
BackgroundLayout
tb_BdQtyx
ds_BdQty
tb_BdQty_X
ds_BdQty_X
tb_BdQty_Im
tb_CostA
ds_CostA
Grd_Rate
gBx_Rate0
Act_Set_RateP
cBx_SetARate
Grd_RateDrawCell
Grd_RateColumnTitleClick
Grd_RateDblClick
Grd_RateKeyDown
Grd_RateCellExit
Grd_RateExit
Grd_RateBeforePost
Grd_RateCellEnter
Grd_RateRowChange
Act_Set_RateExecute
Grd_RateEnter
cBx_SetARateClick
LAMT1_R
CODE="W" .and. (LEN(TRIM(BQCODE))>5 .or. LEN(TRIM(EQCODE))>5)
TwM_Xls_Comp
TwM_Xls_ComplpN
Xls_Comp
COMP_C.DBF
POS_D_XLS_COMP
MAMT1_O
PG_11_O
PG_21_O
PG_31_O
PG_41_O
PG_51_O
EQCODE_O
PG_1_O
PG_11
PG_21
PG_31
PG_41
PG_51
PG_1
LAMT1_O
SAMT1_O
TAMT1_O
PG_2
PG_3
PG_4
PG_5
ed_EQCODE,
"$UPPER(EQCODE))
"$UPPER(JDCODE+NAME+SIZE+UNIT+GNCODE+PSCODE+EQCODE+ST_NAME)
wBx_MAMT
ed_Hal
Act_Set_Hal
ed_HalEnter
ed_HalKeyDown
Act_Set_HalExecute
*.STBSC
;NAME;SIZE;UNIT;BQCODE;EQCODE;EDT_DATE;JDCODE;
BSC_COSTN.DBF
BSC_BDQTY.DBF
BSC_COSTN.*
BSC_BDQTY.*
CostNavi
Act_FindBoq
sBtnLstEqCode
Act_LstEqCode
Act_Ed_Qty<
pn_LHal
pn_MHal
sBtnHaLmCost
Chk_Auto_Hal
pn_XHal
sBtnHaLKike
Pop_Rate_L
Pop_Rate_6
mi_SetAmt6
mi_Edt_Amt6_Rate
mi_HalLt
mi_Ed_HalDx
mi_Ed_HalL
mi_View_HalL
Act_FindBoqExecute
Act_Ed_QtyExecute
Rate_LClick
Chk_Auto_HalClick
mi_View_HalLClick
Auto_Hal
PRT.DBF
ADJ_
"$UPPER(CODE+NAME+SIZE+UNIT+BQCODE+EQCODE+JDCODE+EDT_DATE
Edt_Hal_Rate
Edt_Hal_Amt
.CSTA;*_
.CSTA
CSTA
COSTA.CSTA
P_XLS.CPM
MAKE_XLS
MAKE_XLS
SHOW_XLS
SHOW_XLS
FREE_XLS
FREE_XLS
)= ROUNDDOWN(
= ROUNDDOWN(
tb_BdQtyh
ds_BdQtyx
tb_BdQty_X|
mBtn_EDBOQ$
mBtn_EDBOQClick
.dbf
CostNaviP
sBtnLstEqCode|
ActFindBoq1
Act_LstEqCodeExecute
"$UPPER(CODE+NAME+SIZE+UNIT+BQCODE+EQCODE+JDCODE+EDT_DATE+CONTCODE
tb_BdQty`
tb_Qty
FormDeactivate
CON_QTY9
CON_QTY
CONBD_USD_QTY
/select,"
OnActivate@
OnDeactivate
CostNavi|
tb_BdQty
Act_W2SMt
TwM_JajeXLS
JajeXLS
tb_Boq_
rGrd_Boq
CBoxSetHalMLSW
CBoxSetHal_NBUGAM
rGrd_BoqCellEnter
rGrd_BoqDblClick
rGrd_BoqDrawCell
rGrd_BoqExit
rGrd_BoqKeyDown
rGrd_BoqRowChange
MK_CONT_BOQ_
Conv Boq
ActNewBoq
ActMkBoq,
ActEditBoq<
mi_MkXLST
Act_CalBoq
Act_Mk_Boq10
Mk_Xls2Boq
mi_DefXls_GS
Mk_DefXls
tb_BoqXXP
ds_BoqXXT
RDbGrid_Boq\
mi_View_BOQp
sBtn_View_BOQt
Act_View_BOQ8
MkBoq
CopyBoq
ActEditBoqExecute
ActMkBoqExecute
Act_CalBoqExecute
Mk_DefXlsExecute
Mk_Xls2BoqExecute
RDbGrid_BoqDrawCell
Act_View_BOQExecute
POS_F_PRJLST
(STmate8x)\BOQ_INFO
MAMT3
LAMT3
SAMT3
TAMT3
qty1
BOQ.dbf
ST_Boq.CPM
Edit_Boq
.xls
ComP_CurBOQ
MK_BSCBOQ_EXL
BOQ.DBF
MK_EXL_BSCBOQ
BOQ_E.DBF
TAMT4
update
UhalX
lbTax_Email
ed_Tax_Email
VAT_C
VAT_C5
VAT_C10
VAT_C15
VAT_G
VAT_G5
VAT_G10
VAT_G15
TAX_EMAIL
#,#(VAT)
( Tax:
tb_PrjLst
img_Lst_PrjLst
List_PrjLst
:COSTN.DBF:
:COSTN.SMT:
:COSTA.DBF:
:BDQTY.DBF:
:PRJLST.DBF:
:PRJLST.SMT:
:SYSINFO.DBF:
PRJLST.SMT
:BOQ
.DBF:
COSTN.SMT
COSTN.NSX
COSTA.NSX
BDQTY.NSX
PRJLST.NSX
DOWN_LST.DBF
DOWN_LST.SMT
UPDATE
VAT_P
VAT_P5
VAT_P10
VAT_P15
VAT_S
VAT_S1
Act_PrjLst0
Act_Halt
tb_Mrg_COSTN
mi_Sel_Xls
mi_UseExcel
Act_PrjLstExecute
Act_HaltExecute
Act_Use_Xls_Execute
mi_Sel_XlsClick
ST_CPM\ST_Boq
ST_CPM\ST_P_XLS
ST_PLIST.DBF
SET_REP.DBF
QCODE.DBF
STmate-Exec_Merge_ADD_BOQ
MRG_COSTN.DBF
MRG_BDQTY.DBF
MRG_IMG.DBF
MRG_COSTA.DBF
MRG_QCODE.DBF
MRG_BOQ.DBF
MRG_COSTN.*
MRG_COSTA.*
MRG_BDQTY.*
MRG_BOQ.*
(STmate8x)\BOQ_INFO\
PRJ_DBF
PRJ_SMT
ST_PLIST.SMT
ST_PLIST_DBF
ST_PLIST_SMT
sAmTb
@System@@Halt0$qqrv
@System@@ROUND$qqrv
SetForegroundWindow
GetForegroundWindow
CreateHalftonePalette
@Forms@TCustomForm@WMActivate$qqrr20Messages@TWMActivate
@Forms@TScrollingWinControl@AdjustClientRect$qqrr11Types@TRect
@Classes@TBasicActionLink@Update$qqrv
@Classes@TStringList@Insert$qqrix17System@AnsiString
@Classes@TStringList@Delete$qqri
@Classes@TCollection@Delete$qqri
@Classes@TCollection@Update$qqrp23Classes@TCollectionItem
@Classes@TCollection@Insert$qqri
@Classes@TList@Insert$qqripv
@Classes@TList@Delete$qqri
@Math@RoundTo$qqrxdxzc
@Graphics@TCanvas@RoundRect$qqriiiiii
@Controls@TWinControl@Update$qqrv
@Controls@TWinControl@AdjustClientRect$qqrr11Types@TRect
@Controls@TControl@Update$qqrv
@Stdctrls@TCustomCombo@AdjustDropDown$qqrv
@Db@TDataSet@Insert$qqrv
@Comctrls@TListItem@Delete$qqrv
@Apodset@TApolloTable@Delete$qqrv
@Apodset@TApolloTable@DBFilter$qqrv
@Apodset@TApolloTable@DbfEncrypt$qqrv
@Apodset@TApolloTable@DbfDecrypt$qqrv
MROUNDUP
MROUNDUD
@Graphutil@ColorAdjustLuma$qqruiii
)JajeXLS
OnActivate
Delete selected tip
= 360,000 + 36,000(VAT)
wM_Dm_1.ds_BdQty
wM_Dm_1.ds_BdQty_X
QTY0
QTY5
QTY6
QTY7
QTY8
QTY9
wM_Dm_1.ds_CostA
Act_Ed_Qty
mi_HalL
mi_Ed_HalD
Rate.dbf
PADL(TRIM(PG_11),12," ")
PADL(TRIM(PG_21),12," ")
PADL(TRIM(PG_31),12," ")
PADL(TRIM(PG_41),12," ")
PADL(TRIM(PG_51),12," ")
PG_12
PADL(TRIM(PG_12),12," ")
PG_22
PADL(TRIM(PG_22),12," ")
PG_32
PADL(TRIM(PG_32),12," ")
PG_42
PADL(TRIM(PG_42),12," ")
PG_52
PADL(TRIM(PG_52),12," ")
gBx_Rate
Act_Set_Rate
o_Rate_L
GRASS.DBF
wM_Dm_2.ds_BdQty
LAMT4
MAMT4
SAMT4
wM_Dm_2.ds_BdQty_X
wM_JajeXLS
ed_EQCODE
STBSC
|*.STBSC
= 360,000 + 366,000(VAT)
= 396,000 + 36,000(VAT)
mBtn_EDBOQ
Color Halftone Settings
|Vat
Act_PrjLst
Excel
DataPathAlias
Delete|Erases the selection
&Select All|Selects the entire document
wM_Xls_Comp
BOQ_C
sBtn_View_BOQ
Act_View_BOQ
RDbGrid_Boq
ds_BoqXX
ActEditBoq
ActMkBoq
Act_CalBoq
mi_MkXLS
mi_View_BOQ
tb_BoqXX
BOQ11.NSX
Boq11.dbf
TWM_JAJEXLS
TWM_XLS_COMP
Select a Date
Dr. Halo images
*_표준시장.CSTA;*_실적.CSTA
실적(표준시장)단가목록|*_표준시장.CSTA;*_실적.CSTA
북측노무비(/월)= ROUNDDOWN(기준단가 *
북측노무비(/일)= ROUNDDOWN(북측노무비(/월) / 25, 4)
북측 = ROUNDDOWN(기준단가 * 북측노무비(/일) *
남측 = ROUNDDOWN(기준단가 *
SOFTWARE\경영정보(주)\설계예산(STmate8x)\BOQ_INFO
자재수량집계표양식.xls
SOFTWARE\경영정보(주)\설계예산(STmate8x)\BOQ_INFO\
@@ -0,0 +1,187 @@
path,bytes,sha256,extension,format,analysis_level,core,detail_summary
Apollo5D6.bpl,339456,4364f64c43032e1595ba45ec1c2bc1dade5d68d80a74e4bac6ec3858e68b42a4,.bpl,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 54, ""exports"": 1302}"
BANTAM.DLL,101376,01c8fac9f5f519dfd0314ee7eb70da64afc53bf82f7831a9c16add63fde0b729,.DLL,PE,internal_structure_extracted,False,"{""sections"": 6, ""imports"": 2, ""exports"": 43}"
BDERTL60.BPL,222208,b56d3e643fb1eef7018aa120ddab53ae0402ef997e1441a1ad7ff4ce25f79658,.BPL,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 25, ""exports"": 1036}"
BORLNDMM.DLL,22016,e7b3218d1ef0d16fe29674144dc2f887f281687476b5ba4625cbdd680c22a92a,.DLL,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 6, ""exports"": 12}"
CHARSET.CVB,144454,07cd1afc401f3ec6c913f319813810839f9f20123506b28381e179bf921f6b0c,.CVB,BTCV,internal_structure_extracted,False,"{""header"": ""BTCV##BaseCV\u0000\u0000\u0000\u0000\u0000\u0002\f\u0000\u0000\u0000\u0000\u0000\u0000 \u0003\u0000A""}"
CPMARC.CPM,132096,17d182e5d20dc1e4767d7e5e122566cbaa7e462eaadcf558de87c039f412a38a,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 3, ""exports"": 4}"
CPMUNA.CPM,117760,decb3ca906c76a44b2417b998d7abb07b7a39d17969b37831d819039326ee654,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 3, ""exports"": 4}"
DBRTL60.BPL,254464,6f7d8767276c74fbf80fce4df1e6e9fd470d80e37e7bc6f51095509af3054379,.BPL,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 16, ""exports"": 1314}"
Dclhrp60.bpl,418816,6d96304c04aa11e9dae0163e99bbd0abe2a9dd4dd665aa8d201f7afb7b891ae7,.bpl,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 75, ""exports"": 1333}"
DELPHIMM.DLL,9216,7030bfa308e4b0916349bab32d7783e76f2d5c48dc36e7eda3535d80b3e540e7,.DLL,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 5, ""exports"": 10}"
designide60.bpl,701440,80df9d758d68e5d9e6b0536e102eb6e7744f70cfa95b9306694b93e1a55272a4,.bpl,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 58, ""exports"": 2837}"
DP_Common.CPM,436736,5f55d301c6b2139816ff8832e46becb852c4f0a0c9b5da199371156b6aaf30e0,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 15, ""exports"": 73}"
DP_MinMsg.CPM,82432,2059455faa4f92a8897754494a1e28daa9ecce42c3d79c6c9ac02c58dc631de7,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 51, ""exports"": 3}"
EQSYNC.DBF,2938,3d7dd1d1d1e5d015aaf2d60628368e65251a1a3a2f6c8f8c449b5566e472391f,.DBF,DBF-like,internal_structure_extracted,False,"{""version"": ""0xE6"", ""records"": 54, ""header_len"": 129, ""record_len"": 52}"
EQSYNC.SMT,12311,2537657ec0c036501afb7a9c98c4ef17024b578d537ec0cb59958c5d8c3f4248,.SMT,SIxMemo,internal_structure_extracted,False,"{""block_size"": 64, ""first_value"": 193}"
FAREAST.BTL,517810,27dc4e384c01d6fcadaa90973b018adb6f11be28750d2b97e831215ef22b72f5,.BTL,BTLF,internal_structure_extracted,False,"{""header"": ""BTLF01.001\u0000Chinese_TW:dBASE:ANSI""}"
FTS32.DLL,43520,05e98046789d7508b18dfcbe14c3724c49f06eb22688675e3646d9d790966b1d,.DLL,PE,internal_structure_extracted,False,"{""sections"": 5, ""imports"": 1, ""exports"": 16}"
HRRES32.DLL,19456,4a7d8f8a58e0f82d8a5be2336a79e63a5aa42f6f32a82863c9c957513b25cc26,.DLL,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 5, ""exports"": 1}"
IDAPI32.DLL,589312,fc2faec98fd7167cf7d25fa773ec8ecead0dfc678ca1ffaf6b34f78bac91a91e,.DLL,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 6, ""exports"": 754}"
IDDBAS32.DLL,454144,9955fcc1e214b15dce432a61d489d2de758169a70306d92a27f1c20ea6b45025,.DLL,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 4, ""exports"": 67}"
IDPDX32.DLL,255488,516741a7d632a458e1746137b184a1b050395e974c6b428fca1524ea3a166c6f,.DLL,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 3, ""exports"": 15}"
IDR20009.DLL,116736,b41e0f4c1b63d66f68c6e193742287d0481645fb1c7b95f6858b32435648b360,.DLL,PE,internal_structure_extracted,False,"{""sections"": 6, ""imports"": 2, ""exports"": 4}"
JDLCHK.Size.dll,1206784,da4d1755947d88336f81d1a6c5766a8df0fee71664e6485399cc3ac9bac8e5de,.dll,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 17, ""exports"": 4}"
JDLCHK.Tab.dll,1214976,d8e5d9733b14e18695a1f30ceb2aca7fe14894a040e068ed4a37490a26d105ae,.dll,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 15, ""exports"": 4}"
JDLCHK.Tab_33.dll,1229824,c5052736204cd4b956a3f59a6f7d41b36e298258846ce64fd7231407db8dd43f,.dll,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 15, ""exports"": 4}"
MINIEXTR.DLL,40960,4edc83a1b2d5037820e4ec66b6f172082aa663636b8f9c343dba79e6fb3ce935,.DLL,PE,internal_structure_extracted,False,"{""sections"": 5, ""imports"": 2, ""exports"": 13}"
RAR.EXE,185212,fe079b67547706ce650f2755b16d9f7efb01a1e5ea07ba464bfe585ae9846003,.EXE,DOS-MZ,internal_structure_extracted,False,"{""magic"": ""4d5a7c016a01990840033903ffff282d""}"
RealGrid6.bpl,402944,d1efca11ace3f581e7f4f5408afef2b29d77ce5a4aeb73bc1fa2a94548832ea8,.bpl,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 55, ""exports"": 1630}"
RealGridDB6.bpl,111104,c4963618fdcea616b208d2f4891f870e91494e270db36becebfc66466e492d3b,.bpl,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 72, ""exports"": 272}"
RealGridEX6.bpl,71680,c8f5ec65c1e2af4f0a818e14d791e267b5e47d8d87cf491ecf17e346661aa231,.bpl,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 59, ""exports"": 142}"
RTL60.BPL,685056,aa4a46b7921f225910414422ec7ff5533cd5fad87e2fe2cca248f25eb9899480,.BPL,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 16, ""exports"": 4698}"
SDE32.DLL,132096,b23ef38c5099fc74ffd1b5c72c5684e5cc64d598114637dd1bf2462222121260,.DLL,PE,internal_structure_extracted,False,"{""sections"": 6, ""imports"": 2, ""exports"": 179}"
SDE50.DLL,155648,3a8748c8823f2c2a7fd179d9ba045c9afd13734e06fa8450a74a8e509b2450fc,.DLL,PE,internal_structure_extracted,False,"{""sections"": 5, ""imports"": 2, ""exports"": 179}"
SDECDX50.DLL,274502,2f09909441d8e4f0bb93463f5a7d6f28db329cc1f5f43e6dbbcbf229dacb1bbf,.DLL,PE,internal_structure_extracted,False,"{""sections"": 5, ""imports"": 3, ""exports"": 81}"
SDENSX50.DLL,266240,6e0a5b4967a6d0cc6faee9b471659419540872d9703700fe60a0dc3045ba024c,.DLL,PE,internal_structure_extracted,False,"{""sections"": 5, ""imports"": 3, ""exports"": 81}"
SDENTX50.DLL,258118,a1d5fccff1b5249de5000de1b548216d8c165b1a6f6162cf9f465f1a2a6cb31e,.DLL,PE,internal_structure_extracted,False,"{""sections"": 5, ""imports"": 3, ""exports"": 81}"
ST_BdSN.CPM,122368,9b7320455bc15f5412f9dd11b40fee13fab44780990c4389c2c5f6beb5f6a395,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 118, ""exports"": 3}"
ST_BSC\2007_제비율.JB_M,3379,7139579616921b4e8ac6055d497722b64a2cb048c353861858a179dfa277fc7e,.JB_M,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 25, ""header_len"": 353, ""record_len"": 121}"
ST_BSC\2011(상_0112)_제비율.JB_1,5315,cc5f14790cc4f185f44b0b3e3f5be6c78e52df6a373903f14fcb99134c9b4551,.JB_1,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 41, ""header_len"": 353, ""record_len"": 121}"
"ST_BSC\2015(상_0301,실적)_제비율.JB_RA",12724,ba85cf902cf1846bcc38583c5f8173046404dc804cfa9b21a3a35a95991335e4,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2015(상_0309)_제비율.JB_R,12724,236ffcc157269a8438aac9993f18e4f6d699e4493e692fada8a16102cd68407c,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
"ST_BSC\2016(상_0301,실적)_제비율.JB_RA",12724,a34469eb1b823dc33e10d96985c7fed44428b93b90c53491edc219cb4b3d677d,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2016(상_0307)_제비율.JB_R,12724,b2e87dc37da04744197040ecd863b1b38563ad63ac975b77f3126bf412d13c97,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2017(상_0215)_제비율.JB_R,12724,dab9bf2fb5e62c41c65e9a01dbc6c7e08f06ff8d14a0d5ec90e24f2134c8e61a,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2018(상_0327)_제비율.JB_R,12724,6ec8ef38aaf747e54117451cb0e5ebcb6b4bbb084bc824163a5dc465ed23d8b3,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
"ST_BSC\2018(하_0701,표준시장)_제비율.JB_RA",12724,e771db1af3a0d4725289f5b01b97fbd4982eb5b89776c6130d87b9127857dbe8,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2018(하_0801)_제비율.JB_R,12724,608a7a9b61884dd8ee3557078db32ab94ad9b6e88341c010ce14643327171e4a,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
"ST_BSC\2019(상_0101,표준시장)_제비율.JB_RA",12724,e771db1af3a0d4725289f5b01b97fbd4982eb5b89776c6130d87b9127857dbe8,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2019(상_0107)_제비율.JB_R,12724,1462a445d32cea9d9a054bd3d114b66bdbc5693f1e464771deecd9797ac373fa,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2019(상_0417)_제비율.JB_R,12724,1c42ea998ca321ac9f8c19bc54736360ee38b8c7f4153e8a94e6c02892c42014,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2019(상_0628)_제비율.JB_R,12724,0401a772ef13213c8f49c8ff4f40b1f3b1960e87868b229a4119750829d51a85,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2020(상_0102)_제비율.JB_R,12724,e0069fa4687aabf12f0466a21bc80d064de4d0a391561cfe2cad47e4bb893680,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
"ST_BSC\2020(상_0102,표준시장)_제비율.JB_RA",12724,49610b1853c84922fc47092d32d01a1ab65844eecf95dfeaff48ac4db56b42a0,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2020(상_0527)_제비율.JB_R,22204,aa722b3c970616b2f402719baa199009cdbf7185f6e2ab04c1cbe48fc92dc508,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
ST_BSC\2021(상_0104)_제비율.JB_R,22204,b43e44c96edb0be4c3b50f46c015ed39eb87995f749f055b165d104d97c75b49,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
ST_BSC\2021(상_0421)_제비율.JB_R,22204,c267385aa0d65e4339223ee7d965e44f2bb7e6c351a4689e09ed3071e3d3565d,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
ST_BSC\2021(상_0520)_제비율.JB_R,22204,bbb678008ba42ac8e99ab874884c6219a41c8d474ec4497813b9887edcea0d28,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
"ST_BSC\2021(하_0501,표준시장)_제비율.JB_RA",12724,b0d7975bb563191dfe2f765d30ccf9083feb9b7ff6cac45198499db86bd9b427,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2021(하_0701)_제비율.JB_R,22204,f73382e53a575ccd88222f18323caad6c24d6c1002567e55d11f3a6ac4c45847,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
ST_BSC\2022(상_0103)_제비율.JB_R,22204,45d132ad0de6fdd3b41f63743fadcf4ba4bb1db633ab773af850bc4a2c6cbd62,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
"ST_BSC\2022(상_0103,표준시장)_제비율.JB_RA",12724,b0d7975bb563191dfe2f765d30ccf9083feb9b7ff6cac45198499db86bd9b427,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2022(상_0425)_제비율.JB_R,22204,82d7fdab0dbc6162d0fec4e0e99feb27d20d50031d1ff13ac0d6ce056db09977,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
"ST_BSC\2022(하_0501,표준시장)_제비율.JB_RA",12724,95220f1fb9b4169143f9d0fe88cfc6f83dead1c4f464467003cd0ca755da7265,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2023(상_0102)_제비율.JB_R,22204,1aa1fca4090dc67e28c2820dead8b82daf50a73a20ff82dd1905040bb58f71b0,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
"ST_BSC\2023(상_0102,표준시장)_제비율.JB_RA",12724,95220f1fb9b4169143f9d0fe88cfc6f83dead1c4f464467003cd0ca755da7265,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2023(상_0428)_제비율.JB_R,22204,2cf8869231d0a4b9dede802b6a5d3363e3e956db147c0c851370b06e4af9190f,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
ST_BSC\2024(상_0101)_제비율.JB_R,22204,e594487cc11755b486cf4bfe3b5876107ec044458313f5989f32e0713681bcac,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
"ST_BSC\2024(상_0101,표준시장)_제비율.JB_RA",12724,39af7fa4ebc6a1d12e32cb298538bb24c6658a65249cec57541440044fe46191,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2024(상_0315)_제비율.JB_R,22204,4ed224783fb0d72c66d7c3def6c983f33129011782600d7d78a18cb46ee87a97,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
ST_BSC\2025(상_0101)_제비율.JB_R,22204,196ecc70fa0b3f1b17ed8f2d5ce5b0339ef92bd3e06dde625c87759707a0f2e4,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
"ST_BSC\2025(상_0101,표준시장)_제비율.JB_RA",12724,49542b8fe77b734c6eefd5d4673a1841f00bcdde8205fc71b6289d1ea05c289b,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2025(상_0401)_제비율.JB_R,22204,dc678b3617b203fa88d6fffcb5e0e04a827da5c31545405a1d1c27c72e200839,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
ST_BSC\2025(상_0501)_제비율.JB_R,22204,3f978a6793fc131afc10e614dca9bc84b2064ab9faae71d29fee3a1b79440106,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
"ST_BSC\2025(하_0501,표준시장)_제비율.JB_RA",12724,5f07b35b604129203be578323e260fd37a76ac90bd593a450ed728e407aac7c8,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2025(하_0809)_제비율.JB_R,22204,1463341b3da28f5ae7e24446c3003e9cfdc2177cf9962807f86c0ff14805f090,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
ST_BSC\2026(상_0101)_제비율.JB_R,22204,6fa9bb61555a54f2e6ee95583d76e0c5ab818534b6181783b24a5ed4fb3422e2,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
"ST_BSC\2026(상_0101,표준시장)_제비율.JB_RA",12724,5f07b35b604129203be578323e260fd37a76ac90bd593a450ed728e407aac7c8,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\2026(상_0313)_제비율.JB_R,22204,af27255d84bc9cbdc1dc9ba6ea823d9649fd5f69f4121bba14864113917422d4,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
ST_BSC\2026(상_0413)_제비율.JB_R,22204,19b3fdea3aa891d3e7d37b89c43e7e57fe85dbf39f30c42a9d407f34475f7901,.JB_R,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 1153, ""record_len"": 421}"
"ST_BSC\2026(하_0508,표준시장)_제비율.JB_RA",12724,68778043bc15e24688d17ad8fc3fa775e61291897038b4a6e2824897314bc08f,.JB_RA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x03"", ""records"": 50, ""header_len"": 673, ""record_len"": 241}"
ST_BSC\GRPCOD_E.BSC,340484,2ab6eb0215184f6c442702f94cd82934acef43bc8b398e8227cee58e56cbe9c0,.BSC,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 2539, ""header_len"": 257, ""record_len"": 134}"
ST_BSC\GRPCOD_Z.BSC,1625008,b6c58c548256fdf3d7be2780d0a4b8b23b34d85ba61c8899e5ab38f8e35eaa2c,.BSC,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 12125, ""header_len"": 257, ""record_len"": 134}"
ST_BSC\JDCODE_L.BSC,156358,d967e15b87c6a2168251977119fe8263898bce84e3ef545eb09c78bdf6e465fd,.BSC,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 460, ""header_len"": 417, ""record_len"": 339}"
ST_BSC\JDCODE_M.BSC,19520038,69073533ba84c01bd58ec4ea7cfddbd427e61ee62142a8654284d2bf6db272c7,.BSC,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 57580, ""header_len"": 417, ""record_len"": 339}"
ST_BSC\JDCODE_S.BSC,288907,39a3e525399a842e0df1e27e8f2a76683db42e5c1fefa20c61eb3c74494f4df0,.BSC,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 851, ""header_len"": 417, ""record_len"": 339}"
ST_BSC\JDCODE_X.BSC,282805,6304d8e0bb717efaaed72e9626a688cb4a955866a113b5a9c3e1a4d19bee9163,.BSC,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 833, ""header_len"": 417, ""record_len"": 339}"
ST_BSC\JDCODE_Z.BSC,11501671,decbd6a76ebe98751020f78b74b190970cdeba834316409ebe9db3c3fb7cd10e,.BSC,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 33927, ""header_len"": 417, ""record_len"": 339}"
ST_BSC\Valid_Xml.vsl,58807,84f2e2a950139d00fbc96540b24d8883f5a733ba419c3369f8ecbed9f04b6290,.vsl,text,internal_structure_extracted,False,"{""encoding"": ""utf-8"", ""lines"": 1429}"
"ST_BSC\노임기계\2025(상_노임,기계경비).STBSC",103229,fc6f62bcff5ce69d83d50af61a7f7d415e17a2e0ec10f3321ae4fd8445fd513c,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""MEM.ST"", ""XDET.ST""]}"
"ST_BSC\노임기계\2025(하_노임,기계경비).STBSC",103027,c99902383b569c5941c6bafe6707a0358beb9f81ec19c2dd486d96ea7a152025,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""MEM.ST"", ""XDET.ST""]}"
"ST_BSC\노임기계\2026(상_노임,기계경비).STBSC",104166,74f886bb8cc1ae69e69fe1d92845d23e60c35ff0f06f75631368112a4ca3f1c3,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""MEM.ST"", ""XDET.ST""]}"
"ST_BSC\노임기계\2026(하_노임,기계경비).STBSC",104284,48d7196fed12d887a94a2e391f98b212af7aa9040a8e51555bfdf895869c94bc,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""MEM.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2025\2025(상,국교,해수부,조달청)_표준시장.CSTA",2427111,5c8d0d7bf9e9208e72e6acaafdf8544f88b972a46b7f74ec3b32acc0a3d458af,.CSTA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 4921, ""header_len"": 1057, ""record_len"": 493}"
"ST_BSC\실적단가\2025\2025(상_시장시공,조달청).STBSC",24865,79e534e050664f0248732c9923d9b131a52340bbe4a93c79730d17c285b0e367,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2025\2025(상_표준시장,조달청).STBSC",234037,fa4e340e60845f38a3bfe44966e3415690da9e9eaa0a236d057ff4986a065694,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2025\2025(상_표준시장[노임외 경비적용],국교,해수부).STBSC",168543,432f365195096b67a21f5ba2b804cde79fe24534697294e091858a17cf23bdc6,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2025\2025(상_표준시장[노임외 재료비적용],국교,해수부).STBSC",167083,a66c9af574fba4a6a5d43bfb04de42c0c4b941091a1b2aba1ab2d659e4503f19,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2025\2025(하,국교,해수부,조달청)_표준시장.CSTA",2427111,68cba31f353bfb2c78909a9633e96b8581276d21044ceecce21399f26fd030a4,.CSTA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 4921, ""header_len"": 1057, ""record_len"": 493}"
"ST_BSC\실적단가\2025\2025(하_시장시공,조달청).STBSC",25501,e1fb2b89d26cb19ee88ffa5b40a8401cedcc651de4b80f11b4520db88248cad2,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2025\2025(하_표준시장,조달청).STBSC",234106,ca134e164233b9477ce9d34da9d8f36db902c693ce36e4325bc2319daea17cf2,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2025\2025(하_표준시장[노임외 경비적용],국교,해수부).STBSC",168600,e2a4669ccf5ff3ede5457b1d00a463263303ce2467361d5dd4d5ff10983ab596,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2025\2025(하_표준시장[노임외 재료비적용],국교,해수부).STBSC",167122,cb139c7278f120a6aa6dcc3e1dde9bb5d0b67b8fd62aa728797e6a3d50c3dd0b,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
ST_BSC\실적단가\2025\COSTA.CSTA,2427111,68cba31f353bfb2c78909a9633e96b8581276d21044ceecce21399f26fd030a4,.CSTA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 4921, ""header_len"": 1057, ""record_len"": 493}"
ST_BSC\실적단가\2025\표준시장단가(2025_04_21).Info,206,d4a1fd8bb95b8715a423748f2ccfb516807cdace287a039d3a5a71ba148c805a,.Info,DBF-like,internal_structure_extracted,False,"{""version"": ""0x32"", ""records"": 3139494579, ""header_len"": 47603, ""record_len"": 45533}"
ST_BSC\실적단가\2025\표준시장단가(2025_08_04).Info,342,4b31c62515d0692aaee658adc19cb36cdc3e8963251154401918e7aa0c5b7f64,.Info,DBF-like,internal_structure_extracted,False,"{""version"": ""0x32"", ""records"": 3340821171, ""header_len"": 47567, ""record_len"": 45533}"
"ST_BSC\실적단가\2026\2026(상,국교,해수부,조달청)_표준시장.CSTA",2446831,3cf6ff7b7acb709a9faee154fbe2dbcfc718c6112e317d98868ac493dae666d5,.CSTA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 4961, ""header_len"": 1057, ""record_len"": 493}"
"ST_BSC\실적단가\2026\2026(상_시장시공,조달청).STBSC",25187,303abd1b10ef21a8c7e30f2af9845400346ff82f0f25bf7f9beb6277b43f696c,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2026\2026(상_표준시장,조달청).STBSC",236533,7f85e77265679b46807b2b22311b1fa07ffee463c50db67d6426ad38b5773f07,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2026\2026(상_표준시장[노임외 경비적용],국교,해수부).STBSC",170135,4f09af8780b54dcaeb1da7d268ac7cab253298c8402e15790749bf50ac47f482,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2026\2026(상_표준시장[노임외 재료비적용],국교,해수부).STBSC",168661,19c589ee1b564aa7593e87e556b0ab1855a7291ef0cf894df29a36a1e78170e2,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2026\2026(하,국교,해수부,조달청)_표준시장.CSTA",2446831,a5b26c95d44c47dc7dd7f5997a2e6be68edb1436003fc914fd1402588d68edfc,.CSTA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 4961, ""header_len"": 1057, ""record_len"": 493}"
"ST_BSC\실적단가\2026\2026(하_표준시장,조달청).STBSC",236961,cd3394de4e0ab08b6bab3c0db8cb5d439983ddaece5df5016243b0c32d6bece7,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2026\2026(하_표준시장[노임외 경비적용],국교,해수부).STBSC",170373,dfe6e5a1c922cad51fa49ad3682292857450f0bff5f84f7fa2762a61685aed44,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
"ST_BSC\실적단가\2026\2026(하_표준시장[노임외 재료비적용],국교,해수부).STBSC",168877,fffae2c8fd2ef78af32da16711dba26e952fc0858d25b73e643d2379e66174ad,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 4, ""encrypted"": 4, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""XDET.ST""]}"
ST_BSC\실적단가\2026\COSTA.CSTA,2446831,a5b26c95d44c47dc7dd7f5997a2e6be68edb1436003fc914fd1402588d68edfc,.CSTA,DBF-like,internal_structure_extracted,False,"{""version"": ""0x06"", ""records"": 4961, ""header_len"": 1057, ""record_len"": 493}"
ST_BSC\실적단가\2026\표준시장단가(2026_05_04).Info,224,64934740ee03e4f01fe112ec1ae9cddc01497da48b515f6cdbbb82487c7c75a7,.Info,DBF-like,internal_structure_extracted,False,"{""version"": ""0x32"", ""records"": 3139494579, ""header_len"": 47603, ""record_len"": 45533}"
ST_BSC\실적단가\2026\표준시장단가(2026_05_27).Info,206,207506f87c9c3da5ec86b8e16efab8a4f35570b0cb8934d7443c82502c5803e9,.Info,DBF-like,internal_structure_extracted,False,"{""version"": ""0x32"", ""records"": 3340821171, ""header_len"": 47567, ""record_len"": 45533}"
ST_BSC\일위대가\2026\2026(상_표준일위대가_건축).STBSC,107988,10c39a2e5d1e797b7d9f82f9ff1d099d74ad83a84e9a9c936e192bdbf4744f5a,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""MEM.ST"", ""XDET.ST""]}"
ST_BSC\일위대가\2026\2026(상_표준일위대가_기계설비).STBSC,142723,ef64cde3312b77e99e3f0f9565bfcf8dc6e747a9a4b414d8921f2499a65d6663,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""MEM.ST"", ""XDET.ST""]}"
ST_BSC\일위대가\2026\2026(상_표준일위대가_전기).STBSC,22104,08c88f23a731e05bd6c926e0686ed1565c3900318f2df5779db92b762e026614,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""MEM.ST"", ""XDET.ST""]}"
ST_BSC\일위대가\2026\2026(상_표준일위대가_토목).STBSC,199599,42b6bbad12827b3a68991ee59a78d4a81d43928433043a2b025a77169abe4830,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""MEM.ST"", ""XDET.ST""]}"
ST_BSC\일위대가\2026\2026(상_표준일위대가_통신).STBSC,52561,9bf846f887815e228f4122ca3b9dd6de4b6cd6b26b6f3e647dc7ad8055fc9352,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""MEM.ST"", ""XDET.ST""]}"
ST_BSC\일위대가\2026\표준일위대가(2026_03_17).Info,542,84b673e857218323d8eabb7a6cce309979a6bd65490a6311382f9f2af275b3db,.Info,text,internal_structure_extracted,False,"{""encoding"": ""cp949"", ""lines"": 11}"
ST_BSC\자재단가\시설공통자재\2025-상-시설공통자재.STBSC,184968,7ac21732736a8b83d732f21797dc1434a4376319cea1f8777f86fc37f209593a,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""info.ST"", ""XDET.ST"", ""Start.ST"", ""COST.ST"", ""CH_NAME.ST""]}"
ST_BSC\자재단가\시설공통자재\2025-하-시설공통자재.STBSC,178357,f7f7f884e7d0cfd83be9fd618c99d540c83ca621f26df1d1fa8db6de82afd4c1,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""Start.ST"", ""XDET.ST""]}"
ST_BSC\자재단가\시설공통자재\2026-상(06)-시설공통자재.STBSC,177153,cfcc27abb1759a916983b51737361c348d277ed540b18188da9976fe56cef034,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""Start.ST"", ""XDET.ST""]}"
ST_BSC\자재단가\시설공통자재\2026-상-시설공통자재.STBSC,176293,926f18edcf6390f34391bd9a26a6bf589d5e6b8e10128498a2cdb50341a70185,.STBSC,ZIP,internal_structure_extracted,False,"{""entries"": 5, ""encrypted"": 5, ""names"": [""CH_NAME.ST"", ""COST.ST"", ""info.ST"", ""Start.ST"", ""XDET.ST""]}"
ST_BSC\호환규정코드(2026_09_01),108,7f12adccd919919ef7739f3efce9439e1f183989980c8daeb170bb1e65fdcade,,text,internal_structure_extracted,False,"{""encoding"": ""cp949"", ""lines"": 3}"
ST_Com_V.CPM,648192,d66b620110244d0814513fb18fa3fca6611ad57ffa300e193c0b85af59b2f574,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 17, ""exports"": 10}"
ST_CPM\ST_Boq.CPM,2119168,180707d0423dd2dcb8403d89ba1dbaf2731c0db5c6bb332029479fd9d9923ab3,.CPM,PE,internal_structure_extracted,True,"{""sections"": 7, ""imports"": 132, ""exports"": 4}"
ST_CPM\ST_EdiLWi.CPM,508928,9e83c2a450d31353953361c8bb460bae700cc76927605145a0ae406ca31702ca,.CPM,PE,internal_structure_extracted,True,"{""sections"": 7, ""imports"": 128, ""exports"": 2}"
ST_CPM\ST_EdSan.CPM,628224,101d1f31adff9d46d30a46135ccd6398af41fcee9b2434a91dae5ee466e13753,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 128, ""exports"": 3}"
ST_CPM\ST_FindUse.CPM,436224,c0c2b770e805cfcb78ef091a4657185160f58408434dab09cbef20d982d59a9e,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 125, ""exports"": 3}"
ST_CPM\ST_Jabpum.CPM,411136,d960f6e6b5ffa395c201eabf126cb4dcf8dbe026c2afaa804a7bfa6429164f51,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 126, ""exports"": 6}"
ST_CPM\ST_KanJub.CPM,1718272,ef8d55b259b37916496e80cab6a4a2ba46216e0bd7c5199083dbda632bd50d03,.CPM,PE,internal_structure_extracted,True,"{""sections"": 7, ""imports"": 131, ""exports"": 5}"
ST_CPM\ST_P_Collect.CPM,570880,fd1b468d77398a72705537e28321c93a3736fbc1ea384997659eea2fe9b71737,.CPM,PE,internal_structure_extracted,True,"{""sections"": 7, ""imports"": 125, ""exports"": 5}"
ST_CPM\ST_P_ConEst.CPM,735744,027c72cc019e46fdec78e6aebc68b621aa77c7fc1ac88362f04675f6dab69fab,.CPM,PE,internal_structure_extracted,True,"{""sections"": 7, ""imports"": 125, ""exports"": 9}"
ST_CPM\ST_P_Excav.CPM,809472,62ea015c8fcb05c351d394a8bdb3214ea516d099fb986c25a7503358160fb0d0,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 125, ""exports"": 15}"
ST_CPM\ST_P_iLWi.CPM,634880,1308680f806f9e0298f99ce68d08c5c3e80eb5d7e8cf86fb7a89d7678539ae32,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 125, ""exports"": 3}"
ST_CPM\ST_P_Joong.CPM,797696,30c28a8ace160c06fa79948ea20678504aaeae2d20304daff719300e5f919ee7,.CPM,PE,internal_structure_extracted,True,"{""sections"": 7, ""imports"": 125, ""exports"": 7}"
ST_CPM\ST_P_List.CPM,631808,e14d17b10ee1f82f5abc0f7c90f1b658516f9623452fe092450396eae9deb071,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 125, ""exports"": 11}"
ST_CPM\ST_P_Nae.CPM,1398272,9ecb6a663c988f249548a06a6c7da66abc71d8c245baba141450c329391f1c47,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 125, ""exports"": 30}"
ST_CPM\ST_P_San.CPM,570368,5d364a818883fd6f69839dd08c7e3243e0545fd23062454f5816b3cc0bae941c,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 125, ""exports"": 3}"
ST_CPM\ST_P_XLS.CPM,2314752,1d3f7ed8702ee9e4ea2309126028f3600497617c576c1b91659b0c8c60083da0,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 127, ""exports"": 72}"
ST_CPM\ST_PList.CPM,1586176,638c8167ff5817f454633c9270b9b01b2ef72044339c58bd8d5190b1a8e4766c,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 143, ""exports"": 3}"
ST_CPM\ST_Prt.CPM,1170432,0698a6343ba04a5b379f297da60e68a9fc3f18d5ac0ad262570f70ca98dd3c19,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 130, ""exports"": 4}"
ST_CPM\ST_SanCal.CPM,270336,153967ee6429ba40285939af68a9b2b02daae9888e95440e95dc017acdf0ad54,.CPM,PE,internal_structure_extracted,True,"{""sections"": 7, ""imports"": 120, ""exports"": 2}"
ST_CPM\ST_Sys.CPM,566784,e55845df186ecb2d0ea6de4408b299529cd0d697030da8c114a0a48b3ce0a81d,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 126, ""exports"": 2}"
ST_CPM\ST_U_ADL.CPM,189952,833af9af1263205f3e0e04162079114d451e6136c2e5271776f63532e19a4031,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 48, ""exports"": 6}"
ST_CPM\ST_U_Archive.CPM,473088,1d00333bca0277a3355826419d11c57996852ec9013b7bb508d16ac9ec6ed553,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 125, ""exports"": 16}"
ST_CPM\ST_U_ChgAmt.CPM,130560,37ca3715c216f68274eabd3dd944bcd7922404bd2721b1ba0b73c428e843e3d8,.CPM,PE,internal_structure_extracted,True,"{""sections"": 7, ""imports"": 120, ""exports"": 2}"
ST_CPM\ST_U_ChgCode.CPM,656896,6fe80a7a21e1458852e940bb1efdf3eee618ae23d0090a4e7323c908efb9257d,.CPM,PE,internal_structure_extracted,True,"{""sections"": 7, ""imports"": 124, ""exports"": 10}"
ST_CPM\ST_U_ConBD.CPM,196608,fb0351c1fa96be282b8da6be31ba97673e626e1a5d8e30acb83831f4c72e5d6e,.CPM,PE,internal_structure_extracted,True,"{""sections"": 7, ""imports"": 121, ""exports"": 4}"
ST_CPM\ST_U_Convert.CPM,1825792,0166beb69d2692732eb3d5e897201a96aa1b2955026a67aa53989ffa28431649,.CPM,PE,internal_structure_extracted,True,"{""sections"": 7, ""imports"": 133, ""exports"": 20}"
ST_CPM\ST_U_DelCode.CPM,544768,30cc2e234a67fd2adeb51629b00b3d3d60e2fa2026b1f0b1ff9af958a1b38f9c,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 123, ""exports"": 6}"
ST_CPM\ST_U_DelPrj.CPM,161280,2e47370f7ad85542f375f03e6b3a0aaf88252750d8f6ad1ce631ea02125c2a3d,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 121, ""exports"": 3}"
ST_CPM\ST_U_Indx.CPM,137728,cbe19214915433afe71b856c3f82a7eb4c106ea40df72cb726eb8fcf8e73f2c9,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 124, ""exports"": 2}"
ST_CPM\ST_U_Merge.CPM,718848,350085f3a498628703ec66486bfc4994683169fdf0c4f8e8cc7f9c842b81271a,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 124, ""exports"": 2}"
ST_CPM\STmateQty8.CPM,224768,f92ec517ff931328dac76154a1fedcee8e9cca5ffb64fddfc207af3887c19b37,.CPM,PE,internal_structure_extracted,True,"{""sections"": 7, ""imports"": 124, ""exports"": 4}"
ST_Func_C.CPM,657920,f2d4b2f6ebda2d57e47d343907071400cdb4b9f01fa5cc7756f34eb5f94e2ca6,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 19, ""exports"": 7}"
ST_JD_Lst.CPM,143370,64d6d0dd7629249dc2f3fbdcd7372a9e09a8422fe2ede94ea59a8fedd25f3497,.CPM,text,internal_structure_extracted,False,"{""encoding"": ""cp949"", ""lines"": 26}"
ST_log\ST_log.stlog,149,298b9c72ce903c0a06241dc04bd2f5cca0c525ae2822b09cdeccdda36f9df932,.stlog,obfuscated-log,internal_structure_extracted,False,"{""bytes"": 149}"
ST_Merge_Code.CPM,656896,c3bcc5851d680da5dc69e04b4d9e389baf36c45dc1c2203c5b88e039e6d56c63,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 133, ""exports"": 1}"
ST_Tips.dat,1636,f7de77c90911587bf98c2a75c58d6484bbc166d49b306feb04e895fdc93f4d6a,.dat,tips-data,internal_structure_extracted,False,"{""utf8_html"": true, ""bytes"": 1636}"
ST_U_APatch.CPM,172032,50b79f7c127ec681db22d2cff6814314c143eca73cc473f01d26c71197fb6ed5,.CPM,PE,internal_structure_extracted,False,"{""sections"": 6, ""imports"": 49, ""exports"": 0}"
ST_V_Info.CPM,49,671f6214ec519d846e5b489ffbd37d1a6036945a46169ae1d6294319eba10ce0,.CPM,text,internal_structure_extracted,False,"{""encoding"": ""utf-8"", ""lines"": 3}"
ST_Viewer.exe,1329664,2eeee446f9563a6d64e7a415f7f0373262132f7adfc672ac9b8b108a6e069df9,.exe,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 21, ""exports"": 0}"
ST_VSetup.EXE,1788882,d9e04e9fa0d7886c868d122a20a2143ac913f2ced8fec1c5127ca9fd38a14b81,.EXE,PE,internal_structure_extracted,False,"{""sections"": 4, ""imports"": 4, ""exports"": 2}"
ST_Wal.CPM,325632,da56d1a27a664b0ff7b6af60c8b891bd7c831ffdede9b104ee05d33cad80e82d,.CPM,PE,internal_structure_extracted,False,"{""sections"": 6, ""imports"": 121, ""exports"": 0}"
Stma.URL,48,de22235fba718eff232f134680d246ce485ff5e80178e7f654a1eb605878ce87,.URL,text,internal_structure_extracted,False,"{""encoding"": ""utf-8"", ""lines"": 2}"
STmate.Cpm,3525632,99d5c05675ba1399c51a71db8e26ebd5ff39fd78d02360147c7705deb399b5f5,.Cpm,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 144, ""exports"": 1}"
STmate8.Exe,145408,ee029ac9acf684e894a2ea4743a37288755439391f36107565f4aa87f3499b06,.Exe,PE,internal_structure_extracted,False,"{""sections"": 6, ""imports"": 52, ""exports"": 0}"
STmate_Ins.log,15958,9dd9f8e827f64c593afd6b9d15fe041a8d1139c61c189f02e70ed693c122efc3,.log,text,internal_structure_extracted,False,"{""encoding"": ""cp949"", ""lines"": 288}"
STmexe.Cpm,96256,5ff4005a52c8f56be88d7f263c9dcec782c7ea50618a3c1509e5dc2a06539a6e,.Cpm,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 37, ""exports"": 2}"
SX32W.CPM,4568352,ae0f65b43b5a04ccb1cc181db66cd5e69e7ab5254891c8c6c6810130ff9922de,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 3, ""exports"": 29}"
UNWISE.EXE,149504,49ef36bd01b8ebf38c7b807a5fb44cbaf47c9d4efa883b01c41494c61ae4a2e2,.EXE,PE,internal_structure_extracted,False,"{""sections"": 4, ""imports"": 6, ""exports"": 4}"
UNWISE.INI,51,d8848d6d476fcab45337043e90121cccc24e4090977a5c54d713c36e06e4ced7,.INI,text,internal_structure_extracted,False,"{""encoding"": ""cp949"", ""lines"": 3}"
USA.BTL,36458,4b9819331d4ad485dce6a16609dbe8ae6e18aa4085e8deb1c8f5333735c5e76e,.BTL,BTLF,internal_structure_extracted,False,"{""header"": ""BTLF01.001\u0000English_US:Paradox:OE""}"
VCL60.BPL,1326080,b1b14dfad40e71fec495316a901dffc14d1add020172f99a28b06f953238a885,.BPL,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 41, ""exports"": 6339}"
VCLDB60.BPL,262656,ab75cf8adaf04dc782dab0272cf02e064700870ae962affeeb135e2f4561f788,.BPL,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 58, ""exports"": 931}"
VCLJPG60.BPL,96256,fe1eaf525e2ac3161e57e36333af7eed2b92597fedb5814f0b8824a40b9917cd,.BPL,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 16, ""exports"": 60}"
VCLSMP60.BPL,62464,ded7e1bbdada951183532d60e95a8ef6805118a1249b6c8ea885d8345b3195f3,.BPL,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 38, ""exports"": 136}"
VCLX60.BPL,213504,741b8250412fe40fd3124de2814a506af94f65017e6c90ae2af27a9b54d81052,.BPL,PE,internal_structure_extracted,False,"{""sections"": 8, ""imports"": 51, ""exports"": 617}"
View_Old_San.CPM,667136,debe9a5cbeb477ca5c889269b9bcc69fa074989fe7074be2e347ab421260fd67,.CPM,PE,internal_structure_extracted,False,"{""sections"": 7, ""imports"": 15, ""exports"": 1}"
WLHA32.DLL,90624,96452faeed5affd7dcd88f3aa14930ab5e5709f5916262c87a10927d40838329,.DLL,PE,internal_structure_extracted,False,"{""sections"": 5, ""imports"": 2, ""exports"": 5}"
WUNARJ32.DLL,44032,257b4812c9b4a127b2e7a04eff3bd19166ff8ca20cf03d85684b1ec890b804d5,.DLL,PE,internal_structure_extracted,False,"{""sections"": 5, ""imports"": 2, ""exports"": 2}"
1 path bytes sha256 extension format analysis_level core detail_summary
2 Apollo5D6.bpl 339456 4364f64c43032e1595ba45ec1c2bc1dade5d68d80a74e4bac6ec3858e68b42a4 .bpl PE internal_structure_extracted False {"sections": 8, "imports": 54, "exports": 1302}
3 BANTAM.DLL 101376 01c8fac9f5f519dfd0314ee7eb70da64afc53bf82f7831a9c16add63fde0b729 .DLL PE internal_structure_extracted False {"sections": 6, "imports": 2, "exports": 43}
4 BDERTL60.BPL 222208 b56d3e643fb1eef7018aa120ddab53ae0402ef997e1441a1ad7ff4ce25f79658 .BPL PE internal_structure_extracted False {"sections": 8, "imports": 25, "exports": 1036}
5 BORLNDMM.DLL 22016 e7b3218d1ef0d16fe29674144dc2f887f281687476b5ba4625cbdd680c22a92a .DLL PE internal_structure_extracted False {"sections": 7, "imports": 6, "exports": 12}
6 CHARSET.CVB 144454 07cd1afc401f3ec6c913f319813810839f9f20123506b28381e179bf921f6b0c .CVB BTCV internal_structure_extracted False {"header": "BTCV##BaseCV\u0000\u0000\u0000\u0000\u0000\u0002�\f\u0000\u0000\u0000\u0000\u0000\u0000 \u0003�\u0000A"}
7 CPMARC.CPM 132096 17d182e5d20dc1e4767d7e5e122566cbaa7e462eaadcf558de87c039f412a38a .CPM PE internal_structure_extracted False {"sections": 7, "imports": 3, "exports": 4}
8 CPMUNA.CPM 117760 decb3ca906c76a44b2417b998d7abb07b7a39d17969b37831d819039326ee654 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 3, "exports": 4}
9 DBRTL60.BPL 254464 6f7d8767276c74fbf80fce4df1e6e9fd470d80e37e7bc6f51095509af3054379 .BPL PE internal_structure_extracted False {"sections": 8, "imports": 16, "exports": 1314}
10 Dclhrp60.bpl 418816 6d96304c04aa11e9dae0163e99bbd0abe2a9dd4dd665aa8d201f7afb7b891ae7 .bpl PE internal_structure_extracted False {"sections": 8, "imports": 75, "exports": 1333}
11 DELPHIMM.DLL 9216 7030bfa308e4b0916349bab32d7783e76f2d5c48dc36e7eda3535d80b3e540e7 .DLL PE internal_structure_extracted False {"sections": 7, "imports": 5, "exports": 10}
12 designide60.bpl 701440 80df9d758d68e5d9e6b0536e102eb6e7744f70cfa95b9306694b93e1a55272a4 .bpl PE internal_structure_extracted False {"sections": 8, "imports": 58, "exports": 2837}
13 DP_Common.CPM 436736 5f55d301c6b2139816ff8832e46becb852c4f0a0c9b5da199371156b6aaf30e0 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 15, "exports": 73}
14 DP_MinMsg.CPM 82432 2059455faa4f92a8897754494a1e28daa9ecce42c3d79c6c9ac02c58dc631de7 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 51, "exports": 3}
15 EQSYNC.DBF 2938 3d7dd1d1d1e5d015aaf2d60628368e65251a1a3a2f6c8f8c449b5566e472391f .DBF DBF-like internal_structure_extracted False {"version": "0xE6", "records": 54, "header_len": 129, "record_len": 52}
16 EQSYNC.SMT 12311 2537657ec0c036501afb7a9c98c4ef17024b578d537ec0cb59958c5d8c3f4248 .SMT SIxMemo internal_structure_extracted False {"block_size": 64, "first_value": 193}
17 FAREAST.BTL 517810 27dc4e384c01d6fcadaa90973b018adb6f11be28750d2b97e831215ef22b72f5 .BTL BTLF internal_structure_extracted False {"header": "BTLF01.001\u0000Chinese_TW:dBASE:ANSI"}
18 FTS32.DLL 43520 05e98046789d7508b18dfcbe14c3724c49f06eb22688675e3646d9d790966b1d .DLL PE internal_structure_extracted False {"sections": 5, "imports": 1, "exports": 16}
19 HRRES32.DLL 19456 4a7d8f8a58e0f82d8a5be2336a79e63a5aa42f6f32a82863c9c957513b25cc26 .DLL PE internal_structure_extracted False {"sections": 7, "imports": 5, "exports": 1}
20 IDAPI32.DLL 589312 fc2faec98fd7167cf7d25fa773ec8ecead0dfc678ca1ffaf6b34f78bac91a91e .DLL PE internal_structure_extracted False {"sections": 8, "imports": 6, "exports": 754}
21 IDDBAS32.DLL 454144 9955fcc1e214b15dce432a61d489d2de758169a70306d92a27f1c20ea6b45025 .DLL PE internal_structure_extracted False {"sections": 7, "imports": 4, "exports": 67}
22 IDPDX32.DLL 255488 516741a7d632a458e1746137b184a1b050395e974c6b428fca1524ea3a166c6f .DLL PE internal_structure_extracted False {"sections": 7, "imports": 3, "exports": 15}
23 IDR20009.DLL 116736 b41e0f4c1b63d66f68c6e193742287d0481645fb1c7b95f6858b32435648b360 .DLL PE internal_structure_extracted False {"sections": 6, "imports": 2, "exports": 4}
24 JDLCHK.Size.dll 1206784 da4d1755947d88336f81d1a6c5766a8df0fee71664e6485399cc3ac9bac8e5de .dll PE internal_structure_extracted False {"sections": 7, "imports": 17, "exports": 4}
25 JDLCHK.Tab.dll 1214976 d8e5d9733b14e18695a1f30ceb2aca7fe14894a040e068ed4a37490a26d105ae .dll PE internal_structure_extracted False {"sections": 7, "imports": 15, "exports": 4}
26 JDLCHK.Tab_33.dll 1229824 c5052736204cd4b956a3f59a6f7d41b36e298258846ce64fd7231407db8dd43f .dll PE internal_structure_extracted False {"sections": 7, "imports": 15, "exports": 4}
27 MINIEXTR.DLL 40960 4edc83a1b2d5037820e4ec66b6f172082aa663636b8f9c343dba79e6fb3ce935 .DLL PE internal_structure_extracted False {"sections": 5, "imports": 2, "exports": 13}
28 RAR.EXE 185212 fe079b67547706ce650f2755b16d9f7efb01a1e5ea07ba464bfe585ae9846003 .EXE DOS-MZ internal_structure_extracted False {"magic": "4d5a7c016a01990840033903ffff282d"}
29 RealGrid6.bpl 402944 d1efca11ace3f581e7f4f5408afef2b29d77ce5a4aeb73bc1fa2a94548832ea8 .bpl PE internal_structure_extracted False {"sections": 8, "imports": 55, "exports": 1630}
30 RealGridDB6.bpl 111104 c4963618fdcea616b208d2f4891f870e91494e270db36becebfc66466e492d3b .bpl PE internal_structure_extracted False {"sections": 8, "imports": 72, "exports": 272}
31 RealGridEX6.bpl 71680 c8f5ec65c1e2af4f0a818e14d791e267b5e47d8d87cf491ecf17e346661aa231 .bpl PE internal_structure_extracted False {"sections": 8, "imports": 59, "exports": 142}
32 RTL60.BPL 685056 aa4a46b7921f225910414422ec7ff5533cd5fad87e2fe2cca248f25eb9899480 .BPL PE internal_structure_extracted False {"sections": 8, "imports": 16, "exports": 4698}
33 SDE32.DLL 132096 b23ef38c5099fc74ffd1b5c72c5684e5cc64d598114637dd1bf2462222121260 .DLL PE internal_structure_extracted False {"sections": 6, "imports": 2, "exports": 179}
34 SDE50.DLL 155648 3a8748c8823f2c2a7fd179d9ba045c9afd13734e06fa8450a74a8e509b2450fc .DLL PE internal_structure_extracted False {"sections": 5, "imports": 2, "exports": 179}
35 SDECDX50.DLL 274502 2f09909441d8e4f0bb93463f5a7d6f28db329cc1f5f43e6dbbcbf229dacb1bbf .DLL PE internal_structure_extracted False {"sections": 5, "imports": 3, "exports": 81}
36 SDENSX50.DLL 266240 6e0a5b4967a6d0cc6faee9b471659419540872d9703700fe60a0dc3045ba024c .DLL PE internal_structure_extracted False {"sections": 5, "imports": 3, "exports": 81}
37 SDENTX50.DLL 258118 a1d5fccff1b5249de5000de1b548216d8c165b1a6f6162cf9f465f1a2a6cb31e .DLL PE internal_structure_extracted False {"sections": 5, "imports": 3, "exports": 81}
38 ST_BdSN.CPM 122368 9b7320455bc15f5412f9dd11b40fee13fab44780990c4389c2c5f6beb5f6a395 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 118, "exports": 3}
39 ST_BSC\2007_제비율.JB_M 3379 7139579616921b4e8ac6055d497722b64a2cb048c353861858a179dfa277fc7e .JB_M DBF-like internal_structure_extracted False {"version": "0x03", "records": 25, "header_len": 353, "record_len": 121}
40 ST_BSC\2011(상_0112)_제비율.JB_1 5315 cc5f14790cc4f185f44b0b3e3f5be6c78e52df6a373903f14fcb99134c9b4551 .JB_1 DBF-like internal_structure_extracted False {"version": "0x03", "records": 41, "header_len": 353, "record_len": 121}
41 ST_BSC\2015(상_0301,실적)_제비율.JB_RA 12724 ba85cf902cf1846bcc38583c5f8173046404dc804cfa9b21a3a35a95991335e4 .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
42 ST_BSC\2015(상_0309)_제비율.JB_R 12724 236ffcc157269a8438aac9993f18e4f6d699e4493e692fada8a16102cd68407c .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
43 ST_BSC\2016(상_0301,실적)_제비율.JB_RA 12724 a34469eb1b823dc33e10d96985c7fed44428b93b90c53491edc219cb4b3d677d .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
44 ST_BSC\2016(상_0307)_제비율.JB_R 12724 b2e87dc37da04744197040ecd863b1b38563ad63ac975b77f3126bf412d13c97 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
45 ST_BSC\2017(상_0215)_제비율.JB_R 12724 dab9bf2fb5e62c41c65e9a01dbc6c7e08f06ff8d14a0d5ec90e24f2134c8e61a .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
46 ST_BSC\2018(상_0327)_제비율.JB_R 12724 6ec8ef38aaf747e54117451cb0e5ebcb6b4bbb084bc824163a5dc465ed23d8b3 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
47 ST_BSC\2018(하_0701,표준시장)_제비율.JB_RA 12724 e771db1af3a0d4725289f5b01b97fbd4982eb5b89776c6130d87b9127857dbe8 .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
48 ST_BSC\2018(하_0801)_제비율.JB_R 12724 608a7a9b61884dd8ee3557078db32ab94ad9b6e88341c010ce14643327171e4a .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
49 ST_BSC\2019(상_0101,표준시장)_제비율.JB_RA 12724 e771db1af3a0d4725289f5b01b97fbd4982eb5b89776c6130d87b9127857dbe8 .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
50 ST_BSC\2019(상_0107)_제비율.JB_R 12724 1462a445d32cea9d9a054bd3d114b66bdbc5693f1e464771deecd9797ac373fa .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
51 ST_BSC\2019(상_0417)_제비율.JB_R 12724 1c42ea998ca321ac9f8c19bc54736360ee38b8c7f4153e8a94e6c02892c42014 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
52 ST_BSC\2019(상_0628)_제비율.JB_R 12724 0401a772ef13213c8f49c8ff4f40b1f3b1960e87868b229a4119750829d51a85 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
53 ST_BSC\2020(상_0102)_제비율.JB_R 12724 e0069fa4687aabf12f0466a21bc80d064de4d0a391561cfe2cad47e4bb893680 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
54 ST_BSC\2020(상_0102,표준시장)_제비율.JB_RA 12724 49610b1853c84922fc47092d32d01a1ab65844eecf95dfeaff48ac4db56b42a0 .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
55 ST_BSC\2020(상_0527)_제비율.JB_R 22204 aa722b3c970616b2f402719baa199009cdbf7185f6e2ab04c1cbe48fc92dc508 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
56 ST_BSC\2021(상_0104)_제비율.JB_R 22204 b43e44c96edb0be4c3b50f46c015ed39eb87995f749f055b165d104d97c75b49 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
57 ST_BSC\2021(상_0421)_제비율.JB_R 22204 c267385aa0d65e4339223ee7d965e44f2bb7e6c351a4689e09ed3071e3d3565d .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
58 ST_BSC\2021(상_0520)_제비율.JB_R 22204 bbb678008ba42ac8e99ab874884c6219a41c8d474ec4497813b9887edcea0d28 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
59 ST_BSC\2021(하_0501,표준시장)_제비율.JB_RA 12724 b0d7975bb563191dfe2f765d30ccf9083feb9b7ff6cac45198499db86bd9b427 .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
60 ST_BSC\2021(하_0701)_제비율.JB_R 22204 f73382e53a575ccd88222f18323caad6c24d6c1002567e55d11f3a6ac4c45847 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
61 ST_BSC\2022(상_0103)_제비율.JB_R 22204 45d132ad0de6fdd3b41f63743fadcf4ba4bb1db633ab773af850bc4a2c6cbd62 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
62 ST_BSC\2022(상_0103,표준시장)_제비율.JB_RA 12724 b0d7975bb563191dfe2f765d30ccf9083feb9b7ff6cac45198499db86bd9b427 .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
63 ST_BSC\2022(상_0425)_제비율.JB_R 22204 82d7fdab0dbc6162d0fec4e0e99feb27d20d50031d1ff13ac0d6ce056db09977 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
64 ST_BSC\2022(하_0501,표준시장)_제비율.JB_RA 12724 95220f1fb9b4169143f9d0fe88cfc6f83dead1c4f464467003cd0ca755da7265 .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
65 ST_BSC\2023(상_0102)_제비율.JB_R 22204 1aa1fca4090dc67e28c2820dead8b82daf50a73a20ff82dd1905040bb58f71b0 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
66 ST_BSC\2023(상_0102,표준시장)_제비율.JB_RA 12724 95220f1fb9b4169143f9d0fe88cfc6f83dead1c4f464467003cd0ca755da7265 .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
67 ST_BSC\2023(상_0428)_제비율.JB_R 22204 2cf8869231d0a4b9dede802b6a5d3363e3e956db147c0c851370b06e4af9190f .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
68 ST_BSC\2024(상_0101)_제비율.JB_R 22204 e594487cc11755b486cf4bfe3b5876107ec044458313f5989f32e0713681bcac .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
69 ST_BSC\2024(상_0101,표준시장)_제비율.JB_RA 12724 39af7fa4ebc6a1d12e32cb298538bb24c6658a65249cec57541440044fe46191 .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
70 ST_BSC\2024(상_0315)_제비율.JB_R 22204 4ed224783fb0d72c66d7c3def6c983f33129011782600d7d78a18cb46ee87a97 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
71 ST_BSC\2025(상_0101)_제비율.JB_R 22204 196ecc70fa0b3f1b17ed8f2d5ce5b0339ef92bd3e06dde625c87759707a0f2e4 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
72 ST_BSC\2025(상_0101,표준시장)_제비율.JB_RA 12724 49542b8fe77b734c6eefd5d4673a1841f00bcdde8205fc71b6289d1ea05c289b .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
73 ST_BSC\2025(상_0401)_제비율.JB_R 22204 dc678b3617b203fa88d6fffcb5e0e04a827da5c31545405a1d1c27c72e200839 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
74 ST_BSC\2025(상_0501)_제비율.JB_R 22204 3f978a6793fc131afc10e614dca9bc84b2064ab9faae71d29fee3a1b79440106 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
75 ST_BSC\2025(하_0501,표준시장)_제비율.JB_RA 12724 5f07b35b604129203be578323e260fd37a76ac90bd593a450ed728e407aac7c8 .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
76 ST_BSC\2025(하_0809)_제비율.JB_R 22204 1463341b3da28f5ae7e24446c3003e9cfdc2177cf9962807f86c0ff14805f090 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
77 ST_BSC\2026(상_0101)_제비율.JB_R 22204 6fa9bb61555a54f2e6ee95583d76e0c5ab818534b6181783b24a5ed4fb3422e2 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
78 ST_BSC\2026(상_0101,표준시장)_제비율.JB_RA 12724 5f07b35b604129203be578323e260fd37a76ac90bd593a450ed728e407aac7c8 .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
79 ST_BSC\2026(상_0313)_제비율.JB_R 22204 af27255d84bc9cbdc1dc9ba6ea823d9649fd5f69f4121bba14864113917422d4 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
80 ST_BSC\2026(상_0413)_제비율.JB_R 22204 19b3fdea3aa891d3e7d37b89c43e7e57fe85dbf39f30c42a9d407f34475f7901 .JB_R DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 1153, "record_len": 421}
81 ST_BSC\2026(하_0508,표준시장)_제비율.JB_RA 12724 68778043bc15e24688d17ad8fc3fa775e61291897038b4a6e2824897314bc08f .JB_RA DBF-like internal_structure_extracted False {"version": "0x03", "records": 50, "header_len": 673, "record_len": 241}
82 ST_BSC\GRPCOD_E.BSC 340484 2ab6eb0215184f6c442702f94cd82934acef43bc8b398e8227cee58e56cbe9c0 .BSC DBF-like internal_structure_extracted False {"version": "0x06", "records": 2539, "header_len": 257, "record_len": 134}
83 ST_BSC\GRPCOD_Z.BSC 1625008 b6c58c548256fdf3d7be2780d0a4b8b23b34d85ba61c8899e5ab38f8e35eaa2c .BSC DBF-like internal_structure_extracted False {"version": "0x06", "records": 12125, "header_len": 257, "record_len": 134}
84 ST_BSC\JDCODE_L.BSC 156358 d967e15b87c6a2168251977119fe8263898bce84e3ef545eb09c78bdf6e465fd .BSC DBF-like internal_structure_extracted False {"version": "0x06", "records": 460, "header_len": 417, "record_len": 339}
85 ST_BSC\JDCODE_M.BSC 19520038 69073533ba84c01bd58ec4ea7cfddbd427e61ee62142a8654284d2bf6db272c7 .BSC DBF-like internal_structure_extracted False {"version": "0x06", "records": 57580, "header_len": 417, "record_len": 339}
86 ST_BSC\JDCODE_S.BSC 288907 39a3e525399a842e0df1e27e8f2a76683db42e5c1fefa20c61eb3c74494f4df0 .BSC DBF-like internal_structure_extracted False {"version": "0x06", "records": 851, "header_len": 417, "record_len": 339}
87 ST_BSC\JDCODE_X.BSC 282805 6304d8e0bb717efaaed72e9626a688cb4a955866a113b5a9c3e1a4d19bee9163 .BSC DBF-like internal_structure_extracted False {"version": "0x06", "records": 833, "header_len": 417, "record_len": 339}
88 ST_BSC\JDCODE_Z.BSC 11501671 decbd6a76ebe98751020f78b74b190970cdeba834316409ebe9db3c3fb7cd10e .BSC DBF-like internal_structure_extracted False {"version": "0x06", "records": 33927, "header_len": 417, "record_len": 339}
89 ST_BSC\Valid_Xml.vsl 58807 84f2e2a950139d00fbc96540b24d8883f5a733ba419c3369f8ecbed9f04b6290 .vsl text internal_structure_extracted False {"encoding": "utf-8", "lines": 1429}
90 ST_BSC\노임기계\2025(상_노임,기계경비).STBSC 103229 fc6f62bcff5ce69d83d50af61a7f7d415e17a2e0ec10f3321ae4fd8445fd513c .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "MEM.ST", "XDET.ST"]}
91 ST_BSC\노임기계\2025(하_노임,기계경비).STBSC 103027 c99902383b569c5941c6bafe6707a0358beb9f81ec19c2dd486d96ea7a152025 .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "MEM.ST", "XDET.ST"]}
92 ST_BSC\노임기계\2026(상_노임,기계경비).STBSC 104166 74f886bb8cc1ae69e69fe1d92845d23e60c35ff0f06f75631368112a4ca3f1c3 .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "MEM.ST", "XDET.ST"]}
93 ST_BSC\노임기계\2026(하_노임,기계경비).STBSC 104284 48d7196fed12d887a94a2e391f98b212af7aa9040a8e51555bfdf895869c94bc .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "MEM.ST", "XDET.ST"]}
94 ST_BSC\실적단가\2025\2025(상,국교,해수부,조달청)_표준시장.CSTA 2427111 5c8d0d7bf9e9208e72e6acaafdf8544f88b972a46b7f74ec3b32acc0a3d458af .CSTA DBF-like internal_structure_extracted False {"version": "0x06", "records": 4921, "header_len": 1057, "record_len": 493}
95 ST_BSC\실적단가\2025\2025(상_시장시공,조달청).STBSC 24865 79e534e050664f0248732c9923d9b131a52340bbe4a93c79730d17c285b0e367 .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
96 ST_BSC\실적단가\2025\2025(상_표준시장,조달청).STBSC 234037 fa4e340e60845f38a3bfe44966e3415690da9e9eaa0a236d057ff4986a065694 .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
97 ST_BSC\실적단가\2025\2025(상_표준시장[노임외 경비적용],국교,해수부).STBSC 168543 432f365195096b67a21f5ba2b804cde79fe24534697294e091858a17cf23bdc6 .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
98 ST_BSC\실적단가\2025\2025(상_표준시장[노임외 재료비적용],국교,해수부).STBSC 167083 a66c9af574fba4a6a5d43bfb04de42c0c4b941091a1b2aba1ab2d659e4503f19 .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
99 ST_BSC\실적단가\2025\2025(하,국교,해수부,조달청)_표준시장.CSTA 2427111 68cba31f353bfb2c78909a9633e96b8581276d21044ceecce21399f26fd030a4 .CSTA DBF-like internal_structure_extracted False {"version": "0x06", "records": 4921, "header_len": 1057, "record_len": 493}
100 ST_BSC\실적단가\2025\2025(하_시장시공,조달청).STBSC 25501 e1fb2b89d26cb19ee88ffa5b40a8401cedcc651de4b80f11b4520db88248cad2 .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
101 ST_BSC\실적단가\2025\2025(하_표준시장,조달청).STBSC 234106 ca134e164233b9477ce9d34da9d8f36db902c693ce36e4325bc2319daea17cf2 .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
102 ST_BSC\실적단가\2025\2025(하_표준시장[노임외 경비적용],국교,해수부).STBSC 168600 e2a4669ccf5ff3ede5457b1d00a463263303ce2467361d5dd4d5ff10983ab596 .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
103 ST_BSC\실적단가\2025\2025(하_표준시장[노임외 재료비적용],국교,해수부).STBSC 167122 cb139c7278f120a6aa6dcc3e1dde9bb5d0b67b8fd62aa728797e6a3d50c3dd0b .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
104 ST_BSC\실적단가\2025\COSTA.CSTA 2427111 68cba31f353bfb2c78909a9633e96b8581276d21044ceecce21399f26fd030a4 .CSTA DBF-like internal_structure_extracted False {"version": "0x06", "records": 4921, "header_len": 1057, "record_len": 493}
105 ST_BSC\실적단가\2025\표준시장단가(2025_04_21).Info 206 d4a1fd8bb95b8715a423748f2ccfb516807cdace287a039d3a5a71ba148c805a .Info DBF-like internal_structure_extracted False {"version": "0x32", "records": 3139494579, "header_len": 47603, "record_len": 45533}
106 ST_BSC\실적단가\2025\표준시장단가(2025_08_04).Info 342 4b31c62515d0692aaee658adc19cb36cdc3e8963251154401918e7aa0c5b7f64 .Info DBF-like internal_structure_extracted False {"version": "0x32", "records": 3340821171, "header_len": 47567, "record_len": 45533}
107 ST_BSC\실적단가\2026\2026(상,국교,해수부,조달청)_표준시장.CSTA 2446831 3cf6ff7b7acb709a9faee154fbe2dbcfc718c6112e317d98868ac493dae666d5 .CSTA DBF-like internal_structure_extracted False {"version": "0x06", "records": 4961, "header_len": 1057, "record_len": 493}
108 ST_BSC\실적단가\2026\2026(상_시장시공,조달청).STBSC 25187 303abd1b10ef21a8c7e30f2af9845400346ff82f0f25bf7f9beb6277b43f696c .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
109 ST_BSC\실적단가\2026\2026(상_표준시장,조달청).STBSC 236533 7f85e77265679b46807b2b22311b1fa07ffee463c50db67d6426ad38b5773f07 .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
110 ST_BSC\실적단가\2026\2026(상_표준시장[노임외 경비적용],국교,해수부).STBSC 170135 4f09af8780b54dcaeb1da7d268ac7cab253298c8402e15790749bf50ac47f482 .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
111 ST_BSC\실적단가\2026\2026(상_표준시장[노임외 재료비적용],국교,해수부).STBSC 168661 19c589ee1b564aa7593e87e556b0ab1855a7291ef0cf894df29a36a1e78170e2 .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
112 ST_BSC\실적단가\2026\2026(하,국교,해수부,조달청)_표준시장.CSTA 2446831 a5b26c95d44c47dc7dd7f5997a2e6be68edb1436003fc914fd1402588d68edfc .CSTA DBF-like internal_structure_extracted False {"version": "0x06", "records": 4961, "header_len": 1057, "record_len": 493}
113 ST_BSC\실적단가\2026\2026(하_표준시장,조달청).STBSC 236961 cd3394de4e0ab08b6bab3c0db8cb5d439983ddaece5df5016243b0c32d6bece7 .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
114 ST_BSC\실적단가\2026\2026(하_표준시장[노임외 경비적용],국교,해수부).STBSC 170373 dfe6e5a1c922cad51fa49ad3682292857450f0bff5f84f7fa2762a61685aed44 .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
115 ST_BSC\실적단가\2026\2026(하_표준시장[노임외 재료비적용],국교,해수부).STBSC 168877 fffae2c8fd2ef78af32da16711dba26e952fc0858d25b73e643d2379e66174ad .STBSC ZIP internal_structure_extracted False {"entries": 4, "encrypted": 4, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "XDET.ST"]}
116 ST_BSC\실적단가\2026\COSTA.CSTA 2446831 a5b26c95d44c47dc7dd7f5997a2e6be68edb1436003fc914fd1402588d68edfc .CSTA DBF-like internal_structure_extracted False {"version": "0x06", "records": 4961, "header_len": 1057, "record_len": 493}
117 ST_BSC\실적단가\2026\표준시장단가(2026_05_04).Info 224 64934740ee03e4f01fe112ec1ae9cddc01497da48b515f6cdbbb82487c7c75a7 .Info DBF-like internal_structure_extracted False {"version": "0x32", "records": 3139494579, "header_len": 47603, "record_len": 45533}
118 ST_BSC\실적단가\2026\표준시장단가(2026_05_27).Info 206 207506f87c9c3da5ec86b8e16efab8a4f35570b0cb8934d7443c82502c5803e9 .Info DBF-like internal_structure_extracted False {"version": "0x32", "records": 3340821171, "header_len": 47567, "record_len": 45533}
119 ST_BSC\일위대가\2026\2026(상_표준일위대가_건축).STBSC 107988 10c39a2e5d1e797b7d9f82f9ff1d099d74ad83a84e9a9c936e192bdbf4744f5a .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "MEM.ST", "XDET.ST"]}
120 ST_BSC\일위대가\2026\2026(상_표준일위대가_기계설비).STBSC 142723 ef64cde3312b77e99e3f0f9565bfcf8dc6e747a9a4b414d8921f2499a65d6663 .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "MEM.ST", "XDET.ST"]}
121 ST_BSC\일위대가\2026\2026(상_표준일위대가_전기).STBSC 22104 08c88f23a731e05bd6c926e0686ed1565c3900318f2df5779db92b762e026614 .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "MEM.ST", "XDET.ST"]}
122 ST_BSC\일위대가\2026\2026(상_표준일위대가_토목).STBSC 199599 42b6bbad12827b3a68991ee59a78d4a81d43928433043a2b025a77169abe4830 .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "MEM.ST", "XDET.ST"]}
123 ST_BSC\일위대가\2026\2026(상_표준일위대가_통신).STBSC 52561 9bf846f887815e228f4122ca3b9dd6de4b6cd6b26b6f3e647dc7ad8055fc9352 .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "MEM.ST", "XDET.ST"]}
124 ST_BSC\일위대가\2026\표준일위대가(2026_03_17).Info 542 84b673e857218323d8eabb7a6cce309979a6bd65490a6311382f9f2af275b3db .Info text internal_structure_extracted False {"encoding": "cp949", "lines": 11}
125 ST_BSC\자재단가\시설공통자재\2025-상-시설공통자재.STBSC 184968 7ac21732736a8b83d732f21797dc1434a4376319cea1f8777f86fc37f209593a .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["info.ST", "XDET.ST", "Start.ST", "COST.ST", "CH_NAME.ST"]}
126 ST_BSC\자재단가\시설공통자재\2025-하-시설공통자재.STBSC 178357 f7f7f884e7d0cfd83be9fd618c99d540c83ca621f26df1d1fa8db6de82afd4c1 .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "Start.ST", "XDET.ST"]}
127 ST_BSC\자재단가\시설공통자재\2026-상(06)-시설공통자재.STBSC 177153 cfcc27abb1759a916983b51737361c348d277ed540b18188da9976fe56cef034 .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "Start.ST", "XDET.ST"]}
128 ST_BSC\자재단가\시설공통자재\2026-상-시설공통자재.STBSC 176293 926f18edcf6390f34391bd9a26a6bf589d5e6b8e10128498a2cdb50341a70185 .STBSC ZIP internal_structure_extracted False {"entries": 5, "encrypted": 5, "names": ["CH_NAME.ST", "COST.ST", "info.ST", "Start.ST", "XDET.ST"]}
129 ST_BSC\호환규정코드(2026_09_01) 108 7f12adccd919919ef7739f3efce9439e1f183989980c8daeb170bb1e65fdcade text internal_structure_extracted False {"encoding": "cp949", "lines": 3}
130 ST_Com_V.CPM 648192 d66b620110244d0814513fb18fa3fca6611ad57ffa300e193c0b85af59b2f574 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 17, "exports": 10}
131 ST_CPM\ST_Boq.CPM 2119168 180707d0423dd2dcb8403d89ba1dbaf2731c0db5c6bb332029479fd9d9923ab3 .CPM PE internal_structure_extracted True {"sections": 7, "imports": 132, "exports": 4}
132 ST_CPM\ST_EdiLWi.CPM 508928 9e83c2a450d31353953361c8bb460bae700cc76927605145a0ae406ca31702ca .CPM PE internal_structure_extracted True {"sections": 7, "imports": 128, "exports": 2}
133 ST_CPM\ST_EdSan.CPM 628224 101d1f31adff9d46d30a46135ccd6398af41fcee9b2434a91dae5ee466e13753 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 128, "exports": 3}
134 ST_CPM\ST_FindUse.CPM 436224 c0c2b770e805cfcb78ef091a4657185160f58408434dab09cbef20d982d59a9e .CPM PE internal_structure_extracted False {"sections": 7, "imports": 125, "exports": 3}
135 ST_CPM\ST_Jabpum.CPM 411136 d960f6e6b5ffa395c201eabf126cb4dcf8dbe026c2afaa804a7bfa6429164f51 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 126, "exports": 6}
136 ST_CPM\ST_KanJub.CPM 1718272 ef8d55b259b37916496e80cab6a4a2ba46216e0bd7c5199083dbda632bd50d03 .CPM PE internal_structure_extracted True {"sections": 7, "imports": 131, "exports": 5}
137 ST_CPM\ST_P_Collect.CPM 570880 fd1b468d77398a72705537e28321c93a3736fbc1ea384997659eea2fe9b71737 .CPM PE internal_structure_extracted True {"sections": 7, "imports": 125, "exports": 5}
138 ST_CPM\ST_P_ConEst.CPM 735744 027c72cc019e46fdec78e6aebc68b621aa77c7fc1ac88362f04675f6dab69fab .CPM PE internal_structure_extracted True {"sections": 7, "imports": 125, "exports": 9}
139 ST_CPM\ST_P_Excav.CPM 809472 62ea015c8fcb05c351d394a8bdb3214ea516d099fb986c25a7503358160fb0d0 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 125, "exports": 15}
140 ST_CPM\ST_P_iLWi.CPM 634880 1308680f806f9e0298f99ce68d08c5c3e80eb5d7e8cf86fb7a89d7678539ae32 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 125, "exports": 3}
141 ST_CPM\ST_P_Joong.CPM 797696 30c28a8ace160c06fa79948ea20678504aaeae2d20304daff719300e5f919ee7 .CPM PE internal_structure_extracted True {"sections": 7, "imports": 125, "exports": 7}
142 ST_CPM\ST_P_List.CPM 631808 e14d17b10ee1f82f5abc0f7c90f1b658516f9623452fe092450396eae9deb071 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 125, "exports": 11}
143 ST_CPM\ST_P_Nae.CPM 1398272 9ecb6a663c988f249548a06a6c7da66abc71d8c245baba141450c329391f1c47 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 125, "exports": 30}
144 ST_CPM\ST_P_San.CPM 570368 5d364a818883fd6f69839dd08c7e3243e0545fd23062454f5816b3cc0bae941c .CPM PE internal_structure_extracted False {"sections": 7, "imports": 125, "exports": 3}
145 ST_CPM\ST_P_XLS.CPM 2314752 1d3f7ed8702ee9e4ea2309126028f3600497617c576c1b91659b0c8c60083da0 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 127, "exports": 72}
146 ST_CPM\ST_PList.CPM 1586176 638c8167ff5817f454633c9270b9b01b2ef72044339c58bd8d5190b1a8e4766c .CPM PE internal_structure_extracted False {"sections": 7, "imports": 143, "exports": 3}
147 ST_CPM\ST_Prt.CPM 1170432 0698a6343ba04a5b379f297da60e68a9fc3f18d5ac0ad262570f70ca98dd3c19 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 130, "exports": 4}
148 ST_CPM\ST_SanCal.CPM 270336 153967ee6429ba40285939af68a9b2b02daae9888e95440e95dc017acdf0ad54 .CPM PE internal_structure_extracted True {"sections": 7, "imports": 120, "exports": 2}
149 ST_CPM\ST_Sys.CPM 566784 e55845df186ecb2d0ea6de4408b299529cd0d697030da8c114a0a48b3ce0a81d .CPM PE internal_structure_extracted False {"sections": 7, "imports": 126, "exports": 2}
150 ST_CPM\ST_U_ADL.CPM 189952 833af9af1263205f3e0e04162079114d451e6136c2e5271776f63532e19a4031 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 48, "exports": 6}
151 ST_CPM\ST_U_Archive.CPM 473088 1d00333bca0277a3355826419d11c57996852ec9013b7bb508d16ac9ec6ed553 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 125, "exports": 16}
152 ST_CPM\ST_U_ChgAmt.CPM 130560 37ca3715c216f68274eabd3dd944bcd7922404bd2721b1ba0b73c428e843e3d8 .CPM PE internal_structure_extracted True {"sections": 7, "imports": 120, "exports": 2}
153 ST_CPM\ST_U_ChgCode.CPM 656896 6fe80a7a21e1458852e940bb1efdf3eee618ae23d0090a4e7323c908efb9257d .CPM PE internal_structure_extracted True {"sections": 7, "imports": 124, "exports": 10}
154 ST_CPM\ST_U_ConBD.CPM 196608 fb0351c1fa96be282b8da6be31ba97673e626e1a5d8e30acb83831f4c72e5d6e .CPM PE internal_structure_extracted True {"sections": 7, "imports": 121, "exports": 4}
155 ST_CPM\ST_U_Convert.CPM 1825792 0166beb69d2692732eb3d5e897201a96aa1b2955026a67aa53989ffa28431649 .CPM PE internal_structure_extracted True {"sections": 7, "imports": 133, "exports": 20}
156 ST_CPM\ST_U_DelCode.CPM 544768 30cc2e234a67fd2adeb51629b00b3d3d60e2fa2026b1f0b1ff9af958a1b38f9c .CPM PE internal_structure_extracted False {"sections": 7, "imports": 123, "exports": 6}
157 ST_CPM\ST_U_DelPrj.CPM 161280 2e47370f7ad85542f375f03e6b3a0aaf88252750d8f6ad1ce631ea02125c2a3d .CPM PE internal_structure_extracted False {"sections": 7, "imports": 121, "exports": 3}
158 ST_CPM\ST_U_Indx.CPM 137728 cbe19214915433afe71b856c3f82a7eb4c106ea40df72cb726eb8fcf8e73f2c9 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 124, "exports": 2}
159 ST_CPM\ST_U_Merge.CPM 718848 350085f3a498628703ec66486bfc4994683169fdf0c4f8e8cc7f9c842b81271a .CPM PE internal_structure_extracted False {"sections": 7, "imports": 124, "exports": 2}
160 ST_CPM\STmateQty8.CPM 224768 f92ec517ff931328dac76154a1fedcee8e9cca5ffb64fddfc207af3887c19b37 .CPM PE internal_structure_extracted True {"sections": 7, "imports": 124, "exports": 4}
161 ST_Func_C.CPM 657920 f2d4b2f6ebda2d57e47d343907071400cdb4b9f01fa5cc7756f34eb5f94e2ca6 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 19, "exports": 7}
162 ST_JD_Lst.CPM 143370 64d6d0dd7629249dc2f3fbdcd7372a9e09a8422fe2ede94ea59a8fedd25f3497 .CPM text internal_structure_extracted False {"encoding": "cp949", "lines": 26}
163 ST_log\ST_log.stlog 149 298b9c72ce903c0a06241dc04bd2f5cca0c525ae2822b09cdeccdda36f9df932 .stlog obfuscated-log internal_structure_extracted False {"bytes": 149}
164 ST_Merge_Code.CPM 656896 c3bcc5851d680da5dc69e04b4d9e389baf36c45dc1c2203c5b88e039e6d56c63 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 133, "exports": 1}
165 ST_Tips.dat 1636 f7de77c90911587bf98c2a75c58d6484bbc166d49b306feb04e895fdc93f4d6a .dat tips-data internal_structure_extracted False {"utf8_html": true, "bytes": 1636}
166 ST_U_APatch.CPM 172032 50b79f7c127ec681db22d2cff6814314c143eca73cc473f01d26c71197fb6ed5 .CPM PE internal_structure_extracted False {"sections": 6, "imports": 49, "exports": 0}
167 ST_V_Info.CPM 49 671f6214ec519d846e5b489ffbd37d1a6036945a46169ae1d6294319eba10ce0 .CPM text internal_structure_extracted False {"encoding": "utf-8", "lines": 3}
168 ST_Viewer.exe 1329664 2eeee446f9563a6d64e7a415f7f0373262132f7adfc672ac9b8b108a6e069df9 .exe PE internal_structure_extracted False {"sections": 8, "imports": 21, "exports": 0}
169 ST_VSetup.EXE 1788882 d9e04e9fa0d7886c868d122a20a2143ac913f2ced8fec1c5127ca9fd38a14b81 .EXE PE internal_structure_extracted False {"sections": 4, "imports": 4, "exports": 2}
170 ST_Wal.CPM 325632 da56d1a27a664b0ff7b6af60c8b891bd7c831ffdede9b104ee05d33cad80e82d .CPM PE internal_structure_extracted False {"sections": 6, "imports": 121, "exports": 0}
171 Stma.URL 48 de22235fba718eff232f134680d246ce485ff5e80178e7f654a1eb605878ce87 .URL text internal_structure_extracted False {"encoding": "utf-8", "lines": 2}
172 STmate.Cpm 3525632 99d5c05675ba1399c51a71db8e26ebd5ff39fd78d02360147c7705deb399b5f5 .Cpm PE internal_structure_extracted False {"sections": 7, "imports": 144, "exports": 1}
173 STmate8.Exe 145408 ee029ac9acf684e894a2ea4743a37288755439391f36107565f4aa87f3499b06 .Exe PE internal_structure_extracted False {"sections": 6, "imports": 52, "exports": 0}
174 STmate_Ins.log 15958 9dd9f8e827f64c593afd6b9d15fe041a8d1139c61c189f02e70ed693c122efc3 .log text internal_structure_extracted False {"encoding": "cp949", "lines": 288}
175 STmexe.Cpm 96256 5ff4005a52c8f56be88d7f263c9dcec782c7ea50618a3c1509e5dc2a06539a6e .Cpm PE internal_structure_extracted False {"sections": 7, "imports": 37, "exports": 2}
176 SX32W.CPM 4568352 ae0f65b43b5a04ccb1cc181db66cd5e69e7ab5254891c8c6c6810130ff9922de .CPM PE internal_structure_extracted False {"sections": 7, "imports": 3, "exports": 29}
177 UNWISE.EXE 149504 49ef36bd01b8ebf38c7b807a5fb44cbaf47c9d4efa883b01c41494c61ae4a2e2 .EXE PE internal_structure_extracted False {"sections": 4, "imports": 6, "exports": 4}
178 UNWISE.INI 51 d8848d6d476fcab45337043e90121cccc24e4090977a5c54d713c36e06e4ced7 .INI text internal_structure_extracted False {"encoding": "cp949", "lines": 3}
179 USA.BTL 36458 4b9819331d4ad485dce6a16609dbe8ae6e18aa4085e8deb1c8f5333735c5e76e .BTL BTLF internal_structure_extracted False {"header": "BTLF01.001\u0000English_US:Paradox:OE"}
180 VCL60.BPL 1326080 b1b14dfad40e71fec495316a901dffc14d1add020172f99a28b06f953238a885 .BPL PE internal_structure_extracted False {"sections": 8, "imports": 41, "exports": 6339}
181 VCLDB60.BPL 262656 ab75cf8adaf04dc782dab0272cf02e064700870ae962affeeb135e2f4561f788 .BPL PE internal_structure_extracted False {"sections": 8, "imports": 58, "exports": 931}
182 VCLJPG60.BPL 96256 fe1eaf525e2ac3161e57e36333af7eed2b92597fedb5814f0b8824a40b9917cd .BPL PE internal_structure_extracted False {"sections": 8, "imports": 16, "exports": 60}
183 VCLSMP60.BPL 62464 ded7e1bbdada951183532d60e95a8ef6805118a1249b6c8ea885d8345b3195f3 .BPL PE internal_structure_extracted False {"sections": 8, "imports": 38, "exports": 136}
184 VCLX60.BPL 213504 741b8250412fe40fd3124de2814a506af94f65017e6c90ae2af27a9b54d81052 .BPL PE internal_structure_extracted False {"sections": 8, "imports": 51, "exports": 617}
185 View_Old_San.CPM 667136 debe9a5cbeb477ca5c889269b9bcc69fa074989fe7074be2e347ab421260fd67 .CPM PE internal_structure_extracted False {"sections": 7, "imports": 15, "exports": 1}
186 WLHA32.DLL 90624 96452faeed5affd7dcd88f3aa14930ab5e5709f5916262c87a10927d40838329 .DLL PE internal_structure_extracted False {"sections": 5, "imports": 2, "exports": 5}
187 WUNARJ32.DLL 44032 257b4812c9b4a127b2e7a04eff3bd19166ff8ca20cf03d85684b1ec890b804d5 .DLL PE internal_structure_extracted False {"sections": 5, "imports": 2, "exports": 2}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,221 @@
"""STmate System 폴더 정적 인벤토리/PE 근거 추출. 원본은 읽기만 한다."""
from __future__ import annotations
import csv
import hashlib
import json
import re
import struct
import sys
import zipfile
from collections import Counter
from pathlib import Path
SYSTEM = Path(r"C:\경영정보(주)\System")
OUT = Path(__file__).resolve().parent
CORE = {
"ST_KanJub.CPM", "ST_SanCal.CPM", "ST_Boq.CPM", "ST_EdiLWi.CPM",
"STmateQty8.CPM", "ST_P_Joong.CPM", "ST_U_ChgAmt.CPM",
"ST_U_ChgCode.CPM", "ST_U_ConBD.CPM", "ST_P_ConEst.CPM",
"ST_P_Collect.CPM", "ST_U_Convert.CPM",
}
TOKENS = re.compile(
r"DBF|SMT|COSTN|COSTA|BDQTY|BOQ(?:11|12|13|14)?|PRJLST|RATE(?:_M|_R|_RA)?|"
r"TAMT|LAMT|MAMT|SAMT|QTY|ROUND|HAL|ADJ|PG_[1-6]|KWNGP|EQCODE|IFORM|"
r"STBSC|CSTA|JB_R|VAT|TAX|EXCEL|XLS|\bSELECT\b|\bUPDATE\b|\bINSERT\b|\bDELETE\b",
re.I,
)
def u16(data: bytes, off: int) -> int:
return struct.unpack_from("<H", data, off)[0]
def u32(data: bytes, off: int) -> int:
return struct.unpack_from("<I", data, off)[0]
def cstr(data: bytes, off: int, limit: int = 512) -> str:
end = data.find(b"\0", off, min(len(data), off + limit))
if end < 0:
end = min(len(data), off + limit)
return data[off:end].decode("ascii", errors="replace")
def strings(data: bytes) -> list[str]:
found = [m.group().decode("ascii", errors="replace") for m in re.finditer(rb"[\x20-\x7e]{4,}", data)]
found += [m.group().decode("utf-16le", errors="replace") for m in re.finditer(rb"(?:[\x20-\x7e]\x00){4,}", data)]
# CP949 문자열은 정확한 경계 검출이 어려워 printable run을 보수적으로 추가한다.
for raw in re.findall(rb"(?:[\x20-\x7e\x81-\xfe]){6,}", data):
try:
text = raw.decode("cp949")
except UnicodeDecodeError:
continue
if any("" <= ch <= "" for ch in text):
found.append(text)
return list(dict.fromkeys(found))
def pe_info(data: bytes) -> dict | None:
if data[:2] != b"MZ" or len(data) < 0x40:
return None
pe = u32(data, 0x3C)
if pe + 24 > len(data) or data[pe:pe + 4] != b"PE\0\0":
return None
machine, nsec, timestamp, _, _, opt_size, characteristics = struct.unpack_from("<HHIIIHH", data, pe + 4)
opt = pe + 24
magic = u16(data, opt)
data_dir = opt + (96 if magic == 0x10B else 112)
sections = []
sec_off = opt + opt_size
for i in range(nsec):
off = sec_off + i * 40
name = data[off:off + 8].split(b"\0")[0].decode("ascii", errors="replace")
vsize, va, raw_size, raw_off = struct.unpack_from("<IIII", data, off + 8)
sections.append({"name": name, "va": va, "vsize": vsize, "raw_off": raw_off, "raw_size": raw_size})
def rva_off(rva: int) -> int | None:
for sec in sections:
if sec["va"] <= rva < sec["va"] + max(sec["vsize"], sec["raw_size"]):
return sec["raw_off"] + rva - sec["va"]
return rva if rva < len(data) else None
imports = []
if data_dir + 16 <= len(data):
imp_rva = u32(data, data_dir + 8)
imp_off = rva_off(imp_rva) if imp_rva else None
if imp_off is not None:
for i in range(512):
off = imp_off + i * 20
if off + 20 > len(data):
break
original, _, _, name_rva, thunk = struct.unpack_from("<IIIII", data, off)
if not any((original, name_rva, thunk)):
break
name_off = rva_off(name_rva)
if name_off is not None:
imports.append(cstr(data, name_off))
exports = []
if data_dir + 8 <= len(data):
exp_rva = u32(data, data_dir)
exp_off = rva_off(exp_rva) if exp_rva else None
if exp_off is not None and exp_off + 40 <= len(data):
n_names = u32(data, exp_off + 24)
names_rva = u32(data, exp_off + 32)
names_off = rva_off(names_rva)
if names_off is not None:
for i in range(min(n_names, 10000)):
name_off = rva_off(u32(data, names_off + i * 4))
if name_off is not None:
exports.append(cstr(data, name_off))
return {
"machine": f"0x{machine:04X}", "sections": sections, "imports": imports,
"exports": exports, "timestamp": timestamp, "characteristics": f"0x{characteristics:04X}",
}
def classify(data: bytes, path: Path) -> tuple[str, dict]:
pe = pe_info(data)
if pe:
return "PE", pe
if data[:2] == b"PK":
extra = {}
try:
with zipfile.ZipFile(path) as zf:
extra = {"entries": len(zf.infolist()), "encrypted": sum(bool(x.flag_bits & 1) for x in zf.infolist()), "names": [x.filename for x in zf.infolist()]}
except Exception as exc:
extra = {"zip_error": type(exc).__name__}
return "ZIP", extra
if data and data[0] in (0x02, 0x03, 0x04, 0x06, 0x30, 0x31, 0x32, 0x43, 0x63, 0x83, 0x8B, 0xCB, 0xF5, 0xE5, 0xE6, 0xFB):
if len(data) >= 32:
return "DBF-like", {"version": f"0x{data[0]:02X}", "records": u32(data, 4), "header_len": u16(data, 8), "record_len": u16(data, 10)}
if data[:2] == b"MZ":
return "DOS-MZ", {"magic": data[:16].hex()}
if data[8:16] == b"SIxMemo\0":
return "SIxMemo", {"block_size": u32(data, 4), "first_value": u32(data, 0)}
if data[:4] in (b"BTLF", b"BTCV"):
return data[:4].decode("ascii"), {"header": data[:32].rstrip(b"\0").decode("ascii", errors="replace")}
if data.lstrip().startswith((b"<?xml", b"[")) or path.suffix.lower() in (".info", ".url", ".ini", ".log") or not path.suffix:
for encoding in ("utf-8", "cp949", "latin1"):
try:
text = data.decode(encoding)
return "text", {"encoding": encoding, "lines": len(text.splitlines())}
except UnicodeDecodeError:
pass
if path.name == "ST_Tips.dat":
return "tips-data", {"utf8_html": b"<FONT" in data, "bytes": len(data)}
if path.suffix.lower() == ".stlog":
return "obfuscated-log", {"bytes": len(data)}
return "other", {"magic": data[:16].hex()}
def dbf_structure(data: bytes) -> dict:
fields, off = [], 32
while off + 32 <= len(data) and data[off] != 0x0D:
raw = data[off:off + 32]
fields.append({
"name": raw[:11].split(b"\0")[0].decode("ascii", errors="replace"),
"type": chr(raw[11]), "length": raw[16], "decimals": raw[17],
})
off += 32
return {
"version": f"0x{data[0]:02X}", "records": u32(data, 4),
"header_len": u16(data, 8), "record_len": u16(data, 10), "fields": fields,
}
def main() -> None:
if not SYSTEM.is_dir():
raise SystemExit(f"not found: {SYSTEM}")
rows, core_details, structures = [], {}, {}
for path in sorted(SYSTEM.rglob("*")):
if not path.is_file():
continue
data = path.read_bytes()
kind, detail = classify(data, path)
rel = str(path.relative_to(SYSTEM))
level = "format_checked"
if kind == "PE":
ss = strings(data)
hits = [s for s in ss if TOKENS.search(s)]
structures[rel] = {"format": kind, "pe": detail, "strings_total": len(ss), "domain_strings": hits[:1000]}
if path.name in CORE:
core_details[rel] = structures[rel]
level = "internal_structure_extracted"
elif kind == "DBF-like":
structures[rel] = {"format": kind, "dbf": dbf_structure(data)}
level = "internal_structure_extracted"
elif kind == "ZIP":
structures[rel] = {"format": kind, "zip": detail}
level = "internal_structure_extracted"
elif kind in ("DOS-MZ", "SIxMemo", "BTLF", "BTCV", "text", "tips-data", "obfuscated-log"):
structures[rel] = {"format": kind, "detail": detail, "strings": strings(data)[:1000]}
level = "internal_structure_extracted"
rows.append({
"path": rel, "bytes": len(data), "sha256": hashlib.sha256(data).hexdigest(),
"extension": path.suffix, "format": kind, "analysis_level": level,
"core": path.name in CORE, "detail_summary": json.dumps(detail if kind != "PE" else {"sections": len(detail["sections"]), "imports": len(detail["imports"]), "exports": len(detail["exports"])}, ensure_ascii=False),
})
with (OUT / "system_inventory.csv").open("w", encoding="utf-8-sig", newline="") as fh:
writer = csv.DictWriter(fh, fieldnames=rows[0].keys())
writer.writeheader(); writer.writerows(rows)
(OUT / "core_cpm_static.json").write_text(json.dumps(core_details, ensure_ascii=False, indent=2), encoding="utf-8")
(OUT / "system_structures.json").write_text(json.dumps(structures, ensure_ascii=False, indent=2), encoding="utf-8")
formula_map: dict[str, list[str]] = {}
for module, detail in core_details.items():
for text in detail["domain_strings"]:
upper = text.upper()
if any(mark in upper for mark in ("ROUNDDOWN(", "ROUNDUP(", "ROUND(", "TAMT1<>", "SUBSTR(BDCODE", 'CODE="W"')):
formula_map.setdefault(text, []).append(module)
(OUT / "core_formula_strings.json").write_text(json.dumps(formula_map, ensure_ascii=False, indent=2), encoding="utf-8")
counts = Counter(r["analysis_level"] for r in rows)
formats = Counter(r["format"] for r in rows)
assert len(rows) == 186 and len(core_details) == 12
assert sum(formats.values()) == len(rows) and len({r["path"] for r in rows}) == len(rows)
print(json.dumps({"files": len(rows), "levels": counts, "formats": formats, "core": len(core_details)}, ensure_ascii=False, default=dict))
if __name__ == "__main__":
sys.stdout.reconfigure(encoding="utf-8")
main()
@@ -0,0 +1,81 @@
"""선택한 32비트 PE export를 역어셈블하고 문자열 참조를 붙인다."""
from __future__ import annotations
import json
import struct
from pathlib import Path
from capstone import CS_ARCH_X86, CS_MODE_32, Cs
SYSTEM = Path(r"C:\경영정보(주)\System")
OUT = Path(__file__).resolve().parent / "export_disassembly.json"
TARGETS = {
"DP_Common.CPM": {"GET_ROUND_CUT", "MROUNDUD", "MROUNDUP", "MTRUNC", "MINT", "CALC_STR", "CALC_STR_PART"},
"ST_Func_C.CPM": {"CON_TOT", "SUM_TOT", "ZERO_TOT", "PCN_TO_T", "OPTIMIZ"},
r"ST_CPM\ST_KanJub.CPM": {"Calc_Kanjub"},
r"ST_CPM\ST_SanCal.CPM": {"Calq_San"},
}
def u16(b: bytes, o: int) -> int: return struct.unpack_from("<H", b, o)[0]
def u32(b: bytes, o: int) -> int: return struct.unpack_from("<I", b, o)[0]
def parse(path: Path):
b = path.read_bytes(); pe = u32(b, 0x3C); opt = pe + 24
image_base = u32(b, opt + 28); nsec = u16(b, pe + 6); opt_size = u16(b, pe + 20)
sections = []
for i in range(nsec):
o = opt + opt_size + i * 40
sections.append((u32(b, o + 12), u32(b, o + 8), u32(b, o + 20), u32(b, o + 16)))
def rva_off(rva):
for va, vs, ro, rs in sections:
if va <= rva < va + max(vs, rs): return ro + rva - va
return rva
exp = rva_off(u32(b, opt + 96)); n_names = u32(b, exp + 24)
funcs = rva_off(u32(b, exp + 28)); names = rva_off(u32(b, exp + 32)); ords = rva_off(u32(b, exp + 36))
exports = {}
for i in range(n_names):
no = rva_off(u32(b, names + i * 4)); end = b.find(b"\0", no)
name = b[no:end].decode("ascii"); ordinal = u16(b, ords + i * 2)
exports[name] = u32(b, funcs + ordinal * 4)
return b, image_base, rva_off, exports
def string_at(b: bytes, off: int) -> str | None:
if not 0 <= off < len(b): return None
for encoding in ("ascii", "cp949"):
end = b.find(b"\0", off, min(len(b), off + 300))
if end - off < 4: continue
try: text = b[off:end].decode(encoding)
except UnicodeDecodeError: continue
if all(ch.isprintable() or ch in "\r\n\t" for ch in text): return text
return None
def main():
md = Cs(CS_ARCH_X86, CS_MODE_32); md.detail = True
result = {}
for rel, wanted in TARGETS.items():
b, base, rva_off, exports = parse(SYSTEM / rel); module = {}
for name in sorted(wanted):
rva = exports.get(name)
if rva is None: continue
off = rva_off(rva); code = b[off:off + 8192]; lines = []
for i, ins in enumerate(md.disasm(code, base + rva)):
note = None
# Delphi code frequently pushes absolute addresses of ANSI strings.
for op in ins.operands:
if op.type == 2 and base <= op.imm < base + len(b) + 0x100000:
note = string_at(b, rva_off(op.imm - base))
if note: break
lines.append({"address": f"0x{ins.address:08X}", "mnemonic": ins.mnemonic, "op_str": ins.op_str, "string": note})
if ins.mnemonic.startswith("ret") or i >= 1999: break
module[name] = {"rva": f"0x{rva:X}", "instructions": lines}
result[rel] = module
OUT.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")
assert result["DP_Common.CPM"]["GET_ROUND_CUT"]["instructions"]
print({m: {f: len(x["instructions"]) for f, x in fs.items()} for m, fs in result.items()})
if __name__ == "__main__": main()
@@ -0,0 +1,136 @@
"""보유 STmate STC/XLSX에서 재구현 근거를 기계적으로 추출한다."""
from __future__ import annotations
import glob
import sys
import json
import re
import struct
import zipfile
from collections import Counter, defaultdict
from pathlib import Path
from openpyxl import load_workbook
ROOT = Path(__file__).resolve().parents[3]
SOURCE = ROOT / "resources" / "knowledge" / "original" / "실무문서"
OUT = Path(__file__).with_name("evidence_extract.json")
def dbf_rows(blob: bytes) -> list[dict[str, str | float | None]]:
count = struct.unpack("<I", blob[4:8])[0]
header_len = struct.unpack("<H", blob[8:10])[0]
record_len = struct.unpack("<H", blob[10:12])[0]
fields, offset = [], 32
while blob[offset] != 0x0D:
raw = blob[offset : offset + 32]
fields.append((raw[:11].split(b"\0")[0].decode("ascii"), chr(raw[11]), raw[16]))
offset += 32
rows = []
for number in range(count):
record = blob[header_len + number * record_len : header_len + (number + 1) * record_len]
if not record or record[0:1] == b"*":
continue
row, cursor = {}, 1
for name, kind, length in fields:
raw = record[cursor : cursor + length]
cursor += length
text = raw.decode("cp949", errors="replace").strip(" \0")
if kind in "NF":
try:
row[name] = float(text) if text else None
except ValueError:
row[name] = text
else:
row[name] = text
rows.append(row)
return rows
def normalize_formula(value: str) -> str:
value = re.sub(r"\$?[A-Z]{1,3}\$?\d+", "CELL", value.upper())
value = re.sub(r"\d+(?:\.\d+)?", "N", value)
return value
def nearby_label(ws, row: int, col: int) -> str:
values = []
for r in range(max(1, row - 1), row + 2):
for c in range(max(1, col - 5), col):
value = ws.cell(r, c).value
if isinstance(value, str) and not value.startswith("="):
value = " ".join(value.split())
if value and value not in values:
values.append(value)
return " | ".join(values[-3:])
def workbook_evidence(path: Path) -> dict:
wb = load_workbook(path, data_only=False, read_only=True)
result = {"path": str(path.relative_to(SOURCE)), "sheets": {}, "key_formulas": []}
key_words = re.compile("간접|산재|고용|건강|연금|노인|퇴직|안전|환경|기타경비|일반관리|이윤|부가가치|관급|중기|일위|시장|견적")
for ws in wb.worksheets:
formulas, kinds = [], Counter()
for row in ws.iter_rows():
for cell in row:
value = cell.value
if isinstance(value, str) and value.startswith("="):
formulas.append((cell.coordinate, value))
kinds[normalize_formula(value)] += 1
label = nearby_label(ws, cell.row, cell.column)
if key_words.search(label) or key_words.search(ws.title):
result["key_formulas"].append({"sheet": ws.title, "cell": cell.coordinate, "label": label, "formula": value})
if formulas:
result["sheets"][ws.title] = {
"formula_count": len(formulas),
"top_patterns": kinds.most_common(12),
"cross_sheet_count": sum("!" in formula for _, formula in formulas),
}
return result
def stc_evidence(path: Path) -> dict:
with zipfile.ZipFile(path) as zf:
rate = {name: dbf_rows(zf.read(name)) for name in ("RATE.DBF", "RATE_M.DBF", "RATE_R.DBF", "RATE_RA.DBF")}
costn = dbf_rows(zf.read("COSTN.DBF"))
boq_names = sorted(name for name in zf.namelist() if re.fullmatch(r"BOQ\d\d\.DBF", name.upper()))
boq = {name: dbf_rows(zf.read(name)) for name in boq_names}
source_stats = defaultdict(lambda: {"count": 0, "selected_match": Counter()})
for row in costn:
code = str(row.get("CODE") or "")[:1]
adopted = row.get("TAMT1")
if adopted is None:
adopted = row.get("AMT1")
source_stats[code]["count"] += 1
for slot in range(1, 7):
candidates = [row.get(f"AMT_{slot}1"), row.get(f"AMT{slot}1"), row.get(f"AMT_{slot}")]
if adopted is not None and adopted in candidates:
source_stats[code]["selected_match"][str(slot)] += 1
return {
"path": str(path.relative_to(SOURCE)),
"rate": rate,
"costn_fields": list(costn[0]) if costn else [],
"costn_source_stats": {k: {"count": v["count"], "selected_match": dict(v["selected_match"])} for k, v in source_stats.items()},
"boq_tables": {name: {"rows": len(rows), "fields": list(rows[0]) if rows else []} for name, rows in boq.items()},
}
def main() -> None:
stcs = [Path(p) for p in glob.glob(str(SOURCE / "**" / "*.STC"), recursive=True)]
likely = []
for p in glob.glob(str(SOURCE / "**" / "*.xlsx"), recursive=True):
path = Path(p)
name = path.name
if any(token in name for token in ("간선임도사업(기번3)", "산불진화임도 실시설계", "임도시설사업2차", "계류보전사업(기번1 영덕", "산불진화임도 신설사업(기번8 울진")):
likely.append(path)
mode = sys.argv[1] if len(sys.argv) > 1 else "all"
data = {
"stc": [stc_evidence(p) for p in sorted(stcs)] if mode in ("all", "stc") else [],
"xlsx": [workbook_evidence(p) for p in sorted(likely)] if mode in ("all", "xlsx") else [],
}
OUT.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
print(f"STC={len(stcs)} XLSX={len(likely)} -> {OUT}")
if __name__ == "__main__":
main()
@@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
"""JB 43개를 연도축으로 겹쳐 셀 사용패턴으로 블록 경계를 찾는다. 원본은 읽기만."""
import pathlib, struct, sys, io, collections
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
ROOT = pathlib.Path(r"C:\경영정보(주)\System\ST_BSC")
def read_dbf(p):
b = p.read_bytes()
nrec, hlen, rlen = struct.unpack_from("<IHH", b, 4)
flds=[]; off=32
while b[off] != 0x0D:
flds.append((b[off:off+11].rstrip(b"\0").decode("cp949","replace"), b[off+16])); off += 32
rows=[]
for i in range(nrec):
ro = hlen + i*rlen; rec = b[ro:ro+rlen]
if len(rec) < rlen: break
vals=[]; c=1
for nm, ln in flds:
s = rec[c:c+ln].decode("cp949","replace").strip(); c += ln
try: vals.append(float(s) if s else 0.0)
except ValueError: vals.append(0.0)
rows.append(vals)
return [f[0] for f in flds], rows
groups = collections.defaultdict(list)
for p in sorted(ROOT.glob("*.JB_*")):
groups[p.suffix.upper()].append(p)
for ext, files in sorted(groups.items()):
shapes = collections.Counter()
data = []
for p in files:
flds, rows = read_dbf(p)
shapes[(len(rows), len(flds))] += 1
data.append((p.name, flds, rows))
print("\n" + "="*112)
print("### %s 파일 %d개 형태: %s" % (ext, len(files), dict(shapes)))
# 형태별로 다시 가름
byshape = collections.defaultdict(list)
for nm, flds, rows in data: byshape[(len(rows), len(flds))].append((nm, rows))
for shape, items in sorted(byshape.items()):
R, C = shape
used = [[0]*C for _ in range(R)] # 몇 개 파일에서 이 셀이 0이 아닌가
varies = [[set() for _ in range(C)] for _ in range(R)]
for nm, rows in items:
for r in range(R):
for c in range(C):
v = rows[r][c]
if v: used[r][c] += 1
varies[r][c].add(round(v, 4))
print("\n-- 형태 %d× %d열 (%d개 파일)" % (R, C, len(items)))
print(" 행별 '값이 든 열' 지도 (· 없음 / 숫자=몇 개 파일에 값 있음, 최대 %d)" % len(items))
hdr = "" + "".join(("%d"%((c+1)//10) if (c+1)>=10 else " ") for c in range(C))
print(hdr); print(" " + "".join(str((c+1)%10) for c in range(C)))
for r in range(R):
line = "".join(("·" if used[r][c]==0 else ("#" if used[r][c]==len(items) else "+")) for c in range(C))
nz = sum(1 for c in range(C) if used[r][c])
print(" %2d %s%d" % (r, line, nz))
@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
import pathlib, struct, sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
ROOT = pathlib.Path(r"C:\경영정보(주)\System\ST_BSC")
def rd(p):
b=p.read_bytes(); nrec,hlen,rlen=struct.unpack_from("<IHH",b,4)
f=[];o=32
while b[o]!=0x0D: f.append((b[o:o+11].rstrip(b"\0").decode("cp949","replace"),b[o+16]));o+=32
R=[]
for i in range(nrec):
r=b[hlen+i*rlen:hlen+(i+1)*rlen]
if len(r)<rlen: break
v=[];c=1
for nm,ln in f:
s=r[c:c+ln].decode("cp949","replace").strip();c+=ln
try:v.append(float(s) if s else 0.0)
except:v.append(0.0)
R.append(v)
return [x[0] for x in f], R
fo,Ro = rd(ROOT/"2020(상_0102)_제비율.JB_R")
fn,Rn = rd(ROOT/"2020(상_0527)_제비율.JB_R")
print("2020-01-02 (20열) vs 2020-05-27 (35열) — 5개월 차, 같은 해")
d=[(r,c+1,Ro[r][c],Rn[r][c]) for r in range(50) for c in range(20) if abs(Ro[r][c]-Rn[r][c])>1e-9]
print("\n1~20열에서 값이 달라진 셀 %d" % len(d))
for r,c,a,b2 in d[:25]: print("%2d%-2d %g -> %g" % (r,c,a,b2))
print("\n21~35열(새로 생긴 열)에서 값이 든 자리")
rows={}
for r in range(50):
h=[(c+1,Rn[r][c]) for c in range(20,35) if Rn[r][c]]
if h: rows[r]=h
for r,h in rows.items(): print("%2d : %s" % (r, " ".join("%d=%g"%x for x in h)))
print("\n새 열 중 실제로 쓰인 열 번호: %s" % sorted({c for h in rows.values() for c,_ in h}))
print("새 열에 값이 든 행 번호: %s" % sorted(rows))
@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
import pathlib, struct, sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
ROOT = pathlib.Path(r"C:\경영정보(주)\System\ST_BSC")
for p in sorted(ROOT.glob("*.JB_*")):
b=p.read_bytes(); nrec,hlen,rlen=struct.unpack_from("<IHH",b,4)
n=0;o=32
while b[o]!=0x0D: n+=1;o+=32
print("%-46s %s %2d행 x %2d열 rec=%dB" % (p.name, p.suffix, nrec, n, rlen))
@@ -0,0 +1,137 @@
import json
import struct
import sys
from pathlib import Path
class Reader:
def __init__(self, data: bytes):
self.data = data
self.pos = 0
def take(self, size: int) -> bytes:
value = self.data[self.pos : self.pos + size]
if len(value) != size:
raise EOFError(self.pos)
self.pos += size
return value
def byte(self) -> int:
return self.take(1)[0]
def short_string(self) -> str:
raw = self.take(self.byte())
for encoding in ("cp949", "utf-8", "latin1"):
try:
return raw.decode(encoding)
except UnicodeDecodeError:
pass
return raw.hex()
def integer(self) -> int:
kind = self.byte()
formats = {2: "<b", 3: "<h", 4: "<i", 19: "<q"}
if kind not in formats:
raise ValueError((self.pos - 1, "integer", kind))
fmt = formats[kind]
return struct.unpack(fmt, self.take(struct.calcsize(fmt)))[0]
def value(self):
kind = self.byte()
if kind == 0:
return None
if kind == 1:
values = []
while self.data[self.pos] != 0:
values.append(self.value())
self.pos += 1
return values
if kind in (2, 3, 4, 19):
self.pos -= 1
return self.integer()
if kind == 5:
return {"extended_hex": self.take(10).hex()}
if kind in (6, 7):
return self.short_string()
if kind == 8:
return False
if kind == 9:
return True
if kind == 10:
size = struct.unpack("<i", self.take(4))[0]
return {"binary_size": size, "binary_hex": self.take(size).hex()[:64]}
if kind == 11:
values = []
while True:
item = self.short_string()
if not item:
return values
values.append(item)
if kind in (12, 20):
size = struct.unpack("<i", self.take(4))[0]
raw = self.take(size)
encoding = "utf-8" if kind == 20 else "cp949"
return raw.decode(encoding, errors="replace")
if kind == 13:
return None
if kind == 14:
items = []
while self.data[self.pos] != 0:
if self.byte() != 1:
raise ValueError((self.pos - 1, "collection item"))
props = self.properties()
items.append(props)
self.pos += 1
return items
if kind == 15:
return struct.unpack("<f", self.take(4))[0]
if kind in (16, 17, 21):
raw = self.take(8)
return struct.unpack("<d", raw)[0] if kind in (17, 21) else {"currency_raw": raw.hex()}
if kind == 18:
size = struct.unpack("<i", self.take(4))[0]
return self.take(size * 2).decode("utf-16le", errors="replace")
raise ValueError((self.pos - 1, "value", kind))
def properties(self) -> dict:
props = {}
while True:
name = self.short_string()
if not name:
return props
props[name] = self.value()
def component(self, root=False) -> dict:
flags = []
child_pos = None
class_name = self.short_string()
name = self.short_string()
props = self.properties()
children = []
while self.data[self.pos] != 0:
children.append(self.component())
self.pos += 1
return {
"class": class_name,
"name": name,
"flags": flags,
"child_pos": child_pos,
"properties": props,
"children": children,
}
def parse(path: Path) -> dict:
reader = Reader(path.read_bytes())
assert reader.take(4) == b"TPF0"
result = reader.component(root=True)
assert reader.pos == len(reader.data), (reader.pos, len(reader.data))
return result
if __name__ == "__main__":
for argument in sys.argv[1:]:
source = Path(argument)
output = source.with_suffix(".json")
output.write_text(json.dumps(parse(source), ensure_ascii=False, indent=2), encoding="utf-8")
print(output)
@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
import json, sys, io, pathlib
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
BASE = pathlib.Path(__file__).resolve().parent.parent / "30_원자료"
d = json.load(open(BASE/"TWM_KAN_RATE.json", encoding="utf-8"))
order = []
def walk(n, parent=""):
if isinstance(n, dict):
if n.get("class") == "TRealGrid": order.append((n.get("name"), parent, n.get("properties") or {}))
for c in n.get("children",[]) or []: walk(c, n.get("name",""))
walk(d)
print("폼 자식 순서대로 나열한 RATE 편집 그리드")
print("="*112)
tot = {}
for nm, parent, pr in order:
cols = pr.get("Columns") or []
grps = pr.get("Groups") or []
rc = pr.get("RowCount")
titles = [ (c.get("Title.Caption") or "").replace("\r"," / ").strip() for c in cols ]
gtit = [ (g.get("Title.Caption") or "").replace("\r"," / ").strip() for g in grps ]
tot.setdefault(parent, 0)
tot[parent] += rc or 0
print("\n%-18s parent=%-10s RowCount=%-3s%d" % (nm, parent, rc, len(cols)))
for g in gtit: print(" [묶음] %s" % g)
print(" 열: " + " | ".join(t if t else "(무제목)" for t in titles))
print("\n" + "="*112)
print("패널별 행수 합계:")
for k, v in tot.items(): print(" %-12s %d" % (k, v))
@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
"""Delphi 6 Math.RoundTo 재현 vs Excel ROUND 비교표."""
import sys, io, decimal
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
D = decimal.Decimal
def delphi_intpower(base, e):
# Delphi Math.IntPower: 반복 제곱 후 음수 지수면 역수
r = 1.0; n = abs(e); b = float(base)
while n:
if n & 1: r *= b
b *= b; n >>= 1
return 1.0/r if e < 0 else r
def delphi_roundto(v, adigit):
f = delphi_intpower(10.0, adigit)
# Delphi Round() = FPU 현재모드 = 기본 half-to-even (파이썬 round 와 같음)
return round(v / f) * f
def excel_round(v, places):
q = D(1).scaleb(-places)
return float(D(repr(v)).quantize(q, rounding=decimal.ROUND_HALF_UP))
def excel_rounddown(v, places):
q = D(1).scaleb(-places)
return float(D(repr(v)).quantize(q, rounding=decimal.ROUND_DOWN))
CASES = [(2.44,1),(2.45,1),(2.46,1),(-2.44,1),(-2.45,1),(-2.46,1),
(0.5,0),(1.5,0),(2.5,0),(3.5,0),(-0.5,0),(-1.5,0),(-2.5,0),(-3.5,0),
(1250.0,-2),(1350.0,-2),(-1250.0,-2),(2500.0,-3),(3500.0,-3),(-2500.0,-3)]
print("| 입력 | 자리 | STmate 내부 `ROUND`\n(Delphi `Math.RoundTo`) | Excel `ROUND`\n(STmate 출력 XLSX) | 일치 |")
print("|---:|---:|---:|---:|:--:|")
diff = 0
for v, places in CASES:
adigit = -places # RoundTo 의 ADigit 는 10의 지수
d = delphi_roundto(v, adigit)
x = excel_round(v, places)
ok = abs(d - x) < 1e-9
if not ok: diff += 1
print("| %s | %s | %s | %s | %s |" % (
("%g"%v), ("소수%d"%places if places>0 else ("" if places==0 else "%d"%(10**-places))),
("%g"%d), ("%g"%x), "" if ok else "**✗**"))
print("\n불일치 %d / %d" % (diff, len(CASES)))
@@ -0,0 +1,109 @@
# -*- coding: utf-8 -*-
"""STmate CPM 모듈에서 Math.RoundTo / Math.Floor 임포트 썽크의 실제 호출 자리를 센다."""
import pathlib, struct, re, sys
ROOT = pathlib.Path(r"C:\경영정보(주)\System")
TARGETS = ["ST_KanJub.CPM","ST_SanCal.CPM","ST_Boq.CPM","ST_EdiLWi.CPM","ST_P_Joong.CPM","ST_Prt.CPM"]
WANT = {b"@Math@RoundTo$qqrxdxzc":"RoundTo", b"@Math@Floor$qqrxg":"Floor",
b"@Math@Ceil$qqrxg":"Ceil", b"@Math@SimpleRoundTo$qqrxdxzc":"SimpleRoundTo",
b"@Math@SetRoundMode$qqrx21Math":"SetRoundMode"}
def pe(b):
e = struct.unpack_from("<I", b, 0x3C)[0]
assert b[e:e+4] == b"PE\0\0"
nsec = struct.unpack_from("<H", b, e+6)[0]
optsz = struct.unpack_from("<H", b, e+20)[0]
opt = e+24
magic = struct.unpack_from("<H", b, opt)[0]
imgbase = struct.unpack_from("<I", b, opt+28)[0]
ddoff = opt + (96 if magic==0x10b else 112)
imp_rva, imp_sz = struct.unpack_from("<II", b, ddoff+8)
secs=[]
so = opt+optsz
for i in range(nsec):
s = b[so+i*40: so+i*40+40]
name = s[:8].rstrip(b"\0").decode("latin1")
vsz, va, rsz, ptr = struct.unpack_from("<IIII", s, 8)
secs.append((name, va, vsz, ptr, rsz))
return imgbase, imp_rva, secs
def r2o(rva, secs):
for n,va,vsz,ptr,rsz in secs:
if va <= rva < va+max(vsz,rsz): return ptr + (rva-va)
return None
for t in TARGETS:
ps = list(ROOT.rglob(t))
if not ps: print("!! %s 없음"%t); continue
b = ps[0].read_bytes()
imgbase, imp_rva, secs = pe(b)
io_ = r2o(imp_rva, secs)
found = {}
off = io_
while True:
oft, tds, fwd, nm, fth = struct.unpack_from("<IIIII", b, off)
if nm == 0: break
thunk_rva = oft or fth
to = r2o(thunk_rva, secs); io2 = r2o(fth, secs)
i = 0
while True:
v = struct.unpack_from("<I", b, to + 4*i)[0]
if v == 0: break
if not (v & 0x80000000):
no = r2o(v, secs)
nmend = b.index(b"\0", no+2)
sym = b[no+2:nmend]
if sym in WANT:
found[WANT[sym]] = imgbase + fth + 4*i # IAT 절대주소
i += 1
off += 20
txt = [(n,va,vsz,ptr,rsz) for n,va,vsz,ptr,rsz in secs if n.upper() in ("CODE",".TEXT")]
print("\n### %s (imagebase 0x%X)" % (t, imgbase))
if not found: print(" Math 임포트 없음"); continue
for sym, iat in sorted(found.items()):
pat = b"\xFF\x15" + struct.pack("<I", iat)
total = 0
for n,va,vsz,ptr,rsz in txt:
total += b.count(pat, ptr, ptr+rsz)
pat2 = b"\xFF\x25" + struct.pack("<I", iat) # 썽크 jmp
thunks = b.count(pat2)
print(" %-14s IAT=0x%08X 직접 call %d곳, jmp 썽크 %d" % (sym, iat, total, thunks))
print("\n\n========== 썽크 경유 호출(E8 rel32) 집계 ==========")
for t in TARGETS:
ps = list(ROOT.rglob(t))
if not ps: continue
b = ps[0].read_bytes()
imgbase, imp_rva, secs = pe(b)
io_ = r2o(imp_rva, secs); off = io_; found = {}
while True:
oft, tds, fwd, nm, fth = struct.unpack_from("<IIIII", b, off)
if nm == 0: break
to = r2o(oft or fth, secs); i = 0
while True:
v = struct.unpack_from("<I", b, to+4*i)[0]
if v == 0: break
if not (v & 0x80000000):
no = r2o(v, secs); sym = b[no+2:b.index(b"\0", no+2)]
if sym in WANT: found[WANT[sym]] = imgbase + fth + 4*i
i += 1
off += 20
code = [(n,va,vsz,ptr,rsz) for n,va,vsz,ptr,rsz in secs if n.upper() in ("CODE",".TEXT")]
print("\n### %s" % t)
for sym, iat in sorted(found.items()):
pat = b"\xFF\x25" + struct.pack("<I", iat)
k = b.find(pat)
if k < 0: print(" %-10s 썽크 못 찾음" % sym); continue
# 썽크 파일오프셋 -> VA
thunk_va = None
for n,va,vsz,ptr,rsz in secs:
if ptr <= k < ptr+rsz: thunk_va = imgbase + va + (k-ptr); break
calls = 0
for n,va,vsz,ptr,rsz in code:
for m in re.finditer(b"\xE8", b[ptr:ptr+rsz]):
o = ptr + m.start()
if o+5 > ptr+rsz: continue
rel = struct.unpack_from("<i", b, o+1)[0]
site_va = imgbase + va + (o-ptr)
if site_va + 5 + rel == thunk_va: calls += 1
print(" %-10s 썽크VA=0x%08X 호출 %d" % (sym, thunk_va, calls))
@@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
import pathlib, struct, re, sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
ROOT = pathlib.Path(r"C:\경영정보(주)\System")
b = list(ROOT.rglob("ST_KanJub.CPM"))[0].read_bytes()
e = struct.unpack_from("<I", b, 0x3C)[0]
nsec = struct.unpack_from("<H", b, e+6)[0]; optsz = struct.unpack_from("<H", b, e+20)[0]
opt = e+24; imgbase = struct.unpack_from("<I", b, opt+28)[0]
secs=[]; so=opt+optsz
for i in range(nsec):
s=b[so+i*40:so+i*40+40]; nm=s[:8].rstrip(b"\0").decode("latin1")
vsz,va,rsz,ptr=struct.unpack_from("<IIII", s, 8); secs.append((nm,va,vsz,ptr,rsz))
def v2o(v):
for n,va,vsz,ptr,rsz in secs:
if imgbase+va <= v < imgbase+va+rsz: return ptr+(v-imgbase-va)
START, END = 0x0043A200, 0x0043A400
o1, o2 = v2o(START), v2o(END)
blk = b[o1:o2]
print("=== ST_KanJub.CPM 0x%08X..0x%08X (RoundTo 12곳이 몰린 함수) ===" % (START, END))
# mov dl, imm8 (B2 xx) = RoundTo 두번째 인자(자리수, signed char)
digits = [(START+m.start(), struct.unpack_from("<b", blk, m.start()+1)[0]) for m in re.finditer(b"\xB2", blk)]
print("\nRoundTo 2번째 인자(자리수) 로드 — `mov dl, imm8`:")
for va, d in digits: print(" 0x%08X 자리수 = %d" % (va, d))
IDIOM = {
b"\xD9\x7D": "FNSTCW [ebp-x] (FPU 제어워드 저장)",
b"\xD9\x6D": "FLDCW [ebp-x] (FPU 제어워드 로드 = 모드 변경)",
b"\xDB\x5D": "FISTP dword (정수 저장, 현재 모드 적용)",
b"\xDF\x7D": "FISTP qword",
b"\xD9\xE0": "FCHS", b"\xD9\xE1": "FABS", b"\xD9\xFC": "FRNDINT",
}
print("\n이 구간의 x87 모드/정수화 관용구:")
seen = {}
for pat, desc in IDIOM.items():
n = blk.count(pat)
if n: print(" %-3s x %s" % (n, desc))
if not any(blk.count(p) for p in IDIOM): print(" 없음")
print("\n원시 바이트 (16B/줄):")
for i in range(0, len(blk), 16):
print("0x%08X %s" % (START+i, " ".join("%02X"%c for c in blk[i:i+16])))
@@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
import pathlib, re, collections
ROOT = pathlib.Path(r"C:\경영정보(주)\System")
SYMS = {
"RoundTo": rb"@Math@RoundTo\$qqrxdxzc",
"SimpleRoundTo":rb"@Math@SimpleRoundTo\$qqrxdxzc",
"Floor": rb"@Math@Floor\$qqrxg",
"Ceil": rb"@Math@Ceil\$qqrxg",
"SetRoundMode": rb"@Math@SetRoundMode\$",
"IntPower": rb"@Math@IntPower\$",
"MROUNDUD": rb"MROUNDUD",
"MROUNDUP": rb"MROUNDUP",
"MTRUNC": rb"MTRUNC",
"MINT": rb"\x00MINT\x00",
"GET_ROUND_CUT":rb"GET_ROUND_CUT",
"CALC_STR": rb"CALC_STR",
"ROUNDDOWN": rb"ROUNDDOWN",
"ROUNDUP": rb"ROUNDUP",
"ROUND(": rb"ROUND\(",
}
order = list(SYMS)
rows = []
for p in sorted(ROOT.rglob("*")):
if not p.is_file(): continue
try: b = p.read_bytes()
except Exception: continue
if b[:2] != b"MZ": continue
c = {k: len(re.findall(v, b)) for k, v in SYMS.items()}
if c["RoundTo"] or c["Floor"] or c["MROUNDUD"] or c["GET_ROUND_CUT"] or c["MTRUNC"] or c["MINT"]:
rows.append((p.name, c))
w = max(len(r[0]) for r in rows)
hdr = "모듈".ljust(w) + " " + " ".join(s[:7].rjust(7) for s in order)
print(hdr); print("-"*len(hdr))
for name, c in sorted(rows, key=lambda r: -sum(r[1].values())):
print(name.ljust(w) + " " + " ".join(str(c[s] or "").rjust(7) for s in order))
@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
"""원가계산 설정을 4형식(_T/_S/_TA/_SA)과 패널로 갈라 정리한다."""
import json, sys, io, pathlib, re, collections
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
BASE = pathlib.Path(__file__).resolve().parent.parent / "30_원자료"
d = json.load(open(BASE/"TWM_KANJUB.json", encoding="utf-8"))
def walk(n, parent="", out=None):
if out is None: out=[]
if isinstance(n, dict):
out.append((n.get("class",""), n.get("name",""), n.get("properties") or {}, parent))
for c in n.get("children",[]) or []: walk(c, n.get("name",""), out)
return out
nodes = walk(d)
def get(pr, suffix):
for k, v in pr.items():
if k.lower().endswith(suffix): return v
return None
FORM = {"_T":"일반 T", "_S":"수공 S", "_TA":"실적일반 TA", "_SA":"실적수공 SA"}
def form_of(nm):
for suf in ("_TA","_SA","_T","_S"):
if nm.endswith(suf): return FORM[suf]
return "공통"
rows = collections.defaultdict(list)
for cls, nm, pr, parent in nodes:
items = get(pr, "items.strings") or (pr.get("Items") if isinstance(pr.get("Items"), list) else None)
if not items: continue
vals = get(pr, "values.strings")
rows[form_of(nm)].append((nm, parent, [str(x).strip() for x in items],
[str(x).strip() for x in vals] if isinstance(vals, list) else None))
print("### 원가계산 설정 — 형식별 선택축")
for f in ["공통","일반 T","수공 S","실적일반 TA","실적수공 SA"]:
if f not in rows: continue
print("\n" + "="*100)
print("## %s 선택축 %d" % (f, len(rows[f])))
for nm, parent, items, vals in rows[f]:
mismatch = " ⚠개수불일치(선택지%d/내부값%d)" % (len(items), len(vals)) if vals and len(vals)!=len(items) else ""
# 화면문자열과 내부값이 다른 축만 상세 표시
differ = vals and any(a != b for a, b in zip(items, vals))
print("\n%-20s (%s) %d%s%s" % (nm, parent, len(items), mismatch, " ※화면≠내부" if differ else ""))
for i, s in enumerate(items):
v = vals[i] if vals and i < len(vals) else None
if v is not None and v != s: print(" %2d %-40s → 내부 `%s`" % (i, s[:40], v))
else: print(" %2d %s" % (i, s[:60]))
if vals and len(vals) > len(items):
print(" ▶ 화면에 없는 내부값: %s" % vals[len(items):])
@@ -0,0 +1,73 @@
# STmate 분석
경쟁사 설계예산 프로그램 **STmate**(경영정보(주)) 를 정적으로 뜯어본 기록.
원본은 저장소 밖 `C:\경영정보(주)`**원본은 손대지 않음**, 여기에만 정리물을 둠.
옆 폴더 `../오솔길 분석/` 과 같은 얼개.
> ⚠ `resources/knowledge/original/원가계산/STmate/`**다른 것** — 그쪽은 STmate 가 **뽑아낸 산출물**(STC·XLSX)을 뜯어본 기록이고, 여기는 **프로그램 자체**를 뜯어본 기록임.
## STmate 가 무엇인가
- **Delphi 6 네이티브 데스크톱 프로그램.** 캐드 플러그인 아님. 본체 `STmate.Cpm` + 기능별 `*.CPM` 플러그인 수십 개.
- 저장소는 **Apollo/Six 계열 DBF**, 교환 파일은 **ZIP 기반 `.STC`**.
- 하는 일 — 기초 단가·코드 자료로 일위대가·단가산출을 조립하고, 공종 수량을 곱해 내역을 만들고, 제비율·법정경비·일반관리비·이윤·부가세를 얹어 총공사비를 냄.
- 실행은 확인 못 함(프로세스가 창을 안 띄움). **파일·바이너리 정적 분석으로만** 확인한 것임.
## 어디까지 봤나 — 세 겹
| 겹 | 무엇을 함 | 볼 수 있나 |
| --- | --- | --- |
| **계산 코어** (`*.CPM` 실행모듈) | 식 평가, 반올림, 간접비·안전비·변경설계·끝전조정 | ⚠ 부분 — PE 섹션·임포트·문자열·호출자리까지. 명령어 단위 역공학은 안 함 |
| **기준자료·프로젝트 파일** (DBF·STC·XLSX) | 요율표, 단가, 수량, 결과 금액 | ✅ 전부 읽힘 |
| **화면 폼 리소스** (DFM) | 그리드 열 제목, 선택지와 내부 코드값, **밑수 공식** | ✅ 복원 완료 — 이번 분석의 최대 수확 |
**「어느 명령어가 언제 도는가」는 못 보고, 「어떤 값에 어떤 밑수와 어떤 반올림이 걸리는가」는 대부분 보임.**
## 문서 — `20_분석/`
읽는 순서는 **`14_최종_분석완료_보고서.md` 부터**가 빠름. 전체 인덱스는 `00_분석_요약과_읽는법.md` 에 있음.
| 번호 | 내용 |
| --- | --- |
| 00 | 전체 인덱스, 결론, Aislo 비교, 등급 갱신 이력, 용어 대조 |
| 01~02 | 실행 기술·모듈 구조, DBF 스키마·파일형식 |
| 03~04 | 계산로직과 Aislo 비교, 입력 → 결과 데이터 계보 |
| 05 | 확정등급 기준, 조사 표본, 중간값 계약 |
| 06~08 | 내부규칙 아홉 — RATE·간접비·끝전 / 직접비·단가·중기·자재 / 재계산·변경설계·일괄변경 |
| 09 | 통합 재구현 명세 |
| 10 | `System` 186개 전수 장부 |
| 11 | CPM 계산코어 정적분석 — **반올림 경계표** |
| 12 | 원가계산 4형식과 RATE표 복원 — **설정 83축** |
| 13 | 통제시험 목록 T1~T11 — 아직 못 가른 경계 |
| 14 | 최종 분석완료 보고서 |
## 확정된 굵직한 것
- `TAMT = MAMT + LAMT + SAMT` — 총액은 네 번째 성분이 아니라 **세 성분의 합**
- **내부 반올림은 은행가 반올림**(최근접-짝수)이고 사사오입이 아님. STmate 가 뽑은 엑셀은 Excel 사사오입이라 **20개 경계 중 10개가 원 단위에서 갈림**
- **간접비 항목별 밑수**를 화면 그리드 묶음 제목에서 확정 — 환경보전비 밑수는 직접공사비가 아님
- 원가계산 **네 형식**(일반·수공·실적일반·실적수공)은 출력 모양이 아니라 **공식 집합이 통째로 다름**
- 기준자료 `JB_R` 35열 확장 시점 **2020-05-27**, 기존 1~20열은 한 칸도 안 바뀜
- 설정 **83축** 전수. 화면 순번과 내부값이 **뒤집힌 축 둘** 있음 — 그대로 저장하면 정반대 공식이 걸림
## 원자료 — `30_원자료/`
`system_inventory.csv`(186개 해시 장부) · `system_structures.json`(전 파일 내부구조) · `core_cpm_static.json` · `export_disassembly.json` · `core_formula_strings.json` · 복원한 폼 세 벌(`.dfm`/`.json`) · 문자열 덤프 · `settings_axis_map.txt`.
## 재현 스크립트 — `40_스크립트/`
전부 `C:\경영정보(주)`**읽기만** 함. 원자료는 `../30_원자료/` 를 봄.
| 스크립트 | 하는 일 |
| --- | --- |
| `analyze_system.py` | 186개 전수 등록·해시·형식 판정 |
| `evidence_extract.py` · `disassemble_exports.py` | 계산식·export 추출 |
| `parse_dfm.py` | 폼 리소스 → JSON |
| `rounding_symbol_matrix.py` · `rounding_callsites.py` · `rounding_dispatcher_dump.py` | 반올림 심볼 임포트·호출자리·함수 덤프 |
| `round_table.py` | 내부 ↔ Excel 반올림 경계표 |
| `jb_shapes.py` · `jb_block_map.py` · `jb_expansion_diff.py` | JB 43개 형태·블록·확장 차이 |
| `rate_grid_defs.py` · `settings_axis_map.py` | 폼에서 그리드·선택축 추출 |
## 다음
`13_통제시험_목록.md` 의 T1~T11. **프로그램을 직접 돌려 값 하나씩 바꿔 보는 일**이라 정적 분석으로는 못 가름. 우선순위 1은 T1(요율 좌표 매핑).