비운영 참조

이웃에게 빌리기

공간·시간 스플라인 GAM · gam-spline-v1

한 줄 결론 — 가까운 정류장과 시간을 함께 쓰는 후보다. 현재 좌석은 보지 않고, 채택되지 못한 채 2026-08-19 결정으로 비운영 참조가 됐다.

왜 믿나

잠정 · 아직 순위 근거가 아니다

일일 평가가 전날까지의 관측을 매일 새로 채점해 왔다. 비교 관문(관측일 10일·만석 100건)을 채우기 전이라 점수와 지표는 점추정으로만 읽는다. 재표본 불확실성 범위는 만들지 않았다.

이 모델의 일일 채점은 2026-08-19 평가일까지로 끝났다. 08번(A18)을 단일 운영 모델로 확정하며 evaluation-v3에서 도입한 결정이고, 현재 evaluation-v6도 이어받는다. 새 점수는 만들지 않으며 마지막 값과 중단 시점은 이력에 남는다.

숫자의 원장은 일일 평가 API 하나다. 이 페이지는 열릴 때 한 번 최신 값을 받아오고, 실패하면 배포 시점 값이 남는다. 기준 시점은 아래 스탬프가 말한다. 평가 ID와 해시는 맨 아래 출처 장부에 모았다.

동결 이력 성적

상태 잠정

종합 점수
22.0
평가 관측일
2일 / 10일
만석 누적
173건 / 100건
만석 관측일
2일 / 5일
지표오늘 값읽는 법 한 줄
얼마나 빗나갔나 (Brier)0.0139예측확률과 실제 0·1 차이의 제곱 평균. 낮을수록 좋다.
만석 누락률 (Miss rate)100.0%실제 만석 중 확률을 50% 미만으로 말한 비율. 낮을수록 좋다.
가르는 힘 (ROC-AUC)0.585만석·비만석 한 쌍에서 만석 쪽에 더 높은 확률을 줄 가능성. 높을수록 좋다.
확신하고 틀린 벌점 (Log loss)0.0761확신한 예측이 틀릴수록 커지는 벌점. 낮을수록 좋다.
누적 확률 오차 (ECCE-MAD)0.0273예측확률 순서로 오차를 쌓았을 때 가장 크게 벌어진 정도. 낮을수록 좋다.
드문 만석을 찾는 힘 (PR-AUC)0.012드문 만석을 위쪽으로 모으는 힘. 높을수록 좋다.
확률 쏠림 (Calibration bias)0.0273평균 예측확률에서 실제 만석률을 뺀 값. 0에 가까울수록 좋다.
잘못 안심 비용 1:10.0096잘못 안심과 과한 경고를 같은 비용으로 본 평균. 같은 가정끼리 비교한다.
잘못 안심 비용 2:10.0234잘못 안심을 과한 경고의 2배 비용으로 본 평균. 같은 가정끼리 비교한다.
잘못 안심 비용 4:10.0796잘못 안심을 과한 경고의 4배 비용으로 본 평균. 같은 가정끼리 비교한다.

점수 50 = 시간순 과거 만석률 기준 모델 · 자세한 기준은 평가 규약

구간별 동결 이력 성적

구간행만석Brier만석 누락ROC-AUC
주말18,0551730.0139100.0%0.585
출근2,70200.0006——
퇴근4,195120.0072100.0%0.648
그 외11,1581610.0196100.0%0.579
노선 16507,5321600.0245100.0%0.532
노선 333010,523130.0063100.0%0.832
노선 1650·출근97000.0004——
노선 1650·퇴근1,694120.0101100.0%0.635
노선 1650·그 외4,8681480.0343100.0%0.511
노선 3330·출근1,73200.0007——
노선 3330·퇴근2,50100.0052——
노선 3330·그 외6,290130.0082100.0%0.848

평가 행이 없는 구간 1개: 평일

배포 시점 값 · 일일 평가 2026-08-16분 · 생성 08-17 00:15 KST

Q. 이 모델은 지금 무엇을 계산하나?

현재 시각과 목표 정류장을 기준으로, 다음 버스가 그 정류장을 출발한 직후 남은 좌석이 0일 확률을 계산한다.

Q. 어떻게 계산하나?

정류장과 시간 좌표를 만든다

응답 수신시각을 한국 표준시 하루 안의 주기형 좌표로 바꾸고 목표 정류장을 노선별 전체 순서에서 0과 1 사이의 위치에 놓는다.

가까운 값을 연결한다

정류장축에는 경첩형 스플라인 항을, 시간축에는 주기형 사인·코사인 항을 만든다. 노선마다 정류장 곡선이 다를 수 있지만 정류장과 시간의 임의 조합을 만들지는 않는다.

지나친 굴곡을 누른다

앞선 날짜의 학습 자료만 사용해 정류장 항과 시간 항을 더하는 벌점 로지스틱 GAM을 적합한다. 기저와 벌점은 모델 버전에 고정해 평가 결과를 본 뒤 바꾸지 않는다.

만석 확률과 성능을 낸다

적합한 값을 0과 1 사이의 만석 확률로 바꾸고 뒤 날짜의 각 통과 사건에 한 번씩 적용한다. 점추정은 표본·기간·상태·버전과 함께 표시한다.

이 방식의 강점

재료 한눈에

재료쓰나왜
노선쓴다1650·3330의 정류장 곡선을 분리한다. 수집기가 승인된 공개 노선값으로 기록한다.
정류장 순번쓴다정류장을 노선 위 연속 좌표로 놓는다. 학습 구간에서 관측된 노선별 최소·최대 순번으로 0과 1 사이 위치로 바꾼다.
응답 수신시각(KST)쓴다하루 주기 시간축으로 쓴다.
출발 뒤 만석 라벨학습에만앞선 날짜의 학습 정답으로만 쓰고 예측 입력에는 넣지 않는다.
정류장 ID·이름안 쓴다범주를 외우지 않고 순번의 연속성을 시험하는 모델이다.
정원·점유율안 쓴다라벨에 정원이 필요 없다. 외부 정원 키와의 조인은 0/77이었고, 관측 최대 잔여석은 정원이 아니라 하한이다.
혼잡도(crowded)안 쓴다대상 노선 유형(11)은 공식 제공 대상(13·15·23)이 아니다. 산식도 미확정이다.
queryTime안 쓴다공급자가 적은 시각이라 차량 시각이 아니다. 반증 근거는 평가 규약에 있다.
상류 버스 잔여석·직전 통과 상태안 쓴다허용된 재료지만 이 후보에서는 뺐다. 시공간 면만으로 얻는 몫을 따로 재기 위해서다.

해설 기준: gam-spline-v1(운영 구현)은 노선·정류장 순번·하루 주기 시각·학습 라벨만 쓴다. 연구 구현이 추가로 쓰던 요일·계획 배차간격 항과 출처 필드 명세는 아래 접힘에 있다.

정원·차종은 검증해서 버린 재료가 아니다

M3는 직접 수집분만 쓰고 공식 이력·제원으로 정원·차종 ablation을 실행했다. 직접 관측 고유차량 55/62대에 공식 이력이 연결됐다. 공유 페이지에는 차량번호와 비공개 조인 식별자 값을 싣지 않는다.

새 지표에서 명백한 개선으로 판정한 조합은 0개다. 표본 관문 미달이라 쓸모없다는 뜻은 아니다. 관측 최대 잔여석으로 정원을 추정한 행은 0건이며 계속 금지한다.

재료 상세 장부 — 연구 구현의 출처 필드까지

해설 기준: 연구 구현(코퍼스·M1–M3). 요일·계획 배차간격 항이 들어 있던 시기의 명세다.

노선 — 3330과 1650의 시공간 면을 분리한다.정류장 순번 — 정류장을 노선 위 연속 좌표로 놓는다.로컬 하루 분 — KST 응답 수신시각을 연속 시간축으로 쓴다.로컬 요일 — 사인·코사인으로 주간 주기를 넣는다.계획 배차간격 — 정적 운행계획의 차이를 보조한다. 실제 배차는 아니다.출발 후 만석 라벨 — 학습할 때만 쓴다. 출발 후 0석은 1, 양수는 0이다.정류장 ID·이름정원·점유율crowdedqueryTime상류 버스 잔여석·직전 통과 상태

쓰는 재료 6개 — 출처 필드까지

재료종류어느 API의 어느 필드
노선 (route)직접 수집은 calls.jsonl.route_name, 코퍼스는 route.name을 모델 범주로 읽고 같은 route.routeName 마스터 행을 찾는다. 수집기 설정의 route.route_id와 원응답 routeId는 원문에 남는다.주의 — 현재 S1 구현은 실제로 routeName으로 마스터를 찾는다. msgBody.busLocationList[].routeId를 모델의 route로 복사하지 않는다. 대상 두 노선 밖으로 넓힐 때는 ID 검증이 필요하다.응답 원본msgBody.busLocationList[].routeId; 운영 수집기 route.name, route.route_id; S1 E4 calls.jsonl.route_name; 코퍼스 route.name; route.routeName, route.routeId; S1 routeGBIS 버스위치정보 getBusLocationListv2 + 우리 수집기 노선 메타데이터 + 제한 코퍼스 + GBIS route 마스터
목표 축 순번 (station_seq)stateCd=1이면 현재 stationSeq-1, stateCd=0·2이면 현재 stationSeq를 마지막 통과 순번으로 놓는다. 인접 적격 응답에서 이 값이 전진한 끝점을 통과 사건 순번으로 삼는다.주의 — 모델 축은 routestation 전체 순번이다. 학습 행은 서비스 정차점만 남겨도 축 간격에는 미정차·경유 지점이 들어간다.파생msgBody.busLocationList[].vehId, msgBody.busLocationList[].stationSeq, msgBody.busLocationList[].stateCd; routestation.staOrder; S1 station_seqGBIS 버스위치정보 getBusLocationListv2 + GBIS routestation 마스터 + S1 통과 사건 빌더
KST 하루 중 분 (query_minute_of_day)KST 시각에서 hour*60+minute을 계산한다.주의 — msgHeader.queryTime은 쓰지 않는다. 초는 버린다.파생timing.response_received_at.kst, timing.response_received_at.utc; S1 E4 response_received_kst, response_received_utc; 코퍼스 collectedAt; S1 query_minute_of_day우리 수집기 응답 수신시각; 제한 코퍼스는 수집기가 붙인 collectedAt
요일 (query_day_of_week)KST 날짜에 Python weekday()를 적용한다. 월요일 0, 일요일 6이다.주의 — 공휴일 표시는 없다. 요일만 구분한다.파생timing.response_received_at.kst, timing.response_received_at.utc; S1 E4 response_received_kst, response_received_utc; 코퍼스 collectedAt; S1 query_day_of_week우리 수집기 응답 수신시각; 제한 코퍼스는 수집기가 붙인 collectedAt
계획 배차간격 (master_dispatch_interval_min)현재 구현은 평일 06:30~09:29·17:00~20:29에 peekAlloc, 그 밖 평일에 npeekAlloc을 고른다. 토요일은 satNpeekAlloc, 일요일은 sunNpeekAlloc을 고른다.주의 — 계획값이지 실제 헤드웨이가 아니다. 현재 코드의 피크 조건에 평일 검사가 들어가 토·일 *PeekAlloc 분기는 닿지 않는다. we*도 고르지 않는다.파생route.peekAlloc, route.npeekAlloc, route.satPeekAlloc, route.satNpeekAlloc, route.sunPeekAlloc, route.sunNpeekAlloc, route.wePeekAlloc, route.weNpeekAlloc; timing.response_received_at.kst, timing.response_received_at.utc; S1 master_dispatch_interval_minGBIS route 마스터 + 우리 수집기 응답 수신시각 + S1 특징 빌더
출발 후 만석 라벨 (label_full)정류장 s 통과 뒤 같은 차량에서 (stateCd,stationSeq)=(2,s),(0,s),(1,s+1) 중 처음 잡힌 유효 좌석값을 찾는다. 0이면 1, 양수면 0이다.주의 — remainSeatCnt=-1은 결측이다. (stateCd,stationSeq)=(1,s)는 도착 상태라 라벨이 아니다. 예측 시점 뒤에 생기므로 학습 정답으로만 쓴다.파생msgBody.busLocationList[].vehId, msgBody.busLocationList[].stationSeq, msgBody.busLocationList[].stateCd, msgBody.busLocationList[].remainSeatCnt; timing.response_received_at.kst, timing.response_received_at.utc; S1 passage_events.label_full, label_remain_seatsGBIS 버스위치정보 getBusLocationListv2 + 우리 수집기 응답 수신시각 + S1 통과 사건 빌더

지금은 안 쓰는 재료 5개

이하 1~3절의 수치와 구현 세부는 코퍼스·M1–M3 연구 기록 기준이다. 연구 구현은 노선별 공간×시간 텐서 면을 썼고, 운영 구현 gam-spline-v1은 위 계산 단계처럼 상호작용 없이 더하는 구조를 쓴다. 오늘 성적은 위 표가 정본이다.

1. 왜 이 방법인가

Q. 정류장을 그냥 낱개 칸으로 외우면 안 되나?

코퍼스 보조 학습자료에는 노선×정류장×30분 셀이 833개 있다. 이 중 281개(33.73%)는 표본이 10건 이하다. 719개(86.31%)는 만석을 한 번도 못 봤다. 칸의 비율을 그대로 쓰면 세 번 보고 만석이 없던 셀도 위험 0으로 굳는다.

그런데 무축소 셀 조회에서 검증 정류장 순번을 한 칸 앞이나 뒤로 옮겨도 AUC가 .9100과 .9113으로 남았다. 정류장 ID 하나에만 붙은 신호라면 이렇게 버티기 어렵다. 위험이 노선 위에서 이어진다는 근거다.

GAM은 이 틈을 쓴다. 정류장을 이름이나 ID가 아니라 노선 위 순번으로 놓는다. 얇은 셀은 바로 옆 정류장과 가까운 시각의 기록을 나눠 쓴다.

옆 정류장에도 남은 신호
순번 -1AUC .9100
순번 +1AUC .9113

무축소 노선×정류장×30분 조회에서 검증 정류장 순번만 옮긴 공격이다.

2. 어떻게 작동하나 — 연구 구현

Q. 순번 하나가 어떻게 곡선이 되나?

3330은 순번 1~85, 1650은 1~89다. 연구 구현은 1~89 축에 3차 B-스플라인 매듭 8개를 놓는다. 실제로 생기는 공간 기저 열은 9개다. 이웃 순번은 겹치는 기저 열을 비슷한 비율로 켠다. 그래서 순번 60의 기록은 61에도 조금 닿고, 멀리 떨어진 20에는 거의 닿지 않는다.

얇은 고무판을 몇 군데 눌러 모양을 잡는 것과 같다. 관측 한 점이 주변까지 움직이되, 노선 전체가 같은 높이가 되지는 않는다.

Q. 시각도 같은 방식으로 잇나?

로컬 응답 수신시각을 하루의 분으로 바꾼다. 0~1,440분 축에는 3차 주기 스플라인 매듭 6개를 놓고, 실제 시간 기저 4개를 만든다. 주기형이라 자정 양쪽이 끊기지 않는다. 요일은 사인·코사인 2열로 넣는다. 계획 배차간격도 1열 넣지만, 실제 배차로 읽지는 않는다.

Q. 공간 곡선과 시간 곡선을 왜 곱하나?

공간 9열과 시간 4열을 모두 곱해 36열을 만든다. 이것이 텐서 면이다. 단순히 정류장 효과 + 시간 효과만 더하면 모든 정류장이 같은 시간에 함께 오르내린다. 곱셈 항을 두면 7시의 순번 61만 높고, 같은 61도 저녁에는 낮은 모양을 배운다.

이 면은 노선별로 따로 만든다. 한 노선당 노선 표시 1 + 공간 9 + 시간 4 + 텐서 36 = 50열이다. 두 노선 100열에 요일 2열과 계획 배차 1열을 더해 실제 입력은 103열이다.

Q. 곡선이 어떻게 확률이 되나?

전용 GAM 패키지를 쓰지 않는다. 103개 기저 열을 표준화한 뒤 L2 규제를 건 로지스틱 회귀에 넣는다. 코퍼스 학습자료 내부의 날짜 순방향 교차검증이 공간 매듭 8개, 시간 매듭 6개, C=.3을 골랐다.

작은 식은 이것뿐이다.

p_full = 1 / (1 + e^-z), p_board = 1 - p_full

z는 103개 열의 가중합이다. C=.3 규제가 계수를 눌러 얇은 구간에서 곡선이 심하게 출렁이는 일을 막는다.

순번과 시각이 확률이 되는 경로
노선·순번·KST 분
3차 B-스플라인
공간 9열·시간 4열
9×4
노선별 텐서 36열
두 노선+요일+계획 배차
103열 표준화
가중합
L2 로지스틱 C=.3
시그모이드 뒤 1-p
만석확률 → 탈 확률

연구 구현은 공간·시간 기저를 만든 뒤 노선별 텐서 면과 규제 로지스틱을 거친다.

3. 숫자로 따라가기

Q. 실제 한 행은 어떻게 계산됐나?

2026-08-03 월요일 07:06:05 KST의 코퍼스 검증행을 본다.

단계실제 값
질의3330 · 농수산물시장 · 순번 61
시간 입력하루 426분 · 요일 코드 0(월요일) · 계획 배차 5분
스플라인·텐서·규제 회귀 뒤 점수z=.9572
후처리 전(raw) 만석확률p_full=.7226
사용자용 탈 확률1-.7226=.2774
확인된 정답07:07:08, 순번 61 출발(stateCd=2) 뒤 0석

이 행에서 모델은 탈 확률을 27.74%로 냈다. 63초 뒤 출발 관측은 0석이라 라벨은 만석 1이다. 다만 이 라벨은 좌석이 모두 소진됐다는 뜻이다. 줄에 있던 개인이 실제로 못 탔다는 현장 기록은 아직 없다.

Q. 전체 검증에서도 나아졌나?

코퍼스 보조 검증자료 10,040건·만석 583건에서 raw GAM의 ECE는 .0038, AUC는 .9647이었다. 정류소×시간 기준선은 .0063, .9613이었다. 반면 Brier는 .0328 대 .0327, log loss는 .1034 대 .1033으로 사실상 제자리였다. 순위는 조금 나아졌지만 전체 확률 오차를 줄였다고 보기는 어렵다.

Platt 보정 뒤 ECE는 .0190, isotonic 뒤에는 .0082였다. raw의 .0038보다 나빠서 이 모델은 raw를 대표값으로 쓴다.

언제 실패하나

함께 읽을 한계

프로토타입과 무엇이 다른가

Q. 예전 좌석 예보를 곡선으로 바꾼 모델인가?

아니다. 목표부터 더 좁다.

프로토타입GAM/스플라인
화면 탑승 확률은 정류장×평일/주말×30분 셀의 1-z/n이었다.출발 후 만석확률 하나를 직접 학습하고 1-p_full만 탈 확률로 바꾼다.
차량별 현재 좌석에서 0~80석 분포를 정류장마다 전파했다.현재 좌석을 전파하지 않는다. 위치와 시간에서 바로 확률을 낸다.
셀을 낱개로 조회하고, 근거가 없을 때만 이웃 시간대를 합쳤다.모든 관측을 연속 공간·시간 기저 위에 놓고 늘 이웃과 계수를 나눠 쓴다.
좌석값의 도착 전·출발 후 의미가 계산 경로마다 달랐다.정답을 출발 후 0석으로 고정했다.
확률 보정층이 없었다.raw·Platt·isotonic을 같은 시간순 검증에서 겨뤘고, 이 모델은 raw를 남겼다.

GAM은 프로토타입의 좌석 시뮬레이터를 다듬은 버전이 아니다. 얇은 정류장×시간 셀을 다루기 위해 만든 직접 확률 모형이다.

Q. 보정층은 적용됐나?

적용하지 않았다. 이 모델의 확률은 보정 전 값 그대로다. 연구 검증에서 raw의 보정 오차가 Platt·isotonic보다 작아 raw를 대표값으로 남겼다(3절 참고). 보정층 자체는 숫자 다듬기 · Platt 확률 보정에서 다룬다.

Q. 개인정보와 미래 정답은 어떻게 막나?

관문 기준·구간 정의·지표 정의·학습/평가 분할·라벨 규칙·검열 처리는 평가 규약 한 곳에 있다.

M3 연구 이력 — 2026-08-15 동결

아래 값은 동결된 연구 기록이다. 위 오늘 성적과 합치거나 변화율로 계산하지 않는다.

Brier0.0041ECCE-MAD0.0034log loss0.04431:1 결정비용0.00422:1 결정비용0.00844:1 결정비용0.0168
M3 권위값

직접 API 응답 582개를 고정해 train 604행·만석 28건, validation 1,901행·만석 8건·날짜 1일로 나눴다.

모델 7개를 paired bootstrap 5,000회와 Holm 21쌍으로 비교했다. 결정은 no_winner, 승자 없음이다. 최소 관문은 validation 날짜 10일·만석 100건이다.

validation 양성 20건 미만이면 만석 누락률·PR-AUC·ROC-AUC 수치를 억제한다. M1·M2 수치는 역사 기록이며 최신 결론과 섞지 않는다.

M3 직접 수집분 성적

68/32 이동 분할이 아니라 M2 마지막 응답 뒤의 고정 미래구간을 썼다. 검증 1,901행·만석 8건· 하루·정류소×날짜 129군집, paired_station_id_x_query_date_cluster_bootstrap 5,000회다.

C · 이웃에게 빌리기 · raw

운영 후보 · M3 고정 미래구간 기술값 · 낮을수록 좋음

지표값 (95% 구간)
Brier · 얼마나 빗나갔나0.0041[0.0000, 0.0096]
ECCE-MAD · 확률 오차가 쌓이나0.0034[0.0009, 0.0089]
log loss · 확신하고 틀린 벌점0.0443[0.0009, 0.1014]
만석 누락 @ .5 · 만석을 안심으로 놓쳤나만석 20건 미만 · 수치 억제
1:1 결정비용 @ .500.0042[0.0000, 0.0099]
2:1 결정비용 @ .330.0084[0.0000, 0.0199]
4:1 결정비용 @ .200.0168[0.0000, 0.0397]
승자는 없다

M3 표본은 validation 날짜 1/10일 (미달), 만석 8/100건 (미달)이다. 만석 민감 지표는 양성 20건부터 숫자를 내며 동결 시점에는 수치 억제였다. 관문은 검토 최소선이지 충분조건이 아니다.

모델별 보정 관문은 미달 — 적격 적용 0/3개 · raw fallback 5,703행이다. 비억제 모델쌍×지표 bootstrap 유효비율 최소값은 100.0%(기준 90%), 운영 후보 비용 방향 뒤집힘은 0/15쌍이다. 마지막 세 날짜 누적 Brier도 승자 전에 확인한다.

하루 조건부 기술 구간과 Holm 계산상 0을 벗어난 Brier 쌍은 10/21쌍이지만 날짜 일반화나 우열 판정이 아니다. 최종 판정은 0/21쌍이다. 만석 8건이면 누락률이 한 사건당 12.5%p 움직인다. PR-AUC·ROC-AUC도 만석 20건 미만이면 억제하며 순위에 쓰지 않는다.

1–4일은 관측 날짜 안 조건부 기술값, 5–9일은 진단 기술값이다. 검증 10일부터도 모든 관문을 통과해야 추론과 승자 선언을 검토한다. 경로·수집구간·날짜·라벨 규칙·관측간격 다섯 축은 한 축씩 기록하고 90초 초과는 검열한다. ECCE 동률은 독립 동결 nonce의 SHA-256 순서로 재현하고 전 행 누적곡선을 남긴다. 이번 재실행은 registry 후보 3,054건 중 기존 nonce 3,054건을 재사용했고 신규는 0건이다.

연구가 남긴 실패 신호

이전 공개 평가

평가평가 규격행Brier
eval-20260815-7e03dc730de91f34evaluation-v12,8940.008562

이전 공개 평가의 값은 위 오늘 성적과 합치거나 변화율로 계산하지 않는다.

출처와 검증 장부

오늘 성적 — 일일 평가 보고서 daily-20260816-86afbfc70dbb876b(2026-08-16분, 생성 08-17 00:15 KST) · 모델 버전 gam-spline-v1+fd482d90 · 평가 규격 evaluation-v2 · 구간 규격 cohort-v1.

이력 — 공개 평가 eval-20260815-f0f59cf25a9c3503 · 자료판 current-7cf2243ffe6c4cdc · 모델 버전 gam-spline-v1+cca34cdb · 평가 규격 evaluation-v2 · 구간 규격 cohort-v1 · 관측 2026-08-14 16:38 ~ 2026-08-15 11:47 KST · 표본 2,894행·만석 23건·관측일 1일. 그 앞은 eval-20260815-7e03dc730de91f34(evaluation-v1 · gam-spline-v1+fbebba55)다.

eval-20260815-f0f59cf25a9c3503 해시 — 규약 43913ebf483a48a02f6a83e01181a01ccf8bc10a728a38b9e838031ac9dbeec5 · 구현 cca34cdb16f663754e630e9f41abd26b6b441a19dd5002291f18af63f9a21a9a · 평가 d133e3d6c2db757c5fa780d5ffb19e6998b2dcefc049b844a8faebd64e14a817