them big_tasks.md (roadmap G0-G4, danh dau G1.1-G1.5 hoan thanh) + debug scripts/probes cua phien lam viec G0.1-G1.5 (test_g13/test_g12/test_g15_stress, patch_g1x, deploy/build bridge, probe_g0x)
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
# ROADMAP: Xử lý triệt để như DAW hiện đại — tách UI thread khỏi audio loop
|
||||
|
||||
Ngày: 2026-08-15 · Repo: `C:/Users/locpham/SonicForgeStudio` · Dựa trên bằng chứng
|
||||
`native_bridge/debug/BUG_REPORT.md` + source hiện tại (main.cpp, Vst3Instrument.cpp, lib.rs).
|
||||
|
||||
## Mục tiêu kiến trúc đích
|
||||
|
||||
DAW hiện đại (Cubase/Reaper/FL/Bitwig) tách:
|
||||
- **Audio thread**: real-time, chỉ gọi `process()`
|
||||
- **UI thread**: main UI thread, chạy `view->attached()` + message pump editor
|
||||
- (tuỳ chọn) **Plugin process riêng**: sandbox crash plugin khỏi engine
|
||||
|
||||
Bridge hiện tại gộp 2 thứ đầu vào 1 thread (`while(true)` vừa `renderAll()` vừa
|
||||
`PeekMessageW`, main.cpp:1220-1240) + attach job trên ChannelWorker → 2 thread 1
|
||||
DLL → Nexus throw/hang. Roadmap này tách UI khỏi audio đúng VST3 contract.
|
||||
|
||||
## Nguyên tắc vận hành (áp dụng cho MỌI task)
|
||||
|
||||
```
|
||||
1. Viết test tái hiện TRƯỚC (gui_probe variant / probe_appN / driver kịch bản)
|
||||
2. Implement tối thiểu (đúng phạm vi task)
|
||||
3. Chạy bộ test: gui_probe matrix + live driver + regression cũ
|
||||
4. Ghi nhận bug vào log + BUG_REPORT.md (mỗi bug: kịch bản, log, nguyên nhân)
|
||||
5. Fix → chạy lại → pass hết mới deploy
|
||||
6. Deploy exe vào install/ + commit (theo pattern git log hiện có)
|
||||
```
|
||||
|
||||
Không task nào merge nếu chưa: probe matrix pass + driver 3 run liên tiếp pass +
|
||||
screenshot GUI không trắng.
|
||||
|
||||
## GIAI ĐOẠN 0 — Ổn định hiện trạng (P0, ngăn máu chảy)
|
||||
|
||||
Làm ngay, độc lập kiến trúc. Không phải "xử lý triệt để" nhưng là nền để làm việc
|
||||
dài hạn không bị bug quấy phá.
|
||||
|
||||
| # | Task | File | Done khi |
|
||||
|---|---|---|---|
|
||||
| G0.1 | Chặn/defer OPEN_GUI khi transport PLAY (đợi STOP rồi attach; hoặc tạm dừng transport) | main.cpp handleOpenGui + Rust transport state | probe_app4_live: PLAY + OPEN_GUI → không EXCEPTION, attach sau STOP thành công |
|
||||
| G0.2 | Bỏ spam `openVstGuiRetry` 20×500ms → tối đa 2 lần, có backoff, không retry khi đang PLAY | app/static/js/app.precompiled.js | bridge.log không còn chuỗi EXCEPTION/FAILED lặp; stall không xảy ra |
|
||||
| G0.3 | Watchdog né giết khi attach-in-flight (flag SHM hoặc stall type riêng) | lib.rs:397 + shm | Stall do attach dài → không kill; stall thật → kill như cũ |
|
||||
| G0.4 | Save/restore state nhanh (getState trước khi reload, setState sau) | Vst3Instrument.cpp | Mở GUI → đóng → mở lại: preset giữ nguyên |
|
||||
|
||||
## GIAI ĐOẠN 1 — Tách GUI pump khỏi audio loop (P1, lõi triệt để)
|
||||
|
||||
**Vấn đề hiện tại**: main thread vừa render audio vừa pump message editor.
|
||||
Attach job chạy ChannelWorker (thread khác) → 2 thread 1 DLL.
|
||||
|
||||
**Đích**: main thread chỉ render audio. Thread UI mới (native UI thread) tạo window
|
||||
+ pump message editor + chạy toàn bộ attach/close. Đúng mô hình Steinberg
|
||||
`editorhost.cpp`: 1 UI thread, 1 audio thread.
|
||||
|
||||
| # | Task | File | Done khi |
|
||||
|---|---|---|---|
|
||||
| G1.1 | Thêm `UiThread` (thread riêng, COM STA, message pump riêng, job queue) | main.cpp mới class | gui_probe variant `ui_thread` tương đương bridge mới: Nexus attach OK không hang |
|
||||
| G1.2 | Chuyển tạo window + attach job từ ChannelWorker → UiThread; audio loop bỏ `PeekMessageW` | main.cpp | Probe bridge arch mới: 2 instance Nexus attach OK, không HANG (so với bridge_two HANG hiện tại) |
|
||||
| G1.3 | Chuyển close/resize/IME sang UiThread; bỏ pump gate cũ (g_juceTidsMutex...) nếu không còn cần | main.cpp | close editor đang PLAY không crash; không cần mute workaround |
|
||||
| G1.4 | Bỏ mute-when-editor-open (g_editorOpen/g_editorPathCount) — test lại | main.cpp | 6 Nexus + GUI ch5 mở khi PLAY: track khác vẫn kêu (mute hiện tại làm track câm) |
|
||||
| G1.5 | Regression: driver stress 6 Nexus + Ample + EZkeys, mở/đóng GUI khi PLAY | driver + probe | 3 run liên tiếp không crash/stall |
|
||||
|
||||
## GIAI ĐOẠN 2 — Persistence: restart không mất instrument (P2)
|
||||
|
||||
Trả lời câu hỏi "stop/play nghe lại". Hiện bridge kill = mất hết instance (state
|
||||
trong memory process).
|
||||
|
||||
| # | Task | File | Done khi |
|
||||
|---|---|---|---|
|
||||
| G2.1 | `saveState()`/`restoreState()` đầy đủ (IComponentHandler/getState, preset, MIDI routing) | Vst3Instrument.cpp + NativeInstrumentEngine | Save → reload → restore: âm thanh/preset giống hệt |
|
||||
| G2.2 | Bridge dump state ra file khi shutdown/trước kill (SIGHUP/SHM flag) | main.cpp + lib.rs | Kill bridge → state file có đủ 16 channel |
|
||||
| G2.3 | Frontend auto-reload sau respawn: đọc state file → bridgeLoad lại từng track | app + NativeBridgeService | Giết bridge giữa PLAY → bridge mới tự nạp lại, PLAY tiếp tục, không câm |
|
||||
| G2.4 | Bỏ `!isPlayingRef.current` chặn restore khi đang play | app.precompiled.js:816 | Restore chạy được cả khi PLAY |
|
||||
|
||||
## GIAI ĐOẠN 3 — Watchdog thông minh + health (P3)
|
||||
|
||||
| # | Task | File | Done khi |
|
||||
|---|---|---|---|
|
||||
| G3.1 | Heartbeat riêng (thread bridge ghi timestamp mỗi 100ms) tách khỏi writeIndex audio | main.cpp + shm.rs + lib.rs | Bridge sống nhưng audio stall → không kill; bridge chết → phát hiện <1s |
|
||||
| G3.2 | Phân loại stall: audio (render quá lâu) vs GUI job (attach/close) vs chết | lib.rs | Mỗi loại có policy riêng (GUI: đợi, không kill) |
|
||||
| G3.3 | Bridge tự phục hồi lỗi plugin: catch crash riêng channel (SEH quanh process của từng channel) | main.cpp renderAll | 1 plugin crash → mute channel đó, các channel khác chạy tiếp (giống DAW sandbox-lite) |
|
||||
|
||||
## GIAI ĐOẠN 4 — Sandbox plugin process riêng (P4, tuỳ chọn tham vọng)
|
||||
|
||||
VST3 không có chuẩn out-of-process như AUv3 → cần wrapper tự làm. Đây là bước xa
|
||||
nhất, chỉ làm khi G1-G3 chưa đủ.
|
||||
|
||||
| # | Task | File | Done khi |
|
||||
|---|---|---|---|
|
||||
| G4.1 | Nghiên cứu: host plugin trong process con (VST3 host trong exe thứ 2), audio qua SHM | thiết kế mới | PoC 1 plugin Nexus trong process con, GUI + audio OK |
|
||||
| G4.2 | Bridge → client process pool (1 process/plugin hoặc /nhóm) | thiết kế mới | Plugin crash → process con chết, bridge + GUI sống |
|
||||
| G4.3 | IPC audio real-time (SHM ring buffer double-buffer) | thiết kế mới | 6 Nexus song song, latency < 20ms, không xrun |
|
||||
|
||||
**Cân nhắc**: G4 là dự án riêng (ước lượng gấp 3-5× G1+G2). Khuyến nghị: làm G0-G3
|
||||
trước; G4 chỉ khi cần cô lập crash plugin thật sự (hiện G3.3 + G1 đã lo được 90%
|
||||
kịch bản bug).
|
||||
|
||||
## Thứ tự thực hiện đề xuất
|
||||
|
||||
```
|
||||
G0.1 → G0.2 → G0.3 → G0.4 (1-2 tuần, an toàn ngay, trả lời "stop/play nghe lại" một phần qua G0.4)
|
||||
↓
|
||||
G1.1 → G1.2 → G1.3 → G1.4 → G1.5 (3-5 tuần, lõi triệt để — mở GUI khi PLAY thành công)
|
||||
↓
|
||||
G2.1 → G2.2 → G2.3 → G2.4 (2-3 tuần, restart không câm)
|
||||
↓
|
||||
G3.1 → G3.2 → G3.3 (1-2 tuần, health đầy đủ)
|
||||
↓
|
||||
G4.* (tuỳ chọn, 2-3 tháng)
|
||||
```
|
||||
|
||||
## Bắt đầu ngay — task đầu tiên
|
||||
|
||||
**G0.1**: sửa `handleOpenGui` (main.cpp:943) — nếu transport PLAY, đưa OPEN_GUI
|
||||
vào `g_pendingGui` (đã có cơ chế defer cho "chưa load"), sweep xử lý khi transport
|
||||
STOP. Kèm test: `probe_app4_live.py` biến thể "PLAY rồi OPEN_GUI rồi STOP" — kỳ
|
||||
vọng không EXCEPTION, GUI attach sau STOP.
|
||||
|
||||
## Files liên quan hiện tại
|
||||
|
||||
- `native_bridge/src/main.cpp` — loop (1220), handleOpenGui (943), ChannelWorker, mute/close
|
||||
- `native_bridge/src/Vst3Instrument.cpp` — reload (615), reloadForGUI (528), attachView (550)
|
||||
- `native_bridge/src/gui_probe.cpp` — probe variants (bridge_two 243, two_workers_close 318)
|
||||
- `native_bridge/src/lib.rs` → thực tế `src-tauri/src/lib.rs` — watchdog (356-430), kill/spawn (50,135)
|
||||
- `app/static/js/app.precompiled.js` — openVstGuiRetry (470), restore (816)
|
||||
- `native_bridge/debug/` — BUG_REPORT.md, sweep_bridge_two_8s.json, probe_attach_detail.py, probe_app4_live.py
|
||||
@@ -0,0 +1,122 @@
|
||||
# BÁO CÁO BUG: Mở VST GUI khi đang PLAY → dự án câm, GUI không load
|
||||
|
||||
Ngày: 2026-08-15 · Repo: `C:/Users/locpham/SonicForgeStudio` · git status sạch
|
||||
|
||||
## 1. Tóm tắt
|
||||
|
||||
Nguyên nhân gốc: **nhiều thread cùng vào 1 plugin DLL trong lúc `view->attached()`**.
|
||||
Khi đang PLAY, audio loop `process()` chạy trên các instance Nexus (ch0-4) cùng lúc
|
||||
worker thread của ch5 chạy `attachView()`. Nexus throw exception trong
|
||||
`createView/attached` → attach FAILED → frontend retry ~30 lần (0.3s/lần) →
|
||||
`bridgeWriteIndex` stall 3s → Tauri watchdog kill+respawn bridge → **mất hết
|
||||
instrument → câm toàn bộ**. GUI không bao giờ load được.
|
||||
|
||||
Không phải "instrument track khác bị reset" (giả thuyết 1 sai ở bước này — reload
|
||||
reset state chỉ xảy ra khi GUI ĐÃ mở thành công rồi đóng rồi mở lại, không phải lần
|
||||
attach đầu).
|
||||
|
||||
## 2. Chuỗi bug đầy đủ (xác nhận live, bridge.log)
|
||||
|
||||
```
|
||||
... 6x Nexus loaded ch0-5 + EZkeys ch6 ...
|
||||
[NativeBridge] transport PLAY playhead=0
|
||||
[NativeBridge] GUI attach EXCEPTION ch=5 — plugin threw (createView/attached)
|
||||
[NativeBridge] GUI attach FAILED hwnd=0000000002250F36 plugin=Nexus
|
||||
[tauri] bridge restarted (attempt 1) ← watchdog: writeIndex stall 3s
|
||||
[NativeBridge] Starting DAW Host Bridge Engine... ← restart, mất hết instrument
|
||||
```
|
||||
|
||||
1. `handleOpenGui` (main.cpp ~943): OPEN_GUI ch5 → silence mọi channel cùng
|
||||
plugin path → `g_loadMutex` → `try { reloadForGUI(); attachView(hwnd); } catch(...)`.
|
||||
2. `attachView` (Vst3Instrument.cpp:550): `controller->createView(kEditor)` →
|
||||
`view->attached(hwnd, kPlatformTypeHWND)` → **Nexus throw** khi đang PLAY
|
||||
(audio loop process() cùng DLL đang chạy trên instance khác).
|
||||
3. catch → `ok=false` → log EXCEPTION + FAILED → PostMessage WM_CLOSE (GUI không load).
|
||||
4. Frontend `openVstGuiRetry` spam lại ~30 lần; mỗi lần chạy lại job (silence +
|
||||
mutex + reload/attach) → main loop bị nghẽn → `bridgeWriteIndex` stall 3s.
|
||||
5. `lib.rs`: stall >3s → `kill_bridge` + `spawn_bridge` (restart_attempts==0) →
|
||||
mất toàn bộ instrument state → **CÂM**.
|
||||
|
||||
## 3. Bằng chứng thực nghiệm
|
||||
|
||||
### 3.1 Probe kiến trúc chính xác (bridge_two: 2 worker STA riêng + main pump)
|
||||
|
||||
`gui_probe.exe <plugin> bridge_two <secs>` — kết quả 76 VST3 hệ thống (sweep):
|
||||
`native_bridge/debug/sweep_bridge_two_8s.json`, `probe_attach_detail.py` (bổ sung).
|
||||
|
||||
⚠️ **Hiệu chỉnh sweep cũ**: exit code 0xC0000409 của TẤT CẢ 76 plugin là
|
||||
**artifact của probe** — `ProbeWorker::th` không join → `~std::thread` trên
|
||||
joinable thread → `std::terminate` → fail-fast. RESULT line in ra nhưng không flush
|
||||
kịp. Không phải 76 plugin cùng crash teardown.
|
||||
|
||||
Phân loại đúng dựa trên output per-attach:
|
||||
|
||||
| Nhóm | Số plugin | Bằng chứng | Ý nghĩa |
|
||||
|---|---|---|---|
|
||||
| **HANG attach inst2** | 30 | `workerA openGUI inst1=1` rồi `workerB openGUI inst2` in ra, **không có kết quả** — Nexus 25s không về | 2 instance cùng DLL, 2 apartment → attach instance 2 HANG trong `view->attached()` |
|
||||
| **BOTH-OK** | 20 | `workerB openGUI inst2=1` — Kontakt, BlueARP, Ozone 11 (18) | Attach 2 instance OK; chỉ crash teardown artifact |
|
||||
| **HANG/crash attach inst1** | 18 | `workerA hwnd=` in ra, không in `openGUI inst1` — RX 11 (18) + ACTP | Chết ngay instance 1 |
|
||||
| **CRASH EARLY** | 8 | exit 1.2-4.6s, 0xC0000005 (AV): Melodyne, Orb Arpeggios/Melody, smartEQ3/live, smartreverb, DUNE3, ACDD | Crash thật trong attach |
|
||||
|
||||
Không plugin nào HANG >18s (không WATCHDOG-KILL) — main pump cứu được các trường
|
||||
hợp cần pump; vấn đề là **conflict thread/apartment khi 2 instance cùng DLL**.
|
||||
|
||||
### 3.2 Nexus: hang khi 2 instance — OK khi 1 thread
|
||||
|
||||
- `bridge_two` (2 worker STA, 2 instance Nexus): inst1 attach OK, **inst2 HANG 25s+** (xác nhận bằng run 25s).
|
||||
- `same_thread` (load + attach cùng 1 thread): **OK** (returned=1).
|
||||
- `main_own` (load+attach main thread): **OK** (RESULT done=1 attached_ok=1).
|
||||
- `two_workers_close` (đóng editor inst1 trước khi attach inst2, có closeGUI + attach qua temp thread): Nexus **HANG ngay attach inst1**; Kontakt chạy hết, OK cả 2.
|
||||
|
||||
→ 2 thread/apartment cùng 1 DLL = conflict thật (không riêng Nexus: 30 plugin hang
|
||||
inst2, 8 crash AV). Kontakt/Ozone/BlueARP chịu được.
|
||||
|
||||
### 3.3 Giả thuyết (a) reload mất state — XÁC NHẬN từ code
|
||||
|
||||
`Vst3Instrument::reload()` (Vst3Instrument.cpp:615): `closeGUI()` + terminate +
|
||||
`delete state_` + `loadPlugin(path_)` **MỚI** → preset/state mất khi mở lại GUI
|
||||
(reopen). Kích hoạt bởi `reloadForGUI()` khi `hasAttachedOnce_ && !guiAttached_`
|
||||
(đã từng mở GUI rồi đóng). Không phải nguyên nhân của bug câm lần này (attach đầu
|
||||
chưa thành công nên chưa tới reload), nhưng là bug phụ: **mở GUI → đóng → mở lại =
|
||||
mất preset/state của track**.
|
||||
|
||||
## 4. Kết luận nguyên nhân
|
||||
|
||||
1. **Root cause**: attach GUI chạy worker thread trong khi audio loop `process()`
|
||||
đang chạy instance cùng DLL (2+ thread 1 DLL). Nexus throw → attach fail.
|
||||
Probe không audio: biểu hiện hang (inst2); app thật có audio: biểu hiện
|
||||
exception (ch5). Cùng gốc.
|
||||
2. **Khuếch đại**: frontend retry spam 30× → stall 3s → watchdog tưởng bridge chết
|
||||
→ restart → mất hết instrument → câm. Đây là lý do dự án chết hoàn toàn, không
|
||||
chỉ mất GUI.
|
||||
3. `g_loadMutex` + silence hiện có chưa đủ: không đợi renderAll thoát hẳn instance
|
||||
cùng DLL trước khi `createView`, và Nexus vẫn throw ngay cả khi đã silence
|
||||
(silence chỉ ngăn process gọi tiếp, không chặn instance đang nằm trong process()).
|
||||
|
||||
## 5. Đề xuất fix (xếp theo ưu tiên)
|
||||
|
||||
1. **Chặn/defer OPEN_GUI khi transport PLAY** — đơn giản nhất, an toàn nhất:
|
||||
nếu đang PLAY, đợi transport STOP (hoặc tự tạm dừng) trước khi attach, resume
|
||||
sau. Loại bỏ hoàn toàn conflict audio-loop × attachView. (`ponytail:` người dùng
|
||||
muốn mở GUI khi đang chơi thì nâng cấp thành pause-resume tự động, hoặc đợi
|
||||
`setProcessing(false)` + đợi renderAll thoát.)
|
||||
2. **Giới hạn retry**: bỏ `openVstGuiRetry` spam; thử tối đa 2-3 lần có backoff.
|
||||
3. **Watchdog đừng giết khi đang attach GUI**: phân biệt stall do GUI job dài (có
|
||||
attach-in-flight flag) với stall do bridge chết thật; nâng ngưỡng stall khi có
|
||||
attach đang chạy.
|
||||
4. **Fix state reset**: `reload()` nên save/restore state (`getState`/`setState`)
|
||||
thay vì load instance mới mất preset. (Bug phụ, độc lập.)
|
||||
5. (Dài hạn) 1 apartment chung cho mọi instance cùng DLL (`shared_worker` pattern
|
||||
đã có trong probe) — loại conflict nhiều-thread-1-DLL triệt để.
|
||||
|
||||
## 6. Files liên quan
|
||||
|
||||
- `native_bridge/src/main.cpp` — handleOpenGui (943), silence/close-other (1015-1090), attach job + catch (1132-1160)
|
||||
- `native_bridge/src/Vst3Instrument.cpp` — reload() (615), reloadForGUI() (528), attachView() (550), closeGUI() (640)
|
||||
- `native_bridge/src/gui_probe.cpp` — probe bridge_two (243), two_workers_close (318)
|
||||
- `native_bridge/debug/` — sweep_all_gui.py, sweep_bridge_two_8s.json, probe_attach_detail.py, probe_app4_live.py, probe_app4.py
|
||||
- Bridge log: `%AppData%/SonicForgeDAW/logs/bridge.log`
|
||||
|
||||
Trạng thái live hiện tại: app câm (bridge 21932 sống, không instrument, transport
|
||||
STOP). Test thêm bằng `probe_app4_live.py` sẽ lại làm hư session — cần xác nhận
|
||||
trước khi chạy tiếp.
|
||||
@@ -0,0 +1,6 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
cd 'C:/Users/locpham/SonicForgeStudio/native_bridge/build'
|
||||
cmake -DCMAKE_CXX_FLAGS_RELEASE='/O2 /Ob2 /DNDEBUG /Zi' -DCMAKE_EXE_LINKER_FLAGS_RELEASE='/DEBUG' .
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
cmake --build . --config Release --target daw_vst_bridge
|
||||
exit $LASTEXITCODE
|
||||
@@ -0,0 +1,6 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
cd 'C:/Users/locpham/SonicForgeStudio/native_bridge/build'
|
||||
cmake -DCMAKE_CXX_FLAGS_RELEASE='/O2 /Ob2 /DNDEBUG /Zi' -DCMAKE_EXE_LINKER_FLAGS_RELEASE='/DEBUG' .
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
cmake --build . --config Release --target gui_probe
|
||||
exit $LASTEXITCODE
|
||||
@@ -0,0 +1,760 @@
|
||||
⨊⨪⨪⨪⨪⨪⨪倠敲慰楲杮琠敨攠癮物湯敭瑮映牯䐠扥杵敧硅整獮潩獮䜠污敬祲爠灥獯瑩牯敩⨪⨪⨪⨪⨪⨪⨪ †硅整獮潩剮灥獯瑩牯⁹›浉汰捩瑩 †獕䕥灸牥浩湥慴䙬慥畴敲潆乲杵瑥桓牡›牴敵 †汁潬乷杵瑥硅啥摰瑡›牴敵 †潎䥮瑮牥捡楴敶畎敧⁴›牴敵 †汁潬乷杵瑥卍牃摥湥楴污牐癯摩牥湉瑳污›牴敵 †汁潬偷牡污敬䥬楮楴污穩瑡潩佮䱦捯污敒潰楳潴楲獥㨠琠畲 †ⴭ䌠湯楦畧楲杮爠灥獯瑩牯敩ੳ†††ⴭⴭ‾敒潰楳潴祲㨠䰠捯污湉瑳污敬Ɽ䔠慮汢摥›牴敵 ††ⴠⴭ㸭删灥獯瑩牯⁹›獕牥硅整獮潩獮湅扡敬㩤琠畲㸊㸾㸾㸾㸾㸾㸾倠敲慰楲杮琠敨攠癮物湯敭瑮映牯䐠扥杵敧硅整獮潩獮䜠污敬祲爠灥獯瑩牯敩潣灭敬整Ɽ搠牵瑡潩⸰〰‰敳潣摮ੳ⨊⨪⨪⨪⨪⨪⨪圠楡楴杮映牯䐠扥杵敧硅整獮潩獮䜠污敬祲琠湉瑩慩楬敺⨠⨪⨪⨪⨪⨪⨪ਪ㸊㸾㸾㸾㸾㸾㸾圠楡楴杮映牯䐠扥杵敧硅整獮潩獮䜠污敬祲琠湉瑩慩楬敺挠浯汰瑥摥畤慲楴湯〠〮㘱猠捥湯獤 †ⴭⴭ‾敒潰楳潴祲㨠唠敳䕲瑸湥楳湯ⱳ䔠慮汢摥›牴敵慐正条獥挠畯瑮›ਰ†ⴠⴭ㸭删灥獯瑩牯⁹›潌慣䥬獮慴汬摥湅扡敬㩤琠畲ⱥ倠捡慫敧潣湵㩴㐠ਸ਼䴊捩潲潳瑦⠠⥒圠湩潤獷䐠扥杵敧敖獲潩〱〮㈮㘹㜱ㄮ〰‰䵁㙄潃祰楲桧⁴挨
楍牣獯景⁴潃灲牯瑡潩䄠汬爠杩瑨敲敳癲摥ਮ䌊浯慭摮楌敮›尮畧彩牰扯硥䌢尺牐杯慲楆敬屳潃浭湯䘠汩獥噜呓尳敎畸獶㍴•桳牡摥睟牯敫㈱ਊ⨪⨪⨪⨪⨪⨪慐桴瘠污摩瑡潩畳浭牡⁹⨪⨪⨪⨪⨪⨪⨪刊獥潰獮††††††††††††楔敭⠠獭
††潌慣楴湯䐊晥牥敲†††††††††††††††††††牳⩶匊浹潢敳牡档瀠瑡獩›牳⩶䔊數畣慴汢敳牡档瀠瑡獩›ਊⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭ⬭簊吠楨慴杲瑥猠灵潰瑲慈摲慷敲攭普牯散瑓捡牐瑯捥楴湯⁁坈戠獡摥††⁼匢慨潤⁷瑓捡≫洠祡戠癡楡慬汢潴愠獳獩⁴湩搠扥杵楧杮愠摮愠慮祬楳†簠簊匠敥愠慫洮⽳獵牥獨⁰潦潭敲椠普†††††††††††††††††††⁼†††††††††††††††††††††††††††††††††††簠簊搠獰䀠獳⁰†††††††††††††††††††††††††††††††⁼†††††††††††††††††††††††††††††††††††簠⬊ⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭਫ䴊摯潌摡›〰〰昷㝦捠摥〶〰‰〰〰昷㝦捠㍦㙢〰‰†畧彩牰扯硥潍䱤慯㩤〠〰㜰晦恦敥㘱〰〰〠〰㜰晦恦敥挳〶〰†渠摴汬搮汬䴊摯潌摡›〰〰昷晦敠慤〲〰‰〰〰昷晦敠慤㥥〰‰†㩃坜义佄南卜獹整㍭尲䕋乒䱅㈳䐮䱌䴊摯潌摡›〰〰昷晦敠㝢っ〰‰〰〰昷晦敠扢晢〰‰†㩃坜义佄南卜獹整㍭尲䕋乒䱅䅂䕓搮汬䴊摯潌摡›〰〰昷晦敠づづ〰‰〰〰昷晦敠ㅥ㈱〰‰†㩃坜义佄南卜獹整㍭尲䵉㍍⸲汤੬潍䱤慯㩤〠〰㜰晦恦扥戴〰〰〠〰㜰晦恦扥搴〷〰†䌠尺䥗䑎坏屓祓瑳浥㈳睜湩㈳汤੬潍䱤慯㩤〠〰㜰晦恦捥攱〰〰〠〰㜰晦恦捥愳〶〰†䌠尺䥗䑎坏屓祓瑳浥㈳啜䕓㍒⸲汤੬潍䱤慯㩤〠〰㜰晦恦捥㐶〰〰〠〰㜰晦恦捥㘶ぢ〰†䌠尺䥗䑎坏屓祓瑳浥㈳䝜䥄㈳搮汬䴊摯潌摡›〰〰昷晦敠扢つ〰‰〰〰昷晦敠换㥦〰‰†㩃坜义佄南卜獹整㍭尲摧㍩昲汵汤੬潍䱤慯㩤〠〰㜰晦恥㝣㤴〰〰〠〰㜰晦恥㝣㜵〴〰†䌠尺獕牥屳潬灣慨屭潓楮䙣牯敧瑓摵潩湜瑡癩彥牢摩敧扜極摬剜汥慥敳汜扩汦極獤湹桴㌭搮汬䴊摯潌摡›〰〰昷晦敠㍢〷〰‰〰〰昷晦敠㑢㌱〰‰†㩃坜义佄南卜獹整㍭尲獭捶彰楷汤੬潍䱤慯㩤〠〰㜰晦恦扥攴〰〰〠〰㜰晦恦扥㈶っ〰†䌠尺䥗䑎坏屓祓瑳浥㈳畜牣扴獡汤੬潍䱤慯㩤〠〰㜰晦恦捥慦〰〰〠〰㜰晦恦摥㈷〸〰†䌠尺䥗䑎坏屓祓瑳浥㈳卜䕈䱌㈳搮汬䴊摯潌摡›〰〰昷晦敠㡤〸〰‰〰〰昷晦敠慤㤱〰‰†㩃坜义佄南卜獹整㍭尲汯㍥⸲汤੬潍䱤慯㩤〠〰㜰晦恦捥㍡〰〰〠〰㜰晦恦捥扡〲〰†䌠尺䥗䑎坏屓祓瑳浥㈳坜㉓㍟⸲汤੬潍䱤慯㩤〠〰㜰晦恦捥愶〰〰〠〰㜰晦恦捥㉡〵〰†䌠尺䥗䑎坏屓祓瑳浥㈳捜浯慢敳搮汬䴊摯潌摡›〰〰昷晦ㅠ摣〳〰‰〰〰昷晦ㅠ摣㑣〰‰†㩃坜义佄南卜卙䕔㍍尲卄問䑎搮汬䴊摯潌摡›〰〰昷晦敠㠴つ〰‰〰〰昷晦敠㤴㘰〰‰†㩃坜义佄南卜卙䕔㍍尲䥗䵎⹍汤੬潍䱤慯㩤〠〰〰㌲恤㌲㌴〰〰〠〰〰㌲恤㌲㐵〸〰†䌠尺䥗䑎坏屓祓瑳浥㈳剜䍐呒⸴汤੬潍䱤慯㩤〠〰㜰晦恦捥㝢〰〰〠〰㜰晦恦捥㡣〸〰†䌠尺䥗䑎坏屓祓瑳浥㈳剜䍐呒⸴汤੬潍䱤慯㩤〠〰㜰晦恦扥㉦〰〰〠〰㜰晦恦扥摦っ〰†䌠尺䥗䑎坏屓祓瑳浥㈳慜癤灡㍩⸲汤੬潍䱤慯㩤〠〰㜰晦恦挱㝣〰〰〠〰㜰晦恦挱㉤〷〰†䌠尺䥗䑎坏屓奓呓䵅㈳剜獥浡汰䑥潭䐮䱌䴊摯潌摡›〰〰昷晦敠捣〹〰‰〰〰昷晦敠摣㤳〰‰†㩃坜义佄南卜獹整㍭尲獭捶瑲搮汬䴊摯潌摡›〰〰昷晦捠㔲ち〰‰〰〰昷晦捠㘲搳〰‰†㩃坜义佄南卜卙䕔㍍尲卍䍖ㅐ〴搮汬䴊摯潌摡›〰〰昷晦捠㘲〴〰‰〰〰昷晦捠㘲挶〰‰†㩃坜义佄南卜卙䕔㍍尲䍖啒呎䵉ㅅ〴搮汬䴊摯潌摡›〰〰昷晦敠散っ〰‰〰〰昷晦敠晣㤹〰‰†㩃坜义佄南卜獹整㍭尲䱏䅅呕㈳搮汬䴊摯潌摡›〰〰昷晦敠慣っ〰‰〰〰昷晦敠扣愶〰‰†㩃坜义佄南卜獹整㍭尲敳档獯汤੬潍䱤慯㩤〠〰㜰晦恦㑤昲〰〰〠〰㜰晦恦㑤昲っ〰†䌠尺䥗䑎坏屓奓呓䵅㈳噜剃乕䥔䕍㐱弰⸱汤੬潍䱤慯㩤〠〰㜰晦恦摥㌷〰〰〠〰㜰晦恦摥㈸〹〰†䌠尺䥗䑎坏屓祓瑳浥㈳獜捨牯汤੬潍䱤慯㩤〠〰㜰晦恦ㅡ㘸〰〰〠〰㜰晦恦ㅡ愸〳〰†䌠尺䥗䑎坏屓奓呓䵅㈳䵜噓偃㐱弰⸲汤੬潍䱤慯㩤〠〰㜰晦恦㌷㜱〰〰〠〰㜰晦恦㌷㜱づ〰†䌠尺䥗䑎坏屓奓呓䵅㈳浜摳潭搮汬䴊摯潌摡›〰〰昷晦敠ㅢつ〰‰〰〰昷晦敠㉢攲〰‰†㩃坜义佄南卜卙䕔㍍尲潰牷牰景搮汬䴊摯潌摡›〰〰昷晦捠㈸て〰‰〰〰昷晦捠㌸㜲〰‰†㩃坜义佄南卜卙䕔㍍尲楷浮扭獡汤੬潍䱤慯㩤〠〰〰㌲恤㌲㌴〰〰〠〰〰㌲恤㌲㠴づ〰†䌠尺䥗䑎坏屓奓呓䵅㈳灜睯灲潲汤੬潍䱤慯㩤〠〰㜰晦恦慥摥〰〰〠〰㜰晦恦慥㉦〲〰†䌠尺䥗䑎坏屓奓呓䵅㈳捜杦杭㍲⸲汤੬潍䱤慯㩤〠〰㜰晦恦扥戱〰〰〠〰㜰晦恦扥挱〵〰†䌠尺䥗䑎坏屓奓呓䵅㈳啜偍䍄搮汬䴊摯潌摡›〰〰昷晦敠ち〲〰‰〰〰昷晦敠ち戳〰‰†㩃坜义佄南卜卙䕔㍍尲敫湲汥愮灰潣敲搮汬䴊摯潌摡›〰〰昷晦敠㝢〰〰‰〰〰昷晦敠㝢捡〰‰†㩃坜义佄南卜獹整㍭尲换祲瑰牐浩瑩癩獥搮汬䴊摯潌摡›〰〰昷晦敠㐸ち〰‰〰〰昷晦敠㔸㠴〰‰†㩃坜义佄南獜獹整㍭尲硵桴浥汤੬潍䱤慯㩤〠〰㜰晦恦捥㜰〰〰〠〰㜰晦恦捥挱つ〰†䌠尺䥗䑎坏屓祓瑳浥㈳䵜䍓䙔搮汬漊湷睈摮〽〰〰〰〰䄰ㅃ㈰潬摡湩㩃停潲牧浡䘠汩獥䍜浯潭楆敬屳卖㍔乜硥獵瘮瑳ਲ਼潍䱤慯㩤〠〰㜰晦恥㥣攱〰〰〠〰㜰晦恥慣攵〵〰†䌠尺牐杯慲楆敬屳潃浭湯䘠汩獥噜呓尳敎畸獶㍴䴊摯潌摡›〰〰昷晦敠㙣〷〰‰〰〰昷晦敠㙣〹〰‰†㩃坜义佄南卜獹整㍭尲浩条桥灬搮汬䴊摯潌摡›〰〰昷晦敠摣〴〰‰〰〰昷晦敠散㔳〰‰†㩃坜义佄南卜獹整㍭尲佃䑍䝌㈳搮汬䴊摯潌摡›〰〰昷晦敠㔸つ〰‰〰〰昷晦敠㜸愰〰‰†㩃坜义佄南卜卙䕔㍍尲硤楧搮汬䴊摯潌摡›〰〰昷晦敠晤ぢ〰‰〰〰昷晦敠づ㘱〰‰†㩃坜义佄南卜獹整㍭尲䡓坌偁⹉汤੬潍䱤慯㩤〠〰㜰晦恦扥㈴〰〰〠〰㜰晦恦扥愴〳〰†䌠尺䥗䑎坏屓祓瑳浥㈳坜义剔单⹔汤੬潍䱤慯㩤〠〰㜰晦恦㕣〳〰〰〠〰㜰晦恦㕣戳〵〰†䌠尺䥗䑎坏屓楗卮卸慜摭㐶浟捩潲潳瑦眮湩潤獷挮浯潭潣瑮潲獬㙟㤵戵㐶㐱挴晣搱彦⸵㈸㈮ㄶ〰㠮㈳弸潮敮㡟攷摥㥥㜵㉡捣摤層佃䍍䱔㈳搮汬䴊摯潌摡›〰〰昷晦捠㐳〳〰‰〰〰昷晦捠㘳㕣〰‰†㩃坜义佄南卜卙䕔㍍尲䥗䥎䕎⹔汤੬潍䱤慯㩤〠〰㜰晦恦扤昶〰〰〠〰㜰晦恦扤昶ぢ〰†䌠尺䥗䑎坏屓奓呓䵅㈳噜剅䥓乏搮汬䴊摯潌摡›〰〰昷晦敠摢〰〰‰〰〰昷晦敠敢攷〰‰†㩃坜义佄南卜獹整㍭尲剃偙㍔⸲汤੬潍䱤慯㩤〠〰㜰晦恦扥晦〰〰〠〰㜰晦恦捥㘰〳〰†䌠尺䥗䑎坏屓祓瑳浥㈳坜䑌偁㈳搮汬䴊摯潌摡›〰〰昷晦敠㙣〳〰‰〰〰昷晦敠㙣㠳〰‰†㩃坜义佄南卜獹整㍭尲潎浲污穩搮汬䴊摯潌摡›〰〰昷晦敠㉢〶〰‰〰〰昷晦敠㉢愸〰‰†㩃坜义佄南卜卙䕔㍍尲换祲瑰搮汬䴊摯潌摡›〰〰昷晦敠慡〴〰‰〰〰昷晦敠慡㌵〰‰†㩃坜义佄南卜卙䕔㍍尲卍十ㅎ搮汬䴊摯潌摡›〰〰昷晦敠攸〰〰‰〰〰昷晦敠㘹戹〰‰†㩃坜义佄南卜卙䕔㍍尲楷摮睯瑳牯条汤੬潍䱤慯㩤〠〰㜰晦恦㡥㜳〰〰〠〰㜰晦恦㡥㜳つ〰†䌠尺䥗䑎坏屓奓呓䵅㈳獜捥牵㈳搮汬䴊摯潌摡›〰〰昷晦敠㉡つ〰‰〰〰昷晦敠㍡㤱〰‰†㩃坜义佄南卜卙䕔㍍尲卓䥐䱃⹉䱄ੌ潍䱤慯㩤〠〰㜰晦恦㥥搹〰〰〠〰㜰晦恦㥥ち〳〰†䌠尺䥗䑎坏屓奓呓䵅㈳楜桰灬灡汤੬㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散潍䱤慯㩤〠〰㜰晦恦慥戵〰〰〠〰㜰晦恦慥ㄶっ〰†䌠尺䥗䑎坏屓祳瑳浥㈳浜睳潳正搮汬䴊摯潌摡›〰〰昷晦敠愹〶〰‰〰〰昷晦敠戹㡢〰‰†㩃坜义佄南卜卙䕔㍍尲乄䅓䥐搮汬䴊摯潌摡›〰〰昷晦敠㍡ぢ〰‰〰〰昷晦敠㍡摢〰‰†㩃坜义佄南卜卙䕔㍍尲卄䅐卒⹅汤੬潍䱤慯㩤〠〰㜰晦恦摥晡〰〰〠〰㜰晦恦摥晡ち〰†䌠尺䥗䑎坏屓祓瑳浥㈳乜䥓搮汬䴊摯潌摡›〰〰昷晦摠慢て〰‰〰〰昷晦摠慢扦〰‰†㩃坜湩潤獷卜獹整㍭尲慲慳桤灬搮汬䴊摯潌摡›〰〰昷晦摠扤〶〰‰〰〰昷晦摠扤㙥〰‰†㩃坜义佄南卜獹整㍭尲睦異汣瑮搮汬⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散〲㐺㨱㔰›剅⁒ⴠ䘠楡敬潴搠睯汮慯㩤栠瑴獰⼺愯瑵敲硦砮浯氯杯湩港⼴䌠畯摬渠瑯爠獥汯敶栠獯㩴愠瑵敲硦砮浯嬠崶䴊摯潌摡›〰〰昷晦敠改〵〰‰〰〰昷晦敠昹㔱〰‰†㩃坜义佄南獜獹整㍭尲捳慨湮汥䐮䱌嬊獖㍴湉瑳畲敭瑮⁝潬摡摥䌠尺牐杯慲楆敬屳潃浭湯䘠汩獥噜呓尳敎畸獶㍴⠠敎畸⥳漠瑵桃㈽嬊桳牡摥睟牯敫嵲氠慯湩瑳㴱潍䱤慯㩤〠〰㜰晦恦㝥㔰〰〰〠〰㜰晦恦㝥㠶ち〰†䌠尺䥗䑎坏屓奓呓䵅㈳摜搲⸱汤੬潍䱤慯㩤〠〰㜰晦恦㙥敤〰〰〠〰㜰晦恦㝥㐰〷〰†䌠尺䥗䑎坏屓奓呓䵅㈳䑜牗瑩汤੬潍䱤慯㩤〠〰㜰晦恦㝥㤶〰〰〠〰㜰晦恦㝥昸〰〰†䌠尺䥗䑎坏屓奓呓䵅㈳摜搳ㄱ搮汬䴊摯潌摡›〰〰昷晦㡠㕥〰〰‰〰〰昷晦㡠慥敡〰‰†㩃坜义佄南卜卙䕔㍍尲㍄ㅄ地牡汤੬潍䱤慯㩤〠〰㜰晦恦㡥㠵〰〰〠〰㜰晦恦㡥挵〵〰†䌠尺䥗䑎坏屓奓呓䵅㈳摜捸牯汤੬潍䱤慯㩤〠〰㜰晦恦㡥扡〰〰〠〰㜰晦恦㡥捡〴〰†䌠尺䥗䑎坏屓奓呓䵅㈳牜獥畯捲灥汯捩捹楬湥汤੬潍䱤慯㩤〠〰㜰晦恦㕥㑣〰〰〠〰㜰晦恦㕥㥣て〰†䌠尺䥗䑎坏屓奓呓䵅㈳摜物捥硴慤慴慢敳敨灬牥搮汬漊敮潣敲睜湩潤獷摜物捥硴摜瑡扡獡履敨灬牥楬牢牡屹楬屢数慲灰獵牥敳瑴湩獧畱牥楹灭灣⡰㌱⤵摜物捥硴慤慴慢敳敨灬牥搮汬〡〰㜰䙆䕆䌵䄵㜴㨶⠠慣汬牥›〰〰䘷䙆㕅㕃㍁䌲
敒畴湲版ㄨ
楴⡤㤶〶
〸㜰〰㈰吠敨猠獹整慣湮瑯映湩桴楦敬猠数楣楦摥ਮ湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩摜物捥硴慤慴慢敳敨灬牥挮灰㈨㤲⤰摜物捥硴慤慴慢敳敨灬牥搮汬〡〰㜰䙆䕆䌵㈵ㅁ㩁⠠慣汬牥›〰〰䘷䙆㡅㔶㤴䔴
敒畴湲版㈨
楴⡤㤶〶
〸㜰〰㈰吠敨猠獹整慣湮瑯映湩桴楦敬猠数楣楦摥ਮ湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲⤳琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩漊敮潣敲睜湩潤獷摜物捥硴摜瑡扡獡履敨灬牥楬牢牡屹楬屢数慲灰獵牥敳瑴湩獧畱牥楹灭灣⡰㌱⤵摜物捥硴慤慴慢敳敨灬牥搮汬〡〰㜰䙆䕆䌵䄵㜴㨶⠠慣汬牥›〰〰䘷䙆㕅㕃㍁䌲
敒畴湲版㐨
楴⡤㤶〶
〸㜰〰㈰吠敨猠獹整慣湮瑯映湩桴楦敬猠数楣楦摥ਮ湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲⤵琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩漊敮潣敲睜湩潤獷摜物捥硴摜瑡扡獡履敨灬牥楬牢牡屹楬屢数慲灰獵牥敳瑴湩獧畱牥楹灭灣⡰㌱⤵摜物捥硴慤慴慢敳敨灬牥搮汬〡〰㜰䙆䕆䌵䄵㜴㨶⠠慣汬牥›〰〰䘷䙆㕅㕃㍁䌲
敒畴湲版㘨
楴⡤㤶〶
〸㜰〰㈰吠敨猠獹整慣湮瑯映湩桴楦敬猠数楣楦摥ਮ湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲⤷琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩漊敮潣敲睜湩潤獷摜物捥硴摜瑡扡獡履敨灬牥楬牢牡屹楬屢数慲灰獵牥敳瑴湩獧畱牥楹灭灣⡰㌱⤵摜物捥硴慤慴慢敳敨灬牥搮汬〡〰㜰䙆䕆䌵䄵㜴㨶⠠慣汬牥›〰〰䘷䙆㕅㕃㍁䌲
敒畴湲版㠨
楴⡤㤶〶
〸㜰〰㈰吠敨猠獹整慣湮瑯映湩桴楦敬猠数楣楦摥ਮ湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲⤹琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩漊敮潣敲睜湩潤獷摜物捥硴摜瑡扡獡履敨灬牥楬牢牡屹楬屢数慲灰獵牥敳瑴湩獧畱牥楹灭灣⡰㌱⤵摜物捥硴慤慴慢敳敨灬牥搮汬〡〰㜰䙆䕆䌵䄵㜴㨶⠠慣汬牥›〰〰䘷䙆㕅㕃㍁䌲
敒畴湲版ㄨ⤰琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩䴊摯潌摡›〰〰昷晦敠扡〴〰‰〰〰昷晦敠扡〷〰‰†㩃坜义佄南卜卙䕔㍍尲据祲瑰搮汬䴊摯潌摡›〰〰昷晦敠慡て〰‰〰〰昷晦敠扡昲〰‰†㩃坜义佄南卜卙䕔㍍尲呎十ㅎ搮汬䴊摯潌摡›〰〰昷晦㥠扣〱〰‰〰〰昷晦㥠扣㠵〰‰†㩃坜义佄南獜獹整㍭尲据祲瑰獳灬搮汬⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥㈊㨰ㄴ〺㨹䤠䙎⁏敎畸⸴⸵㜱⠠畣汲㠠㐮〮〲㐺㨱㤰›义但ⴠㄠ‵畁〲㘲㈊㨰ㄴ〺㨹䤠䙎⁏潃灭瑵牥丠浡㩥䐠卅呋偏㐭㍄䜳䈷㈊㨰ㄴ〺㨹䤠䙎⁏潃瑮湥⁴慰桴›㩆䵜单䍉卟䙏坔剁居敲塆ⴠ丠硥獵㐠䌠浯汰瑥履敎畸楌牢牡〲㐺㨱㤰›义但ⴠ䠠獯㩴䌠尺獕牥屳潬灣慨屭潓楮䙣牯敧瑓摵潩湜瑡癩彥牢摩敧扜極摬剜汥慥敳杜極灟潲敢攮數䴊摯潌摡›〰〰昷晦敠ㅡ〵〰‰〰〰昷晦敠ㅡ㘸〰‰†㩃坜义佄南卜卙䕔㍍尲瑮慭瑲汤੬潍䱤慯㩤〠〰㜰晦恦敥㈰〰〰〠〰㜰晦恦敥挰づ〰†䌠尺䥗䑎坏屓祓瑳浥㈳捜扬慣煴搮汬䴊摯潌摡›〰〰昷晦摠㕣〰〰‰〰〰昷晦摠㝣〵〰‰†㩃坜湩潤獷卜獹整㍭尲睴湩灡灡捰牯汤੬潍䱤慯㩤〠〰㜰晦恦ㅣ㐸〰〰〠〰㜰晦恦ㅣ㤸っ〰†䌠尺䥗䑎坏屓祳瑳浥㈳摜瑡敡捸慨杮汤੬湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲ㄱ
楴⡤㤶〶
〸㜰〰㈰吠敨猠獹整慣湮瑯映湩桴楦敬猠数楣楦摥ਮ獛慨敲彤潷歲牥⁝瑡慴档椠獮ㅴㄽ栠湷㵤〰〰〰〰㌰ぁ䔰㠷⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散噛瑳䤳獮牴浵湥嵴氠慯敤㩃停潲牧浡䘠汩獥䍜浯潭楆敬屳卖㍔乜硥獵瘮瑳″丨硥獵
畯䍴㵨ਲ獛慨敲彤潷歲牥⁝潬摡椠獮㉴ㄽ⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥⠊㔷挰㘮㘹⤰›⭃䡅攠捸灥楴湯ⴠ挠摯づ搶㌷㌶⠠楦獲⁴档湡散㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥嬊桳牡摥睟牯敫嵲愠瑴捡湩瑳㴲‱睨摮〽〰〰〰〰㜲〵㉆ਸ睛異灭⁝獭㵧砰ㄳ⁆睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ潍䱤慯㩤〠〰㜰晦恦慡㕤〰〰〠〰㜰晦恦慡㥥〶〰†䌠尺䥗䑎坏屓奓呓䵅㈳瑜硥楴灮瑵牦浡睥牯汤੬睛異灭⁝獭㵧砰ㄳ⁆睨摮〽〰〰〰〰䄳〰㝅ਸ睛異灭⁝獭㵧砰ㄳ⁆睨摮〽〰〰〰〰㜲〵㉆ਸ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰ㄱ″睨摮〽〰〰〰〰䌴〴㍂ੁ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱ਲ䕒啓呌›潤敮ㄽ愠敒㵳‱剢獥ㄽ嬊灷浵嵰洠杳〽㑸䈷栠湷㵤〰〰〰〰〰䍆ㄱ㈷⠊㔷挰㘮挵⤴›敓畣楲祴挠敨正映楡畬敲漠瑳捡畢晦牥漠敶牲湵ⴠ挠摯っ〰㐰㤰⠠℡‡敳潣摮挠慨据℡⤡匊扵潣敤›砰‷䅆呓䙟䥁彌䅆䅔彌偁彐塅呉ਠ捵瑲慢敳愡潢瑲〫㑸㩥《〰㜰晦恦扥㠵㈵攷挠㉤‹†††††椠瑮††㈠根《〺〰‾摣㩢删慥楤杮椠楮楴污挠浯慭摮✠❧圊剁䥎䝎›潃瑮湩極杮愠渠湯挭湯楴畮扡敬攠捸灥楴湯⠊㔷挰㘮挵⤴›敓畣楲祴挠敨正映楡畬敲漠瑳捡畢晦牥漠敶牲湵ⴠ挠摯っ〰㐰㤰⠠℡‡敳潣摮挠慨据℡⤡匊扵潣敤›砰‷䅆呓䙟䥁彌䅆䅔彌偁彐塅呉ਠ捵瑲慢敳愡潢瑲〫㑸㩥《〰㜰晦恦扥㠵㈵攷挠㉤‹†††††椠瑮††㈠根�
|
||||
⨪⨪⨪⨪⨪⨪牐灥牡湩桴湥楶潲浮湥⁴潦敄畢杧牥䔠瑸湥楳湯慇汬牥⁹敲潰楳潴楲獥⨠⨪⨪⨪⨪⨪⨪�
|
||||
†䔠瑸湥楳湯敒潰楳潴祲㨠䤠灭楬楣�
|
||||
†唠敳硅数楲敭瑮污敆瑡牵䙥牯畎敧却慨敲㨠琠畲�
|
||||
†䄠汬睯畎敧䕴數灕慤整㨠琠畲�
|
||||
†丠湯湉整慲瑣癩乥杵瑥㨠琠畲�
|
||||
†䄠汬睯畎敧䵴䍓敲敤瑮慩偬潲楶敤䥲獮慴汬㨠琠畲�
|
||||
†䄠汬睯慐慲汬汥湉瑩慩楬慺楴湯晏潌慣剬灥獯瑩牯敩›牴敵
|
||||
|
||||
†ⴠ潃普杩牵湩敲潰楳潴楲獥
|
||||
†††ⴭⴭ‾敒潰楳潴祲㨠䰠捯污湉瑳污敬Ɽ䔠慮汢摥›牴敵
|
||||
†††ⴭⴭ‾敒潰楳潴祲㨠唠敳䕲瑸湥楳湯ⱳ䔠慮汢摥›牴敵
|
||||
|
||||
㸾㸾㸾㸾㸾㸾‾牐灥牡湩桴湥楶潲浮湥⁴潦敄畢杧牥䔠瑸湥楳湯慇汬牥⁹敲潰楳潴楲獥挠浯汰瑥摥畤慲楴湯〠〮〰猠捥湯獤
|
||||
|
||||
⨪⨪⨪⨪⨪⨪慗瑩湩潦敄畢杧牥䔠瑸湥楳湯慇汬牥⁹潴䤠楮楴污穩⨪⨪⨪⨪⨪⨪⨪
|
||||
|
||||
㸾㸾㸾㸾㸾㸾‾慗瑩湩潦敄畢杧牥䔠瑸湥楳湯慇汬牥⁹潴䤠楮楴污穩潣灭敬整Ɽ搠牵瑡潩⸰‶敳潣摮�
|
||||
†ⴠⴭ㸭删灥獯瑩牯⁹›獕牥硅整獮潩獮湅扡敬㩤琠畲ⱥ倠捡慫敧潣湵㩴〠
|
||||
†ⴠⴭ㸭删灥獯瑩牯⁹›潌慣䥬獮慴汬摥湅扡敬㩤琠畲ⱥ倠捡慫敧潣湵㩴㐠�
|
||||
|
||||
楍牣獯景⁴刨
楗摮睯敄畢杧牥嘠牥楳湯ㄠ⸰⸰㤲ㄶ⸷〱〰䄠䑍㐶
|
||||
潃祰楲桧⁴挨
楍牣獯景⁴潃灲牯瑡潩䄠汬爠杩瑨敲敳癲摥�
|
||||
|
||||
潃浭湡䱤湩㩥⸠杜極灟潲敢攮數∠㩃停潲牧浡䘠汩獥䍜浯潭楆敬屳卖㍔乜硥獵瘮瑳∳猠慨敲彤潷歲牥ㄠ�
|
||||
|
||||
⨪⨪⨪⨪⨪⨪慐桴瘠污摩瑡潩畳浭牡⁹⨪⨪⨪⨪⨪⨪⨪
|
||||
敒灳湯敳††††††††††††吠浩洨⥳††䰠捯瑡潩�
|
||||
敄敦牲摥†††††††††††††††††††猠癲�
|
||||
祓扭汯猠慥捲慰桴椠㩳猠癲�
|
||||
硅捥瑵扡敬猠慥捲慰桴椠㩳�
|
||||
|
||||
ⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭ⬭
|
||||
⁼桔獩琠牡敧⁴畳灰牯獴䠠牡睤牡ⵥ湥潦捲摥匠慴正倠潲整瑣潩䄠䠠⁗慢敳†簠
|
||||
⁼匢慨潤⁷瑓捡≫洠祡戠癡楡慬汢潴愠獳獩⁴湩搠扥杵楧杮愠摮愠慮祬楳†簠
|
||||
⁼敓歡獭甯敳桲灳映牯洠牯湩潦††††††††††††††††††簠
|
||||
⁼†††††††††††††††††††††††††††††††††††簠
|
||||
⁼灤獀灳†††††††††††††††††††††††††††††††簠
|
||||
⁼†††††††††††††††††††††††††††††††††††簠
|
||||
ⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭ⬭
|
||||
|
||||
潍䱤慯㩤〠〰㜰晦怷散㙤〰〰〠〰㜰晦怷晣戳〶〰†朠極灟潲敢攮數
|
||||
潍䱤慯㩤〠〰㜰晦恦敥㘱〰〰〠〰㜰晦恦敥挳〶〰†渠摴汬搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦摥㉡〰〰〠〰㜰晦恦摥敡〹〰†䌠尺䥗䑎坏屓祓瑳浥㈳䭜剅䕎㍌⸲䱄�
|
||||
潍䱤慯㩤〠〰㜰晦恦扥挷〰〰〠〰㜰晦恦扥扢て〰†䌠尺䥗䑎坏屓祓瑳浥㈳䭜剅䕎䉌十⹅汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦敥攰〰〰〠〰㜰晦恦敥ㄱ〲〰†䌠尺䥗䑎坏屓祓瑳浥㈳䥜䵍㈳搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦扥戴〰〰〠〰㜰晦恦扥搴〷〰†䌠尺䥗䑎坏屓祓瑳浥㈳睜湩㈳汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦捥攱〰〰〠〰㜰晦恦捥愳〶〰†䌠尺䥗䑎坏屓祓瑳浥㈳啜䕓㍒⸲汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦捥㐶〰〰〠〰㜰晦恦捥㘶ぢ〰†䌠尺䥗䑎坏屓祓瑳浥㈳䝜䥄㈳搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦扥摢〰〰〠〰㜰晦恦扥晣〹〰†䌠尺䥗䑎坏屓祓瑳浥㈳杜楤㈳畦汬搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恥㝣㤴〰〰〠〰㜰晦恥㝣㜵〴〰†䌠尺獕牥屳潬灣慨屭潓楮䙣牯敧瑓摵潩湜瑡癩彥牢摩敧扜極摬剜汥慥敳汜扩汦極獤湹桴㌭搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦扥㜳〰〰〠〰㜰晦恦扥ㄴ〳〰†䌠尺䥗䑎坏屓祓瑳浥㈳浜癳灣睟湩搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦扥攴〰〰〠〰㜰晦恦扥㈶っ〰†䌠尺䥗䑎坏屓祓瑳浥㈳畜牣扴獡汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦捥慦〰〰〠〰㜰晦恦摥㈷〸〰†䌠尺䥗䑎坏屓祓瑳浥㈳卜䕈䱌㈳搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦摥㠸〰〰〠〰㜰晦恦摥ㅡ〹〰†䌠尺䥗䑎坏屓祓瑳浥㈳潜敬㈳搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦捥㍡〰〰〠〰㜰晦恦捥扡〲〰†䌠尺䥗䑎坏屓祓瑳浥㈳坜㉓㍟⸲汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦捥愶〰〰〠〰㜰晦恦捥㉡〵〰†䌠尺䥗䑎坏屓祓瑳浥㈳捜浯慢敳搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦挱㍤〰〰〠〰㜰晦恦挱捤〴〰†䌠尺䥗䑎坏屓奓呓䵅㈳䑜体乕⹄汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㑥搸〰〰〠〰㜰晦恦㑥〹〶〰†䌠尺䥗䑎坏屓奓呓䵅㈳坜义䵍搮汬
|
||||
潍䱤慯㩤〠〰〰㌲恤㌲㌴〰〰〠〰〰㌲恤㌲㐵〸〰†䌠尺䥗䑎坏屓祓瑳浥㈳剜䍐呒⸴汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦捥㝢〰〰〠〰㜰晦恦捥㡣〸〰†䌠尺䥗䑎坏屓祓瑳浥㈳剜䍐呒⸴汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦扥㉦〰〰〠〰㜰晦恦扥摦っ〰†䌠尺䥗䑎坏屓祓瑳浥㈳慜癤灡㍩⸲汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦挱㝣〰〰〠〰㜰晦恦挱㉤〷〰†䌠尺䥗䑎坏屓奓呓䵅㈳剜獥浡汰䑥潭䐮䱌
|
||||
潍䱤慯㩤〠〰㜰晦恦捥㥣〰〰〠〰㜰晦恦捥㍤〹〰†䌠尺䥗䑎坏屓祓瑳浥㈳浜癳牣汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㉣愵〰〰〠〰㜰晦恦㉣㌶つ〰†䌠尺䥗䑎坏屓奓呓䵅㈳䵜噓偃㐱⸰汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㉣㐶〰〰〠〰㜰晦恦㉣㘶っ〰†䌠尺䥗䑎坏屓奓呓䵅㈳噜剃乕䥔䕍㐱⸰汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦捥捥〰〰〠〰㜰晦恦捥㥦〹〰†䌠尺䥗䑎坏屓祓瑳浥㈳作䕌啁㍔⸲汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦捥捡〰〰〠〰㜰晦恦捥㙢ち〰†䌠尺䥗䑎坏屓祓瑳浥㈳獜捥潨瑳搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦㑤昲〰〰〠〰㜰晦恦㑤昲っ〰†䌠尺䥗䑎坏屓奓呓䵅㈳噜剃乕䥔䕍㐱弰⸱汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦摥㌷〰〰〠〰㜰晦恦摥㈸〹〰†䌠尺䥗䑎坏屓祓瑳浥㈳獜捨牯汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦ㅡ㘸〰〰〠〰㜰晦恦ㅡ愸〳〰†䌠尺䥗䑎坏屓奓呓䵅㈳䵜噓偃㐱弰⸲汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㌷㜱〰〰〠〰㜰晦恦㌷㜱づ〰†䌠尺䥗䑎坏屓奓呓䵅㈳浜摳潭搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦扥搱〰〰〠〰㜰晦恦扥㈲づ〰†䌠尺䥗䑎坏屓奓呓䵅㈳灜睯灲潲汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㡣昲〰〰〠〰㜰晦恦㡣㈳〷〰†䌠尺䥗䑎坏屓奓呓䵅㈳睜湩浭慢敳搮汬
|
||||
潍䱤慯㩤〠〰〰㌲恤㌲㌴〰〰〠〰〰㌲恤㌲㠴づ〰†䌠尺䥗䑎坏屓奓呓䵅㈳灜睯灲潲汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦慥摥〰〰〠〰㜰晦恦慥㉦〲〰†䌠尺䥗䑎坏屓奓呓䵅㈳捜杦杭㍲⸲汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦扥戱〰〰〠〰㜰晦恦扥挱〵〰†䌠尺䥗䑎坏屓奓呓䵅㈳啜偍䍄搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦慥㈰〰〰〠〰㜰晦恦慥㌰ぢ〰†䌠尺䥗䑎坏屓奓呓䵅㈳歜牥敮灡捰牯汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦扥〷〰〰〠〰㜰晦恦扥愷っ〰†䌠尺䥗䑎坏屓祓瑳浥㈳扜牣灹側楲業楴敶汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㡥愴〰〰〠〰㜰晦恦㡥㐵〸〰†䌠尺䥗䑎坏屓祳瑳浥㈳畜瑸敨敭搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦捥㜰〰〰〠〰㜰晦恦捥挱つ〰†䌠尺䥗䑎坏屓祓瑳浥㈳䵜䍓䙔搮汬
|
||||
睯䡮湷㵤〰〰〰〰〰䍁〱䔲
|
||||
潬摡湩㩃停潲牧浡䘠汩獥䍜浯潭楆敬屳卖㍔乜硥獵瘮瑳�
|
||||
潍䱤慯㩤〠〰㜰晦恥㥣攱〰〰〠〰㜰晦恥慣攵〵〰†䌠尺牐杯慲楆敬屳潃浭湯䘠汩獥噜呓尳敎畸獶㍴
|
||||
潍䱤慯㩤〠〰㜰晦恦捥㜶〰〰〠〰㜰晦恦捥㤶〰〰†䌠尺䥗䑎坏屓祓瑳浥㈳楜慭敧汨汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦捥㑤〰〰〠〰㜰晦恦捥㍥〵〰†䌠尺䥗䑎坏屓祓瑳浥㈳䍜䵏䱄㍇⸲汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㡥搵〰〰〠〰㜰晦恦㡥〷ち〰†䌠尺䥗䑎坏屓奓呓䵅㈳摜杸汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦摥扦〰〰〠〰㜰晦恦敥〶〰†䌠尺䥗䑎坏屓祓瑳浥㈳卜䱈䅗䥐搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦扥㈴〰〰〠〰㜰晦恦扥愴〳〰†䌠尺䥗䑎坏屓祓瑳浥㈳坜义剔单⹔汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㕣〳〰〰〠〰㜰晦恦㕣戳〵〰†䌠尺䥗䑎坏屓楗卮卸慜摭㐶浟捩潲潳瑦眮湩潤獷挮浯潭潣瑮潲獬㙟㤵戵㐶㐱挴晣搱彦⸵㈸㈮ㄶ〰㠮㈳弸潮敮㡟攷摥㥥㜵㉡捣摤層佃䍍䱔㈳搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦㍣㌴〰〰〠〰㜰晦恦㍣挶〵〰†䌠尺䥗䑎坏屓奓呓䵅㈳坜义义呅搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦扤昶〰〰〠〰㜰晦恦扤昶ぢ〰†䌠尺䥗䑎坏屓奓呓䵅㈳噜剅䥓乏搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦扥つ〰〰〠〰㜰晦恦扥㝥づ〰†䌠尺䥗䑎坏屓祓瑳浥㈳䍜奒呐㈳搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦扥晦〰〰〠〰㜰晦恦捥㘰〳〰†䌠尺䥗䑎坏屓祓瑳浥㈳坜䑌偁㈳搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦捥㌶〰〰〠〰㜰晦恦捥㌶〸〰†䌠尺䥗䑎坏屓祓瑳浥㈳乜牯慭楬汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦扥㘲〰〰〠〰㜰晦恦扥㠲ち〰†䌠尺䥗䑎坏屓奓呓䵅㈳扜牣灹汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦慥㑡〰〰〠〰㜰晦恦慥㕡〳〰†䌠尺䥗䑎坏屓奓呓䵅㈳䵜䅓乓⸱汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㡥づ〰〰〠〰㜰晦恦㥥㤶ぢ〰†䌠尺䥗䑎坏屓奓呓䵅㈳睜湩潤獷献潴慲敧搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦㡥㜳〰〰〠〰㜰晦恦㡥㜳つ〰†䌠尺䥗䑎坏屓奓呓䵅㈳獜捥牵㈳搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦慥搲〰〰〠〰㜰晦恦慥ㄳ〹〰†䌠尺䥗䑎坏屓奓呓䵅㈳卜偓䍉䥌䐮䱌
|
||||
潍䱤慯㩤〠〰㜰晦恦㥥搹〰〰〠〰㜰晦恦㥥ち〳〰†䌠尺䥗䑎坏屓奓呓䵅㈳楜桰灬灡汤�
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
潍䱤慯㩤〠〰㜰晦恦慥戵〰〰〠〰㜰晦恦慥ㄶっ〰†䌠尺䥗䑎坏屓祳瑳浥㈳浜睳潳正搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦㥥㙡〰〰〠〰㜰晦恦㥥扢〸〰†䌠尺䥗䑎坏屓奓呓䵅㈳䑜华偁⹉汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦慥戳〰〰〠〰㜰晦恦慥戳つ〰†䌠尺䥗䑎坏屓奓呓䵅㈳䑜偓剁䕓搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦摥晡〰〰〠〰㜰晦恦摥晡ち〰†䌠尺䥗䑎坏屓祓瑳浥㈳乜䥓搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦扤晡〰〰〠〰㜰晦恦扤晡ぢ〰†䌠尺楗摮睯屳祓瑳浥㈳牜獡摡汨汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦摤㙢〰〰〠〰㜰晦恦摤敢〶〰†䌠尺䥗䑎坏屓祓瑳浥㈳晜灷捵湬汤�
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
〲㐺㨱㔰›剅⁒ⴠ䘠楡敬潴搠睯汮慯㩤栠瑴獰⼺愯瑵敲硦砮浯氯杯湩港⼴䌠畯摬渠瑯爠獥汯敶栠獯㩴愠瑵敲硦砮浯嬠崶
|
||||
潍䱤慯㩤〠〰㜰晦恦㥥㕥〰〰〠〰㜰晦恦㥥ㅦ〵〰†䌠尺䥗䑎坏屓祳瑳浥㈳獜档湡敮䱄�
|
||||
噛瑳䤳獮牴浵湥嵴氠慯敤㩃停潲牧浡䘠汩獥䍜浯潭楆敬屳卖㍔乜硥獵瘮瑳″丨硥獵
畯䍴㵨�
|
||||
獛慨敲彤潷歲牥⁝潬摡椠獮ㅴㄽ
|
||||
潍䱤慯㩤〠〰㜰晦恦㝥㔰〰〰〠〰㜰晦恦㝥㠶ち〰†䌠尺䥗䑎坏屓奓呓䵅㈳摜搲⸱汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㙥敤〰〰〠〰㜰晦恦㝥㐰〷〰†䌠尺䥗䑎坏屓奓呓䵅㈳䑜牗瑩汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㝥㤶〰〰〠〰㜰晦恦㝥昸〰〰†䌠尺䥗䑎坏屓奓呓䵅㈳摜搳ㄱ搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦攸〵〰〰〠〰㜰晦恦攸慡づ〰†䌠尺䥗䑎坏屓奓呓䵅㈳䑜䐳〱慗灲搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦㡥㠵〰〰〠〰㜰晦恦㡥挵〵〰†䌠尺䥗䑎坏屓奓呓䵅㈳摜捸牯汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㡥扡〰〰〠〰㜰晦恦㡥捡〴〰†䌠尺䥗䑎坏屓奓呓䵅㈳牜獥畯捲灥汯捩捹楬湥汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦㕥㑣〰〰〠〰㜰晦恦㕥㥣て〰†䌠尺䥗䑎坏屓奓呓䵅㈳摜物捥硴慤慴慢敳敨灬牥搮汬
|
||||
湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲⤱琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩
|
||||
湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩摜物捥硴慤慴慢敳敨灬牥挮灰㈨㤲⤰摜物捥硴慤慴慢敳敨灬牥搮汬〡〰㜰䙆䕆䌵㈵ㅁ㩁⠠慣汬牥›〰〰䘷䙆㡅㔶㤴䔴
敒畴湲版㈨
楴⡤㤶〶
〸㜰〰㈰吠敨猠獹整慣湮瑯映湩桴楦敬猠数楣楦摥�
|
||||
湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲⤳琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩
|
||||
湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲⤴琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩
|
||||
湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲⤵琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩
|
||||
湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲⤶琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩
|
||||
湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲⤷琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩
|
||||
湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲⤸琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩
|
||||
湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲⤹琠摩㘨㘹⤰㠠〰〷〰′桔祳瑳浥挠湡潮⁴楦摮琠敨映汩灳捥晩敩
|
||||
湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲〱
楴⡤㤶〶
〸㜰〰㈰吠敨猠獹整慣湮瑯映湩桴楦敬猠数楣楦摥�
|
||||
潍䱤慯㩤〠〰㜰晦恦慥㑢〰〰〠〰㜰晦恦慥㝢〰〰†䌠尺䥗䑎坏屓奓呓䵅㈳湜牣灹汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦慥晡〰〰〠〰㜰晦恦慥㉢て〰†䌠尺䥗䑎坏屓奓呓䵅㈳乜䅔乓⸱汤�
|
||||
潍䱤慯㩤〠〰㜰晦恦挹ㅢ〰〰〠〰㜰晦恦挹㕢〸〰†䌠尺䥗䑎坏屓祳瑳浥㈳湜牣灹獴汳汤�
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
〲㐺㨱㤰›义但ⴠ丠硥獵㐠㔮ㄮ‷挨牵⸸⸴⤰
|
||||
〲㐺㨱㤰›义但ⴠㄠ‵畁〲㘲
|
||||
〲㐺㨱㤰›义但ⴠ䌠浯異整慎敭›䕄䭓佔ⵐ䐴㌳㝇�
|
||||
〲㐺㨱㤰›义但ⴠ䌠湯整瑮瀠瑡㩨䘠尺啍䥓彃体呆䅗䕒牜䙥⁘敎畸‴潃灭敬整乜硥獵䰠扩慲祲
|
||||
〲㐺㨱㤰›义但ⴠ䠠獯㩴䌠尺獕牥屳潬灣慨屭潓楮䙣牯敧瑓摵潩湜瑡癩彥牢摩敧扜極摬剜汥慥敳杜極灟潲敢攮數
|
||||
潍䱤慯㩤〠〰㜰晦恦慥㔱〰〰〠〰㜰晦恦慥㠱〶〰†䌠尺䥗䑎坏屓奓呓䵅㈳湜浴牡慴搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦敥㈰〰〰〠〰㜰晦恦敥挰づ〰†䌠尺䥗䑎坏屓祓瑳浥㈳捜扬慣煴搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦捤〵〰〰〠〰㜰晦恦捤㔷〰〰†䌠尺楗摮睯屳祓瑳浥㈳瑜楷慮楰愮灰潣敲搮汬
|
||||
潍䱤慯㩤〠〰㜰晦恦ㅣ㐸〰〰〠〰㜰晦恦ㅣ㤸っ〰†䌠尺䥗䑎坏屓祳瑳浥㈳摜瑡敡捸慨杮汤�
|
||||
湯捥牯履楷摮睯屳楤敲瑣屸慤慴慢敳桜汥数汲扩慲祲汜扩灜牥灡異敳獲瑥楴杮煳敵祲浩汰挮灰ㄨ㔳尩楤敲瑣摸瑡扡獡桥汥数汤Ⅼ〰〰䘷䙆㕅㕃㑁㘷›挨污敬㩲〠〰㜰䙆䕆䌵䄵㈳⥃删瑥牵䡮⡲ㄱ
楴⡤㤶〶
〸㜰〰㈰吠敨猠獹整慣湮瑯映湩桴楦敬猠数楣楦摥�
|
||||
獛慨敲彤潷歲牥⁝瑡慴档椠獮ㅴㄽ栠湷㵤〰〰〰〰㌰ぁ䔰㠷
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
噛瑳䤳獮牴浵湥嵴氠慯敤㩃停潲牧浡䘠汩獥䍜浯潭楆敬屳卖㍔乜硥獵瘮瑳″丨硥獵
畯䍴㵨�
|
||||
獛慨敲彤潷歲牥⁝潬摡椠獮㉴ㄽ
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
㜨〵㤶〶㨩䌠⬫䔠⁈硥散瑰潩潣敤攠㘰㝤㘳″昨物瑳挠慨据⥥
|
||||
獛慨敲彤潷歲牥⁝瑡慴档椠獮㉴ㄽ栠湷㵤〰〰〰〰㈰㔷䘰㠲
|
||||
睛異灭⁝獭㵧砰ㄳ⁆睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
潍䱤慯㩤〠〰㜰晦恦慡㕤〰〰〠〰㜰晦恦慡㥥〶〰†䌠尺䥗䑎坏屓奓呓䵅㈳瑜硥楴灮瑵牦浡睥牯汤�
|
||||
睛異灭⁝獭㵧砰ㄳ⁆睨摮〽〰〰〰〰䄳〰㝅�
|
||||
睛異灭⁝獭㵧砰ㄳ⁆睨摮〽〰〰〰〰㜲〵㉆�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰ㄱ″睨摮〽〰〰〰〰䌴〴㍂�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
䕒啓呌›潤敮ㄽ愠敒㵳‱剢獥ㄽ
|
||||
睛異灭⁝獭㵧砰㜴⁂睨摮〽〰〰〰〰䘰ㅃ㜱�
|
||||
㜨〵㔶㑣㨩匠捥牵瑩⁹档捥慦汩牵牯猠慴正戠晵敦癯牥畲潣敤挠〰〰〴‹ℨ℡猠捥湯档湡散℠℡�
|
||||
畓换摯㩥〠㝸䘠十彔䅆䱉䙟呁䱁䅟偐䕟䥘⁔
|
||||
捵瑲慢敳愡潢瑲〫㑸㩥
|
||||
〰〰昷晦敠㕢㔸㜲摣㤲††††††湩⁴††㤲�
|
||||
㨰〰㸰挠扤›敒摡湩湩瑩慩潣浭湡朧�
|
||||
䅗乒义㩇䌠湯楴畮湩潮潣瑮湩慵汢硥散瑰潩�
|
||||
㜨〵㔶㑣㨩匠捥牵瑩⁹档捥慦汩牵牯猠慴正戠晵敦癯牥畲潣敤挠〰〰〴‹ℨ℡猠捥湯档湡散℠℡�
|
||||
畓换摯㩥〠㝸䘠十彔䅆䱉䙟呁䱁䅟偐䕟䥘⁔
|
||||
捵瑲慢敳愡潢瑲〫㑸㩥
|
||||
〰〰昷晦敠㕢㔸㜲摣㤲††††††湩⁴††㤲�
|
||||
@@ -0,0 +1,11 @@
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$install = 'C:\Users\locpham\SonicForgeStudio\install'
|
||||
$new = 'C:\Users\locpham\SonicForgeStudio\native_bridge\build\Release\daw_vst_bridge.exe'
|
||||
|
||||
Get-Process sonicforge-daw, daw_engine, daw_vst_bridge -ErrorAction SilentlyContinue | Stop-Process -Force
|
||||
Start-Sleep -Seconds 2
|
||||
Copy-Item -Path $new -Destination (Join-Path $install 'daw_vst_bridge.exe') -Force
|
||||
Write-Output "copied: $((Get-Item (Join-Path $install 'daw_vst_bridge.exe')).Length) bytes"
|
||||
Start-Process -FilePath (Join-Path $install 'sonicforge-daw.exe')
|
||||
Start-Sleep -Seconds 8
|
||||
Get-Process sonicforge-daw, daw_engine, daw_vst_bridge -ErrorAction SilentlyContinue | Select-Object Id, ProcessName, Path | Format-Table -AutoSize
|
||||
@@ -0,0 +1 @@
|
||||
'��o\x00w\x00n\x00H\x00w\x00n\x00d\x00=\x000\x000\x000\x000\x000\x000\x000\x000\x000\x000\x00A\x007\x000\x003\x005\x004\x00\n\x00\n\x00l\x00o\x00a\x00d\x00i\x00n\x00g\x00 \x00C\x00:\x00\\\x00P\x00r\x00o\x00g\x00r\x00a\x00m\x00 \x00F\x00i\x00l\x00e\x00s\x00\\\x00C\x00o\x00m\x00m\x00o\x00n\x00 \x00F\x00i\x00l\x00e\x00s\x00\\\x00V\x00S\x00T\x003\x00\\\x00N\x00e\x00x\x00u\x00s\x00.\x00v\x00s\x00t\x003\x00\n\x00\n\x00[\x00V\x00s\x00t\x003\x00I\x00n\x00s\x00t\x00r\x00u\x00m\x00e\x00n\x00t\x00]\x00 \x00l\x00o\x00a\x00d\x00e\x00d\x00 \x00C\x00:\x00\\\x00P\x00r\x00o\x00g\x00r\x00a\x00m\x00 \x00F\x00i\x00l\x00e\x00s\x00\\\x00C\x00o\x00m\x00m\x00o\x00n\x00 \x00F\x00i\x00l\x00e\x00s\x00\\\x00V\x00S\x00T\x003\x00\\\x00N\x00e\x00x\x00u\x00s\x00.\x00v\x00s\x00t\x003\x00 \x00(\x00N\x00e\x00x\x00u\x00s\x00)\x00 \x00o\x00u\x00t\x00C\x00h\x00=\x002\x00\n\x00\n\x00[\x00s\x00h\x00a\x00r\x00e\x00d\x00_\x00w\x00o\x00r\x00k\x00e\x00r\x00]\x00 \x00l\x00o\x00a\x00d\x00 \x00i\x00n\x00s\x00t\x001\x00=\x001\x00\n\x00\n\x00[\x00s\x00h\x00a\x00r\x00e\x00d\x00_\x00w\x00o\x00r\x00k\x00e\x00r\x00]\x00 \x00a\x00t\x00t\x00a\x00c\x00h\x00 \x00i\x00n\x00s\x00t\x001\x00=\x001\x00 \x00h\x00w\x00n\x00d\x00=\x000\x000\x000\x000\x000\x000\x000\x000\x000\x000\x001\x003\x000\x00B\x00B\x002\x00\n\x00\n\x00[\x00V\x00s\x00t\x003\x00I\x00n\x00s\x00t\x00r\x00u\x00m\x00e\x00n\x00t\x00]\x00 \x00l\x00o\x00a\x00d\x00e\x00d\x00 \x00C\x00:\x00\\\x00P\x00r\x00o\x00g\x00r\x00a\x00m\x00 \x00F\x00i\x00l\x00e\x00s\x00\\\x00C\x00o\x00m\x00m\x00o\x00n\x00 \x00F\x00i\x00l\x00e\x00s\x00\\\x00V\x00S\x00T\x003\x00\\\x00N\x00e\x00x\x00u\x00s\x00.\x00v\x00s\x00t\x003\x00 \x00(\x00N\x00e\x00x\x00u\x00s\x00)\x00 \x00o\x00u\x00t\x00C\x00h\x00=\x002\x00\n\x00\n\x00[\x00s\x00h\x00a\x00r\x00e\x00d\x00_\x00w\x00o\x00r\x00k\x00e\x00r\x00]\x00 \x00l\x00o\x00a\x00d\x00 \x00i\x00n\x00s\x00t\x002\x00=\x001\x00\n\x00\n\x00[\x00s\x00h\x00a\x00r\x00e\x00d\x00_\x00w\x00o\x00r\x00k\x00e\x00r\x00]\x00 \x00a\x00t\x00t\x00a\x00c\x00h\x00 \x00i\x00n\x00s\x00t\x002\x00=\x001\x00 \x00h\x00w\x00n\x00d\x00=\x000\x000\x000\x000\x000\x000\x000\x000\x000\x000\x004\x001\x000\x008\x00D\x002\x00\n\x00\n\x00[\x00w\x00p\x00u\x00m\x00p\x00]\x00 \x00m\x00s\x00g\x00=\x000\x00x\x003\x001\x00F\x00 \x00h\x00w\x00n\x00d\x00=\x000\x000\x000\x000\x000\x000\x000\x000\x000\x000\x00A\x000\x000\x003\x009\x00E\x00\n\x00\n\x00[\x00w\x00p\x00u\x00m\x00p\x00]\x00 \x00m\x00s\x00g\x00=\x000\x00x\x003\x001\x00F\x00 \x00h\x00w\x00n\x00d\x00=\x000\x000\x000\x000\x000\x000\x000\x000\x000\x000\x001\x003\x000\x00B\x00B\x002\x00\n\x00\n\x00[\x00w\x00p\x00u\x00m\x00p\x00]\x00 \x00m\x00s\x00g\x00=\x000\x00x\x004\x007\x00B\x00 \x00h\x00w\x00n\x00d\x00=\x000\x000\x000\x000\x000\x000\x000\x000\x000\x000\x00A\x000\x000\x003\x009\x00E\x00\n\x00\n\x00[\x00w\x00p\x00u\x00m\x00p\x00]\x00 \x00m\x00s\x00g\x00=\x000\x00x\x003\x001\x00F\x00 \x00h\x00w\x00n\x00d\x00=\x000\x000\x000\x000\x000\x000\x000\x000\x000\x000\x004\x001\x000\x008\x00D\x002\x00\n\x00\n\x00[\x00w\x00p\x00u\x00m\x00p\x00]\x00 \x00m\x00s\x00g\x00=\x000\x00x\x004\x007\x00B\x00 \x00h\x00w\x00n\x00d\x00=\x000\x000\x000\x000\x000\x000\x000\x000\x000\x000\x00A\x000\x000\x003\x009\x00E\x00\n\x00\n\x00R\x00E\x00S\x00U\x00L\x00T\x00:\x00 \x00d\x00o\x00n\x00e\x00=\x001\x00 \x00a\x00R\x00e\x00s\x00=\x001\x00 \x00b\x00R\x00e\x00s\x00=\x001\x00\n\x00\n\x00E\x00X\x00I\x00T\x00=\x000\x00 \x00E\x00L\x00A\x00P\x00S\x00E\x00D\x00=\x006\x00.\x007\x007\x004\x000\x004\x005\x001\x00\n\x00\n\x00'
|
||||
@@ -0,0 +1,4 @@
|
||||
Get-WinEvent -FilterHashtable @{LogName='Application'; ProviderName='Application Error'} -MaxEvents 30 -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.Message -match 'gui_probe' } |
|
||||
Select-Object -First 3 |
|
||||
ForEach-Object { $_.TimeCreated; $_.Message; '====' }
|
||||
@@ -0,0 +1,4 @@
|
||||
$ev = Get-WinEvent -FilterHashtable @{LogName='Application'; ProviderName='Application Error'} -MaxEvents 30 -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.Message -match 'gui_probe' } | Select-Object -First 3
|
||||
$out = foreach ($e in $ev) { "$($e.TimeCreated)" + "`n" + $e.Message + "`n====" }
|
||||
$out | Out-File -FilePath 'debug/evt_out.txt' -Encoding utf8
|
||||
@@ -0,0 +1,39 @@
|
||||
08/15/2026 18:14:32
|
||||
Faulting application name: gui_probe.exe, version: 0.0.0.0, time stamp: 0x6a80387d
|
||||
Faulting module name: ucrtbase.dll, version: 10.0.26100.8875, time stamp: 0x303b538a
|
||||
Exception code: 0xc0000409
|
||||
Fault offset: 0x00000000000a527e
|
||||
Faulting process id: 0x391C
|
||||
Faulting application start time: 0x1DD2CA73F032169
|
||||
Faulting application path: C:\Users\locpham\SonicForgeStudio\native_bridge\build\Release\gui_probe.exe
|
||||
Faulting module path: C:\WINDOWS\System32\ucrtbase.dll
|
||||
Report Id: a5c1658e-8152-43b4-9a45-216fa4fe295f
|
||||
Faulting package full name:
|
||||
Faulting package-relative application ID:
|
||||
====
|
||||
08/15/2026 18:05:40
|
||||
Faulting application name: gui_probe.exe, version: 0.0.0.0, time stamp: 0x6a80387d
|
||||
Faulting module name: ucrtbase.dll, version: 10.0.26100.8875, time stamp: 0x303b538a
|
||||
Exception code: 0xc0000409
|
||||
Fault offset: 0x00000000000a527e
|
||||
Faulting process id: 0x4F94
|
||||
Faulting application start time: 0x1DD2CA5FD1B9FEF
|
||||
Faulting application path: C:\Users\locpham\SonicForgeStudio\native_bridge\build\Release\gui_probe.exe
|
||||
Faulting module path: C:\WINDOWS\System32\ucrtbase.dll
|
||||
Report Id: a01a443e-2a0d-4e70-ae77-4e7293d1284b
|
||||
Faulting package full name:
|
||||
Faulting package-relative application ID:
|
||||
====
|
||||
08/15/2026 18:02:55
|
||||
Faulting application name: gui_probe.exe, version: 0.0.0.0, time stamp: 0x6a80387d
|
||||
Faulting module name: ucrtbase.dll, version: 10.0.26100.8875, time stamp: 0x303b538a
|
||||
Exception code: 0xc0000409
|
||||
Fault offset: 0x00000000000a527e
|
||||
Faulting process id: 0x2854
|
||||
Faulting application start time: 0x1DD2CA59B0C2BF8
|
||||
Faulting application path: C:\Users\locpham\SonicForgeStudio\native_bridge\build\Release\gui_probe.exe
|
||||
Faulting module path: C:\WINDOWS\System32\ucrtbase.dll
|
||||
Report Id: 7f3f4817-e770-4024-8f07-7d9f9e43bc95
|
||||
Faulting package full name:
|
||||
Faulting package-relative application ID:
|
||||
====
|
||||
@@ -0,0 +1,31 @@
|
||||
import io, sys
|
||||
p = r'C:\Users\locpham\SonicForgeStudio\native_bridge\src\gui_probe.cpp'
|
||||
s = io.open(p, encoding='utf-8', newline='').read()
|
||||
|
||||
old = 'EXCEPTION: %s\r\n", e.what())'
|
||||
new = 'EXCEPTION: %s\\n", e.what())'
|
||||
n1 = s.count(old)
|
||||
s = s.replace(old, new)
|
||||
print('fix1 (CRLF):', n1)
|
||||
|
||||
old2 = 'EXCEPTION\r\n");'
|
||||
new2 = 'EXCEPTION\\n");'
|
||||
n2 = s.count(old2)
|
||||
s = s.replace(old2, new2)
|
||||
print('fix2 (CRLF):', n2)
|
||||
|
||||
# also bare LF variants just in case
|
||||
old3 = 'EXCEPTION: %s\n", e.what())'
|
||||
new3 = 'EXCEPTION: %s\\n", e.what())'
|
||||
n3 = s.count(old3)
|
||||
s = s.replace(old3, new3)
|
||||
print('fix3 (LF):', n3)
|
||||
|
||||
old4 = 'EXCEPTION\n");'
|
||||
new4 = 'EXCEPTION\\n");'
|
||||
n4 = s.count(old4)
|
||||
s = s.replace(old4, new4)
|
||||
print('fix4 (LF):', n4)
|
||||
|
||||
io.open(p, 'w', encoding='utf-8', newline='').write(s)
|
||||
print('written')
|
||||
@@ -0,0 +1,12 @@
|
||||
9| #include <imm.h>
|
||||
33| ImmAssociateContext(w, nullptr);
|
||||
35| ImmAssociateContext(c, nullptr);
|
||||
67| ImmAssociateContextEx(nullptr, nullptr, IACE_DEFAULT);
|
||||
191| if (!done.load()) { printf("RESULT: TIMEOUT (no pump)\n"); return 3; }
|
||||
196| if (!done.load()) { printf("RESULT: TIMEOUT (pump concurrent)\n"); return 3; }
|
||||
213| if (!done.load()) { printf("RESULT: TIMEOUT (apartment dead)\n"); return 3; }
|
||||
218| ImmAssociateContextEx(nullptr, nullptr, IACE_DEFAULT);
|
||||
228| if (!done.load()) { printf("RESULT: TIMEOUT (same_thread)\n"); return 3; }
|
||||
343| printf("RESULT: TIMEOUT inst1 attach (aDone=0)\n");
|
||||
427| if (!aDone.load()) { printf("RESULT: TIMEOUT inst1 (aDone=0)\n"); return 3; }
|
||||
499| printf("[%s] TIMEOUT openGUI(%s)\n", variant.c_str(), tag);
|
||||
@@ -0,0 +1,27 @@
|
||||
import io
|
||||
p = r'C:\Users\locpham\SonicForgeStudio\native_bridge\src\gui_probe.cpp'
|
||||
s = io.open(p, encoding='utf-8', newline='').read()
|
||||
def crlf(x): return x.replace('\n', '\r\n')
|
||||
|
||||
old = crlf('''#ifdef _WIN32
|
||||
OleInitialize(nullptr);
|
||||
#endif''')
|
||||
new = crlf('''#ifdef _WIN32
|
||||
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
#endif''')
|
||||
n = s.count(old)
|
||||
print('OleInitialize count:', n)
|
||||
s = s.replace(old, new)
|
||||
|
||||
old2 = crlf('''#ifdef _WIN32
|
||||
OleUninitialize();
|
||||
#endif''')
|
||||
new2 = crlf('''#ifdef _WIN32
|
||||
CoUninitialize();
|
||||
#endif''')
|
||||
n2 = s.count(old2)
|
||||
print('OleUninitialize count:', n2)
|
||||
s = s.replace(old2, new2)
|
||||
|
||||
io.open(p, 'w', encoding='utf-8', newline='').write(s)
|
||||
print('written')
|
||||
@@ -0,0 +1,380 @@
|
||||
# G1.2: 16 ChannelWorkers -> 1 UiThread; window+attach job len UiThread; bo main pump.
|
||||
import io, sys
|
||||
|
||||
path = r'C:/Users/locpham/SonicForgeStudio/native_bridge/src/main.cpp'
|
||||
s = open(path, encoding='utf-8', newline='').read()
|
||||
s = s.replace('\r\n', '\n')
|
||||
|
||||
def rep(old, new, tag):
|
||||
global s
|
||||
n = s.count(old)
|
||||
if n != 1:
|
||||
print('FAIL %s: count=%d' % (tag, n))
|
||||
sys.exit(1)
|
||||
s = s.replace(old, new)
|
||||
print('OK %s' % tag)
|
||||
|
||||
# R1: g_workers -> g_uiWorker
|
||||
rep(
|
||||
"""static std::map<uint32_t, std::unique_ptr<ChannelWorker>>* g_workers = nullptr;""",
|
||||
"""static ChannelWorker* g_uiWorker = nullptr;""",
|
||||
"R1")
|
||||
|
||||
# R2: post_resize_view
|
||||
rep(
|
||||
"""static void post_resize_view(uint32_t ch, int w, int h) {
|
||||
if (g_workers) {
|
||||
auto wit = g_workers->find(ch);
|
||||
if (wit != g_workers->end()) {
|
||||
wit->second->post([ch, w, h]() {
|
||||
if (!g_engine) return;
|
||||
auto* i = g_engine->get(ch);
|
||||
if (i) i->resizeView(w, h);
|
||||
});
|
||||
}
|
||||
}
|
||||
}""",
|
||||
"""static void post_resize_view(uint32_t ch, int w, int h) {
|
||||
if (g_uiWorker) {
|
||||
g_uiWorker->post([ch, w, h]() {
|
||||
if (!g_engine) return;
|
||||
auto* i = g_engine->get(ch);
|
||||
if (i) i->resizeView(w, h);
|
||||
});
|
||||
}
|
||||
}""",
|
||||
"R2")
|
||||
|
||||
# R3a: post_close_gui header -> close_editor_now
|
||||
rep(
|
||||
"""// closeGUI() MUST run on the channel worker thread (its COM STA apartment) —
|
||||
// the view was attached there. Calling view->removed() from the main thread
|
||||
// (WM_DESTROY handler) is a cross-apartment COM call that corrupts the plugin;
|
||||
// Nexus then hangs on the NEXT view->attached(). Erase the registry inside the
|
||||
// job so Option B (closing another editor before attach) waits for closeGUI to
|
||||
// actually finish.
|
||||
static void post_close_gui(uint32_t ch, HWND hwnd) {
|
||||
ChannelWorker* w = nullptr;
|
||||
if (g_workers) {
|
||||
auto wit = g_workers->find(ch);
|
||||
if (wit != g_workers->end()) w = wit->second.get();
|
||||
}
|
||||
if (w) {
|
||||
// closeGUI() (view->removed()) PHAI chay tren channel worker - COM STA
|
||||
// apartment cua plugin song o do. Window KHONG bi destroy: VstWindowProc
|
||||
// giu lai (an) de reuse nen plugin editor children (worker-owned) khong
|
||||
// bao gio bi huy cross-thread. Registry (g_guiWindows/g_hwndToCh) chi
|
||||
// xoa trong WM_DESTROY khi window thuc su bi huy.
|
||||
w->post([ch, hwnd]() {
|
||||
// Guard window-replaced race: neu OPEN_GUI moi da dung window khac
|
||||
// (hoac da xoa), khong detach view cua window moi.""",
|
||||
"""// closeGUI() MUST run on the UiThread (its COM STA apartment) — the view was
|
||||
// attached there. Calling view->removed() from another thread is a
|
||||
// cross-apartment COM call that corrupts the plugin; Nexus then hangs on the
|
||||
// NEXT view->attached(). G1.2: 1 UiThread chung — close chay synchronous tren
|
||||
// job; goi truc tiep (Option B trong attach job) hoac qua post_close_gui
|
||||
// (WM_CLOSE/WM_DESTROY).
|
||||
static void close_editor_now(uint32_t ch, HWND hwnd) {
|
||||
// Guard window-replaced race: neu OPEN_GUI moi da dung window khac
|
||||
// (hoac da xoa), khong detach view cua window moi.""",
|
||||
"R3a")
|
||||
|
||||
# R3c: close_editor_now closing + post_close_gui wrapper
|
||||
rep(
|
||||
""" std::lock_guard<std::mutex> lk(g_attachMutex);
|
||||
g_closeInFlight[ch] = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}""",
|
||||
""" std::lock_guard<std::mutex> lk(g_attachMutex);
|
||||
g_closeInFlight[ch] = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void post_close_gui(uint32_t ch, HWND hwnd) {
|
||||
if (g_uiWorker) {
|
||||
g_uiWorker->post([ch, hwnd]() { close_editor_now(ch, hwnd); });
|
||||
}
|
||||
}""",
|
||||
"R3c")
|
||||
|
||||
# R4a: handleOpenGui — bo worker tao + window main thread, mo job tren UiThread
|
||||
rep(
|
||||
""" if (!workers[guiCh]) {
|
||||
workers[guiCh] = std::make_unique<ChannelWorker>();
|
||||
}
|
||||
void* hwnd = (void*)arg1;
|
||||
#ifdef _WIN32
|
||||
// Window PHAI thuoc MAIN thread (audio loop pump nay dispatch
|
||||
// messages cua no moi vong lap). Tao/cap nhat window ngay tai day.
|
||||
HWND nativeHwnd = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_guiMutex);
|
||||
auto it = g_guiWindows.find(guiCh);
|
||||
if (it != g_guiWindows.end()) nativeHwnd = (HWND)it->second;
|
||||
}
|
||||
if (hwnd == 0) {
|
||||
if (nativeHwnd && IsWindow(nativeHwnd)) {
|
||||
hwnd = (void*)nativeHwnd;
|
||||
SetWindowTextA(nativeHwnd, pluginId.c_str());
|
||||
ShowWindow(nativeHwnd, SW_SHOW);
|
||||
SetForegroundWindow(nativeHwnd);
|
||||
// Reuse: cap nhat USERDATA (channel+1) - inst CU da bi thay
|
||||
// the boi assign() -> WM_DESTROY sau nay lookup inst MOI.
|
||||
SetWindowLongPtrA(nativeHwnd, GWLP_USERDATA, (LONG_PTR)(guiCh + 1));
|
||||
} else {
|
||||
nativeHwnd = (HWND)create_native_vst_window(pluginId.c_str());
|
||||
if (!nativeHwnd) {
|
||||
std::cerr << "[NativeBridge] GUI create window FAILED plugin=" << pluginId << std::endl;
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_guiMutex);
|
||||
g_guiWindows[guiCh] = nativeHwnd; // keep window alive
|
||||
g_hwndToCh[nativeHwnd] = guiCh; // WM_DESTROY cleanup
|
||||
}
|
||||
SetWindowLongPtrA(nativeHwnd, GWLP_USERDATA, (LONG_PTR)(guiCh + 1));
|
||||
hwnd = (void*)nativeHwnd;
|
||||
}
|
||||
}
|
||||
#endif""",
|
||||
""" // G1.2: window + attach chay tren UiThread (1 thread chung, COM STA +
|
||||
// message pump + job queue). Window messages do UiThread pump dispatch —
|
||||
// audio loop khong con PeekMessageW (xoa block pump o main loop).
|
||||
// G1.1 verify: gui_probe shared_worker = 1 worker load+openGUI 2 inst OK.
|
||||
uiWorker.post([&instruments, shmIPC, guiCh, arg1, arg2 = pluginId]() {
|
||||
AttachInFlightGuard _aifGuard{shmIPC};
|
||||
if (!instruments.get(guiCh)) {
|
||||
std::cerr << "[NativeBridge] GUI attach FAILED hwnd=0"
|
||||
<< " plugin=" << arg2 << " ch=" << guiCh << " (no instrument loaded)" << std::endl;
|
||||
return;
|
||||
}
|
||||
if (auto* inst0 = instruments.get(guiCh)) {
|
||||
if (inst0->hasAttachedView()) {
|
||||
// Dedupe race: main da silence (setReloading) truoc khi post —
|
||||
// restore de channel khong cam vinh vien.
|
||||
std::vector<uint32_t> sp = same_plugin_channels(guiCh);
|
||||
for (uint32_t y : sp) unmute_if_not_closing(y, "openGUI-dedupe");
|
||||
unmute_if_not_closing(guiCh, "openGUI-dedupe");
|
||||
return;
|
||||
}
|
||||
}
|
||||
void* hwnd = (void*)arg1;
|
||||
#ifdef _WIN32
|
||||
HWND nativeHwnd = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_guiMutex);
|
||||
auto it = g_guiWindows.find(guiCh);
|
||||
if (it != g_guiWindows.end()) nativeHwnd = (HWND)it->second;
|
||||
}
|
||||
if (hwnd == 0) {
|
||||
if (nativeHwnd && IsWindow(nativeHwnd)) {
|
||||
hwnd = (void*)nativeHwnd;
|
||||
SetWindowTextA(nativeHwnd, arg2.c_str());
|
||||
ShowWindow(nativeHwnd, SW_SHOW);
|
||||
SetForegroundWindow(nativeHwnd);
|
||||
// Reuse: cap nhat USERDATA (channel+1) - inst CU da bi thay
|
||||
// the boi assign() -> WM_DESTROY sau nay lookup inst MOI.
|
||||
SetWindowLongPtrA(nativeHwnd, GWLP_USERDATA, (LONG_PTR)(guiCh + 1));
|
||||
} else {
|
||||
nativeHwnd = (HWND)create_native_vst_window(arg2.c_str());
|
||||
if (!nativeHwnd) {
|
||||
std::cerr << "[NativeBridge] GUI create window FAILED plugin=" << arg2 << std::endl;
|
||||
std::vector<uint32_t> sp = same_plugin_channels(guiCh);
|
||||
for (uint32_t y : sp) unmute_if_not_closing(y, "openGUI-createfail");
|
||||
unmute_if_not_closing(guiCh, "openGUI-createfail");
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_guiMutex);
|
||||
g_guiWindows[guiCh] = nativeHwnd; // keep window alive
|
||||
g_hwndToCh[nativeHwnd] = guiCh; // WM_DESTROY cleanup
|
||||
}
|
||||
SetWindowLongPtrA(nativeHwnd, GWLP_USERDATA, (LONG_PTR)(guiCh + 1));
|
||||
hwnd = (void*)nativeHwnd;
|
||||
}
|
||||
}
|
||||
#endif""",
|
||||
"R4a")
|
||||
|
||||
# R4b: bo header job cu (da mo job o R4a)
|
||||
rep(
|
||||
""" workers[guiCh]->post([&instruments, shmIPC, guiCh, hwnd, arg2 = pluginId]() {
|
||||
AttachInFlightGuard _aifGuard{shmIPC};
|
||||
if (!instruments.get(guiCh)) {
|
||||
std::cerr << "[NativeBridge] GUI attach FAILED hwnd=" << hwnd
|
||||
<< " plugin=" << arg2 << " ch=" << guiCh << " (no instrument loaded)" << std::endl;
|
||||
return;
|
||||
}
|
||||
if (auto* inst0 = instruments.get(guiCh)) {
|
||||
if (inst0->hasAttachedView()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32""",
|
||||
"""#ifdef _WIN32""",
|
||||
"R4b")
|
||||
|
||||
# R4c: Option B — close dong bo qua close_editor_now
|
||||
rep(
|
||||
""" // Option B: chi 1 editor VST mo tai 1 thoi diem toan
|
||||
// bridge. Instance thu 2 cua CUNG plugin (Nexus) attach
|
||||
// view o apartment/worker khac -> treo. Dong editor cua
|
||||
// channel khac TRUOC khi attach: WM_CLOSE -> main pump
|
||||
// destroy window -> WM_DESTROY -> closeGUI() + xoa registry.
|
||||
// Chay tren worker job de khong stall writeIndex cua real-time
|
||||
// loop. CRASH FIX: silence moi channel TRUOC khi dong editor
|
||||
// cua no (view->removed() tren worker cung luc process() tren
|
||||
// audio loop = 2 thread trong 1 plugin -> crash USER32).
|
||||
{
|
||||
std::vector<uint32_t> others;
|
||||
bool abortAttach = false;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_guiMutex);
|
||||
for (const auto& kv : g_guiWindows)
|
||||
if (kv.first != guiCh) others.push_back(kv.first);
|
||||
}
|
||||
for (uint32_t y : others) {
|
||||
// Skip channels whose editor already detached (close job
|
||||
// finished): do not WM_CLOSE a hidden reused window, do
|
||||
// not re-silence a channel that is already unmuted.
|
||||
if (auto* yi0 = instruments.get(y)) {
|
||||
if (!yi0->hasAttachedView()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
HWND yHwnd = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_guiMutex);
|
||||
auto it = g_guiWindows.find(y);
|
||||
if (it != g_guiWindows.end()) yHwnd = (HWND)it->second;
|
||||
}
|
||||
if (!yHwnd || !IsWindow(yHwnd)) continue;
|
||||
if (instruments.get(y)) {
|
||||
instruments.setReloading(y, true);
|
||||
}
|
||||
PostMessage(yHwnd, WM_CLOSE, 0, 0);
|
||||
// WM_CLOSE -> VstWindowProc -> post_close_gui -> closeGUI()
|
||||
// tren worker cua channel y. Doi cho view da detach (window
|
||||
// duoc giu lai de reuse, khong doi registry erase nhu cu).
|
||||
bool closed = false;
|
||||
// The close job = closeGUI + destroy children + fresh
|
||||
// reload (createInstance, ~2s for Nexus). hasAttachedView
|
||||
// flips false after closeGUI only - ALSO wait for the
|
||||
// close job to finish entirely (close_in_flight): the
|
||||
// attach must not run createView while another thread is
|
||||
// still inside this plugin DLL (2 threads in one DLL ->
|
||||
// Nexus exits silently, observed in probes).
|
||||
for (int i = 0; i < 500; ++i) { // 5s budget
|
||||
auto* yi = instruments.get(y);
|
||||
bool detached = !yi || !yi->hasAttachedView();
|
||||
if (detached && !close_in_flight(y)) { closed = true; break; }
|
||||
Sleep(10);
|
||||
}
|
||||
if (!closed) {
|
||||
abortAttach = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (abortAttach) {
|
||||
// A close job is stuck; do NOT createView (would race the
|
||||
// plugin DLL). Unmute what we silenced (skips channels
|
||||
// whose close job is still in flight - that job unmutes
|
||||
// them when it finishes).
|
||||
for (uint32_t y : others) unmute_if_not_closing(y, "openGUI-abort");
|
||||
return;
|
||||
}
|
||||
}""",
|
||||
""" // Option B: chi 1 editor VST mo tai 1 thoi diem toan bridge. Instance
|
||||
// thu 2 cua CUNG plugin (Nexus) attach view o thread khac -> treo.
|
||||
// G1.2: 1 UiThread -> dong editor cua channel khac DONG BO (goi
|
||||
// close_editor_now truc tiep). Khong the PostMessage(WM_CLOSE) cho
|
||||
// job khac nhu cu — job close nam sau job hien tai trong queue cua
|
||||
// CUNG thread -> khong bao gio chay -> 5s timeout -> attach abort.
|
||||
{
|
||||
std::vector<uint32_t> others;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_guiMutex);
|
||||
for (const auto& kv : g_guiWindows)
|
||||
if (kv.first != guiCh) others.push_back(kv.first);
|
||||
}
|
||||
for (uint32_t y : others) {
|
||||
// Skip channels whose editor already detached (close job
|
||||
// finished): do not WM_CLOSE a hidden reused window, do
|
||||
// not re-silence a channel that is already unmuted.
|
||||
if (auto* yi0 = instruments.get(y)) {
|
||||
if (!yi0->hasAttachedView()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
HWND yHwnd = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_guiMutex);
|
||||
auto it = g_guiWindows.find(y);
|
||||
if (it != g_guiWindows.end()) yHwnd = (HWND)it->second;
|
||||
}
|
||||
if (!yHwnd || !IsWindow(yHwnd)) continue;
|
||||
close_editor_now(y, yHwnd);
|
||||
}
|
||||
}""",
|
||||
"R4c")
|
||||
|
||||
# R5: main workers map -> uiWorker
|
||||
rep(
|
||||
""" std::map<uint32_t, std::unique_ptr<ChannelWorker>> workers;
|
||||
g_workers = &workers;""",
|
||||
""" // G1.2: MOT UiThread chung (COM STA + message pump + job queue) cho moi
|
||||
// channel — thay 16 ChannelWorker. Verify gui_probe `shared_worker` (G1.1):
|
||||
// load + openGUI 2 instance tren 1 worker OK, khong crash/hang.
|
||||
ChannelWorker uiWorker;
|
||||
g_uiWorker = &uiWorker;""",
|
||||
"R5")
|
||||
|
||||
# R6: LOAD job post
|
||||
rep(
|
||||
""" if (!workers[ch]) {
|
||||
workers[ch] = std::make_unique<ChannelWorker>();
|
||||
}
|
||||
workers[ch]->post([&instruments, t, ch, path, sampleRate, block]() {""",
|
||||
""" uiWorker.post([&instruments, t, ch, path, sampleRate, block]() {""",
|
||||
"R6")
|
||||
|
||||
# R7: bo main pump
|
||||
rep(
|
||||
"""#ifdef _WIN32
|
||||
// Message pump: VST editors (Nexus, JUCE-based...) block inside
|
||||
// view->attached() until the host dispatches messages — openGUI runs
|
||||
// on a worker thread, so THIS loop must pump concurrently (verified
|
||||
// with gui_probe: worker-thread openGUI + concurrent pump → attached
|
||||
// returns kResultOk; without it → hangs forever).
|
||||
MSG msg;
|
||||
int pumpedMain = 0;
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
// CRASH FIX (0xc000041d): same as the worker pump — a C++ exception
|
||||
// raised inside a plugin window proc (Nexus) must never escape
|
||||
// DispatchMessageW as an unhandled fatal callback exception.
|
||||
try {
|
||||
DispatchMessageW(&msg);
|
||||
} catch (...) {
|
||||
std::cerr << "[NativeBridge] main pump EXCEPTION — plugin window proc threw" << std::endl;
|
||||
}
|
||||
++pumpedMain;
|
||||
}
|
||||
#endif""",
|
||||
""" // G1.2: audio loop KHONG pump messages nua — moi window (native VST +
|
||||
// editor children) thuoc UiThread; UiThread pump dispatch chung.""",
|
||||
"R7")
|
||||
|
||||
# R8: ChannelWorker comment
|
||||
rep(
|
||||
"""// Per-channel persistent worker: ONE thread owns the COM STA apartment for that
|
||||
// channel's instrument for its whole lifetime. loadPlugin and openGUI MUST run""",
|
||||
"""// G1.2: single persistent UiThread — ONE thread owns the COM STA apartment for
|
||||
// ALL instruments for the whole bridge lifetime. loadPlugin and openGUI MUST run""",
|
||||
"R8")
|
||||
|
||||
s = s.replace('\n', '\r\n')
|
||||
open(path, 'w', encoding='utf-8', newline='').write(s)
|
||||
print('ALL OK')
|
||||
@@ -0,0 +1,97 @@
|
||||
# G1.3 patch: bo pump gate cu (is_teardown_window/g_ownerTid/g_juceOwnerTids/
|
||||
# g_tidToWorker/post_and_wait) — 1 UiThread: teardown job va pump cung 1 thread,
|
||||
# khong con race "2 thread 1 DLL" khi teardown. CBT hook chi con tren UiThread.
|
||||
import io
|
||||
|
||||
p = r'C:/Users/locpham/SonicForgeStudio/native_bridge/src/main.cpp'
|
||||
t = io.open(p, newline='').read()
|
||||
lines = t.split('\n')
|
||||
|
||||
def rep(a, b, new, tag):
|
||||
global t
|
||||
old = '\n'.join(lines[a-1:b])
|
||||
assert old in t, f'{tag}: old not found at {a}-{b}'
|
||||
assert t.count(old) == 1, f'{tag}: old not unique ({t.count(old)})'
|
||||
t = t.replace(old, new)
|
||||
print(f'OK {tag}')
|
||||
|
||||
# R1: bo comment over-gate + g_juceTidsMutex/g_juceOwnerTids
|
||||
rep(75, 86, ''' // G1.3: bo pump gate cu (g_juceOwnerTids / g_ownerTid /
|
||||
// is_teardown_window): teardown (close/LOAD job) va message pump cung chay tren
|
||||
// 1 thread (UiThread) — job chay thi pump dung, job xong thi editor window da
|
||||
// destroy nen USER32 tu huy message toi window chet. Khong con "2 thread trong
|
||||
// 1 DLL" khi teardown (multi-worker cu).''', 'R1')
|
||||
|
||||
# R2: CBT hook bo ghi tid
|
||||
rep(101, 105, ''' ImmAssociateContext(w, nullptr);
|
||||
''', 'R2')
|
||||
|
||||
# R3: bo fwd decl is_teardown_window/pump_window_channel
|
||||
rep(120, 121, '', 'R3')
|
||||
|
||||
# R4: bo g_tidMutex/g_tidToWorker
|
||||
rep(127, 128, '', 'R4')
|
||||
|
||||
# R5: bo g_ownerTid + comment
|
||||
rep(139, 144, '', 'R5')
|
||||
|
||||
# R6: UiThread ctor bo register tid
|
||||
rep(274, 277, ' OleInitialize(nullptr);', 'R6')
|
||||
|
||||
# R7: pump bo gate block
|
||||
rep(309, 343, ''' // G1.3: bo pump gate cu — teardown (close/LOAD job)
|
||||
// va pump cung 1 thread (UiThread): job chay thi pump dung;
|
||||
// het job thi editor window da destroy -> message chet bi
|
||||
// USER32 huy tu dong. Khong can drop theo close_in_flight.
|
||||
''', 'R7')
|
||||
|
||||
# R8: dtor bo erase tid
|
||||
rep(372, 375, ' OleUninitialize();', 'R8')
|
||||
|
||||
# R9: bo post_and_wait
|
||||
rep(411, 438, '', 'R9')
|
||||
|
||||
# R10: bo pump_window_channel + is_teardown_window
|
||||
rep(495, 554, '', 'R10')
|
||||
|
||||
# R11: don gian destroy_window_on_owner
|
||||
rep(556, 591, ''' // G1.3: 1 UiThread — editor windows tao trong attach job (UiThread), destroy
|
||||
// chi goi tu UiThread job (close_editor_now / LOAD) -> ownerTid luon == current
|
||||
// tid -> destroy truc tiep. Neu owner khac thread (khong con xay ra) -> bo
|
||||
// (leak > crash): cross-thread DestroyWindow khong an toan.
|
||||
static void destroy_window_on_owner(HWND hwnd) {
|
||||
if (!hwnd || !IsWindow(hwnd)) return;
|
||||
DWORD ownerTid = GetWindowThreadProcessId(hwnd, nullptr);
|
||||
DWORD curTid = GetCurrentThreadId();
|
||||
if (ownerTid == 0 || ownerTid == curTid) {
|
||||
if (IsWindow(hwnd)) DestroyWindow(hwnd);
|
||||
return;
|
||||
}
|
||||
std::cerr << "[NativeBridge] destroy_window_on_owner: owner tid=" << ownerTid
|
||||
<< " != current " << curTid << " - leaving window " << hwnd << std::endl;
|
||||
}
|
||||
''', 'R11')
|
||||
|
||||
# R12: attach-end bo g_ownerTid recording
|
||||
rep(1191, 1208, ''' disable_ime_contexts((HWND)hwnd);
|
||||
''', 'R12')
|
||||
|
||||
# R13: bo main-thread CBT hook (windows chi tao tren UiThread)
|
||||
rep(767, 771, ''' // Default IMC = none on the main thread (IME recursion fix).
|
||||
ImmAssociateContextEx(nullptr, nullptr, IACE_DEFAULT);
|
||||
''', 'R13')
|
||||
|
||||
# R14a: comment LOAD job — window tao tren UiThread (khong phai MAIN)
|
||||
rep(1299, 1304, ''' // G1.2/G1.3: window tao tren UiThread (handleOpenGui post attach
|
||||
// job; create_native_vst_window chay trong job). LOAD job cung
|
||||
// chay tren UiThread -> khong cross-thread destroy. An window,
|
||||
// giu registry de reuse; editor detach + reload o duoi.
|
||||
''', 'R14a')
|
||||
|
||||
# R14b: comment attach-fail — WM_CLOSE -> UiThread pump
|
||||
rep(1222, 1223, ''' // registry; WM_CLOSE -> UiThread pump destroy (owner = UiThread).
|
||||
// PostMessage an toan cross-thread (khong nhu DestroyWindow).
|
||||
''', 'R14b')
|
||||
|
||||
io.open(p, 'w', newline='').write(t)
|
||||
print('written')
|
||||
@@ -0,0 +1,97 @@
|
||||
# G1.4: bo mute-when-editor-open — xoa editorOpen machinery (channelQuiet chi con reloading)
|
||||
import io, sys
|
||||
|
||||
p = 'native_bridge/src/main.cpp'
|
||||
raw = open(p, 'rb').read()
|
||||
EM = b'\xe2\x80\x94'
|
||||
NL = b'\r\n'
|
||||
|
||||
def rep(old, new, tag):
|
||||
global raw
|
||||
o = old.replace(b'\n', NL)
|
||||
if o not in raw:
|
||||
print(f'MISSING [{tag}]')
|
||||
sys.exit(1)
|
||||
raw = raw.replace(o, new.replace(b'\n', NL))
|
||||
print(f'OK [{tag}]')
|
||||
|
||||
rep(b"""// Editor-open tracking: while a channel's VST editor (native window) is
|
||||
// attached, EVERY channel assigned the same plugin DLL path must stay quiet """ + EM + b"""
|
||||
// the plugin's window proc runs on the editor channel's worker while the
|
||||
// audio loop calls process() on other instances of the same DLL (2 threads
|
||||
// in one DLL -> Nexus USER32 crash). g_editorPathCount = refcount per
|
||||
// lowercase plugin path; g_editorOpenPath/g_editorOpen per channel.
|
||||
// Lock order: g_editorMutex is taken while holding the engine mutex
|
||||
// (channelQuiet) or standalone in non-rt jobs """ + EM + b""" never the reverse.
|
||||
static std::mutex g_editorMutex;
|
||||
static std::map<std::string, int> g_editorPathCount;
|
||||
static std::string g_editorOpenPath[16];
|
||||
static bool g_editorOpen[16] = { false };
|
||||
|
||||
""", b"", "decl-block")
|
||||
|
||||
rep(b"""// Editor closed / instrument replaced: drop the channel's editor-open state
|
||||
// (refcounted per lowercase plugin path). Called from non-rt jobs only """ + EM + b"""
|
||||
// never from the audio loop.
|
||||
static void clear_editor_open(uint32_t ch) {
|
||||
std::lock_guard<std::mutex> lk(g_editorMutex);
|
||||
if (!g_editorOpen[ch]) return;
|
||||
g_editorOpen[ch] = false;
|
||||
std::string pth = g_editorOpenPath[ch];
|
||||
g_editorOpenPath[ch].clear();
|
||||
if (!pth.empty()) {
|
||||
auto it = g_editorPathCount.find(pth);
|
||||
if (it != g_editorPathCount.end() && --it->second <= 0)
|
||||
g_editorPathCount.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
""", b"", "clear_editor_open")
|
||||
|
||||
rep(b""" // Editor-open predicate: channelQuiet() checks whether ANY editor is
|
||||
// attached for the channel's plugin DLL path (refcounted in
|
||||
// g_editorPathCount, updated by the open/close GUI jobs).
|
||||
instruments.setEditorOpenPredicate([](const std::string& lp) {
|
||||
std::lock_guard<std::mutex> lk(g_editorMutex);
|
||||
auto it = g_editorPathCount.find(lp);
|
||||
return it != g_editorPathCount.end() && it->second > 0;
|
||||
});
|
||||
""", b"", "set-predicate")
|
||||
|
||||
rep(b""" // Editor attached: mark the plugin path editor-open so the
|
||||
// audio loop stops processing EVERY channel assigned this
|
||||
// DLL while the editor lives (its window proc runs on this
|
||||
// worker; process() elsewhere on the same DLL -> Nexus crash).
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(g_editorMutex);
|
||||
if (!gp.empty()) {
|
||||
g_editorOpen[guiCh] = true;
|
||||
g_editorOpenPath[guiCh] = gp;
|
||||
++g_editorPathCount[gp];
|
||||
}
|
||||
}
|
||||
disable_ime_contexts((HWND)hwnd);
|
||||
""", b""" disable_ime_contexts((HWND)hwnd);
|
||||
""", "attach-mark")
|
||||
|
||||
rep(b""" // Editor detached + fresh instance loaded: drop editor-open
|
||||
// state (channelQuiet falls back to reloading flags only).
|
||||
clear_editor_open(ch);
|
||||
""", b"", "close-ok-path")
|
||||
|
||||
rep(b""" // Instrument already gone (unloaded) """ + EM + b""" nothing to rebuild.
|
||||
g_engine->setReloading(ch, false);
|
||||
clear_editor_open(ch);
|
||||
""", b""" // Instrument already gone (unloaded) """ + EM + b""" nothing to rebuild.
|
||||
g_engine->setReloading(ch, false);
|
||||
""", "close-else-path")
|
||||
|
||||
rep(b""" ShowWindow(hToHide, SW_HIDE);
|
||||
// Editor detached: drop editor-open state before the
|
||||
// instrument is replaced (assign).
|
||||
clear_editor_open(ch);
|
||||
""", b""" ShowWindow(hToHide, SW_HIDE);
|
||||
""", "load-close-path")
|
||||
|
||||
open(p, 'wb').write(raw)
|
||||
print('DONE main.cpp')
|
||||
@@ -0,0 +1,19 @@
|
||||
import io
|
||||
p = r'C:\Users\locpham\SonicForgeStudio\native_bridge\src\gui_probe.cpp'
|
||||
s = io.open(p, encoding='utf-8', newline='').read()
|
||||
def crlf(x): return x.replace('\n', '\r\n')
|
||||
|
||||
old = crlf(''' th = std::thread([this] {
|
||||
#ifdef _WIN32
|
||||
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
#endif''')
|
||||
new = crlf(''' th = std::thread([this] {
|
||||
#ifdef _WIN32
|
||||
_set_invalid_parameter_handler(probe_invalid_param);
|
||||
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
#endif''')
|
||||
n = s.count(old)
|
||||
print('match:', n)
|
||||
s = s.replace(old, new)
|
||||
io.open(p, 'w', encoding='utf-8', newline='').write(s)
|
||||
print('written')
|
||||
@@ -0,0 +1,53 @@
|
||||
import io
|
||||
p = r'C:\Users\locpham\SonicForgeStudio\native_bridge\src\gui_probe.cpp'
|
||||
s = io.open(p, encoding='utf-8', newline='').read()
|
||||
def crlf(x): return x.replace('\n', '\r\n')
|
||||
|
||||
# 1) add includes + handler helpers after existing includes
|
||||
old_inc = crlf('#include <thread>')
|
||||
new_inc = crlf('''#include <thread>
|
||||
#include <exception>
|
||||
|
||||
#ifdef _WIN32
|
||||
static void probe_invalid_param(const wchar_t* expr, const wchar_t* func, const wchar_t* file,
|
||||
unsigned int line, uintptr_t reserved) {
|
||||
printf("[probe] INVALID_PARAMETER expr=%ls func=%ls\\n", expr ? expr : L"null", func ? func : L"null");
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif''')
|
||||
assert s.count(old_inc) == 1
|
||||
s = s.replace(old_inc, new_inc)
|
||||
|
||||
# 2) pump_for: wrap body with SEH + param handler
|
||||
old_pf = crlf('''static void pump_for(int secs) {
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
while (std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::steady_clock::now() - t0).count() < secs) {
|
||||
MSG msg;
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
Sleep(5);
|
||||
}
|
||||
}''')
|
||||
new_pf = crlf('''static void pump_for(int secs) {
|
||||
#ifdef _WIN32
|
||||
_set_invalid_parameter_handler(probe_invalid_param);
|
||||
#endif
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
while (std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::steady_clock::now() - t0).count() < secs) {
|
||||
MSG msg;
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
Sleep(5);
|
||||
}
|
||||
}''')
|
||||
assert s.count(old_pf) == 1
|
||||
s = s.replace(old_pf, new_pf)
|
||||
|
||||
io.open(p, 'w', encoding='utf-8', newline='').write(s)
|
||||
print('patched')
|
||||
@@ -0,0 +1,62 @@
|
||||
import io
|
||||
p = r'C:\Users\locpham\SonicForgeStudio\native_bridge\src\gui_probe.cpp'
|
||||
s = io.open(p, encoding='utf-8', newline='').read()
|
||||
|
||||
def crlf(x): return x.replace('\n', '\r\n')
|
||||
|
||||
old = crlf(''' auto t0 = std::chrono::steady_clock::now();
|
||||
while (!done.load() && std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::steady_clock::now() - t0).count() < secs) {
|
||||
MSG msg;
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
Sleep(2);
|
||||
}''')
|
||||
new = crlf(''' auto t0 = std::chrono::steady_clock::now();
|
||||
try {
|
||||
while (!done.load() && std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::steady_clock::now() - t0).count() < secs) {
|
||||
MSG msg;
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
Sleep(2);
|
||||
}
|
||||
} catch (const std::exception& e) { printf("[main] PUMP1 EXCEPTION: %s\\n", e.what()); fflush(stdout); }
|
||||
catch (...) { printf("[main] PUMP1 UNKNOWN EXCEPTION\\n"); fflush(stdout); }''')
|
||||
n = s.count(old)
|
||||
print('pump1 count:', n)
|
||||
s = s.replace(old, new)
|
||||
|
||||
old2 = crlf(''' auto t1 = std::chrono::steady_clock::now();
|
||||
while (std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::steady_clock::now() - t1).count() < 5) {
|
||||
MSG msg;
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
Sleep(2);
|
||||
}''')
|
||||
new2 = crlf(''' auto t1 = std::chrono::steady_clock::now();
|
||||
try {
|
||||
while (std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::steady_clock::now() - t1).count() < 5) {
|
||||
MSG msg;
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
Sleep(2);
|
||||
}
|
||||
} catch (const std::exception& e) { printf("[main] PUMP2 EXCEPTION: %s\\n", e.what()); fflush(stdout); }
|
||||
catch (...) { printf("[main] PUMP2 UNKNOWN EXCEPTION\\n"); fflush(stdout); }''')
|
||||
n2 = s.count(old2)
|
||||
print('pump2 count:', n2)
|
||||
s = s.replace(old2, new2)
|
||||
|
||||
io.open(p, 'w', encoding='utf-8', newline='').write(s)
|
||||
print('written')
|
||||
@@ -0,0 +1,41 @@
|
||||
import io
|
||||
p = r'C:\Users\locpham\SonicForgeStudio\native_bridge\src\gui_probe.cpp'
|
||||
s = io.open(p, encoding='utf-8', newline='').read()
|
||||
def crlf(x): return x.replace('\n', '\r\n')
|
||||
|
||||
old = crlf(''' MSG msg;
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
Sleep(5);''')
|
||||
new = crlf(''' MSG msg;
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
printf("[pump] msg=0x%X hwnd=%p\\n", (unsigned)msg.message, (void*)msg.hwnd);
|
||||
fflush(stdout);
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
Sleep(5);''')
|
||||
n = s.count(old)
|
||||
print('pump_for match:', n)
|
||||
s = s.replace(old, new)
|
||||
|
||||
old2 = crlf(''' MSG msg;
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}''')
|
||||
new2 = crlf(''' MSG msg;
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
printf("[wpump] msg=0x%X hwnd=%p\\n", (unsigned)msg.message, (void*)msg.hwnd);
|
||||
fflush(stdout);
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}''')
|
||||
n2 = s.count(old2)
|
||||
print('worker pump match:', n2)
|
||||
s = s.replace(old2, new2)
|
||||
|
||||
io.open(p, 'w', encoding='utf-8', newline='').write(s)
|
||||
print('written')
|
||||
@@ -0,0 +1,132 @@
|
||||
# Live repro of the GUI-open bug in the RUNNING app: load 6 Nexus + EZkeys,
|
||||
# transport PLAY, then OPEN_GUI ch=5 (Nexus) — exactly the frontend sequence.
|
||||
# Usage: python probe_app4_live.py
|
||||
import ctypes, ctypes.wintypes as w, struct, subprocess, sys, os, time, re
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
|
||||
APP_PID = 22264 # sonicforge-daw.exe (SHM name is per-PID)
|
||||
SHM_NAME = f"SonicForge_DAW_IPC_{APP_PID}".encode()
|
||||
SHM_NAME_LEGACY = b"SonicForge_DAW_IPC" # installed build still uses legacy name
|
||||
APP_LOG = os.path.join(os.environ.get('APPDATA', '.'), 'SonicForgeDAW', 'logs', 'bridge.log')
|
||||
VST = r"C:\Program Files\Common Files\VST3"
|
||||
NEXUS = os.path.join(VST, "Nexus.vst3")
|
||||
EZKEYS = os.path.join(VST, "Toontrack", "EZkeys 2.vst3")
|
||||
|
||||
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
kernel32.OpenFileMappingA.argtypes = [ctypes.wintypes.DWORD, w.BOOL, ctypes.c_char_p]
|
||||
kernel32.OpenFileMappingA.restype = ctypes.c_void_p
|
||||
kernel32.MapViewOfFile.argtypes = [ctypes.c_void_p, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.c_size_t]
|
||||
kernel32.MapViewOfFile.restype = ctypes.c_void_p
|
||||
FILE_MAP_ALL_ACCESS = 0xF001F
|
||||
|
||||
hMap = kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, False, SHM_NAME)
|
||||
name_used = SHM_NAME
|
||||
if not hMap:
|
||||
print(f"OpenFileMapping({SHM_NAME}) failed err={ctypes.get_last_error()}, trying legacy...")
|
||||
hMap = kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, False, SHM_NAME_LEGACY)
|
||||
name_used = SHM_NAME_LEGACY
|
||||
if not hMap:
|
||||
print(f"OpenFileMapping({SHM_NAME_LEGACY}) failed err={ctypes.get_last_error()}")
|
||||
sys.exit(1)
|
||||
ptr = kernel32.MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0)
|
||||
if not ptr:
|
||||
print("MapViewOfFile failed", ctypes.get_last_error()); sys.exit(1)
|
||||
print(f"SHM {name_used} mapped")
|
||||
|
||||
def w32(off, fmt, *args):
|
||||
ctypes.memmove(ptr + off, struct.pack(fmt, *args), struct.calcsize(fmt))
|
||||
|
||||
def rd32(off):
|
||||
return ctypes.c_uint32.from_address(ptr + off).value
|
||||
|
||||
def write_control(ctype, arg0, arg1, ch, path):
|
||||
for i in range(8):
|
||||
off = 2836 + i * 1040
|
||||
if rd32(off) == 0:
|
||||
w32(off, 'IIII', ctype, arg0, arg1, ch)
|
||||
if path:
|
||||
b = path.encode('utf-8')[:1023] + b'\x00'
|
||||
ctypes.memmove(ptr + off + 16, b, len(b))
|
||||
return i
|
||||
raise RuntimeError("control queue full")
|
||||
|
||||
def push_controls(events):
|
||||
for i in range(8):
|
||||
w32(2836 + i * 1040, 'I', 0)
|
||||
for (ctype, arg0, arg1, ch, path) in events:
|
||||
write_control(ctype, arg0, arg1, ch, path)
|
||||
w32(11156, 'I', len(events))
|
||||
|
||||
def log_lines():
|
||||
try:
|
||||
with open(APP_LOG, 'r', encoding='utf-8', errors='replace') as f:
|
||||
return f.readlines()
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
|
||||
def wait_log(pattern, timeout, since):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
lines = log_lines()
|
||||
for i in range(since, len(lines)):
|
||||
if pattern in lines[i]:
|
||||
return lines[i].strip()
|
||||
time.sleep(0.2)
|
||||
return None
|
||||
|
||||
def bridge_pid():
|
||||
try:
|
||||
out = subprocess.run(["tasklist", "/FI", "IMAGENAME eq daw_vst_bridge.exe", "/FO", "CSV"],
|
||||
capture_output=True, text=True).stdout
|
||||
for line in out.splitlines()[1:]:
|
||||
if "daw_vst_bridge" in line:
|
||||
return line.split(',')[1].strip('"')
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
# 1) LOAD 6 Nexus ch0-5 + EZkeys ch6 (restore session state after bridge restart)
|
||||
since = len(log_lines())
|
||||
evs = [(2, 0, 0, ch, NEXUS) for ch in range(6)] + [(2, 0, 0, 6, EZKEYS)]
|
||||
push_controls(evs)
|
||||
print("pushed LOAD x7; waiting for instruments...")
|
||||
loaded = []
|
||||
for ch in range(7):
|
||||
r = wait_log(f"instrument loaded ch={ch}", 60, since)
|
||||
loaded.append(r or "TIMEOUT")
|
||||
print(f" ch={ch}: {('loaded' if r else 'TIMEOUT')}")
|
||||
# 2) TRANSPORT PLAY
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 1, 0, 0, "")])
|
||||
r = wait_log("transport PLAY", 10, since)
|
||||
print("transport:", r or "TIMEOUT")
|
||||
# 3) OPEN_GUI ch=5 (Nexus) while playing — same args as frontend open_vst_gui
|
||||
since = len(log_lines())
|
||||
push_controls([(4, 0, 0, 5, "Nexus")])
|
||||
print("pushed OPEN_GUI ch=5 plugin=Nexus; watching 40s...")
|
||||
pid0 = bridge_pid()
|
||||
t0 = time.time()
|
||||
wi0 = rd32(4)
|
||||
last_wi, last_t = wi0, t0
|
||||
stall_started = None
|
||||
events = []
|
||||
while time.time() - t0 < 40:
|
||||
wi = rd32(4)
|
||||
if wi != last_wi:
|
||||
last_wi, last_t = wi, time.time()
|
||||
stall_started = None
|
||||
elif stall_started is None and time.time() - last_t > 3.0:
|
||||
stall_started = time.time() - last_t
|
||||
print(f" [{time.time()-t0:.1f}s] bridge_write_index STALL {wi} since +{time.time()-last_t:.1f}s")
|
||||
pid = bridge_pid()
|
||||
if pid and pid != pid0:
|
||||
print(f" [{time.time()-t0:.1f}s] BRIDGE RESTARTED pid {pid0} -> {pid}")
|
||||
pid0 = pid
|
||||
lines = log_lines()
|
||||
for i in range(since, len(lines)):
|
||||
l = lines[i].strip()
|
||||
if any(k in l for k in ("EXCEPTION", "FAILED", "attached", "deferred", "restarted", "Starting DAW")):
|
||||
print(f" [{time.time()-t0:.1f}s] LOG: {l}")
|
||||
time.sleep(0.2)
|
||||
print("done. write_index advanced:", last_wi, ">", wi0)
|
||||
@@ -0,0 +1,33 @@
|
||||
# probe_attach_detail.py - targeted runs to distinguish crash-in-attach vs
|
||||
# teardown for gui_probe. Prints FULL stdout + real returncode.
|
||||
import subprocess, sys, time, os
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
||||
PROBE = r"C:\Users\locpham\SonicForgeStudio\native_bridge\build\Release\gui_probe.exe"
|
||||
|
||||
CASES = [
|
||||
# (label, plugin, variant, secs)
|
||||
("nexus_bridge_two", r"C:\Program Files\Common Files\VST3\Nexus.vst3", "bridge_two", 8),
|
||||
("nexus_bridge_two_25s",r"C:\Program Files\Common Files\VST3\Nexus.vst3", "bridge_two", 25),
|
||||
("nexus_same_thread", r"C:\Program Files\Common Files\VST3\Nexus.vst3", "same_thread", 8),
|
||||
("nexus_main_own", r"C:\Program Files\Common Files\VST3\Nexus.vst3", "main_own", 8),
|
||||
("scaler2_bridge_two", r"C:\Program Files\Common Files\VST3\Scaler2.vst3", "bridge_two", 8),
|
||||
("ezkeys_bridge_two", r"C:\Program Files\Common Files\VST3\Toontrack\EZkeys 2.vst3", "bridge_two", 8),
|
||||
("kontakt_bridge_two", r"C:\Program Files\Common Files\VST3\Kontakt.vst3", "bridge_two", 8),
|
||||
("kontakt_main_own", r"C:\Program Files\Common Files\VST3\Kontakt.vst3", "main_own", 8),
|
||||
("nexus_two_workers_close", r"C:\Program Files\Common Files\VST3\Nexus.vst3", "two_workers_close", 8),
|
||||
]
|
||||
|
||||
for label, plugin, variant, secs in CASES:
|
||||
t0 = time.time()
|
||||
print(f"\n===== {label} ({variant}, {secs}s) =====", flush=True)
|
||||
try:
|
||||
r = subprocess.run([PROBE, plugin, variant, str(secs)],
|
||||
capture_output=True, text=True, timeout=secs + 25,
|
||||
creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
out = (r.stdout or "") + (r.stderr or "")
|
||||
print(f"returncode={r.returncode} ({r.returncode & 0xFFFFFFFF:08X}) secs={time.time()-t0:.1f}")
|
||||
print(out)
|
||||
except subprocess.TimeoutExpired:
|
||||
print(f"HARD-TIMEOUT after {time.time()-t0:.1f}s")
|
||||
print("-----", flush=True)
|
||||
@@ -0,0 +1,127 @@
|
||||
# G0.1 verification: PLAY -> OPEN_GUI must be DEFERRED (not attach-while-playing);
|
||||
# after STOP the pending GUI must attach OK. No EXCEPTION/FAILED, no watchdog kill.
|
||||
import ctypes, ctypes.wintypes as w, struct, subprocess, sys, os, time
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
|
||||
APP_PID = 25488 # sonicforge-daw.exe (update per run)
|
||||
SHM_NAME = f"SonicForge_DAW_IPC_{APP_PID}".encode()
|
||||
SHM_NAME_LEGACY = b"SonicForge_DAW_IPC"
|
||||
APP_LOG = os.path.join(os.environ.get('APPDATA', '.'), 'SonicForgeDAW', 'logs', 'bridge.log')
|
||||
VST = r"C:\Program Files\Common Files\VST3"
|
||||
NEXUS = os.path.join(VST, "Nexus.vst3")
|
||||
EZKEYS = os.path.join(VST, "Toontrack", "EZkeys 2.vst3")
|
||||
|
||||
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
kernel32.OpenFileMappingA.argtypes = [ctypes.wintypes.DWORD, w.BOOL, ctypes.c_char_p]
|
||||
kernel32.OpenFileMappingA.restype = ctypes.c_void_p
|
||||
kernel32.MapViewOfFile.argtypes = [ctypes.c_void_p, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.c_size_t]
|
||||
kernel32.MapViewOfFile.restype = ctypes.c_void_p
|
||||
FILE_MAP_ALL_ACCESS = 0xF001F
|
||||
|
||||
hMap = kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, False, SHM_NAME)
|
||||
name_used = SHM_NAME
|
||||
if not hMap:
|
||||
print(f"OpenFileMapping({SHM_NAME}) failed err={ctypes.get_last_error()}, trying legacy...")
|
||||
hMap = kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, False, SHM_NAME_LEGACY)
|
||||
name_used = SHM_NAME_LEGACY
|
||||
if not hMap:
|
||||
print(f"OpenFileMapping({SHM_NAME_LEGACY}) failed err={ctypes.get_last_error()}")
|
||||
sys.exit(1)
|
||||
ptr = kernel32.MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0)
|
||||
if not ptr:
|
||||
print("MapViewOfFile failed", ctypes.get_last_error()); sys.exit(1)
|
||||
print(f"SHM {name_used} mapped")
|
||||
|
||||
def w32(off, fmt, *args):
|
||||
ctypes.memmove(ptr + off, struct.pack(fmt, *args), struct.calcsize(fmt))
|
||||
|
||||
def rd32(off):
|
||||
return ctypes.c_uint32.from_address(ptr + off).value
|
||||
|
||||
def write_control(ctype, arg0, arg1, ch, path):
|
||||
for i in range(8):
|
||||
off = 2836 + i * 1040
|
||||
if rd32(off) == 0:
|
||||
w32(off, 'IIII', ctype, arg0, arg1, ch)
|
||||
if path:
|
||||
b = path.encode('utf-8')[:1023] + b'\x00'
|
||||
ctypes.memmove(ptr + off + 16, b, len(b))
|
||||
return i
|
||||
raise RuntimeError("control queue full")
|
||||
|
||||
def push_controls(events):
|
||||
for i in range(8):
|
||||
w32(2836 + i * 1040, 'I', 0)
|
||||
for (ctype, arg0, arg1, ch, path) in events:
|
||||
write_control(ctype, arg0, arg1, ch, path)
|
||||
w32(11156, 'I', len(events))
|
||||
|
||||
def log_lines():
|
||||
try:
|
||||
with open(APP_LOG, 'r', encoding='utf-8', errors='replace') as f:
|
||||
return f.readlines()
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
|
||||
def wait_log(pattern, timeout, since, verbose=True):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
lines = log_lines()
|
||||
for i in range(since, len(lines)):
|
||||
if pattern in lines[i]:
|
||||
if verbose: print(f" LOG: {lines[i].strip()}")
|
||||
return lines[i].strip()
|
||||
time.sleep(0.2)
|
||||
return None
|
||||
|
||||
def bridge_pid():
|
||||
try:
|
||||
out = subprocess.run(["cmd", "/c", "tasklist /FI \"IMAGENAME eq daw_vst_bridge.exe\" /FO CSV"],
|
||||
capture_output=True, text=True).stdout
|
||||
for line in out.splitlines()[1:]:
|
||||
if "daw_vst_bridge" in line:
|
||||
return line.split(',')[1].strip('"')
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
# 1) LOAD 6 Nexus ch0-5 + EZkeys ch6
|
||||
since = len(log_lines())
|
||||
push_controls([(2, 0, 0, ch, NEXUS) for ch in range(6)] + [(2, 0, 0, 6, EZKEYS)])
|
||||
print("pushed LOAD x7; waiting for instruments...")
|
||||
for ch in range(7):
|
||||
r = wait_log(f"instrument loaded ch={ch}", 60, since)
|
||||
print(f" ch={ch}: {'loaded' if r else 'TIMEOUT'}")
|
||||
# 2) TRANSPORT PLAY
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 1, 0, 0, "")])
|
||||
r = wait_log("transport PLAY", 10, since)
|
||||
print("transport:", r or "TIMEOUT")
|
||||
# 3) OPEN_GUI ch=5 while PLAYING -> expect DEFERRED
|
||||
since = len(log_lines())
|
||||
push_controls([(4, 0, 0, 5, "Nexus")])
|
||||
r = wait_log("GUI deferred ch=5", 10, since)
|
||||
print("G0.1 defer:", r or "TIMEOUT - KHONG DEFER (bug chua fix)")
|
||||
pid0 = bridge_pid()
|
||||
# 4) TRANSPORT STOP -> pending GUI should attach now
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 0, 0, 0, "")])
|
||||
r = wait_log("transport STOP", 10, since)
|
||||
print("transport:", r or "TIMEOUT")
|
||||
r = wait_log("GUI attached hwnd=", 30, since)
|
||||
print("G0.1 attach after STOP:", r or "TIMEOUT - attach khong xay ra")
|
||||
# 5) watch 10s for EXCEPTION/FAILED/restart
|
||||
since = len(log_lines())
|
||||
end = time.time() + 10
|
||||
bad = []
|
||||
while time.time() < end:
|
||||
for l in log_lines()[since:]:
|
||||
if any(k in l for k in ("EXCEPTION", "FAILED", "restarted")):
|
||||
bad.append(l.strip())
|
||||
pid = bridge_pid()
|
||||
if pid != pid0:
|
||||
bad.append(f"BRIDGE RESTART {pid0}->{pid}")
|
||||
break
|
||||
time.sleep(0.2)
|
||||
print("G0.1 RESULT:", "PASS - khong loi, attach OK sau STOP" if not bad else "FAIL:\n" + "\n".join(bad[:10]))
|
||||
@@ -0,0 +1,109 @@
|
||||
# Test A: load 6 Nexus + EZkeys, KHONG PLAY, OPEN_GUI ch5 -> attach co OK khong?
|
||||
import ctypes, ctypes.wintypes as w, struct, subprocess, sys, os, time
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
|
||||
APP_PID = 23760
|
||||
SHM_NAME = f"SonicForge_DAW_IPC_{APP_PID}".encode()
|
||||
SHM_NAME_LEGACY = b"SonicForge_DAW_IPC"
|
||||
APP_LOG = os.path.join(os.environ.get('APPDATA', '.'), 'SonicForgeDAW', 'logs', 'bridge.log')
|
||||
VST = r"C:\Program Files\Common Files\VST3"
|
||||
NEXUS = os.path.join(VST, "Nexus.vst3")
|
||||
EZKEYS = os.path.join(VST, "Toontrack", "EZkeys 2.vst3")
|
||||
|
||||
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
kernel32.OpenFileMappingA.argtypes = [ctypes.wintypes.DWORD, w.BOOL, ctypes.c_char_p]
|
||||
kernel32.OpenFileMappingA.restype = ctypes.c_void_p
|
||||
kernel32.MapViewOfFile.argtypes = [ctypes.c_void_p, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.c_size_t]
|
||||
kernel32.MapViewOfFile.restype = ctypes.c_void_p
|
||||
FILE_MAP_ALL_ACCESS = 0xF001F
|
||||
|
||||
hMap = kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, False, SHM_NAME)
|
||||
name_used = SHM_NAME
|
||||
if not hMap:
|
||||
hMap = kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, False, SHM_NAME_LEGACY)
|
||||
name_used = SHM_NAME_LEGACY
|
||||
if not hMap:
|
||||
print("no SHM", ctypes.get_last_error()); sys.exit(1)
|
||||
ptr = kernel32.MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0)
|
||||
if not ptr:
|
||||
print("MapViewOfFile failed", ctypes.get_last_error()); sys.exit(1)
|
||||
print(f"SHM {name_used} mapped")
|
||||
|
||||
def w32(off, fmt, *args):
|
||||
ctypes.memmove(ptr + off, struct.pack(fmt, *args), struct.calcsize(fmt))
|
||||
|
||||
def rd32(off):
|
||||
return ctypes.c_uint32.from_address(ptr + off).value
|
||||
|
||||
def write_control(ctype, arg0, arg1, ch, path):
|
||||
for i in range(8):
|
||||
off = 2836 + i * 1040
|
||||
if rd32(off) == 0:
|
||||
w32(off, 'IIII', ctype, arg0, arg1, ch)
|
||||
if path:
|
||||
b = path.encode('utf-8')[:1023] + b'\x00'
|
||||
ctypes.memmove(ptr + off + 16, b, len(b))
|
||||
return i
|
||||
raise RuntimeError("control queue full")
|
||||
|
||||
def push_controls(events):
|
||||
for i in range(8):
|
||||
w32(2836 + i * 1040, 'I', 0)
|
||||
for (ctype, arg0, arg1, ch, path) in events:
|
||||
write_control(ctype, arg0, arg1, ch, path)
|
||||
w32(11156, 'I', len(events))
|
||||
|
||||
def log_lines():
|
||||
try:
|
||||
with open(APP_LOG, 'r', encoding='utf-8', errors='replace') as f:
|
||||
return f.readlines()
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
|
||||
def wait_log(pattern, timeout, since, verbose=True):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
lines = log_lines()
|
||||
for i in range(since, len(lines)):
|
||||
if pattern in lines[i]:
|
||||
if verbose: print(f" LOG: {lines[i].strip()}")
|
||||
return lines[i].strip()
|
||||
time.sleep(0.2)
|
||||
return None
|
||||
|
||||
def bridge_pid():
|
||||
try:
|
||||
out = subprocess.run(["cmd", "/c", "tasklist /FI \"IMAGENAME eq daw_vst_bridge.exe\" /FO CSV"],
|
||||
capture_output=True, text=True).stdout
|
||||
for line in out.splitlines()[1:]:
|
||||
if "daw_vst_bridge" in line:
|
||||
return line.split(',')[1].strip('"')
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
since = len(log_lines())
|
||||
push_controls([(2, 0, 0, ch, NEXUS) for ch in range(6)] + [(2, 0, 0, 6, EZKEYS)])
|
||||
print("pushed LOAD x7; waiting...")
|
||||
for ch in range(7):
|
||||
r = wait_log(f"instrument loaded ch={ch}", 60, since)
|
||||
print(f" ch={ch}: {'loaded' if r else 'TIMEOUT'}")
|
||||
print("Khong PLAY - mo GUI ch5 ngay (transport stopped)")
|
||||
since = len(log_lines())
|
||||
push_controls([(4, 0, 0, 5, "Nexus")])
|
||||
pid0 = bridge_pid()
|
||||
r = wait_log("GUI attached hwnd=", 40, since)
|
||||
print("ATTACH:", r or "TIMEOUT - GUI khong attach")
|
||||
end = time.time() + 8
|
||||
bad = []
|
||||
while time.time() < end:
|
||||
for l in log_lines()[since:]:
|
||||
if any(k in l for k in ("EXCEPTION", "FAILED", "restarted")):
|
||||
bad.append(l.strip())
|
||||
pid = bridge_pid()
|
||||
if pid != pid0:
|
||||
bad.append(f"BRIDGE RESTART {pid0}->{pid}")
|
||||
break
|
||||
time.sleep(0.2)
|
||||
print("RESULT:", "PASS - attach OK khi STOP, khong loi" if (r and not bad) else "FAIL: " + "; ".join(bad[:5]) if bad else "FAIL - attach TIMEOUT")
|
||||
@@ -0,0 +1,147 @@
|
||||
# G0.3 diagnosis: track attach_in_flight flag + writeIndex over LOAD->PLAY->OPEN_GUI->STOP.
|
||||
# Determines whether watchdog killed at 3s (flag not seen) or attach hung >15s (flag set).
|
||||
import ctypes, ctypes.wintypes as w, struct, subprocess, sys, os, time
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
|
||||
APP_PID = 9692
|
||||
SHM_NAME = f"SonicForge_DAW_IPC_{APP_PID}".encode()
|
||||
SHM_NAME_LEGACY = b"SonicForge_DAW_IPC"
|
||||
APP_LOG = os.path.join(os.environ.get('APPDATA', '.'), 'SonicForgeDAW', 'logs', 'bridge.log')
|
||||
VST = r"C:\Program Files\Common Files\VST3"
|
||||
NEXUS = os.path.join(VST, "Nexus.vst3")
|
||||
EZKEYS = os.path.join(VST, "Toontrack", "EZkeys 2.vst3")
|
||||
|
||||
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
kernel32.OpenFileMappingA.argtypes = [ctypes.wintypes.DWORD, w.BOOL, ctypes.c_char_p]
|
||||
kernel32.OpenFileMappingA.restype = ctypes.c_void_p
|
||||
kernel32.MapViewOfFile.argtypes = [ctypes.c_void_p, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.c_size_t]
|
||||
kernel32.MapViewOfFile.restype = ctypes.c_void_p
|
||||
FILE_MAP_ALL_ACCESS = 0xF001F
|
||||
|
||||
hMap = kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, False, SHM_NAME)
|
||||
name_used = SHM_NAME
|
||||
if not hMap:
|
||||
hMap = kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, False, SHM_NAME_LEGACY)
|
||||
name_used = SHM_NAME_LEGACY
|
||||
if not hMap:
|
||||
print(f"OpenFileMapping failed err={ctypes.get_last_error()}"); sys.exit(1)
|
||||
ptr = kernel32.MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0)
|
||||
if not ptr:
|
||||
print("MapViewOfFile failed", ctypes.get_last_error()); sys.exit(1)
|
||||
print(f"SHM {name_used} mapped")
|
||||
|
||||
def w32(off, fmt, *args):
|
||||
ctypes.memmove(ptr + off, struct.pack(fmt, *args), struct.calcsize(fmt))
|
||||
|
||||
def rd32(off):
|
||||
return ctypes.c_uint32.from_address(ptr + off).value
|
||||
|
||||
def write_control(ctype, arg0, arg1, ch, path):
|
||||
for i in range(8):
|
||||
off = 2836 + i * 1040
|
||||
if rd32(off) == 0:
|
||||
w32(off, 'IIII', ctype, arg0, arg1, ch)
|
||||
if path:
|
||||
b = path.encode('utf-8')[:1023] + b'\x00'
|
||||
ctypes.memmove(ptr + off + 16, b, len(b))
|
||||
return i
|
||||
raise RuntimeError("control queue full")
|
||||
|
||||
def push_controls(events):
|
||||
for i in range(8):
|
||||
w32(2836 + i * 1040, 'I', 0)
|
||||
for (ctype, arg0, arg1, ch, path) in events:
|
||||
write_control(ctype, arg0, arg1, ch, path)
|
||||
w32(11156, 'I', len(events))
|
||||
|
||||
def log_lines():
|
||||
try:
|
||||
with open(APP_LOG, 'r', encoding='utf-8', errors='replace') as f:
|
||||
return f.readlines()
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
|
||||
def wait_log(pattern, timeout, since, verbose=True):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
lines = log_lines()
|
||||
for i in range(since, len(lines)):
|
||||
if pattern in lines[i]:
|
||||
if verbose: print(f" LOG: {lines[i].strip()}")
|
||||
return lines[i].strip()
|
||||
time.sleep(0.2)
|
||||
return None
|
||||
|
||||
def bridge_pid():
|
||||
try:
|
||||
out = subprocess.run(["cmd", "/c", "tasklist /FI \"IMAGENAME eq daw_vst_bridge.exe\" /FO CSV"],
|
||||
capture_output=True, text=True).stdout
|
||||
for line in out.splitlines()[1:]:
|
||||
if "daw_vst_bridge" in line:
|
||||
return line.split(',')[1].strip('"')
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
OFF_ATTACH = 11160 # attach_in_flight (u32, appended after control_queue_count @11156)
|
||||
OFF_WRITE = 4 # bridge_write_index
|
||||
|
||||
since = len(log_lines())
|
||||
push_controls([(2, 0, 0, ch, NEXUS) for ch in range(6)] + [(2, 0, 0, 6, EZKEYS)])
|
||||
print("pushed LOAD x7; waiting...")
|
||||
for ch in range(7):
|
||||
r = wait_log(f"instrument loaded ch={ch}", 60, since)
|
||||
print(f" ch={ch}: {'loaded' if r else 'TIMEOUT'}")
|
||||
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 1, 0, 0, "")])
|
||||
wait_log("transport PLAY", 10, since)
|
||||
|
||||
since = len(log_lines())
|
||||
push_controls([(4, 0, 0, 5, "Nexus")])
|
||||
wait_log("GUI deferred ch=5", 10, since)
|
||||
|
||||
pid0 = bridge_pid()
|
||||
print(f"bridge pid before STOP: {pid0}")
|
||||
|
||||
# STOP then track writeIndex + attach flag every 100ms for 40s
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 0, 0, 0, "")])
|
||||
wait_log("transport STOP", 10, since)
|
||||
print(f"{'t(s)':>5} {'wIdx':>8} {'attach':>6} events")
|
||||
t0 = time.time()
|
||||
last_w = rd32(OFF_WRITE)
|
||||
stall_t = None
|
||||
attached_seen = False
|
||||
end = time.time() + 40
|
||||
while time.time() < end:
|
||||
w = rd32(OFF_WRITE)
|
||||
a = rd32(OFF_ATTACH)
|
||||
t = time.time() - t0
|
||||
if w != last_w:
|
||||
if stall_t is not None:
|
||||
print(f"{t:5.1f} {w:8d} {a:6d} writeIndex resumed after {t - stall_t:.1f}s stall")
|
||||
stall_t = None
|
||||
last_w = w
|
||||
else:
|
||||
if stall_t is None:
|
||||
stall_t = t
|
||||
print(f"{t:5.1f} {w:8d} {a:6d} WRITEINDEX STALL START")
|
||||
if a == 1 and (not hasattr(sys, '_a_was')):
|
||||
print(f"{t:5.1f} {w:8d} {a:6d} attach_in_flight SET")
|
||||
if a == 0 and stall_t is not None and not attached_seen:
|
||||
pass
|
||||
# log check
|
||||
for l in log_lines()[since:]:
|
||||
if "GUI attached hwnd=" in l and not attached_seen:
|
||||
attached_seen = True
|
||||
print(f"{t:5.1f} --- GUI ATTACHED: {l.strip()}")
|
||||
if "bridge restarted" in l:
|
||||
print(f"{t:5.1f} --- BRIDGE RESTARTED IN LOG")
|
||||
pid = bridge_pid()
|
||||
if pid != pid0:
|
||||
print(f"{t:5.1f} --- BRIDGE PID CHANGED {pid0}->{pid}")
|
||||
break
|
||||
time.sleep(0.1)
|
||||
print("done. final attach_in_flight =", rd32(OFF_ATTACH), " writeIndex =", rd32(OFF_WRITE))
|
||||
@@ -0,0 +1,175 @@
|
||||
# G0.4 verification: close GUI -> preset save/restore around reload().
|
||||
# Flow: LOAD ch5 Nexus -> OPEN_GUI -> WM_CLOSE -> expect "state captured ch=5"
|
||||
# -> OPEN_GUI again -> expect "state restored ch=5" + "GUI attached" (2nd time).
|
||||
# No EXCEPTION/FAILED/bridge restart.
|
||||
import ctypes, ctypes.wintypes as w, struct, subprocess, sys, os, time, re
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
|
||||
APP_PID = 25488 # sonicforge-daw.exe (update per run)
|
||||
SHM_NAME = f"SonicForge_DAW_IPC_{APP_PID}".encode()
|
||||
SHM_NAME_LEGACY = b"SonicForge_DAW_IPC"
|
||||
APP_LOG = os.path.join(os.environ.get('APPDATA', '.'), 'SonicForgeDAW', 'logs', 'bridge.log')
|
||||
VST = r"C:\Program Files\Common Files\VST3"
|
||||
NEXUS = os.path.join(VST, "Nexus.vst3")
|
||||
|
||||
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
kernel32.OpenFileMappingA.argtypes = [ctypes.wintypes.DWORD, w.BOOL, ctypes.c_char_p]
|
||||
kernel32.OpenFileMappingA.restype = ctypes.c_void_p
|
||||
kernel32.MapViewOfFile.argtypes = [ctypes.c_void_p, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.c_size_t]
|
||||
kernel32.MapViewOfFile.restype = ctypes.c_void_p
|
||||
FILE_MAP_ALL_ACCESS = 0xF001F
|
||||
|
||||
hMap = kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, False, SHM_NAME)
|
||||
name_used = SHM_NAME
|
||||
if not hMap:
|
||||
print(f"OpenFileMapping({SHM_NAME}) failed err={ctypes.get_last_error()}, trying legacy...")
|
||||
hMap = kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, False, SHM_NAME_LEGACY)
|
||||
name_used = SHM_NAME_LEGACY
|
||||
if not hMap:
|
||||
print(f"OpenFileMapping({SHM_NAME_LEGACY}) failed err={ctypes.get_last_error()}")
|
||||
sys.exit(1)
|
||||
ptr = kernel32.MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0)
|
||||
if not ptr:
|
||||
print("MapViewOfFile failed", ctypes.get_last_error()); sys.exit(1)
|
||||
print(f"SHM {name_used} mapped")
|
||||
|
||||
def w32(off, fmt, *args):
|
||||
ctypes.memmove(ptr + off, struct.pack(fmt, *args), struct.calcsize(fmt))
|
||||
|
||||
def rd32(off):
|
||||
return ctypes.c_uint32.from_address(ptr + off).value
|
||||
|
||||
def write_control(ctype, arg0, arg1, ch, path):
|
||||
for i in range(8):
|
||||
off = 2836 + i * 1040
|
||||
if rd32(off) == 0:
|
||||
w32(off, 'IIII', ctype, arg0, arg1, ch)
|
||||
if path:
|
||||
b = path.encode('utf-8')[:1023] + b'\x00'
|
||||
ctypes.memmove(ptr + off + 16, b, len(b))
|
||||
return i
|
||||
raise RuntimeError("control queue full")
|
||||
|
||||
def push_controls(events):
|
||||
for i in range(8):
|
||||
w32(2836 + i * 1040, 'I', 0)
|
||||
for (ctype, arg0, arg1, ch, path) in events:
|
||||
write_control(ctype, arg0, arg1, ch, path)
|
||||
w32(11156, 'I', len(events))
|
||||
|
||||
def log_lines():
|
||||
try:
|
||||
with open(APP_LOG, 'r', encoding='utf-8', errors='replace') as f:
|
||||
return f.readlines()
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
|
||||
def wait_log(pattern, timeout, since, verbose=True):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
lines = log_lines()
|
||||
for i in range(since, len(lines)):
|
||||
if pattern in lines[i]:
|
||||
if verbose: print(f" LOG: {lines[i].strip()}")
|
||||
return lines[i].strip()
|
||||
time.sleep(0.2)
|
||||
return None
|
||||
|
||||
def bridge_pid():
|
||||
try:
|
||||
r = subprocess.run(['tasklist'], capture_output=True)
|
||||
txt = r.stdout.decode('utf-8', 'replace')
|
||||
for line in txt.splitlines():
|
||||
if 'daw_vst_bridge' in line.lower():
|
||||
return line.split()[1]
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
def watch_restart(since, pid0, seconds=15):
|
||||
end = time.time() + seconds
|
||||
while time.time() < end:
|
||||
for l in log_lines()[since:]:
|
||||
if "bridge restarted" in l or "EXCEPTION" in l or "FAILED" in l:
|
||||
return l.strip()
|
||||
pid = bridge_pid()
|
||||
if pid != pid0:
|
||||
return f"BRIDGE PID CHANGE {pid0}->{pid}"
|
||||
time.sleep(0.2)
|
||||
return None
|
||||
|
||||
for attempt in range(1, 4):
|
||||
print(f"\n===== ATTEMPT {attempt} =====")
|
||||
pid0 = bridge_pid()
|
||||
print("bridge pid0:", pid0)
|
||||
bad = []
|
||||
# 1) ensure ch=5 loaded
|
||||
since = len(log_lines())
|
||||
push_controls([(2, 0, 0, 5, NEXUS)])
|
||||
r = wait_log("instrument loaded ch=5", 90, since)
|
||||
print("LOAD ch5:", r or "TIMEOUT")
|
||||
# 2) STOP transport (idle state)
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 0, 0, 0, "")])
|
||||
wait_log("transport STOP", 10, since)
|
||||
# 3) OPEN_GUI ch=5
|
||||
since = len(log_lines())
|
||||
push_controls([(4, 0, 0, 5, "Nexus")])
|
||||
r = wait_log("GUI attached hwnd=", 60, since)
|
||||
print("G0.4 open #1:", r or "TIMEOUT - attach khong xay ra")
|
||||
m = re.search(r'hwnd=([0-9A-Fa-f]+)', r or "")
|
||||
hwnd = int(m.group(1), 16) if m else None
|
||||
restart = watch_restart(since, pid0)
|
||||
if restart:
|
||||
print(" restart during open #1:", restart); bad.append(restart); time.sleep(5); continue
|
||||
if not hwnd:
|
||||
bad.append("attach #1 timeout"); time.sleep(2); continue
|
||||
time.sleep(3)
|
||||
# 4) WM_CLOSE -> close job runs captureState -> reload -> restoreState
|
||||
# (all 3 lines appear ~simultaneously; use one shared since window)
|
||||
since = len(log_lines())
|
||||
ctypes.windll.user32.SendMessageW(hwnd, 0x0010, 0, 0)
|
||||
print(f" sent WM_CLOSE hwnd={hwnd:#x}")
|
||||
r = wait_log("state captured ch=5", 60, since)
|
||||
print("G0.4 capture:", r or "TIMEOUT - khong captureState khi close GUI")
|
||||
cap_line = r
|
||||
if not r: bad.append("no capture")
|
||||
restart = watch_restart(since, pid0)
|
||||
if restart:
|
||||
print(" restart during close:", restart); bad.append(restart); time.sleep(5); continue
|
||||
# 5) reload + restore also inside the same window
|
||||
r = wait_log("[Vst3Instrument] loaded", 60, since)
|
||||
print("G0.4 reload after close:", r or "TIMEOUT - reload khong xay ra")
|
||||
if not r: bad.append("no reload after close")
|
||||
r = wait_log("state restored ch=5", 60, since)
|
||||
print("G0.4 restore:", r or "TIMEOUT - khong restoreState khi reopen")
|
||||
if not r: bad.append("no restore")
|
||||
# same component size before/after = preset preserved
|
||||
mcap = re.search(r'component=(\d+)B', cap_line or "")
|
||||
mres = re.search(r'component=(\d+)B', r or "")
|
||||
if mcap and mres and mcap.group(1) != mres.group(1):
|
||||
bad.append(f"preset size diff capture={mcap.group(1)} restore={mres.group(1)}")
|
||||
# 6) OPEN_GUI again -> attach succeeds after restore
|
||||
since = len(log_lines())
|
||||
push_controls([(4, 0, 0, 5, "Nexus")])
|
||||
r = wait_log("GUI attached hwnd=", 60, since)
|
||||
print("G0.4 open #2:", r or "TIMEOUT - attach lan 2 khong xay ra")
|
||||
if not r: bad.append("attach #2 timeout")
|
||||
restart = watch_restart(since, pid0)
|
||||
if restart:
|
||||
print(" restart during open #2:", restart); bad.append(restart); time.sleep(5); continue
|
||||
# 7) watch 10s for EXCEPTION/FAILED/restart
|
||||
since = len(log_lines())
|
||||
time.sleep(10)
|
||||
for l in log_lines()[since:]:
|
||||
if any(k in l for k in ("EXCEPTION", "FAILED", "bridge restarted")):
|
||||
bad.append(l.strip())
|
||||
pid = bridge_pid()
|
||||
if pid != pid0:
|
||||
bad.append(f"BRIDGE RESTART {pid0}->{pid}")
|
||||
print("G0.4 RESULT:", "PASS - save/restore preset OK, GUI reopen OK" if not bad else "FAIL:\n" + "\n".join(bad[:10]))
|
||||
if not bad:
|
||||
break
|
||||
else:
|
||||
print("\nALL ATTEMPTS FAILED - attach treo intermittent (bug G1), G0.4 chua verify duoc")
|
||||
@@ -0,0 +1,127 @@
|
||||
# G0.1 verification: PLAY -> OPEN_GUI must be DEFERRED (not attach-while-playing);
|
||||
# after STOP the pending GUI must attach OK. No EXCEPTION/FAILED, no watchdog kill.
|
||||
import ctypes, ctypes.wintypes as w, struct, subprocess, sys, os, time
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
|
||||
APP_PID = 30228 # sonicforge-daw.exe (update per run)
|
||||
SHM_NAME = f"SonicForge_DAW_IPC_{APP_PID}".encode()
|
||||
SHM_NAME_LEGACY = b"SonicForge_DAW_IPC"
|
||||
APP_LOG = os.path.join(os.environ.get('APPDATA', '.'), 'SonicForgeDAW', 'logs', 'bridge.log')
|
||||
VST = r"C:\Program Files\Common Files\VST3"
|
||||
NEXUS = os.path.join(VST, "Nexus.vst3")
|
||||
EZKEYS = os.path.join(VST, "Toontrack", "EZkeys 2.vst3")
|
||||
|
||||
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
kernel32.OpenFileMappingA.argtypes = [ctypes.wintypes.DWORD, w.BOOL, ctypes.c_char_p]
|
||||
kernel32.OpenFileMappingA.restype = ctypes.c_void_p
|
||||
kernel32.MapViewOfFile.argtypes = [ctypes.c_void_p, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.c_size_t]
|
||||
kernel32.MapViewOfFile.restype = ctypes.c_void_p
|
||||
FILE_MAP_ALL_ACCESS = 0xF001F
|
||||
|
||||
hMap = kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, False, SHM_NAME)
|
||||
name_used = SHM_NAME
|
||||
if not hMap:
|
||||
print(f"OpenFileMapping({SHM_NAME}) failed err={ctypes.get_last_error()}, trying legacy...")
|
||||
hMap = kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, False, SHM_NAME_LEGACY)
|
||||
name_used = SHM_NAME_LEGACY
|
||||
if not hMap:
|
||||
print(f"OpenFileMapping({SHM_NAME_LEGACY}) failed err={ctypes.get_last_error()}")
|
||||
sys.exit(1)
|
||||
ptr = kernel32.MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0)
|
||||
if not ptr:
|
||||
print("MapViewOfFile failed", ctypes.get_last_error()); sys.exit(1)
|
||||
print(f"SHM {name_used} mapped")
|
||||
|
||||
def w32(off, fmt, *args):
|
||||
ctypes.memmove(ptr + off, struct.pack(fmt, *args), struct.calcsize(fmt))
|
||||
|
||||
def rd32(off):
|
||||
return ctypes.c_uint32.from_address(ptr + off).value
|
||||
|
||||
def write_control(ctype, arg0, arg1, ch, path):
|
||||
for i in range(8):
|
||||
off = 2836 + i * 1040
|
||||
if rd32(off) == 0:
|
||||
w32(off, 'IIII', ctype, arg0, arg1, ch)
|
||||
if path:
|
||||
b = path.encode('utf-8')[:1023] + b'\x00'
|
||||
ctypes.memmove(ptr + off + 16, b, len(b))
|
||||
return i
|
||||
raise RuntimeError("control queue full")
|
||||
|
||||
def push_controls(events):
|
||||
for i in range(8):
|
||||
w32(2836 + i * 1040, 'I', 0)
|
||||
for (ctype, arg0, arg1, ch, path) in events:
|
||||
write_control(ctype, arg0, arg1, ch, path)
|
||||
w32(11156, 'I', len(events))
|
||||
|
||||
def log_lines():
|
||||
try:
|
||||
with open(APP_LOG, 'r', encoding='utf-8', errors='replace') as f:
|
||||
return f.readlines()
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
|
||||
def wait_log(pattern, timeout, since, verbose=True):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
lines = log_lines()
|
||||
for i in range(since, len(lines)):
|
||||
if pattern in lines[i]:
|
||||
if verbose: print(f" LOG: {lines[i].strip()}")
|
||||
return lines[i].strip()
|
||||
time.sleep(0.2)
|
||||
return None
|
||||
|
||||
def bridge_pid():
|
||||
try:
|
||||
out = subprocess.run(["cmd", "/c", "tasklist /FI \"IMAGENAME eq daw_vst_bridge.exe\" /FO CSV"],
|
||||
capture_output=True, text=True).stdout
|
||||
for line in out.splitlines()[1:]:
|
||||
if "daw_vst_bridge" in line:
|
||||
return line.split(',')[1].strip('"')
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
# 1) LOAD 6 Nexus ch0-5 + EZkeys ch6
|
||||
since = len(log_lines())
|
||||
push_controls([(2, 0, 0, ch, NEXUS) for ch in range(6)] + [(2, 0, 0, 6, EZKEYS)])
|
||||
print("pushed LOAD x7; waiting for instruments...")
|
||||
for ch in range(7):
|
||||
r = wait_log(f"instrument loaded ch={ch}", 60, since)
|
||||
print(f" ch={ch}: {'loaded' if r else 'TIMEOUT'}")
|
||||
# 2) TRANSPORT PLAY
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 1, 0, 0, "")])
|
||||
r = wait_log("transport PLAY", 10, since)
|
||||
print("transport:", r or "TIMEOUT")
|
||||
# 3) OPEN_GUI ch=5 while PLAYING -> expect DEFERRED
|
||||
since = len(log_lines())
|
||||
push_controls([(4, 0, 0, 5, "Nexus")])
|
||||
r = wait_log("GUI deferred ch=5", 10, since)
|
||||
print("G0.1 defer:", r or "TIMEOUT - KHONG DEFER (bug chua fix)")
|
||||
pid0 = bridge_pid()
|
||||
# 4) TRANSPORT STOP -> pending GUI should attach now
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 0, 0, 0, "")])
|
||||
r = wait_log("transport STOP", 10, since)
|
||||
print("transport:", r or "TIMEOUT")
|
||||
r = wait_log("GUI attached hwnd=", 30, since)
|
||||
print("G0.1 attach after STOP:", r or "TIMEOUT - attach khong xay ra")
|
||||
# 5) watch 10s for EXCEPTION/FAILED/restart
|
||||
since = len(log_lines())
|
||||
end = time.time() + 10
|
||||
bad = []
|
||||
while time.time() < end:
|
||||
for l in log_lines()[since:]:
|
||||
if any(k in l for k in ("EXCEPTION", "FAILED", "restarted")):
|
||||
bad.append(l.strip())
|
||||
pid = bridge_pid()
|
||||
if pid != pid0:
|
||||
bad.append(f"BRIDGE RESTART {pid0}->{pid}")
|
||||
break
|
||||
time.sleep(0.2)
|
||||
print("G0.1 RESULT:", "PASS - khong loi, attach OK sau STOP" if not bad else "FAIL:\n" + "\n".join(bad[:10]))
|
||||
@@ -0,0 +1,9 @@
|
||||
import sys
|
||||
sys.stdout.reconfigure(encoding='utf-8',errors='replace')
|
||||
P = 'C:/Users/locpham/SonicForgeStudio/'
|
||||
src = open(P+'native_bridge/src/gui_probe.cpp', encoding='utf-8', errors='replace').read()
|
||||
lines = src.split('\n')
|
||||
for a,b,title in [(34,115,'ProbeWorker'),(220,290,'shared_worker')]:
|
||||
print('====',title,'====')
|
||||
for i in range(a-1,b):
|
||||
print('%5d| %s' % (i+1, lines[i]))
|
||||
@@ -0,0 +1,12 @@
|
||||
import sys, io
|
||||
sys.stdout.reconfigure(encoding='utf-8',errors='replace')
|
||||
P = 'C:/Users/locpham/SonicForgeStudio/'
|
||||
src = open(P+'native_bridge/src/gui_probe.cpp', encoding='utf-8', errors='replace').read()
|
||||
lines = src.split('\n')
|
||||
out = []
|
||||
for a,b,title in [(34,115,'ProbeWorker'),(220,290,'shared_worker'),(540,560,'tail')]:
|
||||
out.append('==== '+title+' ====')
|
||||
for i in range(a-1,min(b,len(lines))):
|
||||
out.append('%5d| %s' % (i+1, lines[i]))
|
||||
open(P+'native_bridge/debug/rd_out2.txt','w',encoding='utf-8').write('\n'.join(out))
|
||||
print('written', len(out))
|
||||
@@ -0,0 +1,155 @@
|
||||
==== ProbeWorker ====
|
||||
34| for (HWND c = GetWindow(w, GW_CHILD); c; c = GetWindow(c, GW_HWNDNEXT))
|
||||
35| ImmAssociateContext(c, nullptr);
|
||||
36| }
|
||||
37| }
|
||||
38|
|
||||
39| static void pump_for(int secs) {
|
||||
40| #ifdef _WIN32
|
||||
41| _set_invalid_parameter_handler(probe_invalid_param);
|
||||
42| #endif
|
||||
43| auto t0 = std::chrono::steady_clock::now();
|
||||
44| while (std::chrono::duration_cast<std::chrono::seconds>(
|
||||
45| std::chrono::steady_clock::now() - t0).count() < secs) {
|
||||
46| MSG msg;
|
||||
47| while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
48| printf("[pump] msg=0x%X hwnd=%p\n", (unsigned)msg.message, (void*)msg.hwnd);
|
||||
49| fflush(stdout);
|
||||
50| TranslateMessage(&msg);
|
||||
51| DispatchMessageW(&msg);
|
||||
52| }
|
||||
53| Sleep(5);
|
||||
54| }
|
||||
55| }
|
||||
56|
|
||||
57| static void sleep_for(int secs) { Sleep((DWORD)(secs * 1000)); }
|
||||
58|
|
||||
59| // Per-channel persistent worker replicating the bridge (round-3 probe).
|
||||
60| class ProbeWorker {
|
||||
61| public:
|
||||
62| void start() {
|
||||
63| th = std::thread([this] {
|
||||
64| #ifdef _WIN32
|
||||
65| _set_invalid_parameter_handler(probe_invalid_param);
|
||||
66| CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
67| ImmAssociateContextEx(nullptr, nullptr, IACE_DEFAULT);
|
||||
68| #endif
|
||||
69| std::unique_lock<std::mutex> lk(mu);
|
||||
70| for (;;) {
|
||||
71| if (stop && jobs.empty()) break;
|
||||
72| if (!jobs.empty()) {
|
||||
73| auto j = std::move(jobs.front());
|
||||
74| jobs.pop_front();
|
||||
75| lk.unlock();
|
||||
76| try { j(); }
|
||||
77| catch (const std::exception& e) { printf("[worker] JOB EXCEPTION: %s\n", e.what()); fflush(stdout); }
|
||||
78| catch (...) { printf("[worker] JOB UNKNOWN EXCEPTION\n"); fflush(stdout); }
|
||||
79| lk.lock();
|
||||
80| continue;
|
||||
81| }
|
||||
82| cv.wait_for(lk, std::chrono::milliseconds(5));
|
||||
83| lk.unlock();
|
||||
84| try {
|
||||
85| MSG msg;
|
||||
86| while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
87| printf("[wpump] msg=0x%X hwnd=%p\n", (unsigned)msg.message, (void*)msg.hwnd);
|
||||
88| fflush(stdout);
|
||||
89| TranslateMessage(&msg);
|
||||
90| DispatchMessageW(&msg);
|
||||
91| }
|
||||
92| }
|
||||
93| catch (const std::exception& e) { printf("[worker] PUMP EXCEPTION: %s\n", e.what()); fflush(stdout); }
|
||||
94| catch (...) { printf("[worker] PUMP UNKNOWN EXCEPTION\n"); fflush(stdout); }
|
||||
95| lk.lock();
|
||||
96| }
|
||||
97| #ifdef _WIN32
|
||||
98| CoUninitialize();
|
||||
99| #endif
|
||||
100| });
|
||||
101| }
|
||||
102| void post(std::function<void()> j) {
|
||||
103| { std::lock_guard<std::mutex> lk(mu); jobs.push_back(std::move(j)); }
|
||||
104| cv.notify_all();
|
||||
105| }
|
||||
106| std::thread th;
|
||||
107| std::mutex mu;
|
||||
108| std::condition_variable cv;
|
||||
109| std::deque<std::function<void()>> jobs;
|
||||
110| bool stop = false;
|
||||
111| };
|
||||
112|
|
||||
113| int main(int argc, char* argv[]) {
|
||||
114| if (argc < 2) {
|
||||
115| printf("usage: gui_probe <plugin.vst3> [variant] [secs] [hwnd]\n"
|
||||
==== shared_worker ====
|
||||
220| } else if (variant == "shared_worker" || variant == "ui_thread") {
|
||||
221| // Proposed round-3 fix: ALL VST3 instances live in ONE apartment —
|
||||
222| // one persistent worker thread hosts load + openGUI for every channel.
|
||||
223| ProbeWorker w;
|
||||
224| w.start();
|
||||
225| std::atomic<bool> done{false};
|
||||
226| int aRes = 0, bRes = 0;
|
||||
227| w.post([&]() {
|
||||
228| bool r = inst.loadPlugin(path, 44100.0);
|
||||
229| printf("[shared_worker] load inst1=%d\n", r ? 1 : 0);
|
||||
230| fflush(stdout);
|
||||
231| if (r) {
|
||||
232| HWND h = CreateWindowEx(0, "GuiProbeClass", "ProbeA", WS_OVERLAPPEDWINDOW,
|
||||
233| 0, 0, 800, 600, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
|
||||
234| disable_ime_contexts(h);
|
||||
235| r = inst.openGUI(h);
|
||||
236| disable_ime_contexts(h);
|
||||
237| printf("[shared_worker] attach inst1=%d hwnd=%p\n", r ? 1 : 0, (void*)h);
|
||||
238| fflush(stdout);
|
||||
239| aRes = r ? 1 : 0;
|
||||
240| }
|
||||
241| r = inst2.loadPlugin(path, 44100.0);
|
||||
242| printf("[shared_worker] load inst2=%d\n", r ? 1 : 0);
|
||||
243| fflush(stdout);
|
||||
244| if (r) {
|
||||
245| HWND h = CreateWindowEx(0, "GuiProbeClass", "ProbeB", WS_OVERLAPPEDWINDOW,
|
||||
246| 0, 0, 800, 600, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
|
||||
247| disable_ime_contexts(h);
|
||||
248| r = inst2.openGUI(h);
|
||||
249| disable_ime_contexts(h);
|
||||
250| printf("[shared_worker] attach inst2=%d hwnd=%p\n", r ? 1 : 0, (void*)h);
|
||||
251| fflush(stdout);
|
||||
252| bRes = r ? 1 : 0;
|
||||
253| }
|
||||
254| done = true;
|
||||
255| });
|
||||
256| auto t0 = std::chrono::steady_clock::now();
|
||||
257| try {
|
||||
258| while (!done.load() && std::chrono::duration_cast<std::chrono::seconds>(
|
||||
259| std::chrono::steady_clock::now() - t0).count() < secs) {
|
||||
260| MSG msg;
|
||||
261| while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
262| TranslateMessage(&msg);
|
||||
263| DispatchMessageW(&msg);
|
||||
264| }
|
||||
265| Sleep(2);
|
||||
266| }
|
||||
267| } catch (const std::exception& e) { printf("[main] PUMP1 EXCEPTION: %s\n", e.what()); fflush(stdout); }
|
||||
268| catch (...) { printf("[main] PUMP1 UNKNOWN EXCEPTION\n"); fflush(stdout); }
|
||||
269| // Stay alive 5s with BOTH editors attached and the worker pumping,
|
||||
270| // while MAIN KEEPS PUMPING like the bridge audio loop: distinguishes a
|
||||
271| // live crash (bad) from a stop-pumping probe artifact.
|
||||
272| auto t1 = std::chrono::steady_clock::now();
|
||||
273| try {
|
||||
274| while (std::chrono::duration_cast<std::chrono::seconds>(
|
||||
275| std::chrono::steady_clock::now() - t1).count() < 5) {
|
||||
276| MSG msg;
|
||||
277| while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
278| TranslateMessage(&msg);
|
||||
279| DispatchMessageW(&msg);
|
||||
280| }
|
||||
281| Sleep(2);
|
||||
282| }
|
||||
283| } catch (const std::exception& e) { printf("[main] PUMP2 EXCEPTION: %s\n", e.what()); fflush(stdout); }
|
||||
284| catch (...) { printf("[main] PUMP2 UNKNOWN EXCEPTION\n"); fflush(stdout); }
|
||||
285| printf("RESULT: done=%d aRes=%d bRes=%d\n", done.load() ? 1 : 0, aRes, bRes);
|
||||
286| return (done.load() && aRes && bRes) ? 0 : 3;
|
||||
287| } else if (variant == "bridge_two") {
|
||||
288| // Exact bridge architecture: per-channel persistent worker threads with
|
||||
289| // own COM STA apartments and idle message pumps; inst1 loaded+attached
|
||||
290| // on worker A, then inst2 loaded+attached on worker B; main pumps.
|
||||
@@ -0,0 +1,168 @@
|
||||
==== ProbeWorker ====
|
||||
34| for (HWND c = GetWindow(w, GW_CHILD); c; c = GetWindow(c, GW_HWNDNEXT))
|
||||
35| ImmAssociateContext(c, nullptr);
|
||||
36| }
|
||||
37| }
|
||||
38|
|
||||
39| static void pump_for(int secs) {
|
||||
40| #ifdef _WIN32
|
||||
41| _set_invalid_parameter_handler(probe_invalid_param);
|
||||
42| #endif
|
||||
43| auto t0 = std::chrono::steady_clock::now();
|
||||
44| while (std::chrono::duration_cast<std::chrono::seconds>(
|
||||
45| std::chrono::steady_clock::now() - t0).count() < secs) {
|
||||
46| MSG msg;
|
||||
47| while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
48| printf("[pump] msg=0x%X hwnd=%p\n", (unsigned)msg.message, (void*)msg.hwnd);
|
||||
49| fflush(stdout);
|
||||
50| TranslateMessage(&msg);
|
||||
51| DispatchMessageW(&msg);
|
||||
52| }
|
||||
53| Sleep(5);
|
||||
54| }
|
||||
55| }
|
||||
56|
|
||||
57| static void sleep_for(int secs) { Sleep((DWORD)(secs * 1000)); }
|
||||
58|
|
||||
59| // Per-channel persistent worker replicating the bridge (round-3 probe).
|
||||
60| class ProbeWorker {
|
||||
61| public:
|
||||
62| void start() {
|
||||
63| th = std::thread([this] {
|
||||
64| #ifdef _WIN32
|
||||
65| _set_invalid_parameter_handler(probe_invalid_param);
|
||||
66| CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
67| ImmAssociateContextEx(nullptr, nullptr, IACE_DEFAULT);
|
||||
68| #endif
|
||||
69| std::unique_lock<std::mutex> lk(mu);
|
||||
70| for (;;) {
|
||||
71| if (stop && jobs.empty()) break;
|
||||
72| if (!jobs.empty()) {
|
||||
73| auto j = std::move(jobs.front());
|
||||
74| jobs.pop_front();
|
||||
75| lk.unlock();
|
||||
76| try { j(); }
|
||||
77| catch (const std::exception& e) { printf("[worker] JOB EXCEPTION: %s\n", e.what()); fflush(stdout); }
|
||||
78| catch (...) { printf("[worker] JOB UNKNOWN EXCEPTION\n"); fflush(stdout); }
|
||||
79| lk.lock();
|
||||
80| continue;
|
||||
81| }
|
||||
82| cv.wait_for(lk, std::chrono::milliseconds(5));
|
||||
83| lk.unlock();
|
||||
84| try {
|
||||
85| MSG msg;
|
||||
86| while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
87| printf("[wpump] msg=0x%X hwnd=%p\n", (unsigned)msg.message, (void*)msg.hwnd);
|
||||
88| fflush(stdout);
|
||||
89| TranslateMessage(&msg);
|
||||
90| DispatchMessageW(&msg);
|
||||
91| }
|
||||
92| }
|
||||
93| catch (const std::exception& e) { printf("[worker] PUMP EXCEPTION: %s\n", e.what()); fflush(stdout); }
|
||||
94| catch (...) { printf("[worker] PUMP UNKNOWN EXCEPTION\n"); fflush(stdout); }
|
||||
95| lk.lock();
|
||||
96| }
|
||||
97| #ifdef _WIN32
|
||||
98| CoUninitialize();
|
||||
99| #endif
|
||||
100| });
|
||||
101| }
|
||||
102| void post(std::function<void()> j) {
|
||||
103| { std::lock_guard<std::mutex> lk(mu); jobs.push_back(std::move(j)); }
|
||||
104| cv.notify_all();
|
||||
105| }
|
||||
106| std::thread th;
|
||||
107| std::mutex mu;
|
||||
108| std::condition_variable cv;
|
||||
109| std::deque<std::function<void()>> jobs;
|
||||
110| bool stop = false;
|
||||
111| };
|
||||
112|
|
||||
113| int main(int argc, char* argv[]) {
|
||||
114| if (argc < 2) {
|
||||
115| printf("usage: gui_probe <plugin.vst3> [variant] [secs] [hwnd]\n"
|
||||
==== shared_worker ====
|
||||
220| } else if (variant == "shared_worker" || variant == "ui_thread") {
|
||||
221| // Proposed round-3 fix: ALL VST3 instances live in ONE apartment —
|
||||
222| // one persistent worker thread hosts load + openGUI for every channel.
|
||||
223| ProbeWorker w;
|
||||
224| w.start();
|
||||
225| std::atomic<bool> done{false};
|
||||
226| int aRes = 0, bRes = 0;
|
||||
227| w.post([&]() {
|
||||
228| bool r = inst.loadPlugin(path, 44100.0);
|
||||
229| printf("[shared_worker] load inst1=%d\n", r ? 1 : 0);
|
||||
230| fflush(stdout);
|
||||
231| if (r) {
|
||||
232| HWND h = CreateWindowEx(0, "GuiProbeClass", "ProbeA", WS_OVERLAPPEDWINDOW,
|
||||
233| 0, 0, 800, 600, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
|
||||
234| disable_ime_contexts(h);
|
||||
235| r = inst.openGUI(h);
|
||||
236| disable_ime_contexts(h);
|
||||
237| printf("[shared_worker] attach inst1=%d hwnd=%p\n", r ? 1 : 0, (void*)h);
|
||||
238| fflush(stdout);
|
||||
239| aRes = r ? 1 : 0;
|
||||
240| }
|
||||
241| r = inst2.loadPlugin(path, 44100.0);
|
||||
242| printf("[shared_worker] load inst2=%d\n", r ? 1 : 0);
|
||||
243| fflush(stdout);
|
||||
244| if (r) {
|
||||
245| HWND h = CreateWindowEx(0, "GuiProbeClass", "ProbeB", WS_OVERLAPPEDWINDOW,
|
||||
246| 0, 0, 800, 600, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
|
||||
247| disable_ime_contexts(h);
|
||||
248| r = inst2.openGUI(h);
|
||||
249| disable_ime_contexts(h);
|
||||
250| printf("[shared_worker] attach inst2=%d hwnd=%p\n", r ? 1 : 0, (void*)h);
|
||||
251| fflush(stdout);
|
||||
252| bRes = r ? 1 : 0;
|
||||
253| }
|
||||
254| done = true;
|
||||
255| });
|
||||
256| auto t0 = std::chrono::steady_clock::now();
|
||||
257| try {
|
||||
258| while (!done.load() && std::chrono::duration_cast<std::chrono::seconds>(
|
||||
259| std::chrono::steady_clock::now() - t0).count() < secs) {
|
||||
260| MSG msg;
|
||||
261| while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
262| TranslateMessage(&msg);
|
||||
263| DispatchMessageW(&msg);
|
||||
264| }
|
||||
265| Sleep(2);
|
||||
266| }
|
||||
267| } catch (const std::exception& e) { printf("[main] PUMP1 EXCEPTION: %s\n", e.what()); fflush(stdout); }
|
||||
268| catch (...) { printf("[main] PUMP1 UNKNOWN EXCEPTION\n"); fflush(stdout); }
|
||||
269| // Stay alive 5s with BOTH editors attached and the worker pumping,
|
||||
270| // while MAIN KEEPS PUMPING like the bridge audio loop: distinguishes a
|
||||
271| // live crash (bad) from a stop-pumping probe artifact.
|
||||
272| auto t1 = std::chrono::steady_clock::now();
|
||||
273| try {
|
||||
274| while (std::chrono::duration_cast<std::chrono::seconds>(
|
||||
275| std::chrono::steady_clock::now() - t1).count() < 5) {
|
||||
276| MSG msg;
|
||||
277| while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
278| TranslateMessage(&msg);
|
||||
279| DispatchMessageW(&msg);
|
||||
280| }
|
||||
281| Sleep(2);
|
||||
282| }
|
||||
283| } catch (const std::exception& e) { printf("[main] PUMP2 EXCEPTION: %s\n", e.what()); fflush(stdout); }
|
||||
284| catch (...) { printf("[main] PUMP2 UNKNOWN EXCEPTION\n"); fflush(stdout); }
|
||||
285| printf("RESULT: done=%d aRes=%d bRes=%d\n", done.load() ? 1 : 0, aRes, bRes);
|
||||
286| return (done.load() && aRes && bRes) ? 0 : 3;
|
||||
287| } else if (variant == "bridge_two") {
|
||||
288| // Exact bridge architecture: per-channel persistent worker threads with
|
||||
289| // own COM STA apartments and idle message pumps; inst1 loaded+attached
|
||||
290| // on worker A, then inst2 loaded+attached on worker B; main pumps.
|
||||
==== tail ====
|
||||
540| catch (...) { printf("[main] PUMP2 UNKNOWN EXCEPTION\n"); fflush(stdout); }
|
||||
541| printf("RESULT: done=%d attached_ok=%d\n", 1, 1);
|
||||
542| return 0;
|
||||
543| } else {
|
||||
544| printf("unknown variant %s\n", variant.c_str());
|
||||
545| return 2;
|
||||
546| }
|
||||
547|
|
||||
548| printf("RESULT: done=%d attached_ok=%d\n", done.load() ? 1 : 0, result.load() ? 1 : 0);
|
||||
549| return 0;
|
||||
550| }
|
||||
551|
|
||||
@@ -0,0 +1,110 @@
|
||||
# Reproduce: attach ch5 -> PLAY -> LOAD EZkeys ch5 (editor open) -> STOP -> WM_CLOSE -> watch
|
||||
import ctypes, ctypes.wintypes as w, struct, subprocess, sys, os, time, re
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
APP_PID = int(sys.argv[1])
|
||||
SHM_NAME = f"SonicForge_DAW_IPC_{APP_PID}".encode()
|
||||
APP_LOG = os.path.join(os.environ.get('APPDATA', '.'), 'SonicForgeDAW', 'logs', 'bridge.log')
|
||||
NEXUS = r"C:\Program Files\Common Files\VST3\Nexus.vst3"
|
||||
EZKEYS = r"C:\Program Files\Common Files\VST3\Toontrack\EZkeys 2.vst3"
|
||||
|
||||
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
kernel32.OpenFileMappingA.argtypes = [ctypes.wintypes.DWORD, w.BOOL, ctypes.c_char_p]
|
||||
kernel32.OpenFileMappingA.restype = ctypes.c_void_p
|
||||
kernel32.MapViewOfFile.argtypes = [ctypes.c_void_p, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.c_size_t]
|
||||
kernel32.MapViewOfFile.restype = ctypes.c_void_p
|
||||
hMap = kernel32.OpenFileMappingA(0xF001F, False, SHM_NAME)
|
||||
ptr = kernel32.MapViewOfFile(hMap, 0xF001F, 0, 0, 0)
|
||||
user32 = ctypes.windll.user32
|
||||
|
||||
def w32(off, fmt, *args):
|
||||
ctypes.memmove(ptr + off, struct.pack(fmt, *args), struct.calcsize(fmt))
|
||||
def rd32(off):
|
||||
return ctypes.c_uint32.from_address(ptr + off).value
|
||||
def write_control(ctype, arg0, arg1, ch, path):
|
||||
for i in range(8):
|
||||
off = 2836 + i * 1040
|
||||
if rd32(off) == 0:
|
||||
w32(off, 'IIII', ctype, arg0, arg1, ch)
|
||||
if path:
|
||||
b = path.encode('utf-8')[:1023] + b'\x00'
|
||||
ctypes.memmove(ptr + off + 16, b, len(b))
|
||||
return i
|
||||
def push_controls(events):
|
||||
for i in range(8):
|
||||
w32(2836 + i * 1040, 'I', 0)
|
||||
for (ctype, arg0, arg1, ch, path) in events:
|
||||
write_control(ctype, arg0, arg1, ch, path)
|
||||
w32(11156, 'I', len(events))
|
||||
def log_lines():
|
||||
try:
|
||||
with open(APP_LOG, 'r', encoding='utf-8', errors='replace') as f:
|
||||
return f.readlines()
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
def wait_log(pattern, timeout, since, verbose=True):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
lines = log_lines()
|
||||
for i in range(since, len(lines)):
|
||||
if pattern in lines[i]:
|
||||
if verbose: print(f" LOG: {lines[i].strip()}")
|
||||
return lines[i].strip()
|
||||
time.sleep(0.2)
|
||||
return None
|
||||
def find_hwnd(ch):
|
||||
for l in log_lines():
|
||||
if f"ch={ch}" in l and "GUI attached" in l:
|
||||
m = re.search(r'hwnd=([0-9A-Fa-f]+)', l)
|
||||
if m: return int(m.group(1), 16)
|
||||
return None
|
||||
|
||||
since = len(log_lines())
|
||||
print("== step 1: attach ch5 ==")
|
||||
push_controls([(4, 0, 0, 5, "Nexus")])
|
||||
r = wait_log("GUI attached", 30, since)
|
||||
print("attach:", "OK" if r else "TIMEOUT")
|
||||
hwnd5 = None
|
||||
if r:
|
||||
m = re.search(r'hwnd=([0-9A-Fa-f]+)', r)
|
||||
if m: hwnd5 = int(m.group(1), 16)
|
||||
print("hwnd5:", hex(hwnd5) if hwnd5 else None)
|
||||
print("IsWindow:", user32.IsWindow(hwnd5), "tid:", user32.GetWindowThreadProcessId(hwnd5, None), "visible:", user32.IsWindowVisible(hwnd5))
|
||||
|
||||
since = len(log_lines())
|
||||
print("== step 2: PLAY ==")
|
||||
push_controls([(3, 1, 0, 0, "")])
|
||||
wait_log("transport PLAY", 10, since)
|
||||
|
||||
since = len(log_lines())
|
||||
print("== step 3: LOAD EZkeys ch5 while editor open ==")
|
||||
push_controls([(2, 0, 0, 5, EZKEYS)])
|
||||
r = wait_log("instrument loaded ch=5", 60, since)
|
||||
print("load:", "OK" if r else "TIMEOUT")
|
||||
print("IsWindow:", user32.IsWindow(hwnd5), "visible:", user32.IsWindowVisible(hwnd5), "child:", user32.FindWindowExA(hwnd5, None, None, None))
|
||||
|
||||
since = len(log_lines())
|
||||
print("== step 4: STOP ==")
|
||||
push_controls([(3, 0, 0, 0, "")])
|
||||
wait_log("transport STOP", 10, since)
|
||||
|
||||
since = len(log_lines())
|
||||
print("== step 5: WM_CLOSE to", hex(hwnd5) if hwnd5 else "None", "watch 45s ==")
|
||||
if hwnd5:
|
||||
user32.PostMessageW(hwnd5, 0x0010, 0, 0)
|
||||
end = time.time() + 45
|
||||
seen = []
|
||||
while time.time() < end:
|
||||
ls = log_lines()
|
||||
for l in ls[since:]:
|
||||
if any(k in l for k in ("state captured", "state restored", "closeGUI", "EXCEPTION", "FAILED")):
|
||||
if l.strip() not in seen:
|
||||
print(" LOG:", l.strip())
|
||||
seen.append(l.strip())
|
||||
if any("state restored ch=5" in s for s in seen):
|
||||
break
|
||||
time.sleep(0.3)
|
||||
if not any("state restored ch=5" in s for s in seen):
|
||||
print(" NO 'state restored ch=5' in 45s; last 10 log lines:")
|
||||
for l in log_lines()[-10:]: print(" ", l.strip())
|
||||
print("IsWindow after:", user32.IsWindow(hwnd5), "visible:", user32.IsWindowVisible(hwnd5))
|
||||
@@ -0,0 +1,4 @@
|
||||
cd 'C:/Users/locpham/SonicForgeStudio/native_bridge/build/Release'
|
||||
$cdb = 'C:/Program Files/WindowsApps/Microsoft.WinDbg_1.2606.22001.0_x64__8wekyb3d8bbwe/amd64/cdb.exe'
|
||||
$plugin = 'C:\Program Files\Common Files\VST3\Nexus.vst3'
|
||||
& $cdb -o -g -G -c "g" .\gui_probe.exe $plugin shared_worker 12 2>&1 | Tee-Object -FilePath 'C:/Users/locpham/SonicForgeStudio/native_bridge/debug/cdb_zi_shared.log'
|
||||
@@ -0,0 +1,5 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
cd 'C:/Users/locpham/SonicForgeStudio/native_bridge/build/Release'
|
||||
$cdb = 'C:/Program Files/WindowsApps/Microsoft.WinDbg_1.2606.22001.0_x64__8wekyb3d8bbwe/amd64/cdb.exe'
|
||||
$plugin = 'C:\Program Files\Common Files\VST3\Nexus.vst3'
|
||||
& $cdb -o -g -G -c "g" .\gui_probe.exe $plugin shared_worker 8 2>&1 | Tee-Object -FilePath 'C:/Users/locpham/SonicForgeStudio/native_bridge/debug/cdb_zi_shared2.log'
|
||||
@@ -0,0 +1,5 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
cd 'C:/Users/locpham/SonicForgeStudio/native_bridge/build/Release'
|
||||
$cdb = 'C:/Program Files/WindowsApps/Microsoft.WinDbg_1.2606.22001.0_x64__8wekyb3d8bbwe/amd64/cdb.exe'
|
||||
$plugin = 'C:\Program Files\Common Files\VST3\Nexus.vst3'
|
||||
& $cdb -o -g -G -c "g" .\gui_probe.exe $plugin shared_worker 15 2>&1 | Tee-Object -FilePath 'C:/Users/locpham/SonicForgeStudio/native_bridge/debug/cdb_zi_shared3.log'
|
||||
@@ -0,0 +1,8 @@
|
||||
$ErrorActionPreference = 'Continue'
|
||||
cd 'C:/Users/locpham/SonicForgeStudio/native_bridge/build/Release'
|
||||
$plugin = 'C:\Program Files\Common Files\VST3\Nexus.vst3'
|
||||
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
||||
& .\gui_probe.exe $plugin shared_worker 15 *> 'C:/Users/locpham/SonicForgeStudio/native_bridge/debug/direct_shared4.log'
|
||||
$code = $LASTEXITCODE
|
||||
$sw.Stop()
|
||||
"EXIT=$code ELAPSED=$($sw.Elapsed.TotalSeconds)" | Out-File -Append 'C:/Users/locpham/SonicForgeStudio/native_bridge/debug/direct_shared4.log'
|
||||
@@ -0,0 +1,48 @@
|
||||
185| attach_job(); // editorhost pattern: attached on main thread, pump after
|
||||
186| pump_for(secs);
|
||||
187| } else if (variant == "worker_own_nopump" || variant == "worker_foreign_nopump") {
|
||||
188| std::thread t(attach_job);
|
||||
189| sleep_for(secs);
|
||||
190| if (!done.load()) { printf("RESULT: TIMEOUT (no pump)\n"); return 3; }
|
||||
191| } else if (variant == "worker_own_pump" || variant == "worker_foreign_pump") {
|
||||
192| std::thread t(attach_job);
|
||||
193| pump_for(secs);
|
||||
194| if (!done.load()) { printf("RESULT: TIMEOUT (pump concurrent)\n"); return 3; }
|
||||
195| } else if (variant == "bridge_like") {
|
||||
196| // Bridge pattern: plugin loaded on thread A which then EXITS (COM
|
||||
197| // apartment dies), openGUI on separate thread B, main pumps.
|
||||
198| std::thread loadA([&]() {
|
||||
199| CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
200| printf("[bridge_like] loadPlugin on thread A\n");
|
||||
201| fflush(stdout);
|
||||
202| bool r = inst.loadPlugin(path, 44100.0);
|
||||
203| printf("[bridge_like] load=%d (thread A exiting)\n", r ? 1 : 0);
|
||||
204| fflush(stdout);
|
||||
205| CoUninitialize();
|
||||
206| });
|
||||
207| loadA.join();
|
||||
208| std::thread t(attach_job); // thread B, after A exited
|
||||
209| pump_for(secs);
|
||||
210| if (!done.load()) { printf("RESULT: TIMEOUT (apartment dead)\n"); return 3; }
|
||||
211| } else if (variant == "same_thread") {
|
||||
212| // Load and openGUI on the SAME worker thread, kept alive; main pumps.
|
||||
213| std::thread t([&]() {
|
||||
214| CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
215| ImmAssociateContextEx(nullptr, nullptr, IACE_DEFAULT);
|
||||
216| printf("[same_thread] loadPlugin on worker\n");
|
||||
217| fflush(stdout);
|
||||
218| bool r = inst.loadPlugin(path, 44100.0);
|
||||
219| printf("[same_thread] load=%d\n", r ? 1 : 0);
|
||||
220| fflush(stdout);
|
||||
221| if (r) { disable_ime_contexts((HWND)targetHwnd); attach_job(); disable_ime_contexts((HWND)targetHwnd); }
|
||||
222| });
|
||||
223| pump_for(secs);
|
||||
224| if (!done.load()) { printf("RESULT: TIMEOUT (same_thread)\n"); return 3; }
|
||||
225| } else if (variant == "shared_worker" || variant == "ui_thread") {
|
||||
226| // Proposed round-3 fix: ALL VST3 instances live in ONE apartment —
|
||||
227| // one persistent worker thread hosts load + openGUI for every channel.
|
||||
228| ProbeWorker w;
|
||||
229| w.start();
|
||||
230| std::atomic<bool> done{false};
|
||||
231| int aRes = 0, bRes = 0;
|
||||
232| w.post([&]() {
|
||||
@@ -0,0 +1,72 @@
|
||||
115| bool stop = false;
|
||||
116| };
|
||||
117|
|
||||
118| int main(int argc, char* argv[]) {
|
||||
119| if (argc < 2) {
|
||||
120| printf("usage: gui_probe <plugin.vst3> [variant] [secs] [hwnd]\n"
|
||||
121| "variants: main_own | worker_own_nopump | worker_own_pump | worker_foreign_nopump | worker_foreign_pump | bridge_like | same_thread | two_instances | two_instances_close | close_reopen | bridge_two | shared_worker | ui_thread | two_workers_close\n");
|
||||
122| return 2;
|
||||
123| }
|
||||
124| std::string path = argv[1];
|
||||
125| std::string variant = argc > 2 ? argv[2] : "main_own";
|
||||
126| int secs = argc > 3 ? atoi(argv[3]) : 20;
|
||||
127|
|
||||
128| CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
129|
|
||||
130| // Watchdog: never let a stuck plugin hang this probe forever.
|
||||
131| std::thread([secs]() {
|
||||
132| Sleep((DWORD)(secs + 10) * 1000);
|
||||
133| printf("WATCHDOG-KILL\n");
|
||||
134| fflush(stdout);
|
||||
135| TerminateProcess(GetCurrentProcess(), 0);
|
||||
136| }).detach();
|
||||
137|
|
||||
138| HWND ownHwnd = 0;
|
||||
139| {
|
||||
140| WNDCLASSEX wc = {};
|
||||
141| wc.cbSize = sizeof(wc);
|
||||
142| wc.lpfnWndProc = DefWindowProc;
|
||||
143| wc.hInstance = GetModuleHandle(nullptr);
|
||||
144| wc.lpszClassName = "GuiProbeClass";
|
||||
145| RegisterClassEx(&wc);
|
||||
146| ownHwnd = CreateWindowEx(0, "GuiProbeClass", "GuiProbe", WS_OVERLAPPEDWINDOW,
|
||||
147| 0, 0, 800, 600, nullptr, nullptr, wc.hInstance, nullptr);
|
||||
148| printf("ownHwnd=%p\n", (void*)ownHwnd);
|
||||
149| }
|
||||
150|
|
||||
151| void* targetHwnd = (void*)ownHwnd;
|
||||
152| if (argc > 4) targetHwnd = (void*)(uintptr_t)strtoull(argv[4], nullptr, 0);
|
||||
153|
|
||||
154| printf("loading %s\n", path.c_str());
|
||||
155| fflush(stdout);
|
||||
156| Vst3Instrument inst;
|
||||
157| Vst3Instrument inst2;
|
||||
158| bool isDeferred = (variant == "bridge_like" || variant == "same_thread" ||
|
||||
159| variant == "two_instances" || variant == "two_instances_close" ||
|
||||
160| variant == "close_reopen" || variant == "bridge_two" ||
|
||||
161| variant == "shared_worker" || variant == "ui_thread");
|
||||
162| bool ok = true;
|
||||
163| if (!isDeferred) {
|
||||
164| ok = inst.loadPlugin(path, 44100.0);
|
||||
165| printf("load=%d\n", ok ? 1 : 0);
|
||||
166| fflush(stdout);
|
||||
167| if (!ok) return 1;
|
||||
168| }
|
||||
169|
|
||||
170| std::atomic<bool> done{false};
|
||||
171| std::atomic<bool> result{false};
|
||||
172|
|
||||
173| auto attach_job = [&]() {
|
||||
174| CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
175| printf("[%s] openGUI start hwnd=%p\n", variant.c_str(), targetHwnd);
|
||||
176| fflush(stdout);
|
||||
177| bool r = inst.openGUI(targetHwnd);
|
||||
178| printf("[%s] openGUI returned=%d\n", variant.c_str(), r ? 1 : 0);
|
||||
179| fflush(stdout);
|
||||
180| result = r;
|
||||
181| done = true;
|
||||
182| };
|
||||
183|
|
||||
184| if (variant == "main_own") {
|
||||
185| attach_job(); // editorhost pattern: attached on main thread, pump after
|
||||
186| pump_for(secs);
|
||||
@@ -0,0 +1,40 @@
|
||||
1| // native_bridge/src/gui_probe.cpp — standalone VST3 GUI attach probe.
|
||||
2| // Debug tool (NOT shipped with the DAW): loads a VST3 with Vst3Instrument and
|
||||
3| // tests openGUI under different thread/pump/parent-window setups so we can
|
||||
4| // find why view->attached() hangs inside the bridge.
|
||||
5| #include "Vst3Instrument.h"
|
||||
6|
|
||||
7| #ifdef _WIN32
|
||||
8| #include <windows.h>
|
||||
9| #include <imm.h>
|
||||
10| #endif
|
||||
11| #include <atomic>
|
||||
12| #include <chrono>
|
||||
13| #include <condition_variable>
|
||||
14| #include <cstdio>
|
||||
15| #include <cstdlib>
|
||||
16| #include <deque>
|
||||
17| #include <functional>
|
||||
18| #include <mutex>
|
||||
19| #include <string>
|
||||
20| #include <thread>
|
||||
21| #include <exception>
|
||||
22|
|
||||
23| #ifdef _WIN32
|
||||
24| static void probe_invalid_param(const wchar_t* expr, const wchar_t* func, const wchar_t* file,
|
||||
25| unsigned int line, uintptr_t reserved) {
|
||||
26| printf("[probe] INVALID_PARAMETER expr=%ls func=%ls\n", expr ? expr : L"null", func ? func : L"null");
|
||||
27| fflush(stdout);
|
||||
28| }
|
||||
29| #endif
|
||||
30|
|
||||
31| static void disable_ime_contexts(HWND w) {
|
||||
32| if (w && IsWindow(w)) {
|
||||
33| ImmAssociateContext(w, nullptr);
|
||||
34| for (HWND c = GetWindow(w, GW_CHILD); c; c = GetWindow(c, GW_HWNDNEXT))
|
||||
35| ImmAssociateContext(c, nullptr);
|
||||
36| }
|
||||
37| }
|
||||
38|
|
||||
39| static void pump_for(int secs) {
|
||||
40| #ifdef _WIN32
|
||||
@@ -0,0 +1,18 @@
|
||||
import ctypes, ctypes.wintypes as w
|
||||
k32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
k32.OpenFileMappingA.argtypes = [ctypes.wintypes.DWORD, w.BOOL, ctypes.c_char_p]
|
||||
k32.OpenFileMappingA.restype = ctypes.c_void_p
|
||||
cands = [
|
||||
b'SonicForge_DAW_IPC',
|
||||
b'SonicForge_DAW_IPC_22264',
|
||||
b'SonicForge_DAW_IPC_16140',
|
||||
b'SonicForge_DAW_IPC_26328',
|
||||
b'Global\\SonicForge_DAW_IPC_22264',
|
||||
b'Local\\SonicForge_DAW_IPC_22264',
|
||||
]
|
||||
for n in cands:
|
||||
h = k32.OpenFileMappingA(0xF001F, False, n)
|
||||
e = ctypes.get_last_error()
|
||||
print(n, '->', hex(h) if h else 'NULL', 'err=', e)
|
||||
if h:
|
||||
ctypes.windll.kernel32.CloseHandle(ctypes.c_void_p(h))
|
||||
@@ -0,0 +1,66 @@
|
||||
# Sweep ALL system VST3: gui_probe <plugin> bridge_two (exact bridge arch:
|
||||
# 2 worker threads, own STA, main pump), classify load/attach/hang/timeout.
|
||||
# Usage: python sweep_all_gui.py [variant] [secs] [jobs]
|
||||
import subprocess, sys, os, time, concurrent.futures, re, json
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
VST = r"C:\Program Files\Common Files\VST3"
|
||||
PROBE = r"C:\Users\locpham\SonicForgeStudio\native_bridge\build\Release\gui_probe.exe"
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
variant = sys.argv[1] if len(sys.argv) > 1 else "bridge_two"
|
||||
secs = int(sys.argv[2]) if len(sys.argv) > 2 else 8
|
||||
jobs = int(sys.argv[3]) if len(sys.argv) > 3 else 4
|
||||
|
||||
# top-level bundles only (dedupe inner Contents/x86_64-win/*.vst3)
|
||||
plugins = []
|
||||
for root, dirs, files in os.walk(VST):
|
||||
if "/Contents/" in root or "\\Contents\\" in root:
|
||||
continue
|
||||
for f in files:
|
||||
if f.lower().endswith(".vst3"):
|
||||
plugins.append(os.path.join(root, f))
|
||||
plugins.sort()
|
||||
print(f"sweep {len(plugins)} plugins, variant={variant} secs={secs} jobs={jobs}", flush=True)
|
||||
|
||||
def run_one(p):
|
||||
t0 = time.time()
|
||||
try:
|
||||
r = subprocess.run([PROBE, p, variant, str(secs)],
|
||||
capture_output=True, text=True, timeout=secs + 20,
|
||||
creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
out = (r.stdout or "") + (r.stderr or "")
|
||||
code = r.returncode
|
||||
except subprocess.TimeoutExpired:
|
||||
out = "HARD-TIMEOUT"
|
||||
code = -1
|
||||
dt = time.time() - t0
|
||||
m = re.search(r"RESULT: (.*)", out)
|
||||
res = m.group(1).strip() if m else ""
|
||||
if "WATCHDOG-KILL" in out: verdict = "HANG"
|
||||
elif code == 0: verdict = "PASS"
|
||||
elif code == 3: verdict = "FAIL"
|
||||
elif "load=" in out and re.search(r"load=0", out): verdict = "LOAD-FAIL"
|
||||
else: verdict = f"EXIT{code}"
|
||||
# extract individual attach results if present
|
||||
a = re.search(r"workerA openGUI inst1=(\d)", out)
|
||||
b = re.search(r"workerB openGUI inst2=(\d)", out)
|
||||
detail = f"a={a.group(1) if a else '?'} b={b.group(1) if b else '?'}"
|
||||
return {"plugin": p, "verdict": verdict, "detail": detail, "secs": round(dt, 1), "res": res}
|
||||
|
||||
results = []
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=jobs) as ex:
|
||||
futs = {ex.submit(run_one, p): p for p in plugins}
|
||||
done = 0
|
||||
for f in concurrent.futures.as_completed(futs):
|
||||
results.append(f.result())
|
||||
done += 1
|
||||
print(f"[{done}/{len(plugins)}] {results[-1]['verdict']:10s} {results[-1]['detail']} {results[-1]['secs']}s {os.path.basename(results[-1]['plugin'])}", flush=True)
|
||||
|
||||
results.sort(key=lambda x: (x["verdict"], x["plugin"]))
|
||||
print("\n==== SUMMARY ====", flush=True)
|
||||
for r in results:
|
||||
print(f"{r['verdict']:10s} {r['detail']:8s} {r['secs']:5.1f}s {r['plugin']}", flush=True)
|
||||
from collections import Counter
|
||||
print("counts:", dict(Counter(r["verdict"] for r in results)), flush=True)
|
||||
with open(os.path.join(HERE, f"sweep_{variant}_{secs}s.json"), "w", encoding="utf-8") as f:
|
||||
json.dump(results, f, ensure_ascii=False, indent=2)
|
||||
@@ -0,0 +1,534 @@
|
||||
[
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Celemony\\Melodyne\\Melodyne.vst3",
|
||||
"verdict": "EXIT3221225477",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 1.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Orb Plugins\\Orb Arpeggios.vst3",
|
||||
"verdict": "EXIT3221225477",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 1.5,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Orb Plugins\\Orb Melody.vst3",
|
||||
"verdict": "EXIT3221225477",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 1.9,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Sonible\\smartEQ3.vst3",
|
||||
"verdict": "EXIT3221225477",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 1.6,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Sonible\\smartEQlive_x64.vst3",
|
||||
"verdict": "EXIT3221225477",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 1.3,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Sonible\\smartreverb_x64.vst3",
|
||||
"verdict": "EXIT3221225477",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 1.3,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Synapse Audio\\DUNE3.vst3",
|
||||
"verdict": "EXIT3221225477",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 4.6,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\ACE Bridge 2.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\ACE Bridge ARA.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Ample Sound\\ACDD.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 3.0,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Ample Sound\\ACDX.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Ample Sound\\ACEH.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Ample Sound\\ACGQ.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Ample Sound\\ACKH.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Ample Sound\\ACP.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Ample Sound\\ACQD.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Ample Sound\\ACTP.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Ample Sound\\ACZ.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Audiomodern\\Riffer_64.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\BlueARP\\BlueARP.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Focusrite\\fast-balancer.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Focusrite\\fast-compressor_x64.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Focusrite\\fast-equaliser_x64.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Focusrite\\fast-limiter_x64.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Focusrite\\fast-reveal_x64.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Focusrite\\fast-verb_x64.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Kontakt.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 11.3,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\LANDR\\LANDR Composer.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\LANDR\\LANDR Guitar.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Nexus.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Orb Plugins\\Orb Bass.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Orb Plugins\\Orb Chords.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Scaler2.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\ScalerAudio2.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Sonible\\entropyEQ_x64.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Sonible\\freiraum_x64.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Sonible\\proximityEQ_x64.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Sonible\\smartcomp2.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Sonible\\smartlimit.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.3,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Toontrack\\EZdrummer 3.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.3,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\Toontrack\\EZkeys 2.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=?",
|
||||
"secs": 8.3,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Clarity.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.3,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Dynamic EQ.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Dynamics.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Equalizer.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Exciter.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Imager.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Impact.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Low End Focus.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Master Rebalance.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Match EQ.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Maximizer.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Spectral Shaper.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Stabilizer.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Vintage Compressor.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Vintage EQ.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Vintage Limiter.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11 Vintage Tape.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\Ozone 11.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=1 b=1",
|
||||
"secs": 8.3,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 Breath Control.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 Connect.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 De-click.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 De-clip.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 De-crackle.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 De-ess.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 De-hum.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 De-plosive.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 De-reverb.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 Dialogue Isolate.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 Guitar De-noise.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 Monitor.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 Mouth De-click.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.1,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 Repair Assistant.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 Spectral De-noise.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 Spectral Editor.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
},
|
||||
{
|
||||
"plugin": "C:\\Program Files\\Common Files\\VST3\\iZotope\\RX 11 Voice De-noise.vst3",
|
||||
"verdict": "EXIT3221226505",
|
||||
"detail": "a=? b=?",
|
||||
"secs": 8.2,
|
||||
"res": ""
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,181 @@
|
||||
# G1.2 verification against live app: single UiThread.
|
||||
# Flow: PLAY(audio advancing) -> OPEN_GUI ch5 during PLAY (deferred, audio still alive)
|
||||
# -> STOP (attach ch5) -> PLAY again -> OPEN_GUI ch6 (Option B closes ch5 editor
|
||||
# synchronously, ch6 deferred) -> STOP (attach ch6) -> close ch6 editor via WM_CLOSE
|
||||
# -> no EXCEPTION/FAILED/restart anywhere, writeIndex advancing while PLAY.
|
||||
import ctypes, ctypes.wintypes as w, struct, subprocess, sys, os, time
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
|
||||
APP_PID = int(sys.argv[1])
|
||||
SHM_NAME = f"SonicForge_DAW_IPC_{APP_PID}".encode()
|
||||
APP_LOG = os.path.join(os.environ.get('APPDATA', '.'), 'SonicForgeDAW', 'logs', 'bridge.log')
|
||||
NEXUS = r"C:\Program Files\Common Files\VST3\Nexus.vst3"
|
||||
|
||||
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
kernel32.OpenFileMappingA.argtypes = [ctypes.wintypes.DWORD, w.BOOL, ctypes.c_char_p]
|
||||
kernel32.OpenFileMappingA.restype = ctypes.c_void_p
|
||||
kernel32.MapViewOfFile.argtypes = [ctypes.c_void_p, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.c_size_t]
|
||||
kernel32.MapViewOfFile.restype = ctypes.c_void_p
|
||||
hMap = kernel32.OpenFileMappingA(0xF001F, False, SHM_NAME)
|
||||
if not hMap:
|
||||
print(f"OpenFileMapping failed err={ctypes.get_last_error()}"); sys.exit(1)
|
||||
ptr = kernel32.MapViewOfFile(hMap, 0xF001F, 0, 0, 0)
|
||||
print(f"SHM mapped ({SHM_NAME})")
|
||||
|
||||
def w32(off, fmt, *args):
|
||||
ctypes.memmove(ptr + off, struct.pack(fmt, *args), struct.calcsize(fmt))
|
||||
def rd32(off):
|
||||
return ctypes.c_uint32.from_address(ptr + off).value
|
||||
|
||||
def write_control(ctype, arg0, arg1, ch, path):
|
||||
for i in range(8):
|
||||
off = 2836 + i * 1040
|
||||
if rd32(off) == 0:
|
||||
w32(off, 'IIII', ctype, arg0, arg1, ch)
|
||||
if path:
|
||||
b = path.encode('utf-8')[:1023] + b'\x00'
|
||||
ctypes.memmove(ptr + off + 16, b, len(b))
|
||||
return i
|
||||
raise RuntimeError("control queue full")
|
||||
|
||||
def push_controls(events):
|
||||
for i in range(8):
|
||||
w32(2836 + i * 1040, 'I', 0)
|
||||
for (ctype, arg0, arg1, ch, path) in events:
|
||||
write_control(ctype, arg0, arg1, ch, path)
|
||||
w32(11156, 'I', len(events))
|
||||
|
||||
def log_lines():
|
||||
try:
|
||||
with open(APP_LOG, 'r', encoding='utf-8', errors='replace') as f:
|
||||
return f.readlines()
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
|
||||
def wait_log(pattern, timeout, since, verbose=True):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
lines = log_lines()
|
||||
for i in range(since, len(lines)):
|
||||
if pattern in lines[i]:
|
||||
if verbose: print(f" LOG: {lines[i].strip()}")
|
||||
return lines[i].strip()
|
||||
time.sleep(0.2)
|
||||
return None
|
||||
|
||||
def write_index():
|
||||
return rd32(4)
|
||||
|
||||
def sample_wi(seconds):
|
||||
a = write_index(); time.sleep(seconds); b = write_index()
|
||||
return a, b
|
||||
|
||||
def bridge_pid():
|
||||
try:
|
||||
out = subprocess.run(["cmd", "/c", "tasklist /FI \"IMAGENAME eq daw_vst_bridge.exe\" /FO CSV"],
|
||||
capture_output=True, text=True).stdout
|
||||
for line in out.splitlines()[1:]:
|
||||
if "daw_vst_bridge" in line:
|
||||
return line.split(',')[1].strip('"')
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
bad = []
|
||||
def collect_bad(since):
|
||||
for l in log_lines()[since:]:
|
||||
if any(k in l for k in ("EXCEPTION", "FAILED", "restarted")):
|
||||
bad.append(l.strip())
|
||||
|
||||
since = len(log_lines())
|
||||
pid0 = bridge_pid()
|
||||
print("bridge pid:", pid0)
|
||||
|
||||
# --- Phase A: PLAY, audio advancing ---
|
||||
push_controls([(3, 1, 0, 0, "")])
|
||||
r = wait_log("transport PLAY", 10, since)
|
||||
print("A transport:", r or "TIMEOUT")
|
||||
a, b = sample_wi(3)
|
||||
print(f"A writeIndex {a}->{b} delta={b-a} ({'ADVANCING' if b > a else 'STALLED'})")
|
||||
if b <= a: bad.append("A: writeIndex stalled during PLAY")
|
||||
|
||||
# --- Phase B: OPEN_GUI ch5 during PLAY (expect deferred) ---
|
||||
since = len(log_lines())
|
||||
push_controls([(4, 0, 0, 5, "Nexus")])
|
||||
r = wait_log("transport PLAY) - queued", 10, since)
|
||||
print("B defer ch5:", r or "TIMEOUT")
|
||||
a, b = sample_wi(3)
|
||||
print(f"B writeIndex {a}->{b} delta={b-a} ({'ADVANCING' if b > a else 'STALLED'})")
|
||||
if b <= a: bad.append("B: writeIndex stalled while GUI deferred")
|
||||
collect_bad(since)
|
||||
|
||||
# --- Phase C: STOP -> attach ch5 ---
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 0, 0, 0, "")])
|
||||
r = wait_log("transport STOP", 10, since)
|
||||
print("C transport:", r or "TIMEOUT")
|
||||
r = wait_log("GUI attached hwnd=", 30, since)
|
||||
print("C attach ch5:", r or "TIMEOUT")
|
||||
|
||||
# --- Phase D: PLAY again -> OPEN_GUI ch6 (Option B synchronous close of ch5) ---
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 1, 0, 0, "")])
|
||||
r = wait_log("transport PLAY", 10, since)
|
||||
print("D transport:", r or "TIMEOUT")
|
||||
a, b = sample_wi(2)
|
||||
print(f"D writeIndex {a}->{b} delta={b-a} ({'ADVANCING' if b > a else 'STALLED'})")
|
||||
if b <= a: bad.append("D: writeIndex stalled during PLAY #2")
|
||||
since = len(log_lines())
|
||||
push_controls([(4, 0, 0, 6, "Nexus")])
|
||||
r = wait_log("transport PLAY) - queued", 10, since)
|
||||
print("D defer ch6:", r or "TIMEOUT (maybe attach directly?)")
|
||||
time.sleep(1)
|
||||
collect_bad(since)
|
||||
# ch5 editor must be closed (Option B) — check log for close editor of ch5
|
||||
closehit = wait_log("closeGUI", 15, since, verbose=False) or ""
|
||||
print("D close ch5 editor:", closehit or "no closeGUI log (check)")
|
||||
|
||||
# --- Phase E: STOP -> attach ch6 ---
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 0, 0, 0, "")])
|
||||
r = wait_log("transport STOP", 10, since)
|
||||
print("E transport:", r or "TIMEOUT")
|
||||
r = wait_log("GUI attached hwnd=", 30, since)
|
||||
print("E attach ch6:", r or "TIMEOUT")
|
||||
collect_bad(since)
|
||||
|
||||
# --- Phase F: close ch6 editor via WM_CLOSE (post_close_gui path) ---
|
||||
since = len(log_lines())
|
||||
# find ch6 hwnd from log
|
||||
hwnd6 = None
|
||||
for l in log_lines():
|
||||
if "ch=6" in l and "GUI attached" in l:
|
||||
import re
|
||||
m = re.search(r'hwnd=([0-9A-Fa-f]+)', l)
|
||||
if m: hwnd6 = int(m.group(1), 16)
|
||||
if hwnd6:
|
||||
ctypes.windll.user32.PostMessageW(hwnd6, 0x0010, 0, 0) # WM_CLOSE
|
||||
print("F posted WM_CLOSE to ch6 hwnd", hex(hwnd6))
|
||||
else:
|
||||
print("F hwnd6 not found")
|
||||
r = wait_log("closeGUI reload", 30, since)
|
||||
print("F close ch6:", r or "TIMEOUT")
|
||||
collect_bad(since)
|
||||
|
||||
# --- watch 8s for crash/restart ---
|
||||
since = len(log_lines())
|
||||
end = time.time() + 8
|
||||
while time.time() < end:
|
||||
collect_bad(since)
|
||||
pid = bridge_pid()
|
||||
if pid != pid0:
|
||||
bad.append(f"BRIDGE RESTART {pid0}->{pid}")
|
||||
break
|
||||
time.sleep(0.2)
|
||||
print()
|
||||
if bad:
|
||||
print("G1.2 RESULT: FAIL")
|
||||
for x in bad[:20]: print(" -", x)
|
||||
else:
|
||||
print("G1.2 RESULT: PASS - 1 UiThread, defer OK, Option B OK, close OK, audio advancing, no crash")
|
||||
@@ -0,0 +1,189 @@
|
||||
# G1.3 verification: pump gate removed, single UiThread.
|
||||
# Stress: resize (WM_SIZE) editor, LOAD replacing instrument while editor open,
|
||||
# close/reopen cycles, Option B, PLAY audio advancing throughout, no crash.
|
||||
import ctypes, ctypes.wintypes as w, struct, subprocess, sys, os, time, re
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
|
||||
APP_PID = int(sys.argv[1])
|
||||
SHM_NAME = f"SonicForge_DAW_IPC_{APP_PID}".encode()
|
||||
APP_LOG = os.path.join(os.environ.get('APPDATA', '.'), 'SonicForgeDAW', 'logs', 'bridge.log')
|
||||
NEXUS = r"C:\Program Files\Common Files\VST3\Nexus.vst3"
|
||||
EZKEYS = r"C:\Program Files\Common Files\VST3\Toontrack\EZkeys 2.vst3"
|
||||
|
||||
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
kernel32.OpenFileMappingA.argtypes = [ctypes.wintypes.DWORD, w.BOOL, ctypes.c_char_p]
|
||||
kernel32.OpenFileMappingA.restype = ctypes.c_void_p
|
||||
kernel32.MapViewOfFile.argtypes = [ctypes.c_void_p, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.c_size_t]
|
||||
kernel32.MapViewOfFile.restype = ctypes.c_void_p
|
||||
hMap = kernel32.OpenFileMappingA(0xF001F, False, SHM_NAME)
|
||||
if not hMap:
|
||||
print(f"OpenFileMapping failed err={ctypes.get_last_error()}"); sys.exit(1)
|
||||
ptr = kernel32.MapViewOfFile(hMap, 0xF001F, 0, 0, 0)
|
||||
user32 = ctypes.windll.user32
|
||||
|
||||
def w32(off, fmt, *args):
|
||||
ctypes.memmove(ptr + off, struct.pack(fmt, *args), struct.calcsize(fmt))
|
||||
def rd32(off):
|
||||
return ctypes.c_uint32.from_address(ptr + off).value
|
||||
|
||||
def write_control(ctype, arg0, arg1, ch, path):
|
||||
for i in range(8):
|
||||
off = 2836 + i * 1040
|
||||
if rd32(off) == 0:
|
||||
w32(off, 'IIII', ctype, arg0, arg1, ch)
|
||||
if path:
|
||||
b = path.encode('utf-8')[:1023] + b'\x00'
|
||||
ctypes.memmove(ptr + off + 16, b, len(b))
|
||||
return i
|
||||
raise RuntimeError("control queue full")
|
||||
|
||||
def push_controls(events):
|
||||
for i in range(8):
|
||||
w32(2836 + i * 1040, 'I', 0)
|
||||
for (ctype, arg0, arg1, ch, path) in events:
|
||||
write_control(ctype, arg0, arg1, ch, path)
|
||||
w32(11156, 'I', len(events))
|
||||
|
||||
def log_lines():
|
||||
try:
|
||||
with open(APP_LOG, 'r', encoding='utf-8', errors='replace') as f:
|
||||
return f.readlines()
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
|
||||
def wait_log(pattern, timeout, since, verbose=True):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
lines = log_lines()
|
||||
for i in range(since, len(lines)):
|
||||
if pattern in lines[i]:
|
||||
if verbose: print(f" LOG: {lines[i].strip()}")
|
||||
return lines[i].strip()
|
||||
time.sleep(0.2)
|
||||
return None
|
||||
|
||||
def write_index():
|
||||
return rd32(4)
|
||||
|
||||
def bridge_alive(pid0):
|
||||
try:
|
||||
out = subprocess.run(["tasklist"], capture_output=True, text=True).stdout
|
||||
for line in out.splitlines():
|
||||
p = line.split()
|
||||
if len(p) >= 2 and p[0] == "daw_vst_bridge.exe" and p[1] == pid0:
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
bad = []
|
||||
def collect_bad(since):
|
||||
for l in log_lines()[since:]:
|
||||
if any(k in l for k in ("EXCEPTION", "FAILED", "restarted")):
|
||||
bad.append(l.strip())
|
||||
|
||||
def find_hwnd(ch):
|
||||
last = None
|
||||
for l in log_lines():
|
||||
if f"ch={ch}" in l and "GUI attached" in l:
|
||||
m = re.search(r'hwnd=([0-9A-Fa-f]+)', l)
|
||||
if m: last = int(m.group(1), 16)
|
||||
return last
|
||||
|
||||
since0 = len(log_lines())
|
||||
# LOAD 6 Nexus + EZkeys (state may differ per run; just LOAD the needed ones)
|
||||
for ch in range(6):
|
||||
since = len(log_lines())
|
||||
push_controls([(2, 0, 0, ch, NEXUS)])
|
||||
r = wait_log(f"instrument loaded ch={ch}", 60, since, verbose=False)
|
||||
if not r: print(f" WARN load ch={ch} timeout")
|
||||
print("LOAD 6 Nexus done")
|
||||
|
||||
# --- T1: OPEN_GUI ch5, wait attach ---
|
||||
since = len(log_lines())
|
||||
push_controls([(4, 0, 0, 5, "Nexus")])
|
||||
r = wait_log("GUI attached", 30, since)
|
||||
print("T1 attach ch5:", "OK" if r else "TIMEOUT")
|
||||
collect_bad(since)
|
||||
hwnd5 = find_hwnd(5)
|
||||
print("T1 hwnd5:", hex(hwnd5) if hwnd5 else "None")
|
||||
|
||||
# --- T2: resize (WM_SIZE) while attached ---
|
||||
since = len(log_lines())
|
||||
if hwnd5:
|
||||
user32.SendMessageW(hwnd5, 0x0005, 0, (900 << 16) | 600) # WM_SIZE w=900 h=600
|
||||
time.sleep(1.5)
|
||||
print("T2 resize sent; log tail:")
|
||||
for l in log_lines()[-4:]: print(" ", l.strip())
|
||||
collect_bad(since)
|
||||
|
||||
# --- T3: PLAY with editor open, audio advancing ---
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 1, 0, 0, "")])
|
||||
r = wait_log("transport PLAY", 10, since)
|
||||
print("T3 transport:", r or "TIMEOUT")
|
||||
a, b = write_index(), 0
|
||||
time.sleep(3); b = write_index()
|
||||
print(f"T3 writeIndex {a}->{b} delta={b-a} ({'ADVANCING' if b > a else 'STALLED'})")
|
||||
if b <= a: bad.append("T3: writeIndex stalled with editor open")
|
||||
collect_bad(since)
|
||||
|
||||
# --- T4: LOAD EZkeys on ch5 WHILE editor open + PLAYING (replace inst with editor) ---
|
||||
since = len(log_lines())
|
||||
push_controls([(2, 0, 0, 5, EZKEYS)])
|
||||
r = wait_log("instrument loaded ch=5", 60, since)
|
||||
print("T4 load ch5 (EZkeys) while editor open:", "OK" if r else "TIMEOUT")
|
||||
collect_bad(since)
|
||||
a, b = write_index(), 0
|
||||
time.sleep(2); b = write_index()
|
||||
print(f"T4 writeIndex {a}->{b} delta={b-a} ({'ADVANCING' if b > a else 'STALLED'})")
|
||||
if b <= a: bad.append("T4: writeIndex stalled after LOAD while editor open")
|
||||
|
||||
# --- T5: STOP, close ch5 editor (WM_CLOSE), reopen ---
|
||||
since = len(log_lines())
|
||||
push_controls([(3, 0, 0, 0, "")])
|
||||
wait_log("transport STOP", 10, since)
|
||||
hwnd5b = find_hwnd(5)
|
||||
if hwnd5b:
|
||||
since = len(log_lines())
|
||||
user32.PostMessageW(hwnd5b, 0x0010, 0, 0) # WM_CLOSE
|
||||
r = wait_log("state restored ch=5", 40, since)
|
||||
print("T5 close ch5:", "OK" if r else "TIMEOUT")
|
||||
collect_bad(since)
|
||||
# reopen ch5 (now EZkeys)
|
||||
since = len(log_lines())
|
||||
push_controls([(4, 0, 0, 5, "EZkeys 2")])
|
||||
r = wait_log("GUI attached", 30, since)
|
||||
print("T5 reopen ch5:", "OK" if r else "TIMEOUT")
|
||||
collect_bad(since)
|
||||
|
||||
# --- T6: 3x close/reopen cycle ch5 ---
|
||||
for i in range(3):
|
||||
hwnd = find_hwnd(5)
|
||||
if not hwnd: print(f"T6 iter{i}: no hwnd"); break
|
||||
since = len(log_lines())
|
||||
user32.PostMessageW(hwnd, 0x0010, 0, 0)
|
||||
r = wait_log("state restored ch=5", 40, since, verbose=False)
|
||||
since = len(log_lines())
|
||||
push_controls([(4, 0, 0, 5, "EZkeys 2")])
|
||||
r2 = wait_log("GUI attached", 30, since, verbose=False)
|
||||
print(f"T6 iter{i}: close={'OK' if r else 'TIMEOUT'} reopen={'OK' if r2 else 'TIMEOUT'}")
|
||||
if not r or not r2:
|
||||
bad.append(f"T6 iter{i}: close/reopen fail"); break
|
||||
collect_bad(since)
|
||||
|
||||
# --- T7: watch 8s ---
|
||||
since = len(log_lines())
|
||||
end = time.time() + 8
|
||||
while time.time() < end:
|
||||
collect_bad(since)
|
||||
if not bridge_alive(str(APP_PID and 0)):
|
||||
pass
|
||||
time.sleep(0.2)
|
||||
print()
|
||||
if bad:
|
||||
print("G1.3 RESULT: FAIL")
|
||||
for x in bad[:20]: print(" -", x)
|
||||
else:
|
||||
print("G1.3 RESULT: PASS - resize OK, LOAD-while-editor OK, close/reopen x4 OK, no crash")
|
||||
@@ -0,0 +1,159 @@
|
||||
# G1.5 regression stress driver: N iterations of LOAD/OPEN_GUI/PLAY/STOP/WM_CLOSE
|
||||
# on Nexus + EZkeys. Watch: bridge process alive, no new EXCEPTION/FAILED, writeIndex advancing.
|
||||
import ctypes, ctypes.wintypes as w, struct, subprocess, sys, os, time, re
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
|
||||
APP_PID = int(sys.argv[1])
|
||||
ITERS = int(sys.argv[2]) if len(sys.argv) > 2 else 5
|
||||
SHM_NAME = f"SonicForge_DAW_IPC_{APP_PID}".encode()
|
||||
APP_LOG = os.path.join(os.environ.get('APPDATA', '.'), 'SonicForgeDAW', 'logs', 'bridge.log')
|
||||
NEXUS = r"C:\Program Files\Common Files\VST3\Nexus.vst3"
|
||||
EZKEYS = r"C:\Program Files\Common Files\VST3\Toontrack\EZkeys 2.vst3"
|
||||
|
||||
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
kernel32.OpenFileMappingA.argtypes = [ctypes.wintypes.DWORD, w.BOOL, ctypes.c_char_p]
|
||||
kernel32.OpenFileMappingA.restype = ctypes.c_void_p
|
||||
kernel32.MapViewOfFile.argtypes = [ctypes.c_void_p, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.c_size_t]
|
||||
kernel32.MapViewOfFile.restype = ctypes.c_void_p
|
||||
hMap = kernel32.OpenFileMappingA(0xF001F, False, SHM_NAME)
|
||||
if not hMap:
|
||||
print(f"OpenFileMapping failed err={ctypes.get_last_error()}"); sys.exit(1)
|
||||
ptr = kernel32.MapViewOfFile(hMap, 0xF001F, 0, 0, 0)
|
||||
print(f"SHM mapped ({SHM_NAME}) iters={ITERS}")
|
||||
|
||||
def w32(off, fmt, *args):
|
||||
ctypes.memmove(ptr + off, struct.pack(fmt, *args), struct.calcsize(fmt))
|
||||
def rd32(off):
|
||||
return ctypes.c_uint32.from_address(ptr + off).value
|
||||
|
||||
def write_control(ctype, arg0, arg1, ch, path):
|
||||
for i in range(8):
|
||||
off = 2836 + i * 1040
|
||||
if rd32(off) == 0:
|
||||
w32(off, 'IIII', ctype, arg0, arg1, ch)
|
||||
if path:
|
||||
b = path.encode('utf-8')[:1023] + b'\x00'
|
||||
ctypes.memmove(ptr + off + 16, b, len(b))
|
||||
return i
|
||||
raise RuntimeError("control queue full")
|
||||
|
||||
def push_controls(events):
|
||||
for i in range(8):
|
||||
w32(2836 + i * 1040, 'I', 0)
|
||||
for (ctype, arg0, arg1, ch, path) in events:
|
||||
write_control(ctype, arg0, arg1, ch, path)
|
||||
w32(11156, 'I', len(events))
|
||||
|
||||
def log_lines():
|
||||
try:
|
||||
with open(APP_LOG, 'r', encoding='utf-8', errors='replace') as f:
|
||||
return f.readlines()
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
|
||||
def wait_log(pattern, timeout, since):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
for i in range(since, len(log_lines())):
|
||||
if pattern in log_lines()[i]:
|
||||
return log_lines()[i]
|
||||
time.sleep(0.2)
|
||||
return None
|
||||
|
||||
def wait_gui(ch, timeout, since):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
for i in range(since, len(log_lines())):
|
||||
l = log_lines()[i]
|
||||
if "GUI attached hwnd=" in l and f"ch={ch}" in l:
|
||||
return l
|
||||
time.sleep(0.2)
|
||||
return None
|
||||
|
||||
def bridge_pid():
|
||||
out = subprocess.run(['powershell', '-Command',
|
||||
'(Get-Process daw_vst_bridge -ErrorAction SilentlyContinue).Id'],
|
||||
capture_output=True, text=True).stdout.strip().splitlines()
|
||||
return [int(x) for x in out if x.strip().isdigit()]
|
||||
|
||||
def bad_since(since):
|
||||
return [l for l in log_lines()[since:] if 'EXCEPTION' in l or 'FAILED' in l]
|
||||
|
||||
def find_hwnd(ch):
|
||||
last = None
|
||||
for l in log_lines():
|
||||
if "GUI attached hwnd=" in l and f"ch={ch}" in l:
|
||||
m = re.search(r'hwnd=([0-9A-Fa-f]+)', l)
|
||||
if m: last = int(m.group(1), 16)
|
||||
return last
|
||||
|
||||
fails = 0
|
||||
for it in range(ITERS):
|
||||
print(f"--- iter {it} ---")
|
||||
since = len(log_lines())
|
||||
# LOAD Nexus ch5
|
||||
push_controls([(2, 0, 0, 5, NEXUS)])
|
||||
if not wait_log("instrument loaded ch=5 type=0", 30, since):
|
||||
print(f"iter{it} LOAD Nexus TIMEOUT"); fails += 1; continue
|
||||
# OPEN_GUI ch5
|
||||
push_controls([(4, 0, 0, 5, NEXUS)])
|
||||
if not wait_gui(5, 30, since):
|
||||
print(f"iter{it} OPEN_GUI Nexus TIMEOUT"); fails += 1; continue
|
||||
# PLAY -> writeIndex advancing while editor open (G1.4 core)
|
||||
wi0 = rd32(4)
|
||||
push_controls([(3, 1, 0, 0, "")])
|
||||
if not wait_log("transport PLAY", 10, since):
|
||||
print(f"iter{it} PLAY TIMEOUT"); fails += 1; continue
|
||||
time.sleep(1.5)
|
||||
wi1 = rd32(4)
|
||||
ok = (wi1 - wi0) > 50
|
||||
print(f"iter{it} PLAY editor-open writeIndex {wi0}->{wi1} delta={wi1-wi0} {'OK' if ok else 'STALLED'}")
|
||||
if not ok: fails += 1
|
||||
# STOP
|
||||
push_controls([(3, 0, 0, 0, "")])
|
||||
if not wait_log("transport STOP", 10, since):
|
||||
print(f"iter{it} STOP TIMEOUT"); fails += 1; continue
|
||||
# WM_CLOSE ch5 -> state restored
|
||||
hwnd = find_hwnd(5)
|
||||
if hwnd:
|
||||
ctypes.windll.user32.PostMessageW(hwnd, 0x0010, 0, 0)
|
||||
r = wait_log("state restored ch=5", 30, since)
|
||||
print(f"iter{it} WM_CLOSE Nexus hwnd={hex(hwnd)}: {'OK' if r else 'TIMEOUT'}")
|
||||
if not r: fails += 1
|
||||
else:
|
||||
print(f"iter{it} hwnd Nexus not found"); fails += 1
|
||||
# LOAD EZkeys ch5 + OPEN_GUI + PLAY + STOP + CLOSE
|
||||
since = len(log_lines())
|
||||
push_controls([(2, 0, 0, 5, EZKEYS)])
|
||||
if not wait_log("instrument loaded ch=5 type=0", 30, since):
|
||||
print(f"iter{it} LOAD EZkeys TIMEOUT"); fails += 1; continue
|
||||
push_controls([(4, 0, 0, 5, EZKEYS)])
|
||||
if not wait_gui(5, 30, since):
|
||||
print(f"iter{it} OPEN_GUI EZkeys TIMEOUT"); fails += 1; continue
|
||||
push_controls([(3, 1, 0, 0, "")])
|
||||
wait_log("transport PLAY", 10, since)
|
||||
time.sleep(1.5)
|
||||
push_controls([(3, 0, 0, 0, "")])
|
||||
wait_log("transport STOP", 10, since)
|
||||
hwnd = find_hwnd(5)
|
||||
if hwnd:
|
||||
ctypes.windll.user32.PostMessageW(hwnd, 0x0010, 0, 0)
|
||||
r = wait_log("state restored ch=5", 30, since)
|
||||
print(f"iter{it} WM_CLOSE EZkeys hwnd={hex(hwnd)}: {'OK' if r else 'TIMEOUT'}")
|
||||
if not r: fails += 1
|
||||
else:
|
||||
print(f"iter{it} hwnd EZkeys not found"); fails += 1
|
||||
bad = bad_since(since)
|
||||
if bad:
|
||||
print(f"iter{it} EXCEPTION/FAILED: {bad[-2:]}"); fails += 1
|
||||
|
||||
# final watch: bridge alive + no new bad
|
||||
since = len(log_lines())
|
||||
time.sleep(3)
|
||||
bad = bad_since(since)
|
||||
alive = bridge_pid()
|
||||
print(f"bridge alive: {alive} (expect non-empty)") if alive else print("BRIDGE DEAD")
|
||||
if not alive: fails += 1
|
||||
print(f"G1.5 RESULT: {'PASS' if fails == 0 else f'FAIL ({fails} issues)'}")
|
||||
sys.exit(0 if fails == 0 else 1)
|
||||
Reference in New Issue
Block a user