From 78de0960c86fcefeaf0b071b9fef9817bb914427 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 May 2026 12:36:47 +0900 Subject: [PATCH 01/94] docs: add Serial transport design and client fork plan Introduce design documents for a new USB Serial transport extension on scratch-link 2.x. SerialTransport.md describes the server side: a /scratch/serial JSON-RPC endpoint on ws://localhost:20111, targeting CH340 (VID 0x1A86 / PID 0x7523) on Windows first via System.IO.Ports.SerialPort and WMI-based VID/PID enumeration. scratch-link-fork-plan.md is the aluxcoding-scratch client-side counterpart aligned to the same wire contract. Uses Serial-specific RPC vocabulary (serialDidReceiveData, serialDidDisconnect, startReading/stopReading) so callers cannot confuse Serial events with BLE or BT events. Co-Authored-By: Claude Opus 4.7 (1M context) --- Documentation/SerialTransport.md | 322 ++++++++++++++++++++++++ Documentation/scratch-link-fork-plan.md | 272 ++++++++++++++++++++ 2 files changed, 594 insertions(+) create mode 100644 Documentation/SerialTransport.md create mode 100644 Documentation/scratch-link-fork-plan.md diff --git a/Documentation/SerialTransport.md b/Documentation/SerialTransport.md new file mode 100644 index 00000000..cf92da61 --- /dev/null +++ b/Documentation/SerialTransport.md @@ -0,0 +1,322 @@ +# Serial Transport 설계 문서 + +본 문서는 scratch-link 의 fork (aluxcoding 배포본) 에 **USB Serial 트랜스포트**를 추가하기 위한 설계를 기술한다. 기존 BLE / BT(Classic) 트랜스포트는 변경하지 않고, 동일한 패턴으로 새 세션 타입을 추가하는 형태이다. + +1차 타겟 칩셋은 **CH340 (VID `0x1A86`, PID `0x7523`)**, 기본 보드레이트 1,000,000 bps. OS 는 Windows 만 고려한다. 후속으로 CP210x / FTDI / CH341 등을 동일 트랜스포트 위에 얹는 것을 염두에 둔다. + +연결 상대 Scratch 는 `../aluxcoding-scratch` 모노레포의 `scratch-link-client` 라이브러리를 사용하며, 본 문서가 단일 출처(SoT)가 된다. 클라이언트 측은 본 문서의 포트/경로/메서드 명세에 맞춰 정렬되어야 한다. + +## 결정 사항 요약 + +| 항목 | 결정 | +| --- | --- | +| WebSocket URL | `ws://localhost:20111/scratch/serial` (기존 포트/평문 유지) | +| TLS | 사용하지 않음 (loopback) | +| 프로토콜 | JSON-RPC 2.0. **수신 / 분리 알림은 Serial 전용 명명** (`serialDid...`) 으로 BT/BLE 와 코드상 구분. 요청 메서드(`discover`/`connect`/`write`)는 일반 동사라 공통 사용 | +| Serial API | `System.IO.Ports.SerialPort` (저사양 안정성 우선) | +| VID/PID 열거 | WMI (`Win32_PnPEntity`) | +| 1차 칩셋 | CH340 `VID_1A86 & PID_7523`, baud 1,000,000 | +| OS | Windows (`scratch-link-win`) 만 | + +### `System.IO.Ports.SerialPort` 채택 근거 + +`Windows.Devices.SerialCommunication.SerialDevice` (WinRT) 는 비동기 I/O 효율과 capability 모델 정합성에서 우월하지만, 일부 구형 / 저사양 PC 에서 `DeviceWatcher` 이벤트 누락과 WinRT 초기화 오버헤드가 보고된다. 본 fork 의 배포 대상이 저사양 교육용 PC 를 포함하므로, 동작이 단순하고 디버깅이 용이한 `System.IO.Ports.SerialPort` 를 1차 채택한다. `SerialPort` 의 알려진 단점인 USB surprise removal 시 hang 은 [§ 5.3](#53-분리surprise-removal-감지)의 이중 방어로 보완한다. 미래에 WinRT API 로 전환할 수 있도록 추상화 인터페이스([§ 3.1](#31-serialsessiontport-common-추상))는 API 중립으로 설계한다. + +## 1. 클라이언트 정합성 가정 + +`scratch-link-client` 라이브러리가 본 문서의 명세에 맞춰지도록, 다음 항목이 클라이언트 측에서 정렬되어야 한다 (참고용 — 클라이언트 작업 항목). + +- WebSocket 엔드포인트: `ws://localhost:20111/scratch/serial` +- 요청 메서드: `getVersion`, `discover`, `connect`, `write`, `disconnect`, `startReading`, `stopReading` +- 서버→클라 알림: `didDiscoverPeripheral`, `serialDidReceiveData`, `serialDidDisconnect` +- 페이로드 바이너리 인코딩: base64 + +## 2. 변경 지점 개요 + +| 위치 | 변경 | +| --- | --- | +| `scratch-link-common/Serial/SerialSession.cs` | **신규** 크로스플랫폼 추상 세션 | +| `scratch-link-common/Serial/DiscoveredSerialPort.cs` | **신규** 발견 결과 DTO | +| `scratch-link-common/Serial/SerialDiscoveryFilter.cs` | **신규** discover 파라미터 모델 | +| `scratch-link-win/Serial/WinSerialSession.cs` | **신규** Windows 구현 | +| `scratch-link-win/Serial/WinSerialPortEnumerator.cs` | **신규** WMI 기반 포트 열거 | +| `scratch-link-win/WinSessionManager.cs` | `/scratch/serial` 라우팅 추가 | +| `scratch-link-common/scratch-link-common.projitems` | 신규 .cs 파일 등록 | +| `scratch-link-win/scratch-link-win.csproj` | `System.Management` NuGet 의존성 추가 | +| `scratch-link-win-msix/Package.appxmanifest` | `serialcommunication` capability + VID/PID 항목 | +| `Documentation/NetworkProtocol.md` | Serial 섹션 추가 (별도 PR 가능) | + +기존 BLE / BT 코드는 건드리지 않는다. + +## 3. 클래스 구조 + +``` +Session ← scratch-link-common/Session.cs (그대로) +└─ PeripheralSession ← 그대로 + ├─ BLESession<…> (기존) + ├─ BTSession<…> (기존) + └─ SerialSession ★ 신규 (common, 추상) + └─ WinSerialSession ★ 신규 (windows, 구체 구현) +``` + +### 3.1 `SerialSession` (common, 추상) + +책임: + +- JSON-RPC 핸들러 등록 (`getVersion`, `discover`, `connect`, `write`, `disconnect`, `startReading`, `stopReading`) +- 발견 결과 캐시 및 연결 상태 머신 관리 +- 쓰기 데이터 base64 디코드, 수신 알림 base64 인코드 +- 수신 응집(coalesce) 윈도우 적용 후 알림 발사 + +추상 멤버 (플랫폼 구현이 채움): + +```csharp +protected abstract Task> EnumeratePortsAsync( + SerialDiscoveryFilter filter, CancellationToken ct); + +protected abstract Task ConnectAsync(TPort port, SerialOpenParams open, CancellationToken ct); + +protected abstract Task WriteAsync(byte[] data, CancellationToken ct); + +protected abstract Task DisconnectAsync(); + +// 수신 루프에서 발사. SerialSession 이 base64 인코딩 후 클라이언트로 알림 전송. +protected event Action DataReceived; +``` + +### 3.2 `WinSerialSession : SerialSession` + +- `EnumeratePortsAsync` → `WinSerialPortEnumerator.QueryAsync(filter)` 호출 ([§ 5.1](#51-포트-열거--vidpid-필터링)) +- `ConnectAsync` → `System.IO.Ports.SerialPort` 인스턴스 생성·구성·`Open()` +- `WriteAsync` → `BaseStream.WriteAsync` +- 수신 루프 → 백그라운드 `Task` + `BaseStream.ReadAsync` + `CancellationToken` ([§ 5.2](#52-수신-루프-패턴)) +- 분리 감지 → IOException 캐치 + WMI `__InstanceDeletionEvent` 백업 ([§ 5.3](#53-분리surprise-removal-감지)) + +## 4. JSON-RPC 프로토콜 (`/scratch/serial`) + +기존 BLE 메서드명을 그대로 차용해 클라이언트 라이브러리의 트랜스포트 어댑터가 BLE/Serial 분기를 최소화하도록 한다. + +### 4.1 `discover` (요청) + +```json +{ + "jsonrpc": "2.0", "id": 1, "method": "discover", + "params": { + "filters": [ + { "usbVendorId": 6790, "usbProductId": 29987 } + ] + } +} +``` + +- 응답은 즉시 (`{}`). 발견된 디바이스는 `didDiscoverPeripheral` 알림으로 push. +- `usbVendorId` / `usbProductId` 는 10진수 정수. +- 필터가 비어 있으면 모든 USB Serial 디바이스를 반환. + +### 4.2 `didDiscoverPeripheral` (서버→클라 알림) + +```json +{ + "jsonrpc": "2.0", "method": "didDiscoverPeripheral", + "params": { + "peripheralId": "COM7", + "name": "USB-SERIAL CH340 (COM7)", + "vendorId": "0x1A86", + "productId": "0x7523", + "rssi": 0 + } +} +``` + +- `peripheralId` 는 COM 포트명을 그대로 사용 → `connect` 시 동일 값으로 전달받음. +- `rssi` 는 BLE 와의 메시지 호환을 위해 항상 0 으로 채움. + +### 4.3 `connect` (요청) + +```json +{ + "jsonrpc": "2.0", "id": 2, "method": "connect", + "params": { + "peripheralId": "COM7", + "baudRate": 1000000, + "dataBits": 8, + "parity": "none", + "stopBits": "one", + "flowControl": "none" + } +} +``` + +- `baudRate` 외 파라미터는 모두 선택. 기본값: `dataBits=8`, `parity="none"`, `stopBits="one"`, `flowControl="none"`. +- 연결 성공 시 수신 알림이 자동으로 활성화된다. 명시적 토글이 필요하면 `startReading` / `stopReading` 메서드 사용 (BLE 의 `startNotifications` 와 별개의 Serial 전용 명명). + +### 4.4 `write` (요청) + +```json +{ + "jsonrpc": "2.0", "id": 3, "method": "write", + "params": { "message": "", "encoding": "base64" } +} +``` + +응답: 송신된 바이트 수 (정수). + +### 4.5 `serialDidReceiveData` (수신 알림) + +Serial 전용 명명. BLE 의 `characteristicDidChange` / BT 의 `didReceiveMessage` 와 명확히 구분하기 위해 별도 명명을 쓴다 — 클라이언트 코드에서 BT/BLE 와 혼동 없이 즉시 식별 가능. + +```json +{ + "jsonrpc": "2.0", "method": "serialDidReceiveData", + "params": { "message": "", "encoding": "base64" } +} +``` + +### 4.6 분리 / 오류 + +- `serialDidDisconnect` 알림 — Serial 전용 명명. BLE/BT 의 `peripheralDidDisconnect` 와 구분. + + ```json + { + "jsonrpc": "2.0", "method": "serialDidDisconnect", + "params": { "reason": "device", "message": "USB device removed" } + } + ``` + + - `reason`: `"user"` | `"device"` | `"error"` | `"shutdown"` (선택 필드, 없으면 `"error"` 로 해석). + - `message`: 사람이 읽을 수 있는 보조 메시지 (선택). +- 표준 JSON-RPC 2.0 error 응답 (코드/메시지). + +## 5. Windows 구현 세부 + +### 5.1 포트 열거 + VID/PID 필터링 + +`System.IO.Ports.SerialPort.GetPortNames()` 만으로는 VID/PID 를 얻을 수 없으므로 **WMI** 로 보완한다. + +```sql +SELECT DeviceID, PNPDeviceID, Caption +FROM Win32_PnPEntity +WHERE PNPClass = 'Ports' AND PNPDeviceID LIKE 'USB%' +``` + +- `PNPDeviceID` 예: `USB\VID_1A86&PID_7523\6&1A2B3C4D&0&5` +- 정규식 `VID_([0-9A-F]{4})&PID_([0-9A-F]{4})` 로 VID/PID 추출. +- `Caption` 끝의 `(COMx)` 에서 COM 번호 캡쳐. + +필터 매칭에 성공한 항목을 [§ 4.2](#42-diddiscoverperipheral-서버클라-알림) 형식으로 1건씩 알림 발사. + +> `.NET 6` 에서는 `System.Management` 가 NuGet 패키지로 분리되어 있으므로 `scratch-link-win.csproj` 에 다음을 추가한다: +> +> ```xml +> +> ``` + +### 5.2 수신 루프 패턴 + +```csharp +_rxCts = new CancellationTokenSource(); +_rxLoop = Task.Run(async () => +{ + var buf = new byte[4096]; + try + { + while (!_rxCts.IsCancellationRequested) + { + int n = await _port.BaseStream.ReadAsync(buf, 0, buf.Length, _rxCts.Token); + if (n > 0) + { + RaiseDataReceived(new ReadOnlySpan(buf, 0, n).ToArray()); + } + } + } + catch (OperationCanceledException) { /* 정상 종료 */ } + catch (IOException) { OnSurpriseRemoval(); } +}); +``` + +- `SerialPort.DataReceived` 이벤트는 **사용하지 않는다.** 콜백이 ThreadPool 에서 호출되며 OS 버퍼링이 비결정적이라 1Mbps 환경에서 드롭 사례가 보고된다. +- `ReadTimeout` / `WriteTimeout` 은 무한 (`InfiniteTimeout`) 으로 두고 취소는 `CancellationToken` 으로 제어한다. +- 수신 직후 즉시 알림을 발사하면 메시지 폭주가 가능 → 1\~5 ms 의 **응집 윈도우** 를 두고 모은 바이트를 한 번에 알림으로 전송. 기본값은 1 ms 로 시작해 실제 디바이스로 측정 후 조정. + +### 5.3 분리(Surprise Removal) 감지 + +`SerialPort` 는 USB 분리 시 `ReadAsync` 가 즉시 예외를 던지지 않고 hang 하는 사례가 있어 이중 방어한다. + +1. **WMI 이벤트** 구독: + + ```sql + SELECT * FROM __InstanceDeletionEvent WITHIN 2 + WHERE TargetInstance ISA 'Win32_PnPEntity' + ``` + + 이벤트의 `TargetInstance.PNPDeviceID` 가 현재 연결된 디바이스와 일치하면 `_rxCts.Cancel()` + `_port.Dispose()` + `serialDidDisconnect` 알림 (`reason: "device"`). +2. `ReadAsync` 캐치블록의 `IOException` / `OperationCanceledException` 처리에서도 동일 정리 경로를 호출. WMI 가 누락되어도 자가 복구되도록 한다. + +### 5.4 MSIX manifest + +`scratch-link-win-msix/Package.appxmanifest` 의 `` 에 추가: + +```xml + + + + + + + +``` + +> 본 구현은 `System.IO.Ports.SerialPort` 를 사용하므로 WinRT capability 가 엄격히 필수는 아니다. 그러나 (a) 미래의 WinRT API 전환 여지와 (b) MSIX 사용자에게 명시적 권한 동의를 받기 위해 등록을 권장한다. + +후속 칩셋(CP210x, FTDI 등)을 지원할 때는 `` 항목만 추가하면 된다. + +### 5.5 라우팅 + +`scratch-link-win/WinSessionManager.cs` 의 `MakeNewSession` switch 에 한 줄 추가: + +```csharp +case "/scratch/serial": + return new WinSerialSession(webSocket); +``` + +## 6. 시퀀스 (CH340 예) + +```mermaid +sequenceDiagram + autonumber + participant GUI as Scratch GUI + participant Link as scratch-link + participant Port as CH340 (COM7) + + GUI->>Link: ws://localhost:20111/scratch/serial + GUI->>Link: discover { filters:[{usbVendorId:0x1A86, usbProductId:0x7523}] } + Link-->>GUI: { } (ok) + Link->>GUI: didDiscoverPeripheral { peripheralId:"COM7", vendorId:"0x1A86", ... } + GUI->>Link: connect { peripheralId:"COM7", baudRate:1000000 } + Link->>Port: SerialPort.Open() + Link-->>GUI: { } (ok) + + GUI->>Link: write { message:"" } + Link->>Port: BaseStream.WriteAsync + Link-->>GUI: { sentBytes: N } + + Port-->>Link: (bytes available) + Link->>GUI: serialDidReceiveData { message:"" } + + Note over Port: USB 분리 + Link->>GUI: serialDidDisconnect { reason:"device" } +``` + +## 7. 식별 / 브랜딩 점검 (배포 전) + +- `scratch-link-win-msix/Package.appxmanifest` 의 `Identity Name`, `PublisherDisplayName`, 트레이 아이콘 리소스, 자동 시작 `StartupTask` ID 를 aluxcoding 배포본 브랜드로 교체. +- 라이센스: 본 fork 의 베이스는 `develop` 브랜치 머지된 **AGPL-3.0-only** (커밋 `18ee302`). 자체 배포 시 AGPL 의무 (소스 공개) 가 발생하므로 배포 정책 사전 확인 필요. + +## 8. 미해결 / 후속 결정 사항 + +1. **수신 응집 윈도우 기본값**: 1 ms vs 5 ms. 실제 디바이스에서 측정 후 결정. +2. **다중 동시 연결**: 한 세션당 단일 포트 (BLE 패턴과 동일). 다중이 필요해지면 별도 세션을 여는 방식으로 운영. +3. **타 칩셋 추가**: CH341 / CP210x / FTDI 는 동일 `SerialSession` 을 그대로 쓰고 manifest 의 VID/PID 항목과 `discover.filters` 호출만 다르게. +4. **로깅**: 기존 scratch-link 의 로깅 채널에 `SerialSession` 로그를 동일 레벨로 통합. +5. **테스트 디바이스 확보**: CH340 보드 1대 + 분리/재삽입 + 1Mbps 연속 송수신 테스트. +6. **클라이언트 라이브러리 정렬 PR**: `aluxcoding-scratch` 의 `scratch-link-client` 가 본 문서 § 1 의 명세대로 변경되어야 함. diff --git a/Documentation/scratch-link-fork-plan.md b/Documentation/scratch-link-fork-plan.md new file mode 100644 index 00000000..f5816646 --- /dev/null +++ b/Documentation/scratch-link-fork-plan.md @@ -0,0 +1,272 @@ +# Scratch Link fork + Serial extension — 작업 계획 + +작성: 2026-05-22 +대상 브랜치: `feature/scratch-link-websocket` +관련 코드: [libs/scratch-link-client/](../libs/scratch-link-client/), [libs/virtual-machine/src/io/web-socket-link.ts](../libs/virtual-machine/src/io/web-socket-link.ts), [libs/virtual-machine/src/blocks/extensions/codetinker/codetinker-peripheral.ts](../libs/virtual-machine/src/blocks/extensions/codetinker/codetinker-peripheral.ts) + +이 문서는 Link transport 전략 전환 (자체 link 폐기 → 원본 Scratch Link fork) 의 **본 저장소 측 작업 계획** 과 +**fork 가 노출해야 할 WebSocket 프로토콜 경계** 를 정의한다. + +fork 내부 (C# 구현, 시리얼 드라이버, 세션 매니저, 인증서 흐름 등) 는 별도 저장소에서 작업하며 본 문서의 범위가 아니다. +fork 작업은 본 문서가 정의한 **WebSocket-level 계약** 만 충족하면 된다. + +--- + +## 1. 배경 + +### 1.1 전략 전환 + +- **변경 전**: 자체 link 프로그램 `aluxcoding-scratch-link` 신규 개발. + - 자체 RPC: `listSerialPorts` / `openSerial` / `closeSerial` / `write` + `sessionId` 모델. + - 엔드포인트 `wss://localhost:28347`. + - 본 저장소의 [libs/scratch-link-client/](../libs/scratch-link-client/) 와 [io/web-socket-link.ts](../libs/virtual-machine/src/io/web-socket-link.ts) 는 이 RPC 에 맞춰져 있음. +- **변경 후**: 원본 Scratch Link git 을 fork 해서 거기에 **Serial extension** 을 BLE/BT 와 동형으로 추가. + - 클라이언트는 원본 Scratch Link 프로토콜 패턴 (`discover` → `didDiscoverPeripheral` → `connect` → `write` / `startNotifications`) 을 그대로 따름. + - 원본의 세션/세팅 흐름 재활용 (loopback `ws://localhost:20111`, JSON-RPC 2.0). 1.3 시대의 wss/인증서/device-manager DNS 는 2.x 에서 폐기되어 본 작업에서도 사용하지 않는다. + +### 1.2 왜 fork 인가 + +- 자체 link 신규 개발 시간 + 배포 문제. +- 원본 scratch-link 는 이미 검증된 세션 처리 + 다중 클라이언트 정책을 갖춤. +- BLE/BT 와 동일한 호출 패턴을 따르면 클라이언트 측 추상화가 단순해진다 (peripheral 추상화의 BLE/BT/Serial 모드 분기). +- loopback `ws://` 모델이라 인증서 발급/배포 문제도 자연 소거된다. + +--- + +## 2. 책임 경계 + +이 작업은 두 저장소에 걸쳐 진행된다. 본 문서는 **본 저장소 (aluxcoding-scratch)** 의 작업과 +**두 저장소 사이의 WebSocket 계약** 만 다룬다. + +| 영역 | 책임 저장소 | 본 문서가 다루는가 | +|---|---|---| +| WebSocket 엔드포인트 (loopback `ws://`) | fork (별도) | ✗ (요구사항만 명시) | +| JSON-RPC 메시지 schema (메서드명, 파라미터, 결과) | 양쪽 공유 (계약) | ✓ §4 | +| Serial 드라이버, COM 포트 열거, 세션 관리 | fork (별도) | ✗ | +| 페이로드 인코딩 (base64 byte 처리) | 양쪽 공유 (계약) | ✓ §4 | +| 클라이언트 (브라우저) JSON-RPC 처리, 재연결, 메시지 라우팅 | 본 저장소 | ✓ §5 | +| IO 어댑터 (`web-socket-link.ts`) | 본 저장소 | ✓ §5 | +| codetinker peripheral 의 Link 분기 (`_isLinkMode`, `_scanLink`, lifecycle override) | 본 저장소 | ✓ §6 | +| 다른 peripheral 의 Link 통합 | 본 저장소 (후속) | △ §8 | + +--- + +## 3. 전체 로드맵 + +### Phase 0 — 폐기 대상 정리 (사전 작업, 진행 중) + +- [x] 자체 link 전제로 작성된 문서 제거 (`scratch-link-protocol.md`, `scratch-link-codetinker-verification.md`). +- [ ] 본 문서 (`scratch-link-fork-plan.md`) 확정. + +### Phase 1 — Serial RPC 계약 확정 + +- [ ] §4 의 RPC 메서드/notification 명세를 fork 측 담당자와 정합 (특히 메서드명, peripheral 식별자 형식). +- [ ] 엔드포인트 / 인증서 / 포트 정책 확정 (원본 scratch-link 와 동일 vs 변경 — §4.1 참조). +- [ ] §4 본문 갱신 + fork 저장소 README 에 동일 명세 미러링. + +### Phase 2 — `scratch-link-client` 재작성 + +기존 self-link 호환 코드의 protocol/messages, capability probe, client 의 RPC layer 를 새 계약에 맞춰 재작성. +재사용 가능한 layer: + +- [transport.ts](../libs/scratch-link-client/src/transport.ts) (WebSocket + 재연결 + state machine) — **재사용**. URL/포트만 교체. +- [codec.ts](../libs/scratch-link-client/src/protocol/codec.ts) (JSON encode/decode, base64) — **재사용**. base64 라이브러리만 유지. +- [client.ts](../libs/scratch-link-client/src/client.ts) — **부분 재사용**. JSON-RPC request/response 패턴은 유지, notification 라우팅과 메서드 enum 만 교체. +- [protocol/messages.ts](../libs/scratch-link-client/src/protocol/messages.ts) — **재작성**. `ListSerialPortsParams` 등 self-link RPC 타입 전면 폐기. +- [constants.ts](../libs/scratch-link-client/src/constants.ts) — **재작성**. 포트·호스트·메서드명 변경. +- [errors.ts](../libs/scratch-link-client/src/errors.ts) — **재사용**. 명칭만 유지 (LinkXxxError). +- [capability.ts](../libs/scratch-link-client/src/capability.ts) — **부분 재작성**. probe URL 만 새 엔드포인트로. + +작업 단위: +- [ ] §4 계약을 `protocol/messages.ts` 의 타입과 `LinkMethods` enum 으로 옮긴다. +- [ ] `client.ts` 에 새 high-level helper 추가 (예: `discover(filters)`, `connect(peripheralId)`, `write(message)`, `startReading()`). +- [ ] 새 엔드포인트로 `LINK_HOST` / `LINK_PORT_WS` / `LINK_URL` 갱신. +- [ ] `capability.ts` 의 probe URL 갱신 + 응답 검사 (단순 WS open 만으로 부족하면 `getVersion` 호출 추가 — §4.5). + +### Phase 3 — IO 어댑터 (`web-socket-link.ts`) 재작성 + +기존 [web-socket-link.ts](../libs/virtual-machine/src/io/web-socket-link.ts) 의 `sessionId` 모델 (openSerial → close → write) 을 폐기하고 +`discover → connect → write/startReading` 모델로 교체 (Serial 전용 명명). + +작업 단위: +- [ ] `WebSocketLink` API 시그니처 검토 — peripheral 측 lifecycle override (`scan`/`connect`/`write`/`disconnect`) 와 매칭되도록 유지하면서 내부는 새 RPC 로 교체. +- [ ] `subscribe` 콜백 (`onDataReceived`, `onConnected`, `onDisconnected`, `onReadingError`, `onConnectionCancelled`) **그대로 유지** — peripheral 측 변경 영향 최소화. +- [ ] `listPorts`/`addFilter` 는 `discover(filters)` + `didDiscoverPeripheral` notification 수집 모델로 교체. +- [ ] `write(data: Uint8Array)` 의 페이로드 인코딩 / RPC 메서드명만 갱신. +- [ ] `currentSessionId` 외부 노출 검토 — 새 모델에서는 `peripheralId` 기반이므로 명칭/시그니처 정리. + +### Phase 4 — codetinker peripheral Link 분기 정합 + +[codetinker-peripheral.ts](../libs/virtual-machine/src/blocks/extensions/codetinker/codetinker-peripheral.ts) 의 +`_isLinkMode` / `_scanLink` / `scan|connect|disconnect|isConnected` override / write 흐름이 §6 의 호출 패턴과 일치하는지 확인. + +작업 단위: +- [ ] [codetinker-peripheral.ts:541-583](../libs/virtual-machine/src/blocks/extensions/codetinker/codetinker-peripheral.ts) `_scanLink()` 의 filter 등록 (`addFilter({ vendorId, productId })`) 이 새 `discover(filters)` 명세에 매칭되는지 검토. +- [ ] [codetinker-peripheral.ts:498-617](../libs/virtual-machine/src/blocks/extensions/codetinker/codetinker-peripheral.ts) lifecycle override 골격 유지, 내부 어댑터 호출만 교체. +- [ ] write 흐름 (큐 처리, immediate write) 의 어댑터 메서드 시그니처 변경 반영. + +### Phase 5 — 시험·검증 + +fork 빌드와 본 저장소 dev 서버를 함께 실행해 단대단 확인. 절차는 fork 측 README + 본 문서 §7. + +--- + +## 4. Serial extension — WebSocket 프로토콜 명세 + +본 절은 fork 와 클라이언트가 **반드시 동일하게** 따라야 하는 wire 계약이다. +변경은 양쪽 PR 을 동시에 진행한다. + +### 4.1 엔드포인트 + +- `ws://localhost:20111/scratch/serial` +- TLS / 인증서 / DNS resolve 없음. scratch-link 2.x 가 loopback 평문 모델 ([ScratchLinkApp.cs:17](../../scratch-link/scratch-link-common/ScratchLinkApp.cs#L17), [Documentation/SerialTransport.md](../../scratch-link/Documentation/SerialTransport.md) §0) 이므로 그대로 따른다. +- 포트 20111 은 정품 scratch-link 와 동일하므로 동시 실행 불가. 정품과의 공존은 본 작업의 비목표. + +### 4.2 메시지 프레이밍 + +- WebSocket text frame, UTF-8 JSON, JSON-RPC 2.0. +- 한 frame 당 한 JSON-RPC 메시지. batch 미지원 (원본 scratch-link 정책 동일). +- 바이너리 payload (USB 시리얼 byte stream) 는 base64 문자열로 인코딩 후 JSON 필드에 담는다. + +### 4.3 메서드 (client → server, request) + +| 메서드 | 파라미터 | 결과 | 설명 | +|---|---|---|---| +| `getVersion` | `{}` | `{ protocol: string }` | 핸드셰이크. 클라이언트는 연결 직후 1회 호출해 호환성 검사. | +| `discover` | `{ filters: ReadonlyArray<{ usbVendorId?: number; usbProductId?: number; pathHint?: string }> }` | `{}` (빈 객체, 즉시 응답) | filter 매칭 포트 열거 시작. 결과는 `didDiscoverPeripheral` notification 으로 streaming. `usbVendorId` / `usbProductId` 는 10진수 정수. | +| `connect` | `{ peripheralId: string; baudRate: number; dataBits?: number; parity?: "none" \| "even" \| "odd"; stopBits?: "one" \| "onePointFive" \| "two"; flowControl?: "none" \| "rtsCts" \| "xonXoff" }` | `{}` | 특정 포트 연결. `peripheralId` 는 직전 `didDiscoverPeripheral` 의 식별자. baudRate 외 옵션은 생략 시 기본값 (`dataBits=8`, `parity="none"`, `stopBits="one"`, `flowControl="none"`). | +| `write` | `{ message: string; encoding: "base64" }` | `{ sentBytes: number }` | 직렬화된 byte stream 송신. `sentBytes` 는 실제 송신 byte 수. partial write 는 fork 가 보장하지 않음 (전체 송신 후 응답). | +| `startReading` | `{}` | `{}` | RX 수신 활성화. **참고**: scratch-link 측 (SerialTransport.md §4.3) 은 `connect` 직후 자동으로 RX 가 활성화되므로 본 메서드는 명시 토글이 필요한 경우에만 호출. RX byte 는 `serialDidReceiveData` notification 으로 push. (BLE 의 `startNotifications` 와 별개의 Serial 전용 명명.) | +| `stopReading` | `{}` | `{}` | RX 수신 일시 중지. write 는 계속 가능. | +| `disconnect` | `{}` | `{}` | 세션 종료 + 포트 해제. 정상 종료 시 notification 없음. | + +### 4.4 notification (server → client) + +| 메서드 | 파라미터 | 설명 | +|---|---|---| +| `didDiscoverPeripheral` | `{ peripheralId: string; name: string; vendorId?: string; productId?: string; rssi?: number }` | discover 중 새 포트 발견 시. `vendorId` / `productId` 는 16진 문자열 (예: `"0x1A86"`). `rssi` 는 BLE 메시지 호환을 위해 0 으로 채워질 수 있음. 같은 discover 세션 동안 같은 peripheralId 의 중복 발행은 fork 가 억제. | +| `serialDidReceiveData` | `{ message: string; encoding: "base64" }` | RX byte 도착. `connect` 성공 직후부터 자동 발행 (scratch-link 측 SoT 가 자동 활성화 모델). `stopReading` 호출 시 일시 중지. **Serial 전용 명명** — BLE 의 `characteristicDidChange` / BT 의 `didReceiveMessage` 와 구분. | +| `serialDidDisconnect` | `{ reason?: "user" \| "device" \| "error" \| "shutdown"; message?: string }` | 외부 요인 (USB 분리, fork shutdown, 드라이버 오류) 으로 세션 종료. 클라이언트의 명시적 `disconnect` 응답으로는 발행 안 함. **Serial 전용 명명** — BLE/BT 의 `peripheralDidDisconnect` 와 구분. | + +> **명명 결정**: 수신 / 분리 알림은 Serial 전용 명명 (`serialDidReceiveData` / `serialDidDisconnect`) 채택. BLE/BT 와 코드상에서 한눈에 구분되도록 한다. RX 토글 메서드도 `startReading` / `stopReading` 으로 BLE 의 `startNotifications` 와 분리. scratch-link 측 SoT ([SerialTransport.md](../../scratch-link/Documentation/SerialTransport.md) §1·§4.5·§4.6) 에 정렬 (2026-05-22 확정). + +### 4.5 핸드셰이크 / liveness + +1. 클라이언트가 WS 연결 → fork onopen. +2. 클라이언트 → `getVersion` 요청. fork → 응답 (`{ protocol: "1.0" }` 형태). +3. 응답 `protocol` 가 클라이언트 기대 버전과 mismatch 면 클라이언트가 disconnect. +4. liveness 는 WebSocket close detection 으로만 감지. 별도 ping notification 은 두지 않는다 (scratch-link 측 미지원, 원본 BLE/BT 와 동형). +5. 클라이언트는 별도 keepalive request 를 보내지 않는다 (원본 scratch-link 와 동형). + +### 4.6 에러 처리 + +- JSON-RPC 2.0 에러 객체 (`{ code, message, data? }`) 를 사용. +- 코드 매핑 (권장): + - `-32600`: invalid request + - `-32601`: method not found + - `-32602`: invalid params (filter 형식 오류, baudRate 범위 등) + - `-32603`: internal error (드라이버 실패) + - 애플리케이션 에러 (예: 연결 실패, 포트 점유) 는 `-32000 ~ -32099` 범위 사용. 구체적 코드는 Phase 1 에서 확정. + +--- + +## 5. 본 저장소 측 변경 사항 + +### 5.1 폐기되는 코드 / 상수 + +본 저장소에서 self-link 가정으로 작성된 부분 — 재작성 또는 갱신: + +- [libs/scratch-link-client/src/protocol/messages.ts](../libs/scratch-link-client/src/protocol/messages.ts) 의 `ListSerialPortsParams` / `OpenSerialParams` / `CloseSerialParams` / `WriteParams` (sessionId 모델) — **전부 폐기**. +- 같은 파일의 `LinkMethods` enum — **재정의**. +- [libs/scratch-link-client/src/constants.ts](../libs/scratch-link-client/src/constants.ts) 의 `LINK_PORT_WSS = 28347` → **`LINK_PORT_WS = 20111`** (TLS 폐기로 명명도 정정). `LINK_HOST = "localhost"`, 권장 URL 상수 `LINK_URL = "ws://localhost:20111/scratch/serial"`. +- [libs/scratch-link-client/src/client.ts](../libs/scratch-link-client/src/client.ts) 의 keepalive ping 로직 — 폐기 (§4.5). WebSocket close detection 으로 대체. +- [libs/virtual-machine/src/io/web-socket-link.ts](../libs/virtual-machine/src/io/web-socket-link.ts) 의 sessionId 추적 / `openSerial → closeSerial` 흐름 — **재작성**. + +### 5.2 유지되는 코드 / 추상화 + +peripheral 측 영향을 최소화하기 위해 다음 외부 API 는 시그니처를 유지: + +- `WebSocketLink` 의 subscriber callback (`onConnected`, `onDisconnected`, `onConnectionCancelled`, `onDataReceived`, `onReadingError`, `onDataSend`). +- `WebSocketLink.connect(baudRate, options)`, `disconnect()`, `write(data: Uint8Array)`, `writeImmediate(data: Uint8Array)`, `isConnected`, `dispose()`. +- `addFilter({ vendorId, productId })` — 내부적으로 `discover(filters)` 의 filter 로 매핑. + +내부적으로는 sessionId → peripheralId 로 식별자 의미가 바뀐다. 외부 노출용 `currentSessionId` getter 는 +`currentPeripheralId` 로 개명하거나 deprecate. + +### 5.3 신설되는 RPC 헬퍼 (client.ts) + +[client.ts](../libs/scratch-link-client/src/client.ts) 의 `request(method, params)` 위에 high-level 헬퍼 추가: + +- `getVersion(): Promise<{ protocol: string }>` +- `discover(filters): Promise` — request 응답은 `{}`. discovery 결과는 `onDidDiscoverPeripheral` callback 으로 전달. +- `connect(peripheralId, options): Promise` +- `write(bytes: Uint8Array): Promise<{ sentBytes: number }>` — base64 인코딩은 헬퍼 내부. +- `startReading(): Promise` / `stopReading(): Promise` +- `disconnect(): Promise` + +콜백 인터페이스 (`LinkClientCallbacks`) 도 갱신: +- `onDataReceived` 유지 (의미: `serialDidReceiveData` notification 처리). +- `onDeviceDisconnected` 유지 (의미: `serialDidDisconnect` notification 처리). +- `onDeviceError` 유지. +- `onDidDiscoverPeripheral` 신설. +- liveness 모니터링은 WebSocket close detection 으로 처리 — 별도 콜백 불필요. + +--- + +## 6. codetinker peripheral 통합 영향 + +### 6.1 유지 + +[codetinker-peripheral.ts](../libs/virtual-machine/src/blocks/extensions/codetinker/codetinker-peripheral.ts) 의 +Link transport 1~5 차 커밋 (`bbdf5a696 ~ bb61aa819`) 에서 추가한 main-side 골격은 그대로 유지: + +- `_isLinkMode()` 분기 (전역 transport 선호도 기반). +- `_scanLink()` 의 WebSocketLink 인스턴스 생성, filter 등록, subscriber 등록 패턴. +- `scan()` / `connect()` / `disconnect()` / `isConnected()` lifecycle override. +- write/flushSendQueue 의 Link 분기. + +### 6.2 변경 + +- scratch-link 측 SoT ([SerialTransport.md](../../scratch-link/Documentation/SerialTransport.md) §4.3) 가 `connect` 직후 자동 RX 활성화 모델이므로 별도 `startReading()` 호출은 **불필요**. 명시 토글 (한시적 RX 중지 등) 이 필요할 때만 `startReading` / `stopReading` 사용 (Serial 전용 명명). +- `addFilter` 호출은 그대로 (`{ vendorId, productId }`). 내부적으로 `discover(filters)` 의 `usbVendorId` / `usbProductId` 키로 매핑. +- 단일 포트 자동 선택 로직 ([web-socket-link.ts:108-120](../libs/virtual-machine/src/io/web-socket-link.ts)) 은 `didDiscoverPeripheral` 누적 + 첫 포트 선택으로 교체. 다중 포트 picker UI 는 후속 (§8). + +### 6.3 다른 peripheral + +CodingDrone / CodingRider 등 Link 미지원 peripheral 은 본 작업 범위 외. +같은 패턴을 따르면 추후 통합 가능하지만 현재는 USB Serial (codetinker) 만 대상. + +--- + +## 7. 검증 절차 (Phase 5 채워질 자리) + +Phase 1~4 완료 후 본 절을 구체화한다. 현재는 골격만 기재. + +1. **fork 단독 시험**: fork 저장소의 자체 단위 테스트 + 통합 시험 (별도 저장소 책임). +2. **본 저장소 단위 테스트**: `scratch-link-client` 의 RPC 헬퍼·콜백 라우팅을 mock WS 로 검증. +3. **단대단 시험**: + - fork 빌드 실행 → tray 또는 콘솔에서 `ws://localhost:20111` listening 확인. + - `pnpm dev` → `http://localhost:4200/ko/codetinker` 접속. + - stage-header transport 토글에서 **Link** 선택 → USB 버튼. + - 콘솔 / Network tab 으로 RPC 흐름 (`getVersion → discover → didDiscoverPeripheral → connect → serialDidReceiveData / write`) 확인. + - 미션 sb3 로드 → 컨트롤러 명령 전송 / 센서 RX 동작 확인. +4. **회귀 시험**: USB transport (`_isLinkMode() === false`) 가 영향 없는지 확인. + +--- + +## 8. 미해결 결정 사항 (Phase 1 에서 닫는다) + +- [x] ~~**DNS / 포트 정책**~~ — `ws://localhost:20111` 로 확정 (2026-05-22). +- [x] ~~**메서드명 최종 확정**~~ — Serial 전용 명명 `serialDidReceiveData` / `serialDidDisconnect`, RX 토글 `startReading` / `stopReading` 채택. BLE/BT 와 코드상 명확 구분 목적 (2026-05-22). +- [x] ~~**인증서 trust 자동화**~~ — TLS 미사용으로 항목 폐기. +- [ ] **discover 종료 신호**: discover 가 시간 제한 없이 streaming 인지, fork 가 timeout 후 `didDiscoverFinished` 같은 종료 notification 을 보내는지. +- [ ] **다중 포트 picker UI**: codetinker 가 유일 시리얼이 아닐 때의 선택 UI (이번 phase 의 범위 외이지만 결정 시점 명시). +- [ ] **다중 클라이언트 정책**: 같은 peripheralId 에 두 탭이 연결 시도 시 fork 의 거부/대기 정책 (원본 scratch-link 의 BLE 정책 차용 여부). + +--- + +## 9. 관련 자료 + +- 메모리: `link-transport-strategy` (전략 전환 배경). +- 원본 scratch-link 저장소 (LLK/scratch-link) — fork 작업의 출발점. BLE/BT extension 의 메시지 schema 가 Serial extension 의 참조 자료. +- codetinker Link transport 1~5 차 커밋: `bbdf5a696` ~ `bb61aa819` (main-side override 골격, 본 작업으로 변경되지 않음). From 15e5c1530e639e693377d7c65821486caf5af10f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 May 2026 14:16:15 +0900 Subject: [PATCH 02/94] feat: add Serial transport for USB devices Mirrors the BLE/BT session pattern with a /scratch/serial JSON-RPC endpoint. CH340 (VID 0x1A86 / PID 0x7523) is first-class via WMI-based VID/PID enumeration; other CDC devices work through the same path with appropriate discovery filters. Why a separate listener port (20211): this fork is meant to coexist with the stock scratch-link on user machines (e.g. existing Scratch 3.0 users), so the default 20110/20111 cannot be reused. Why sync SerialPort.Read on a Task-Run thread instead of BaseStream.ReadAsync: .NET 6's SerialStream does not override the async read overloads in a way that survives CH340's open-time DTR/RTS toggling; the first ReadAsync reliably throws ERROR_OPERATION_ABORTED even with the cancellation token unbound. Synchronous Read with a 500ms ReadTimeout + TimeoutException-as-loop-tick matches the working test_cs reference and lets shutdown be observed via the CTS. DtrEnable/RtsEnable are pinned low explicitly because some firmware (codetinker on CH340) treats DTR/RTS transitions as reset signals. Co-Authored-By: Claude Opus 4.7 (1M context) --- scratch-link-common/ScratchLinkApp.cs | 2 +- .../Serial/SerialDiscoveryFilter.cs | 28 ++ .../Serial/SerialOpenParams.cs | 37 ++ scratch-link-common/Serial/SerialSession.cs | 340 ++++++++++++++++++ .../scratch-link-common.projitems | 3 + scratch-link-win-msix/Package.appxmanifest | 5 + .../Serial/WinSerialPortEnumerator.cs | 143 ++++++++ scratch-link-win/Serial/WinSerialPortInfo.cs | 37 ++ scratch-link-win/Serial/WinSerialSession.cs | 299 +++++++++++++++ scratch-link-win/WinSessionManager.cs | 2 + scratch-link-win/scratch-link-win.csproj | 2 + 11 files changed, 897 insertions(+), 1 deletion(-) create mode 100644 scratch-link-common/Serial/SerialDiscoveryFilter.cs create mode 100644 scratch-link-common/Serial/SerialOpenParams.cs create mode 100644 scratch-link-common/Serial/SerialSession.cs create mode 100644 scratch-link-win/Serial/WinSerialPortEnumerator.cs create mode 100644 scratch-link-win/Serial/WinSerialPortInfo.cs create mode 100644 scratch-link-win/Serial/WinSerialSession.cs diff --git a/scratch-link-common/ScratchLinkApp.cs b/scratch-link-common/ScratchLinkApp.cs index 52626e00..fa7077a1 100644 --- a/scratch-link-common/ScratchLinkApp.cs +++ b/scratch-link-common/ScratchLinkApp.cs @@ -14,7 +14,7 @@ namespace ScratchLink; /// public class ScratchLinkApp { - private const int WebSocketPort = 20111; + private const int WebSocketPort = 20211; private readonly SessionManager sessionManager; private readonly WebSocketListener webSocketListener; diff --git a/scratch-link-common/Serial/SerialDiscoveryFilter.cs b/scratch-link-common/Serial/SerialDiscoveryFilter.cs new file mode 100644 index 00000000..1e2efd37 --- /dev/null +++ b/scratch-link-common/Serial/SerialDiscoveryFilter.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) 2026 ALUX, Inc. All rights reserved. +// Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only. +// + +namespace ScratchLink.Serial; + +/// +/// A single filter entry passed by the client in a serial "discover" request. +/// A port is reported when it matches any filter in the list. +/// +internal class SerialDiscoveryFilter +{ + /// + /// Gets or sets the USB vendor ID to match, as a decimal integer. + /// + public int? UsbVendorId { get; set; } + + /// + /// Gets or sets the USB product ID to match, as a decimal integer. + /// + public int? UsbProductId { get; set; } + + /// + /// Gets or sets an optional port path substring to match (e.g. "COM7"). + /// + public string PathHint { get; set; } +} diff --git a/scratch-link-common/Serial/SerialOpenParams.cs b/scratch-link-common/Serial/SerialOpenParams.cs new file mode 100644 index 00000000..2b52f66e --- /dev/null +++ b/scratch-link-common/Serial/SerialOpenParams.cs @@ -0,0 +1,37 @@ +// +// Copyright (c) 2026 ALUX, Inc. All rights reserved. +// Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only. +// + +namespace ScratchLink.Serial; + +/// +/// Parameters extracted from a serial "connect" request. +/// +internal class SerialOpenParams +{ + /// + /// Gets or sets the baud rate. Required. + /// + public int BaudRate { get; set; } + + /// + /// Gets or sets the data bits. Defaults to 8. + /// + public int DataBits { get; set; } + + /// + /// Gets or sets the parity setting: "none", "even", or "odd". Defaults to "none". + /// + public string Parity { get; set; } + + /// + /// Gets or sets the stop bits: "one", "onePointFive", or "two". Defaults to "one". + /// + public string StopBits { get; set; } + + /// + /// Gets or sets the flow control: "none", "rtsCts", or "xonXoff". Defaults to "none". + /// + public string FlowControl { get; set; } +} diff --git a/scratch-link-common/Serial/SerialSession.cs b/scratch-link-common/Serial/SerialSession.cs new file mode 100644 index 00000000..b6f9ce01 --- /dev/null +++ b/scratch-link-common/Serial/SerialSession.cs @@ -0,0 +1,340 @@ +// +// Copyright (c) 2026 ALUX, Inc. All rights reserved. +// Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only. +// + +namespace ScratchLink.Serial; + +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using Fleck; +using ScratchLink.Extensions; +using ScratchLink.JsonRpc; + +/// +/// Cross-platform base for a USB Serial transport session. Uses Serial-specific +/// notification names (serialDidReceiveData, serialDidDisconnect) +/// so callers cannot confuse Serial events with BLE characteristic events or +/// BT message events. +/// +/// Platform-specific port handle, passed back to . +internal abstract class SerialSession : PeripheralSession + where TPort : class +{ + /// + /// Initializes a new instance of the class. + /// + /// + public SerialSession(IWebSocketConnection webSocket) + : base(webSocket) + { + this.Handlers["discover"] = this.HandleDiscover; + this.Handlers["write"] = this.HandleWrite; + this.Handlers["disconnect"] = this.HandleDisconnect; + this.Handlers["startReading"] = this.HandleStartReading; + this.Handlers["stopReading"] = this.HandleStopReading; + } + + /// + /// Implement the JSON-RPC "discover" request. Parses the filter list and + /// kicks off platform-specific enumeration. Discovered ports are streamed + /// back via . + /// + /// The name of the method being called ("discover"). + /// A JSON object optionally containing a filters array. + /// A resolving to an empty result; discoveries are streamed via notifications. + protected Task HandleDiscover(string methodName, JsonElement? args) + { + var filters = ParseFilters(args); + Trace.WriteLine($"received serial discover request with {filters.Count} filter(s)"); + + this.ClearDiscoveredPeripherals(); + return this.DoDiscover(filters); + } + + /// + /// Platform-specific implementation for port discovery. Implementations + /// should return promptly and stream results via . + /// + /// The filter list from the client. Empty means "match all". + /// A representing the asynchronous operation. + protected abstract Task DoDiscover(IReadOnlyList filters); + + /// + protected override Task DoConnect(TPort port, JsonElement? args) + { + var openParams = ParseOpenParams(args); + return this.DoConnect(port, openParams); + } + + /// + /// Platform-specific implementation for opening the given port. On success, + /// RX should be active and incoming bytes should be reported via + /// . + /// + /// The port handle previously registered via . + /// Open parameters extracted from the connect request. + /// A representing the asynchronous operation. + protected abstract Task DoConnect(TPort port, SerialOpenParams openParams); + + /// + /// Implement the JSON-RPC "write" request. Decodes the base64 payload and + /// forwards to the platform implementation. + /// + /// The name of the method being called ("write"). + /// A JSON object containing message and encoding. + /// An object with sentBytes equal to the number of bytes written. + protected async Task HandleWrite(string methodName, JsonElement? args) + { + if (args == null) + { + throw JsonRpc2Error.InvalidParams("write requires a message buffer").ToException(); + } + + var buffer = EncodingHelpers.DecodeBuffer(args.Value); + var sentBytes = await this.DoWrite(buffer); + + return new Dictionary { ["sentBytes"] = sentBytes }; + } + + /// + /// Platform-specific implementation for sending bytes to the port. + /// + /// The bytes to send. + /// The number of bytes actually written. + protected abstract Task DoWrite(byte[] data); + + /// + /// Implement the JSON-RPC "disconnect" request. Closes the port without + /// firing a serialDidDisconnect notification (that is reserved for + /// external-cause disconnects). + /// + /// The name of the method being called ("disconnect"). + /// Unused. + /// An empty result. + protected async Task HandleDisconnect(string methodName, JsonElement? args) + { + await this.DoDisconnect(); + return new Dictionary(); + } + + /// + /// Platform-specific implementation for closing the port. + /// + /// A representing the asynchronous operation. + protected abstract Task DoDisconnect(); + + /// + /// Implement the JSON-RPC "startReading" request. RX is enabled automatically + /// on connect, so the default implementation is a no-op. Subclasses may + /// override to re-enable RX after a stopReading. + /// + /// The name of the method being called ("startReading"). + /// Unused. + /// An empty result. + protected virtual Task HandleStartReading(string methodName, JsonElement? args) + { + return Task.FromResult(new Dictionary()); + } + + /// + /// Implement the JSON-RPC "stopReading" request. Default is a no-op. + /// + /// The name of the method being called ("stopReading"). + /// Unused. + /// An empty result. + protected virtual Task HandleStopReading(string methodName, JsonElement? args) + { + return Task.FromResult(new Dictionary()); + } + + /// + /// Report received bytes to the client as a serialDidReceiveData + /// notification. The payload is base64-encoded. + /// + /// The bytes received. + /// A representing the asynchronous operation. + protected async Task DidReceiveData(byte[] data) + { + var encoded = EncodingHelpers.EncodeBuffer(data, "base64"); + await this.SendNotification("serialDidReceiveData", new SerialDataReceived + { + Encoding = "base64", + Message = encoded, + }); + } + + /// + /// Report an external-cause disconnect to the client as a + /// serialDidDisconnect notification. Does not fire for the + /// client-initiated disconnect request. + /// + /// One of "user", "device", "error", "shutdown". + /// Optional human-readable detail. + /// A representing the asynchronous operation. + protected async Task DidDisconnect(string reason, string message = null) + { + await this.SendNotification("serialDidDisconnect", new SerialDisconnectMessage + { + Reason = reason, + Message = message, + }); + } + + /// + /// Track a discovered port and report it to the client. Uses + /// to + /// obtain a session-scoped peripheral ID. + /// + /// Platform-specific port handle. + /// OS-level port path used as the address (e.g. "COM7"). + /// User-visible name, may include the path. + /// Vendor ID as a hex string (e.g. "0x1A86"), or null. + /// Product ID as a hex string (e.g. "0x7523"), or null. + /// A representing the asynchronous operation. + protected async Task OnPortDiscovered(TPort port, string path, string displayName, string vendorIdHex, string productIdHex) + { + var peripheralId = this.RegisterPeripheral(port, path); + + await this.SendNotification("didDiscoverPeripheral", new SerialPortDiscovered + { + PeripheralId = peripheralId, + Name = displayName, + Path = path, + VendorId = vendorIdHex, + ProductId = productIdHex, + RSSI = 0, + }); + } + + private static IReadOnlyList ParseFilters(JsonElement? args) + { + var result = new List(); + + var filtersElement = args?.TryGetProperty("filters"); + if (filtersElement == null) + { + return result; + } + + if (filtersElement.Value.ValueKind != JsonValueKind.Array) + { + throw JsonRpc2Error.InvalidParams("'filters' must be an array").ToException(); + } + + foreach (var item in filtersElement.Value.EnumerateArray()) + { + result.Add(new SerialDiscoveryFilter + { + UsbVendorId = item.TryGetProperty("usbVendorId")?.GetInt32(), + UsbProductId = item.TryGetProperty("usbProductId")?.GetInt32(), + PathHint = item.TryGetProperty("pathHint")?.GetString(), + }); + } + + return result; + } + + private static SerialOpenParams ParseOpenParams(JsonElement? args) + { + var baudRate = args?.TryGetProperty("baudRate")?.GetInt32(); + if (baudRate == null) + { + throw JsonRpc2Error.InvalidParams("connect requires baudRate").ToException(); + } + + return new SerialOpenParams + { + BaudRate = baudRate.Value, + DataBits = args?.TryGetProperty("dataBits")?.GetInt32() ?? 8, + Parity = args?.TryGetProperty("parity")?.GetString() ?? "none", + StopBits = args?.TryGetProperty("stopBits")?.GetString() ?? "one", + FlowControl = args?.TryGetProperty("flowControl")?.GetString() ?? "none", + }; + } + + /// + /// Payload of a serialDidReceiveData notification. + /// + protected class SerialDataReceived + { + /// + /// Gets or sets the encoding identifier; always "base64" for serial RX. + /// + [JsonPropertyName("encoding")] + public string Encoding { get; set; } + + /// + /// Gets or sets the encoded payload. + /// + [JsonPropertyName("message")] + public string Message { get; set; } + } + + /// + /// Payload of a serialDidDisconnect notification. + /// + protected class SerialDisconnectMessage + { + /// + /// Gets or sets the disconnect reason: "user", "device", "error", or "shutdown". + /// + [JsonPropertyName("reason")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Reason { get; set; } + + /// + /// Gets or sets an optional human-readable detail message. + /// + [JsonPropertyName("message")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Message { get; set; } + } + + /// + /// Payload of a didDiscoverPeripheral notification on the serial transport. + /// + protected class SerialPortDiscovered + { + /// + /// Gets or sets the session-scoped peripheral ID used by the client to connect. + /// + [JsonPropertyName("peripheralId")] + public string PeripheralId { get; set; } + + /// + /// Gets or sets the user-visible name of the port. + /// + [JsonPropertyName("name")] + public string Name { get; set; } + + /// + /// Gets or sets the OS-level port path (e.g. "COM7"). + /// + [JsonPropertyName("path")] + public string Path { get; set; } + + /// + /// Gets or sets the USB vendor ID as a hex string (e.g. "0x1A86"), if known. + /// + [JsonPropertyName("vendorId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string VendorId { get; set; } + + /// + /// Gets or sets the USB product ID as a hex string (e.g. "0x7523"), if known. + /// + [JsonPropertyName("productId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string ProductId { get; set; } + + /// + /// Gets or sets a placeholder RSSI value for cross-transport message compatibility. + /// + [JsonPropertyName("rssi")] + public int RSSI { get; set; } + } +} diff --git a/scratch-link-common/scratch-link-common.projitems b/scratch-link-common/scratch-link-common.projitems index 9ce3b456..569953fd 100644 --- a/scratch-link-common/scratch-link-common.projitems +++ b/scratch-link-common/scratch-link-common.projitems @@ -13,6 +13,9 @@ + + + diff --git a/scratch-link-win-msix/Package.appxmanifest b/scratch-link-win-msix/Package.appxmanifest index 9d911758..97d9a55a 100644 --- a/scratch-link-win-msix/Package.appxmanifest +++ b/scratch-link-win-msix/Package.appxmanifest @@ -45,5 +45,10 @@ + + + + + diff --git a/scratch-link-win/Serial/WinSerialPortEnumerator.cs b/scratch-link-win/Serial/WinSerialPortEnumerator.cs new file mode 100644 index 00000000..4167521a --- /dev/null +++ b/scratch-link-win/Serial/WinSerialPortEnumerator.cs @@ -0,0 +1,143 @@ +// +// Copyright (c) 2026 ALUX, Inc. All rights reserved. +// Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only. +// + +namespace ScratchLink.Win.Serial; + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Management; +using System.Text.RegularExpressions; +using ScratchLink.Serial; + +/// +/// Enumerates USB serial ports on Windows via WMI (Win32_PnPEntity), extracting +/// the COM port name plus USB VID/PID from the PNPDeviceID. Used by +/// for discovery. +/// +internal static class WinSerialPortEnumerator +{ + private const string WmiQuery = + "SELECT DeviceID, PNPDeviceID, Caption, Name FROM Win32_PnPEntity " + + "WHERE PNPClass = 'Ports' AND PNPDeviceID LIKE 'USB%'"; + + private static readonly Regex VidPidRegex = new ( + @"VID_([0-9A-F]{4})&PID_([0-9A-F]{4})", + RegexOptions.IgnoreCase | RegexOptions.Compiled); + + private static readonly Regex ComPortRegex = new ( + @"\((COM\d+)\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled); + + /// + /// Synchronously query WMI for USB serial ports matching any of the given filters. + /// + /// Filter list. Empty means "return all matching USB serial ports". + /// List of matching ports. May be empty. + public static IReadOnlyList Query(IReadOnlyList filters) + { + var results = new List(); + + try + { + using var searcher = new ManagementObjectSearcher(WmiQuery); + using var collection = searcher.Get(); + + foreach (var item in collection) + { + using var mo = (ManagementObject)item; + var info = BuildPortInfo(mo); + if (info == null) + { + continue; + } + + if (!MatchesAnyFilter(info, filters)) + { + continue; + } + + results.Add(info); + } + } + catch (ManagementException e) + { + Trace.WriteLine($"WMI query failed during serial port enumeration: {e}"); + } + catch (Exception e) + { + Trace.WriteLine($"Unexpected error during serial port enumeration: {e}"); + } + + return results; + } + + private static WinSerialPortInfo BuildPortInfo(ManagementObject mo) + { + var pnpId = mo["PNPDeviceID"] as string ?? string.Empty; + var caption = mo["Caption"] as string ?? string.Empty; + var name = mo["Name"] as string ?? caption; + + var comMatch = ComPortRegex.Match(caption); + if (!comMatch.Success) + { + // No COM port number means this isn't a usable serial port from our point of view. + return null; + } + + int? vendorId = null; + int? productId = null; + var vidPidMatch = VidPidRegex.Match(pnpId); + if (vidPidMatch.Success) + { + vendorId = int.Parse(vidPidMatch.Groups[1].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture); + productId = int.Parse(vidPidMatch.Groups[2].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture); + } + + return new WinSerialPortInfo + { + Path = comMatch.Groups[1].Value, + DisplayName = name, + VendorId = vendorId, + ProductId = productId, + PnpDeviceId = pnpId, + }; + } + + private static bool MatchesAnyFilter(WinSerialPortInfo info, IReadOnlyList filters) + { + if (filters == null || filters.Count == 0) + { + return true; + } + + foreach (var filter in filters) + { + if (filter.UsbVendorId.HasValue && filter.UsbVendorId.Value != info.VendorId) + { + continue; + } + + if (filter.UsbProductId.HasValue && filter.UsbProductId.Value != info.ProductId) + { + continue; + } + + if (!string.IsNullOrEmpty(filter.PathHint)) + { + if (info.Path == null || + info.Path.IndexOf(filter.PathHint, StringComparison.OrdinalIgnoreCase) < 0) + { + continue; + } + } + + return true; + } + + return false; + } +} diff --git a/scratch-link-win/Serial/WinSerialPortInfo.cs b/scratch-link-win/Serial/WinSerialPortInfo.cs new file mode 100644 index 00000000..b28f27d2 --- /dev/null +++ b/scratch-link-win/Serial/WinSerialPortInfo.cs @@ -0,0 +1,37 @@ +// +// Copyright (c) 2026 ALUX, Inc. All rights reserved. +// Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only. +// + +namespace ScratchLink.Win.Serial; + +/// +/// A single port returned by . +/// +internal class WinSerialPortInfo +{ + /// + /// Gets or sets the OS-level port path (e.g. "COM7"). + /// + public string Path { get; set; } + + /// + /// Gets or sets a user-visible name (typically includes the COM number). + /// + public string DisplayName { get; set; } + + /// + /// Gets or sets the USB vendor ID, or null if not parseable. + /// + public int? VendorId { get; set; } + + /// + /// Gets or sets the USB product ID, or null if not parseable. + /// + public int? ProductId { get; set; } + + /// + /// Gets or sets the raw PNPDeviceID, useful for surprise-removal matching. + /// + public string PnpDeviceId { get; set; } +} diff --git a/scratch-link-win/Serial/WinSerialSession.cs b/scratch-link-win/Serial/WinSerialSession.cs new file mode 100644 index 00000000..06cf5c58 --- /dev/null +++ b/scratch-link-win/Serial/WinSerialSession.cs @@ -0,0 +1,299 @@ +// +// Copyright (c) 2026 ALUX, Inc. All rights reserved. +// Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only. +// + +namespace ScratchLink.Win.Serial; + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Ports; +using System.Threading; +using System.Threading.Tasks; +using Fleck; +using ScratchLink.JsonRpc; +using ScratchLink.Serial; + +/// +/// Implements a USB Serial session on Windows using +/// for I/O and WMI for VID/PID-aware port discovery. +/// +internal class WinSerialSession : SerialSession +{ + private SerialPort port; + private CancellationTokenSource rxCts; + private Task rxLoop; + + /// + /// Initializes a new instance of the class. + /// + /// The WebSocket connection for this session. + public WinSerialSession(IWebSocketConnection webSocket) + : base(webSocket) + { + } + + /// + protected override bool IsConnected => this.port != null && this.port.IsOpen; + + /// + protected override async Task DoDiscover(IReadOnlyList filters) + { + var ports = await Task.Run(() => WinSerialPortEnumerator.Query(filters)); + + foreach (var portInfo in ports) + { + var vendorHex = portInfo.VendorId.HasValue + ? $"0x{portInfo.VendorId.Value:X4}" + : null; + var productHex = portInfo.ProductId.HasValue + ? $"0x{portInfo.ProductId.Value:X4}" + : null; + + await this.OnPortDiscovered(portInfo, portInfo.Path, portInfo.DisplayName, vendorHex, productHex); + } + + return new Dictionary(); + } + + /// + protected override Task DoConnect(WinSerialPortInfo info, SerialOpenParams openParams) + { + if (this.port != null) + { + throw JsonRpc2Error.InvalidRequest("already connected").ToException(); + } + + try + { + this.port = new SerialPort(info.Path) + { + BaudRate = openParams.BaudRate, + DataBits = openParams.DataBits, + Parity = MapParity(openParams.Parity), + StopBits = MapStopBits(openParams.StopBits), + Handshake = MapFlowControl(openParams.FlowControl), + ReadTimeout = 500, + WriteTimeout = SerialPort.InfiniteTimeout, + // CH340 + codetinker firmware treats DTR/RTS transitions as a reset signal; + // pin them low explicitly so SerialPort.Open does not toggle them. + DtrEnable = false, + RtsEnable = false, + }; + this.port.Open(); + } + catch (Exception e) + { + Trace.WriteLine($"Failed to open serial port {info.Path}: {e}"); + this.CloseConnectionSilently(); + throw JsonRpc2Error.ApplicationError($"could not open serial port {info.Path}: {e.Message}").ToException(); + } + + this.rxCts = new CancellationTokenSource(); + var token = this.rxCts.Token; + this.rxLoop = Task.Run(() => this.ReadLoop(token)); + + return Task.FromResult(new Dictionary()); + } + + /// + protected override async Task DoWrite(byte[] data) + { + var currentPort = this.port; + if (currentPort == null || !currentPort.IsOpen) + { + throw JsonRpc2Error.InvalidRequest("cannot write when not connected").ToException(); + } + + try + { + await currentPort.BaseStream.WriteAsync(data, 0, data.Length); + } + catch (ObjectDisposedException) + { + throw JsonRpc2Error.InternalError("write failed: port was disposed").ToException(); + } + catch (IOException e) + { + throw JsonRpc2Error.InternalError($"write failed: {e.Message}").ToException(); + } + + return data.Length; + } + + /// + protected override async Task DoDisconnect() + { + var loop = this.rxLoop; + this.CloseConnectionSilently(); + + if (loop != null) + { + try + { + await loop; + } + catch + { + // swallow: the loop's own error path already reported anything client-visible + } + } + } + + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + this.CloseConnectionSilently(); + } + + private static Parity MapParity(string parity) => + (parity ?? "none").ToLowerInvariant() switch + { + "none" => Parity.None, + "even" => Parity.Even, + "odd" => Parity.Odd, + "mark" => Parity.Mark, + "space" => Parity.Space, + _ => throw JsonRpc2Error.InvalidParams($"unsupported parity: {parity}").ToException(), + }; + + private static StopBits MapStopBits(string stopBits) => + (stopBits ?? "one").ToLowerInvariant() switch + { + "one" => StopBits.One, + "onepointfive" => StopBits.OnePointFive, + "two" => StopBits.Two, + _ => throw JsonRpc2Error.InvalidParams($"unsupported stopBits: {stopBits}").ToException(), + }; + + private static Handshake MapFlowControl(string flow) => + (flow ?? "none").ToLowerInvariant() switch + { + "none" => Handshake.None, + "rtscts" => Handshake.RequestToSend, + "xonxoff" => Handshake.XOnXOff, + _ => throw JsonRpc2Error.InvalidParams($"unsupported flowControl: {flow}").ToException(), + }; + + private void ReadLoop(CancellationToken ct) + { + var buf = new byte[4096]; + + while (!ct.IsCancellationRequested) + { + var currentPort = this.port; + if (currentPort == null || !currentPort.IsOpen) + { + break; + } + + int n; + try + { + // SerialPort.BaseStream.ReadAsync on .NET 6 reliably throws + // ERROR_OPERATION_ABORTED on the first call against CH340 ports + // (even without a CancellationToken, even with DTR/RTS pinned low). + // Use the synchronous Read with a finite ReadTimeout so the loop + // wakes periodically and shutdown can be observed via ct. + n = currentPort.Read(buf, 0, buf.Length); + } + catch (TimeoutException) + { + continue; + } + catch (OperationCanceledException) + { + break; + } + catch (IOException) when (ct.IsCancellationRequested) + { + break; + } + catch (IOException e) + { + Trace.WriteLine($"Serial read IOException on {currentPort.PortName}: {e.Message}"); + _ = this.DidDisconnect("device", e.Message); + this.CloseConnectionSilently(); + break; + } + catch (ObjectDisposedException) + { + break; + } + catch (InvalidOperationException) + { + break; + } + catch (Exception e) + { + Trace.WriteLine($"Unexpected serial read error: {e}"); + _ = this.DidDisconnect("error", e.Message); + this.CloseConnectionSilently(); + break; + } + + if (n <= 0) + { + continue; + } + + var data = new byte[n]; + Buffer.BlockCopy(buf, 0, data, 0, n); + _ = this.DidReceiveData(data); + } + } + + private void CloseConnectionSilently() + { + var localCts = this.rxCts; + this.rxCts = null; + + try + { + localCts?.Cancel(); + } + catch + { + // ignored + } + + var localPort = this.port; + this.port = null; + + if (localPort != null) + { + try + { + if (localPort.IsOpen) + { + localPort.Close(); + } + } + catch (Exception e) + { + Trace.WriteLine($"Error closing serial port: {e}"); + } + + try + { + localPort.Dispose(); + } + catch + { + // ignored + } + } + + try + { + localCts?.Dispose(); + } + catch + { + // ignored + } + } +} diff --git a/scratch-link-win/WinSessionManager.cs b/scratch-link-win/WinSessionManager.cs index 9d8e1313..36603a24 100644 --- a/scratch-link-win/WinSessionManager.cs +++ b/scratch-link-win/WinSessionManager.cs @@ -7,6 +7,7 @@ namespace ScratchLink.Win; using Fleck; using ScratchLink.Win.BLE; using ScratchLink.Win.BT; +using ScratchLink.Win.Serial; /// /// Implements the Windows-specific functionality of the SessionManager. @@ -21,6 +22,7 @@ protected override Session MakeNewSession(IWebSocketConnection webSocket) { "/scratch/ble" => new WinBLESession(webSocket), "/scratch/bt" => new WinBTSession(webSocket), + "/scratch/serial" => new WinSerialSession(webSocket), // for unrecognized paths, return a base Session for debugging _ => new Session(webSocket), diff --git a/scratch-link-win/scratch-link-win.csproj b/scratch-link-win/scratch-link-win.csproj index df4ac45a..f364bab5 100644 --- a/scratch-link-win/scratch-link-win.csproj +++ b/scratch-link-win/scratch-link-win.csproj @@ -41,5 +41,7 @@ + + From e48ea8fadbfce10732046ce109246a3ce4d8f623 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 May 2026 14:17:35 +0900 Subject: [PATCH 03/94] chore: rebrand fork as Alux Scratch Link Sets fork identity across assembly/package metadata, manifests, tray UI, and icon assets so users can distinguish this binary from the stock scratch-link they may have installed in parallel (see the port 20211 split in the Serial transport commit). ScratchVersion.targets gains a floor of 1.0.0 when GitInfo finds no semver tag, so an untagged build ships as "Alux Scratch Link 1.0.0.x" instead of "0.0.x". Real releases are still cut by tagging. Co-Authored-By: Claude Opus 4.7 (1M context) --- SharedProps/ScratchVersion.targets | 9 ++++++++- .../Images/LockScreenLogo.scale-200.png | Bin 1854 -> 2561 bytes .../Images/SplashScreen.scale-200.png | Bin 31626 -> 182715 bytes .../Images/Square150x150Logo.scale-200.png | Bin 12016 -> 51493 bytes .../Images/Square44x44Logo.scale-200.png | Bin 3333 -> 6452 bytes ...x44Logo.targetsize-24_altform-unplated.png | Bin 1033 -> 983 bytes scratch-link-win-msix/Images/StoreLogo.png | Bin 1945 -> 2776 bytes .../Images/Wide310x150Logo.scale-200.png | Bin 14073 -> 54467 bytes scratch-link-win-msix/Package.appxmanifest | 10 +++++----- scratch-link-win/TrayIcon.xaml | 4 ++-- scratch-link-win/app.manifest | 2 +- scratch-link-win/scratch-link-tray.ico | Bin 5390 -> 3255 bytes scratch-link-win/scratch-link-win.csproj | 4 ++-- scratch-link-win/scratch-link.ico | Bin 143099 -> 73875 bytes 14 files changed, 18 insertions(+), 11 deletions(-) diff --git a/SharedProps/ScratchVersion.targets b/SharedProps/ScratchVersion.targets index 469911a4..51cd3651 100644 --- a/SharedProps/ScratchVersion.targets +++ b/SharedProps/ScratchVersion.targets @@ -24,7 +24,14 @@ This file sets up version properties in our own Scratch way. --> - $(GitSemVerMajor).$(GitSemVerMinor).$(GitSemVerPatch) + + 1.0.0 + $(GitSemVerMajor).$(GitSemVerMinor).$(GitSemVerPatch) $(ScratchVersionTriplet)$(GitSemVerDashLabel) $(GitCommit) $(ScratchVersionFull)+$(ScratchVersionHash) diff --git a/scratch-link-win-msix/Images/LockScreenLogo.scale-200.png b/scratch-link-win-msix/Images/LockScreenLogo.scale-200.png index ff37a993b1e19e451cbc6b6599c06b4d33d5cc39..21ca7051ddb5fcf16e70f9bf417e1849406d36c9 100644 GIT binary patch literal 2561 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 diff --git a/scratch-link-win-msix/Images/SplashScreen.scale-200.png b/scratch-link-win-msix/Images/SplashScreen.scale-200.png index afc0fdd205980b57a4b215bbc4e36bd7682ba6c7..6b669f453d0607b73dd70dcdcfc6f2e45996f356 100644 GIT binary patch literal 182715 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

fqR)5kc@vdr-unNGNA>1 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

%^>dDYHn0 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 diff --git a/scratch-link-win-msix/Images/Square150x150Logo.scale-200.png b/scratch-link-win-msix/Images/Square150x150Logo.scale-200.png index 5f8efebb56f910aaa0327a1948f12bef1889080d..ee4d4ef45efb7b5d315a93f4b318849c37fb4b04 100644 GIT binary patch literal 51493 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 literal 12016 zcma)?WmFqY7^p*$26u`Sx8fQoS}5)g!QG)a6fY1c?yfB^0fIXecZX2CxEE+~3ccxf z&$;K^A6Ig+nVs34&CJfsJFh%Z>Z)?s7~~iL003J-URo0XKw|%Q0MQU7zJc*xhy=w} zQbiH~s7t{7V~&c*(^$%DssI3fOaQD6RA86Itzoub0a!Kzp_O;y6Ov*AU`GEPe%+>>hIs9 zm!gCfSXu6Dyb&0Zsd3NPNMYAsuheZ~s9H{T@~YCW&HMY)abQFS-Zm%R(&bWnT@51{ zxZUvBd^QB0M) zZh8tF{yvfh#+Vh)54=6Ua*^}5G@U1@#CS&zfDyA65n4VAaJucwBu#3*4=@j~m~bZ7 zD6xwn7{WycIK^=XR_z4l8y>C3y)HCp*r$$PDzdoQk^=zZr8OD__q)q0w0aJ27S7$z z%=s?+kiHR*#HdC;aV_C5E~B5vQXE`Q%u{hgGOz$O?_G^7Ce}QfC*!^6Ybpu2NB~B0 z2E*sgg@O6+9B_F*WuOD_Lo8=arupL8p^k#@sJZX}bOhst$)(Rld?OC4r@?a{K7vfh z0n+>ecE#7zH%x42Xv6mw1Q+#)X~X#iJ2r3r8|b430Dwg&%;Qb(7It>$&?#smV1jrP zWj`B5F;8W5qjXEmrg4M|l>r_xawj zu_IXfJxc_1S)(%}U4!fZS@1nisuz@K(@ zRQs>u;#4u10Khw@--PL0HpC<(06@?{P+?)v;-_#_fCQ5HVqNlLoBxIwraNNIX^&D& zDP=#_u1#Tq!2m$2S-|^K>wx2%fy|e%asc4Xyd|UGPiyv8f0J*8F92U)@z~8>oG0pe2wydU#hjDpPGKfbT$HX(IYt6w(V=w@p`chr-cW~JDk^j5X8%#d@35Hl~ z=7|3M&y$e3^`0HAwXQ{X z)<0P<3$myqe<#~mtOM{!zEIgdS`0#<2?LnKCUwni%Bh|$ks<2pq)`%Y8OHn!2HW@D zFJ-+dRjs7`z@`8QYAl)QoVWDtD`z4$^4lnq-~x60ybw!^{w<74&m)}6xOETMPXG{; zJEFik@C^z7Zj^U$4>#X~6w;-=R#d*lwitkh{YPvoD7gBfc`*_O6My3s&}dbaAHBW) z?}~>}M#KB!#wAP=2JY*X7ms_t*p{+tLO_`gCY{w5B(hR7JEwI%W5?~xaV0jGrFPSR3tPrh2!NXU$ zuUvXvUI5IOu@4?>4v(l7-SC))9=(L{3SQ8#i~JZ@I6tc9OiKSn7I(&>Q|^dF!(JsJ zcbAanMEp6P5|u(BqPAK$w?Gt=nikNv|&q{ipgiaFl zx{^-tMaVnXer7`f^l75IbCmx)0jzQl{u&CrBSpeXk2WB#m{Gus`hi_v+xrsz6D;%M zdi^}cnM22nL`E{|IuG^aLIcsJc!BKb4FOp6HVtmAlIFoqKZ*p{@-jQrsJBzzt~z8M z8PG?L9hBFh==t*HH#(-_zp2bWc0|LjLHB2yiNB-nbjOVFNPs7AgX(-r9!HMBpMfBT z7_;X`y2M|d7cL#9cY+&qXmGW;=Ub+&O~2X;{{n)L+#@>eCP_$w!A{#E{^6@vGCzjj z66C*G=Oj@fzf5bYQ~I%6-;z+q(z?#@-OP~s$X`^V&&2qM>Va(RM2b3m zBaf}1Z3ZZq2ad6Y;>H`xegH^Gh%l>FsBBvxpEVAUjQ|+4B6Z`*|2C(Bp8$P-$YFq2 z5?dczg}7y%xi4>VtV!Qfk>Uu_)KsGBH+ka?YHNQ-2)QQPUpQ-`MWUS7g1IVv1%hm2 zX1V{Qr0+ROy1ES9HsTO_uA`DHd?)iob}yE=@h- z?fjr*>}Q963AtVu!-O_)F(uE5-+cRNJNPZz5lZ`-L>ccZvSBL6d335l&Jnv)WGK@r5*7s#Oq|M`$hjBh$l=jE?9<6^gd*u$)k z0vz9h$PD*B?DmIxQsAr3zEwU*AN%)k@AHLX@j6fD2`YDdnO=0a(( zpww>gYd-Ti-lhTRzM5mAIC!aHIPiknO8UWmOIB$VvA_n)nce2-PlpAyf1T*_5@K5@4s~XX zKgGlXStq=iyg1LE(E6z6o9{KL;E!S<%$Hv)&)-<8mi7}NYSA&te=U3jF^X?>t}iw} z?&9D#dM54pMI|)U+`s&cL8(AjJjd+yK(Sb{U6)+_z~H8{L}!a>YFK@hEkJqVt&FsB z4UyqGH+%P&W?`n6$W{@XcQbWW?1ujr9{gsrzDA_YML4Q_YId&r)}cWyX+BYBVt2b* zkx^7uQ>yG^d|N)OMlTiT!AIO`3O)bU9)BdCDU^{q+U)4p&Kr|T!h|4PG%d}e>^X^7 z^YK4};9i>_Tl+v~d<;@|Qp>8=OF?H?MZKyxbS-~7Y-xexEQE4cXEoXN#0EH~B}uas zE1-JSx4jfMa+{l+?-z55DQQDdJ$AjpfpQ;#O7uEY;KkisN)mKoIr3?lzt3CS9Evr; zH7*ff`qy09J$5Jjs2Iek}#I z(qL~gT$+>7d8k)tD^SE#WO06~n+$KOVS=6)Pg%Nn!W~7{n8U2NjG98K?}b}~t4YEB zPuviY>B?}-^h^TRAz+XN0%|b{BGB@2mB>nY5!a9rr$!zl3Dym1UO8=N`>>h`S~@K1 z_|Evs7*w|Ij2c5S`t;W@X4yL~SJL4_86JGI(woAsS!y``SV{wW6z*(2xL1WhRbFD{DLmbu#FWScXsK~kv))+ zY*W99nWx=up0Vf9x2@aqd6n&>qwexNw=9-;kIw-QCuOIqvUw`xhHZ{-Ov8O+~`hL^-Nr%`EgKE6#^&7+C9hzO+geS+{ zI8xKui@uTTFxTu5V|c-sPY7(HuP`FOq|VM#xF9UVigI)em>$^o8_GyszmYNKO|nQ6 zmolrL>7sLPUNFqES}z43r(sV?ob^q-Mc!!1R2U5^0p9YH(T|5!&?R2`;LB&bzZRO8 zDfg{4=qv24eGSp+PQLEW7596}KHZCmWl)H}pe7q<7Xh|T*$}oED}Wa+l;4ZOW4W)V zMUQ^ee2!bpvuk{EMRnesZ$HW>=(G4Wuq|-WF^(EvG)2(2k<$w9ogL*_kZgf5=;&^sO@9(zlilRK2u1 z@`j(B+f}ExbG9jdw`b2}LqCbgRm)tiG<>{cx(N6-nf#*Lb>`Fb0}6iS#zaTaME=n4 zPA_!m?R88So3SL=(?V}`iREcc1zBvHEw;?t=M^-g`=*G|P!h~~3G`4>y^}{$dvZ8y zT7k=`cG|X%^gJjUiww$wZRKUK@!`Eha343Fo8cN7s3fxyy@90aH0!UUWSRs0-28lSba@wo%w42m7WI`llBTex>xim#qb z<@^);--gE;5Ktc31`tcAP}y_7XZLJG3t3Q}bPXM`{wmd>HFamQ@?H<0Wbt!sam4Qv z4}D{WejFuC#0ZR@bu!y7d>i)|=uvc6dPTaL+kf4&;Osi2-E8@*sw@k!9Dg&e3-E7u z_r=Xkt0e=c#NQE=jYpcA7WHu9Gj*WC>G0-%Rq?|bwWOG*GtvGSr{sIR{T3yv8x1=#2x;R5oQF!G|CsGs zds;b7C{Hmyox9c3*5XUbna<2-hnw@Gn?G;sPR+jN6L5%U)*9kewZs2J7#%hJ@T?w5 z%O#m?Yd|&+jG!*%u-Ic;A+F2Cb3man<{S5mar^b_5Ex+AUyG0@BQ2}WREIp*T-_XU ztZM$$p5^`PsiLi`mj(PdPOV?wi!BZ8FIDZTE+Y1FNwD{;ICp*2$1b%o!t`_dAq{gv zuLF&K2(gdYbWJi3&Xrf@jYuInuPw&I?GCX~#+tbG4*X9O`x1k5juTi6W5NsK6+9~o zPk>DN@;&Ly&(}@IJb_kY=lG|;#I;g@H^cRRBJD~sYAw-Hrld8GIp&Oi_j9o}X3!?Z zl;t;9VObqi0>5m|bhLVfQ-A*<&d)v0q-Dodrz`y0I1xRctmo?i+pY+j_D5M~@p{vT z-FU}cu}S~bs1g!Esg8JhI|p9V6O0nO`r}(?WyklGKKl0P2Mw~K=7S4X^+5~^ zs{QXtO2Ul- zgX+DYo4eIW=5FSyl(mGmG*2L^KH*$uIWTB74KIE3u~F2V=j_)DgWImvc+|?&g%LLvHS!25l4&>%G^ld<42fC!*2k0&RshFpDN~gk*bF zPi?A%k857i`R#$zjze7&x8{1 zODj~qRRT|1=S*r^5|z>Pfo#9A;Xaq8s8ZS)wlqxI8AxF1Ab2b~pr|Wl_ zah_x=7+s@A}Y>}K6jPn6XPk-U62L35?n?j8|J=YU5}v(N@G{$a+Xi- z_9^)TXU>e_&x_jy4;lV)E%2Z%U=1#tD{ zaiYE$WU%&O><^8JHQa3K&l7m=x6bw<5$#}Su4|~Pu?>6uHKMikom@nfh$rHeEE7N+_6YJ| z2TqEx+V*`^+j`(JJwcc~rKMl+)xffyfx8dK*;$_IdJ2!4M_mDqwOWb>VUwe~U3;7E zEurroReLEjR?I$oHHY{H@%P2-WLweG6LRU^4Fy!6%d4s|-=hIzkTMh<6m~uO011Mr z;*j^xC@JHNeXOoAvMeOri{V2Um760dd97JO9f=HLuRmiVp)YB%omL`t0)CxvkrA(N zo*fova)k1Kb1c!vBSj!iiD@yE`vha{E6LxIEyt#dk^|#%vSi&x9qOhU%tDh+fa4>v zf(=bzzjp=2wzp0a!C#1Bmp^2kjSFMxELvNZ%DCxkzzM8O?DZKS&X3w^NQ~X(uY|~mJZ}50C ztEF1@IB2wf70Uba-aSjmXb~eTstOoGqCRL#@UwEO>g+C`%tIv(tvceEKn7-)#3_X^ zfG53+iP@jPac{I3c#}_JIv0!d~P_)P8E}Hd(8mf&$|5PWjg(tw7|Iogenb8^Y z#h@e&BBPaP9U39xYNXa|Go%4bNJ-TIZ;2k0_xZu>QnDwBmr;k;zZLKjbKu#?wpJ@M zbJZYKtUblZS|S{1O6V~Ug1$axgTY*VWf^X>%=tN5?UWZx)>_<2>A?R4d3roE$GZ#q)k<2BjDxk4`BEcH#3k zJL;%PPMC1EUZyC5N^r={1Uh-ol&xEz`DGgC$b=tq>3?aKou!oV(HbHon-$jo>P*Kd z8l`RhS>}xbVbgkkv=o|-d%WTAr4<9XM8wBL&?lIxMBHww(NRLWJ+L3V3$VI-^|P{x zNx_Lt%RO7ZD`}0VYKoj*2q+i+K?b>xd@$AIgI7mhcKnm!`C^&cyemdvvpH<@_1tmg ztWN-Rx?!Ij|EG&(*L3VunBAnLW4s6OL~o^eVXD%bm=`H;V9sRr5%XG0R-vF;lE7PLYcJ7~j zSJ@;*WA740!}Gwkd_tg*E-cfKciTWm2jbehWFO8SC|xZHXd<~Z^fXT?FEXaTYDP&M zo5rhElf4z*2ccVaPAP6M*9?CT^H{0JD*wPlXoMDYo@w_(4)ytqbVxzKzWEP9jES1@ ztu(&f$?bV6oxI+h6L4Aj%DQFr6k8&nF(d(=5VW+sROxTDytw9K@?VCTQFR%!-y=HoL?pYnO><-Fo23mHX zs)Fl_no7`PMtj88Hd$MW#{E{aY4JM>KmqOYVT|A!YM(B*zSol6zVSEat0mu6>%Q$u zR`L_|O-NSqIW|auSwZx3kU?#|WSuGx_(W_+fw;504zMY22JgH0&3UrcM}N|Uw(&umcm;SznZMVTr0VfC9ql%B3uepN zXGCq6h;guYQ1;o33S`}5x3Mp+&d<_#b#<`Y1$d*H6MOxBR+-#3fITQ8mnEO;b4r&~ zOwXM(IP$8+B`~~-{rU^}L2`v|7C&*RSxmP+%~_ARD(asrOdA`%N2VkRE|Sz&W8*S+ z?u?RiWC(m{UUR<=pgG|{MiEJ|wblEDf8xLMV5U~)AgJkGes*HT(oAu=R(K~a)%!#+ zNBvx&J)eum& z9~^&@^gCR6m)f~`;`78ML`H4}3LzfmZuER&@YS#x4l=xY6CtuEd?mGbscdr22i{yo zxchH5;rwCZj^T2+4L?P##wnFDBgV(P z6QGh(_O?~A%(2vn=e+B#*$c}ZT4T+d62eB&4AHUcUj)O)i7o(fv-}D`0 zamPzDm!aX9Tm7LNI<`Sisb*#$^(G^y9C{BHIV1F-OQ!A-e ztEkFi;a*&X=Ds|#>l1#Lb?b8E>cTet7m{{~&4gA&7TZk$O(P_^`IARAs zD&86S7BZHF%8D%t+49wVUNPyk1{*rzm@L3Czmf2XjbiVU+MSJBnaN{c3>Nid`7B(y;9LP>;hY7?H3vO&?D zkibOmQL+3vbm2Hi0f~!vZ`x)qpv#0&uc4@hfNgZ_62j=%MVpt-(}quK?^zf3O#U?$DzI5f%}bgj>#l#Es6c0{{xo=uYY%N@ z4~%M*{@hv1X~o){a#V1t@OXBQFfv8r?l2bpv-o8jhJ*N?KOp=Yg%MDJ4e0qUR<(*2 zi7C0k+k)$^vqf*9Dl>b%Z#s6oIbqnxHceG-W#;5mrZCvhr`6xSwrk-I&3vF6UP?4b z*h)c@e9I?u`YOsEK4o3uV84QG!U}p&N_Or3q3u!w5%*+AnlJKZ;qiX))+?1ktj z2+O+@qSKW%D!hjbe=Ia7e&+Cr_w_dC{`;gc$<7e$*UcinMBy%!7S(gA=FYA^TO*^p zsM;$;8@WqSe?(L9R}yTA;!ER(row1L3+3HdS-H$PS<94!4qjXKOk$-QJO{k;B+kwR5Z&YuCrSqVaCKMZbG4edoIxk>hog zdY2kX{U$y_%gGlvHu|d+I6rAnu7eis`~vXUXJdWm(_=RPUK zkjO3tKY|#&KCQQjXJXI38&?D?58tF3WRn>9$&>{aCt>(dTV!1Yy#Jb47gVY?et8QM z4|2Q3mrEvYT38^vaHn_QO8qc{CAFMs)JY5(qDJMJiH4WhrFU;8`?h{Quj^!wzCz4&3xNTWB3n(X44E>%q){N_(xez;ubJlJ3w zq)N-t%3Byg{jc*ovBxe=3d{_{5dBsG|2C6>bZml@Xa2C3GrNl2Q%Q_=Q@nIz^cZ_t znq{C;5;F0C94()^tS;qa_`7Fs5L(FRx$oy0Lqj4elbk2f+@vnLW%V2VEt>nsWpS$2 zxWd`6jrtRulP|eh!R0(s1!3}`I#u-AElNxB6-WBH>?pO1g;cpuo|SHH$D(duYWrt? zTYFPkP?ud#g?JvFR9!s0Fs~zk`zu2j^$amV*0`5557hV{xC9F-(1c}ZeybRM=b}jC zOYBM{967EUZIB7+Mc?aM;f(YLA1z^jTx_{}bkcG1K{fBP|276!o=m!u_`Kg$hOaBm z+*kdmJo5Mb!_{60c8{(|F=)@1v87b&)GeoUSArrdT{++M7ao6t zkcEEz%@9T(MR_J~+j@QYwbAp3{b~gXW>(IF@FcWGO?*?CKVO~7=z-(%A%=USucI70 z7<}{?Z1%Jl!eCf9LHx#W_471(X!`r8jSfdIDTxQZ;X(u4mb7D*+Tb0IeU)u<-6mYL z8q_-YqJR16Gw{(ZpD7P{HjPY+h5H% zg!$d@oH*pvp3alTq!v3o0Zy&gg1ZeatMOyDN4@4xekrm%n(5s2TK*v{`F#gvlVtxE zC@lCZ)#*D{P8~DJKbFWQh9R!Y(y@kQi{5u^WNcM; zhmFQVCf{5*#hT%mRfBT6570c_cs+*JZ(#$GTyX)L&8{g}wL= z;H&e${-&MDCj}=tw2J-)#Y;CkQZmh^T5^PNmzd0IMVtXX6_5#Cg{O-Tv3?y`s(`j$ z7+0vqYCqXRpuSk&_%*~!uU9yzNpSdc4zplV_Oa*(+A4{ujZm8R-~0)(9yNXZv9GYAXRTK#eSJ1E=VK>~>X0uDYFFke zC;56r{sn{Fn-iY>ZAlB=GV$6SgdhC%Gt0Qu9>J`%%zU9oX^d-d4vbC|2U-nA5?)_* zFP@uOA!rlgA@;;J4`i_~ZS;x|wM1>?Ka3xtue?r?hMCo9mW3yUqABI>e6jRqwLY~T@xfCLt<&2)d3s@{aTM^C3ws-nal<1Ptgv~4dV9P)qD?!RVl zyVy20pyr3|Hl76;Ba^V-OWY>C>P0dy`!e(cVHbwRGF;?zf+A8+i5~q|Uz@W~@<3$D zPo4GVhjr`5ObEhMS|VLn^r7Yy!*d4!-2| z^jc;}u1bkiBMNaXx}gSk zR<;;8#-@tY>y0@7G*V$Q3^s=W?EC9`KV3nJan&6+41FPM?Tp2@?|jqC&(C=~hg7p; zDcvA42;@Q|v*RiT5sK$n)ek==Fp|JE+3a-XVDjG?Q13F%*72*v5^s;)oX32tKHrLUvMr1n%spEEl&HXk{&jbWam zr^vK+^n$EprqY-8pa68T0XT^-NCex$Ydq@933`kKvuf#8$2I@4l%mdAr98d$E#iS1 zAFp8lA_{mjZzS?Bcs14nr33h^xrEB0LGKZZYfjnvC5f)2ltj2l{NFI1VV zog*J{n;nx4Z7f~;97%D~nNu1mfFTH8COxoxE1wC!a-Ahq2Ga{$kLF&@ugB!u?S$K) z@6XsBXC65WWzYa0pIt^wFMcP@BaE1D0VJ?+_ zCke?_MzB8fm*7!dLK~tE5rd~di&IFL9j~bUHVBx3lDWIRSMLmK|33159n;-cmRksVJCP?%l7Ud zu{rAn$D-jvA{W)06^3rA5ISi9RIwk%IoBamSswTT4!#(aQeY;UAt24RiQ1D zkM6`XGJ<8IXMb_e*QQX`v}=ZB^N46}3js+8*0kNr?cGBhoJcwDKs11PTLBF1UrbF- zK$#gqW>LQ%K(Ix0F)$!Q^q)iZBzlZr9M9shqX;%CNf|8VXm~_O=by)AT5$IbSr4?8X4&o=swHemAZaxWBDVimI z%QPoUJ`frqda3Rvx`x0KA=Wrk*ON0oGPgt@X4Ed;r1@8~$_&75jzyRr4i4A|uDvs( zgbE@NX3i&Sy8kyzhxp(BMcTcgXFtO=iv7pxQChs>`3bYIwU9&ts5kfj^0in7ItCOX zz&=(0pptvzBx@{#;6aqjOapOU797PheOUsD;=%ndpH9GpfCAUd2mhe_L;dP0b?2_A z8}Q-(s6wSjss4W?ArVc0$=q6S+&0!3uJgA(1Uo1(r~Yb?(!ih<0~5g~`U@Y%==Z9D zqv{eY-H-rga)k%@-hI&C$Jd;&eWhPVJ+;ct2GZn+{@nD z1C50ZF;D(s+QkL{Tt~@LOTwhQ^;y7n0KgEAntSRo>G|)q=+$abj|D^jFxF%MUzm&(IRXaGGkmqwoK$k*Q;|1=-IW}Qs6nIv zGqzL&UTpF;N?#*#9@{bR+1WXX$q`)PEOK%Yh6K>ks0#Ecn7O-ii{j&YK~EOTb$<0H zM%E%jj@j=g<-zYx?u}Q!{TinUtM+Cw5rap0NKxn#)y?wIEFUDjNlyCm{|BIsx%-}S%Zeeb2b#$-W g|E+?viKNkl_*l|oyNCX%N`7kyjK|w+S0zwhW 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 O0000&QgwKS@&wiW^Iu(_kE`1mL(-}C88Yh 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 diff --git a/scratch-link-win-msix/Images/StoreLogo.png b/scratch-link-win-msix/Images/StoreLogo.png index d14b26275423214151efe5e83041a9eb4ddfca45..36df575dbd4ce1a69b83f8290acabc1e762cb348 100644 GIT binary patch delta 2769 zcmV;?3NH1T57-ruBYz5?Nkl(&d`zyI-n<-ifHUj;o|>H`TK8QvyHKi2aCt%#~U~Q?E1xj{WW*L|3E|p zcjxG%=f8a9>{Bo8Yz)VrzYzL={M9dTd|?$*3pR%O27iM3cy6xW zfA6*LoZDHu`qut??)DW9^RTLN{M=K2(T3hbdA+KC`uivK(Gxq2?HuGssmAM6>))lm z^#dL{o%6AkNBPFTtf#Cj5%KZv`t^UhS4gGv` z1!MZ|*MAA^4YDW@0_nYr{LI+_r$C5Hr13taYdt=jGfZpx`ZM9}-Z*y+*6+ z#8`glbwZGaGILx6g7!pIK8k#O^rf}`a8W*HZhwT}96ORhwMx5riP-KTQedw5EbT;F ztg1;VAb^Os?=zO)A0U34dW$p3jWTQX*rGzaitY~4&~&qo%%b9`ICTxvT2NKoeb?|`?N<%z{!3nm0ji0qS}fwUkEh*PyWRTE5u;FdPb(mhl7co=6AvixCd zjemY2S{5z1B2psK0*2r?O{WtIfe5=3qqS%mLTa1U2O=V> zAxH@GG)9ptn&o(1bj!*eG{bT5go}bY+oPJ60#Qh9y?QSzlX$>@fU1gW6l=(Ws|3Mg z3FP2i9U=(s4eAX9VN@{_L%~xsd|)D?DDGH{D4GHDvsV}{ErNr1=L<1)-5LE?m%YrBxAY>i!xgr*3&ZEK=(1P7syF9}2)Jz_Th@cu>1P7uxpg0*w zoJFB4njEEzR>ov9Mcfq=+^l*qfFO#4JEj0CAd0wlYNQ6zq|6# z<85zY<$2A^^U1(1kQ_9^%75uVGugeke(67--+u4i%ZCLM4_Y3kwoRVWR#07;R7N#1 z%6=z?(ADMQj=NxPfO2G@h?^qNTR!#MLS$MsRNEudX1gx6VPUb<+M?}l=Je(kK6UcR z&%EPqkM68pyK)#X@t}pSrN&az+>ltTjA~(T5?Sm63A{5}GkOL!#eeq3{OmKQSo-U? z7~X8jq^ai$=ZUj}`0Rxx{oJR|m8Vb4u{cob2EO+7xB06V*6M}Dm3Zvj)2~dnho_rr zlJ5G_vbJ?^rfK5Pl+NXKv>XhZBB0qIh zIdKf~vVnFN+6|g&4}Z}O{_r=SVX`~P|L$8`)5W7lPcA?7@h`8v{k<0t+L=6XgU;P) z>+1D#F?)VA5?kMBIDh7YEM&K7)XY(Z`sT}=Uw)JGKRpL#SliO9HjJA+tQnyyXpE$$ zMy4D5&aZxsm;d{Fai?i*e&ytEtzUla#e+8V;=z0H(A0acm4CsRSZ+7g0TY}A-pQZ< zX=X`~fGSKjZ(?SM3M!!D1QJmKZUS{nrh#hvT^>Gml?xy5#cy65vp87zV&0p}tG(U& zAh~j=23&?>L4=CFX$`1F8xd5Ml?y1YGcB2#HW% z=HyaCYEvyCi+@?sUp#0#?@$f8dc1p?POOBb;=l3Jlnf+ZoDV6Efss3=f!^LoMBc0>Z&kwZN`sN2-TZb6TS zYkwZa88yB3m8%1`ww74E3NiKwK|5lwj+QMsmJI0-c6J3v)e!~NoYeN&xYgs@n>kl* z4tRSlvwu8fv2ChxGac_9)Hfg8qRj5Q!|VUN^2ifyIX4&o@%3H4`1pWNw3}SoO&mL( z)9)oh1QnYVTl?w)W#FVb=eOpUjz70s+xXJ;Y4-TZoFn~=t$$%+_@1*d6t=g7tu5Ht6xN3@yd@0R zg+&Q?Y>DM07&Y>BI*1^)7tg1>!r-n{5fvn(%%Z@>EdbhNc82i)Phqm7CzFZHpf zzx40YA3QytPR1)?xBuKH6Q4ahRGMjnU6}uAF`qsPn~<}_j*T9eN|#c-57O~NPkUjsjXWlp(qjp8bt9BLk#3G5JN;&NU5P7 zZ~xbHxc*05YghheGTNH__>ORVsFIssKEAwo{PZv6gXLd|y}6$cu~-oiOof1S#?o6- zN?2Q8wYqw}o$kCm-5Y&-vORotyt6S(?d){K9ae~Px6jyQMK8p>*9&>k7Y&8rSV~G& zYU^ogn<_PRlbYK8kE7jB>N~94iLKqRw&MhwFa< XOh=TrrMc+h00000NkvXXu0mjfr3#Aj delta 1932 zcmV;72Xpw?6`2o^BYyw{XF*Lt006O%3;baP0000WV@Og>004R>004l5008;`004mK z004C`008P>0026e000+ooVrmw00009a7bBm0000;0000;07l7cJ^%m!2XskIMF-~s z0unne=$en100006VoOIv00000008+zyMF)x28c;SK~!ko-G5qnY*a-UNB{CKi$UWR zO+2C|8vH{{REP*t4B!EnAPQ=LC?H~#LrFX+5|y;O94)p6JZeGdN$CNlu)8g-y}R9( zmeQ8q^rjc3-FDyZ+s~PK+c|dMF1y=mc9~?7zOOU$zTf+<-^|X88Mk!H3A-aiAHFz5 zuh|r$kN7GuI)BzBd@N9nk?J6-5(C*~c&4ie_)1Y}R2tg=arwL_lrPFQQTcB@cIPaRC4j}}_~HGo?? zByLDN*eqc0t7KqvJ`;f4hq95U+H?cW??yrX7-zZI&MGo@nH#Hk1w=p4qUu)Gf^Ue- zR)2X|c`o^Zjq5IE?| zgWHQGvHk(+MK7mmw_L-%{*@F3NXFYNu+!dDY77EN0aqNP^IOfss#y_#tj>uMxZALw z$S^lEBkP^(Z>HncUQ8ovY~TR<1fRT+e6pXC(n*($-l-k)GkMQ%WWw4G;)6@RbDu78|#C5nkJ z6IZkMnb>&4rveb3&8nr})hg*XYAWd$Z(%7AjtJ7)U>yS~d!1+z#Ecb?DNI%rM%Nj2 zDvHZZNv;KPxPx%6X)B0$|3HDDn4pRwmtw`mOsYHvKxzx#w;&l`DCOo1Ivg_vPZR}P zhESAtqd**SJKk08A4Qp@(0>Y$3>P4B4>GqbiJQjpe&R~hN~udJL&oiZO4i{?BevMI zlSUDUt3@yL(5vjWukzMQ1& zb8L0p(RZ(bta0RSHTElHD&%6=wQRM=$fgRMj*M`H=8K&#hY$5ATRq@mGv*Z#T(~;M zN4Q9~f$h>CXm|Lk0wQHGc?J(>T{vZ~M0*Zj58Wn@gJw_HaS*Pkc4zHSro!i00>^Sb z@b6vXXc z%@Ti$9Y!jI0000bbVXQnWMOn=I%9HWVRU5xGB7eTEif`IFfvpzI65^sIy5#bFfckW zFl!`ca{vGUC3HntbYx+4WjbwdWNBu305UK#Gc7POEif`vF*rIkIXW~pD=;uRFfbZ< S-p>F4002ovP6b4+LSTZ!?R{MU diff --git a/scratch-link-win-msix/Images/Wide310x150Logo.scale-200.png b/scratch-link-win-msix/Images/Wide310x150Logo.scale-200.png index 1530f6bddc1d1ecd1ca2832be59f8e3abc4a6617..54f760d126bed6e129f0e9aab3ce3b0a9e72451a 100644 GIT binary patch literal 54467 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 z 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 kwr!^a3)BDG)%TYHBbI@*YA|;h;)`z$Ld20Q{k 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 diff --git a/scratch-link-win-msix/Package.appxmanifest b/scratch-link-win-msix/Package.appxmanifest index 97d9a55a..72092f3a 100644 --- a/scratch-link-win-msix/Package.appxmanifest +++ b/scratch-link-win-msix/Package.appxmanifest @@ -9,11 +9,11 @@ + Version="1.0.0.0" /> - Scratch Link - Scratch Foundation + Alux Scratch Link + Alux (based on Scratch Foundation) Images\StoreLogo.png @@ -31,8 +31,8 @@ Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$"> diff --git a/scratch-link-win/TrayIcon.xaml b/scratch-link-win/TrayIcon.xaml index ecce2afa..40fdf892 100644 --- a/scratch-link-win/TrayIcon.xaml +++ b/scratch-link-win/TrayIcon.xaml @@ -9,7 +9,7 @@ diff --git a/scratch-link-win/app.manifest b/scratch-link-win/app.manifest index e0412302..285545f7 100644 --- a/scratch-link-win/app.manifest +++ b/scratch-link-win/app.manifest @@ -1,6 +1,6 @@ - + diff --git a/scratch-link-win/scratch-link-tray.ico b/scratch-link-win/scratch-link-tray.ico index b53e3878b7c02f76a83d8ca4a56db07ee63ddb39..508024d5e145b0d9c8ea95d7cf44e25b5fec75f4 100644 GIT binary patch literal 3255 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 HfBpI!78I0s diff --git a/scratch-link-win/scratch-link-win.csproj b/scratch-link-win/scratch-link-win.csproj index f364bab5..5eab41be 100644 --- a/scratch-link-win/scratch-link-win.csproj +++ b/scratch-link-win/scratch-link-win.csproj @@ -5,8 +5,8 @@ win10-x86;win10-x64;win10-arm64 10.0.17763.0 ScratchLink.Win - Scratch Link - Scratch Foundation + Alux Scratch Link + Alux (based on Scratch Foundation) $(Company) disable true diff --git a/scratch-link-win/scratch-link.ico b/scratch-link-win/scratch-link.ico index 42da3aceb737795778d5d7e3c5a285339ea7b1a2..5d9a2704b93c6caffe3e92ee28ff2f5cd088946f 100644 GIT binary patch literal 73875 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 E55!qLx&QzG From 2fd2f75e7c6c335701da16e5e361948aad531696 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 May 2026 14:17:48 +0900 Subject: [PATCH 04/94] docs: remove relocated Serial transport docs SerialTransport.md and scratch-link-fork-plan.md moved to a sibling documents/ folder outside this repo so the fork's design notes can be edited alongside the related client-side work without churning this tree. Co-Authored-By: Claude Opus 4.7 (1M context) --- Documentation/SerialTransport.md | 322 ------------------------ Documentation/scratch-link-fork-plan.md | 272 -------------------- 2 files changed, 594 deletions(-) delete mode 100644 Documentation/SerialTransport.md delete mode 100644 Documentation/scratch-link-fork-plan.md diff --git a/Documentation/SerialTransport.md b/Documentation/SerialTransport.md deleted file mode 100644 index cf92da61..00000000 --- a/Documentation/SerialTransport.md +++ /dev/null @@ -1,322 +0,0 @@ -# Serial Transport 설계 문서 - -본 문서는 scratch-link 의 fork (aluxcoding 배포본) 에 **USB Serial 트랜스포트**를 추가하기 위한 설계를 기술한다. 기존 BLE / BT(Classic) 트랜스포트는 변경하지 않고, 동일한 패턴으로 새 세션 타입을 추가하는 형태이다. - -1차 타겟 칩셋은 **CH340 (VID `0x1A86`, PID `0x7523`)**, 기본 보드레이트 1,000,000 bps. OS 는 Windows 만 고려한다. 후속으로 CP210x / FTDI / CH341 등을 동일 트랜스포트 위에 얹는 것을 염두에 둔다. - -연결 상대 Scratch 는 `../aluxcoding-scratch` 모노레포의 `scratch-link-client` 라이브러리를 사용하며, 본 문서가 단일 출처(SoT)가 된다. 클라이언트 측은 본 문서의 포트/경로/메서드 명세에 맞춰 정렬되어야 한다. - -## 결정 사항 요약 - -| 항목 | 결정 | -| --- | --- | -| WebSocket URL | `ws://localhost:20111/scratch/serial` (기존 포트/평문 유지) | -| TLS | 사용하지 않음 (loopback) | -| 프로토콜 | JSON-RPC 2.0. **수신 / 분리 알림은 Serial 전용 명명** (`serialDid...`) 으로 BT/BLE 와 코드상 구분. 요청 메서드(`discover`/`connect`/`write`)는 일반 동사라 공통 사용 | -| Serial API | `System.IO.Ports.SerialPort` (저사양 안정성 우선) | -| VID/PID 열거 | WMI (`Win32_PnPEntity`) | -| 1차 칩셋 | CH340 `VID_1A86 & PID_7523`, baud 1,000,000 | -| OS | Windows (`scratch-link-win`) 만 | - -### `System.IO.Ports.SerialPort` 채택 근거 - -`Windows.Devices.SerialCommunication.SerialDevice` (WinRT) 는 비동기 I/O 효율과 capability 모델 정합성에서 우월하지만, 일부 구형 / 저사양 PC 에서 `DeviceWatcher` 이벤트 누락과 WinRT 초기화 오버헤드가 보고된다. 본 fork 의 배포 대상이 저사양 교육용 PC 를 포함하므로, 동작이 단순하고 디버깅이 용이한 `System.IO.Ports.SerialPort` 를 1차 채택한다. `SerialPort` 의 알려진 단점인 USB surprise removal 시 hang 은 [§ 5.3](#53-분리surprise-removal-감지)의 이중 방어로 보완한다. 미래에 WinRT API 로 전환할 수 있도록 추상화 인터페이스([§ 3.1](#31-serialsessiontport-common-추상))는 API 중립으로 설계한다. - -## 1. 클라이언트 정합성 가정 - -`scratch-link-client` 라이브러리가 본 문서의 명세에 맞춰지도록, 다음 항목이 클라이언트 측에서 정렬되어야 한다 (참고용 — 클라이언트 작업 항목). - -- WebSocket 엔드포인트: `ws://localhost:20111/scratch/serial` -- 요청 메서드: `getVersion`, `discover`, `connect`, `write`, `disconnect`, `startReading`, `stopReading` -- 서버→클라 알림: `didDiscoverPeripheral`, `serialDidReceiveData`, `serialDidDisconnect` -- 페이로드 바이너리 인코딩: base64 - -## 2. 변경 지점 개요 - -| 위치 | 변경 | -| --- | --- | -| `scratch-link-common/Serial/SerialSession.cs` | **신규** 크로스플랫폼 추상 세션 | -| `scratch-link-common/Serial/DiscoveredSerialPort.cs` | **신규** 발견 결과 DTO | -| `scratch-link-common/Serial/SerialDiscoveryFilter.cs` | **신규** discover 파라미터 모델 | -| `scratch-link-win/Serial/WinSerialSession.cs` | **신규** Windows 구현 | -| `scratch-link-win/Serial/WinSerialPortEnumerator.cs` | **신규** WMI 기반 포트 열거 | -| `scratch-link-win/WinSessionManager.cs` | `/scratch/serial` 라우팅 추가 | -| `scratch-link-common/scratch-link-common.projitems` | 신규 .cs 파일 등록 | -| `scratch-link-win/scratch-link-win.csproj` | `System.Management` NuGet 의존성 추가 | -| `scratch-link-win-msix/Package.appxmanifest` | `serialcommunication` capability + VID/PID 항목 | -| `Documentation/NetworkProtocol.md` | Serial 섹션 추가 (별도 PR 가능) | - -기존 BLE / BT 코드는 건드리지 않는다. - -## 3. 클래스 구조 - -``` -Session ← scratch-link-common/Session.cs (그대로) -└─ PeripheralSession ← 그대로 - ├─ BLESession<…> (기존) - ├─ BTSession<…> (기존) - └─ SerialSession ★ 신규 (common, 추상) - └─ WinSerialSession ★ 신규 (windows, 구체 구현) -``` - -### 3.1 `SerialSession` (common, 추상) - -책임: - -- JSON-RPC 핸들러 등록 (`getVersion`, `discover`, `connect`, `write`, `disconnect`, `startReading`, `stopReading`) -- 발견 결과 캐시 및 연결 상태 머신 관리 -- 쓰기 데이터 base64 디코드, 수신 알림 base64 인코드 -- 수신 응집(coalesce) 윈도우 적용 후 알림 발사 - -추상 멤버 (플랫폼 구현이 채움): - -```csharp -protected abstract Task> EnumeratePortsAsync( - SerialDiscoveryFilter filter, CancellationToken ct); - -protected abstract Task ConnectAsync(TPort port, SerialOpenParams open, CancellationToken ct); - -protected abstract Task WriteAsync(byte[] data, CancellationToken ct); - -protected abstract Task DisconnectAsync(); - -// 수신 루프에서 발사. SerialSession 이 base64 인코딩 후 클라이언트로 알림 전송. -protected event Action DataReceived; -``` - -### 3.2 `WinSerialSession : SerialSession` - -- `EnumeratePortsAsync` → `WinSerialPortEnumerator.QueryAsync(filter)` 호출 ([§ 5.1](#51-포트-열거--vidpid-필터링)) -- `ConnectAsync` → `System.IO.Ports.SerialPort` 인스턴스 생성·구성·`Open()` -- `WriteAsync` → `BaseStream.WriteAsync` -- 수신 루프 → 백그라운드 `Task` + `BaseStream.ReadAsync` + `CancellationToken` ([§ 5.2](#52-수신-루프-패턴)) -- 분리 감지 → IOException 캐치 + WMI `__InstanceDeletionEvent` 백업 ([§ 5.3](#53-분리surprise-removal-감지)) - -## 4. JSON-RPC 프로토콜 (`/scratch/serial`) - -기존 BLE 메서드명을 그대로 차용해 클라이언트 라이브러리의 트랜스포트 어댑터가 BLE/Serial 분기를 최소화하도록 한다. - -### 4.1 `discover` (요청) - -```json -{ - "jsonrpc": "2.0", "id": 1, "method": "discover", - "params": { - "filters": [ - { "usbVendorId": 6790, "usbProductId": 29987 } - ] - } -} -``` - -- 응답은 즉시 (`{}`). 발견된 디바이스는 `didDiscoverPeripheral` 알림으로 push. -- `usbVendorId` / `usbProductId` 는 10진수 정수. -- 필터가 비어 있으면 모든 USB Serial 디바이스를 반환. - -### 4.2 `didDiscoverPeripheral` (서버→클라 알림) - -```json -{ - "jsonrpc": "2.0", "method": "didDiscoverPeripheral", - "params": { - "peripheralId": "COM7", - "name": "USB-SERIAL CH340 (COM7)", - "vendorId": "0x1A86", - "productId": "0x7523", - "rssi": 0 - } -} -``` - -- `peripheralId` 는 COM 포트명을 그대로 사용 → `connect` 시 동일 값으로 전달받음. -- `rssi` 는 BLE 와의 메시지 호환을 위해 항상 0 으로 채움. - -### 4.3 `connect` (요청) - -```json -{ - "jsonrpc": "2.0", "id": 2, "method": "connect", - "params": { - "peripheralId": "COM7", - "baudRate": 1000000, - "dataBits": 8, - "parity": "none", - "stopBits": "one", - "flowControl": "none" - } -} -``` - -- `baudRate` 외 파라미터는 모두 선택. 기본값: `dataBits=8`, `parity="none"`, `stopBits="one"`, `flowControl="none"`. -- 연결 성공 시 수신 알림이 자동으로 활성화된다. 명시적 토글이 필요하면 `startReading` / `stopReading` 메서드 사용 (BLE 의 `startNotifications` 와 별개의 Serial 전용 명명). - -### 4.4 `write` (요청) - -```json -{ - "jsonrpc": "2.0", "id": 3, "method": "write", - "params": { "message": "", "encoding": "base64" } -} -``` - -응답: 송신된 바이트 수 (정수). - -### 4.5 `serialDidReceiveData` (수신 알림) - -Serial 전용 명명. BLE 의 `characteristicDidChange` / BT 의 `didReceiveMessage` 와 명확히 구분하기 위해 별도 명명을 쓴다 — 클라이언트 코드에서 BT/BLE 와 혼동 없이 즉시 식별 가능. - -```json -{ - "jsonrpc": "2.0", "method": "serialDidReceiveData", - "params": { "message": "", "encoding": "base64" } -} -``` - -### 4.6 분리 / 오류 - -- `serialDidDisconnect` 알림 — Serial 전용 명명. BLE/BT 의 `peripheralDidDisconnect` 와 구분. - - ```json - { - "jsonrpc": "2.0", "method": "serialDidDisconnect", - "params": { "reason": "device", "message": "USB device removed" } - } - ``` - - - `reason`: `"user"` | `"device"` | `"error"` | `"shutdown"` (선택 필드, 없으면 `"error"` 로 해석). - - `message`: 사람이 읽을 수 있는 보조 메시지 (선택). -- 표준 JSON-RPC 2.0 error 응답 (코드/메시지). - -## 5. Windows 구현 세부 - -### 5.1 포트 열거 + VID/PID 필터링 - -`System.IO.Ports.SerialPort.GetPortNames()` 만으로는 VID/PID 를 얻을 수 없으므로 **WMI** 로 보완한다. - -```sql -SELECT DeviceID, PNPDeviceID, Caption -FROM Win32_PnPEntity -WHERE PNPClass = 'Ports' AND PNPDeviceID LIKE 'USB%' -``` - -- `PNPDeviceID` 예: `USB\VID_1A86&PID_7523\6&1A2B3C4D&0&5` -- 정규식 `VID_([0-9A-F]{4})&PID_([0-9A-F]{4})` 로 VID/PID 추출. -- `Caption` 끝의 `(COMx)` 에서 COM 번호 캡쳐. - -필터 매칭에 성공한 항목을 [§ 4.2](#42-diddiscoverperipheral-서버클라-알림) 형식으로 1건씩 알림 발사. - -> `.NET 6` 에서는 `System.Management` 가 NuGet 패키지로 분리되어 있으므로 `scratch-link-win.csproj` 에 다음을 추가한다: -> -> ```xml -> -> ``` - -### 5.2 수신 루프 패턴 - -```csharp -_rxCts = new CancellationTokenSource(); -_rxLoop = Task.Run(async () => -{ - var buf = new byte[4096]; - try - { - while (!_rxCts.IsCancellationRequested) - { - int n = await _port.BaseStream.ReadAsync(buf, 0, buf.Length, _rxCts.Token); - if (n > 0) - { - RaiseDataReceived(new ReadOnlySpan(buf, 0, n).ToArray()); - } - } - } - catch (OperationCanceledException) { /* 정상 종료 */ } - catch (IOException) { OnSurpriseRemoval(); } -}); -``` - -- `SerialPort.DataReceived` 이벤트는 **사용하지 않는다.** 콜백이 ThreadPool 에서 호출되며 OS 버퍼링이 비결정적이라 1Mbps 환경에서 드롭 사례가 보고된다. -- `ReadTimeout` / `WriteTimeout` 은 무한 (`InfiniteTimeout`) 으로 두고 취소는 `CancellationToken` 으로 제어한다. -- 수신 직후 즉시 알림을 발사하면 메시지 폭주가 가능 → 1\~5 ms 의 **응집 윈도우** 를 두고 모은 바이트를 한 번에 알림으로 전송. 기본값은 1 ms 로 시작해 실제 디바이스로 측정 후 조정. - -### 5.3 분리(Surprise Removal) 감지 - -`SerialPort` 는 USB 분리 시 `ReadAsync` 가 즉시 예외를 던지지 않고 hang 하는 사례가 있어 이중 방어한다. - -1. **WMI 이벤트** 구독: - - ```sql - SELECT * FROM __InstanceDeletionEvent WITHIN 2 - WHERE TargetInstance ISA 'Win32_PnPEntity' - ``` - - 이벤트의 `TargetInstance.PNPDeviceID` 가 현재 연결된 디바이스와 일치하면 `_rxCts.Cancel()` + `_port.Dispose()` + `serialDidDisconnect` 알림 (`reason: "device"`). -2. `ReadAsync` 캐치블록의 `IOException` / `OperationCanceledException` 처리에서도 동일 정리 경로를 호출. WMI 가 누락되어도 자가 복구되도록 한다. - -### 5.4 MSIX manifest - -`scratch-link-win-msix/Package.appxmanifest` 의 `` 에 추가: - -```xml - - - - - - - -``` - -> 본 구현은 `System.IO.Ports.SerialPort` 를 사용하므로 WinRT capability 가 엄격히 필수는 아니다. 그러나 (a) 미래의 WinRT API 전환 여지와 (b) MSIX 사용자에게 명시적 권한 동의를 받기 위해 등록을 권장한다. - -후속 칩셋(CP210x, FTDI 등)을 지원할 때는 `` 항목만 추가하면 된다. - -### 5.5 라우팅 - -`scratch-link-win/WinSessionManager.cs` 의 `MakeNewSession` switch 에 한 줄 추가: - -```csharp -case "/scratch/serial": - return new WinSerialSession(webSocket); -``` - -## 6. 시퀀스 (CH340 예) - -```mermaid -sequenceDiagram - autonumber - participant GUI as Scratch GUI - participant Link as scratch-link - participant Port as CH340 (COM7) - - GUI->>Link: ws://localhost:20111/scratch/serial - GUI->>Link: discover { filters:[{usbVendorId:0x1A86, usbProductId:0x7523}] } - Link-->>GUI: { } (ok) - Link->>GUI: didDiscoverPeripheral { peripheralId:"COM7", vendorId:"0x1A86", ... } - GUI->>Link: connect { peripheralId:"COM7", baudRate:1000000 } - Link->>Port: SerialPort.Open() - Link-->>GUI: { } (ok) - - GUI->>Link: write { message:"" } - Link->>Port: BaseStream.WriteAsync - Link-->>GUI: { sentBytes: N } - - Port-->>Link: (bytes available) - Link->>GUI: serialDidReceiveData { message:"" } - - Note over Port: USB 분리 - Link->>GUI: serialDidDisconnect { reason:"device" } -``` - -## 7. 식별 / 브랜딩 점검 (배포 전) - -- `scratch-link-win-msix/Package.appxmanifest` 의 `Identity Name`, `PublisherDisplayName`, 트레이 아이콘 리소스, 자동 시작 `StartupTask` ID 를 aluxcoding 배포본 브랜드로 교체. -- 라이센스: 본 fork 의 베이스는 `develop` 브랜치 머지된 **AGPL-3.0-only** (커밋 `18ee302`). 자체 배포 시 AGPL 의무 (소스 공개) 가 발생하므로 배포 정책 사전 확인 필요. - -## 8. 미해결 / 후속 결정 사항 - -1. **수신 응집 윈도우 기본값**: 1 ms vs 5 ms. 실제 디바이스에서 측정 후 결정. -2. **다중 동시 연결**: 한 세션당 단일 포트 (BLE 패턴과 동일). 다중이 필요해지면 별도 세션을 여는 방식으로 운영. -3. **타 칩셋 추가**: CH341 / CP210x / FTDI 는 동일 `SerialSession` 을 그대로 쓰고 manifest 의 VID/PID 항목과 `discover.filters` 호출만 다르게. -4. **로깅**: 기존 scratch-link 의 로깅 채널에 `SerialSession` 로그를 동일 레벨로 통합. -5. **테스트 디바이스 확보**: CH340 보드 1대 + 분리/재삽입 + 1Mbps 연속 송수신 테스트. -6. **클라이언트 라이브러리 정렬 PR**: `aluxcoding-scratch` 의 `scratch-link-client` 가 본 문서 § 1 의 명세대로 변경되어야 함. diff --git a/Documentation/scratch-link-fork-plan.md b/Documentation/scratch-link-fork-plan.md deleted file mode 100644 index f5816646..00000000 --- a/Documentation/scratch-link-fork-plan.md +++ /dev/null @@ -1,272 +0,0 @@ -# Scratch Link fork + Serial extension — 작업 계획 - -작성: 2026-05-22 -대상 브랜치: `feature/scratch-link-websocket` -관련 코드: [libs/scratch-link-client/](../libs/scratch-link-client/), [libs/virtual-machine/src/io/web-socket-link.ts](../libs/virtual-machine/src/io/web-socket-link.ts), [libs/virtual-machine/src/blocks/extensions/codetinker/codetinker-peripheral.ts](../libs/virtual-machine/src/blocks/extensions/codetinker/codetinker-peripheral.ts) - -이 문서는 Link transport 전략 전환 (자체 link 폐기 → 원본 Scratch Link fork) 의 **본 저장소 측 작업 계획** 과 -**fork 가 노출해야 할 WebSocket 프로토콜 경계** 를 정의한다. - -fork 내부 (C# 구현, 시리얼 드라이버, 세션 매니저, 인증서 흐름 등) 는 별도 저장소에서 작업하며 본 문서의 범위가 아니다. -fork 작업은 본 문서가 정의한 **WebSocket-level 계약** 만 충족하면 된다. - ---- - -## 1. 배경 - -### 1.1 전략 전환 - -- **변경 전**: 자체 link 프로그램 `aluxcoding-scratch-link` 신규 개발. - - 자체 RPC: `listSerialPorts` / `openSerial` / `closeSerial` / `write` + `sessionId` 모델. - - 엔드포인트 `wss://localhost:28347`. - - 본 저장소의 [libs/scratch-link-client/](../libs/scratch-link-client/) 와 [io/web-socket-link.ts](../libs/virtual-machine/src/io/web-socket-link.ts) 는 이 RPC 에 맞춰져 있음. -- **변경 후**: 원본 Scratch Link git 을 fork 해서 거기에 **Serial extension** 을 BLE/BT 와 동형으로 추가. - - 클라이언트는 원본 Scratch Link 프로토콜 패턴 (`discover` → `didDiscoverPeripheral` → `connect` → `write` / `startNotifications`) 을 그대로 따름. - - 원본의 세션/세팅 흐름 재활용 (loopback `ws://localhost:20111`, JSON-RPC 2.0). 1.3 시대의 wss/인증서/device-manager DNS 는 2.x 에서 폐기되어 본 작업에서도 사용하지 않는다. - -### 1.2 왜 fork 인가 - -- 자체 link 신규 개발 시간 + 배포 문제. -- 원본 scratch-link 는 이미 검증된 세션 처리 + 다중 클라이언트 정책을 갖춤. -- BLE/BT 와 동일한 호출 패턴을 따르면 클라이언트 측 추상화가 단순해진다 (peripheral 추상화의 BLE/BT/Serial 모드 분기). -- loopback `ws://` 모델이라 인증서 발급/배포 문제도 자연 소거된다. - ---- - -## 2. 책임 경계 - -이 작업은 두 저장소에 걸쳐 진행된다. 본 문서는 **본 저장소 (aluxcoding-scratch)** 의 작업과 -**두 저장소 사이의 WebSocket 계약** 만 다룬다. - -| 영역 | 책임 저장소 | 본 문서가 다루는가 | -|---|---|---| -| WebSocket 엔드포인트 (loopback `ws://`) | fork (별도) | ✗ (요구사항만 명시) | -| JSON-RPC 메시지 schema (메서드명, 파라미터, 결과) | 양쪽 공유 (계약) | ✓ §4 | -| Serial 드라이버, COM 포트 열거, 세션 관리 | fork (별도) | ✗ | -| 페이로드 인코딩 (base64 byte 처리) | 양쪽 공유 (계약) | ✓ §4 | -| 클라이언트 (브라우저) JSON-RPC 처리, 재연결, 메시지 라우팅 | 본 저장소 | ✓ §5 | -| IO 어댑터 (`web-socket-link.ts`) | 본 저장소 | ✓ §5 | -| codetinker peripheral 의 Link 분기 (`_isLinkMode`, `_scanLink`, lifecycle override) | 본 저장소 | ✓ §6 | -| 다른 peripheral 의 Link 통합 | 본 저장소 (후속) | △ §8 | - ---- - -## 3. 전체 로드맵 - -### Phase 0 — 폐기 대상 정리 (사전 작업, 진행 중) - -- [x] 자체 link 전제로 작성된 문서 제거 (`scratch-link-protocol.md`, `scratch-link-codetinker-verification.md`). -- [ ] 본 문서 (`scratch-link-fork-plan.md`) 확정. - -### Phase 1 — Serial RPC 계약 확정 - -- [ ] §4 의 RPC 메서드/notification 명세를 fork 측 담당자와 정합 (특히 메서드명, peripheral 식별자 형식). -- [ ] 엔드포인트 / 인증서 / 포트 정책 확정 (원본 scratch-link 와 동일 vs 변경 — §4.1 참조). -- [ ] §4 본문 갱신 + fork 저장소 README 에 동일 명세 미러링. - -### Phase 2 — `scratch-link-client` 재작성 - -기존 self-link 호환 코드의 protocol/messages, capability probe, client 의 RPC layer 를 새 계약에 맞춰 재작성. -재사용 가능한 layer: - -- [transport.ts](../libs/scratch-link-client/src/transport.ts) (WebSocket + 재연결 + state machine) — **재사용**. URL/포트만 교체. -- [codec.ts](../libs/scratch-link-client/src/protocol/codec.ts) (JSON encode/decode, base64) — **재사용**. base64 라이브러리만 유지. -- [client.ts](../libs/scratch-link-client/src/client.ts) — **부분 재사용**. JSON-RPC request/response 패턴은 유지, notification 라우팅과 메서드 enum 만 교체. -- [protocol/messages.ts](../libs/scratch-link-client/src/protocol/messages.ts) — **재작성**. `ListSerialPortsParams` 등 self-link RPC 타입 전면 폐기. -- [constants.ts](../libs/scratch-link-client/src/constants.ts) — **재작성**. 포트·호스트·메서드명 변경. -- [errors.ts](../libs/scratch-link-client/src/errors.ts) — **재사용**. 명칭만 유지 (LinkXxxError). -- [capability.ts](../libs/scratch-link-client/src/capability.ts) — **부분 재작성**. probe URL 만 새 엔드포인트로. - -작업 단위: -- [ ] §4 계약을 `protocol/messages.ts` 의 타입과 `LinkMethods` enum 으로 옮긴다. -- [ ] `client.ts` 에 새 high-level helper 추가 (예: `discover(filters)`, `connect(peripheralId)`, `write(message)`, `startReading()`). -- [ ] 새 엔드포인트로 `LINK_HOST` / `LINK_PORT_WS` / `LINK_URL` 갱신. -- [ ] `capability.ts` 의 probe URL 갱신 + 응답 검사 (단순 WS open 만으로 부족하면 `getVersion` 호출 추가 — §4.5). - -### Phase 3 — IO 어댑터 (`web-socket-link.ts`) 재작성 - -기존 [web-socket-link.ts](../libs/virtual-machine/src/io/web-socket-link.ts) 의 `sessionId` 모델 (openSerial → close → write) 을 폐기하고 -`discover → connect → write/startReading` 모델로 교체 (Serial 전용 명명). - -작업 단위: -- [ ] `WebSocketLink` API 시그니처 검토 — peripheral 측 lifecycle override (`scan`/`connect`/`write`/`disconnect`) 와 매칭되도록 유지하면서 내부는 새 RPC 로 교체. -- [ ] `subscribe` 콜백 (`onDataReceived`, `onConnected`, `onDisconnected`, `onReadingError`, `onConnectionCancelled`) **그대로 유지** — peripheral 측 변경 영향 최소화. -- [ ] `listPorts`/`addFilter` 는 `discover(filters)` + `didDiscoverPeripheral` notification 수집 모델로 교체. -- [ ] `write(data: Uint8Array)` 의 페이로드 인코딩 / RPC 메서드명만 갱신. -- [ ] `currentSessionId` 외부 노출 검토 — 새 모델에서는 `peripheralId` 기반이므로 명칭/시그니처 정리. - -### Phase 4 — codetinker peripheral Link 분기 정합 - -[codetinker-peripheral.ts](../libs/virtual-machine/src/blocks/extensions/codetinker/codetinker-peripheral.ts) 의 -`_isLinkMode` / `_scanLink` / `scan|connect|disconnect|isConnected` override / write 흐름이 §6 의 호출 패턴과 일치하는지 확인. - -작업 단위: -- [ ] [codetinker-peripheral.ts:541-583](../libs/virtual-machine/src/blocks/extensions/codetinker/codetinker-peripheral.ts) `_scanLink()` 의 filter 등록 (`addFilter({ vendorId, productId })`) 이 새 `discover(filters)` 명세에 매칭되는지 검토. -- [ ] [codetinker-peripheral.ts:498-617](../libs/virtual-machine/src/blocks/extensions/codetinker/codetinker-peripheral.ts) lifecycle override 골격 유지, 내부 어댑터 호출만 교체. -- [ ] write 흐름 (큐 처리, immediate write) 의 어댑터 메서드 시그니처 변경 반영. - -### Phase 5 — 시험·검증 - -fork 빌드와 본 저장소 dev 서버를 함께 실행해 단대단 확인. 절차는 fork 측 README + 본 문서 §7. - ---- - -## 4. Serial extension — WebSocket 프로토콜 명세 - -본 절은 fork 와 클라이언트가 **반드시 동일하게** 따라야 하는 wire 계약이다. -변경은 양쪽 PR 을 동시에 진행한다. - -### 4.1 엔드포인트 - -- `ws://localhost:20111/scratch/serial` -- TLS / 인증서 / DNS resolve 없음. scratch-link 2.x 가 loopback 평문 모델 ([ScratchLinkApp.cs:17](../../scratch-link/scratch-link-common/ScratchLinkApp.cs#L17), [Documentation/SerialTransport.md](../../scratch-link/Documentation/SerialTransport.md) §0) 이므로 그대로 따른다. -- 포트 20111 은 정품 scratch-link 와 동일하므로 동시 실행 불가. 정품과의 공존은 본 작업의 비목표. - -### 4.2 메시지 프레이밍 - -- WebSocket text frame, UTF-8 JSON, JSON-RPC 2.0. -- 한 frame 당 한 JSON-RPC 메시지. batch 미지원 (원본 scratch-link 정책 동일). -- 바이너리 payload (USB 시리얼 byte stream) 는 base64 문자열로 인코딩 후 JSON 필드에 담는다. - -### 4.3 메서드 (client → server, request) - -| 메서드 | 파라미터 | 결과 | 설명 | -|---|---|---|---| -| `getVersion` | `{}` | `{ protocol: string }` | 핸드셰이크. 클라이언트는 연결 직후 1회 호출해 호환성 검사. | -| `discover` | `{ filters: ReadonlyArray<{ usbVendorId?: number; usbProductId?: number; pathHint?: string }> }` | `{}` (빈 객체, 즉시 응답) | filter 매칭 포트 열거 시작. 결과는 `didDiscoverPeripheral` notification 으로 streaming. `usbVendorId` / `usbProductId` 는 10진수 정수. | -| `connect` | `{ peripheralId: string; baudRate: number; dataBits?: number; parity?: "none" \| "even" \| "odd"; stopBits?: "one" \| "onePointFive" \| "two"; flowControl?: "none" \| "rtsCts" \| "xonXoff" }` | `{}` | 특정 포트 연결. `peripheralId` 는 직전 `didDiscoverPeripheral` 의 식별자. baudRate 외 옵션은 생략 시 기본값 (`dataBits=8`, `parity="none"`, `stopBits="one"`, `flowControl="none"`). | -| `write` | `{ message: string; encoding: "base64" }` | `{ sentBytes: number }` | 직렬화된 byte stream 송신. `sentBytes` 는 실제 송신 byte 수. partial write 는 fork 가 보장하지 않음 (전체 송신 후 응답). | -| `startReading` | `{}` | `{}` | RX 수신 활성화. **참고**: scratch-link 측 (SerialTransport.md §4.3) 은 `connect` 직후 자동으로 RX 가 활성화되므로 본 메서드는 명시 토글이 필요한 경우에만 호출. RX byte 는 `serialDidReceiveData` notification 으로 push. (BLE 의 `startNotifications` 와 별개의 Serial 전용 명명.) | -| `stopReading` | `{}` | `{}` | RX 수신 일시 중지. write 는 계속 가능. | -| `disconnect` | `{}` | `{}` | 세션 종료 + 포트 해제. 정상 종료 시 notification 없음. | - -### 4.4 notification (server → client) - -| 메서드 | 파라미터 | 설명 | -|---|---|---| -| `didDiscoverPeripheral` | `{ peripheralId: string; name: string; vendorId?: string; productId?: string; rssi?: number }` | discover 중 새 포트 발견 시. `vendorId` / `productId` 는 16진 문자열 (예: `"0x1A86"`). `rssi` 는 BLE 메시지 호환을 위해 0 으로 채워질 수 있음. 같은 discover 세션 동안 같은 peripheralId 의 중복 발행은 fork 가 억제. | -| `serialDidReceiveData` | `{ message: string; encoding: "base64" }` | RX byte 도착. `connect` 성공 직후부터 자동 발행 (scratch-link 측 SoT 가 자동 활성화 모델). `stopReading` 호출 시 일시 중지. **Serial 전용 명명** — BLE 의 `characteristicDidChange` / BT 의 `didReceiveMessage` 와 구분. | -| `serialDidDisconnect` | `{ reason?: "user" \| "device" \| "error" \| "shutdown"; message?: string }` | 외부 요인 (USB 분리, fork shutdown, 드라이버 오류) 으로 세션 종료. 클라이언트의 명시적 `disconnect` 응답으로는 발행 안 함. **Serial 전용 명명** — BLE/BT 의 `peripheralDidDisconnect` 와 구분. | - -> **명명 결정**: 수신 / 분리 알림은 Serial 전용 명명 (`serialDidReceiveData` / `serialDidDisconnect`) 채택. BLE/BT 와 코드상에서 한눈에 구분되도록 한다. RX 토글 메서드도 `startReading` / `stopReading` 으로 BLE 의 `startNotifications` 와 분리. scratch-link 측 SoT ([SerialTransport.md](../../scratch-link/Documentation/SerialTransport.md) §1·§4.5·§4.6) 에 정렬 (2026-05-22 확정). - -### 4.5 핸드셰이크 / liveness - -1. 클라이언트가 WS 연결 → fork onopen. -2. 클라이언트 → `getVersion` 요청. fork → 응답 (`{ protocol: "1.0" }` 형태). -3. 응답 `protocol` 가 클라이언트 기대 버전과 mismatch 면 클라이언트가 disconnect. -4. liveness 는 WebSocket close detection 으로만 감지. 별도 ping notification 은 두지 않는다 (scratch-link 측 미지원, 원본 BLE/BT 와 동형). -5. 클라이언트는 별도 keepalive request 를 보내지 않는다 (원본 scratch-link 와 동형). - -### 4.6 에러 처리 - -- JSON-RPC 2.0 에러 객체 (`{ code, message, data? }`) 를 사용. -- 코드 매핑 (권장): - - `-32600`: invalid request - - `-32601`: method not found - - `-32602`: invalid params (filter 형식 오류, baudRate 범위 등) - - `-32603`: internal error (드라이버 실패) - - 애플리케이션 에러 (예: 연결 실패, 포트 점유) 는 `-32000 ~ -32099` 범위 사용. 구체적 코드는 Phase 1 에서 확정. - ---- - -## 5. 본 저장소 측 변경 사항 - -### 5.1 폐기되는 코드 / 상수 - -본 저장소에서 self-link 가정으로 작성된 부분 — 재작성 또는 갱신: - -- [libs/scratch-link-client/src/protocol/messages.ts](../libs/scratch-link-client/src/protocol/messages.ts) 의 `ListSerialPortsParams` / `OpenSerialParams` / `CloseSerialParams` / `WriteParams` (sessionId 모델) — **전부 폐기**. -- 같은 파일의 `LinkMethods` enum — **재정의**. -- [libs/scratch-link-client/src/constants.ts](../libs/scratch-link-client/src/constants.ts) 의 `LINK_PORT_WSS = 28347` → **`LINK_PORT_WS = 20111`** (TLS 폐기로 명명도 정정). `LINK_HOST = "localhost"`, 권장 URL 상수 `LINK_URL = "ws://localhost:20111/scratch/serial"`. -- [libs/scratch-link-client/src/client.ts](../libs/scratch-link-client/src/client.ts) 의 keepalive ping 로직 — 폐기 (§4.5). WebSocket close detection 으로 대체. -- [libs/virtual-machine/src/io/web-socket-link.ts](../libs/virtual-machine/src/io/web-socket-link.ts) 의 sessionId 추적 / `openSerial → closeSerial` 흐름 — **재작성**. - -### 5.2 유지되는 코드 / 추상화 - -peripheral 측 영향을 최소화하기 위해 다음 외부 API 는 시그니처를 유지: - -- `WebSocketLink` 의 subscriber callback (`onConnected`, `onDisconnected`, `onConnectionCancelled`, `onDataReceived`, `onReadingError`, `onDataSend`). -- `WebSocketLink.connect(baudRate, options)`, `disconnect()`, `write(data: Uint8Array)`, `writeImmediate(data: Uint8Array)`, `isConnected`, `dispose()`. -- `addFilter({ vendorId, productId })` — 내부적으로 `discover(filters)` 의 filter 로 매핑. - -내부적으로는 sessionId → peripheralId 로 식별자 의미가 바뀐다. 외부 노출용 `currentSessionId` getter 는 -`currentPeripheralId` 로 개명하거나 deprecate. - -### 5.3 신설되는 RPC 헬퍼 (client.ts) - -[client.ts](../libs/scratch-link-client/src/client.ts) 의 `request(method, params)` 위에 high-level 헬퍼 추가: - -- `getVersion(): Promise<{ protocol: string }>` -- `discover(filters): Promise` — request 응답은 `{}`. discovery 결과는 `onDidDiscoverPeripheral` callback 으로 전달. -- `connect(peripheralId, options): Promise` -- `write(bytes: Uint8Array): Promise<{ sentBytes: number }>` — base64 인코딩은 헬퍼 내부. -- `startReading(): Promise` / `stopReading(): Promise` -- `disconnect(): Promise` - -콜백 인터페이스 (`LinkClientCallbacks`) 도 갱신: -- `onDataReceived` 유지 (의미: `serialDidReceiveData` notification 처리). -- `onDeviceDisconnected` 유지 (의미: `serialDidDisconnect` notification 처리). -- `onDeviceError` 유지. -- `onDidDiscoverPeripheral` 신설. -- liveness 모니터링은 WebSocket close detection 으로 처리 — 별도 콜백 불필요. - ---- - -## 6. codetinker peripheral 통합 영향 - -### 6.1 유지 - -[codetinker-peripheral.ts](../libs/virtual-machine/src/blocks/extensions/codetinker/codetinker-peripheral.ts) 의 -Link transport 1~5 차 커밋 (`bbdf5a696 ~ bb61aa819`) 에서 추가한 main-side 골격은 그대로 유지: - -- `_isLinkMode()` 분기 (전역 transport 선호도 기반). -- `_scanLink()` 의 WebSocketLink 인스턴스 생성, filter 등록, subscriber 등록 패턴. -- `scan()` / `connect()` / `disconnect()` / `isConnected()` lifecycle override. -- write/flushSendQueue 의 Link 분기. - -### 6.2 변경 - -- scratch-link 측 SoT ([SerialTransport.md](../../scratch-link/Documentation/SerialTransport.md) §4.3) 가 `connect` 직후 자동 RX 활성화 모델이므로 별도 `startReading()` 호출은 **불필요**. 명시 토글 (한시적 RX 중지 등) 이 필요할 때만 `startReading` / `stopReading` 사용 (Serial 전용 명명). -- `addFilter` 호출은 그대로 (`{ vendorId, productId }`). 내부적으로 `discover(filters)` 의 `usbVendorId` / `usbProductId` 키로 매핑. -- 단일 포트 자동 선택 로직 ([web-socket-link.ts:108-120](../libs/virtual-machine/src/io/web-socket-link.ts)) 은 `didDiscoverPeripheral` 누적 + 첫 포트 선택으로 교체. 다중 포트 picker UI 는 후속 (§8). - -### 6.3 다른 peripheral - -CodingDrone / CodingRider 등 Link 미지원 peripheral 은 본 작업 범위 외. -같은 패턴을 따르면 추후 통합 가능하지만 현재는 USB Serial (codetinker) 만 대상. - ---- - -## 7. 검증 절차 (Phase 5 채워질 자리) - -Phase 1~4 완료 후 본 절을 구체화한다. 현재는 골격만 기재. - -1. **fork 단독 시험**: fork 저장소의 자체 단위 테스트 + 통합 시험 (별도 저장소 책임). -2. **본 저장소 단위 테스트**: `scratch-link-client` 의 RPC 헬퍼·콜백 라우팅을 mock WS 로 검증. -3. **단대단 시험**: - - fork 빌드 실행 → tray 또는 콘솔에서 `ws://localhost:20111` listening 확인. - - `pnpm dev` → `http://localhost:4200/ko/codetinker` 접속. - - stage-header transport 토글에서 **Link** 선택 → USB 버튼. - - 콘솔 / Network tab 으로 RPC 흐름 (`getVersion → discover → didDiscoverPeripheral → connect → serialDidReceiveData / write`) 확인. - - 미션 sb3 로드 → 컨트롤러 명령 전송 / 센서 RX 동작 확인. -4. **회귀 시험**: USB transport (`_isLinkMode() === false`) 가 영향 없는지 확인. - ---- - -## 8. 미해결 결정 사항 (Phase 1 에서 닫는다) - -- [x] ~~**DNS / 포트 정책**~~ — `ws://localhost:20111` 로 확정 (2026-05-22). -- [x] ~~**메서드명 최종 확정**~~ — Serial 전용 명명 `serialDidReceiveData` / `serialDidDisconnect`, RX 토글 `startReading` / `stopReading` 채택. BLE/BT 와 코드상 명확 구분 목적 (2026-05-22). -- [x] ~~**인증서 trust 자동화**~~ — TLS 미사용으로 항목 폐기. -- [ ] **discover 종료 신호**: discover 가 시간 제한 없이 streaming 인지, fork 가 timeout 후 `didDiscoverFinished` 같은 종료 notification 을 보내는지. -- [ ] **다중 포트 picker UI**: codetinker 가 유일 시리얼이 아닐 때의 선택 UI (이번 phase 의 범위 외이지만 결정 시점 명시). -- [ ] **다중 클라이언트 정책**: 같은 peripheralId 에 두 탭이 연결 시도 시 fork 의 거부/대기 정책 (원본 scratch-link 의 BLE 정책 차용 여부). - ---- - -## 9. 관련 자료 - -- 메모리: `link-transport-strategy` (전략 전환 배경). -- 원본 scratch-link 저장소 (LLK/scratch-link) — fork 작업의 출발점. BLE/BT extension 의 메시지 schema 가 Serial extension 의 참조 자료. -- codetinker Link transport 1~5 차 커밋: `bbdf5a696` ~ `bb61aa819` (main-side override 골격, 본 작업으로 변경되지 않음). From 351be7a796509d063e535f56a36e8f7a7d144ce9 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 May 2026 14:18:25 +0900 Subject: [PATCH 05/94] chore: gitignore Visual Studio upgrade artifacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UpgradeLog*.htm, _UpgradeReport_Files/, and Backup*/ are produced by VS's project upgrade flow and are IDE-local — they should not enter the repo when someone happens to open the solution after a toolchain bump. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 915bf3e7..4b69c948 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,8 @@ Package.StoreAssociation.xml **/fastlane/report.xml **/fastlane/screenshots **/fastlane/test_output + +# Visual Studio project upgrade artifacts +UpgradeLog*.htm +_UpgradeReport_Files/ +Backup*/ From 39214cbea1e568aff43e37993c976e57f57338fe Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 May 2026 14:21:00 +0900 Subject: [PATCH 06/94] chore: add brand assets and icon rebuild script Adds brand/alux-l.svg as the source of truth for app/tray/MSIX icons, plus brand/build_icons.py to regenerate them. Generated files are already committed; the script only needs to run when the SVG changes. Co-Authored-By: Claude Opus 4.7 --- brand/alux-l.svg | 9 ++++ brand/build_icons.py | 107 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 brand/alux-l.svg create mode 100644 brand/build_icons.py diff --git a/brand/alux-l.svg b/brand/alux-l.svg new file mode 100644 index 00000000..54e912f4 --- /dev/null +++ b/brand/alux-l.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/brand/build_icons.py b/brand/build_icons.py new file mode 100644 index 00000000..401f0ab8 --- /dev/null +++ b/brand/build_icons.py @@ -0,0 +1,107 @@ +"""Rebuild Windows .ico + MSIX .png assets from the Alux brand SVG. + +Source of truth: + brand/alux-l.svg + +Outputs (overwrites in place; all paths relative to repo root): + scratch-link-win/scratch-link.ico app icon, 16..256 sizes + scratch-link-win/scratch-link-tray.ico tray icon, 16/24/32 + scratch-link-win-msix/Images/*.png MSIX tile/splash/store/lock assets + +How to run (from repo root): + pip install Pillow # one-time + python brand/build_icons.py + +When to re-run: + Whenever brand/alux-l.svg changes, or when a new MSIX asset slot needs + to be filled. Generated files are committed alongside the source so + that builds work without running this script. + +How it works: + alux-l.svg is a thin SVG wrapper around a single base64-encoded PNG + (634x706, non-square). We extract that PNG once, then for each target + slot fit it preserving aspect ratio onto a transparent canvas of the + required size. No external SVG renderer (cairosvg, rsvg, etc.) is + needed - Pillow is the only dependency. + +Editing the targets: + To add or change output sizes, edit ICO_TARGETS / PNG_TARGETS below. + ICO sizes must match the slots the existing scratch-link*.ico files + advertise; MSIX PNG dimensions are dictated by Windows + (Square44x44Logo.scale-200 must be 88x88, etc.). +""" + +from __future__ import annotations + +import base64 +import re +from io import BytesIO +from pathlib import Path + +from PIL import Image + +REPO = Path(__file__).resolve().parent.parent +SVG = REPO / "brand" / "alux-l.svg" + +WIN = REPO / "scratch-link-win" +MSIX = REPO / "scratch-link-win-msix" / "Images" + +ICO_TARGETS = { + WIN / "scratch-link.ico": [16, 24, 32, 48, 64, 96, 128, 256], + WIN / "scratch-link-tray.ico": [16, 24, 32], +} + +PNG_TARGETS = { + MSIX / "LockScreenLogo.scale-200.png": (48, 48), + MSIX / "SplashScreen.scale-200.png": (1240, 600), + MSIX / "Square150x150Logo.scale-200.png": (300, 300), + MSIX / "Square44x44Logo.scale-200.png": (88, 88), + MSIX / "Square44x44Logo.targetsize-24_altform-unplated.png": (24, 24), + MSIX / "StoreLogo.png": (50, 50), + MSIX / "Wide310x150Logo.scale-200.png": (620, 300), +} + + +def extract_source() -> Image.Image: + svg_text = SVG.read_text(encoding="utf-8") + match = re.search(r'xlink:href="data:image/png;base64,([^"]+)"', svg_text) + if not match: + raise SystemExit("Could not find embedded base64 PNG in SVG.") + png_bytes = base64.b64decode(match.group(1)) + img = Image.open(BytesIO(png_bytes)).convert("RGBA") + print(f"source image: {img.size}, mode={img.mode}") + return img + + +def fit_padded(src: Image.Image, target: tuple[int, int]) -> Image.Image: + """Scale src to fit inside `target` preserving aspect, center on transparent.""" + tw, th = target + sw, sh = src.size + scale = min(tw / sw, th / sh) + nw, nh = max(1, round(sw * scale)), max(1, round(sh * scale)) + resized = src.resize((nw, nh), Image.LANCZOS) + canvas = Image.new("RGBA", target, (0, 0, 0, 0)) + canvas.paste(resized, ((tw - nw) // 2, (th - nh) // 2), resized) + return canvas + + +def main() -> None: + src = extract_source() + + for path, sizes in ICO_TARGETS.items(): + biggest = max(sizes) + base = fit_padded(src, (biggest, biggest)) + # Pillow's ICO writer accepts a list of (w,h) sizes; it down-samples + # `base` for each entry. Providing pre-rendered frames isn't supported + # directly, but Lanczos downscaling from the 256x256 master is fine. + base.save(path, format="ICO", sizes=[(s, s) for s in sizes]) + print(f"wrote {path.relative_to(REPO)} with sizes {sorted(sizes)}") + + for path, target in PNG_TARGETS.items(): + out = fit_padded(src, target) + out.save(path, format="PNG", optimize=True) + print(f"wrote {path.relative_to(REPO)} {target}") + + +if __name__ == "__main__": + main() From 1a1afd8f94aa6a685d66ae5d67298b25de88f1fc Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 May 2026 14:32:30 +0900 Subject: [PATCH 07/94] docs: rewrite README for Alux Scratch Link fork Rebrands the title and removes upstream-only content (macOS/Safari, semantic-release, CFBundle notes). Adds a fork notice with the AGPL-3.0 attribution to scratchfoundation/scratch-link, documents the Serial transport and the coexistence port (20211), and points to brand/build_icons.py for icon regeneration. Translated to Korean. Co-Authored-By: Claude Opus 4.7 --- README.md | 138 +++++++++++++++++++++++++++--------------------------- 1 file changed, 68 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index d4355c91..e7e5daf2 100644 --- a/README.md +++ b/README.md @@ -1,102 +1,100 @@ -# Scratch Link 2.0 +# Alux Scratch Link -Scratch Link is a helper application which allows Scratch 3.0 to communicate with hardware peripherals. Scratch Link -replaces the Scratch Device Manager and Scratch Device Plug-in. +Alux Scratch Link는 Scratch 3.0과 PC에 연결된 하드웨어 주변기기를 중계하는 도우미 앱입니다. +[scratchfoundation/scratch-link](https://github.com/scratchfoundation/scratch-link)의 **Windows 전용 포크**이며, +원본의 AGPL-3.0-only 라이선스를 그대로 따릅니다. -System Requirements: +원본 Scratch Link와의 차이: -| | Minimum -| --- | --- -| macOS | 10.15 "Catalina" -| Windows | Windows 10 build 17763 +- **Windows 전용** — macOS 빌드와 Safari 확장은 빼고 Windows 패키징에 집중합니다. +- **Serial 전송 추가** — 기존 BLE / Bluetooth Classic에 더해 USB 시리얼(CDC/CH340 등) 장치를 + `/scratch/serial` JSON-RPC 엔드포인트로 지원합니다. 구현은 `scratch-link-common/Serial/`과 + `scratch-link-win/Serial/`을 참고하세요. +- **포트 20211 사용** — 원본 Scratch Link(20110/20111)와 한 PC에서 공존할 수 있도록 별도 포트를 씁니다. -The Windows version requires the Windows App Runtime version 1.2, and will install it automatically if possible. +## 시스템 요구사항 -Manual installation is available here (choose your platform): +| | 최소 사양 | +| --- | --- | +| Windows | Windows 10 build 17763 | + +Windows App Runtime 1.2가 필요하며 가능한 경우 자동 설치됩니다. 수동 설치가 필요하면 아키텍처에 맞게 받으세요: * https://aka.ms/windowsappsdk/1.2/latest/windowsappruntimeinstall-x64.exe * https://aka.ms/windowsappsdk/1.2/latest/windowsappruntimeinstall-x86.exe * https://aka.ms/windowsappsdk/1.2/latest/windowsappruntimeinstall-ARM64.exe -## Using Scratch Link with Scratch 3.0 +## Scratch 3.0과 함께 쓰기 -To use Scratch Link with Scratch 3.0: +1. Alux Scratch Link 설치 후 실행 +2. [Scratch 3.0](https://scratch.mit.edu) 열기 +3. 블록 카테고리 아래쪽의 "확장 기능 추가" 버튼(블록 모양 + 아이콘) 선택 +4. micro:bit, LEGO EV3 같은 지원 확장 선택 +5. 안내에 따라 주변기기 연결 +6. 새 블록으로 프로젝트 작성. Alux Scratch Link가 Scratch와 하드웨어 사이의 통신을 중계합니다. -1. Install and run Scratch Link -2. Open [Scratch 3.0](https://scratch.mit.edu) -3. Select the "Add Extension" button (looks like Scratch blocks with a `+` at the bottom of the block categories list) -4. Select a compatible extension such as the micro:bit or LEGO EV3 extension. -5. Follow the prompts to connect your peripheral. -6. Build a project with the new extension blocks. Scratch Link will help Scratch communicate with your peripheral. +## 개발 -## Development: Getting started +### 문서 -### Documentation +전반적인 네트워크 프로토콜과 지원 하드웨어 프로토콜은 `Documentation/` 아래에 마크다운으로 정리되어 있습니다 +(Architecture, Bluetooth, BluetoothLE, NetworkProtocol, TestPlans). 프로토콜 호환성/안정성은 +중요한 우선순위이므로, 프로토콜을 바꾸는 PR은 충분한 정당화와 문서 갱신이 동반되어야 합니다. -The general network protocol and all supported hardware protocols are documented in Markdown files in the -`Documentation` subdirectory. Please note that network protocol stability and compatibility are high priorities for -this project. Changes to the protocol are unlikely to be accepted without very strong justification combined with -thorough documentation. +문서 PR을 보내기 전 [markdownlint](https://www.npmjs.com/package/markdownlint)로 점검해주세요. -Please use [markdownlint](https://www.npmjs.com/package/markdownlint) to check documentation changes before submitting -a pull request. +### 버전 번호 -### Version numbers +이 포크는 [SharedProps/ScratchVersion.targets](SharedProps/ScratchVersion.targets)에서 base 버전을 +`1.0.0`으로 고정해두고, 빌드 번호는 git commit 수에서 가져옵니다. 결과 4-part 버전은 +`1.0.0.` 형태로 EXE 파일 속성과 트레이 메뉴에 노출됩니다. -Scratch Link 2.0 uses [semantic-release](https://semantic-release.gitbook.io/semantic-release/) to control its version -number. The `develop` branch is treated as a pre-release branch, and `main` is treated as a release branch. Each time -a change is merged to either of those branches, `semantic-release` will calculate a new version number. +정식 릴리즈를 끊을 때는 `git tag v1.1.0`처럼 semver 태그를 찍으세요. GitInfo가 태그를 감지하면 +위의 1.0.0 고정 로직이 자동으로 비켜나 태그값을 따라갑니다. -Apple requires that `CFBundleShortVersionString` is unique for published releases. The App Store will also reject an -upload unless the `CFBundleVersion` tuple is greater than that of previously uploaded builds. To make this easy, we -set `CFBundleShortVersionString` to the version calculated by `semantic-release`, and `CFBundleVersion` is calculated -from the date and time of the build commit. +확장 버전 정보(`git describe`와 유사한 상세 문자열)는 트레이 메뉴의 버전 항목을 클릭해 +클립보드로 복사할 수 있습니다. -Extended version information is available within the application. This extended information is similar to `git -describe`. +### 브랜드 자산 -### Secure WebSockets +앱/트레이/MSIX에 쓰이는 모든 아이콘은 [brand/alux-l.svg](brand/alux-l.svg) 하나에서 파생됩니다. +SVG가 갱신되면 다음 명령으로 ICO/PNG를 재생성하세요: -Some previous versions of Scratch Link used Secure WebSockets (`wss://`) to communicate with Scratch. This is no -longer the case: new versions of Scratch Link use regular WebSockets (`ws://`). It is no longer necessary to prepare -an SSL certificate for Scratch Link. +``` +pip install Pillow # 최초 1회 +python brand/build_icons.py +``` -This change caused an incompatibility with some browsers, including Safari. The macOS version of Scratch Link 2.0 -includes a Safari extension to resolve this incompatibility. +생성물은 모두 커밋되어 있어 일반 빌드 시에는 이 스크립트를 돌릴 필요가 없습니다. -### Windows platforms and installer size +### Windows 패키징과 설치 파일 크기 -The `PublishReadyToRun` (R2R) setting enables ahead-of-time (AOT) compilation, as opposed to just-in-time (JIT) -compilation. This can improve performance, especially at startup. The drawback is [R2R binaries are larger because -they contain both intermediate language (IL) code, which is still needed for some scenarios, and the native version -of the same code.](https://learn.microsoft.com/en-us/dotnet/core/deploying/ready-to-run) +`PublishReadyToRun`(R2R) 설정은 ahead-of-time(AOT) 컴파일을 활성화합니다(반대는 JIT). 시작 시간 등 +성능에는 유리하지만, [R2R 바이너리는 IL 코드와 네이티브 코드를 모두 포함하기 때문에 +크기가 더 커집니다](https://learn.microsoft.com/en-us/dotnet/core/deploying/ready-to-run). -Recent versions of .NET (5.0 and above) can build a "Framework-Dependent Application" or a "Self-Contained -Application" depending on settings. +.NET 5.0 이상에서는 설정에 따라 "Framework-Dependent Application" 또는 "Self-Contained Application"으로 +빌드할 수 있습니다. -* A self-contained application includes the .NET runtime framework. This includes a platform-specific (x86, x64, or - ARM64) version of `dotnet.exe` to host the application. - * Cannot be built for "AnyCPU" because it must include the native portion of the runtime. - * The app can be "trimmed" to include only the portions of the framework needed by the application, but it'll - still be larger than a framework-dependent application. -* A framework-dependent application does not include the framework at all; it must be installed separately. - * The generated MSIX will trigger automatic framework installation if necessary (requires Internet connection). - * Can be built for "AnyCPU" since it doesn't include the native portion (or any other portion) of the runtime. - * Can be built for a specific CPU if desired. - * Debugging this requires setting `None` in the project file. +* **Self-contained** — .NET 런타임을 함께 번들합니다. 플랫폼별(x86/x64/ARM64) `dotnet.exe`가 + 포함되어야 해서 빌드 결과가 커집니다. + * 네이티브 런타임 일부를 포함하므로 "AnyCPU"로는 빌드할 수 없습니다. + * 앱이 쓰는 부분만 남기는 "trimming"이 가능하지만, 그래도 framework-dependent보다는 큽니다. +* **Framework-dependent** — 런타임을 포함하지 않으며 별도 설치가 필요합니다. + * 생성된 MSIX는 필요 시 자동 설치를 트리거합니다(인터넷 연결 필요). + * 네이티브 부분이 없으므로 "AnyCPU"로 빌드할 수 있습니다. + * 원하면 특정 CPU로도 빌드 가능합니다. + * 디버깅 시에는 프로젝트 파일에서 `None` 설정이 필요합니다. -When packaging an application: +패키징 시: -* An MSIX file (`*.msix`) can contain exactly one platform (x86, x64, ARM64). -* An MSIX Bundle (`*.msixbundle`) can contain more than one MSIX -- one for each platform, for example. +* MSIX 파일(`*.msix`)은 한 번에 하나의 플랫폼(x86, x64, ARM64)만 담을 수 있습니다. +* MSIX 번들(`*.msixbundle`)은 여러 MSIX를 묶을 수 있어 플랫폼별 MSIX를 한 번에 배포하기 좋습니다. -Ideally, it would be possible to package a single "AnyCPU" build of the app with stub MSIX files to install each -platform-specific copy of the framework, resulting in a Bundle that's only a little larger than a single copy of the -app. More investigation needed. +이상적으로는 단일 "AnyCPU" 빌드를 stub MSIX와 함께 묶어 플랫폼별 런타임을 설치하게 하면 +번들 크기를 최소화할 수 있습니다. 다만 이 구성은 추가 조사가 필요합니다. -However, it is possible to build a platform-specific MSIX containing an AnyCPU build of the app. That's much smaller -than a platform-specific build of the app, so even with 3 full copies of the AnyCPU app -- one each packaged for x86, -x64, and ARM64 -- the resulting bundle is significantly smaller. +대안으로, 플랫폼별 MSIX 안에 AnyCPU 빌드를 담을 수 있습니다. 이 경우 x86/x64/ARM64 세 카피를 묶어도 +플랫폼별 self-contained 번들보다 훨씬 작습니다. -Disabling R2R and bundling AnyCPU builds of the app generated a bundle roughly 12% of the size of a bundle of -self-contained apps for the same set of platforms. +R2R을 끄고 AnyCPU 빌드를 묶은 결과는, 같은 플랫폼 세트의 self-contained 번들 대비 약 12% 크기였습니다. From c51d8415497752481f91d9af883dbd1b85604bb1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 May 2026 16:06:02 +0900 Subject: [PATCH 08/94] docs: add Windows dev setup guide for Visual Studio 2026 Captures the VS 2026-specific workload names, the missing .NET 6 SDK and Windows App Runtime 1.3 manual installs, and the startup-project gotcha (scratch-link-win, not the wapproj) that causes MddBootstrap to fail on F5. Co-Authored-By: Claude Opus 4.7 --- Documentation/WindowsDevSetup-VS2026.md | 139 ++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 Documentation/WindowsDevSetup-VS2026.md diff --git a/Documentation/WindowsDevSetup-VS2026.md b/Documentation/WindowsDevSetup-VS2026.md new file mode 100644 index 00000000..75f95de1 --- /dev/null +++ b/Documentation/WindowsDevSetup-VS2026.md @@ -0,0 +1,139 @@ +# Windows 개발 환경 세팅 (Visual Studio 2026) + +이 문서는 **Visual Studio 2026** 으로 Scratch Link 윈도우 버전을 빌드/디버깅하기 위한 환경 세팅 절차를 정리한 것이다. Visual Studio 2022 와는 워크로드 이름과 일부 컴포넌트 구성이 달라서 별도 가이드가 필요하다. + +## 0. 사전 정보 + +- 솔루션 파일 `scratch-link.sln` 은 VS 2022 (v17) 포맷이지만 VS 2026 에서 그대로 열 수 있다. **버전 변환 프롬프트가 떠도 변환하지 말 것** (sln 포맷이 바뀌어 PR 이 지저분해진다). +- 윈도우 버전 프로젝트: + - `scratch-link-win` — WinUI 3 기반 본체 EXE + - `scratch-link-win-msix` — `.wapproj` (Desktop Bridge) 형식의 MSIX 패키징 프로젝트 + - `scratch-link-common` — 공유 C# 코드 (`.shproj`) +- 맥용 `scratch-link-mac` 은 솔루션을 열면 "Unsupported" 로 표시되는데 **정상이다**. 윈도우 VS 에서는 어차피 빌드하지 않으므로 무시한다 (솔루션에서 제거하지 말 것 — `.sln` 이 수정되어 git diff 에 잡힌다). + +## 1. Visual Studio Installer 워크로드 + +VS Installer 를 열고 **수정(Modify)** 으로 다음 워크로드를 체크한다. + +### 워크로드 (Workloads 탭) + +- ☑ **.NET 데스크톱 개발** (.NET desktop development) +- ☑ **C++를 사용한 데스크톱 개발** (Desktop development with C++) +- ☑ **WinUI 애플리케이션 개발** (WinUI application development) + - VS 2022 의 "Windows 응용 프로그램 개발" 워크로드가 VS 2026 에서 이 이름으로 바뀌었다. + +### 각 워크로드의 선택 사항 + +워크로드를 체크한 뒤 우측 "설치 세부 정보" 패널에서 추가로 다음 항목을 켠다. + +**`.NET 데스크톱 개발` 의 선택 사항:** + +- ☑ **MSIX Packaging Tools** — `.wapproj` 빌드에 필수. VS 2026 에서는 개별 구성 요소 검색에 안 나오고 이 워크로드 안에 들어 있다. + +**`WinUI 애플리케이션 개발` 의 선택 사항:** + +- ☑ **Windows 11 SDK (10.0.22621.0)** — `scratch-link-win.csproj` 의 `TargetFramework=net6.0-windows10.0.22621.0` 가 요구하는 SDK. + +`유니버설 Windows 플랫폼 도구` 는 이 프로젝트에 필요 없다. + +## 2. .NET 6 SDK 별도 설치 + +VS 2026 인스톨러에는 **.NET 6 런타임만 포함되어 있고 SDK 는 빠져 있다** (.NET 6 은 2024-11 EOL). 프로젝트가 `net6.0-windows10.0.22621.0` 을 타겟팅하므로 SDK 를 따로 받아야 한다. + +1. 접속 +2. 표에서 **Windows 행 → 설치 관리자(Installer) 열 → `x64`** 클릭 + - `전체 (dotnet-install scripts)` 는 CI/스크립트용이므로 선택하지 말 것 + - `바이너리(Binaries)` 도 압축본이므로 일반 설치엔 부적합 +3. 다운받은 `dotnet-sdk-6.0.xxx-win-x64.exe` 실행 +4. 설치 후 **새 PowerShell** 을 열어 확인: + + ```powershell + dotnet --list-sdks + ``` + + `6.0.xxx [C:\Program Files\dotnet\sdk]` 가 보이면 OK. + +## 3. Windows App Runtime 1.3 설치 + +이 프로젝트는 `Microsoft.WindowsAppSDK 1.3.230331000` 을 framework-dependent 모드로 참조한다 (`SharedProps/WindowsSDK.props`, `scratch-link-win.csproj` 의 `false`). 따라서 **Windows App Runtime 1.3 이 시스템에 설치되어 있어야** 디버그 실행이 된다. + +설치 안 된 상태에서 F5 를 누르면 다음 다이얼로그가 뜬다: + +> This application requires the Windows App Runtime Version 1.3 (MSIX package version >= 3000.820.152.0). Do you want to install a compatible Windows App Runtime now? + +다이얼로그에서 **예(Y)** 를 누르면 Microsoft 사이트로 안내된다. 자동 안내가 실패할 경우 수동 설치: + +1. 접속 +2. **"Windows App SDK 1.3"** 섹션을 찾아 **`WindowsAppRuntimeInstall-x64.exe`** 다운로드 (ARM PC 라면 `-arm64.exe`) +3. 실행하여 설치 +4. 설치 확인: + + ```powershell + Get-AppxPackage -Name "Microsoft.WindowsAppRuntime.1.3*" + ``` + + `Microsoft.WindowsAppRuntime.1.3.x64` 가 보이면 OK. + +> 이 런타임은 최종 사용자 PC 에도 필요하지만, 배포용 `.msixbundle` 은 자동으로 프레임워크 설치를 트리거하므로 일반 사용자는 따로 깔 필요가 없다. 개발자만 수동 설치한다. + +## 4. 솔루션 열기 + +1. `scratch-link.sln` 더블클릭으로 VS 2026 에서 열기 +2. "Migration Report" 가 뜨면 **OK** 로 닫는다. `scratch-link-mac` 이 Unsupported 로 나오는 것은 정상. +3. 솔루션 탐색기에서 `scratch-link-mac` 은 회색으로 표시된다 — 그대로 둔다. + +## 5. 빌드/실행 설정 + +VS 상단 툴바에서: + +| 항목 | 값 | +|---|---| +| Solution Configurations | **`Debug_Win`** | +| Solution Platforms | **`x64`** (또는 본인 PC 에 맞는 플랫폼) | +| Startup Project | **`scratch-link-win`** ← 중요 | + +**시작 프로젝트는 `scratch-link-win` 이어야 한다.** `scratch-link-win-msix` 를 시작 프로젝트로 잡으면 F5 시 다음 에러가 난다: + +``` +MddBootstrapInitialize called in a process with package identity +0x80070032 지원되지 않는 요청입니다 +``` + +이유: csproj 가 `None` (언패키지 모드) 로 빌드되는데, wapproj 가 그 EXE 를 MSIX 로 배포하면 패키지 ID 를 갖게 되어 `MddBootstrap.Initialize()` 호출이 충돌한다. `README.md` 의 "Windows platforms and installer size" 섹션 참고. + +### 시작 프로젝트 설정 방법 + +솔루션 탐색기에서 **`scratch-link-win` 우클릭 → Set as Startup Project**. 프로젝트 이름이 굵게(bold) 변하면 적용된 것. + +## 6. 워크플로우 + +| 목적 | Startup Project | Configuration | 결과물 | +|---|---|---|---| +| **일상 개발/디버깅 (F5)** | `scratch-link-win` | `Debug_Win` / `x64` | 언패키지 EXE 직접 실행. 평소 작업은 이걸로. | +| **MSIX 패키지 동작 확인** | `scratch-link-win-msix` | `Release_Win` / `x64` | publish profile (`Properties/PublishProfiles/win10-x64.pubxml`) 이 `WindowsPackageType=Desktop` 으로 오버라이드하여 진짜 패키지 빌드. | +| **배포용 msixbundle 생성** | `scratch-link-win-msix` | `Release_Win`, 모든 플랫폼 | x86/x64/ARM64 번들 `.msixbundle` 생성. | + +## 7. MSIX 사이드로드 준비 (선택) + +MSIX Debug 빌드는 임시 자체 서명 인증서로 서명된다 (`scratch-link-win-msix.wapproj` 의 `GenerateTemporaryStoreCertificate=True`). 자체 서명 MSIX 를 신뢰하려면: + +- `설정 → 개인 정보 및 보안 → 개발자용` → **개발자 모드 켜기** (또는 최소한 "사이드로드 앱" 허용) + +## 8. 자주 막히는 곳 + +| 증상 | 원인 / 해결 | +|---|---| +| `NETSDK1045: The current .NET SDK does not support targeting .NET 6.0` | .NET 6 SDK 미설치. §2 참고. | +| `Microsoft.DesktopBridge.props was not found` | MSIX Packaging Tools 누락. §1 의 ".NET 데스크톱 개발" 선택 사항 확인. | +| `Windows 10 SDK version 10.0.22621.0 was not found` | Windows 11 SDK 22621 미설치. §1 의 "WinUI 애플리케이션 개발" 선택 사항 확인. | +| `scratch-link-win-msix` 가 보이지 않거나 회색 | 솔루션 Configuration 이 `*_Win` 이 아닌 `*_Mac` 으로 되어 있을 때 흔하다. | +| F5 시 `MddBootstrapInitialize ... 0x80070032` | 시작 프로젝트가 wapproj 로 설정됨. §5 참고. | +| F5 시 "This application requires the Windows App Runtime 1.3" | 런타임 미설치. §3 참고. | +| StyleCop 경고가 에러로 처리됨 | 원본 동작. `SharedProps/StyleCop.props` 참고. 거슬리면 임시로 `TreatWarningsAsErrors` 만 끄기. | + +## 9. 참고 문서 + +- [`README.md`](../README.md) 의 "Windows platforms and installer size" 섹션 — 패키지 형태와 배포 크기 트레이드오프 배경 설명 +- [`scratch-link-win/scratch-link-win.csproj`](../scratch-link-win/scratch-link-win.csproj) — 본체 프로젝트 설정 +- [`scratch-link-win-msix/scratch-link-win-msix.wapproj`](../scratch-link-win-msix/scratch-link-win-msix.wapproj) — MSIX 패키징 프로젝트 설정 +- [`SharedProps/WindowsSDK.props`](../SharedProps/WindowsSDK.props) — Windows App SDK 버전 핀 From 9e7d29da45c039bebf92de173e4e9aa4187b46e1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 May 2026 16:07:48 +0900 Subject: [PATCH 09/94] chore: swap brand source to labs-l.svg Replaces brand/alux-l.svg with brand/labs-l.svg as the icon source of truth and regenerates all derived ICO/PNG assets. Wrong source file was committed earlier. Co-Authored-By: Claude Opus 4.7 --- README.md | 2 +- brand/alux-l.svg | 9 --------- brand/build_icons.py | 10 +++++----- brand/labs-l.svg | 9 +++++++++ .../Images/LockScreenLogo.scale-200.png | Bin 2561 -> 2391 bytes .../Images/SplashScreen.scale-200.png | Bin 182715 -> 166171 bytes .../Images/Square150x150Logo.scale-200.png | Bin 51493 -> 46655 bytes .../Images/Square44x44Logo.scale-200.png | Bin 6452 -> 6034 bytes ...x44Logo.targetsize-24_altform-unplated.png | Bin 983 -> 927 bytes scratch-link-win-msix/Images/StoreLogo.png | Bin 2776 -> 2545 bytes .../Images/Wide310x150Logo.scale-200.png | Bin 54467 -> 49583 bytes scratch-link-win/scratch-link-tray.ico | Bin 3255 -> 3070 bytes scratch-link-win/scratch-link.ico | Bin 73875 -> 67384 bytes 13 files changed, 15 insertions(+), 15 deletions(-) delete mode 100644 brand/alux-l.svg create mode 100644 brand/labs-l.svg diff --git a/README.md b/README.md index e7e5daf2..3382b52e 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Windows App Runtime 1.2가 필요하며 가능한 경우 자동 설치됩니다. ### 브랜드 자산 -앱/트레이/MSIX에 쓰이는 모든 아이콘은 [brand/alux-l.svg](brand/alux-l.svg) 하나에서 파생됩니다. +앱/트레이/MSIX에 쓰이는 모든 아이콘은 [brand/labs-l.svg](brand/labs-l.svg) 하나에서 파생됩니다. SVG가 갱신되면 다음 명령으로 ICO/PNG를 재생성하세요: ``` diff --git a/brand/alux-l.svg b/brand/alux-l.svg deleted file mode 100644 index 54e912f4..00000000 --- a/brand/alux-l.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/brand/build_icons.py b/brand/build_icons.py index 401f0ab8..59081a85 100644 --- a/brand/build_icons.py +++ b/brand/build_icons.py @@ -1,7 +1,7 @@ """Rebuild Windows .ico + MSIX .png assets from the Alux brand SVG. Source of truth: - brand/alux-l.svg + brand/labs-l.svg Outputs (overwrites in place; all paths relative to repo root): scratch-link-win/scratch-link.ico app icon, 16..256 sizes @@ -13,13 +13,13 @@ python brand/build_icons.py When to re-run: - Whenever brand/alux-l.svg changes, or when a new MSIX asset slot needs + Whenever brand/labs-l.svg changes, or when a new MSIX asset slot needs to be filled. Generated files are committed alongside the source so that builds work without running this script. How it works: - alux-l.svg is a thin SVG wrapper around a single base64-encoded PNG - (634x706, non-square). We extract that PNG once, then for each target + labs-l.svg is a thin SVG wrapper around a single base64-encoded PNG + (non-square). We extract that PNG once, then for each target slot fit it preserving aspect ratio onto a transparent canvas of the required size. No external SVG renderer (cairosvg, rsvg, etc.) is needed - Pillow is the only dependency. @@ -41,7 +41,7 @@ from PIL import Image REPO = Path(__file__).resolve().parent.parent -SVG = REPO / "brand" / "alux-l.svg" +SVG = REPO / "brand" / "labs-l.svg" WIN = REPO / "scratch-link-win" MSIX = REPO / "scratch-link-win-msix" / "Images" diff --git a/brand/labs-l.svg b/brand/labs-l.svg new file mode 100644 index 00000000..0cf24797 --- /dev/null +++ b/brand/labs-l.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/scratch-link-win-msix/Images/LockScreenLogo.scale-200.png b/scratch-link-win-msix/Images/LockScreenLogo.scale-200.png index 21ca7051ddb5fcf16e70f9bf417e1849406d36c9..de5f4da99f5f17f498e93b3d31aa27419ce54759 100644 GIT binary patch delta 2380 zcmV-S3A6Tr6xR}vB!3=BL_t(|+U=Upk6l+%$3Io)-1~m@Yj=CP?T+JLvE$5m5(|gOG?_@lKnC*5=$xIg*K0*FN+r>{K!yUXhr{v??* znGI1OhJsL(kaIQI`oVA9`@w(y&2iExd>YKE%9&@s`e*&q7k__$Z?Dp_sLx)$U`uOf za-Fq4*x5<5Tz`et(-(fNh;ehcv-R(YJpKrX2=30>`71B2UwQGH`+E4ynx5tboGsbn|&Ui+-vc|Jteop@Djc;X3S$|^;2M6~*czIOUg3v z-u8%6BkGO`WH*v!EISPxH;`k=qmcy>#G-Y{veD`+Y1!%U#^yeCZIore@WxDW1jka{ zyysS7*?+_n|Nj(fb`C}79PY$UPbEYKGb16GSbtN2x5R3Q5*gj0=b%^qToJq&&NWcg$}W(3aZPF5nEBC3K2(z=7S?{ z2#%PM#+9iAu)OQ}FakWz2n12Ws+$vw7G(g_Ip^hLdPf9xsH-U|0>;4oSnNM4fJWhq z27l3@J)b3FQBtbnL6Nz^CV~Mjf~QQCW)OrtOZUtkD}Y1Cs%FtPBE+&q5rnLup^1Py zm>4faWywrndg60zzr2ASb!K%)gP+o+yFQR1}&~e{m=*lRY4R`$F<2sA`Swo&41#8 z;O5n5CIaH%Zfc%z1yjQn#2fu%!67*Ah95RUhgEDoL*fz6kro1AW`=_zcuq}28X5*Q zT4-*JI^G}!9G?U5|D%}s$A)B!f>;QEyXA~mE|j^RnFd!0($GX46>0VtC}Kc@V%ae~ zgb=0G>vvnd<&Co2zZ%NcZ@>S& zpWnXq?l%{SL|mj7uxy6=K|oKYS%u@+oc}uSy+oXh)9$qqje4-RPuc2R$bV)Rw3^cH z^s1Hh4O?4Vqupuia5UuRdpB%0o3_`Ue&OFNrE9x)ZhY^kBbWuxKypuMS0r3WqnU}D zih{Z~U86P`$g&~b$S-{3S9tC3|AB6|V;dLGbMeX-_3VXn<;k@b`b!Ilca*zVoebSM5&sWS$NG zaXi?)Ek~FmEfxWH>dELv=(kDZu`!z>?G~P$!=aVTzY>AhcXuhRp?_2|Z)!#mHn(>n z8!kc!k)+Bq*Pdbh>{)&A;ce@#Zu~l%*T4N}DKtM=c{YB#b>b9hIx-(kDAv1FRsPXJ zCk?HnU6265i6S30{D;dKg1O+98MOkdPd*XvZQj&&_rxn9MsiAza56Xlt)}C*GzRi? z%=rE;p$w>aBO}BSaeovis#B`b79*;ok`XmTA&L_nf;&NsAWnr5y8Whl$KqUwML5bJ zY+)%;O@`N16|tEPZrsF^fl4DI=32YaNKLcv+EiZ^q3NOLY*Qyl144t7>&$49n=>S| z5j~P^3lFxc@!&2gnTp53%}s{y-6OV}iJarOFxN*7mF)0f1Ap#KbQ~wqfY2h)D+>;8 z>@Xc1pbBn2@+0=33k5PUuBKx5R@W?vNcz zhS!GG8PAToG&em0UXK}Xz0dZ4f2TsSDx_QA`PbFSXn!z0ilmTFbFGRyE2qw$JM-*I zx9YmKYF1VK^G}s0FMe5DODEA#&JTiv&l`Nth*fw!WjfqvytiYM2irC~c#vc^(b#I2 zL6r~Re*H_kTQ}c1sveS0cQxFEc6H&GiA=7mVLctaIvec%-Eep7pAU9E+_an*?g`{!Z|M&=YxnwP zclisK+P&2ukL}JEDav&f2?%(~`>C34rfTwjnnjLoRg>XXH5u*K({XJdH}+FBG(3vG y8a$LA<^}KZ{}&I$ delta 2551 zcmVFF8I_$3^X#C9Ho za72(53}gWkS%e5s7Dgb1#18S;u|N@QumoZq7KjJ|@(#ozf(QsqA|58TvBEeRkK^&Y zpWV0b<2F7#Fb?&Ku{lCY*zORJu^M4YN?|NncX8d4Z?=tc4 z7_hhxcpBf&%RUscvbMP$Rz{Dj_p78dZL8_UYO-^=o=uv4pa;mteE|?vHXr%GPpxi0 z`o~3o_@QW!bH<6H0x{Q<+3o9pc>DZoe^Sr(>VpI!_i8q(%84hRd11Kq*zZgybLz>Y z>6MaI3{03uRevptVzfFSSJO8yz51_DRg<0BL4lBavUxMMf9UC7+IZ~AzZ#Es#*c31 z;V*ycAwB*69;2R7xA4Xl;V=LG0%u;?n~gS3^qalgUwZrHfBNa1(qS?nfKjXr!Xu|Y zIi5F3A78ue|N2jVLQkGbP`6+$dHmmK5opVg@*AIflYhTEGq2W;jC$A4{`&`ZuU&HH`A6_5u<(CIPw0GShs8)3Aiw)zHtUGGmruU3=aq@Mt`gu>PoUA3VDv@0|B7R#wqn7s4s>& zN4D0o;v&9z6HU9_-&h0;BO;P$+k!eeoL9(p%W^(k6Veb$6Gd{0YlG~`8FYxK14&>R zqy;jlF>7Gjx-253*jzg(G2xdpAn?8zsCXphJnAcu5cP<-&gRKvVn>+5tPadu4~3B0 z`hU_v>7wPG*cYn+DmkyND2T_L!<<7*x|K&UGKjJ_2{f(CE}Oc4NAfKMQbr?A4Ae9>K_| ztqu)iNMKeqbo79w+#aeLT{uB$fONtJR1thA-gNy7Wlvg1rIR zI&%?m9RqYgWM6t4BHH*k`QB%r=C9Tn8>&QdyQ;d_K)wqQ(0iVmtl%^wzb%9bb9t8#$+Y2C=*ewkot)sV&% zehb8TvzG1medG&1^p2G)qmQ*_RP%-uyJ?n3j7U%WwL6Qy{)xH&{m;Hm6YEY^OMl+a+hP!7!mT|) zKJp{%>?y;(qdzbRHB@&(p6a_RGpH~;gCr`o2@4~Buo zBE+_yB}F<61YJVIYJ8`1FzIAH%`o#;&u%OG9wPI7pwyDl(;kmry7>^Z|jOB>r zgyf9nOtwWnP>)$A)^n__2s9KL2`YH;C=O!Asbb^TdGg^Iy+DqcT#nX1{J=ADO3_j? z|BoURT-_yJz3FkHomY3YtZrXmvUm^?GNJ}zcu{{ZuC&?DlC?BXRl^RlKq<`SW+x$2QmqkJ4SLg zL?Gva-Q7T1$bWLPIC-$e-36DkottmO`CcO`#Y>m_T)w%9$u%~Qd170UQ{HzQvu<@n z46_A0!d-EPa~?CLnhG~}9A__-)UBr{eS{%~z&uzvKpYg0FQ z>AV!f{(q3I)gC?xv2rw3pqdBjd7!QWxh+X~g=iz@dBm0Ji2uE{&X>+_@@Hqt{MBy_ z>(C#R!8y6{&6hq_O?Gydt!B&pwO31h_~{>iv0UH!^lVmF8t3}Ht=2zvY_5-P)ReBP zQV7swrHaaK?YJ^6xx5qdr8}B$?P*L}YOmifLVp>^&FtpQb6gw&bn*Ccf z+i?5hbm#h)XLqh&Xq!6SZ}InmwN0E4QuK%YqBq#|Mem3>KM;%@<21%*lG=JVHuW?% zRUN-msEOP?U;*#_kqO~`+D9Vtt_MZl)3Xxq7Nz8SWs@KHQ!MZC^?z)`6;U3A7ViK6 N002ovPDHLkV1f?r2q6Ff diff --git a/scratch-link-win-msix/Images/SplashScreen.scale-200.png b/scratch-link-win-msix/Images/SplashScreen.scale-200.png index 6b669f453d0607b73dd70dcdcfc6f2e45996f356..38974c6e11cc1e5af8c99223cf62dc2bfdbcf4f2 100644 GIT binary patch literal 166171 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ξv`yn-^@ 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%0A~uvOAPMj##I zDNg;AH3r50lr1lX(uwkfkj2lS_Yk_#cBf4W6>53Czb}?f`mGGDT25R4*dJF}vp)B? z>%=D`ANliruuD$Ig;sD69XsEDUr6h-BK^{Q%n^;gB<00d-kZq(;t3p0!Z~6uQbdG= zvubIuY31xK2Zq1pr@mTBgN>seYG%t+5dllTfG0ZCRK(+Uo{p#6R<~zrn`!`JtEzC7 z1+CCRK9`-hML!Y<>}5h5pL0$Y2wY8z^!#q*bObURUPv+0s@Btl+5brYke{Nx`i)uC zkRT$H?Um+(RJY_5jv~V`YKPxoWj`NEvF70}vU#_c1wkb{p9^?=UU+?gTp1Kc#hF9B z1iI)xlg}(pY}B-g`0|RJ*(Z$SC;(3>_+H`J4s|GDmIQLD8In}n?GxoFNj%|3>a-X= z5!hNK1AwKOB=E8m+hT1)rD(fx=rI}t;F~N-ONr|jbbT&210H_o-_hmbDms3zd)JC4 zT5v;t6#h^4Bgy6fMUzJdzi)cX3=ybIc{eH-AiXWeaT|J|yu4VLUSKFq=0GvxOpSr2; zf?FT|Z9&HFs+zHnebOxVtG8kC=UlJuxU;ePPOR zF;%_OpIhv9S=nXc#bfwH*d#gvRIB;lMo0Z!r{N&vO)OGw98LF+}cUBxZdL3`S4hpoU>%ZZcpXQUL z#Sv`L_%!MC*DY!(UUZ+BZur)Y$Q3!`ff7u5R~TWolljc+$yEXFx1rBd8@`k^pXri2 z|B9#~1RaowGZr)LsOVpBX+812Jw%q6Sd$mhJy;G_T*eNcrx>vVUdk9nG4dQA2Bk+c z!q+c;y1eq{XFTUgTD@asBn`6=PK3yR_O*TaCrtd;RQFJMx;z_&26X%N$}p9d4`*9F zq+im-Z+;HAp9iVWdRMbIRm0am`G?#8lnAMvPJQld%cWawZFJ2W2&$s2Rqt2#cd)4{ z(T40>+bQRbJQ6w!pV`+;^->;rmTukTxFi3vj^_$i`qx8P-IL=cRzKHIDXmt|NV%UE z;ztnJFYa_IGAWm+D`vAJ$7!GOQGj6(@lyAjnr@pXjybp99$UI&*}f!2-R984Q@gi5 zYZ!*vc2+|ID4;LN#=)@#ghnpqk)pYwt6+F6WG89I$M3A3w2hKucU(*UtxthuF?Q(} zGx>Ru>s}_*#Dn4|@BJgF3kUgOyiD!hCP*Ji58_xF(A8-iX-j6(>ONQ4?Srt}f&8$x zg`M?}(1!l5I!;$|;PznmABQIOPh@4fQ1>{G9SyC?x0)M!pt9(3u~s7PcXx0|n!nIP zTC`%UHgXPsUz(%OVrgNTgRTs*gL5V{S@m+GflB^zx6@Y>dUTJDdmWHu01IAe?CWj` z*N)G6_~+s|H75k+C78v6G>Wv41VMX@5w9oK^PL2?hb^Td!>>eiaRnny^u`m4>54y# z#fa`8xa=p5zz$t)a!Llr0PDm4jq#maybV%1dVABzJOS>Rg#ay_shqOYx+X&9Y`dS4 z*PHF!dMluG7C-J0h5_lK6uT)7=fI0YyL}V7vQnM3nl)tE7)5nAPkdR1;J56L@NsP^ z%mIUt+D8%kA&Ziyff~lJ#IhudyP(yddqI~U&%=&=?|*qWHt9rN&slugjI#nR=2DaV z$)Nv5ahHc4D+6lStkNnUM5EW0?^RPnR{9KuH5#h&*Tp|iq}k;%}h(5Ku440Q^M9Y zOP_qyrDT>VxTqG)R+6zsVN-4Q75J0M!Q?2A54$Bp7V#64AV*=sLyT*}eoTFbJHkVm zoME?-7K_FVq)=#|x6aX5%7o%v>qmd%fSCVXPDyv6!2rQILlI$dadDr6i`%hES@HLt zcgtZP8*T$~F1T?QF}L0YI1<<}pj9Xda3CU8cF1*WYnqX07xNaDpdTwZ< zPNzM*{Tn5qJDP6l23FU9cQ5}2-R`(Vy?)i6rJT4+Fv3=(nCSv!br|S#=9-g$GZlro z3JaLNoRKP&Woe3GY-(%~o(la~P?o;^o*s3S^6hg(Gs|!%(aG_mIV5^GF4BcsO_OGP z(rSZTQ}fnrvEa(q-e)8NA3p-F^Oce^Iu%8TgH^bbDc`Nm8~~x_lFE7pUMSxZh;4=- zH<{OS8|m+sKh|C^*S1_={oFfSf5GUOc=?{wqX+Ue0{*_>4<-CBs<%`dgl|)sy}M@* zb-6p}=?My3s+-I3yFdGVV!X!r3!N+Unt~#R!0^a3|M*t_PMc*akFpWOx1Y zeNxzs(j7MSLycpK@dxs(8tA->2MGA;XNT_l8!!;Uv2SJuIFN1_E1H1EMiXx7wL={C z%Ie4KX1D331*dkmqP^3m(oITemF6?Zbn?@{d`iQhmKvm6E-hBQ%Ip6VuK1_6nbPd6<{`h0^7gZAE70E zO3O~m2Boz4%7vbppnUXRDpPEz+@Jfc+#Ef6GQqE8Y>GUGZ=vTB=1d1#n<5HN^K4AZ z+Sy8-6$)~!xl~qD^M6;g3x@hri{iSvIor6oz3pKaWX8xF;?${+S>MT%p^6XxX!O;| zxBjuP09XkYqZl02MZ7yCIq$jNxYR#LW}zeR(Dv|!d;g3a)=wkLDxN@!5zp-a{}mtW z4UjrJ)6Tk@Ziwv8xn}sM;U`8DT=@txe4RqV`0ao(Zuh+QQ{nBHpwDh7QOcq$Ew3%< zBxY4CwjK~XK@;|#Q0?d>*`V!g8H_)Y`xn?nVETg+oWRX&~arv>5{_MJu ze)B6Qjy1k}dZY)u#A%5X(?f1yu?;9dEE7In#3mM)*Ds%hF?Mq7O z&B5&|h-G?2zVrtyC4feq$S7O@ED@eopb^3|DFV<9!!1y;LM4k9l`5pB^_9syN_n@hJZ_K1)3I7PcL;h}0PY>EChi7Xik?2H7J8z)}nm4e~ z7cR8alfH;OqR)JyQ=N_)eXEH|rV5sBU$!+ZatcpQsf*Osdt!yehrycm`#M+!0+ci+ z4<)h8PlCw5)fS+qv6E)l5Kf4>46h)|!MK1OJ;vEy$&FHe=z=ErA&xi@(2eNi2>Xs1 zZGegSXExuB+rj+Jg>sCYpz;Jv?p_9gKfi$Q1Zf{;0XJQOLo9kV(>liqj*z z6+tXW8@w?(NK>K#w?Ya}M6X@K5uuDxqJ?il(xscxMiC^@uBR`pkrOJ+BMa<d;_8ge#-P1~4d!_05@{JHqbu!i_C=(o8s9+kNT?bcsK{l66Y$GpPF z0GQ%9KPlTqaakqU-tqSElUE8C!|fgv*oPwgW2%eRC*4adGm~}pg zf{hoNpGrza38=((!-e0m2Pol+d=Uq?Qu8H00IfAi6%BCa#eDF7D*cR0Z={riPl@EM=o!& zh=6@=Jua9NG%+{KJjZ<&DaJfqZEk~o4!RpYgMAg8#}IjLh&(wE#7qb*`VRYF8{FXp z(z)iqS>@*z_#L46X}dkS1AA*F1CHl|?v-ACv%j0W$4(gXe{ucg8A&0owH!;4!Iy7H zo?ftx$812U9~u9ZI7(RwGlpJv)l&OY;EK>VQ!&CqG%YS7OWH&R7eNTB`f|CKqRX=TJ?ehlQg&f?i(ss|j zSIxXeH<$n@r$I;go8t2Z=GuQbnEEDtkN)o6DV?8HrQVrHDT=EE{{WIl=&?c+nacfZ z&#nLf4nQrT^LAva8z2C7Yep@@bCbVEMmHtkMmCmOASf-9Ld%o@8lJHQszpXc&E-xo z%VPOQ!gQFmm_T{Q;c@2dM0^BU7OEIlB^@?In0!_AEMr_*P%?DOiz%74YWX@&7Grs! zcHD7-b#pAlv3d>tVl(80;ptXA9^5QE5En38DvWXjqES`9O@{S{#`*8ldgpe^KWYz8 z1|V(Z!}Ea--x_RY(-r5&!p7XMts7>7Hb)VoZ5J^NJ*1x zNgtPE@1Mo|-<-*kQTZSPJCMK$s3wnwU(!e6kgrPzRqHmhNBq0V`D5@=ptHy-d{9_v zQ~DRb(uZCfR}_M6xynLb6oak3F@zcX3kL%QmoUMv$ik3gVl7<7Y?t;&hxqYV<`PO- z6e|5y3pU7Y%S=OiWwas8c0i6`%?*$R;2fsv41UBRP7wFQ|abNSOQxD2}QyCnZ9T zYCz++_zHN8mg3L9|KHmf+Hjy6*=!s@WeHq-73;+Ps!oj-# zrhG~#9e@S^ypolMy3Fm~zAv`caas<%?M-wjSxntOJ71g@hRKn=jh!Ktt566bX3>$J zkR_w;wM)ei0(MFp)V%^yMfqX8Bo_M?=y6Qm2_yzDV|0NHDBc%iRg&OkQ#@lfRm{=K zDGWJXDmq{CtQ9psKyFYo(e>Q_foJGPj4cUGQc*8h-mvKPuGt>)yj|jAx)sfr9_Rmm z{eRH{E6$j|Q#=e#FKZiyLiIIL`~Ny>Mdys%nh-;p5TiZsV!CI0+EnIvz!A9~b!^tV?h+k1R3Z-Fx9dMw zr`e+>kT|Z3cTt9~#V7wqLO1xXIF! zRY0orUh?~`*_!Q?NFH)Q2f7Mkumu5u%dH|jVY*3%O0L$ zS0&LnvpYf;Hh(+dTII?8AZ1#8xD5A*iCrQy^&sjnE`K-J0z(4}02^<>!DD%@;@}G~ z0+T53K0yjn^JQfA1ib^%GpLkk9E_1x5mw*~fpsOL|B* z7`VfBa`Ykp1e!}WNx1Y+kPy!NdAO)HFv>ApF|1v-IU|46v)Db~>2-c-xZw5rac#y> z=f;CI4|yL4#wB9!LQ-U+1q&l15)TYVgZRqGPPVc=`3Av^RW@LP5$bwq_*jw>8!-X} zF$}PFpDQx5ekSq@5;f;bieh8L^acJBRJhebwiKy*l?(^AO3^)ReX1vgirYH8u^M09 z_#!~_&@p{*kL<7WF>rji|Ku}bSBgmWlv$P1wThiAQ{-upNq+ zV(+4@(rYjMf(Pby+O9P=%aJwk1^;|3CrQR}pp@3CJ8*Lnn35;ueDdQPFKxQiZTS5u zUDNV7)xUK9Jr@1H=UX;0)gX^%f4~$ze_JQk>QUF&blN;$RYW(kzM+&nW)Aj9NRt0l z>6=N9GlL<3ndyB&M~m0Wb?|#-157AplpOOH z*1ljF1#nmBuUv01z>y)WZ#@SuA0VsnZQqZc9=VS71?LC7+;Z8^!_a&4m8lB9MqM3U z#vu44+^_DAHZCjT-y(_}DE^w$zwM7*+YdSz?*$`L{2%3$(Lly zFPp%-q~Zab3CE&8E#zb5<4a?J_fx@?<%|$;j*KjtI$!i+f=Zlk`+!07o!9Xw>iqD>QDbk)ru;3d`Tv!xtz37EeVqa43AMZJ;Mapc1cUcvS|XaEpc(Co~W z9r24yj8EQ)qWpf)422{wyL8*TcU^a`xJZv>6^o_=C%0IiILw^3kZM6dJJ}_vM`y)IXk@tRTb01Y~LW zsL1UOH@Syv0+TtxDj$qdlxUT@0|yD3@0EeUJY>(hU)^X_5YNtu_|jYwvwf<`n6oo< zq~;`a{1f6XXE7xK<>4aYeWszqt9K1}pR_7_pZj>_LdCvG7FE*QP z7mjm^uC?aBi?FzRsjFl%0g%}tIMI0ELEKdK*Ez=nKV44rC9i)qOQDY3^{-QU&FQ2P zwAY5n|HSS8p7tSYq|TE5V!gZF`D(&&>Hgix`>I=FqSkE1`t8b@f+f$F`4FQ-DYc3L6T_-1%O{#l6cTrqH>#kRM=`T{^; zcHpwp%Qoa&OT0Gd^QL=3*67SHQ0l#C(*up1r=5Ts;gW<;#uiFmGy z`n1z~fU3`1zPQpC6TdyQOJWWGIr=9Qfd6KjbBEN)cE?=6*_-oyeF>M#N9p>D*9l{0 zH^i|vFd`n9ob^#mR?TUZi^5|Mn2+yl&GUOF$WO^ylV z-|qZRn6%Y8k~}qbc0Avn@=HLtIq$5tKDTj_df1T*jV@%hFW@W^zR0+XEAL`KULv8= z@NAuV5|LZu4q3KQ7TUR&z`4h4TlQ42ty{BD_i#6M65ict#mIQh#27i*BDcNA+`v?P z`zAM!;_R=SV>Hg(WDQTk=c-hyMP~BPhiBW_pHWumExRvkHrw-EmVeUj9w7y-Qf_o2 zTu&~j5NG!Rb2%^_*?MFrEB`kM|F_4Rq1r%(?sitrt_MHqmX^J?^l6;TQQWFq=^-IO zd;m>e?Va2AgCcQ($qY)3zf4O7>0QZ_(v`hS*RnjJZD~eatHGM-+%P+|vS9cxnN)LW z_t0ePhYHgx#B78_+whSr$MTZv>4vuHyI+O@ZsN$0P{&<6b>!w;4^^euSVMjvf!bE~ zTSQCg@X@R3R8O*kTWVKkP4!`llQ!9_@U5#Y#L@5DvO6}q*7LYlJCC!A%*O#W|FQf< ze2j48$DQ_~j7E=(xmJPQVboKfcU;-Zvf02=q(Gj3S6IVi_ROiIDSswWyXXQ^5CtPd)YTc#(!?*KwJKUAy0WR*zch z?i9YO?R2`%18>=oCVUM75h-{QW{P!RMWJ1JOIHOy%hLpn;$X1u@QqKN25U1<*lzMG z>WO`8;84+xI+heZc)>)4-6l}*J=F>$n>(nr<(j8)wR4 zSn&xeoI_+grF_2w#gaayZ*z5Zy*NXP&Rh`83QkhsHJ%HBsS#rurTe5XK*(P+x3amNE9Ily9 z&$Lg+&>$=@7SfZ$+^6CTX=$kTs`>L4uAi&Zn<+caR!J{R|Bjpg9)D%r+I>cUQNsPO z#~gK8gw2bh8#6=6D~y*y)zp5ny4CjtuzD1P%CChcG&}}s>Aov@{a{HtKHkE-^$n;P zr+S-ZoW*xGQoWHnA-Ulzmm%Dgew;j=jtGr_nFXO7aJg`k?no*9YkA&3FI0zzzVulg zdCR$1_5O1mjHh*0W!!l}h>TKy(LJU7p>8(bAYU!qgiz*9l%W#~sL)?UaecFv{0+jO zN=j-%0Cnt9C)sl?{>T0RhH}jRvA_3gLx!iLKm8K)T`#US@6!IKRq3&Ky=W(djBQYU z5z+-W3leDIDi`6HIBTv}7b71$I>e_Ok_$TqvvK=jOt9pS&qB84t3JlQcW&a2hCp_V z*1KV5F&W<{9ke4UpY$$I$$o1Xo1@7WTMue^pH=OMBocn3t&ghSoIIFkLBgmVUEei* z94R=9Q@02$5lBqA9+vI-!6O4YXgK@Y_0inH=`Lpew&V@qX6=6JS{FL}2fol_{7vY) zEy^C6WzW+Rx`yj*9hBkYbCf;lqK}4p;?Q6`|17ly5A+$frq0bSjiFW!=atG?Wa4EC zj~-*v1U9a6n|fsQv0|@wb}Z*y0$3V@NNy6ALX{=9Rct&Y2POw5;lN4F2KdL_Zeulj zH#^cAzi&S`auewGj=A_c5Z#PzV_jfnBRSoBwf;GMU%uqlJ+(*6LR0dPd4o)zc{TA2%Gn?mfG)KUoPMxeYGDF1yJPvGr2V z`Anai`+aaNeQYhQ`Z&Da+f*j5GHv?@2W&F9<@l;g^LCpAKzZw@iI7eDBWitH7D0kQy>V2of2(t>^_p zGz=}iEOMALt}J4KWs^T&)a;;{>+_R3U>#G7>^qZZ#U$d7I=-0NUz>Ujce;KQDf}8y zpxmoP`QT3p`rlN@D7M|(omvbHwDr2v7j3;BLu9757C~W{xw(9B?()m+%{l3*9z0!w z9V3z!SC(oeg{$m=2U^^q;*h)1FX?MWqsMh_Zab16%7aW*!ieAYa(PA?h$d_BN5rq^ zfvo1X*%6>=s@iu#YEeQ7>F3`I^lOOMElv}yq~W)7`Mh6h@;OKC>6)HDg;iW*r*+wr z0#ko~ODfL8!#rvpn!QXAnh)*#Sa)}M=_1&B@ZwJ#q5V5o($O(?Oy0_$AG93JqPjQM zhFc#fJ{tPb1uu%5NZ@bu3+pq^^vA2CWxcCE%{`@OmL)$bd;lm;keghR^JI zp_~v&{U1*pPF7vR=>7tb|IG$|db0($i|v8)<(qxfX?g3-G-f3^^77l1GZv#mG4dU6 z+3wlOht&SYtXudW&hSV4u zrYmu#R!uc;u-_mW|NLD~-f~eoe}|`GX>ntuIYS6UNKOQCUxPtk$;KrKrwrYNHdYPT zNiN*%dVm=J!jyk~13-nZX?K()ymP-@+Bvv6aH&O+!`?$!$Y3^amA1DZ)#p#jGSEFc zoM8m{DHm@sVUMNS@~z@r5uuGt%%ePc`bAk#(fXY2_A-c5k%Jv6 zGfDd<7pMp!3cAN}!F|`;%5W>+)#p?FdQX1DaSe6JQ$-o7_}AG_u{bkC#dl4^X&G3akI{1=u3Z^+i>I^QfcU0=8lHrGKSL+c`XoE8S`X@-3ca-`3S#+III*l} z0n34%oR6ZpKiLA|vC3?Xz4;0#09OO?_^u0C;hr%7X!KGAtGb$%qx6t2Ja@)AhOYIh z!7rqKb!FtOrCiC`1&p&=OC!}qHYQ10S!*P0?A3Bg{gpz3LW$x@LCMvxsm<-$?BED) z-yOSm>YpGwI;We`WN(p6BCNm)#azS2+qJV@0Xp0C+tbSr65Y1S|4BAL(LPVly+2)V zm#i`_BVA^0oMYLGj<*th@I_#SVm)vl4b5Bq4{Q_a>8(MQGDVoGjNY#kgkHyr9y~I3 zZc-!P{zx=d-N4twgTt*Vl3la^J|hW7G`hsO(wDxE!*CEcnDT|u51(id6I(|VuN0dI`qa|4~{N9 z`!n0A-je( z^@`U`jMVqmu@-tkQSm+iSYw$s7fwj*9*T*iA|^Vh{XHM{V|b=_8y74(GfWb|kPSI< zVawwYAZ9D?RkA`-6qMd+6G!jIcXE#5N{y6gl!z`{mOu#AwO^<5sCJw!)P-vVee9*z z94IZZij;WAiS)(klckS-lp*1T8fiNJnSpv8IsLlx+dt6v!=H%)&8rrL&`&t0U1&U+ z6GOF^OQ6W(p87m4p&RVQ$KfqDC{4BE^>{tek6P55T#G8o&BpSyQ0Oh((k=`Jn0u76NPbdxi|nlGMZDfF zK5{4de*@X|C34n7Y{22|qJe9aJ6*~#37$=f}&?StQBpZL;Og&M1)m9U0YcqdD&T*Y;?&|w=vVokk98Kbao`qa_w~HVs2SF zaUUj_POZ(dtD{son~-(xV5GDqgA%c`@lC#Usg&wJJ?3Ju%M8K4fLO0Wtq*liqCVr8 z`^yfnTO7N-Lgq8o{Uq=dCDHR3g?)`qYG4XqIU05(s6O|as=;z;C|_|rVsBD$&MZrMTnu&_ompc z<^|w~9hHUKmKwfogsc3a(900_w}^mF&a~UJcyhOW)}DdphOFNi8gm*g>{W#|g{s_mls%vBI+$P2->V!HBCu0$ z#X6=H?J;`wdvJe_p%(+IB1obCX6|nHICp*ZikGG=<6W<<=ATO4ZacnwVu$xX19PF^u2`yFX;A-${jk0qI)fl(}27<(MJV~m@5{eP%uZ+f`~d&@T-6^ zCn$YHUR>hci;M+8;Lk*_s<*6`Bl52!9Y~X^&BaVs;DNDN3rn_kHOq#5==S|H@Rx^t z-hmi=rw&|-gbYwj5+Naa%XHyJ^LIVWCQ0;KbZ@R-yGI8hL#_54)j!p5Hep9kl}a3?2I#7ev}E5jZwf%3l>!-!p{EPA zvJO#b9vPz6Djrf};Yo!BX%WP74qnPlb(+~!%wmXe<|DJg^iX~p);^QkIBoE&4@hjD z;qw_Ad3Y`P47_#*E<|w>B+l&MfTkeZ_o9+ib*zP%6Di~IvnnK$5y##Q7m=1;BK(o`M7OFFm0^*A&fb&MCxbOqN(rjh5Y9q&dI1}r{hN{f z=Bwf5+bdpF2SR8hklo}zXxMwX{tH&E)49IuCZZ$dmadEuzW8Rq22+z_F$nW zP3Mh>n3!OewSvOo&k+W{7+k*-4_OXOPGEtGZc*ZfuK+pqChm#&s!OV!gM(k*>(Zl( zqh1%3-=q6aV~^iQ#^MN+_a>cW?e#3N(`LfV1KiDPrBv(TXeV5C!9r+kVImh~J_#aI z()I)of@vp^HPnmOpfJ@dStRG!xbm_OmkmhmAxa7;408O*A~a3KEn!{$2Dp3o+?vLN zr!E@E*w4tx>~^p_+$rU-Ga93R)$_*dCplEc_^(0R@~#jm*na@JE$m=U$=35OQcuF= zR7!Kju%I7k2muOmGpI0@6Z?}eU-^o>kYJqg3%SZJ4_NB3m9YAOAGgHz5)dO+28DF@ z;;xi(R-mCX?uZx@n`rWJLOCsyj(*RA#4mqQLb&#q%3LmU9mMNUIOhk8-HY>YL|R2U zy=uE>FCT6;a@RBprtZnZYnX&m!VIa)7x&6%!zk2cjCR2zj}UU__k4G-bOmL{XM|0N0-t87W%pJ^h@yku)i*e75{4h;irqDt}c4T4UvgB z`a%G56_+RY>7s{Sy_-Y*A}yfGxy zuI+A@n77pUUo{;V($|qVWP4K+&X1^5uVyXp$zdaV7GZFm@e)falUj7(7&CV zKAJ4^qS3$X=f1gmBh}T|Y8Rf;NksWN>IY!$fxrP+T&7SaDC*ezM-1MN`J9}|hyk%R zPGy5}%WR8bbo(=7e_v78<&@JkA|iH{@7gX*wYAOPmDu#Obf%Pt-dj`{v4Ba$cX{r9 zEG8`9S@rJZp|(Cc=(W1eJ^f4J;b8v(Y94`=t#wt1Ey3mUR?71Plo_%?aQ>PZv`pe1 z#1opal#=oJ0d0QBd2Dnj_ePY=&W2@CmPt#^*(~0LHG_s#g^p6YI8B!JATA3qfS%1j z*?*{QCY&HUWPMds((9OE32|Udok6eaZ9u#m!toYe4JyIRdlwP)RDX^%{RV zKlZTS>ik1ZYnM~)3q`6yAT>UHDwnf1W8IGur0`Mn4o0VzM0#b6{F}A)vYX@9n{dSMM|bhTaepXLjDL~u z0sOc;E6~<+gs$;)%nJ32$W2R`$nY2qy$UNkU{Qk^yS(%VfOsLjU=LIw=Z*kb=6U}lF#fF*#Zlsv=4HhOxi`+G{_9xnKi z?;1K%Y@0)-_1*mgA04c0Z&Nqg@deT(&G>2azm}hP{`O`9^QqjYsqIU7Dh-HpS@eiW zA;S8b=G#=yHhZsRhsflCvTn1Ks&KV#S)pu#VWvdvNJK^c}s8KJ}lB?j~Sypt&-4t%E*|}`8>E;3IMjEv^SGjy3ubr8$fI> zyIrj|()HRJ{0Da){6@IhO1a%mUfX({XRy$sf{25O6Gfz9D~c(OZo$R={LU4w)Uk#@ zVswem7e>F!?zu`N;&>5jx{Eu>PJAho+7_%`PJ=to|Dr!^D6`Jf4oj}Rij8h{@zD|{ ztX;_&>t-g>gWT)j;1bxf<6yf!`bBIe%-=4he4aT6gODVclmOJ(^qEebD-+Y=1s+B| z2|H(^vckCb(14t!%`;Mqxcyxa5g)EMMyA`&Jz@wB4VER4R?-xJ#^BoYlYRY3kPSEg zjD7HOfDp5g&k{}1aDkdj(#y?{7j-p#Sc|x$TPeHUUG5mU4KG{8B6X&_Uk6;*Mvu`V zS*b&_Nn{+`l}QpK1Z4rk=m5}p)XSWw;3S5QrS|wn1I7K8odb%<*bqzS(xeN8fp-Os z=-<9{Z}SKN{V6{urb~F9bD`!MTdzV9Ey@*~kN={eUwRdMK&tXvHvKDMv-hhj_!`!b3V<`j#C|IMc zYjL$P)g$i%LXX-uePwtO3vrW&z_4vT!a3jHJv>&bJ=*><@3J+jx6trh-Uv**9jDX5TIW;*(cQ}NI$)AJk6-B?lf$vlhH=huW9|=kAJ)VzvHF{ z8#wjD{VH}-*qj`N{wd4??X}|~L8w9{{8M_vxU%4Tu1uxY#~wwMi^D1(=${EwxHm=N zP9eUss)wgwJQk);tDqrC@rkMpyUY|(Y+p<$JzUK2L`SUjwg!zL&K@i@Hg;c1GK>>^ z1&VrLtm4Uh$^^34h;Y{M;c*xU1rID(t>NbaPuCfRqQm9{2|;TUtp~SuEiQ^Gx{L>? zgqrc$oLAnljX^WnasEFZ3V~K-;gcZiS&b*^oc3+HSUAK`P!RS)tHj#bp75c>^6kSV z)S>9zj{X&Fp`og`ip@VV!;>K1DlCU#n1GCvG)NS=MKt z0h9X1HvDh2wKwCV{Z6mH%E503FWu#GDknH!(6+cZ9w1TsC%tqx8F`&2#I4bPD`y5Z zhw7iFo3rx9y17Nqtv!Ta?@?qZC%UX6JiFf#E#}5b?T82xNzlOe(!0bA=)zB?NK0jX zoEog-q+te(@s(}U_8_V@QV3ZDm=IG((ybrdER?MbbGN@nO+>E0z73WNL7e5G084J` zEDH^NGqyeqBL;&8qP`!2I~c!+II+PI-m3Iz?TKyBcHL-5+fzS?bRrrwiY(MO8@Rnj z&G}^EEn4BmM?YW4o+Lo!p@aaWr=mQfRx$!vrLslj>u@ z_K(^!z#C@uAF?xW0iLomm(4xlqie*j`_ZpeJ#o(~(wmOuOHQxb#Yc9VXIM$I_q5M$ zrl!vX9t+kcTB<(lV`S#F{&wmFi-H+mC}-qZFcb%LOX>X&Lk}~YR|Fm3%^qodP#TrFzPu=ctW26+FO(w$e!;jyc0^A;R;a93tP zz{#5|cR~)j^^UofkLYx%YU9eN#DJ6lzF*>lCsgnIJ80{Wf9bks`tZss@=)p~;g00) zknW0j$@SXwz9zo-N{L(m_oKC;;R;fa2In+3XJSGex>y9VLQ){Pn1#7wqY6chjh1wR zD;sq(4!_=psT=U{h1L=iU#k~pJT%j@k>9q{0!`fSKrc)!Rw3k%Rfa5i>d2&?8LD;% z(pSq=yCBjSqp#}AAlv}X``KY_a{68SPMJikJbH749Anq{6&RWVHa*V9L^3>q6^mp<}=AW$c zN+PZ<7RhO%{xb#vJ#-qTiEX6Z_Cl{4&+jC>Z9*%7%B-Ku%cPB1(q_#aYPmx{7mh7j zHP_-RO+SutwBgqb{cLIU##ifUEFKmaK>_1xkZViN(71EE$Vwh!E%d_N>q_ZjmF^CB zU*(C0M_&HOiE;yM{fHi;RNnAn;xve*Ez4mouBRI8dWx2#)vD#3kOb+<35C?y|3tnM zMRV0p5j(nRkey4jQeM*ASfji);`q)Jvv0wq;Czx*|LdcpC*3;(OSTDf?7n!V;88i5 z(OGKu{F#H=I+5k|HILAf6NjeTDbF8AL9OTd2uvh1+?i=b&o)zN3*5#@+f>|@tfAHz zzrFuVZ;7&vnDjIkaviUUjyq^Dvt3x|Tb~A#Q}k%>(r@*;8b##|Ydi_T`eU(wSgST? zZ+GkS739cGN^D?8y19=4KhfLBxx(l8CL7Q6U}t`V?oe29OgQ=G=cleJL(Q>4U}aC1 ziR{RY2E`nM!aitpy-^HnIqlKSmi$bF;F9YO(cJ~&I&y{0>n8AUWr@We3u*&M<1?XW zk?Ri`B=yJTl#ldDzUbQJS7uk}4tNN?Vb3i~w2X<;&ZGFgUXJIWJsaTXwj~uG35%A} zlu5SqQAD%Yve1Bni!~l-C(Pv6ABY@i{DpMBny1ph06QoR;t+Y_9XEywdt~ztFu$Z%J zz0+X(VQY-IMdf*T2=0eq%59XPOg4jlpT|w;^lLf*7;;9^UqgKG zh*d)T4+2n%;N{Y!FeIZKAdX zu}MIvPpR0Lw#j&Q`NVqo1l$S;ikD^J6vBdFAT=kn>0uDL`}I@_W-dvrK-L5Nj72cKZQHVJN`WB;wvzETc2FtvV?VEcELYX!^>&bI1SFPr-~bF9h4dB z$pc4?Q=nyg4JrirXyOQuYT`XI*MGY;tU3O!oERx9*$W=}!)l1ZUdJ*g~8Qb7c z5gb*L5dLvb=Y>9vwGoZrxt1M>8&tny7XK1#Y53zhX^T!0alE=5E717-ucD0bCg$_{ zAC9~|ueV%`>b!RU4i~eTTQOTvca>dp+{{5hxj1G(e+RACT`HQ=l!M=tAD2 z>OBY{A$)bf0Ag1#&(}N5+|76Eqe= zW(Mon)^#gSu{gaI$OqLG4TcAT0Bqh>r&+mZVHg|j{+x#1v%_fu;O*?keu7LeIU+ey zaFOFT7EKbC!CoLINF;4_NO<44adGwbQF=Bt0*g-EHDb%G%Ly?s3?lX)9G(7Zh|5#Q z5r0qfOl-V?rWSV_;o_Wkf3FdmAAajj$Gw9KCN+gn_AdUEs%@=1L0n&axSjlE^beON z@~88z%o8&%xE=QEB%HsyJjc9Igz@Sy0Udz+=RUyp>^h`0x|niAXylht_tmLV0n94L#R85XvJuBDOA0J_57GI-a<3n@^AY)7QLCRm zYO-uSPTrZJpO7WUWhC{yl0%dK`xJDO36uLOm^{0)NK=TgevrMAfWaVmrG_gsgt#E* z=~BY;+me(#y4!3;g8x>g z$>m_+XGzow=wNh_a06QD_ZXuF8Lq#U{XPe)RqtQc+6eDh?F^aiFP$LOpWNoRS7nS;(0vg+r>wcoNS@XNntG%%2%1x#%hWeIATmoI@g@!Y8Hi_Tw5nD=0^;Ph3Jxy9tz;%R~kbP-Uv=U9Gsf| zI@YD~5*9h{M4lE}jx6mF_#Q|&b2U?!ZM3k5INm*L9+5&__+_XCOaE8Ox-9uYab~gM z+OKPV85_`5FMpdzSvd9V>o=oMDzf~ey-e|zR#}R8V>QpWR0~;=_1A^NAP9aGg($j= zzbq*yt3uo{^}W^v&@=c0Z2TGV4BP2R-?MKJ&5`!Tfw=^!Z>lVdjDr?Czy4h+VN z^0cwx&j(L*RliSH`%0OsNwte19UXmwl`5d#zhVfs&kEO&QM4Ax6m6e7&UJ%oHVhPp zNM$^K;V8p_9eWAj5Qd0?bG#|~-W|Wr=6OO??5CWm*xahz$S!i7Av<}s;u0|R0LnQA zX;*I-_jdg)QlLc=i%rN@&h5Y`=&>5p#tC5rW9#aMT?~pv9`0Y;u3@9@b}qKvN9;u2 z885u^Es`;l9<}szSFo`+3F4uB3EY*)oa>(X`4-|ll@(k)Xu}R)E=$lM1@Z-xn6@CC zTsI$W4DFk5rfjl!IsBtlCHiCHiz(yE-m|r-{q0=gyVL5$+pHQw+$b?5agO{={EWE{ zo}7LVM)J!sx7n4o#~+F6ieJOACMgFs8!{km&wcE?<2S!=8OL@$@cMo3N!RlG%W~vM zlOuU8kFdf=jB)>1&O}UQBdaVZ8l6J<%=@F3XP^WHOvb5jp%KA|K&FS&pom`IdO&8F z_-^@Zs-d$}@Zv0{(7Z!fibT&4ZD-vJ+8TvUtW>N}fBQ2E3#?p%oOZb<_aDQQt`t$d zXq_SkeduFR*3UG)VF(fP#WYUg;Q(TMgLQG3#N;8&mF#TM+?AE*GX-;&1yf`4Okn>X zM1xZ!FHI_-4s3I`Z$E0Z#jnejka9eju^xsLWV>w71u6-5&FZMo-5 zkP*FoGPO+Cplu8jtU$5azZk27l;=NGc!zIkvHaI9cdbHJxx;(m?b-cOzXV#?t zBUw2t>Fo-;7Y#1W-4n%8nn+)sXWeqmW})}@f#wFklm^i1Y{p;D6o1Tk0<^f*)(md_ zfgDll!2* z(7~m;TnQ<1@LrT7LJb!IcQIzVE*MZaQ3#9uFdS#f>iSkKeW>0xQdD+(iEBBX*f1!I z9yA#*lRH;{;TI6bAFl9Tc9?4L1c!Sh(;mG<5Q?kJ&H8rnmW_UtN7j@v$D}Bav;0>9 z@yZL_pCW!6xY}mF_!u6z{}2ba(Z6Rj!D8}rsrDn2DZtbwDF$;-(*w$y?XjhfjHP^? zmpvazp&of*U030!?(G|ivHl{8($-UUNJ!S1N%RbcB~b9Y&r=I}gu@omrgv^MwbSIZ z_L@znD=o?@wLH%78;j;?skWBzwU~@HC?nmejo^x z2vYCwOKRV(n0zk1L%_Nt%mh@QX68~rV?<^FZHSchsNHf})GaICmXLCGlS0tCrsS|OmxKBJ~m{3Ps(_>|@R4LE*`uU+@4h(-9pBAr^i_TW{0TQ`?byfeYDh6g#^>iby zLlN(G4jG(Pz=hN8;-gj zkHinCCGMM*a|G{_>pDxA>sdsVZx`_E7`cM=v#N%^A7bd7`ME~PY@xoi`2D*T-{p>S-f>jgXkpB6yqqid!+k>l=6EJblrvcs*`nExYk(Dt zM#syyqc6AifcPLfKQn$aG1PZb6HG~}Ou%v!!_~5)jb<1c-w^dm8Nyr+J!mrqfO2pi zBE4O~{ZtUzw)f!2PAfhDA+%5i3JZWaU3MaVA+5BCk(imszF^tfw{f}-)NSj2gt501}_sPPhu9m4ru zOp+;(vKF)8OnixDBz54p7vuGQ@r*4rcw902&Y)4Omk%Bt$Sq>a%^Hkh;!rd@uKcc) zSIHxqgjwbL4%?$-^~k0F7I5+0PVEVL*cRh;&egu+!G6?6pw`AYhv) z$@>lMVtY&;Xn%2bt@%-Fg!VrD(Zls9`WU$nahz@NGG4fJP3f16?ezy{-RLDfRC6hE z^Cvb(#`>7bKO{cvIfoShPCTX(ju^-&F$iT@YdhL19&5pI%by)t6-g35*9nSul< z)*kYc?lUHz8b!+!moS97&I&@1UVJ(ayBRa1==om=qRSBCWRm7=OffuJ+;EASBtb!j7qQWj|bAVfKyiT1d*Mv|iU@89q57ObV{6;xC3jc~ zzBh5~OZo?pNFQPr@6W+ODrysPu8)9v9D&>FMuM8{@<5M>k9HMm_yaY@dWfE}<@mu# zc|`;3eSss2{9fVf`{vV?b#X)@RcvCXUO=x1!6Md~sGJB<2S~pxxnCw3SCJA>xhy9E z85IoJ1---GKJ*6E@{An)YG=8p8ekq5M-J2xBT+pMdKip3fkeI+_8bf0tVPB)(T1!~ zfRCRX7w|-MeEGT^ZKMgBrpRMVO{2h(KCp2jmr4~%K^0QlWC#6oiSVyP{9=mVX2j|G z{>~ugQ9fgC0i&j_ZAafdnF3&J2=TqrV*lQq`87Dd&aVjniIa{dJ&Vj5P~p=rqLWpu z_pO~)WlNn!WlO!Y>3kpBqd1A{tyIjx_Z;NQS6s6AIm(G&DNpQVlFVb@g8L{=$kxxO z=l4X_mjJQW{`A)1Z`39=n^6mI%|_lLFAo-IeoB~jEiO;PH3!r!sU*K!N_=QZwmdi7 z7rdTJHT{m8_$aZojKLHr$S|AgKf;*!LPf&1K6NkmWcY`$29OfS>|^O`$xoifnK<)F z=#%9qW#3m_7&3fVbSwtyQLOH|s!>U8{VUK9c0w!XUaO6Eo=g{9QYYu-?X=fb@MhwzRtK+^KjXq1f^6u0U7V@T_iHAxe0^cT_t!T3Que&`9}2&= zTT3DMuN0=1m)6bcNPP+Jr7%?5)9{#?-bjC2*Wih#71uX(m4zr%XOI;-)wy>8u8J&a zFbOVT3xh*`S4ePwvA(0zz4ilY7_){7%i+jW1&z;7{0>LUuC*^roh^3Vf6Jvyd?czL zqSDvtZRZ|g=p0~JEt0Q}WdTsHdDKtOoG=)_Ii?G%_6m{xl{92#z5`62nYLV`e0H9! zdGPLJL;&q)kai@vzTLwk>~e!2VmsI^&nih=(D>t~ss4I^THlM>QdQAcnL69H-5&MXfa=%%*yY#`>JC(d5ejNLh`AT+6Tn%#m`5;-)cPK+)6drvpZ`k!o z;0PV!@TphIKXd8dd(s|U3LN8Rh)Z{h8z)a`fvUSA)=D%LZZ&dAvb`Kr@;!CQdOB-G z8r7x`Mnq$>fER7~-q3}{s_vplo)0@lU0wq-CR{7R39+IxGh#yuX8FqbCq$+V?MEVp z>1_F|gr)?YWSuS%hK=%yR6*JYl;e!WXzwZQAPFcO9@PST)oL8Sp#m)OVS}QyuDt!H ztj_t9+cJsulOH9sRi_ibTE%WX*0#y~`B=LwI^Wl$Nm}LQj#airnO}xj{>SjbZu?1? z^2^hQqF6DRibtDl^oo655VS%vF~qooa@UM^yRnQau5w5{89^#NA$4h4G~e1%iG#Su z2dYQ=?^dWHBlA!Ehsr+@ueyDn+~M|)5}O`m%M0zUXa#+o95t6Z>{cT!{z{}djXcS= zJfPe7y=~@x_jc{~0B1Duf36%Ha$m?hR?+n?c1LO+E=@c>$Y(3NAg1G{f2mIf(-}9Z zZh2Nlg&zNDaA|a-*?KXU1rn(=w`78u<-JX$UUt7c;kwurvt1qDlju?7XQpSV*!cyw zic3UG%W`~~X3O^)n>tcBaex5m7u?QaNG(huqyu>@{T`4vO7^14x#ZLlD)u~!3}5dw z7g?0=l#pzBdO9Y=NUsO?BLN7~ljehRRK1}V+=QZ;%F~IF*s;gdj$RK-2W*AkTMJp9!ny=}v5=bV^KKPw9fP~kHH!oWG1s=^RM6WVr;lrJjQ zqNK6W`QCC-?1qho3yq!uBZz(Ln??N_$ENcOekbxraH9B$k-*c=(W?nZJF>;_mrdGv zF!I?xjC z!?&+U^e;{HlX6-Z3v2d&nVRDLj*};J9~`+FC}jV9UjMeX)%#U@u>mpI49v<56?bu= zvTZsdF14|aa*!ML?*hC>gMdw@byXPrdH0UKzFO!iCkKhccvfh&d> zc^Eku28;Nt11?~F8Pam+^a@STCus2_m5^XKgpky^aP~;rjLI-yFo&8i0oSobI_+Wp zDGmp=MN;PTd%A1OUv^FJBgUCJ0yfizfySDjgsx=rUQ`fcU?d& z87^3Fb`G8VGW?H1?rO8EAFOy$6k@(LbGSUz{vw4CI%MAJT0^=o;0hfV3=ux z&lGO(w{9k1U+LH^INcz6P`z^ja$Sf;4PfRxWw`a!>eH1;vnA&}Nr(cFI#^DA!S&Y$ zh#IBeCnK6ey-z$YqoAdP%m7g#2(s6pOd8BN!&H{Ky8xj=`yS_xuT(we_N(ulBu8F) zwHcl>>HoTz=F^!tbm0=KlA?&!#HQI*Fo%}mrv;4-2UArh`2TSA)_+m9+xzzbLw5`z zJ#;q;0@4oMHFP)9DM(9q=TI_qcXtSg$j~6Ik^%w>g3s*jeSe3z^Nv^>>NuW<2*WU?2fVOmP$H&tqY4Iv`fKf zhNCJ3)n?@Oy;AF*$Dr_|sHA309QhKxc}8Be9q?QKziPPu6Xv=;VERx7`1xKxOnaN_ zD!}j>afRs?tj}ta-;1-?ZJ2H84M21OMrww9D^Rr;qN$0HL8p%zxydU<#B`Fqi9H6- z3(kew^CKB+aFxfN_u(u~5Gi*lif!e1C1QAX>>0k$dOsX~-e%fN|yn2Cb>J)Nw5}tk>sEi2!D~FSE ziEqNDlvu{Vxs1n7Ma4w#+vu2Wy@)BVQ##gzt>;_1mAh$pAb*GdV|I!d8Z-Mat4S7< zAfd%p&WI*w45ge^22{Fw<#f*D{0yB=vNImjuU@*5(&Z4SrFbzR$_5iVBGK|I$0lx# z)%l2T;t|>^ycHs z4F3$M!gdmmvgxFzqp6u;BsF_Xr?Wk)Z>@{l;`Hri;%K9pFnqIEm-#YNHP_wi0hqu3 zy!ZE4l(UUh>mFM?C7vYgu+l)j+^$+=3=0WT0)eUE3KX!kURY@Ar%=lkaPsr=UYUx; zx8yL>L}->Q=(F&dba|gWzH3_s>$(1O>0@GK^YTBp4u)-a(>cP#xttVs=5H-y*Ew0P zS!L0@gK@-FZg%ov*6&bD&wyWPDj5;=6eEX3_qf?t*?GXYO-kI1qL^jCoZ^X|>l6r& zF=`RpwjbpJpl<9{n;IJyn~wi9hM~oRhSJZ?eEZsfew*ujbKBi3(eh~ysYX^9u3mf{ z2{9*`5_asWz1^l{M<9Mq*FafypoTfACyM(e>x(MQP`wIve7`HZdtc>mUz|8f{`x2X z{{?BiQMjqLcZkcIED&S10x->=|7s(kTVi3RAbYQY*sz>!dgnm?lwuKJyh=u-2OxcC zJ>)C2yYpb&*}Y*kDQ!jSs~Rb|oZ}R>$aM4?SwUt%Ri8Z=3uP^DRhXmR_lS`A*@;4u zL7FjB_|nEWW3vkbouThOKDHPB`5xho!H;$T$bF@mw9J0+MB7dCi!-E4G4~bB(>qK% zg;A6r;86*6Zr}poLTo&)M8ax|9i!8@FV<{F$g20t&~56a8VR|-ALTs`jJ_9V`)ZT< zsmS?a9S;JBGf)s9Yox@S)ch^jRzN(3Q;DyU^4NZE#XGahbUS@Waoh*D`leOW9QI0V zWnLPRUsot;0~&Wu>~)G-L44GjnbJ;QW=kj9kGgxQ5kad+|0w5r@9Jx*0|A7#@^8EU z-PEU{u}!PR1K5YldaB;L8Jd|{A5jPI`^ar0Gh7kcQwquH`$c{^0k2z6rK`stx1G!E z*jo$@>UW%u2|CeK^*s* z=J%uSvDX6oa=3r3vg%+jwJa4?{)C09(%~1vuCa29cKm-*ewrnnnQ->2TGd1;3x$XN z?o5wzot44xDy=e1F5qd_uL(OAP_Lacxc+G`h*^y5j$^(mVT5~quCdVRinC;%>_czt z^}PyPABw(>!y5h~4_`!=+L=MwA^`?8_O6HnW2Ph_fBWu1_L()!AI5hRm~gVi>J()Q zbx47lJ~O)WI(l1?s8js}@4aKkc2%6;et>QU_DM~(wylpkFf@kK^U3&!Lywk1g5?jp z9e;~P|2TSwUSUe$Nx0p9mWx|wUF4U@i8)d!282$2Nz^wf3weZlLfzj^jz-HL{igJ<_iNnTK0PLHxJ24u(r0@BrG zSKMzM;y+8hA}_!QZN{f`$LNZfUD8ssIWFS8=qyJK?G&mF<(GMnVjCFu>nGmT1;^0^ zl~Vx0Bt8~sDhM%YT|3Hi_BH95mSMG43HkEP|p0DoBeGRSLSL`Xp!pn|>dw*G5?rZ&{;ekgV$I zS6Ws5e0#+_$!V9dFXck=*Km}MV5(Y0Un6UCZrg|5PV)3RUU71M7QEb)By_y7v5@5F z2KLC_OvwSpr;8^Uq?6g^%l1YFAFY1I!K+ba`&t@eTUC9fau#VlS`rQU16-Es*_>3` z@lqx58WQ%-cw_p><^FEx|GQukV#U{IANA=vKCh<-;J|fBVKF>`-yTdkS>snyD$ZpC z6Iw+=x^`waoVNNDCH0+Da_g*d`{y})WS?OBoo!4Mt|R5r>lPa}?#)qcm*bbtA7fh3B>%uJ3YC67jwi2oPZsg9HcA0`|j%%@T*)y{7> z?3VB0(LXVkrG}*fIw^Ht*Z*n-HMe45R)1)&URx-#{DV#-;#jyscO% zkbCmeck9dyd^k|kHr^2MKZ;ciVx2`%dx}?hj{c-pYoFrFFyvL5@`i&}dxO+^0^6(2 zKG~Lk3hdB-j;ZX+hv%MbjnhiQZ!^Bx)8T$U$AXmX7htLGGAc&ht%SxU<2zg{%pO_@ zW<%$Y*D?APmS(s%hL%}@3k-p2mO`^>iJ+59N*U4FkhsTiD+)$C_(?pj%fBB!gA<>O z1BrkBncHb9*bKl+*LKB1m$8_h{!Y1OA;j~7kn3r_22E}Ma!Akhf%CR?i#IyQ}NLpH(t(yuY2r=HhC(N3jS+6idLBzppJK&L^7Zo=u{{w>o*uEeoxh`E^; z?j3n1d#LhW8or`xdfwklsyez`@UDhA1BXnD2!Apl-f{!QQTSHB*^r%`4-Hif#U(%Q z(NO=v_9JAHSp4(0`;|a_ad4>ki!o^-jQUBXl*zkoUHcez!}uu1^fmUd=hN~|NL_+8 zzh6ONUn|Mv^i%9NYALN(58*k74Jux5a@k+<%9r}()S0=$*++Sz<75R99Lg;w|wcld%0Uu?kuYW+>({w@}6OgRS?`^^v6Y zQqQ{sjEVeYWHQM({R1eE$;{hsgA*Ut{t?~mHoxk&bO^}s@l(H$G{ai2A?jgkd-Li~ znRw5*A0Z;II*&b;&Twp^L_ZWvnCgY?^FF(_=hS`>ag8sRGL#YR7*y3{e4*{Xp~sN3 zDPq{WKD(qrDwKnZg;RyDIpo$cG#2vKF$8BQAyK!HkTulb2#rOQ4SIg#>_mST)Q|{{ z5hd2j`ZDKo&Vm}c*!nC~o-9x7;BA4|F!4XgjDJ(U!Af#M^pvOT5BzQ~a4~A2BH8wY zuB#-{xa!(hl0JTmp5|-l9pt9M%OE)lkJ&LXePg1ic+v8>_=ixWj%996bj1bJ-O6tq z#ey_Ynzgn{pTd0Q`3#mG_9)syBZ`m5EKqbG1=9bd8@eP+kU+fh78DXyd;wZ2=)ifBORV!L zExWArG@QiDbo}K$-TP@E<`ZPnT;=NQZ!0^y9w{gGbfgI=)4*&ptRD2avRbJon$8to zk$S4_g}86FzW=OVNoaI2I9VthciAe%WUH!Uq^g)|&x5D>lPRYUj6WbKL@=E;pQ0QAW_kyEI7 z4J(oe#uLK1$W$vzccea`XVa>nptgA0WfkLh>uA2;=m8{&3Z>+P6r6ibGld@ilQ;j-89KOCE(O6)JHBb~wNnXfuz6iJ_&%#?iUw5M*_rxP}b zyVYpzB+rtdQb_67pWnTUrHV5P%w(m>d&VA~`PFgLX=5Wak`Bc-MUpU;F1A9CJ3undLcpMZSE69-)&G-J zq-VU%5bg2Hu;r^pReN2XC9<4)TP0Ap#CcJgiC^Q{SfS&53b||!@iIqBy7=|>i901e z?=2lriI&BRi4l9E)~@tRJ4ek3RnMHkE@eZi;2=%@oR;UyCc4M;`y7y?8-7caV`cU< zDo&y4*AaU=*oWW5bn69dyy}T@AicHpqHY!~nRvB*A>MaJcV$OMulEsRjLA^Zp@b5+ zgKQ;F1x~1?$9f^NSC!vn7*;9pvIGs@d0Q7SFukzbo^g78phY@BrhFpl*0?3o=2b2j zq)`Z{-Aa8K%#o?vM2mUiYs~Cc2D}N3@7ZX*{?*2!?sFIZjX2^QHm_(>(sXwp0OYP>KgtwklRx_$bq)+xRx#1ou7Md&P))sM zsN#$8CCu+xkT=FO;!+gqQ|bGXpu3SPg5o19JLbk*Q0(d+(mrIT%3B}sA@`+h4cTHq zxGw2R&MLY1n0ObvKn~R?)hITAk60`GdGBj6-7$HZ^G8__MKUY00CIIf#jtEqPnp)$ zoYkg@0vUp6c6?10EothiY9#Riy1&gQaUnwSRlm#C_v;b4&2^wC$ngf{xbX6LjZ~#M zzr~Jge!?waVy;?5&}%eLrk--OUFQxQJ6nE3HXY zC8|nBG5qsnL|-06{$Yb40eQu&`bIqXMx3%T*_spTp;!AAT8fb$V>wTpGRh)Vuw z+N-??G*fw}J=}0#ffCu&U`UvTSxW^4{?_Rdu%{I(a8?3>jdNNr`e~`WXD=qtOI<@j zVzHmRMl+@S#!7B3=RhVkE-5P zWv|?-mNpTbKk}JoY=kT%=c~>Z!RK1PN?Hj3!Sr)F(FEOqx&P0?CZB%-_8!S&(p(cS}QH=#WT)U%ZmKnsrUOr)U$kcXp zwEsFo#=NQ3u%<{NtuFM&64jhSgo9n=06z{@7Il%vM^rZDx638x_P2WJgZ}!}?lah$ zb=HweL3QKAvTXpFa^H(&WC=iMr0P0XK;&()Bq3`U_}-^x0>ZU+#Mx#EtVZJjz*I%k*W3j)WBF z9|#k}&p&7r9RF3oyg`jgeVYHA8{M6&fvD`>^yX!0E~AjOA+7k_fHZuM-yi9P}p4xutTMOjcs)bcFuIz54KUogUiYr zs1%(3GIY{^5WBv>YF=>+3L*E{=cTJ66o&PDO)ECIk?J}8+Tz898Us1+H6F*e5ur&j znfDq>0roy=1duZ(LA_Uku2g}GQogWiIAWYqbT9POF2WKpz8JXAO~(nI=Y*F&Jl3pT z)jxV^GgR*HZU-i2{pLPu4&X#6680-K>M&Z-EgZ`1(!AmNAFcmS??)6{MY^YiF~5cd zQx=07$v2U(Q%*%yLAYl&Fv`qg;~-wM8c(uJ09ll(>3Onol442 zkl?|<roy5bb3OS+B)EN$)lB#Z)?bd=ux_$G_o&)_rc$KLU&$ElplHjGX{V|o4; zU}3e;88Lw$$5)!xV7I2GM?tkP2ld>Uz27R&yCT53+;edgM6lYneF@W}$W<_z%^YX* ztSq#?n1CkI!0K`?zpco6ou=aY@suiWHGQ#0`)-N$oIHM3G&>Jpd<7C#plo6>Sl}j( z#z`q?O+z}4Z#hZMhz{g*Ds(xMcM0SkiJS-eH5Agcz3>9lH}LPM#g@2mbv*PP%{?WK z>Z1~?6yDk~yZlR~Az}dk*NgLgYM8@|uAMKe5xogpZ%rPz7D(@_6+gq%`b0t#Komw| zL{CmUO2M5u`p2B#I2@>C-eaTfZbycSbk3eDx=cheazzhe5V&Zy_-C}Do~3}ZAFxhn zome{s@F4{=G8kr&??h#k9unWpwC_`rOl?SQ2;the+G@7oSfSO_UZu-g3E7(`8>SKD2V~ND4!OT+xTLX1 zk7P>;Y2lJNxx>{y&BSt=ru)tQaQNE8Fi<*0R_mkHu=`VEV@wwKDTJt(=|lG?K~mp* z;t~J7B#CTig_0@Lkj8BG)c8avFtskD+7BJ+j1+&#)*;C|grhiID2ym`q&@67NUvbk(~u~9PqaR<(LW!rbfr6WYk6^t~JVj6D(%W|5Voyt6d!T z%;PFxLpzu`ymQR8Cf@a^wBn~}qu=K`MSy${zirase#6Ua`mUUcjq`@YB-yD3xe&>w zJ;d%AKXtW*V};9U4)!!KjkPhrk2dzji|6!U)*@Ec{h5{1cFLa^6=eJdO-m&&Gw&CDbRrOZ5y3ATq~t(L z?n6Oy_vNtrn9A%@496*1XLD>KBrolDrLDhh(R%p!Mo5-g<9jNa-&kr7Nt=4;8mEhL zdJJy(>F!}1@;5LWTZzfy4- zB8Go7qE$RGZXZa$EZ4Tg83O0Q!Li!jr`!t_*7VQ5IiVTp7&y}#e^JSV^Sx>hD&1d4 z*Ca)VQjNxWAbl!m3xlk?DP7B|7Bzrszhr@x*RHHk6aYz%ptMW!>iwuc@oFoma;kKr z6T;LcYl{I7?DdRoN#jhJNwotTwcTG%a%>$wM49fF8fgkxoTv)@sm-#G}emvVO39 zDbG;#q|^Mcbrt*JQTi%{B#5Ia(bzj|LE?>^GJF({Fvk@?O<+2FEHX}ZT=~$|kd$^? z-xh}Lri<);SAMd~{$XrF!`g;)oq3(#1pGsSH;QQcl`obj;JT zgIfD!W6e3W`+eO#ik?9}=I7qf>b{kMdU?fy`ZrLywWFrBD|AQ=Vdzq3P|}^x82+oR z@ulSW(JW=hHp+FAXiZ}dwerbwN+fhG-uH%ADtVQc{y6*n^WSDM2}eg8KW@!}=(VZi zD-g$vEJ_$3rByFFtp3(I|BZu02ESYTt2f*cGWej%r9e_BiEQ1e_2yafAdC7+`RR$-SM&0G`wHb= zD6?~yn1Q{?Ki+{^m3_VGpt|vN9s@ znJA0#Mo9{KvxWQ0vNl>&qNuj{$Dc5)Jb#9`7>EBY1Q%tH;OEaWq4UByTMZ08Iw|N% zJ8U}b+y098w`JuwEqKWjxJqMaO5^lke%5nz?Qm#C9UbW*WJQCyKVv~oVGhO9nYrKp zDChqopRDPQ7d3|}qxN%rjLS;s!sW_hQ2_cifdERm^f6wQQ0pA)z6bSFO`+*uYwvs# zFTk`5BoDd=h-uqPv!_RjLGcN3#bvDi9J*Mebm_X${$HSP&Zd2-1(gVKutqER+95S0 zK)l9#L?E;N$xLkh-C|lIRt!%__-V5OjXZ@#E}8PwOLW1tn_;l`HMU+ikMFa_rj+5bLV`;#L)+dTjCiqArm6Ooa(mAfku7l<1@0X9UTZ%lj0`m~ZvW zSE|@p;pI4rV>wtzc*yKCL;LJ_p3$|pB;|Gb&0|FQ_o`ZIFe~Hi@}(jT{^N9mhQgdR zsC}L;j2x0XJH$E`*>>pW+~<_@@N5O0*+Was)S>kYC+`}u>ThD=nD*nU2A6LBmoBt^ zMD&W86w#!rNn`@V1mK%KUt?IT5)U2HJGx=|c5RV^FaULGS?kniQ4~uiG!6T0wQopZ zZ(CK#+F3qDY7>WNbBv2qJQV{NPfpgZ{fmVk-Zhqkp2$<1tD}#~l)&Fj8v^XkxVx9) z?F6EkzI?4YNKmbWfEZ4B93YSV?0G1oz`A$SRL!$=&^Gn@FxIB9sdmzt&m4BAVo zwv=DtaB4QgD$b#mT;0yT`)vV<7EI7bD$#sot6suqCZ~F}+qaBl;D_Ix2qetWSel0- z4sDFlK|M8ueJ%B{C2ta!QEfv^hFmWK7dtM4wQ{S2N3W*z&X>9%1X}S8eQNtv_gAIE zO)Ebna-RK0EWmT2AS`~pp=)f^G(mgp`T0usS$Bal+j;6W1By_J4l0Xm6{up(c@=}9 zGd9HLJdym~^}J_m=v`~)W5!2yoVE&0BSpqL_Lp87IALjxd}e>KcK`R_-$DO4%X+Yb zP+p57=rzpvT;>;_lGUiY%LTpu1D>vxa1Md*NG-_zeLAv}7nl+9D#zvS4~(3 z8_4HR8k(vaM}zVh*j)qCPyA2)Yp)Vg=jrW4-dWuCK(CmOhRu&pKapEr!`-K;R1=`M zoTFAHJhnBnddmg=?>#wwc`-qYj49^KHiBU9UP3j@%t6=pB(eT~&l{P)RPOH_snM3n zGkn*EbUV5Q3kq|0v(pD-%hF2M!tJ-=QHjeBMm866zLhj+l-fu?DP9DRI?1Z*%w)wG zvyNdB$zl1Wo5=MczaDf<7_>oGoFxP3>>=37Rpd3RB0Dz!WObol_a2VMWq9>1&goND z3J|D-JAsoN>PcDlsRBG0KV9cCqi{Wyv>#)h$yk#KfEc{pw|Ld^BbN!$$?#nf^0b7f(-ns}RnB(&5l}2pV*D8nP zp(9SL8s37c7oU%;EW`0x8*k^0y7dhR#uN-i)YSWG=87~*_lLQ)evki;EMbt1j(F3A zh|q7w^q@(TggZIda#J!mK&#cr}welXt&N zuv+K^fYP8KN$p)keYh&1vorw3wHBwmA{%2;MJr8muvQD{`b} z2t@*5TqOJP|B5iDM&u_){NslxGC?Lon&{VKiWFs7!3Rx$2rCW*J1UxRg;6iybb*BA zlikZORNHU$tr=u{gOqQPn5049^i&;aBs=)iyso6WBl;a|DfQhZqn}m0Q|{1Nb&H`B z{fn>2)E$~4UXq0d6N(8|2G#K;bTcfI^XE=RifK{5w!k1=hqBcejCR>4=VjQY8i4Ne za(kpJYLE!6hlT-%EHu* zb(~{#?x|1?hTk1Wd8~=c2%csb1U(*5PE-X)1a8Dk`GFi(Wu$|OiAY+yj_$xt%M3kr zb#;h^>CwPG>$$SLLJEDgiVGLjLyEJ6{B1zN1C#M)La9n>zO5o6fKugS=< z^{U!OIjoWdkS!=%Kcf=t7p)uW>%pDhmjXwi_EcF>nweHj@1gTcYGF9q=q+H5d#?+B zrqJrQti5vz5~ug&g?mItG_YfzU1t?Pw1sTMSoF9AMQ(0 ztV=D!zoR5GO=mAsNtM1<9r?LE5qE{d>ey08RDcxZjA`z*sK)~1Y}Kb%VTV`1mevZr zBbTxd-DJK^pY8fahHEz`i6ZGx55!8QHq5$Bx8QUrJ#B;87UJ}dKYYN>bpP)f`d4YO zoxZdzc;Ml$6x-3B;rMZ`Ucr*sRr<_H=f{eDGFJCfc%8Oy2^x?nqQs(xTxdBXZzN8e zGzFONI{xgCPF__tcve^8q%1ET2iSOm4xjxq00kf6r3K^ zEb67{X&iXmHotWqP3b@tG&Td+AM;2pR~3AG8e=1mTju2kY7{V@pU1PSE)la=|8q+- z{A;E`Rx1RqzQm)gYTPDmQe8uh{65Q`yg0A4}?kr`xQ z^lH#vjz9wTb|(LBuydVIomfd;3dZ>%w7b8SU$rLQqE#D~C%%W8B3Au+1*SSLjs~5P zoY;?gL`3nSHpaN{h&siW1|YG)k}s;N-Y0Xmd#_m~RL3D_g8XU5sh&rWeC>|lmdT5s zp^&KBj8;t%B2KtFn3*z-9y4)2RY!ba$>m?Y%IStwfB>;C=(;ACmehl1U}Ce+Sk9$| zt}|i-+49EBD&iAPB`x^E?uOye>;k~ihmqZ>{kP?8oL0x(Epl0OBj^^UUQ*Ej`ol@y z1rj5PXa6w%|DE{qa}>S3fCHZ}irv|~#-wX8XrPq?J;RqVLcc1mVAlMP|mJfFzZ659F1*XI1rfCqDn&4S?`Q5d=pqs`{MB!tYF^FPB$(PO&W1h$x1z03KZOpSD<* zcZcHE_`)0F<8*^00nEujKHlf2!}iolUyobs+%z-}6jUgCey)5bZuUmGv0c*xK4obn z^b($6VgVgF)BbIy{)>mxh!#e6?ibJ&SuJ94#h%5Ii3;V^i?8HNu>y31{$$q6C!Z~m zh%_+;bQpN4I-+Z)Qcj{-QwlDmsKtAw&KA5x)&3L86RVx<)UKdPQLhU_jFYzN!(#oR zYWBN_R#(LVKXj*o94#-R@1#Q|55kn>`md zzT2&}b0q6t8!!drBB9uDVA*Q>;M>Q-t#n2(q73;&*TFIl4i^>BSluf*6;amAgJsO7 zVvv400W|>9u*(q`)RTKd(D*LQk8?xH+`vFW(>Es}i#B_tyryf~aFI_nLf2b1+Wb4(!(8#;{BZpXl;22 zCG5D}@M3V7CM2jBO8SujLCAa$mx)qFcSa6t;|L`?j$?W;r@uLl<8U;BChxitszDoM zCTPcme{zo(|H(z^&05p&TTHU|hNv(#7r{C16UNC+;S#b{ zbO$z1OR;qWuvfa{lxtzF9tKbDs;m3j4^3KHHftSxlV-nmbbiwXYL6`$_h8lZ|K{9m zTPkY2Yj%x~gBBM_N~Mmuj(tw4s_TtwD7x7*zTW)S{2fR0f+gl}Z2kor1OM#MjC*PJ z$8Tk}b-oQ{8SWUR&ek|a0qXI=>~HF8#$+m_Lgy)%+HNgnlv2IMpCv5~WeI6triLyJ z95P{Loz=X@mi+aQ^8xXyj$Qt*Q1j zuI>tt;W?X>Cj#4`JNfCLtc@m+Ga)`*kB?&Kg+ePRHfnHyp`FrJ;l`(?7IJfx6Zqo= zswPZ78^bzrYh-<*9WF3QiJX$L;sEmK@>DZZ^?c~nW1FrB1Cd};9n(%Qx=r*X(gOt} zC(8Y*xV3EOIiubAc{g>xNmF{G!jAam^&Y7O;#Ir$*knB$n3d+2cqLpkTQ7NEG_^Sy zjlZkWHhWn)n3e1J^+tNIBOgUWc+~!k7g~ksX z*VaDAJ_-#8i~c_``iFe{x|E1m`^hVTFNN6LhiQVYve_}rZH5f)yQ9eaVv{RU;UyHb z5?>u}ceYf0Xhup*ri&*x?lv&=%*NeQE6$|WqhuDyLHeF@Hv(1dSqr8u`Mfl&T9ZsS zmq9S1B6RV7tlV@!;fcL5aUBSDG^FS^-DR<8)o_ECemjkwvqI~_>wv^=6)qxaVJiv> zlCiHDHfx{%R5A zs@BylWVDs#A;qX#T7Ab)kq=;nfgExfY{RGVZcqRVM^S%JZzi6fjvJ8D7!*1!iH-N2 z*T(B9`_h}<$eKTKHFX3AVS!#*lNz4WR2&c==&qcYzETbj(}8|4Qf8=nSJ#H3X)dgA z%%c-jrwZE*`H-~*;-3V{`%$;Y^|f`{6RXF^m0~$*WoWN+Wubd5NwbMS6lN&V zdL5VgRun;NYvsnZz%nU&CmfN$-bgaHh-p5?R5~NN#lS17eOV-CI=VSZUhH}S zeG0t$3Y6E2gZz5}{kyw7`Pr=0JCtHGb+O!RwWElP-jF-!$qyWLW15_VI}59rWaNFC zEz3Nq$?KlJ5~0vmj+{kuhJ=vCo59%B6?qY#+f^mTeo>WdX^yVbDJB>If(t>`dXbi% zHkv_>h=u8eD4fXzXcGJY01MSLS^3l-THQaaWa#sOBdpJ4U_xxO1px$OXNL-`lQ5uyKTo_ z^xh6Hoy#b0@G7eG^HgbcDF~Dp^)?i~aI&rzIe^9_C^E$51iUfnOd4D+j6T~th>CLC zm-jh^BvG-U5s4P;gcsInbEiVh)mZq`=gA2E+R^^a_==f1SPlg~?~EoK)pPpM3J|mB z?kPbp^u1nOgM&PqCTz>ni@1C6g=9t}Ve;5`$QPSaTjmGmm2=T&FFspO9%?INTim#+ z>A|0uL01SL{qdsVonLiIrlqi?L+6mZ<^Z~sLmq9qlocLL?OCeImy5qJpve$8vg}nJ z+?JuK<^qOxkB>%iyUC{cqr8Y93A^`1a+$4Sbf06IslT+)H9us|i6>;%q*t-fCmml4 zbUN=rE6>Zxijk=eR%%g@%nom6jnSvb8!gR}ubdNs-p#KuDD3X5lq?u1=%JTNm2Y2I zT;5^@2zTnsT-Wy_aj(bltFI0qel}8d)8Ex?rLxiz09D8+z^`z5uVsU&V)RTS!?%Ai zTL~rA>6HwtMqK@pJO_48QWog18~@)2)$dPMR)k*)bf*1cOj3++n&-u@*1w|kZL{wB z()P|vXteq#FGliTevBx>62?cLi5wlYOK)0t6~LPcQB&TqQJs}cD!xeGO18PJ1BzUMIMX&ilthBdRQ0rzIhiFNOKF~0Uo;o;zr z9QUSJH@Px!CT;&|a3vPNZNihYSXN6?oy*RN)Ps$#XM{IbwJH+qOV7b`yI~R}KUG9= z`}=I+>YeXE@ctmWgvv2zmLq0CuZlT8G;dw=8mchz7y2#p&pRAYoYIe>E{Ac!<9G(E zARg!$Q`NaldlM+*LTWljvL38SF9TSz#u9xct%+ndVT+*!0HPVKg>3M|7+IjPdS~0( z=#JMY=oCS(Z5N|Sp$&#cY5+q_YVYtRYRD`E1VC1mGSLqAbS7Wpe?>MTY(6Ua7aJd2 zMChAuxJ2MA$=Rt(QS9p8Z9*5x|REl{K=^cmy!2c`0dmyNBnP9wAn$mt_HL6ll4{Y^26uQx=jFlO1TK?BVo;He;wxec zvc{Z2QH`fLgc@ODgQr_v>}0c^m56n^ zATnf#Nc{Mx7Gf3SRx)y-!`>uG|+}tCj(ILI_ z*EOT>kHkvJyq^80&y^9n&jlw(Z@)!bDbDvcE;60?Ak_x$>W*<%TdzIUBaVTqg9SYQ zY0LZ-5CDn|RWrnj_2#2QY=1?e8rMc*(}Gz~AoP>~C}RlMXG}|vzBV7Nw$dPF91g(i zk_BA~nQ$vg!FJ@h0SM%TD~pr-;R;?BhwV9Aawx^kuJ;_QM+8hb8377mxoBxbB{SK; z=h!`^Z7(?+koFLHbfqy`V+4)ik3ZJuAKIDK>X}S6ZE6Al7O4tLVh@jeEA~Dp4Daxs zZZ1#+X+B7%w{_#1`58BYnT9u`-|*WX-m#A)(W<|9aETaiaaU@o%~dhX+CwQ%a<0A6 z=9m;Z`zF&UL2G5V11SUQgja$HI^np_c?F;C^pAXGvB=%F8ntouXE=X}#|8`f=5+nT z*SF9VCn&V5CGjY>F(bZ^ONQEdq-9Q0rn=`#8vDgvqY1wnX72MF#c_zA1m92@Ns{vL z&E{LHtX~?4M@IrFvOzVby)4Z4%=E{#rJ;Q?(~j=be^?VET!o(`Dwci3LR&$89fXIU zUWi2Wnf+0`{H!k9SQwoIGC2RT^jfEqD|>f=Q1~~e9>G@HgJ!NKX#zZ;27=a zMbr1a>#)y#`h%?EG9W<>2#k%uLaYD+`TV9)8?AAy(wUVyY*~`FI{Zx z${h3vLgo0ydj8Z~7?t}VOl=UitokoEDA2N<0>asGa~29AP;o-%Dq)67gOR+VAm|e%=LBmm-i_WhrRA#nGA4mDyUa0gslBy%+zP$>W{zbqsn|ylmvGbGrddSm(YviH&o@g@3(j2M5X6huWvkl`VS$Qj*1X7J6z2O5c5(JIb6n0$bPTLg{lq<2H!TH`1pkN$WKjZAr@c zZrHvulUDCJd(~T<6I!EhVEWzktT)+xmV*c$|GhW3_puV!zWddrz8RNHk)#(M`?C3a zulg_V`<}1(^7YYqnThP8c%D8O{Cf6xvph-U5B=}{VS4>39RAU);g56riv({&_m~*N zaSNHueW9W0tQUCFAdqA*ays#2T%PPj>49uK`0*?B-Y}ZJAND@IqbDRj1*z_DF~0Z@l0j8z=0 z&*!T620AFRf2=qF4ZMTzL3?QQWYTHILA0K+-&V%%F(veSMKQ3s8)^}eY*xZTm^d>b z2hf^fk?UQD&9cB%ZyHg!_HA8N&!Qma-ZN}kP_TD@)CY|T z--y2Ew`yGdUxq^_f^zHp)yBSuePNK_sQ>YTH-g8x!^~99ucV3yPA$rmT#lbU69 zk{jR8ioG*i_YaRMu-?Dt%Kt^`$A|d#nV)y`B<56GEpgx_ccuoI)t{>;^4n_bBo4w} zWh6KOFYfCKRZ1?dmyglj{LKEmx3`DJx@$W+(H!b1LbFY9`jwz&uf=oP_C#>|12%jC z6=Up~ESnLj;6bkGgx-Z3bGb}EMYZMt2D)KZpOC(0>ZljTNw3|wo)+ND0Jo^ufn_a> zV$*udx%}fqR}~;y<;}vh)1>030X*#S%CO{bC2ruqh$0|!l`n6 z<~*e=|Kw8>pDo-{7Fc|0WS^I#Z{1fj6$ayh+J@3QuY+L8A2rVYJvVdw;g$z|HO`i` zUOScNx1a6yEdHN+r$a&BoGeMHpogRVNe1P1n6Cc^fCI%t5D zT);q(Y4_I_bwl=!`Q!JXUM$Ef?t4k(kus#tdRN-qQ`6l`azv(yOOCCXTV3}k_})1+v@-cTJn3%tXNzY`g-(5GF7|bx zfUZB;jY{Zoq5VX3@-5NG(wvAv(5O_&ledlidnlzpD4$?uWhcGZ&k5t{6y$?yX#~+W z8u5-(h9-89GS)rzc*uNPGj3mqjj@UbM0Ol^U-|%FE50bU^`jtSJ=?_Ym->DY7`FfU z^}wIF)n}A{&(vW+`+wKQqoXbH1GM29`e)fFEn$my>pLn1p7_=~piDL&XQ8uljQ(8P zSBM>ar!b<$U&2b;Ks+V$p40 zk58>oz{{&uQLFg*f_#_|W$1lM|{*O!8c3fheBZcoSYzyy0V{s?8jRiX9>q zW7CaI&Dt&z+6qDZDw6ne7qulFuKc(qij=(qTJBmydqP5aQUr|f@Jxk51$Cai<7kOb zA*>chpikPuI-`64d>0sWME<&p8eP~~iCH*Ku>B#cUjQi`Vb%*%>u;^foOQIMK1YS4 ze(&rB*k?QXIjp7{2er}Yrr@;_AK~PDcD>ilmU=N8TUyd72$-fBZJbJ=`KF7~>xP}h3h%v%Ena(1lT#j}k zME?v|dQ=DYfadN!X_z^zexP~nJ5UlAOcU-VS8fsdYRM_y zuCHO4Q)7r6dqj%WR&wOk1a%r6yEXkzyLaDy9^&&3N~ZnC`EA5d97&QT=fF%0>#g&_ zY<}S3JM0Pf?Ot}?(5&C>pZ}Wf`e@AJNU%eq2kxh% z-!2fV+$y7fI~LBvXSJ~E$}%awmj_&KUtY0Rq}7bCkNT4WZW$bwCSR0#4t6PEh#(!d zweM_ix@FM({`-U1<<*>zjNuMhEc1t=)A+EtYu+Fo6^2Y6=Axc@w?8bZodv4r7J0rtp$^+lSq^jJ1L9yo4t) z@O3i0n&-jKwcHbP7e-5d;K3YTtT#EV^}D4N-oD3QBjYYp#P!mC%ZyIKGZz$u4WXKd zC|o}Vdj~0vJ=a5)9m39c+fQ$k*1y@{{fY%4j+^u8jP)8i@qj`zGM$k#Hr2VM6ie1C zYz}M9570h4(^@w-(3bMqJ4re|+qjk5Jo@_p;uQYAG=%M+tAg$BfmR)*&jG6*)r2Je znqAl|K}O1H&EvDx;~{q8i<*o%ox&cSH9b7%L3VT94Kr;7lod?gWs$P*?XQY@5>+O5 z`@9dJt*Nfcy}g4F%YYf4=J$Tz0Cn?-FyF61sFw^sf4jwhfe%jPmyB>Ft>|H)dUO}r z6UMaHft38~8S$q0WJ~yh)DE8loB=7L;ArK+Z#bg~>lGNg2hsWTZGinZ_M|4CgjNQf z>~0n|65ALW(pPvmgRrLtN2YY&aFE(GNE2T!oSfaqyYh9){FUs|SbRZkDjy8lrWaD%J)HT^wfnY&qE&qa;523-;nprb_? zuXXd>n8S1Tutc&yx*~E_!~;C7unj6XQJ5r1*Uprqo7ZEpCL|+TC_;uCEPY5WGa%&o zsY6 z+y5r6M&jRx-L<0}^97}|8Yn!&RtdX}Ly+#*o9r=;D)%f?b@&CWZ9$ua>D^sW$w8-P|QO`R|cy%ZJ1x8o7K-YxmpwfXl?=;5P0 zyVE^e0p0vzm3yLI2<--gRnKW&f^wrPM$`lcy$KD}&%w=Bpx6+17>!e%n zA#I&WysQ+x*B)j$hD!+M1CPhtnrQhtBA4_*8B&KzT0xWA#?Xm^ZJW|2YdiqcV+=Z( z;WzU={`|KojWTUDyFOb2f@w7UOFRrU=r0bp9VN!TI4GhU;wh7@c;IuVuocxs(-0rs z_if$M+}l$;YA!SC%G9xi{xEWFE+N>;DTP%^rP6YW^jyidp`1aL26PX_AN?NXmnUid z!4qIS+GGB(c{Dn#+{dVm+V)nYV?!!Au)YrhxG&m8k3*?xUh1gxq%HY>^zAU6%>m5` z(;Zc5H_x(P5f3pmn7{fafteV=4#y&h=#IX4Aaz2wHm%*@#GtCvId^t0{Gm({VkiQr zdR}Q`Bh6%iLt;f^fYOGLp~BFz=QU4P(Bd)dVjJQC0`-3{@A@3^&6rfTWAUv2N~xaG zg}cGhS)3pTxSuYOifp};+!{l+;~EvyFkpjTgjHMW-&k?btO}9@6!QDKBL@JRfzp z{f4)e91jM_JG0O9kE7m_6=M|{oTnxGmKo__NdHdLK)nwL^hIi>by4%IA`BarQH5Bz ztBAn$w#GPIkgCjMfw#M!-LB(Pu2s2l<~yMEL3M0s)F)h>Dz5Zr)uZ>9VYZlTXOa(h z*L_@4fnBjzrgS+Ry4{0!8JlBBe1blanqN2vZ~0#K*~p8b6SFH&3!05~E^ep523C%w zt}p-lp+&DspVNN~DQlt@NnMlLz&+#bo_;kr z?E|iCu`xULZ8{?`*6RgSBqp9*<^tty(MHFTm-xLy+t=T^3htlO;8VQli+QQ>J1^OT zbgJSKUe8GUIJR@YJKcBC?`jj)>G#-MIFM*b)ET77K7u+y%2zsP*r3?6oOkPV9jixy zkLWhobaYbE20%B8r2q=2Uf#Xs4p7j+bN$RH8$2d*j^?#P_gUG96j*X{q~ODO+oK;> zef(dr%czueOs80iozfX|D2d>kMKFf^WU|2Wy6!Vlw7#lzz zzhVRW&8>h@w943XCog=+?zysT3iLvleJ%$I z4Mxn%AXivwx-_2}Lyz>8%FXTi7wXYUcRli7(>_J^0WqPvrGkQjeu^lwbbq*GmW4R) z7UPYVvz;bulj7M@HFRX>n<|VWCHEds{OY+XI)~;`5OlF$qId5YQEndkm$L(%?*+}N z|3RreJ`T?KP#8Z7EhKxGeMTK9xn<2zDcS~kj;R&xm0YKd+Oe+Zrr>dPtu`~+^3P&D zEiTbj(3O|*7VR#{Emwl?ldE{LNgazygPlOeWEL}D708RIWngFYp1$rSR$1~w-)EazBY!=zHl(zIH$}jdb$~(ru$uIS!v}dzs5)K535>C>Xy9r@d@v?Inv#%!_jR2{b``RI6g zF&xxJ+|rKdek^qAoc;>@)1e*p>sX$`^wzvh*T}ZsYyo?P7Xv+;D+t0 z1@}NaHU}v3APpPGWa(~<)j;BOHl(66R5~6^2J7ex`K2bMw1}2g=~OcVg85+lTL?0#_p8`ho6|uRHb; zTPvG?)ARpk9P^LH^($A@@9+h1#fEZ$99Ys?pCxmQ2o*2C=TC^B&?xGN%pM9CPrS28 zF~_S4mc$h}@daVJ+xy8T^9D&iw%J@qm^qEnhIzmqo~ zV8_8H@L91FB`Ix5Ru-P4QPH)1y+gK&-z@ie$og?u=7hD2dbd3)d)k}VL#{7ZcMV^M z*2H=XLX;IvvaJv0vh6kkS1_4 zrnOe_h1k4Y)#^Ad%r)M;m>9sS&fya=>m5vik)*T*lp7bAJlhSuqJaNse#Y5`F0seqPqf zdStFY>m;ww_7vE~z+BOaVOA*iX>+9E3Orzb3?$_gpach%<48%ZT=jEx0IpI|im?qV zgWO_afM+HZ8MaXdHVyOM#ZRKZSARZp@u7*n?=?J3tUz^mj5$I`{rRuMApKHR|3GE) z`14W(SWS}-;^G@XZc3gT9B?W-sf&FsgK@XYwZ?{|jL_^#i$;(b<}X#ISIP?hjF#ep zNIn0w;l^ZW-*m~|%LPk5wB^%G<7rwIr7>YoSg3DL$7|RYF0Doj6#nA{6gKLIxYc5c zi4GRT=FD$;DL4LLH#Wu{h;3Q)PQ@nZsTAwM@RHMoO21y?nZerC)7;$DEF(n8B>5bF zwlUP&>tw{HCQLFQfWti(rLsMpu80zPA} zF;t^xoQ6wsmPy(SJ!A3lSW{(2PJ9UMczhQRo!=>|p#bo#GSqiS`Fg$<44L}1lu<@^ z=C9HTxUA}M%tWej;FOJ%+q_fCZHi!hZ$+ZJjPaR)$g|w&Y%5ix<;sQJnVQvD-daJxUx% zJ)SLEvw64a;q^UkbJ5ulV|h~zL12ezAMIPnyGoB9y57uqCg5xi>VR2@n5d~?kR^T^ z7T}7pc zMiMmH_0fhO!YB!DG-sQ6-FEa8LlAm~YSTO0`BWcdodJ$OhT0WqZ3k{!SoBugV9dLo zCR7K{A6Y6X+U7*gMH#Y%CL=hGSJ{hCtjGC3SdW$GlpiY-9tmLhsnXwN#(lN>IFlGu z^zL=_BA^+l$!;d9y=T08TL-U7x7K2@ulkm$^t<$@+fv4c;)92BnM~lCG2O?sno(VM zxRwrTO{~3sOQ3q;nrJsGoSDsosSuUd|EjT~?*vh+%2@x>Z*8iKwzT`)8n^xszF}jqC+qfGZw9&&0d&s|CKAZfn&K9u10K1{%2Pck8qMBlxgvXvWo3~aC^WvpJ zhH(^zIwE~Bw|DCRET<6yn<^7{Tl2T~XsO5R>)~|&)8MkQERrmp572~oU6#Hwvg%7- zGS=(Q=47*$N5|hcRgfD2C3?hiaw}b{VlRCzRe;XAF47NMWEl@lt7#yWhp6E3=A=%# zCMMwq4X63ri6y`)($<}meqXRNvw`K^wleC711O?gpfptc;x8RVCC?)@t>PpqQtsDRO-@^p zzHc`P!$dZkbukee#=*93(-i0V6CHEuQ#PM#^K~`*HlZEi`~P>9_-Zds=n~sr2KvT5 z<$)U2i+aQI!{M(?C+hPsb8>aA%V|#}fU{3KZVXL4iu}Q(Ag*rSpz|oTKNzxF84^FB zSR0mlQVaNKP7+uT$cNskm)UPjn~sOIMO&$RkT}-99wODB8M=#<0(O!!ZQe9ROrAuz zyq`lJgtMLq?Xm}hs{8nQApJ>iq%v&<^v7PoJh|GGT5nIT3KJ?oU-h@3;1x#E@vdGg zLcHXbZahP08u7|ch=E)hdl#!-BY?62R~i*HgsSV72AXrA?cLaUhxjp!I(VRcF+H?Lj+k1=&RG%N3 z@wx9Pu;%d##kPDT#Z*RocWP1+P7k4UzxThaGooc*G{`6PKEHg+!FPA%1z$He-2_Mn zx7LbdWtf;%6CPdBZ4%mANONl~>0U$?=ChfV&n#KM1H@u}jXO6G4G4qj^?{ivE_HsH zu>zMSoid-ti+<|!j?_;aY7S-bQ`&F^i4q#D=}34xt6W-G&MA`F@Wl%-)Csr|_YQg3M0|>Sl|(x<<*|=Pg7GH^!>`Cc0$>rD{=9Qwg#h!YM;8X_1L2yO0A4x_JeT7 zMd(jdFq7~EPd~(8g$%Al{@c#^*|kU^CjbYKmHpcbH+69(Tk6r;fb;L?R)HM-ugUjg zfqnVKdjHWwzYm9B08vAbeuW`-RL`;)jW%5FL#0zmu#)`QnBUH9{j9$g{KJRK)^v*E zs8o?Wjz2J(AYr%|@Zs9de7d6aO7Q9z4v3~+A_ z-xO@jiqXH%7}`SuHAn0H02rJ9aL1+I33+;P_xGxg-4BQW9tsXHq?ESP*(h3K|NSg0 zi<$gV&gF$FQ5PlqPh(KLGBuuQl=p3;I~0)|@0)yzpA)2JGf(b=O9|1pk%zrr*0Ww= zogxFO8@qY4ZUeB7pxcYsPKx`DRXY$RMal$?6KNp{Y4g@82pWVXK9&o)t_UBx2O^e& zA3ZiBX8!xV&8-JjUYxA2V1%X*58W_Y&Q#>6e>>-M4ey*iFTKk35`(QBsfqj=tbSI( zqioYSe0=j%EF`5#c6u$}%$%nr)bPc^qCGx+8J6TRib;b{@B(=SqDnW%ICoN!!1UDW zXrXpO;ug4$yFG6^(6rbhDBeqTyx_1qIA!}hRJlWb&`V=T5Hegr+hoY|PG~+jNI)|2 zJ+B3f20)RUX%0YTnRF+=_sP0<_VmyqKpI13D$5c*LRchF7!uA%{-l(P640cSW?B5a zdGg&?OcK$z<=b8BI^qhPVeLylY;gte%1^k|Pm6C0Mwp+vw74@}pH$;GX1}G43%=TE zf5iA(GxGn;YmD$3@Ub4zdQ6If{|v0cm*)yC;Ycp{jYRLi1oonIc<{>cw0##MiQ!Rx zilrvIU)V#P4=E3a^`mQh#A!K<)jwZhS$+jLJhlj$_VEZX=gQC?C$H7vgp5e$YWQ$* zjiG3qS5si>Du}!C(+81uX?Zl4l?2KM|i8+>Y2XJZINMUV53 z4G=4e2d0ZT4xqSv=(*jZx-B;>9_iKSAqXkrD>uuQ19ec32q$vj72|}M1!-6S(L*1_vw#ox&}kp?&-wrYI&Q@Fi2 zeYl0LB{`ER=C|+PbUD>;WYLrODcW^-^^<9zMjl~j z8AwT87Y^GChxwq=69HBL9xdN%O0ly{enWkjQMUPv>`4o6h@z6?E2rH}-3>3oBg_Ku znJkiY&g6X6$fL(MF6do`n@W&a=jKpzDxJPsdVJAE&tqodD|3pa;H&xA_Ha!?`_>z5 zrHkSr&*(U+>2K*%gw65%r9=g~c3HSbASJ*-n)EnfpC=sjmYLp~>pSTkzi($#l|MYr zjX5txf1OW`y$L%z`zWfhA_3q&2h|?iPd}A7j)9 zejR$;y**34-ucHsyj>oxtp36BOUIeu_3^nUa|BOD-s5Q{4aAJaG);Y&6QSCn>C@(e z0ZBHpP9mOsws|yn&Exhq>>8;I=Wndc_CETR z2^1TtnTEHR#quwzphGAGtG;_4M|{&&A@|OjBKgRwxG+ssM6E;6YH+Y-Rlh_j;m)+Z zd0GqB79F3y&BB!U196*#k5{D_H-@(gAK|>zrG?UT#=fa&>gsJsX3MR-@^v5H%-eqI z@jiB5MGMT_`N7ARJlFccu-9j2NuOLlrdS{*waU`{!=E|DS-)gxIhTCg|DPu3>OY&D z{3C*o+y;;D4m+Sv(KLK=cU+?+*Z^l^xuON7s4%v%>vQy;~BHE?hmLA zsT81x+-@uj2{82GiAV}!d40pKL?(Vo)%3)KGl32_gu7EvdBKM*Z zPZuQKMql0{kP+WIf^c@U9!Zl&8$$k-K9@#aO^Mqekz@ZLNAMdm`jKZ@y9*8XE6k(D z_0()fd;BOCg7={@I{n6%XG`1AY_>9$v69%E2#PNw*!N0Y8d>*FS$L9w(Z@yKz){u5 z|GX(-jzIeuJO8`Zx&WOeGaGz@7DpA!d$Zu0X!^dd1)QGgF2Q_j*{{~+8&0cd$MXwu z8DwKDaA?@Mo0Gzc2fK0Wi83*C7*2JkMhRrZ+R{)TcGzoqTPR*0>E;ECU<4uO;shD= zsUSZjlE(bhdJBV<{$6h;6=xjC<6R+Pc1)%043`}y_ zd6rAt}Q?E-6k_5U!O8~ zB|ck9s@jNv)R0h1ph8^CBXVT~_-h;0KGjt3_!(Qi0;rLmp(N!sWx&PylM1909yk+l z^xxOyHUGrS-irL)ORt}H8ehRCKe7_b8KY?Z?KuSoY!clM43JpnDeld&bhJh5Kni|o z@ZKnw!?s|2Rr11pw$g8A?%&Jz@s#^XU?-D1oaZeJiQI` z6VhGA-qS5!`m!NT3x#H}b$$ZAS&FG?R@>A0nwBtmv~YKc$Y!GZTlDbnnKt|fL*B;C zRin*)Nb3+QmY%xAYqywY>+>V*EZ`VV50gP~Mvc>hsnAf~W1cMdrtV2VRjGse-d*W| zM8eSl+fDYTF3!ku{n;oyg4mdz_AN9>1NRHKbwHG1$0tkGptz>CEJf@i#oLQo6(7CP zc^RvesvR1#knQB~sKp1;05D8}4X@war}n zR3`P6Sh^+g0HLCphI6WDU_d*Pf=H#ygTqCCWgjMM{Vu$uwL!M~ZJ++zxW^19L@D+G zi20xt$wDq!NC z&!GX~M9?(Zr%m?G;UTupc;fl!vhBt_;um;P;f8o5I9V{n+2l!raeypd+NLlP@55U^ zy+)D@xV{)7ErDdZFX=<~YsPAOiA=kXjo*ft;P=-LNtX*-MgQVV|5gxfi&^lm*96w~ zk~PqGJCpA8h?`T?Krm{b(Jft08+;KT??rN&f1^V@ZdDrQfZ`&+4_wf%3cpLvv~?MH zN|=U+=nZZTy9DxJO;ciN*?+}=X*9!1V#-9vY@Rfvcx1ZC2V1vjVSH&oejq5g&*hU| zrF)AQMt9B22Xv1fhPT|ln`4ASE9A6JrfiV4H6(UZjUqQ_c0L&{&2th@MOoxg?~3k< zg7=si6R>a;TOP0A+Gjbo5@L+#Miwx@D4wpS96!QJiou*-?5)-uCuSj7*lz# zMe&?30@Eym~Mn=paPL|ETy+<)IX;(`v~6 z9udXw^XGyn@l|Mu5I0+~g6tv8#mXaUy5fa-;iRo|-GSUVa|1g=phCYL2RJ2okv`lK zt@hYQo`DYyuf-J`Z41u?#pu0Y$DP|8@=qs4bx%277;EjvQ8wT&^OyPYtud*uvPedH z2FY!#)k;B!a5Tn5r>*HvwwAPF@$A!vRtcgx*!QI>D(HijD+bL+X^A^Px;^F}10*>g z3}ZyuN;hofUCJw{sfU3;pdoBc8USfhI{|T;c9@$;XT>X0+_iP4t~yA#sKvk8!TC6~ z73W=slSd)V`^)%=K2d5gt?c7C6)14g%(L0NNV`vHL(nbx5Bw8$ajfZM8$L!a4#!5> z2xrYh3$M(1K2zJ=O>Cx&OUR>>Pn^^*F|z)S^--E@CN&2#9Y1lY&oe=I2G;gKm}!%^ zY`D^xwUX!5DEYRnH6`(U6AG`kRI<}y*=Kz>7j><3v?-#^Tp>LvD{qy6liDc%kdQ@q zJ0GP_UY+cDKW2TypyJ|*NtH|b=H7glY_A%^zx$@^d~KUSg*2ziL-W2Y14wt3UR* z*bXl}E~|h?iT-f|&(+U=F;{-XP+mbG3T9hnVSu>iMm8hhJF?8yJHitCYbQ6*0pHZ zB66}h#x#0=JNY={pL@!d=-V&Iz@_S+Zs5X^k@|)5nR`z|bk-LZF20@5s*cBV`=^7d zXzb(TCq?gqdiL$Q4)&)NmS&mxb3-C&lBvDHCm#7h>BN~$m(fbCJ1C_H~Kz&dg zn76e>WR7nxedXm5%?7+`UC*lA{L8scVBo{G^7!gsAYf~UC+6N>%RLLY8kC&b4M#^YHr--v9;pqb1^8S)+A4=_3 zrJ?57LO-^?mO2sTKIjBK-l^X85gq=002qHioEVP=H1>O*ArI3=^f;CEqeL%)>Pd@( z-m-IlJ&qL}_IdPr^~mdV8lTnks}tzlfwK zs!ySa)Cjd?Ni7-mza!(4j!9`6?BWIL$(eA-&{U8eZ}9tnqQ{Ne2PD{{7GXMA@$G zp=y7t zRSM{u1*DdZ=uN25z$vYXaB0>Xp)}6aOnGO?Nz-~(+ua~k;axbOpQL#aj>6b|@@KGL zak1XW)=Pn3wQQ2}L%%Br$xwkOixlm>lLOVuOAN~`XpK~x& zgDO|j=kU`yB>>?RtIari@i|VW&lQmq*)kIZCgP6?X(2sC!w364`tW0)4ykGcRn{1% z(h-MgOmE(H3rHM$&)g7>nvd))=10Azm8j81{2e=%iMI#lR3BWkn6?a`-JIg zw&m1`X@xfXE1;pZKhAh?d(keKgxeR0Gpk9UhWZr}?-C@oZuBP zzyj$Ns}TLI--Hgjs9o3UI1r{>16GoDYo|R_`eTF2N$=Mwctz(Q`0!s-x^d4adi!!I z^6S=9KAzkd&)#I-nw_1WEk3{5tCE<68CrCg*+X>dc%8rI8N@YzqZs-TpFsB{EWvKT z8Dcm2LG9}Z9zLlHdrtFKr;fu=a~UmIV3pyCe1zxO<$3@5nMyW@Z#&Gydf{lFo zTz+2DprbjrcH#xZ_}Z*q2q2suwa!UJoH`Gc#f;Bz!HB-mirNPpCmDw2_LF6*>?3fW zhsnmy?a*ig*yfO@SS_Y10izhKh(F4@C%~QS%H<;r#Jhf24+w1kKPdJuryYVoFmVro z6hPnk*)#tRs5AJJ=U5II+aZ%v(A`KUlw;SctH(+LxH8M#kK>gtPiKIiB6uky-J*#CI19hV z4QTGhvKP2YqL%^;le{M2agnwsTc(094{eSM#|PEc3r15198*^VP(48=?=V-uMrjeQ z@1VyKv}9V*S>o4Qk8UfsFgvWjIlq5d>7L$FJi(C1Pqz;M4#vzN7bbeq*2HSDMctQq zpDWN~OF{e_I>WXWCW;v!FuNKCqax-tqX+?!b+ z3adWOp(a+mWO02K#8j16X6$0J#dF~1H4e9ePpqS2c;{75zar&kf6jEx%>Nydn4+de z!0t0Fz8Kn2Vt3g1p>0m5ZyK+2TL;->$KovNR3A?=gSO$xN+w?F>bPo2$WcB$27Zfr zv$p#LE2>53x;U)oQmxF+E5gT*%IaB7_Gd&=C{^BQm?&sWXESRKr^W%O{*bUwtobGFw7cg`nL) zUu5@ZvZ@$7fv&GX>_kI2Dd(T`o-L=g4r)X4^jC4{&kEkRIGd)rinxU`@5WNTX&lEy zR7m^379AV4E!W)9=GzaGZfM1#_F8%w`@{@t22YN==oyqgV9_PTw7qu&Ppq8 zB7cgbwUGVPueOyyzBl_f|AyxRF^jUfw^MD~z#g z!Vy2b91{)&IHTBrd0TIKfetO&+Q#X%?wg577){0wa%=V=jJ$fggw&WSuUs6?Yr0Lz znfm{huyi|AKr-}zG<-$XqKB<6T`Q6nA2qOf9LxIf?>03<#e8d}dtPcXXv-p4sZ;(j}w zF~~fQZ8wc%+p_G&p_K(hhMt7)Y7I@R1BUYg2h2zKJGR5@}K>?e^P7}>;~DM!Y|**gd#mwO9ikbreG+{f{rxHZD*ZekU(zJ zy+o`_!$tPi3AIYk%4@DmpAE(lY&ke<=JA>0?1K05)tU?32#?ExiG;%OU8Ju6;~J|A zB%PCwR7Ng!{Y<|R1x4@tN3-IkQ@u4;YYzZ|qH|vIxp`1;vM>cUy5{dfCV+nv%N$0< z7SEQG#XKCVTXMRq_((;ZmD{o9L~lD<@lfq&_(01kGvp0TqR}cZ4{$#vX`fn3>g!3{ z;(MMMjP@BQ_O=OIYK2N_g~#n!{mc5|+n{Xn;wd^3`@k)7xt_2_x3x0Zs=UOnoR9qq z9c7y4Fw*TZOZ5kE{Z( zicd_9aH3vY_>W5~zfW6MKJWtRYegF4sEpxQIY6cIyFTP4QxwBzPmk_QRA}XE_Aj?fBWajWlZGtET(SvM@(BsU4T+u! zI1n0HhKO(xd^A>|8SVQ;yOp+ARbzMeJZlfci0)(IVxHDXTe(SOSS^XIi=!U}AY10V z^XoV{J0q4_ab&;wHR&oLdg4RcWiC&;qsf-KGz5azgtBOgE0ct@pVw?ol$?TE@6YeA zbw-;0>8f<35xJ6(=NnrwwZqDBDK~g%aWdW!Bw7ZjsE;1asiWanY4J?#jtsI}$cZQ6s26w43T$Ezqkc$i1q%pYzaYEbK7GxR(JXoDr(Z~9KFIfJv7oP!hYl#sBa zIOBlp&rs-+Q0cJsrnGoA+r?F9O>H!#GyKf-d0Bo}DMQ!AoYE{hYe#Co-9z7UAl2Vv z*ZlFvtbdK9J1!gtESVnVcYI`tmVfmLaY6Zc6qSI@INLp3S$-_0!cG;x35)Ec-GRmt=cEX9Dm@k z4XxLM8lSxk?PNW>-WKfcK1pHAWg51NhKr9{RPE=RYgKMKQ|Gu_;g7}hE4F!Gr1sjN z_=rf8*=sbfSFa$!LxZG03h4$#<%!i&B@qXrSRv;3x=)@QJ)jfM3H*)c)izgC z)17EmDqnP*JDfaWe4R-cY3LT_dM94}gyS4$BpqQpC6~P4`jun1c99a^n-Er^n2y@% zJ+r0{$vOn1STFj|Hd((j@0q0RSaN6sI8U>&c(rUt`P!^u=3x!WA5j7(sHBL5Rpifu<`QfaKB4B0AuM|SX@@i zZmxGI-k`xgAcv#Y#4ljse%#L!vEv~3#G~};K;vk~)8z_LN?CpTt|Ct|zT-6L6Xwv+ zsU@K8_P4DZzo!_VX8Iv3`lXp@3GWBJ!~x8s%|VTsKr~cvuK8j43pWe!*VHZcY?eqp z;lnj*Tz)u@UJhm0%Wb_A9rQZDVZV(upi@Izhl+68ScjYAL+xeZkb||_l<2Z@AFeqi zrN7waZQMb;(H?G@dNjGR*A`+ujwAI0BT?yYm-5#4ljy#mVm0luDWUjd9>QUCB45W# zOBDuIme#H7iqX!Y9XA0_g23y4j+MC>ZMkpBme;d5@6Mq?lq9!3e0@<|zUZjGgNnIa zDYvQKn-a!lrsY)JTQQ{+?y+`coA!8==V}YJu8-8nJtjMp;F`FPX<%lVQSgPNyinkG zwUnKr(Vtm;m0`=nWYQdgr7PBDVY}T8#uF8U#H%Xc&x#NglS;3X+m6&OS~W`HB)}u0 z1kvoV0Y49o*i3X_nAiGL738c{FS)R7w*4G5Ebs&rUY<7JQ#MsZZr$r+45Zj)U$!iM z>i5UsRp8{E*(s5$?q;^QbQRu_zB}J2 z-d%RwTtcrq|J9JkQvdG{H0)^I4twKh$PI;PnLtH{sd}%4^ZjdamvCuhVrAGux4V0# z;-5-@J?1ou+P-js(IZkNEvF92cZxa&ZC!tp`^q~M*EM21K@469$0|vq(4Fg_!(u%} zPUM>8_0b!ZZnd@)rmw(S<&EXuw~xjm`Wl$F2+ zGclYsZpBmY`Ep<-R!gv>tyexm-THx_+Rz@ZY=G)CjV> zIB$$shrufGO)jpc->IelnPMv-+(9)QA8lNE{BwKu|9Bgz|1$EyZyEBq#sc2pNpo|S z$$Nz`TUu0Wix`E7i?!fDM3DhtZAny+5)TfAk31^0mJ6>?GNH3XM4H z^MNgF%-o+AB_%bJYkMbF#^ z3t#wCU<|w$nt`eZe^3qjoC)}DdUgJN}tF+PSY zHTd>oFTFX1P-I3-tK+>=ZtjsX~ttBeDK)v6RXE9)QBFMCU7@%{CVmAMbunU z%Dv+lP0u8d^HDgKx5IL3Em+9P18`}_WBNz!;}j52W|cCFkDW^N znU0@+i|K)ClX(_1)W@9bGHF6X3WFSJ62Bwx@b2!K?^BHf%pB1VrfHmCAX|<+T3p6v ze!z8;5WCp*wVL_0(AaMsZ1KrBOl-mor5l5M`1xb@X(RN%C@LfUy^E8Zs}pqI6k6FD0~2btMnpM2ZaJviJ-0x0G-iU9_&%$pgN^#ztqn+E@Oy%QV4kA4Y|BQYL zpi2JP1VZ|@4qR2zG3pZ_e)vs}jE%X<-f0B&;ayKW7}XCt2(p(Imo!c1d*Ga`AGHk< zCw)Ww=FITCrj}8ndrW> zUDxvf5hAp(J=)q*SnM;4JFY|G)*;R#gP_iE+GM8)DrjvI9#(b$bs%@k$RiHT?=dMw{+J%^XmF5 zM}>ALlh5@MIGS!Zh54dT@7@>9D#X(Dn45`1>eUZiQ0un|6${uHDh%LRN-XJ%lg#d< zZ}jM~uc=whV^f?*-2CuluwODn1{2^e|1P&+HYU4S0Gc%CyMTy-%|>cT^Z+mwk2T_vFA4i+AjW$ely< zx&_>xHKt0be^HyL+Ek;%uhFQCc*($Pi|R0`zI`o{NSGI}d$#pxuzd7aoWTF1aladl)_G-y=!gR4sj+7)A#9?|8Hh-TOAU$i zx5$OTHuE}rXcj64JH3Jtat5J0N#(=?ihI4bEd~UmI@5Xg{=-b_Ee|V<(pLOw{l%Xh zAGS*h8NFrSLSV}~Z%(Ew zk~Ze<=QQ1;(5L;DU7=|CXA$-hWt7_gN7h#`MD^|M4&B|I(jgrKNP{3H-JOHd-60?# zprlB*)X*_BNDk64bc%Gx5CWI`zUP1LJ)V!S*Is+=^?UMiLf7Q>kqh=(8?hmz^Hs=W z$Vk7)Uoh6AApziLFxpmPjMu*ON2A;~87w&%VW^Vrl}aP@xy2Rb_xFCE$k5NnU8xP_ zsoznIVuMlUjc#+$CTFH>`c)w$`Brs2qZWiPTl?0T_?W=*o;5f14XHR> z;1EDS^yB!m)-%{TKoTZ>AL?mRGd)OU2icb<>=rIHW_az$+(qbVGb$l2Ai0skuU& zoNSYoc<g3%pj=Uz#NQxpyVa4|&1xC0_Iuc{B#$dQf0Mxhm`s)j}N)}Mw+-1-V- zRf6pH2<3sO+=USTA0E&#l4?E)1k;s05-@bgn8g978{z~&B=~82J(!(30f=3q2?$V( zHMGE@>RzQffhUx)q*3TUZv^`+duqYL3L$ZVmptI2bf595V$xi?=srMYJc4oCF7^B^ zq%rE?ChlasYxKW=Gb&`T6O=$e3jn(Rg&4Gs@`Czf zut=e0Rj5Q-{{x9q{FTbd)ldTSzF;@XsaQg3tc$SkTW?6dG^u4E3cBod-lPC&xrtok z%{>Xc-E}$4a9+|t+RXLKb_`Z}Zb0km6aiT$*O2@0^u7t)^hXr0SzlDl%^mj{pL`x# z(H6;v#^prcwfpiN+RQLox1UBkMg1ImVzjS(rT};QT9HS%umm=@-$C0yye+$)r__y` z?l|vdUs$Zeh2pttmWY&=_mK(uc(r#y6^zSX?n+6$hZH#c?i2&FvIBB z+ASj85G=rAY1W{sP@N4cq|WDzf`D0xbY^|A1^!qE!Y1MFPbk0YiZ!9drA$@JZj-mD zh>K#u04yaE?r7xI4S7{K=@MnM*-5-|X#%K1@0FokF~Ux{$Io)I_+3#}U|mb*B#oZ^ zOIn`=rY3{;jq&U%`a540xSGBV7;t9IC2?mNiAxEXfeJt7Ae*VnXy`K}s3yJ9G&nQR zP`0<(S`~%ygB~LMnZQIL8z{l;vvE9-Ac4K zw@X13fdNkmuWMD9rGhrrdC+UM$2-iR#$*%=9nJ5k5r&6)3C*3tD3JYG(t6KVGG8Ty zS(BcPWO64Q7a?W~Qm8hOgxjtaV{ImwpZI2h$4&?h?rsfpO15sMsRZjcdi`NU{l^$s=$v$jN4;>#$5Ar z6JlZ4q|gtMxJ^=u`Bp70q=Fp}jD~fPI0cXzt!w}&`-h^NkxE~`dLjs+FW%@fPnsgw zb`pxHI_o@GkskB4=F(e#&T}7P2kzsFwcYho-*b~=v-G$P5a}HA`~INJ-;!qf!vA7) z%P}D!r73JfocO-+r2pr>vhiL<#n=;2#pv+U3`J$P*zZ^Zfx^yXs^jpQ^BVz1%=Mj} zfoGaHfOC+gj&p1bU%p?$L%$Jp=A61T);Ft^rI}KEd$>uCG+v3Yz^q$oWbywrK za|i7o1=2sXmq-G2#zNPR-GcV|Tnx5jl;QpDa?#zwHBOntk$je(?Y)AL-D1{Qcf7JR z+!v1a*pobfNY6;WUf_>BfOW@|drjVs3f0rh#e79+;~T#wHN3Co3E(Z8isM!&P8zt7 z>c=)8f51p68$1zZW~;iM`V|1gp0Z$RpLY~J&B4>L*iYiN5~!XiQKYJoCdvhtt5UYH z(L=lj{(NVZx%`JfKVKouP7X|i1{$tqJ)}BId$#+&U7cLSUgELQ~(@7!)zpnchv>Raa&n^7L`EZZ({x> z^!_I~@kX&*asG~skXLt)66ra*%HA@$^a86A@y}u+vHEl5P=zm!4U3%2Oc49sPtVlZ zdz2Q+SOZW0chQpq5gBd@#`Ge2D2po6(MtYba2*WcUj6xCXusaAnj|3muEi7EHNM+P zT8vlkgFummrkTjp`qG8&v|7J@sJw5bja#>=QM%P1oO>` z4Sx@M-~yuSZ_sqXxVrZz4dw@qUv|D`a@C&W1je&VY3O?Jm$H`|#kSnw?CsyOWC0aue>j}6Evd#fj_-O>d!55kbb^b4# z>U2?kJLWAu$vM+Y0V^+5?k$cxWL?NHR6<7Gd;UrQj689xnMA*rv%$q$_Z>WwXVi|G zjrF>g^IEJMGh>bb>DVNe-gJ#zR~$ddGZfl`zGllHiTbx(>k$@hqZ+IX3x9={?_wQoB0g`|u8PFwj-+ z5SJy#jCY&`cj4*SqIf@4xE$%@Hi;8S;l%EJ0j}3uwG+}#q&n>spTKwMa!CjNdfLmb zidY*;+ds7{3>h-|kwnO~wT|f(%4MM|IEyJ0FHkW@bQ>(iCqQixj{_C{6RwcaGzw=! z-q?Y=ZPZ;Y_pW-SpV%oMz;D_LKPJB6z-@7lMB);kI3^iG`pn#;gFohkD`09Oo+FYS z-0Til5WH9c#5dL$^66%q36)dpBBT{SpB-SfSu<*4=#+BUW_FeCXB&tSvjKyY=*q0$ z+PB)j)WF>+kEx4%t3IF=zCok8C~rmfki}5Vrme`v0ptGUD$TJEoN1}E#+wh=dbY9O z432BG5Yu~A?f&wxygx?KEctfI`KMw$WhH_@*}x#hyZ<8a1UYbFiA;xJ(FG2_*XV=& zC%wfKXfHn#|MDIoQ#YNY)!&xi>T7U6m0v-W9R}Z@mP|tD&y%q2bMhB8$gJ;)NGKdS*gtxa;hA zs+Jn2G4Rh@z0Wh*256yG$bo^ERkIL#A9ug&DxqbW0e#+~NcRYe^5!ShFFpP5eRM-* z`_jvb3E%2b8T7JARAYdDaNr$ql2N7t4vsy5liH>cgrgqfpu+7=Iq?nj`H{5`FM=t2 zMF(xX?Kp2B)O2dSvQjbuBi17dERLVp}#AWh$vcy4nOQlUb}I#?eiL%zQU zMn~Wt#`7pO!1s#c##(yIQ1R8dkk+4V>;zHZzfwPL6zQmN>|R-*LV(Q4gr{twDK9Q% zC_|inPBj*m9O|1I9C{6g(u43~@02L{G?s{~^ z$N)ZI$^iNB*46LV$6_(5r&C0Ax+xiZw4U_Kpc7Z7Yy9v6)stmDuiRWs&I;_E0>DV0 zpHI&lyEk)Pi1m@d?P>U%A&+=#CtYf?p8px`& zQc;MvdC}TZ(7bdj0(Ydgy3A1(_m-+x{HFt<#pEE%j$y*g9=FG`(0yRL%@5)S;?s2F zPqSpvJjZw{zDDOK3=u|)KN=rz4{hTNY{V{SKskpBWA2W#qH>2gSqH||4V0+6!9X+I z`p0M=nDJ%mhpiLA`=yR5O)zCbZJ=1;Iu8CBvR)AALc(D~2ij(+VRiLuGVj9H+18#K z_lGBn&C-c$&GxFCbZa}^*p_I;f%mb!yp0B&hBoF@YEAAWWs8b{^%II#pwmg0-r(v# z62pJrjGU<>aYi23IVKn!u*TTROCx>4$oS`Ywp{_>c=I%EjxApdWy}I!MYv~h*X^RN zfs2#5A@~g?1~*cWWwRWYglg1QB_`6>?7d;B!Ra-WRoC%z@(wy5b86EqoVV0yUsvof zW|l#k^f~X%H%o%7IJ4XbCDYNl8AuQ+Z6&k16XMI6nztbW#xUuKv0d4>>OC95S&nCQ zG7`G)CAsi}#cnY(vgbj-#gqrT%EFQSD2eOiGHB|;zMNbu<^^nZ!|Fh}5{n8~W1ltA zf}x9qKY41LRjdTqI}Io*)`p{XN_?HC%1y9|Y_u8P zIx^`tF3v(2^zL)0RttC|wg>&aviwY(p`!lQP*yNxJ3~g54=KHrfv2Dn5r$~%dL$f3 zG40LrI1;9>E?Obg24ZH!U8$K4BmMJUfjX5GuG;;~XiBZ&)_*Vs@S)+S^kI^0x2HR< zcy*gCkb}2p!>gQqjcV6DB{_0jir%e-to`fN|9`ka2->$IIu;87#%QjI@V3ZT774|` z*LEu!O{4ykb@~E+q%^OgJ82cl3#CzkQqLqn4JlH~i&!GzWg4u>S5b$wNQLt`tyZtO zT3lwp6=P+H1U z#~bzR1;5vy4}*~~@Y}6w=qp=H`&thCnEk)d!>JHSjk<>`BB~j?x0MSKSmMkY0_$FE zXs?d*lkX>3?S~t90>HG&F1)jw3@&`Py%`oAWCX=sMGJZS;Qfun- z1^E@eudzeXJdUw!ZJ5$R_8SylEB9r$gx1WJe;VaA6ZGo(3LQ6)RTP1ZM2YHqHff=? zup=-)8A#VLVI%BaJo?vb*t*H2?;AJW#ia1pOIA$UX#)4|WRd7}Rw&s9{9L!a#Q2O= z%c4EE5za*44%T`pv3!HD+oQD?W)6T3QUk?t?lWhM_O8S`a7UETs5b!m;$*p|{)pDQ z09M=bqj|#BlTYIhQI`a+pOD|l7@QtJ=xTgEF)-r@0eQOol?o-d2F<0uxp^NaeQkOy zdU#GRz5JWNtd0EXp!#dDgIhZL!@%*z$r++4-Y8fMuv`>N-)?HPQaASi(myd$!lhBf zA~RML=C&>-;lqhbLoin&yi4VR^tWi}>-SJ@@_oeja+Ci=aaqxNe&#cp(oy6$$1nj? zl;leK{MPitA3MpL2|&yb7qI&2!g|T|>=mX{2kEUR`FU;4FhGNh|1d~@Yp)0ToJgU6 zxv}5{fVG_pt_iWXFfbvWC^$*@Rybm$rE33=1NG3KtsX8 zNCd6aoKn(+He0F%D=34$r}#^A?3r~=6o#l_&^S(B{1&HiWQ(?doGuOzq0}4Trw+QM zX@BzTe7Kfqj`;xwe4}WCo^%SI-CmkN8Y}MK4~9l&ph3fvL)>q3a_|1;qEzS21cQl} z>pcI2k``ZMjAmr(LDF788@+&^j>fzX4tahUpx(lOLw}2 zmFhE=`-lz^^E^+7)pz<&V(Ol}`r=cb)XuXNQBB^4l(Rhc3)WuKi(i$jy>njtn*J!R zGPlFKa@^{kd4?c-*59ab9(Jq#v>4{Olle<*s2)izk(}Kv3Za}z!%%c^kbkdshmXeN z47Q(Bp(qJGZWOnN-V>if9p(W|R)-rMB25w%yJLO>C618Gp)G0aYsd-`TH--?#YMu7 zPh1!hm;e{`jaSH1={4=&vbK#j8s~zC2^yg{(OL);ss>x>a(lmJA=Dr=uKvw!rgw%b zR(sd(i8py+HwJVYkq4{X7A|3`7~zP&-kpp*d1Q&zXu3_grXldTyY6uNB^2gqB696f z)IKvw@cpyVp2$!ch3R=$E&!Q_W}ewNRh}WF528?YKkr%megW`(W4+Zp(GuBPCQF>S z0=WLY9^mgYv8TE^6)zd?3a=3wB`n-hmp|%Z9RIBDVBbzU3i8h`q|QC|bs2A*br(Y| zSVGnTd>ZGGs7sUIGNUQoM0h9YZ6loa=62UcTb$*^Q*z+_pP9d+XKp$%v??2exs2)T zYT0g0dL$;8#LvIR<(Ik~fU*rD@}Wmjm}n!`v)W|xjP7duaVIYh9|o@3ws(vW+$=)t z^hY0Fau+R)6<}9eXd>h%81zD@Do4&cG>N#k(o0!*)(QBJeMzcGv{eUFEm~iehnn*{ zADZpQvsT4d{07K;7Q!&`V+{#3X=TwWo_7EBRP-tv#C;4v?0rt<@$*ex(edXvMCe zIHbuKpZwH041Vq~R0^zyOmpjN(V$7(UB7C5((ix&U$S4Sz)vrYd8@CO1d?6JMlqvk z=Joib7e`*D5GW`14=!<+L`r%GEsXgfNj64|Y6UrLqIpzX)K?>2C+< zq3qk+;wm?GpW~MIOgJp;p@c>9Tr*|$&Q69mxj)$6yxx#DevX2)`Jo#`7}+zPX)i0J z0fh0#^}N;x=7m3yXsVJkV_EzTC9j=PP_>`$yxYyF)kAZNr#E$(O(!ix+gnvRpoV^B z5pu2=dZ(a5ea>-0xykV|vi;n2C|<%3+$h%@Wm<0C*&*eSU?H z5-rmJI8s$>he^30&oZwp9!7DG76-GjTJ#o5xC7WwvcnrJ6j<190`#SgUhJbcz(XySqo}_FU z9g21D9%dPm^h4JBFnKbzHsF+NKjrwVD~ZD;vWy)t=&O)s@eU}U%N0I}fHrqF-#0=- zhL7K&&XJ{{Ih+q&(l4FEaoRh)s7w7=>aLF3@obV&Z*aWjtGj+l7}bx`=6}^m{KwXY zSggX;e`B<=u-?YI>&kwrLSO=evMBfbf$ab51^I_WU136d1?b2OyrSIsRF&f}|-UatA5KdZ7~Pa8`<0Sq}V(&o68~2Yj@fgZWoYqoALwYEVOR$DBS9 z-?TnkZ{z=~NvL^B2>&`DotqK!XoUs~*}2$wx6%+ZvJc5gnN@rQ(QsFEO%ikBeT&Ig zLE}8*mbB4sTLY+-*QI|>TVHJtNU(P}g_ z%I4(sKunDpENpge0N}sksMu#kYnvcOzZKu;`JHpbNNcQ29eReu7i3DxBEI3iTV)gS zY`-MYRa43g;0dpu-bO_*i@;0k!{4!*VJ!dJ$XO%4Y~r=8|HFRRJBI>iowJ909p7APo%JGl91n+i zX7e$I9}(8O+WSFD5h?wugL2>#wMAhZEf=7{Y>wBlU_(_26Kf3+Ssmxk>c{%X_bAKf zTkMEG^WRaX~SD!CJo|w#DP}#_)ym0-|wx%kT$5FW0SlG$Iz=fxQ=ysI>a{*w#8Gh zMnHave5bvYn%%JX7SLZcXy@?>uh8pu@3BbtLejgQ_+DN8eZ^~yJZdz1l@^q-Yzg{M z7?0)N18*Y}6bW@TG3;Z6bM-YNg)k?osQ~%3=}~FYxixY3Xx8N>2W-=Dn^G07Fj6)R zushd$349k2=fbVSjtML)W9a9si2>=LYRVs6cr!sFqWcEh+h6?Wn$BTAssZ|5L#7A0 zUe!FdJx?%(7$W;h#;0pz65^%R(=!Q{Ri6%0`UsHHtCa&1Q)@isA*{{f>Eo2m4SHc0 zC3;B&hALB!QL}b1KpoJ8#hL%jVjkBS0hk>yVm)u{+eLFS9_oy2d4OcZdl;W}?NzQ7 zPJ)DPzEy!BAfWgSN@0%UxIZS`NHj)+3R}Bg{d>GCbRo60qf^Xu|5-PH21(@no;aIe z?Z!rscKp5Vo`Vz8t;km!HLM+onuaun0$+h<+J$mQEQGsx1)gHGaWTw}WH@;zX_1j% zER~?$Eda|A{~#eR6hF=AmoCxB#-r`Zz7MQa*p2Pe``lH)^r@@=z*oOB-#HvP;8%UR zq=!rj>zbc#3k4e#MeE^NRgzGD;)r=bGCAm08@iniO(M`XJsY3L6~%2jr7*&KBN_uI z4G!+?>;FA;Q@f2>C5cAY8Cv%=yK{XfdUgC^`^urE?Ea$MyaCR8^NHc(UodZE2qPor zskN&2vaI30OVo#191BR2YPEos?TMZx>lcIBmutrPgB=QREUOPoM;90Np`9jJLIUk` zy+#|$nDfom3S-Eu&l!qBlgQkqTZe)rVd-)I_ugY-wK^u)!@F$FiU>X5^aGYb#y=gR zv+ySvc5_`5R|f2rTOWyuO1HF|k8_Q|p@epcA&^T0`VYWS($Lfi{%A7t$+vs*X1U#m zltC@$ZL1y5x6h$k`{JHFW5bNw3*E|{%B!8y;JagMrsEWWD<+f!b;3Uxnn6;ycc}XkoH`2wr5mg z>ok&*5Nc2s#R>F{5LMQ>*SR-5uv;MoFq*JL}NNws+&XsAeCx71c*Jsu@tf|JVL{yzC54IaE=Z6|`Il_Dv zq{-zluN0l`?VJJ>GU9NiG;J`A0YxE>@6Jow!Blh4=vg73Ps+}CO3Oxv`4LfW zhRa}2*Zvlnj>NmG-iI_MZ27Jbndg$$+4Bs3y{`dP9d?v-sMjwe%Dh|M)_4?pFQokJ z-o8*A&m>Yuf`!Mp{@|m7CFdbpU@Rn9YaQQq`VfmGri;*bFy@nh)a|zzAFJ8c{--AH z8PoeWzbA}lTq*Y$^Fl?4nq9e8k}(CYvK#i^JY8-wiPZv4JYo2dQDFVD?Zv1+L8275 zN6!xn?%TFDiv^q}J@MXNO|p|cf?{M|W`mR3YL-8dVqP(dza0&f2*+g|HiWwhKEo+F z2!vecGMF|>w`R*J?_|PUy2(mFwo;vvOlod~ZEYJlS?*Y*r%e$#GTfY` zMhCn zg#432Nv-v9Kam;yPv@U~raJ#aZH%$aW~E%;ImH*J07LP9KPLZwhet@@#_a zIBo0R-YyW%kvQTot-E-g_Fp{%!QLZd) z6cAfZuzf!^pW5 z@kcPO&5uNp*R>%>b#iYyZZSBnb94c;zMh?8Tt{XQns<%gUq?@Qk;7IOPxOBcyKTWhSP^NkaonKF z)%qr`#rzcJq_YM1(z7?O^`+BHhT{v3UFzL5Fht7OTP6zL)208*yOuy z|DzJ`|2v%Zxz?+(PX+C*k;JtL-F@%b42&<2?w)c0OOZIaDS?SQ?#VBa1HXprvCGm1 zKJZ+kw7Qj2on?ooZy+s8_G>aof5q_}iLrtcoLqLB=nA1&ra5UIoJYZ`){Fbkci2v{liJ?nLWSNGS{kOTb*)k1ZrUy&JZqK3FfHh} zT66R`7#S?X1ac8y_lG7! z0S?>e;v}wn%om5UMCa)(_ zs`;<(AqU8A0lG~l_GzYGd}ixBzEvHlYNN_7Km3~y5EB~lN2VpybGe~I<>t_;G)90gdO%dN2`?B=?u@-@OY4+|fOyjd- zEn&s?cvwJv+5FI?4_KxNwxw&;m3F8(3H8URa^RjhQyvj&chkl!D=+G^cQ5|Lo4a>6 z%k5blpl!n7B_k&@Fg+YG3cVf!`JcXrBi3($mp2BV8$nmI4Kiy_NrDc47sJBE=N$+` zN}qv8>4UnP)!a8M8`V4qgDdiBt}$Kv`S!rnQF4XH&iaNUqY?QZ*c8bHd)`3RtVu1f zKngvxpRY;P0X2~k17ixCZ$?vH8$wm+ zW_{jTZ%?}Ba3y~cM!{mX_wu`U^aotO8~52wq2Ez?pP0m4 zN8z2QXi)=FvR<`@CBlBQvuCS3AO0^8-}&XMR|t5%Dpz+dW_mU667c3xaiUei+ioul zy2Ws}_ZxrtAsuNxs{XH^*c#K6ncac;(Y^|hSZ@5w6BoFY0-FHs4~aptxQa6WAVEQ& z>RclT$57mJ=);xKhB9yptYe7JIQ0C0efbQaI( zO9RSeaL^vaaRWT7kJi@JAr=&&2jXe<>Nny?r!^(p9?byotUmN=5-T%%JR)24Fx`0i z=5#Y7*c^{G-9oofmrD#4Xhwf2z;>4M_t||j5V>mvhTW0z*qQ2!E;xvrIwPxyuSN%fH-DH zz*r{&q$6J@cY1p31aG;r`t>~wD!;3i)&eLfHG+4o>uyB7Ig95{;qRbEO^$3+4Wl3L z`$z}O93`{g0~#!RSv?yP))-fUj#r^&K3yg=X?$HF>zg!qR%v6j0z+J69YO6?HT$>TwZl_@Av4zxD5C<~Wil(4(9dXbS{Syka#iP#ePJ0g z@X>z0ZxlAqds+)^gkhYG4_pk3uPslE2G2yas`Us^+}_-nV{ zyuv5=a4JXaOtETqHry7XmMD8?6h1>!HJUoo@355EIB2gU$XHUVZCHGXYGsOBb1K~b z&FgiLg8pQ`^FpEBQOeYcl3lpYF^BAUD?%2@o5n({*>`%EAESxA@A!o|iTb;iHVMTx5LkQad(aYJKb&IY|*jCN5HEBM;~ipEY7}T8KQQTY9_sGC-n;1Z`ANv z7*IBz{(h>YA>16zGi>58NF-I1w`Un>57>30DJ0}2>4&K zEfcJQHj3H?_(jCMhmG+2QNFo@8`Al`5Lz2XQUl7-s645it}+LO$Xbr$act^ME0Ha9 zBZ=MKG1%Bl0r%%E*wHX_YF9j|2hb7nufiKPjP*sRzUj_M`gU+_fqhuBd}aiwqoPuI zdOKgW5*sB*`V3zC(t?};k<`8+@BjSybEv#42KUHri{t5G1y`01{jy5Xb>L0xQ%0{i znHjmaMqxo{AH`lg?tH5L81=UrQSY8o`X2wRt!$^>l_K4SjQiZOh z+2CW!_;B&t8$VvLA{@%v(J8f58s~9Y-aJWtLr-3p`F?MKGvDDD&${n0Nu21d9|VQ1;Hx%Xzy1v}>#*h;y+pZ>i7653B2_w3m;#vOtcj3Q z18Hnvod8-+1izo48-#JMnYIg@wEHp)nmt!O&?b88)qS2Er28!Dxzx&yd(AzN1rQX^ zB3;;&aMzCQ=&`ox&#VYQ3bB5$Dv_H946cD@`~-0I-}j;`CJ%Kb7P zQqd(2br`aq`k74mbTuR+UJ?&ml`)1))Ta`HrCMXn{d2xuiDj34&#mT1T;!yqgB`pP zTW_^9dM}9i22RHF3uQn$BHw@aT=OViow%j)rs%T&bvlhJ4m4@SS!J+*6*1g9b71De`*F9{9Jsrny%r^jCDuni6}^I(=!eT;+{YwW&KzOe%c>%-=?y zR3MR^bKmVZ{b$>&GBc5rL4kbTmppiEUkHYwHz@2I<_e6@Uxj*I^;>PZBBQ-S{NmW@ ze!sm{eAB&&ik=UF?Zh_KTX~|e?&C(ym*PFkcx=XVJR+?LuW?4KoZcRdbg6c^;O06oOzg9~lfh7%kO=gYWnE^P&cW1%k&wrAphLY9BRcLJW( zm4BUdYh08TO{4EDZP_K0CRO{sf6`ZE;w}j7WSSoWA&2>lQ(7%(4_?h_y~6S#u-za| zt|32FjeQh>?_Qqs)P=}Z6IG1Hv;C~@eEHmOWv>h+&>dEehSDDY-Kh zWw~u>CIv$k>iY&DB6JY3vQzYE{uLyfB*ozmY31_ zpVjzBZTB$EAKbnHP7mnLPH-*xHv08B79++kW5PQyvD^AH0PebdY+%*Lhqtdl{J>66 zs_@7&?rYo9#(1yXGEy7;_1;1g9K1Ky_$0A)vINTlA1PM zon++ddCM@~^ANXibIb(;t?|n3^g|=D4pM#+Ig}|1CsDvIt=al>%|n-vhCUT{L0%a_ zG}2mLnefG7%mubShrWEDZ7HwMPWz4+bF_n>!?xsdsrDy`Rg+)HFj~^gLvKe>=7aNT zLOLd{Ps9p6C!XEp`ocytd?1*pQ!=!K2g?dk#mgnSf%j3UgHLq-q1?yd@-bnzA#XqK@bkD2Uf6Xp<3U``RDB)UE5-$OCS*35I zSJ;lkzV#n?Oj9rsxSMrqd@J^*25{^uMdCT^%Y56ww1@Z-hV3NX!mq6UQ^MRZAbQ_9d zcn#WA0FT|bv(M}7BC0*yeC-YDVMoWXxX*xaQnhzN#~l1HW4vPln_u3*KOWXyePQ}L zJrcs{z4@i}-u~bTy~E2lwFPTy7XmhRlQ;$uIF&Nk8-MDJZk*dV{?V5HyR-82laO;0 zGLJ0nC1M9@w|9mDtC0c~5b=CF`G6rOO!zIa7CqZdxniC$D zM1Fy*lZvagMl9|15{Z!+Jjj&=vp4L@GK)Cr&i$0ThEu=XTpG7j(+i=~8BJ4K(eZzB zw)J{FK3+mp>XI4N$`lQxM6d&Al7*+%eheNd1YAvoaZo7!H1vkIRdqPVpo{3 zH$I3*pl@WVrZ6?dLEQp+cybkwb7Gp&4XGrCpio(Aj>yg@gaYP)IDMeK7-%ApsJP}>$eC(zk*uRm7aaGU#8B; zL)LB&7UI3D1~#QvjKUjZC;6@N5QKnqi+OKl#pwmKvT_C3%*|t4$`4K!A9FDOMLGYI zHMR>(o!CWsYw<1CF}6E+um(XRasqT-M@mP8O;KeXvqJh?nM_}_*6DRaXx3M+NEdF^ z!D*_t%-lOy~CtTe8M{Q+00XU}`%+-Je&>Hqb-Z!#h#8Vah|D2_ABDi`8`Khxs$Dt4&Vz zXw$ZtIgbx1X?>)%%T5FFbtU&>R=WVjm(i5yW}M$Ko`e$$!JEB)AsR(wFngA6Q&g$5 z<0YySb}8VDxKX_8aiiQZPrhm?jaNa>Ir(ACPKlJAFaeXWvUQafQ9 zi0b(KDi;dSP65*^=TetSM@?2mFB3QM+9`G4^JCiswBH-$VN|>hdbK}eq1U1E3PxBN z`31GtKMH;n?i`u1RVBN#e=SXFhR2f>F(t_(Hno#+>@a{qZ`YcYG%|$_8xAmYeNT)y z@8Fn%WQxO6|fD)7e%G(2eonjNfu9$D*B>t85@ag|Wp8##U zW5azL+lGm($e|DYp5@sHKf#{|5Vfz40B+COS$iUPb+}1>A&McH3y8H0N0Hng^%u*F zyg%svnTn?;HOZw=Yj{?MEi92v3@nN1(^rL3aOP$>47>GB>y3cB_%+IAk5 zyQoOy9>71vEB=RA|9{!u0dfT?HUw=IEmqPP_IREf#TvV}MZ8mz;_u?uaruOSowLeA!mb zd@B0Sx*gNL@683g)rEy=oZp2a*MlTSaP-W<#S^|RE;T4e(Rc@w0s1-J?#*X=^O!#A zWU6s7_I3sb#7wxE>vaPRKc4aLUF|-vYO7}0ib!R=>N zL3fs9An)_?p?=$L70+t6zc6d7d(PVs!DBB%gdBYI_M(r*D+(L4?gPkK&e&BhL4Msx zv}0p4sLtd+fUfH8`O$FWOOO>uRAT%Liim zVF6~3<@%!r!J2c1Xf+(mCV_FcXV_hO1CmzxFhR6nySU}4U~}L>PTN85V({QtRV}Fjvfp>>qc{t9_>0?h+SWsgUkCc#@2C!b7O{;YmL{ zo#Iz$*V?H*Ht7(}@#_~40->PQpztnP?sOQRm-=>K!C`EBj?kz;nQNA3 z`!dJ}`OFNN`=w&em1cA&<)}F3aKr6n*mk|pZPk6vR?N9HqN$ThAdIee#8jOYO z`I&n`_m=GovuQEI)wR>{tIGMkY|58Yux|bCzf&br(K`Z z%^vA2)F8P3b%14k8V$v|IzA~*U3|Q-g(ckO`@9~!Yk`7pmyuu6I(C6bf6%L~b4cK= z>!1Vz-b*=vVphYxcptKmR1J1?>h~cvq!N!erEN!MmI`PuQS3@7@hq&)&H~E>%4raBk{n^FE5600;=h#g^=_ZP%jy1M<0{4Fi zb99MGNT0UchVt)WIWz$fHSLZtG3fQw^0V`2CVL}=g-X=!T=_Sz~qJp zh2$V3TNH1dV4Dc;Hnv-bz^uK!{+AH{_t_PcJnCTA!|=YS2f&K*3`y~1&T$33mJBbw zkB2F;*B^FKwJTRfCzfv}q1LCm+HRP!_oov?TGw5~_?aaJ;Ubl=~-yR*7C&UH1X&YtksE^iXWOGP;v&MNN`c32o zJ@@VIdBi*u<;Wlg0oZivW7Pg$!^~1h4&K1un1Z^3j)wWJ#-Wm;SP)mlIihom-=Gk+ zW zlpi8X{b7CuiP|o~c;!^hetvR*l*@+zjzsMr9{KgzmgYy=@!W`DtuSy!9@;*8`YX_G ze%mhx-vz9twbne!gjTbSKZM0qJA-`vS8j)%38rpSQ6ZSu`#yq=(rb_?bi`^t;AyW~ z6QDgG#3-jvm!s+`7Mbd3TyoEoU~ES-J-Z^QU%NGuyh-u;y(ni&Plui@)uX%DzlO%0%7 z9N(K%RO(iMs(G8*$y;jeK<4aXp!5yzE}LRleeO?WFN{8R|pQom3;mzJQV_hCMr0+;6%I3oBO4_lgd1 z#pc9b1uXV{w!=WKVEsfx#=WCU=hMq0tDi5mzM59YJI3J|c-d4q`#ZGAyQ_abB6~B0 z1VN1}L(r@e>s!qofz-rZ6Z z!~GQzN1+XX7o7A-6)Q@(fa6vP3g{;h2_P<)>>|dFI=Yunv_g6 zAAelW?mn-A z`gs==B8;L7&@b+llkpU0pcLxxO?k$C&+>80ZMP~zc^LUWWPN2+8|t!l2yQ7*+@*rM zQy@6SCAhm=aSt9GS}5+)5L}Ct;!>=*Ly;CJPI3RZd!KX9clY^|m9_Hg&G<9V%&;|A z@7Q>cTj}Wia8dkOWU_wC z1@0Mj#hL}d21r2ea&dF)McnC|qQhJF_JNjvU;_7f8h}g>8&SX6`FqPt3)OWon!f7; z=J)6x8!j!MxNXaJXX!6gI3>j_Vt-Md-Zh@V9^OWTpE(}Q6(!K9e#((TfCNaAg10;GW*XfBvvJleLZDDVbM4>p+7?Vg2S z_pOwM=6VHg$6U{9FlDSA2u{ck-~OR+9b&P+p^Q%QF)t7{z-tW9KYey9%u{4!2vJS& zHF5akaVbh>+pDB*6h!1+6#}z%`!`D=K<>loU(#eS#2BK`KVdFVOK(ibg)Uni)t#Q5X^otS5uJkltC#6&Q%s zR=ZD2O;3GCP&QGceOlV8nr$gnLYQSc(rxA&^K4W}F~fc~rp9DZCbP8t^l2USp#3yC z<|t5MHVF}C+Ce6flNDAd`oyvjyJlqo-pYF4$E1v!bz;qICV|+npI_F zx2OsohY?4FLd~A;5ghR~K*d3=@K8wPy`Su}7vIMO#PN5KV@v)6@%?)h++$pzviBK& z4rM&X+J#c0*okz@z`W@;`)KR@@WCq~sH z$!?^9>QP!kPYmI51w-aae%@L|VY*MsZ<7Skg5mq~Z0>gGvo(nDDKU!KHYrl|{3a5Z z$Wcj7f1&DPY?z$(keo%-AqzCW;g(-pSpL8wNHT{xuaV#R4zAbPz60lB1=h?(*Iw+F zTU6>uE1&kJ>8+ys3lF_`TCaZln;wLP#{qOiffU$Gm<#|-EC+oE`QFYh&QUlRUQ@JTHKT6(~r z*de1B0-bQm>oepplbIfJT5li7tA3HcGW!ifCKlny*!nCYrtgsLw%iU<0O01xPtlgtN~j?*)HpmwgMhp|Jp{u>Z2AX3qZ>>GIH5JZ1v05 z>y+}2xqD1feq&z+ z)uu3NULzf_d*cA->rXPWv+Q0vfMQyg8#(wiPgf0AOk?T<{VpxPwGdhwA`d&pW%qA8 zyGDulxAp$(p5)GwG(*p5Z#~*?D?a4O$_SI{xYd+OHmg=B*-|`OPHh{Iq~gVo^1Adx!R|b@(T>ZL;I8>6Kd4yxiFLgJ}od) z?$<<_1XYq%H(j#02~Y14-H%4*Lw_C}hIsdbuM@lig(%DB6kP>#Txm1tSRggSqWbuT(k z)?-!$uZ~RQ+fyJDxI52qEnuu24+*_+b1otzA66k#+dbZOx)8H;IR(`qQK0-p;>XdgLF#HURX7Haj+02? znPR_E8axAMgyLj1Sxs7go_2gMTGv|M+FwyYY2kOY>VBdBP&2#epGTr+`5|Xv_v36w z5*Zo((Te|}(6;Q>{Y)_9qOn2t<#t{?zo=cf7>b0!%|f6FGjZ(;>Xo<}15;9aHNcA% zB*EOJ)cu-2|0(ZrGd+*p6KIE`i_g;?e8PuKaq5= zNM(qUk6)K+ltGwN6-ttzY)_vWWvVJ)`ODA-irEDDUC0-(;GmBzi$N|?jypTCw!95* z8=5kPF&o|4ogSLemTjS?i@C~8af3AFJlua&swpgRsYhS1n-ah(sHpMB9U%w4E7`9= zjcAwYZbg%6TrP2vj&T-F6Dc?<6Q^OAqm{4Ct3UV&1)om}WX4F9IkD7g6*G78$1qpqK5 zvUffOdW8Ry7HBK4m6%8nKa|xI6<*qC67Kx5wQG?4(D>IwHJDzQDn30Ff|b`l7$Uic zi@vavPQEtY{F4ki>eu8vzqBX?3(k`Oy<%C20ptV4n}^GPV67G2TqPVNyg~ zOlh+G9Z??bSO zyunTK4xiQkAy}q>cMRxeHw28cbkcGvc?gX80RTc9Or(UWuv%Oynt;Jk;}V<9MQk^7 zLCdHRM`P>VI)ioet*!%MAB${n(DH)iq?-CRTuPWI(Za8TqGd_>cJh-#`&@i+;e zfn3^i*4PGMQcUAaG|>)tc5xAY)%|km5+>5w&DT$3oc1SP%8 z791*xA8~wMVKIh9)Ahm;cdGSXBW(hN%n1nZ2m0Atpn}oOb5=aA zWY$y6fn`EpZ0o<0X<2S{6KG8X?4XxHn4L8n!BGxKA<`b5%IhztW=Cf_Go9PkIB%}M z^f*pgq4_(4KCiyY73`%WGd<#b9;I#SSLMt$#;2J$xa))Arky3lnV*ld-PnfOV>wq9 zZ69XA+le-pbu-t3O;bFxf{q#b;=GKC z?WK@2TaqL7TNqihE-#A7s&>$gJtmsx`nVWnLxv)sKw12^VbdWQ{EvBSTtU_{@wv1m zUy_-}p_#*CrLd9Qk)X|AL(L+5N~0Op9MARc7q$@R?OV7hL@aWI~pG&=5|L0!kK z1?jCcY|Bi#JBvJb0$LRq9HdO+ii`20Bi2c)@fDx$r#b|V~y`rTx`x@{W2A?E}# z!PxF;Z3a>(DQU5fBXa2G0vtkbgU7Fn|!(8 z&<7h}t-?zlvpcYR3o2OzS~vd+SpGnkUV7L~Fww;S)-+LL*P7~VvoL5H4RgnW(gNqD z)30mckE1e54ZgYdkDlblm~OE_7krA#t|v|xNQNJ66)UsIo1EY*SWquY5bYQrYP$;;esl3ba zkYB@oxL{qWVXx_+FqR9Y(3Rc3gJWhTb<|7_7e+vl&C~oU@POZ0yEy6}5AFU0n1{&7 zT**4Lzs8N~3ZbL^_Vbt1#LF$z3(}%O>R%qVyRD4t?Z1*sK{d+a?giwL<^xv z#OxdY<+GVnC4o(Ux$$ErYw1)qUx3z**(hD19i_rdKVF=Zo581j%Hg$07@&}Gm8MkR zDWhH+4&lUp~F-s>5vhq4&M@`mqxk)Y1cQ9!ezP(mIr%6+K4~TZ$~8 z>Fq@J(_ES?yU@!!P2?O>f+Q$dQ$Hjqj@G@ldVJL8I#L}8!)sI#zc;IXNf zW+amuqt9YVko0l3WdL8x%Dz^Oh)m;i18S)R5L-=c`JQo&d*Or_%tBip&Z0Ke{_%g} z^M9OI;2-*=LT-baL`W1yo}BbLSI;(BUrr=cce+8PaVzwljeZz|G=-YwAxD0Uw-r|y zRZ2#A*?@}N4l+3{wrkNbHANKV^{KO=jVaz`0!MR1eCJrnPGp;66ytAx{kPL|ycVSS z@iLA8U6*%K?tM;QTNmomn}vYBu(Cyn-H{oE|HdFgj>2Rl>a<19cPF4A69c_>QC|`i zSvFvKm9>%7rA_?q3upOdDVbV{^u=a|r|$(1$VO&Al`^L)v5Qc%dS$&)fW5M2u@dHw}$MS(cG@0FltyFkz$h!~vE!K@| z=Ur>z&IO?wSPJ-fJSbo-878lU2#gX=W;j(EqZ+Sy7migOdn119HAWb?Fawtes?eyy z&&_DyaBvwNrgTs0nEtoa|M#B=8s^SyV5a2)g9S!R(R6WmqnXtzz1g66&!m7^QB=Y` z02+4E@&-Z!d6I;eq!3L{o#kfQ7^ffUGMEdugZ89|NYC$;K#-pgJ|4NYP-9EIPn^8u z05Wwckbd=d#En|4$m%{v5B~$Rlws$`V15 zLof8+G;^(wIIXUX?S|@zh#yd|2N`YL_@+#E?p`d`c~?d&ghhH$j}&}5p>#}WMI(2c za`|myZ8jeSiWX3x(TzAz#H>Zia{4J^w9h&I;l`J>}zDqvp!R6wn!rG}mz zYen!Yka%){>?SgGcq?GijkR-5`WxNKvFLiC{jUe!025?q{usQ0`Q6P(cVG8pt$_*5 zI(IfU^d%nRYv7VoV#oNnjtYQ!wT!lU$lyy zg_jBMDK9Xr#bviPXzPD@x9yG6WxW?WDtys2+knrhAnv{SXID9mrYtl=-zB$;FH%9q zh((P>&H1PCzux;FnRcP^cWrdZXcNIRpO?uoNpTCN^h*YN+qZ;a1LpU-rypB{x~F>r z722QH)r8PfttG;6*>~2mi;};Y(yAT^^~#C4RJp!CuXOr|ju8QPdB~+!!e0Zf+*1y8 z?Hs^_iR^d9m-06%1k&4ydSY;r6^!~Aq6ZwLH6WL84Z$sxW~aY~iNz zJ~?Md@qp%e|B9S|wGsm{79Z){RFz}Z;K>s1r9soU%TL$e6Io0RkS%Ma*)Kfl zSH3lxF+?t<`?(l$T+rOi5oW=eoo-r$QD1OeB`Vq6f?h}TE*7RYIWwyf9o=#ZWb=M9 zL1nsBhi1)|!4}?Eis&X9(Qp9P91zon_FRTwOCxix0DDfB1aCpv*M_wnO!QJ?)5jkL zbt(Kuq*0h_Gs%1KfUwRt*2i>MZ5+_a0Zy1YR#6J(eu7|UKL`x2B(iEcB8mZtI#GGi z^LmW91>=SXjfSR1OTMk>z~#5^bd{Go$s}bYj<<@Warvj#m#ONawW>ty^eUO6N=HVh zP!DY&d1JrjLGEh~X`19WfG)EJO#(Xl$BQpRqnWkIZg!}?K!_?@4}xQXT<)EAarUjx zmCz8gm=w4J=GCa1SV)}xtOWuWG;oQ^o!7D5!SsKq1$KL|dOD@zKsZ`{( z-b{o~Bv#16irE|4Tbw%xmq==BQ8`{Cqlq+Ny^0yx6%`7W>6CJzcs8Qqm_AKu_?316 z@Bw~V;~CByZZP5KbA{x9+K~~*ih{V~8qODfM;T_tjq?gllZ9Ml?8YA{yy<31@j4#S z;6qjU><~?DlA>DQpmLd0>DaK`ScDiKT?>`5*Y-AR^!Ij^)X@iuxwk86TWLIo;U`$W zx_t3n;bsfZzkd&o98QWnqB}ckv?&UDE9Y!$_zpHN>~OwmX%4}V-(Q`fxOd+iwzg%S@mx&RK zU&s_S2XBUBn-adfCxSI^xK0xbr5;XVd6Nk%Q8K*eC+MUQST4QKo2UOgewb?!I+JpJ zEcu1nM3BgvkXilKPs#>|y(bfXVHR_8#`47lcOTqj`bUtF>$X#d#z76B&r+<-7>g_u z8;6)bfelz$=r#7kk@g#V9c-%v&x76oW z!=?4PYimeWGq-t$ls&i~^%@;^qv(XcZjnaRuqc{eD!Nxr05C-Tl$a~SsywR;kR=ZW-h2F) zGE2-uJWwaPM;JjZkY3_9RJxdjngL6_>=yP?I2fJwY-BbK;)}ktA*wyMiB)GaETN(lqp2lU|%N z^mXhdS1Y!X^vM47&}n6L+*{TQ62;6~jNf}D%=jXFyo9vh*j$arN=)m5>jv)pQ6BF| z^*5gL3SN#-S+(1q^a_7zVoSjq&~a}pbM7?g%-U++EcjEtu(l6{4c-hj8KZXiKs>Xp0_|x1TDS{UqB4v>MPfr@X3JV6(T-xEW6qyEu&X5>cC1yWkFZ6Z z2q&m&a_y6OF=HZt`yg$OR@PM4uoZshx#;@mx~U?M#re|O=Q15F%Ss87t%ne^@AxDVj z{tiQByOB>Ac{8i9WNTTlFzI#sHHW?j;%khE{6_+PjET&zr}gXR6%TM6Yij^ikz8S37_v8*PKx^(*0E?gPJEckZ9#Cy61pV9LLTYSJA5Kc2(<@n0+-}w(kQ~a-(CQRnJhbFKa4juNWvp)-R@2g3H=_((9{f zl0&6`9(lTWgsK%)w$T00s!)L-8PVC;g`F=D?v^ODTSM~{BMsiX=kJ79+93uMqF35~ zs;eG3)dT%6uB=!?^}Wf&tS9r&gM4X|&~>!K97uQKL1T@hb+%C6_I0m4HS2wSiWA~5 z(mx*b{1Ww%~gXF&bFX+S3RSob}yMg%k~iRITuxg?E+SBZbHp@{pti zV_tNZ5i!@bz6V%H1lUyC0OJLKPlxQ<7D=L{a9z%X_$B-3?~+;#1z=eZ9I2M7&G~k^ zNl+0NEi)mF*;gW*?~iy3?Yhg zn+V+Ml)b-_(=i6{nbf>6fsvAEe-l}N+;WCD#XJ;TiBpF5>@XL+raIvI_T4_QB_T+_ zX%oB7ZJEh8`-4Jk=;EA$x6idCtH{0smtrsZYuxB1XaaIMJ=zE7HG@5^P2xWd1LrfE z?&rU)rzOALOlMlSG?U4&`B89sKG!L+HJ&0Sp1BZ*zFoku%>1vkgB)KSf4b=X#+Fa% zd&zSCPN{}-?M8M^pjePO)Erbla0iz|8jaEha7AUtGz?l8FcNtya_?N$deLLOMOq|TpUzWl)-L%2Q}7vAety5=of)R0q>7s2r&dcPNC=S4n;awQ;= zgoALA;i70UPLE`6fWbv?V#Ebi)C66WTiNvY0tn^$6)?)>orgQ91gnL(;mpzxrmgWpL6uZV?AtXlkdRfUdU`_OdHxQ-cF8SembblJ)QH- zp12wC!0s0gSgwdl__k==plV%@47jx7B63fni$rZmlx(o(`(1=9e2An*p$FS3Mf$uw zCnwM{-_LFb3%pQip5@tId3R=L_&zeI;bgn#54gftI9t;^F$mP5gVjld07gm(I)~RQ zH#c!bQlIQ^8;W`%;2=RFupL_GR!UfalFiELr%0H@8WTg|-_`$rs^ORD29@s`JWBn9 zzIrAw;lpdvwkSr_4)K*}MXJ%nnH;f}XNU_j-Qv!6K2hj?~hytzvKsN*{{oodR zWxw=jI87;zn+c4XwCWjIAjfvo4$bm(BgbFp>YDW*m|yX(4Bn4q8C}bz&ByN=x*l~y zqX|4lLJ1U;ba2(^g5*!jp^}F)pa`FB^7`pwNfdoxUp8Jfk=r5v zk>Pb!%>0mklO5~Cv;NjXK)>Tv@0R3?raeIII?&2#+XU!?7?84qK@(Dv0U-@YILN*N zMFoLw{596-vHZXSB!bGv#0%pd)Oxo>q zLQ6}D+*Bc#cg%5c!t3gg^YhN~A6n)qxu2sSB{eCZZk;l>(|jv2B)W)!ifB1ZLDN|r zADvweTh3$aER^83=cufF@3+0u3`U&Y&8bm_b!cluN_+6N&XFsgg@kS!hJ(yAD7_+C z;tSR&wg)@Qaky0CZ7WTrqIb3dyb@bUactOO)*uwBd`x^@LQ^}Z07~{ZN9ZriUlod$ zg#E*=Z=_4iBs7Ucxouxs*JK(nQ)+7d=IQ~w!#CSsxh6*Cz0A@*(lZ!~VXN?~$d;%OK_wQuB8}{-xiuCr<WJF>BP;bUg7WsMzl3AXV zp}x7ybvqOyIc@D|!H9%dZ71$QUxHP1+qf*;TmX~m9#OTDW_L`pm@xltL;Zi*CUQL! z`O}od=&a))hzRm>w#VItjNV+gmR<$!4k&!>u3}~Iy-#m24{qciX zZ4f}+f;#e)_kGz8jss?~nZVLXBbO{@E-EwvoX7NgrB+{7L(^3exgKQOB8PR9SoeX$ zC(KH>Gf*1ZA29>)?}3Hc$H^bpWRtn7gkb|I@13ZFo$ej+{o;yByqq8<9i?m^?VVdz zXRMFa1w>uKw=@XPVDOF_Qf)A$z>=WsUUCs9wY_^k=JOYZzGB?vJ^7($qtQsa_6$Dj zNtB8w!2Ly6=3pFCEzTMS_J4)z|F3W+e_D9jih)R%83ufVV1y-O0sI)!FEAKlUkW4R zxUuR3*>dIEa~@ifn84QNlUVp%Bt$YP+}cl-6xJjWvs^wk-8o8EXqm2wekHa%OG=DH z-qo-~Ld@r08LnW;=#K}s5}h4T|0G;^!7Oq=2xo6xZ;MOrCEhTegA8(9V8Qfn0zl!P zqGD5wF^i~gS5cK$Co z?B7mr`t=JUJ>F2iMa2uGr_P5YDuh%(N6>=mo%{hAh}@KzM?iJ4^ovOt^FtVlGrTQKx0dCHnFR4m~bzwxU8dFuo)AQS~9_TpnV={fJ&nCH_I^DI<#cZ4D@73PLdL2eb zwLBzqvlKS@V>AX%W_(p)XmJb|+cRhzwonINLBLz|OZq|DjH7J+C_@~oB+nwIqVocL z!oo%>_hoVEoLrO7D?qeV zikVlD`;)%*>vflG{bcS;N2F~$$5l+9_(p^w6GdBGri~g4O>M^>fvQJ)DtgOBcNf8D zXla=TA1D2A%XAnUx@Tpnv}c^7i*(xwy`k6c5y?sj4z+hkWuny*U4r(nMSH)-Eeuem ze=1-|Xo~K?@}#e^e=U@pCw)#@B)I${MPoT)OI;4%J9}Z12h{^2Uzz*Wl5;+>t?4A( zRH5R&cZyV5OGE%|Y9sUAp2hPcE{f+(7MOW3@(K&PWIdl35QDJX`}hT7a0XeQ&@2CK zW37{QRO-UUU5u$CnjeM$PHFcQQA~qZFM-lhR!@c#>>K>2dZ&UwO-!zBe()*#L zD!ia2!iUnWBon(zQO@%E$jqN*N8s4{G*tJUp=|Cl@@-kZG}6+B;G0k%sLP(%(k6Qh z%3{&e2bF^_R-y&@Q&*wmRC@5+R37idc zo2K#edI<;qK=T!sb(jN2qJcPBG%p;YkDepNd4!scMB^0SFrY7oZm2k2 zh`gd~LwU{>d6m2*YL~1*z2d4QvJnUS7ffe?}Vl2gQts2(ymh|*D)XeZb;EXv`8MT-ND^`M! zm6nK;8Qj?Tb4ktSfZ+-BP;gFC4xG^pT+j>z6tpt}8@TlYvnDxxO*!MI4J~K+bjEjY zTtM2b6l$Wc3`$!<#45{QbBrp_uIMkO34e-_s|qM3+w3vn64FIJHxDE zntqLq+S^mu?gYB@KF4~F&@kaXr{)La+A4c}Ezv$MX6#$Ge3>9$Ij6diF!~8Ia!ypm z%=QO&XS34cz%vAL8?0l|6Sk+oh@w9Hn2VqG{-3U5_jwwyuoXUpP=HrT#OKoRrN_vS zmZg0+D8{c;Ex*iR0xIdze5{T|I76djTG~+1rYw(@%Shuwl9FFyKy;Ea9Y)P#u=9x; z^j6N)L&fy$CZw(QkUs3%f&zN^9>S-WbQi@?((FM8lgs3O{i{T zXIH@A@Ol4eB@~ZZmL=Qp$xzHv$)8-;ba(C}XC`8NPWq;>c2tsST6mK_GiF^lnK^tw z*V<70cMsa3?i6e?Xq9G861Xm^IZ{e&LB0Btg^M1#NVfm`oN0QqnO zF4={MCMWy*MW;!n)S<7mySBB*A^W}mMPjN8P%dCDufUoz9)Q&KJ!W)qkJ=f5VHZ{C` zea{H6IzO`E?r6Ecu{-J66_O;{LzP0d1(%1OI#;7Lt9ACGMN8j~OV&?JtdX8N^N9k@ zlQogO&}Ok(ipFe{*s^ZCHP_L8j2sgqKS%Z{nxxfJQZ$V-d`F`UmD92aFVN}@L1Mr6 z>#t^tJco2v={Eyk!?p9V;OVg=WA4F@8pzNRLbdZ+l+eC_Hg#7)f8IDY4$AOzU8OU9mfskf{-s{AeN(AD zHZEU_wUmrA-ZAyP!Lqtqc}sppniE_OnRe!8Hof93I6^{zC_-K)I)U4MLDRd(&f7>r zU9h!}lzws9VGI78Wyz)dqjsFjiB@FY)gCv1FrP&m!eGf{58`-butOM%`^5AQwV-+0 zWrQFEhRo9=xb=b0iQq5)e8}I;XG6mYr{yvorwpAojKohnTYQ||BNh)W6FS`B%Sax+ z{ekFH%fQA;^Ahbuk^K#g!Ts~LB5l&L)<_*gTPuW*HR5B-Cc6aha{-h^a|+z$S}{#vw7}gz-jml9XV$l?$zFQw^Ob}8Pw+)`|}jUTt{@?voL5a=kN%lX4e~K zTs-cjKdc`@B-NLF00gUJ`$zQ25NyCU2Qf!B!&6RB!*3!I4y*16|14k#3_SZa z5GsSI&(gpw-H^30Z62?NTK`PPG`;<56#A;Z?FdiQhTHJzK>F?gSPeo5#44AP2(k6_ z`D`U$R5T3fR8yl9h(aa(iBzg_%jX`IF|2lXi#pRfQz}~O3p^dGj=ySoy43x?j+*Hr zlpm(QoZcg}GoG{%TGjvE?^CAiQRdV5Y#(G1hoUzWLB`OMXv;`DjvVs9aQ!1>o%ts> zzB}EP20W#^gwUKFh24~08Ujm?7S&~8Mrc&#sWTUAmwBe@mn#q@Gt(Dpl*@kq8f1;v=YU{Q` zJj+O3SG6(t37CGzY1Qd~ubk3<6O(qF=qBrK60KT+s803*6TU7*j-8q1-<+8FsFOk3 zxvP4>r5i(}L&HE@J0>Eh^|ReZ3FT$PO+!RelaPqZgoxasX_ziAM7=;iKUIB>p?M@d zrVTsF$Muc<(&ruLx9~)*e4+VhgehNAXUoJ@rXlmY(t;1NmAQlvbhih~* zZOxm8X|LfH{Vr%7$jqa9`X<#kINdAC;56v5yFtX?cQvnFZ1i?+h__ub;t*P@__7^p z{<_y6_?+jJwKZNW9Bb*Dak__km%61dYaxx~9=fN|YT58_k>TH0?dLxC_fx-j+s|)y zPu_j``teso)m|ZTBh~3>M=XcrUs?6PMX}qW`V+sg0;q>kLiET&$VwHe$NK@CbtHAP zOD^27xbx!t+2mQ+U}SIyyil7$G6{kEqGD!NX0MeTCuwP2^ss;*Gz zH7M($Gs<$03*h55^hDeXwS7?8Cq*%35Bk!`=76OQyW%PrT!ydwDqY_=Wn^K(;z~iN z@+X~7MGO5*_X20E%)ElKHXUNwCDh3$BeWTce;PSX0Tu~$_pp9Vwr-i@A@#E5Qr>$a ziLdZtAk31A#vJbUEbhP#POd6i>WwOZgCL!D0RuK& zlkBZ~hcDu{BX5p6IF)aoe(I2opn+Zyb5TLKkhqz+L>jCZKkq3+TPP;jscZ#7vs75g za3GJ_%f7eKRd3I03%?r7{o30*xzYK!Ia8gTD|)?qUO({Tji~?K!@K+a=G=t3h_ICW zzmT7Q%LMCjolGbRD^-){kr6Np61qD=Y+>@i&1iMJW~9P2K!oOS8ey|<)} zS5id-tJEDag$jI~(w(iW@KpV>b_GvZ&p~~w6Schmn=rL~kVwO?A?jhmO(o+84ssAb z+J{ytR%0}S^DJ>y^oYi`GhXT?Xx4iUS2RIjfsaQDJW;+zGY%Hd&$w;m&CD;0aO}Yd z0gvpwI_S$XsCJ&pNzYVNBBcGewP?{8f`+E1jw_km|3UBW!^~K%2ze|4tehha5l=C= zyWK9wpCOuwy*H!@Z^4dMD>v0bZKF_yjNsakNxSpB?=oudGVbmo8GjG4_yVXn(Y<&> zta(ArA0;^Q<~%v<2dpNPE#qTMGr{u(g18%Ma5>#mdJzD)*WpM=m?(6@X zRZ0UyrjV9_sHx+~Gf~_XIva6CJx9@EGqyeM_OF7hh{}Zhmc=z~p{PPMdNWNgbFa=2 zjj_9Z&W-^iy6~UELKRer@lB%`-=()iI=N}6f&mksjS=d^PmUTiC0E-QYU)uwAc_q) zwa!|0Jn5)Hi60j-83F}z?mgFaWhkHMPp(SZXR%CEgqK*H!jwL?#E5ucA9rjFrV z)jXDsfluW_CeivkO+viNQN01jH7wV?G=D?tlTNSfTsK0lq z-l3t8g-0LU$>dQcQ*n^U&M*{biX<$cVKSr8Pp_u~%jXAWHw*CTa7h(KfmrZ(9{IDT z+5x45TyuK%-f_w2Jl{Jg%<~OjWo}U&U2I3KT>onCx&GyF`f%qy^{~$}_2rh}^zLJ* ziB+KptuP}?IYBwmimydMg5m3t0b(FIIlXv5l^~?ltj9l%?8q}n@vo$% zuidjDk&I47kGO*76zCNESe0n4Zee3vLA9`aesq0_qc-xkSzwa-?XnY8=`Ec``~GTvDio|C zVSdPH9R}F*`@@AAI!jmeTMCn~(WvqB*9CXCM5dX6^WuJ3>7*US!BvmB>!6Q(OfM1FP{{QbneXjiX+yk@QsL(HMkas${U2Y04GG%q6^uHA(oQnk|&=~GSR0}+-uA^Ba*KF!CU^=+NX^>ZWoIH z&g4@L7y~8b7q1yd)EcwR09mk%3u>_aa78;qm3kL74XRp9&M8{b;u=!)B+f<|%J@B1 z&s4hlkkZrx=h1f#_RHw${Lu04d;&fA*KhQryFcffiMbWSOgu$@ zwL4z^J!iA)&19m9Pj8e?Dow5Gm_URRXa%;Sy2+GvwM-U`WRut(Uy+s)ppYJcu{Klw&SOuVl^#7Uf130e=fE!NInN!F6KQ7j{Z^{X`72ak<=1~|9PR{XsYWJz+l|ALYw8e zssZ%e+Y;OWO=H{&2TY$3_PwgQ3goW%9EydNwxzV6AYNyN@BP(|kkvjhlbeL|_B8sE zZ1Ko#xv>_7l{r1aTY8Gb*ZbjmIBo3Vs;@mQ=;Y>i)Z?d5M;)gwqP~wgCgNhg9&8%! zgmi!Tynl@>-6teOwqnajOIKTT5oiRuYN%7NW0NE|eXSt=a7N9EbMMfkI**)sPgC6U z8r>QtUwf^Y5izUn^9-I=e>sw8d*sS9_kmYHzqw~*v=o%e+1%j)BeakGivMszJ36i%@#lE!C0>4DBCYBW@E7Cf5tw>7LWQ|fAce&4}RSYeDXgkGMALgF}xT|E?v zWYnW?GtRb=%{KdusvjWrn2CCz-_mv#Sxx-QlIo*MS+y>|G%bjaRH2S8ZE+(r@ML;E zvMuP-o0+SNdgsIXgn??GBUTJb#F`}9fYs_4$R0!kS}(#w)z=&r)HZ)8g43I zQQ$Y0W@oSR5-#&D_1ge_?`F9AB2l}MWyfoN1@$46SC8$v2jR6PO@`y^-`DaT@zoD% z&?$}Cfas>!j1;kj&di$L5}}-73r@OMY#;2*(NslN559Y~oenSEo-RFmidn16M;u?f z+wPyKx?gh--3c?Ts2@WL3{jyK|yy+5%nlk=Y zXMYu63tWurj)w)8Hq;j=u%SL(rbYh{q`rcxW1iC6hH~(*_JFR?tY=V|xstOpSIE3E zTvoYDz=~EL^5Zq|as2SlYMOELm($lS;yza-d0#Fs@*aq{Ti)&EG4z?hO9(v<$~M`l%_9^qme1vwy3cpM701 zU-^r^VZ%Z*1|+6Wnh4I_D`;mJ6<<`2D{nS+{fZVBDi7KnOw&cST})I$i&BWb${z?{ z0*CVpV&fs6<}({flQ)P1aFWU=2yIxanhjJ7#`O!n8j`OB9BuProObORG*88Tc)-qXk_RF&$-dYYuM=szQqT3yvtavwRK4?moZa?6Jh5%7v70ou z8{4+g7?VtFHBFPo#>BSO#c7+12u03$!_H3%DJhq%q7hon2qqQmN^TlwCm?O*?Csu#tNJk#I0*a*_0!~As zw>Bt~$WycgH+L|0zKRM*inFl~mvgqu*PDBGHpm>o zy~)!}VmG7;@*27IJXw=nowN7?BlN#DbH{r%s_cCeDc6e(Wu#)v2_PO?xm>(jeH0CI z2c7fiAT%IA5d#57@K_BR8AgFNOF5>UO*buuOm9%L(Oi#UK2?>Dg2MJ8JW^|F@nvDR z2z>CDy4iLWUPfG4LT}@KZ#zz?IqG8^-&I8LU#+2;5o`JcngY8f4fNcSyVTi&y3j)9 z6(xycD5Rw3ZitAXX`Qx~9Sp`s9X{lT6RvT|P zu(!u;1Ixif%4(YNhMn9xnLQKU*#)1!l9zM3UzA6u9~pymNpfza(Mcf*8p<=vz0by(xNP@qajFd!ZYIh zD72tv6l_oNiQ{B(BLs?~kaxPTrWp%1op~lDuK<51qDNB=X61MFg0h?^%9q>6ysF0J zWL?oFD1=XPW8sGs0_(u*o*=K&MT(yHIno4jC1~<28u<6MWh=Ga_6;fLKbp<|KFR`Z z06c263l;$~%~~?vWwxFzL>ROe7e{u?KcM1mU2BfE2cdhlEvIUKX2b)Tiu^{tF*L4D zEj5|vppnlrZ8piE&6f*qOYKM^L9JQd)O7(P^-I%-_|dXHTb`?$vh>Q}rkCCk4u6<8 z5}QgJtf+=xD+AH=6J{HpXEnWs%S1A`LX#|O%tR3S1$=qee7jq1i?7a0BG|#0qtcVb z+}AH0;9LCZgEb3HIKr?%E%W=UEi|c@_uE;#N>vf?IhGt;EyAGodf&vFlJP8`(U44t zS+3h;emJ8}^*l34A*oG5lVqPP^C`xH)8ZV4h*Mv+A9o-3bHq^|l_Xrb*pGZ@4i)ya zjh))8>RdCzUQ;%Pxxu*$#~cisw2s#yl;?rRin*P$D&L^%{l{7ewwtdKM^AtF1>@g5 zhBz?hiD@EBjDWaZ)NO>4fQeks?vrOz%&7Sx>Q1*(I z+SD2|?T(z4GYgA3&u!u*N7WHQ$vzbyp~WKAi6%QHo-1mk^#==^Kpa39?a$g`&0E{{i}X8Dpf6;fLcq}QZ6>w@<8A2@c)ApHaPq5ABZ1-{SMq9blg=Ecv%EC?xj>eW@F*xsRo z?S&o9+|@Xv@)RkPmrG!s1oA9hE9^q8z_ab(N|pF*ns$w-n0slrOFWH`*;bEZx*|de zP>19C^&-vp*V`0yej(yF_pky(a?p1rdg2@dFbl7?DpJ?smZRFd*vho*;$(3Ar@wVk zi0yYvE(-bZg86VU=GENZX-%hWS6UjUdKLA=WomGB1+^opWQ!ayIPRyGvEpIPbkP8& z>#JG8ef=!lPy@BTH{gdZogPVA_ikUCo~_J)^vTJfKYzm0AghgQkQjNRR>clGZ!a5> zEa7zuwr-9~_CTM_T%gtay`=LPm~qNHzV4M%LYDHdLQ$T$GGDaV&if=40D_u zMa3dAx3o6oaribBm~b_vn#C}+xQ;Q3>mk@yoxg;QvBo7?4uDOebUH>Z{sg?yQv@8` z^xVHJZUo(Cy9C?@-5+gSb~1m``1kWpbUMmbORWuGD;PV?d`6WOt9J8&CNpx5uHYVWi(u$gaYcMyGh(Sts>4c3)V&~WMChELqIi(t|ockN$vOb9+ zb)vv3fhHy$jB}>+#IM~%tlil3tozdB>M9EP`78Kk0^tQ&qSSeOqE3I)7khH*rL91P-Wk{FWbY%i*lOf&vqm~# z*!k7!Hr9kyB!d7)fIZMxf2gLT%HWIHx7}-9Ee_6-UrJ&(ZWvSjEO5Ys@O3(vMV!BMb7@RoBQ^7PZ#;DSf6k%pM0D-ERWz zv+^LA7`FHqd61Ege~;q4z-rls4b&i*ADim#?axCCkvyCPp(%@}t?=Jrto4N>^x+c= zoS9pE8ayc>zSHKMSt`QQ$>t*)DfiBZ>&bS^*pX4FRAOfxx_($D6M+uMEaa#uc8o&w zdH6i&al-}j#LhlaVJIf|AAa$_fdP=dO46t(`&1jLMr^a$rjcuXrFMA5xjwuSG{Ph& z^oK}$VzFRevv^^nkBu5_8dh5UZdmi4L+#b*{6GD3P<3@TNIZ40iBuZ~D!T4j+DCff zXH8!nfV66nKdqmmE~^=!J`^~-lg$9;re)&%_5r5Ju)IaMX(A!c^g&rn+x74(3Kae4 zj*b&Pd}=KOIjBh6oxlC6fi7xlr-Bv;KW5D6$o;t)N(!oIt63%b`||Kbab_dP#}V;n zM8EKTKI-O&PVqpDyqKn;!$oi$@6xE^;Bc>NE%k2Ze0(~rB?M!-)78JH#)L8_*p|sv za-(u;nk=!PdfDP$8}hE}fxl!JGjP9RmAK#G94h>vE*dZ3rKHEytSBvnDU-(LdpdT; zjjKz0jZ|RAmmFA-Hgy+ASC-W>vGSxh;QKXy`AdWdfQU7?kyYj5M0#n<(RR=1oRx!C zc{1{fUN&U7XM8;UuD8Yb6O8<2Dep-%aU*I|%tp0K-1zUkY-p?PYgoaWTH=Fyan&W0 zF0491Tb36AWIZFB?)!XYWG5BbLWHC!Geq8z~-d&P&`9r;44>qzGm62FcKDi-CL7q)wC{!RtTaV zH-_bQL4Mx}di5#+%IDQ-iBK3=e=VUEXgW0#Ny4>N*xg#&C~6))GfG+RK%?`^O|nw` zJWVuv2LCOh7QT`)7{*lis{Xk}e0^XmD1s^yTE>5fxaoDaqk{VB*IEuQsvHaAWcppK z6jky=8?gy*3p2rSm(K>^`6GRcMeQqMWcoOR=6e}73Nu8UGX!AIxBC$ov(F^jIONU1 zYl(;VhPP|5FjVVD>a6G2nIn5+e%YDm4TgWC$q^G`jM5sMP(_AnU?7xNw4Srbw69$n zJ%3q_VR=r1(YO?)!O*>>*OFc z&2%1g3+7(5S%G|M1s7#T9e4@AuK6{1)ns^cZyOk3-O5(k2Wih|Iur*#XV9>Tou=Ex z|4K%O8WOMLe>{7`fvPD85MWC=`ipSc{ihAGP+{^U9Q1CCN@H^oGW&<6Df+J_bSnp& zr&0yi6OO>0;t~3{t{WTrN)!$DQeh-k-EV+Q!M3`Xy+Yp1(!A*Sy~-uBsm@uAG@L^f z`JQEz?6QY0?HMSTa)I1|8X6Bqe)lx?j9=XSN$T&HFFF}~Y#GF1rZjFMx*T~J-jdQD zD$%?%%I5v!>!b!yqtIpHV+sNInyEaLwfxb`?d!X3S`GtbsNt>t_PZ;x@Y5YjgER1+ zWks{eBZPSSi*|I~^2B7G3u!vCd}^Js3Qtc=@ySXMVfw7`ICa!8?aSi~g+6EALTAL7X_*OI<3e8}!6QS6zbw|s4?3Nl&Q^LHI<#hw6 z52mh>@w-tH^3w5~6Fm4F38<|>mC_YtPEG=A>-$4zWLANl1(cV%4*9#unbf__f-kL) z-F`xImpJ73dTXl{4E8-vS-Jcl4mRxw_oywkB|0Ecj#&~#eNDmG87T2Y7BEJMKh|;) z7+wRvO{62N_QE~p%Fae;oZUWEn8E34!iBJtI`=%Vi@fZdrk@(i6B%GO?)>q{b$>N`IT#z3$& ziJu1e)D7#t9PTiK$@(#0g{cQa4i7Yhsei?s>lf!bhdSa*p+Y1r4IkTvUC&!^$?Om_6a;@#W#@=7gsu$UkdNMs2UA6Va5uJ;{q5g)?9en6 zdkB24>SX@9zjS9#$qt+=oi9h6mhS;1BNLpMX-#cgx6S`T0S)tqhMNX{F^!JtQ-SaA z553<=Ft(m{f{y!6bDycF-1S%fQ`r9hLvVt2EKonypfb`woI?wnZq@KGcof*aVf^S+ zr|8~Cbi`Q4K-nY>+s2`aYFLS(YFm zNoyxE0ivEak=pepH>B3Zy?i4)bTxl(T6Te^EKI*x)?_1pNYT^_l6Z$SDYsHyO}T%; zcO&6%4b8~QFv2mC(?!m_HBw6sE}&#vL|a-r4-ldbX@6_)tf?B{d$_GlcSt1g3m}01 zHr^&R&~;t+*e7FG(q?+wq-M^%&1;i4I4AI-E*S<3-pbF~O^Uvchi=wWr*mSBg zCuy$tL>xo_J5p23O%&f>v&5q&yAx<-H&Vs4{f* z;w&qj6;K82?R(8J6?IVz1IKt8smZToam9w6lz6il=lCR=&P>QfcIefpc{&BxL@5u8XiMIb@y_2CwD;;Hvv+x0KUI zJ52r)yOvtD9K8oOoM=u6iay+SNQe`?gDm~C6q7>0IiD#9AYVO3nszNcg53*V=w{{f zts{+FPl=cO#O=szGis-|N=L`&rHfX0(&|-&APwUMLK6G%$#liR07~Gw46GEGgtutO zja7oN;4Nc%H+M&j2Ep(AwgGB^Y4<)@I>v$$K+q)hfLfd3_krlm&}ka9!lvThs-C$2^vNL;%QC6`;q@~XSt1r<6JHaQNe_Y) zD%0rVE!YyJ9-r|Xf&r?N%C_BnwYWF&zX6m$`tExk9fD{GWd5mi|26GDc`z@-wlC77 zw%cC|5s|9mUVpkHFZ~(xh+ub@{vm=;_munwksx3j^dtp}X-wB~FD(Pw(*50i)n`^N z#gStEsc=Aa77AO}X*(kuC5GyPCasl{+O7eW@1yDAIcRQ5G`Za0|POVoccm;u^F=3M~5lScaI(qq@!z=^&pq$WDkC~3{ z%$uu3LRGJ;p(1UK>-niPx1)cEG6j;Q-#KR#SCFLDSuswjEd(DwV@^!K-hy85<-#p% zZX#X98o1o@$pRA;kVgrkdwwoJBWgYKI67Eb^AERko#g+DOo@+~j!3)dLL=>-h`s+OvIRrmX6URAuxn1a5uzt9mHzSuXnf6)38Ll#?1H(g#sspzL9RA* zHecM?fp@W@!si%|{FMI-djZ?Qr+$?cLQNRGL)4Lt=TY@_!AE8VhqJ*z&Y3<~tobFh zLWJ1#y!GdAtMvuY(=qxwvC-9do}Ug^+pEhw!{^0lvY*Hb#{w>FVc_44srt2@+@K zUBG?t1X)gtHxcR*l18oiZI!i+HIvyNeAB?Bv|vdkOd0Tp6ec)h`NPbR@myI6;x{!5Qp+%E#IBvRlAUai z)p8k3>BoM)|5*|t__bD#ApS5|6Xsn>d1_BNVUhj;Prm|2B685ODYE%@`32i;f;eJX z*#hpce#O?_AXfN-8~lKoi3v7va*23=aDBtCpb18`-knMvINrOXXJG0HV4ZI@ic9!= zcy%8q*#_n=U;LaN__R3Y^3p~idJ~?T<@J1K`A@jje_vj?IYrev1-CyEW+w7`b8JZl z-nFzxs2*i)q6PvcP9csfz~xJi>& zsd+~kR2i~Y2U!%7I&(?+c5Nod)KFdmlfLKca@^Ls$%WVaxqCt(;5;{V6|q0cz~_k7 z!N?4}=K%xzdh0d0mhae0A%kFWGBb##>#TO@HPV<23+>eYB*vRRJ?$>jth;8GA#O+e zrPY2$KEalCEpbRVpR}515q@rYuc|Vn;Pn(437HX@v@U(;y)a?J9u; zC;SN%2~?5#{_GzQ{8lKntv8(o)n{ZH?|+odJ_qu#Onudp;1-&F9Idai0Rd7FA{BqsrfUS$fk2rnjr+V#iR{O#<4 z=)Ax#2I`6Nfh*9V zcwwZY?%-MR>)Hhe*0s+^-{0-BQc$KDF(burEL~|688cuQ`qQ)q+p7~8@_C)WLarpi zzxWh0l+?8!#p)kFeKDo~y;S#Y(ZuFjK{Qc%&5z@gn6L-MUEA{F;nMCRxJ=(*J-`r~ z);d=E`PQcSf>-n0$D1!L6Ho)r)sfhV!W(IgBRQbN$C`f$@O3#m$ve*knFj`QtY^RLfd|5^sjxItf;W za5ZFAogsC&0!wG|`>7}?%W+a6*QN9}m!C!sv!dh7F6$~Y^D2d`!+r3(q1|&N3ZXIV zzIVE&%x*`7y^&uKOj z$0ZgU?o$ip+q|JY*i=6_Pl6iQNI>_A7*aQ|-p|RM-sCD1Lbq&Yj68r|fKNagJsF`? z)pPRILaoQ^srJ-!HY|-2B$3-U%bsh+DXeW7MO(^9S3}P47yMJQD@i$TR60(=RhW0b zC(TdkkLzWKzW^V%V3x;S${6unUA6Vpk??`Kpu6#;S(K^pU9eX@G$4(uW$ufIO7+d| z?R_u-o|+h@?f2a5cn9q{P=A74sr)ZA^#Due=xNqZV=a@vTajRV`2iZel_!q;NL4kV zugN0!yjZYWKUtu2D{jIQhaxAsS17csASSPx$HO#QJ|e0>J6!V%4Yp)BW^TL{!>bFK zP7(h8nch-9Jxc^^Oj|cDn#beF6TSh>#TJf36nMbv!wNP{C~#)Zyr>{F^;a}*O4|Z1 z^SjCcsiR^dIPS}(QU_F&*lq%w*I}MBO{IVs@=5il827%~95(78kxL56OEnx?3T9A8 zMa0r6Rxf_2l$0jiZtYw(hFJ#T9O?Eqj;Za2hAz^(lu9N=*ie3nZTm?^ry0YhhS@v@ zeaDvjug3uGnQG!+m~MEe=vABXG6U3%A9knKdy83z^$)Wjj$rCAaKrYPsK?zxqYKcl zHE>F!LcY_It+Pp*=^6ySx$`hW!Z_D|Dlva!>)tt7Xxe(LgMayg^0$ zmWw35q_;62svW=v5UNY{{a8Ac7%pbQ?x!ikTCN6b@n~2{EO#Nk2abki{Pr;tdnL0$x|p6(M+BhC>FmCNMtoQHmnQjlrk(n|}EYLBbe zbg2>f<#!qErlghCHE`gY9GO5A1~G1=*U6#LyThMAM@z?~nFaF?ex)^PTRe&>aI{3#qlS3Szha3UtKzHH^NJE&dysEm#6ZN|U zeo*QK?0jp_j8VEk!khpHSXGm=cTq=b!J=&*%Jdq-UA4&t|79sx`a2P7j#sa;n1I3j z%95BC*c0w+=#qY4CAsK@l$x~upoYCP)t1`6eG=>U&%*E(Op8gwXSH*Y{6D8eAH&K9 zL~vyoapZppsXJrYVc9$LfNHge^qpuIFR&6`L%b4nM+jYmMox#-qRo!ecrHf{pE1a^ zKcZy=M`IC-PR9P9FyeBf$M3GmyZf;sNOF->_+JE1k94_a)#(!Cnr9VVUkCO{o38`>)lpB}ol*;8hg zd`UwZMi1>Lqu7}&EYr^m;G&u10 zy;$-7cBy(rW(R+ln*(C3#+OA>$9Hf#*qoM*3KQptd$GK9RZ|tBGybPw zlGChB6L{&JJ~tWYFD*&xiC1vp4TuH19zwf5LS}k8l?BVm(xlQvTCf!i*4|h|KIZHl z1l~=)<2A79(3%98N}1`#cyM;Dmj&bHx~SF5_T|BZPPVGT=yuoIZj@FD6%ud-P4Cli zkV-KR0=}HMc}0O6DXv06;QJ;cU1>F>i@4J+doc7t8w~8Hvi#p}(rSVw=7+MKP7}*{ zg4qG(^I74wJE2tH?Tu^}sBk+ZNBvIa%K4AY(KUu>(hJZLoqoJa^LAcdP%nX3h~SX1 zST4gH3V@N?DVDwthZ2J+MyGym7VFnx;Jp9RHm92SHQs0x)|bej&X0r<}7lj)> zH!5$On68ul`Bzo+i{Y6N=WhiEu5&xWVs3%btFMOXAoVPQXcJMDHL!I z8544(gEDFVD!*B&eHgN;6x;cIAM{t(Snz#=7Jyj_pF}1vMjcUJ)?YD0by*N8`UyU2 zi{2eeF~xKjFP!em15gK2klsNWPkANU;YcetJwWQmks_<_Gtc(aV!#PQYU=l!Ul+D7 z?P_*Q8b zy@p;iW65iWk?~K{Fi@$Q@Gah9gBCpN$7CnVGdE?4p`kpa+MQ7`sXF7XA3}i=G=cKN zg`-}`$7tzp0E7YjIfdYPGgd>a!*s|LIexe+51E4oEsb2TrLAE5PK2$vmiuDl!hfFF zvgMVVGr>J?ObV_Lwz%Z({P{!5gwm+3$btz?M^&lVjJmdxe(!GAA>vjubR|w^o@hbU zEuMD55so&GwVDSfMHR~YZi8N=re;EGyd|`aQ`G&Y0pv{4$1u7w2j#7AWC8=kGsZCW zfv?)*sU^%}Uavpq{r7OgaR-sHq3Q~f{0HR%&hjLd7IGwE$NUDbed6bi!%i#cAC9iE zrpS@(jadE8jew)Q`wG2jTj_3>n`5nfJ%d714C4%g>7!x3n`Twa)ipKOe^)eweD6>b ztGnYzrj&g=q#uq3ThmdylquQwGwGqlhvc$<3Z|_yy zvD!10US8)nX_P1W&3GlapGA?HP0^~rN^6j44mQdLrXu8;n48z3pU#Cch3=f zPJ+%?h{(TcJR}KAP1-1pzTk_~SeAv&!o=jq^`kxs_mX(&n|b+dU|8?int=(PA4_8A zl#`J*ODWt~efmK0L!^UQ)N;&ws+zZsS(a%dMHRims)Svo1bQs06K9^=<5ap8m4FGcI?0=Q}_OnJ4BgE8Q0 z%&S^cqC%9DZ08Hg!TAVcxp`3X{XjDMG!-c4F0kUNS)5G!F-y`TpgcW=N&f^d#y7{6 z5A&Tc$w6T&6=q{Y=Q~48MUBDZ!5ot`FqVS-+~FQQKl-OUTRYO`Hzm(DzJ>w92HUDR zPD=P)gutv4W?kFsPZI|dYialXm9W9uT9l?gyr^#TAbTj|uIF)Q-dIa~lLJdcF}!e4 z^y|fJOf=d9qwiJ*lcr9ky12U963+L1;-c8xftZ1!)@6dLYy+S3{SJnJ-jx+7n?r;w zGW6wh>$5vS!%bEnSC`0}Sd^^nb513=aKdmRLpsI5GA&o3Y*(QiS5M$zN`;M&pXXqT z4T?y>m-xMgQq?-MuQns4x++V$X~LRx06~yV87_+0X;?H!8rpu%*R{vN01HpGjRMBjvfD%a{wxKt1?iFF#>~UjI4^UhSi`EC=BxQVPXrFywyzz;-JEz_o2=Ejv4rJ z@C}V}YuT7b1EEjRJ@Ht^Vm$FQp-S)@J|sqG2o4#th(A9uQEvc3cBCwL5Yn3$G@fm+ zZjD=O=X`$8Zy4Qq&hC&O!axyNBe&W-^I%VA;nFwg5SBZ!rg zV~T5X(t6yzPZJSmijUN*)!jE*b_qoa|J!a};gG<2#tOJZ*K!Gg;^*fqY1x@YC3^IG zb?+=Ca)(bkW*!H>IQpmiDm)9-yd@S^s|j1Wg-KY;qMEda>su8PSOq3l%}nEO_U|b% z08^w{@VA|HsET+gB)jRjs4(_7QVi0l1=T3u=VEMhRNim7?8DJ9jnGrKM9q2Uy04he z4b@eDD1jSfQ*yn_AED)PeHi8ba`)}^-7(WIyx!#=9Xsa!KCYPZUY@kKO#g%%B*qXH@kF67tXcoyeaFsiADHU znjtM>9(WSrOYNhB`}Z6E$G4Ex23d+XjNE{Si^7+de{7`x*G(cnN0}QbtHA!T{6l>u zf3TaZgaqW1hHm;>?`@Y*4WQg)Na(=!}HOsxTjXe%yRjAl>Q; znTNaS3tnLC^y>~;72EeJPw`lf*An$~1X})iAsn$*EktusJ?+p~KtD8RaLsqpwg3(_#q;q=#f$0?e<3M6mo)t5yiVpOsPlEhqxC`K9ZkJns;3%?a8 z{3p%s|Lk295=}WdUyl$vX&7)C(E+kE>rxYN!$N~hT^4bE7T6oEwdEa9vs8Y!NJGvMIDh)P;??JcZ}Gbc=k(5 zm()ncDxY}l=S_eLenpcwAOu*2>JTM=7Mnc7rA1~A^#OL@jX#;>VGqBJMG`)318Jc! zcIIZGQ}iOEUUD9O!SQ;I%&Xm5o48H9gsPgz(_I2)@#M4ujHeHG+HR^(pqLU|%*3op z07Aal?1;C>zJ6GVq{LtE1}5B7WV<%8nDUg#is0|iWRf7tn1X^&V6dSGmxw9Z+fN3c z_NF_a{3CpyHU5^gpf6YwW+D<~_^@Z&N7@ErsJ^UEg<`69nz%w|_{Zm^uQyp^dVK1I zhpWr0HMe%JPOT4VGZ$tnJJm1+#`zi6RtS!_-1*$ZlWjh&6I`7PMEX38D)<}^5nT0V z+oh!)E>obV({)Uq)hL}HmsbQEU`1v1)&uDKnPTq`wR&>l!ecumn`)|>k2s)eACC5k z_7)%Ej`sbx?IKkBZX57if*>$2*(NU?t^S9kAr1lOf)r3b@Fg%_bL6t>m8Zy9A+xA? zrdkFn@%K_v?csQuGwt_L3W?bc-i$KH!hcRy*Td$wDTh{_Sz_TGb;P3eH0xr7T3aEz zxn0i>1G)Z}YbMVf=WYMQe*NFy!Hc&1ea=lU@e+T92HJNPd8ZsNQZ}Ct4JFUD6xRX6 zNt&}0TNPea_Nw34io@MMfDNaNgQ*dU2P+s;FTeAnlum4=xSBlF{M#(U3I?cn-v4(Q zK%KK$fRl&=bNQ4qF{^3TlNMCmQSj5eY|;0CjR{(_&5ZufPg;h&b-;%OQmdiQpeN+8 zs1W4PE`=&Gnw9o~(b_XP`$9M-TZCz#6{rUu*=8LyrAZia;w=8aUlh+=#yNcON4<=& zl0mV%NM9{HPo34eLd=LDR!cs-lGzq){fC-)UsOjDE#1RG8uI_)nDnlpF zb>)_CCfwqu$k{t}qO$M0Vx);W^jr0Nm({qJ5i=jCqog` zn;KPdsxZkh>%x`ohBn+e?5y6Px^vY8m;X>be<46vfh|E&!~x+Yks+(_oxx&UkYD)+ zo!vaV*q97ZJQqS30&g$h;NOBoZ+Ne{f(~`AtF|79MQ&zE_(+|Do6;39V0+vA_+W!MMm z4(ht`Lve$X3LN{3VUfm2QX)?s)znwTB!ZDu9i*#Zu_S&VQx55UZf$0lZi zI1ZcXf!*0`z)#jarkI8@4Z6hgYLK`^F2yku5r$EM9d-n1fZ1#1-I*B?wML>U zSlx!*b&@Zn)TJ5cBT>yyp`kR0k}lY|qslMh8mZs}1DT%*68qIdQ=zdC99h-v@A<+z zCi?ILXtkOo8YKuZjp{~2+8B_LluK=N(=a$VckWh*$ODh9);l~Ya{W)Sb6>|LJ8#>j zcDZVLLUbs);{@;7-Ij^MBD9bE`rC~q?WL=h_>5Tj9y?_B2=gebHth%!1ipZZ$rSCJ zoTb$~=_wrndHl$2UEEri>@XeIHDY!lA)Ghl7$!m^18F9`*RY10tHEXFn@SIlCT{}d z!hRSOIXS!U{YPF9a{_P}dS~+;y;tkyO~M09 zJ=VOzn|%`YjyvR z4Eva<`p=lw0|w+|@!^y9oI)W$ACq!F?==4&T-}OYKdk58$pZ;$9#Hclo*}b+u(WIi zNL9RjHSz2;Zc~tMkEsYB0uXM3Q}OV#H7!T4lOkV~;nYlycBZahuxPjjx+0Ki$I`yXw$5Z`msqim)pcqEM%$CFPQ3 zb(~HVjv|GpHIZEMmcz<&%>f%_xA(LZ(iM6aFxhbx3>8hcs{W6Z!3Yu<>poIfIC)V zP0mhXX=46mF6F8$2Ci3+s1M&>?rUivuIRNt1nXrv5rS##do6wD-Kzb8R)qjkf zN3{6b0e)IEVX?4x=}~9?UDHk7&f|?sbhK@rEYDjPWlI4_LPQycw!D@r3l(C0t9gTJ z4$jkkSAJL|3CkTjH&(ehH8hr6)>g#FVvlkFptKO7Dmgnyv^;5NF?X8}^0 zo`xXW9u-T%Crc(WnHHt?50B8Ob4k|k7bIz)mRO~d*m3E#k zRVow@gN!12Mocb&`vhFxeAEh95G7je<*=@n82zKwpR@{c8vIBXyqc~j=z~|*x6GhZ zr^i##XQiwJoj)`F6jxP(_q}D5RvaqiXtz-=D1iFR$xegu(U)oVWD7&iX)S3GxD5Xc zRg-UBR_&{cb8UAg75V4CHwY&E7q8ki=M*D?NjD)%Jm%U@f+9!1HO)lhnK_4 zZP}i`R-KP+yjR1g7}wimn#jK}_02n=kHV!@ggyoj)znrC|71c2k~4 zs{S%6f}OkNMm-rM-{!&kx=~7im|M{!2bP7cgfB?kpoT zKHkCVUaHsWAJ?;e_qwLFCG30%G)%ZloYjZ;w5Lf+k9@sOeHxE^J9XfEeB7Sja@#yF zi+k?+1h-z;J~I5XUE=?oid@)QMoas`@Z>N7xpGpC^m4IM%`#%V zIic>vg(D=@B3vsRvz+%3PDGBTX-dM%+m6oM1)M}6vQUI6{PmR0q)f=RFsAQDAmxUO zN(UaYKet-NfM3_q|Pb%1>~)c@_7Bj)LY%?TNh~^9TOebBi%mJ z_kC+^-62z&@4;{l4__JWZcx7eGU!{Rd9Ni+Rui6%?nDgBCOU8bptRav2* z(lY|9cb-Mi%-6^op)IFH`o3dMkc=uZ_idYZivMcBg|qu__|)D6@7AD=aZnV2No%~I zH=Eo2B(3v?$jCdRPGI9t>eXNZ!JCsxKZL`nf`9x?{9y`oi|Fd9%4B*Q40~Qts=Z#5 zX`o!R!KU^d-a0o95tG2ke>rgD=mdGr;_?;81h45ijN5PQr;+>a6`L4ae!)AB)Qg;y zmz1X%W+yU`)_sK;^dt&V*^Ac^4efbwfmj8cp4V6e-2v|32fZp(EU4?Vk;7_vfMHCZ zX)&5*?7pei$JPjRbm7RZrebW7;e@rqOYpY7bjij};=1o+6J&l)_B~srw8G{Sgf;np zrATkx>R6Ryx3XIMoW8*wh+>Wus?yNi-;Aj*v#oHGS>ZTs>;Gp~+dJGYyny^KCfMICL%uLYd$ zrOy56r8%_cOC`#muIlo(+xH0}8NZ`Zxp}o9tB>(l>}^vQ^~qVHxx43|!!p%i&uPZI z!HG-S*=)ZZeRHeO08<2}w_E*~1g5Oiex z~8fq0uoFLDip!^77T9BoO9goq19hr+MHnzx6@wu)v z4Z0MWoJ8jnJagqEb>+*f%e5KzAKo|WCt=?jcBtu&;}y9U6#2nVj-&1)h@H z*fe;bR3&-#wUgIX)0eU6R%>US{HmrI^nV#tWk!1Psp*MmCHlGLF!T(uB!tOx^Ig<& z6{cGOlqE`tk;Q<$zdv@7Vd6Mebl@L0Klk#8msQ1SFY<&yA)Fb)jqgql;AofY78jg+ zGH!Jzu@U{lZ)jw)S6E8%-krK?b`36t`s+m+{OcJ!>Wx3S8^W(Kp)Xl*3It@@<;HHM$G_2i2=Jz)UAm

fqR)5kc@vdr-unNGNA>1 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

%^>dDYHn0 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 literal 51493 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 diff --git a/scratch-link-win-msix/Images/Square44x44Logo.scale-200.png b/scratch-link-win-msix/Images/Square44x44Logo.scale-200.png index 98a688f46b377c2ec73fd60df68308f02764c6eb..85715c35e2eb260dedc13d7fbde16a2807696a53 100644 GIT binary patch literal 6034 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 M07*qoM6N<$g8c8;{{R30 literal 6452 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 XOh=TrrMc+h00000NkvXXu0mjfh+d0M diff --git a/scratch-link-win-msix/Images/Wide310x150Logo.scale-200.png b/scratch-link-win-msix/Images/Wide310x150Logo.scale-200.png index 54f760d126bed6e129f0e9aab3ce3b0a9e72451a..d35fa8c1629cb6b3ba5a145488d7b824dfa42744 100644 GIT binary patch literal 49583 zcmdqI_cxr6^FF+4lvOrX7rocjB|5A3&JrxKVfBba?`0802}1Nl7eut^y@ViGy(c7k ziQc}O_bZ?C{14AL&Yr^$d(UlVuDRx#nHYUtH4-8^A^-qDqM;5o1OTvI001n00({J0 zf;jdk0f5dI8c;=JpShhI%jyqK&vK$$-(K8oSL=E2ZF%X9K0kXGibc!L5}N09|8-2L z!+08wvA&%Y_)}NHL3}sdvh4ux!D-~r>L-!#S)#`SX)4mtm?G_HHhwK;hs-?E2v-8I z6fT5jSo@_OQ~7qwnYHuHUHb31;r**SI$LJjG641yxo}l8v)$Iyx$@JGLDHhjXL!l% z8vlR(`Qfj0ai3k|Xy=xurZ|`%NoIfXol_(Ey{%UAkKea5=SyL+D8(*YJ5~g%9l63G zV-ak`IKK>06mqkP5-k9GY9#;2ZNdD9?k<9jul;I_qbMuU^Cx~@&rK!fv&v64Oli># z?}3uc0VF-etj~=IYVcvM8U%u)7^x?svSo~R~?%8MEv#rK<$-S3kq*sgUht>0X z>-os+p!qOi%va-CV!j@5L#U{y-QEaxNziRj<1({(_^9dVUi8RDbTs_ffi_C7{LmF5 z!43?8L%4y=*xdmw2yC428ME9XA|o6Ea=Yp^_|#$O)}MsAbFD{=ZT0iAw~=4f$bx?! zt=^Emq)t53Ba+fwO=H&}s%O`DR-g)%der*mVVmEvms;_3u$}kwYZJPts_H|HN(ybt zVQiez8XgqjnL!a?7_4uPkJAHCC&4$tv$ci10Kbt$4@dcSs>i(Z75g|2l(knni9%+vJX zo1@kK;MMU(vfI8w|Cf6sMh#%Me_mw*m=k?-lexRDo3FZU8W}tZrs8+k^(MmlplOw% z0HhfPql>KMIFwCJSq8fhP#Tbu6T9(FB|U4wjGm^^tEx);makxOo|A6 zHtbTp-y!Dd&rli&>JZfsp7&KII+dp46RcgaPIvpVZO2QwcR!?;ubVuBOE09e*aw$| z)Z1`1j>sgQO1kB?{z0eTHSN}I-n~Iy^KfLM@bXx-m5!f({Yk0yyI|xbO{-SI6Nlo} zHFdNMy;TkESFvvtH~1zb9^>#sA9Mn72}I+>OzkZ9@WOTe_aCx6pX*YfyYe4T6DJtwdM)Gp-^0~-LTc;*!syQLt0NQ8ce3 zt6e^g8V9>ihkGbb3S{SN0|9#gy#8*A47}k5 zE=R^yke1;Qy~LmXm(fmBTTSjzayYqghHnBHmg0NzYg!Y$_PV8%SO2 z>y`|l{rlX*@?uGw%Vj2GcO%+V_4l;68}q`$KlOI|5&A}nb0|gH{?8S@O5;`E?RH}z z6d^Z4$CeTW614W@g8?{dKtx!n08vQ*vY0AGrgG`s*g_!-ch;D5Saq2&bq?xl`FtT? zaL4n@;Jt55GT*Ag{=Kum4+-p`YdiO@W_`QiF43r0XWfn!hn`?6U|F4=oBeU+#cQ4Q zeZfyT`_mOV zn_obk8@vLiru;lIHL25yqaWMEcZKd2Z+h1s2Z>{fAI8)7ua`t=$aDOE##dRj-h8*A ziMRd%$74GLQF>N|Af2_Ttvu<`;^ZUpO!*CyDwHaKk0C0y(AS1C&hdCu!KD!9UM^>= zJeD8kxD2aJMkb#}AZqIF@hZ z=-c5_hoVB_^1>jY5OnOK)Y>yT&$jvXXTcqA6^#oIJZk3Q4Y?kkz6Un+YT8o}r1w4# zp(YP^q%7lmy`3&@P2BiRyi+$r92m_zy;ZyK=$t}YMM~ycSkx-n1J?#7*)PGHo1cpi zTFLC;UMcJsvR#L>Q@dKZH=)6_-5a?%C{AS_r4P~Q`-H}n2+CoG6GME2qDeQLp_7%I zr!_F77srJx8i#Zpiw*cB;ti0yUrnmjlVo)HOAOyrvufE#UE_m1C}Ps}h`6tyvwiul z@Mtp6yIY)vn_m=@{$%<>LXcQ&40)<(aIP@LSu-XvdXWF5#H6!_oD)n15!NOVxzc5` z?#V9fN@D8Q|Akv~d9d2Qe{H`XxW0eg?q6w|%s#m9sreVJ&V(?zbjg={%Owm9)}>8R zjHMl!tvh}r2Z&Nt_?T3sR1EVB^2B268$aY3(uZtC9A72YOyhja%~@-rw&^;qYL6Oi zJ>j(W`)Oj;-8Zms9-GQl2a4gHfMz)25HlLPJ#ej`?NsoXRMD|gU(#9sj zZ}aICV`}8JrP^oK10+`iB=gJe?TCQz?J88Nd0rKobY_xJlQFGi+1%j=olpl8zFZ2T zZ$HX*w|~Uo5#YVO%8W~Z6JrB{BM zS@$Gf4?gutm+jYPwjeA*p%XceT@~52*K^L3H$p~Jxr_=S4)YI}Wx|)Rytct>~;pXE?T5#+^Lnl;-_(hoosl)>?JYY-mNDH%Csd~MYkohW7TopL)dtRaBC zs)>z(VWZ>+Fc_q_=%m-{>v znU4ffa1_8QaT`*pZ;~n!qSa~6myn=$&_yh?wv?@Ru;kBVN295Y=9g33!~5ek6TSJ3 zC1_5oHU!Qsl$UUq*ncMPE8iZK%&yqyhiRgubiYn|Q13;us-sMFc{ zJiDZL%DT8bz#x_#0Rr20o?4iHF}J#>@ZRCU(fu>iM2|0z*IiosW;Y1>%dsi2OJ8P) zTs_X-VwB7c1_dAK1yUw5+N@=}2U19WOTenEeiS;(SB`>>P>vX>WVtUAj2WD4jZe|b zi&seA{cc=#3VOit4@;#lZEVZM7lTgX@9HZO+sjlDs=!#*7soTCC1#pD{9mL3-Q%~Vz^9vAj9fsLpgJ5ne!{!9{($9gDQtRo z(`|ZxPnEx(BANoMhb#4&9NFoCwCU0|o2!vDIih)x`s=cHCjB(}gCuun*zelK2c!!XYU%$%cb@-XDW-VXi z($9RJ@F@&N%q(ZPBw z5GL3B&2sT^M4PpX6Jw?5bHlD)1p98DWT1FFZH~ zyLTKJ$!C_}@hl)#1gLNbnaA+Ey~6%R2Cmm&OI^9B(#;Y4Cxc9Tz zbh#5A;5^$qtEMo*SNj2fgqJW>)Z8NU!}%4tqIrjDO}k8V$3fGyO}EzQa?iLQV2aR~ zPoGSmW{7-3j2BbqhH*I(DaIlA5N^|as?1~sO^AKF3I!GgTts1rh%)x2{1+UP-eQ{| ztOlC^EVBLO-c7kXyq252`I3;}1YAj$*X^opjMoT9eV$qYdQFZC!a#X^z}g^XbjImUyduT^;!4Kob6 zc`o(mzxHqfuEG;-MHEb(jgQalSzhxLE#f5*tw*;VShQTseU-8%EMbJahLbDMU|s=- z!coC%e4={86^r|>6jLp;_f919dv04 zt)Kq^Kb>}8X~H068IfSG`wD>C<45G#2o$-RT-W&92zv-|tlaIFa>tVOpZs(%yqKR= zm;$epy)kh9rVd58;I6$`wcFrRWh(*k5~N@cIm?`_X}#X1>Yx6&ZfDqXb=WVJ(JbMd z0hZ|>3Gs_@Ej>Tll#4X8X(2`9sB;0e$)BA$!K0i`5ID34ofu5(mOkqc=@{m6blLfN zOf_ELW02m<3~HA&BAG6(^5YX#r9pzMGFMv@Lr|TTN1R&6^AbGnQre=#hrL!l+wTYSx%&N_v!i05Tf;l#cogS&y$TTh1#Hg zw2Fatg#ylL%IfLvrswk)l-;KU+bI+Qn}vEFch~o2fEjDIu8%s?y-c~8H9q^b4yPV60xe|7s2D-JOrlVI4*h}z5 zd>!g$bFhCuRR2#=8I7eWbWPN=fhU>OA@7<@dwPEG+$AMYHJkzkaY`y6bgP$MqwpCw z%v;1_DqG^-C3^+h^b|LP7nxl>pS}Kb(|xsfel+wswqhsbwS@N%yV$P)Am8y5Pp5wR>G^Z=okmxfb$CXZ)IFP`=R?fVG2)Xw(o{r&J?+t$kV z%?|Q#ngBlxe=wGagXE-tWEAhpsn+U}jG8*7GOWSKY<~rrr-Z`xbq{Z?#AQVkI(zmS zKQ|gV2fNQJ;Fkcb^hsXBI}YE7j+L$a`U5;;l<5kx>9q2@<1Wh&QCN?lFXr;O`HT+b<;AZcp!ZY~ga#Yxe;NjYA*t3>5T>?c^_%zqg~Llg9@k zO(siKY1{&odN73dcAfY&5W=$pkK7#uox)m!_(Y~TCqClGQ$6E<1!m^fcnEv&pf%I= zo<=hBV@#Qr(TbXiiXIs^<2 z^`7I&f++UOnjU_}bx?y_UP(%9Q;vlg=bvk-(X^Dt33~`LpB1C3%p8+KIms*9@`yE;!Q))$QBTrL{PE3^-)F=F==vhK!Elvdwa z{MSoZ&_dz>JsUO@wR9`=gEtFH{7*`lw`il)! z0O=WSr~7moYup-Lym=n8j7$I7WE+0-u51?Tc76dxB+;2Kq`1Qn9#- zpXM1dms2vzKZ+I!o#C<`4k6d?m;JaT)xAq^#xk}vILI1ek}l&AFHJUjc;X&>PlBP) zu(Jf81ACyupvQV-dD$WPEF&ynWNtdQ1Ul@vD`((VBcc+I2iR;FR zL)KrneN)|;4r6V=QItDm& zN-hPFNmGpZt-I-``D$ndSr*qQaTMiLp(8kkJD`u%g@rTbE|cvAwwj)ydrEj>35G+Q z%1T(EA0m&Ud_zg9%f?Ds#n_32iTvZRLoFYpPedvbCU`Rc!7`ztDSOsQ7UfW#=_EO% z?h|?n znyHvpHCPG9y(#E_3dNCGcr_NZfc{|HcY03a&>9KE=zG7Cn9CqIu>=GP@UGcI;S8&m zk+Ubl!j@GBOVLcLDQbx<+v2>ehVOHa&JrSj9X#(;Kkyg-Oet8Qw=@hayKPb+0akrk zQ!$Q7Z)lkENbOO}_umFpf_C!(Vn;KX?9hdYI-l1E@5(x3Q7*^M{2Iw%3@*t~4EY5@ z`Gx9d;;6X!hI33*7a|R-$O$@&Olp=~uy{&rwNv~AVU`qO9SEsKH_wwlU|=|ExgeAP zM#&$xD7LzLCJ&7Su#TC3Nbc!R(B#hYQnPd1kk&L2f^P<;BLXQknZaoAH_*YJ|0|EPwAYGK9LR&4Y;?Tk}HB7aBJ?$Vj*B?8KS73q>TlmgFJ zzR525p3{6@vYmV(Nad{k$s^#@a5N)=2Q~k|@=1k?YSy-5?tMDgq5rF?f#r{jJvDV_ zgoJ97#V=6T; z)XXT+E1!cBF;Bue4Xfu|;D-8&8Mc7l)VQv9`g{`GVJFO(mU@`^K8R+Ab-$HtzvBtX zI=rU9Dq^9ptbQ@;;sNc6fn~E@KIviVJ=Q8a!dbYS$U-b+RXgWAz#ALqSpV$Xq4% z3n9;GhRpIOrp1 zTkHCzI)kh<+B%Kpu9C4U1AD)F;jk0$Ql37it^M^SqTF{*3%hlY72iNjmZgdlMd+}) z<$S$IBgUw|DY@dLyd1vwWWk{nVWcI5Sezb=wOfY46%++ z%~GLmX;j#U@dby>X~YQRzPw~26CzWf4Tzm=jqz3D`7J3M|h^fl^2iYaNQ3NV8dvT!db&ORyUL2r|waJ#ExOQ~hy0A?x( zA#}zppFuY7!%B`VOa(gH=q7rrs8Cs{Q1lE5e&Tpw%7Vn3mBMGMV@mPFXU}kWZOj zLzSY@oDT>Cp~YLlZ~HRyCufd;%QpJl4^w6FZzg0zbl_6HQls|Q20Ur)>ey+9L)!nKj(VxN3ko_6#7=rpEfekFyWA&@?`18J~G)ikH6&0 zs`Uc}8JieU)e|EA>frwcn21<<=ZA$OC-7*(pbCM&tV_4p3B6=b;JjaJUo|W|E{m9Z z(!gIPuH^M6*lGaXVeajbr0@e(s~yz}2`+uRlD<6=)6yqF{ibZ&@!VUvbGvjGn#SX9 z18bb|W6l-YBgy?A5=WUE-H>U8DeQ^GX(q%>Eu)>8+k>u(ihf_f}TXpmbV zt{zB9nbSw;zX{0%QN5B1xSkth+%vF2$yEz&H6osHs4#OT`xehQVr}Cf7X6D( zpU_s&$KzpWNys$cs{=}89JSNU`>#$}lJo@pR#|e5wGZR#%cd1nz%gOA=!Gn*M`Lq8 zzUH>WBpLPTTSFDXf+i5FhLv@f@5j5ah}!iE8*Pr~rE<&)_{Tr5*vnUX4_AHq*V6nE zxToA?aRm>ekoBsh80azqht`6Y<#`|#63nz64tOYNr=QFVhTqMFA`EE`KSOKFRtbL2 zzCq$66zcqLjQ)7mD_C`0K1xwwT;lt_MdBBMikeTEoo+;Jac9n#+S1LsiP3Xk@=n1% zq$*7nyMnKbtA?M|l$mZ?wwH8^a95aEgE)e~fciJS|Vku-5kN4T$8YKuC&!dXz^eFFU8R zIrNqJ%YHgAk>TRoExC5|f59|3@d!#Ry!?I1j(i)+Vk0SNl?sWysxx;;wyj(Gd{iR! z1NJ>WwrK` zY)aq-CI5NXcf%>-mNM==fAk`5UI;FfMiEgpayx_|1LSIw#krxHzaHbMpOp!q!(Zzh zU|Kq_zmuM}Hcu^!(2Fwnlg6s^Ow_aJ_deD9G74xr-4B2#+{~Vvzg|+eOOkB9(fd{2 zhahJj#>aErGxVvErb+|YwiQm$O$eRzuS(pOKWdLxX^9$n=o0vy+HTZ+woFANRP)u01=3^NoFwSB^BfCL z?tpiPxU7<(Z3AG?Ky{cB*6CI4(rD@2beR$`>fSFy?RD*`{q-(*>Eo2aK0p&RS32SsqHybW+XW$ALB1-N_r-PdtH_2R+(mC3vmrB!FxhDY#y-|;{p zzeE)1j(;&?g>+VH;&}{a)$XrwQw+t3ARpe*EfB`+5xE-izEn#Vp9t-L{_0T}vAsD7 zvs)#OU=Qqh)Ct=SqYg1>ROi^6o#lz8{OMCxa1wctM4Sq@Il+Be&r0f4@_5`97u605 z&M<^Tbz}5#*2BGE4^JuW`Tlb6qdIN?W}L`Z-~$&7%k5SO2!yp{D^?QfM3q{@ggA6C zYXS5a`R?Fm%231N0mawMo;-1e1mSGE7o}5PGgPuUNJfQbn0tW*U`)eaX%l-C_J+du zCs^uec8260YLK!w`<(^xcAXqYtpuDc3fbFnt2QF$RAGi?exhM{<#UkLBLWOHnnMNL2^a5V?{{f?f)S1h7 zzxRC*vdjJK>?dfmAai47+8Ij#l&TV+rE8cOx8%ZaitFj4HO)5vJW1b88Rn_UX1^5eE4VgTkQCreG@d@{dGbVf`f* z+6SMbiL%fRxE6qY;+6gtn68 z?=n$(XDVzs>pEUL5KlX%8|{hJxv>B)oh*!e5#+z`-3T|u6$WFMd~TaSvBnrs3!gbQ zIoP@h)vJB=ooIxY*A$q%nwYeg&t&Po^eRSiI6Zv!Yqiyc#H2XfdsB4_6FjdeFduEX z-rV`AQzp5Y29vVAtrirTH|SRzL_A*Q3baHSxUei50|4C`Y9-%+F{N{-+`v9WqreJN zgV#x4!QT4Co8qntz8aumDEOL-bF%qUPc%oi;TNfDoS(Ci5EAcTmD9uo3`RkufP^}~ zgo%fN>ryAx)@~`S^-jB{MARun%Gu!euUPR?;7>FETJv`yFswMU8sybfCXiL(@P5{g z73$RztwM~I(fT0-&rpg}D`{C3z`pRI2$OywCT&@{a0?~ZxL`E7tAJc# zrTz%8FK$?J*iAoy*%q-!AuP$HZ>)pG3a{30udzo|e-o86sVX`uW%P?vOaxjqI?0N> zSMqB?g`yZo{~D5Pg-Q6M8(LCS#%P`(Lh409vqVoY%9ssl?`act!C6@; z!(m!|6Pr-+wBtfOajhTqsC*zG4q1*cXU=k;eNT%IB=;c@q=;U%wRX+q#Yd?Bs3rs$ z;_%pddnThb*J8SZ72+l|=-F}g9M0=`s z^ENcbg~xFf{91B3eBf$3)noCa;jKj?jg!$QiPCaNb)AnmwV%=tkjn<6t{5CoWr}Bq zaEeXS?vrGXpH~^>gj7BaM0ct?#8Ox`;Dc7#VbixF{76~PJ2fcLL^OgHV~)mOb@8Gt z&$mnU*$<9g+$rnfrji#*@?YG0x4g^buV+~s=sc0JZalm6l9(Xni= z7vSpelv7X@<}eadj>+r;gqQ-V_wm2vB>c}fdahyf_ zQ|Fh*0!v{T%=|P@LPD9XuFrGq0tW^5y6`eVSX1(<&2d=`xs&!1X|mZ1&cKD_0a}0ntGJ)-MbA6NG$7^^%uqhJ=o+&r$1re8eZ^Y zXvEc>o$L0)CZc@Q_J@JA@>nOj=D{wTIHEKJWK0fkCmy(47fNg$oK7Sm?U?=TxcvXr zw?#=;9u>`5KP{}2gIR<`hHT<5Hyt}A6TDZLU5}EwQ>XNP_lTO1aSFr~@=2XIPH~l5 z%-sAJ1-69C(sL=Q^6y-xpAS#L_ypEy-N+J`&~^bgdkKz+yxOKMO_Xh2*zAKMqss9I zLnWrdzbDN;p)Bi5O{r@T8D*;0mW@!2JVeIl1X%IcYuV9upH=`9)t^y4vp`3^f4 zvElOJpwgqYQf^cH$-?k#flj{8R%4USNVl6JXdmRsipVG;tTWAMOm%=aO0PHjktzYV zjPr-dc|xYb-!dW|zAYdB$JgfzDoMU-j-X9OoPqo>JU_ftIk++87#b|(FBu}WH*2S) zxvA`UNeDtdrIw`+l1s|uD2=RL~jY?E; zi_+A`&M=DeJfp>%WoW&yeRWm$WrLd&XB+f@1kNN zt_j7-uXY266M>ZA#%^p@C$pR(60CjDOkq{(h`4kmXjAF8B>df$Nh4=T|-?L+^FSI#pISOU%GJ-!jtg5#O> zE(0)d_4l_SI!UXZwu01*Pf0xd*zSrEU2eFxwW#0ZxjEt>aDxNu0vj~bAY_nvNn>AG z!V!1fP$+;45H|ZzQy*gSYhXadS=a@{(dF8L*n6b1Z4gN;T}df`_mYl`g@JOCp1xXr zivZpvCf&2i$uAu?)jJ@hk&OHBZ~NX5k8%N6M>?)jA+`&KRO0K^i9KwH>l-C__DEe- zaY^3v_tYvIv&T-?QMaTtlLU~I?cu&5sF^w!?zElK!2>&wo9ZuD^#dUyU=Yf)(ZbSJ zND;)hkg-SWyUZPG3o6n|l7Cv30WL9Vrg=xYzE+fQ$)!6o2B8)mrqDQ|!p$yfy_ABC zPXAwHjOeQ8SW^t5*VDj^kr^@_|^((LO@W5?yu7o|Ldp!T6ES368>knN(LpSUQ-S`+p3X* z5d@KJDgF!hKq@O0iG?uBkW$|UZvQEYxgI`T=Ha-F_?~#88@J`!(Z*u^2!gLPaILctmQNrBhT)DQE&xJjACEdaU zz;OumO_-c2|I*_BvGtsycd-gkdZTr!Cvi(uDvP}uJ_VIS#b!|Ma+V@jBG94oRpV-M zhJs?{OYi!lQ&U+ys6eW!1EtzRbl;E&@ZOUU^0T1vv~meah(6iJ$GF&MEAeReM>>?^ zWhJn;vc7&o#*34AQ(n{N1ndzoE*l)9a<&hUWYv00l!BB9bg4nfbZJGDI8)QPeW?=z*-mAhtPQx79P;;`TTtVnkv zqEt8NV-e+*Q(`P(RHyqa6(=w<*ljG93jY;~4h|w;&GD@=VZ@Ba|5;T9eJiQz!G|T_ z)}BUbKHzY_k+`mwu3ESvk&T%+FC0)J5$nbblNzG*jenBw)O zRh5M#Rz>Vtx?s55xM?mtV5LznoR%F)l}18}VC>p1x9oaPX;jI47_)9%>|3v%e*t-! z??)Vdm)A$a94Bq+O1JNnE!IBvf3w0^Mgy8B<#8IRvoD!`O{2c%E#b_W29=A1sJCp^ z>U?qpnSZ_SO6a9l>KV7}0k?-!0e~($;}6`3;{leER3&~Nv&LQgAS5`-V$3B-8$ClB z3Mn~8>O*=-&PmOi7YX**Gs9$+&0;(6OSZO`B1y!;LIvIx(7k=;3MAseiammFc`YlS2zDd}=%&q1(}A%fq}Ox4OlrSLE=OODvOU z;l1sWIpw!8(~^%heoqogAErbKFGv562kJX(+pba0zMN7Q zPommW8-2i5@+Hp>L5>p+o|L$Vl_FllwAqcX8f~^OoN5ezWH=JeXibdRx^DFfeANl) znvQtqyV?TefEre)wKf7+aYad2A5PoWjWZ?PJBK-QhcxRInta8}*(_FkpO>jx5&eRz z#7P@}9bOI#)|q4fE?HG%+TXu8hzaNa*|R^*K{N()_Ra_4hcMnT)v|8aYbNehbK9Ni z8iXaCSXR3MAk;cVw<&bx%Hh4Zy7^OPAF3sKvvkNR4LTDwvsRf*?sK=i{3SG7=)#OmBFg>>GG=im+u{FrX zQ1Pso#f>NJ;}&mtZ)JSmLzQj@I8m*yE3A+wG^5jH>4`!}zA7$CfnAem?#ALPA0d`m zY?Y_Cp+f6@t?dXHADU%n7@&fes$88P*Ty+Kz#qGMVOvJs1j2Nk|0|ylw&AbE3jnPn zi<#!zi12}U4m)x$=)f0+vJDU;bT|M&V zcoh-1w%erF%MDB`+dY@lTpSdgOnxixDZnn>_fSQyM1rO+j&%Pg82s;FP`*37()3>?}LI6Ig7 zsdJzRhS8WYMM7}{6U|4@musLsGu+^*$xXw`cX>9S-cpwtH8Sh4jpugqFZnQYBwPs- z*O+I)ybMp(ob7};5!!Baj&8a|dlD+!L>zcEp#utdOG?!l?+uRK@5_P==EJ;H=Aa{8 zmNkuU<4Q9^6nn<#+VR87&QKx)Y%*QdfVIY5XFCsTrmVMqP=eDk?_8TF|F^4h^{!Gy zf-cn2Awp29SNHBHa!iz6>P`@r1hhBTi`_@$*GJq4ran++~OXxVfP~T6g$ql4APmm$c|NL4c0rjk|9^iPSc|{ z>t0D|_>EDTB3L+I9uA(JCv)lUDe-*is5B)jGy3bQ|DEW4&cQ+8xGzjTJfm;)G5TEo znF>stvuP33%~|99oK1;%T0AQr9}4_nO7FmIL>@U1{)Y;8ba0B>JMj!pEyMLmp+VeE zhFKjjv@?smtW?cQ0sdq>v*R&y{jhkEwQjX~uBZZE<8r(3*8A1#KO>b-d-IpKoSd}@ zo+91d^N3h?biA#Ie*7EI1uzxiu(Hz4ae9${tZXfaoqxh-$A?@^HYDZwt}p8(j8 z4}e~WlCG0s%VTjW_VIKa2TxXzo8FnErT=)&ps4z{ zy6>hLb?CO)!nCdS#cAa4t{CTquFDwm(;hRSmh7}_JBSho84 zeUKVLK(8C9ve5L<=FBp2&ynL8Wj|L|tMr{)nPea7E?W(eawPs)xiNxYi3Km~C@4;y z-+q56)2xW?8T}NJt>5x{)u3`cqjet>G&-35ESV`ueu|XCSifV13R)FFvfQ9jT*I&X zA608Rh^Kz-tvFt&P2nZ}mB$1OCVhgV1q@n#B+C)dXG#u=(` z!^wAzw^RR0ZvU-Y{T^DT?I@#cYhWC!-?Bd{E8;r(KH~?B2IHrPmD26W`4Cu8R+#aj z2pj=2>dJv9w9Y26S%K}|mhV3F`cY6Z#Yufa2YgW**Fz%OK5}f=FpLP4!J3b2D_`>P zmXkZ{j=qbFfq$0%gT5C>6%7$!AoZsX(5@alUP8&N6;>*g>de7@2WSJ!6R77HXfb!m z|C5np=_NRS<$?K>k>yH{#ps8<_40fJElfI3rE`3&q*S>^KYM+y5chufI@(L zdZ({Ztr=oU$Qvr{!Hy3A+*jURtB}<-NCCvY*&1GJ4d;H9Pheh>{-r;I2tNcmmx9Mh zQX76g|GR|Sqyf^5NY;-n~RIi5Q#Xi!tJsnNr7x|sHC?0$37wPC? z;jW}V@tC{yA6~9peJsLOK(h1WimGzNQAq5LQ;mC%`OjLCzSRO@)r6G%Y5v&u=<$&9 zk*Y2+HTT+!VOzl^j7v}N5m2C&JCWoSW;jH`?8svNcW(vADoso;#Hu4_{d6c(i2E_e z6uHv|3nhf2#^YS@%I4H=0xT1cLxRMztzswFgyN;ALywOIi=IchxuGuBzVYk*A3G97 zosb`aYmkEIIkA!KELZu<$1ow?Z%|z5_hS7bK*R^(!#Ps>kfj0bt%! zzJP&u$W4i*%g;m~UlEQ?9NJmSqXZhkzh&nr@+67``RaeP=!rbXtwx@#kW7#}{~*Iv z&Mun4;{#IkJ&HU((o3KT%p_{NFJlc2_B&1rG$Df0!0lL1L2XIix*mu=#}uRg5%P)*fTizZKa1!YOwBTCQi zt{1Icejc?-F{~HJt@2SpPD`e;5npFnCK9hAh6&bB?37fL^M60={<2To{fl#*>s;q3g8tXQB|sAlIvN^k#98W&7Cf1(NbPp` zl?3cpqIsIB8r$&?+N%JuRjGyuchVKfGG}?+1oeBRxP&a3gi;`G_?PzOF;+;_ao#ku zFAp&_g_|k1lzN9F-Kw<^RsaQ64gRzyzccrVyi{`4Jm><(8ynLQSmTuuKY}bOHG63! z@yLYJS$DkFU>1x~sal3LXt=fb^8e2T)sH;lPbfGhA+1UOtwwaU zo!Xh2|Fb+(IvKva*)xmXSXx?bK~EBfA#4NCvqJa0Un7M5GDY4YJyKXQx-{uA6lziX zBFoMoI|Lscp*qN35=`4U8CrtuagO^Iz=_2eZf@z7p{mi&W};48JxE;U!zLW_B%fZg zB*yPIOc2-2QxBFOHvf<7xEUHnz?5iJC(_AqRcJ>bY zKhzZAWGlzUwWLWY4sz&xar&xU&`=Tv?Z=^B+I#e}4+?G!(Cvy1GzhO$2+l;0F*U!7 zyB4E;HePH(jaJ0$Bt1C2HJ1UgtIQ8l(3;Q*^-|ErU=IslEV%5b=_@$tm7wcKaA7T* z5(_b~tnZ!18m6vOSBKg>eSZ(Uz~HDnW{RNwir4k~ef}&^aK(rkYx+(@dY9SE{ausS@L=$D^kDw56X*t`;*WN^}p9LBoV~c8&wh>QHd$ro!;9Kl49VR z_Q<~N+CDtI5Wi!g5SEix^b}itL_5o@;56Ws)VsRCMu5i8I%vbCHMPp56N2($2eVDd z<#bLw$_3Mr4q>0khdx*}0;wH8Jgc&Z*3C*drzVG6ZRaAoTmatPe=;+ zM3|4f>iY}{r6QO8TYJZ@=z!c|ByZ!r6;yVkIxBbr)gBaXHeZ^EeR0crEGEj!WvsYv z2Kw($!b4xYSRf0ECi9d>7&Q* zmuy_z*v7v{5F4m8KZ)eCM@2(UQ)AfTFt@{U5L1(UYZ|62 zl9aQ~uTW3>?n0vbgQ(my&O3D^)h-&cX8el!XLb$!c<)p&&775M3o+a(6`e#;)P}bILtV8iDvC31K#ii z(DJI;)}3P_%w?podo1aH8B`!>Bru)X_n>sqIuhI(#tLe+S{hFh*j!XQ0J)Naov)Id zqs;%mQgSQsp&$Gh1{v@W!w;v_zClZ5*$Q$Zi(q3t^nLac^&I|vc3?Bdo#RU~B@j=kvi~^43qo zV^zwUoFmPQ-XKiZyEUOzb``B^%@?lxFKn{)XU|Li2X|*J$wpYk>GHG&s7XhBe|!4B zeD*>V=z|^BX&4;Mp#Ma?#|VIn12E3SFdV0IOqpTjyZeduYO+bv7CCvq8IU45CR^P*qxDU=x*K8yIUCGu ze@k!w4RR*QLp9klF+3tNkmh8?h7@4`w4=ty; z#u!SE8B^7fe%nPMf&5id<03 zN8_!Z-s|cvZ`z_U$GnwEw?Iu=enG;>U}hbh=%#k{toX)Jd&hSO0qHEOTzB2CsnNZO zC}2B1^zyBK6Kk`l%JH~GHX?fSC{Cy z^6_O0Q!7D&ReL=&M6k1#(lvj(&kxaqz9a}F%~e}V7}U(=ksVz%(HK?INSafNi(OT? zq-zq#W{}~{-G0V=4O_`aa_58|(%_zvTPIgp+r7;Q8|h{qI=!Op2dIr0VkL_N60s>n=MGi~Pxo}(WnFG>3r8^+BKYn^C`Ka16Dss; z{mHjenI)sxGgR&2PpaE-E*BUko6;s$IShackIB6s9{48-)b(3TpuEWaTw#a=&<^i+ z(T_N14XL06eaFmy^hE#O&5DkWv%PMjvaVBia5jSuJE)A zTT$&dMVM+l5zH%Ch})hh8xDN9rmaLs`FqLD~ z87r$Qm*&#&#L|$tQ#n0mi8KV+Ybr2`VT^n(o4_gC!NW{Z zx2Q>QV4LHZTWHU%)kELGA}lj64WC=nGS4aU(#5|Ib7%G5vHrryV(}hYV z+#=X&@DKSup)bNEm*^`Vs6gDdae0&yr_S`1rEpHg7 zjNdT)%tADof!kfkKrLk{ucy20BJ>>i=#0jBO7rLtXm(?zy~9iCo_4YSEYl29AZLu_pp~<_ z2xwinza1GA`xS!W)d{hLSaRFwVGC5P8$V_%lT&ooib2~oJW4cQZ(ajmR3?(*;t7K$ zT}3oMB7>S(DH<*8gfn9bDs?M=Z+<${LtlU4w-zR^2`5rY+45Q`Z6g1cs#grN^~iXM z*V#fTiIf!+LN^fqipy)rBih?$VjdJIolv~krP^x(u$yG|l5J?+7803nh{$JrYGWv+H zR&J=_;2Td0*m}mo;OIdifxJ42__~Q}nz>L#$&1h^1y}Zl4SrDftEZv{Eu&V&N0Jaa zyoRA#fhPSqsIX-QqRB9g<1|VDRiuUIXpS#;-=Yws*D+}8+l583>Qfj^B*_(MrCaxV z$!2rbzd-KkknO*h;H9goP4{rj(8GE>#hY4 z(h$B=xZShV=w6b2*k+#PPNVEN zcZ98!-JeMMJRD;Ufgf(8TUhA?UtFLD|ABr-S+|c+?n&R!4Sn4NdBG9z#KE`EW+_Jf z)->}PCi97i9}JS*#V9438q?4hb+Kd_%sH{nWNOWxYhGS2=VLDKuUeI{9TD}k8j|4& zwa^v>$EB&-NOu*;Pb$55%F|o=VMB(Ul$Zc(8G)jJJN?4VvO6h?@(o(9{g+{fLf{C9 zBsLq-SyZEfBG(gmaG3c`1sYyHiXtt1kxLK7aU@KYwKSc(HJcAky^pMvz$9BqIxFe( zY&ZJ?$Z#J_jgflro3EUaI`i?XbmudLI@7pcFo8@GN9od-R(eMp%u5^+snBvMRq@>A zYGDo9kDx8wviWWZiM9s%I{pX19!=&qg5zo_8zXD#bcrF`_c#->rVcBnN8fzlLLo)7 zW)XL$)pg}U6^ZuWkh&z*A+;q*90I24a6CeciM<=Qw-`nEYrq~gm*|8K%jvI9vojJj zqYce9GDZuoC#PV#)}@HgECCmhjI__~2J`BQ_AmT>teJai^jiPp9FKl~HNjKi@8?o3 zp|t^@$I);60A}eRl!jxgON`HItMojgNV;_-} zkn2;l8>k%mdxgik9XzNs*rJlHb6Vw_+nLYh?z5=)RZg0Q(4hOLn~ajKYExGe9GPXX zLA7oaz!3cpM3filpoeTGE=eWfy%O}82sr+=>0}NxQ&0kF31uNQviUf^I;H+cW63GW zIqAFodMqZU%ERxDkNnCgeGZA;Q#O=iH0!y;J6c^$pdDlQo_H#}O^Tah{zPWH(@n=1 z2KtQQ6%+Va$7wRrp#p*5>L*D^kEatt9WgpVy3^0<|Lz0Ipf)NgS~ro2I;_2zvt|6J zg(2#1mBj6BJUg?Y9x^2&aDxWEM)JouDLBb367e*Jvz>2dhA)O}!G${US6AcApJ|p} zZ=_huRx&8=DgkT0^CkhXbD~)Tb5TqO3DKi`-@n1(>kHI|ufw0z1i6ur)W`uJzbY28 zHvhMX`ga0q21;7q=?~#=<$iXT#U`fmIOqyVb{)JYrSHHmkG6qo;IH{XbC8{nau6=R z)G9rr>*gUscTfYGF-0%lUwrz7(qOFiCyvvae7xS$NRh8M)YKz+7yBNxTi5CDr(#Gw zHgX1%GC*z^Hs!3LKIh|{thF6HcK1QAz`rge{&+=^;5at}z*~&W!*+6x;bOP3e0m{6 z7lh$j6bEHNa-L#>UZH22{l^`v&u^obAy$R!3x=~EQ_CZftBtj`b5aYGE7k|37y_%0 z4h1mMawma4E7OeBGEtv8=@O1CRp94ExTNV2s<%TQYz2Q$eOiUzTJAn|Pnq&q*lRw( z{okGp=9A(%2Q?_i`2$R=4>$*{vSxi=S&<{3utSXKmWmuCrc_HCUDL<~vAnTqIZ9x@ z6km={MI!Z$M0+F{$x6;%y(M?soq`gJ)w4+^$jf{CxlrZ02ROo?#|P^;w%YM84(C3l zas&n|&T?qmdiXE*^!av$tCp!11k$uUm|9j@M4{IN|JcKh!+IvEi6&23r(4o;3l5i@ z=VxCFnuVejyAprw7M9Z!0yc2qG`3;gJt~Q{evm2vF^9SUip?lmNS*ZWGom_DJ&RLeY^V|X3uoN zM%U{S1>T!%qV`KTEA0aTz#3N91-aH%0Ix%<1DMr5x_>9=@SM| zAhD)n1UtD%N;8V2RT=>?IUjdtkc)#>^-~%jU~%efjCo#PC6a@J^us#nY=g%cj@@3- z2b+oRj$<4%w#X8JqM#YE8LOy@3#T59(R%~#3AFodTVEdtZ||3h&|h8g(mtIO5=`K0 zcR+VWU^1!Bj!JDcRJ>A2!ofq+m-R~*B?;DH9vce<8ba*_J?%~Xkc;betQdMXEVyy5 zFK}E5W$`!(+H`qJ>)`il)-nrugByHHziUV&T`aF97{xKPkPBbVS+ErSfR&1gVF=e7 zDUnzCu@(2u)=%cordknO{>nA0F#_+BJ2F1Kiu!|HPZy+BsO;?1Pp@ZhkwE*#-mmlI z^wvzKyK|NUdX7pf9IlU8Y#(YB6@f9E*pPjWXKULcA;tRFe#N&3UE5V{KGRlZD-9v*zl2f8p%*cuF7Tt96R`=&glbl-V8n|bpVD#~rXuV@r^A1&dfAAI z47F~rNAH6R>y76WGYyt?(NER`#{Oa(0YjciKH@z+f)$NN=j~RW)_Dh$&kbo4st7ea zET}xbpwxq1C*9vX`gE1OXurU(OU?^|>y#_Pmwpk{t1JRU$4~cea!piAY$Y!Re;}5; zUP>7Z#p1s}6xsRIE;8j>&#>gSn3!f6q<;&DeD0rM_Dk_>T_L6vn-A0>k=BnVCRyVvZ2n|8x@3YXypBKAQwZt4TJgB?UxjxiUEG>q4UU z?Sx7wY>CKmV)aMrQfqP&iWZ`(oH_8#AX$L(L`gdl83w|5M)t?IQtm4lKyl|Yq)?4O zx4XvMEzcGf1XRuiU#kwh*PJpC!s%W22kq=j%+I$wR5ijV` za4J6=tzpsJKmt=mdu`GExckZWD=R^qW0{3FKPbq)#o}S|Txq_(^M~bZ1F(varbfDp zU~OJ=*HnADLV48;SuS@9sD;HugyybltoS&~Pc1>bs4xzuBoY=<-EKwO^eBL_woUb{ z+ACgS@`zHE=t^=TW!YiNSaC<X3u z(?Q0#7@eyR?%4mB2+FBiFhnO%CN+yq5K5}AQ06xRB!TR|J5@TWXJ4#3cdfEqcbwW& zW$pJ4(Ud3|sS}O5H@>v9k9}w7s)fH#0~&lN(!0-C8GLT@JzzJw&Ay1y{<7f1$^#8l zW#q4b$?U5IHaZa=dM+aNUKW+U+XG<~9DoJu2Wmd8!ZHu$`Vd8?o*$+pO*5Cg{L5B?waM83#vZibJV$V>(n&JKt_@lMPau<$Wc~ zH_Ge(C`1KyJQj8NvPf(PHDO1)4@`m^BSI{bD{f_??Fu>#6-&(E!0;!uVB$>apCJ*n zX#-C-d!wB**fvCbyIq-!NV?rwOA9o%MplOl~C#@TbY zUvNjRtmHv-rr}_1ub(mraa6!Ic~{jM>jn=ab(-7HqWLEkMi>HyL}OI0CSSJ>OwO9W zL8n#ADuv?IG=@a&TD6`!xId{aNw`4RX7Le-Yv4=q!GKJxteCpcB2kZ-dEji|vp9~n zgCCoo;9QRzn*aoHA! zvAaiVEC))-dy?zjkg{j}$E}+t%+|h-*Mf!0#bEw^I^9{D7+7y7R>{`)WbGEYE7paO zeIN8u%Y09E&~gEznldFu>u#^9E;SD8PBJmc+bN#`_0%J5*kvs(a>W?wzfzU=l zU2AiAUQQ_$+H=GnQRxwAyzTODM^lQ;Gqy}*AtSvKSsdWG2*j|_f&Me)-xnJ=C!N^j zw0LAaAi@S}2RliTcEw%|iVH_J69fOP<4+b7{VwrS6}IN&eNkh{Wd$Fw#9 zr%yv)g519evHyMRiCS)9GtnB{MF#GBaj}U?(dIXy?&fZqt*O3Q82y%C( zU5$i|h{idp+W{B><>9a2{p4k$(GYVtxa;I>hhmdq7B0ipy{8~S3-sX0ddHjfm@pOe z072FeL)Jb6kftkum{+K^qHI9AMxRxb+w<{cc{xdWH_P-R(a~%TvHD#5=WUU!a-xNb z+nJjbFj}8RfMKrQdgY<#uy@|6?t6x!TWC zHVaDI#E){sCqE650LB;|GA-m$y6Sg~`J%b&fEv7ym}y$(EnwXfj*BGAj?)di2~pE-6#Fa0UyrS^%8=;XAm$Zzyl^!GsMv*+3&Zw(k@Edn;Nv``;Aw8jRex1 zBP^m`HZBa+&H4^jySNvts~>K?Z-R+pAK;VO3bB20dv~?#;M~!d0agfZ7T6kci{57WdQ<3B(BQ_eqHJq{9KZV$r+y= zOVsf3jh7XsF|DUAr67*O2)KslzT8y3z1IGM0V}y+oR`aoeOTiLm5|7;kkDG;)oEg@ zkUr^?Kx7vdl@E0AeNLYG-2=g`=7y^kwGa|h%BO*Uz3>Rd_Bs3W^6>&0Z4nV}YR{S! z`+(1MkX?CwCRRH-l?c%-K`YVS&redFaAyb#QC%CNn8J+ z?Oj+?z8-6CJKw)ae)?}GASl;4+gC&$Iy2zFV<*U`EE*!8ov4SE+c$O3#P!cAer{VF>1w@PfyGDAxUvee(Kob z`KAf@RLN|Mgq&RIgANZdHRtnV@C;ePX3P zf?!aJVtocVt3+mV`4TF|u|yK@B4^t+hgkv7n^f~$lQOWh-Bzv6<%2OmUK_!H`7x~z zQe$6rVN$SZwo|4l;eGj2UXF^tT?ymB)z0E%a<3;p$>djWo^dVnxmSEx1WLVjWye;G#HxIAsDO5CS7=-Ni)xofKEU-iHR?EfpIEATBTcUsQQ`aL)*?Vn zw{36X{Qx5b`9SMVMLeZMu+h3Rq^p_t%a@6PtU(cLYg8h%HUu>nzA(P1M<#hI==I@^$h1-NvYyu|I0>3|CK9}`Jg)~kMB2VYgMZb z$C}L2ID@ePqhYDlsI=u&@=rD+8>sJtc14g56`dfMt4 zw7;3ozx^NonzgzHb72tvu{ZyTzjtfT?a_{6^iOb_3T_9tYD`xLx5y5?2M4iyL$jB; zz`=vP?;C6QNZ6*EH*aeAJ5F9Ty+3bxtFj# zB7TM;nK%)(;NR|w_Tl%uKbi7AENpJLoY!l)9l8dkHc)*-aK4IsOQh!Rj=7=A^F=gV zy*vzwk?b@L#?w%-#ZT`~a?sUkm}aeFC8OKL&!9d#W(oSmr*w-dKAIV6c{{ZfL{;yx zfL_T?GK%tDV`CI`bCN|2es4G0gaH#m@#L#OUJP+5ZC6Wle8E@z#fKwb7!j*CHpwiay!XdF7d1bwsGe}?r@oG zWYy{M-0CbIdq+mY>@&F(T3SH0(q1@+ge8w%Yr{-&86!1CP>Moi-kSjQV!)NoZA-Ec zZVel`8zoz1y>n=b4c!#JUphLd45lgzuLgKnoe0flG}}eBFcdBgoXwWWuu9m&>F&lD zgi=wZgZYi?J@V42xGd`TB*; zI3!R~w0P5IoIM%*DScZZpNh-5flu+iEP&~8S!w(a3*>B}1mGN4g7S#i%5W9jGK16h zOJl2Kl^Z398Ap$|ppZP_OL`A@D9&GZ?|Qa|Ym>3A(cXtDr>xbKHQfK`YY3nKwEh_1h_{;w3i&!VPhGxeHY8&qHWN% zrKGmLBta{+CRm!xj$q3%A%9|yf3f}{yqg`lA-)^1x%&BM`IgLUe}@-D^K4q)o^w3% zjrCeUdE9xk6nn%Gp&^s|h{ugzw9uFJP*Nr@zz_r8LNtmp@!lzq-PH*O#mwr_nH080QIIbdl4#!k*_!7G$>?Y&YqEe}CZU)k;ttzV) zsc({UFUgJ;uUS`|Ye>5y!w1z}Gh|>*Fh(YFwaK8N0GY(mQ*1Y$WmmL+>&NutS+wDB zZ-Vg3FEg9oGU3+PUFpiT9b}mZr7l<$MUZllKDI-i*5j<|jI@E#tVwjPB5X1xuHt1n z-^I~A)A?Oi@ZgM6yn#5(3x}y0Ba5rYLqR*0CS8q3|Jh)90Dam zEp&vrR|uLcu*Q?xok#X1`rkjft<*3HjrX(F@B}^3PE#p&w;=bB?D@{;yN21PZK0bk zUmm}Fs{BV2y$`vp-yCb+47S~y9Up|A|D<~z<06Og`ed#ahQVlvQ-W8TsD>r0*md>G z;!h{P@Y;|;Yw}!WOKckBl-C-{r{U!-L*1MMu>f=@%H^}y;SHsh5YN{SvX2`G@}PUE zW1Y4u9Mzg0px-6uBp!IHKI+Ur@D7gicSDl@Dea-HRyJ|h4mw!PclT@PX_sHfnZ+eD z^j~G;C0uX178S76T`U4{9c1a3tLN$93E;yGGp(ZE@mEn~Y8Oe2Q5WVgJ9~frW``!c zd>PaXktTJPc}QD*uk_mW!GZ25FIewQMUEPEXMH>9{T+V@tE1#F($WjnPq4<3x~nzH zu=<`L#=Em8BxbkI!mknBQxcEH4@Vza?>PUglHFk(wA^Ec>@(W*$sc}4yIc<+FE0k` zrl<2{(NtI~cAZV|H+Y}oSqE*um=9RN{cP2iY}edT#bOvAhEInMmjGHSh2T7!dh-zX zKou_&L>q5<$f@j+5Z) z*;jIjw&YO_>Aj3@`YS0wml0DUc1@xwzRbp&xGvuu8r5%b)x0>m+@nEeBb_=guU^jj zIlproCv{qm-pOl`QhXLx(&?%ALXKsaQoci8IbGKdPHxksY|z!y+|xZ7&Xi^m&u1$0 zySx;&vPMIP!$N%&69-tS`gr2GDx_uOxr~@46z3Ke{OaYwtzQ=B9?BGDR1e{*d_Qw@^c21Yr03qDMS`%^7{6R1|5MRpz06gmHDOSjv(1La5##}BlODnkGk@e z_VHBchLcxS-Qsxz%>kTbNM_ZBo2J?^iRUBC1l3o3-;HFfzaL6jx;}q!N^AC)@W0HV zs&j!|m>JT#O3?-fk{IucvJURi=;_{m(m^NskWQ1^%`*qMr_Fp0+yLs0Pn9+~3p&HG zsikdvwi_?uV5W*@%#LF1!EtU^$ZQYzkC_8-Aa!dD2PabR`nTSkp7ocrEKC!^;XZ7Z zL*eQL7FAbGUR<}g`Q;+|RIzB6JsMa0jnPyD`; zgLvAqPFr0z7TZZ{+Aawekpn+lIL{!RPKRS_uShvsrCYUFUd@L)nB!yixal2)E47;M ze4;~h-J`p!kG4S}G%+THW#uK4s#som9SDvhr*OjyB`t|ZZj0`8Y5$qD@LajQSnQe# z-9B8s8k5p!m~u?Tblb!H8LU=C{*TNxe;B(vW-I$!4rnoQ+bq8ZIhZ3q-4dq^Tgh`Bsms4X+&<|RQ4 z-N7N)bfPB&;c!?JL<2rBPKdHcC>d=hALNvStG|*=5>I?tv?J66c7bSKCt`Am^Ie*F zguZFN^J+&U?~qV}EG|oV#h!$Ek5&H~Ro*+xsF_1d5*g>$*s(xe50|7>zZ5E?GDDsL z*s@!5$1#$>LCMropL4Ozhjz(-(@G)aH{CNle9`23?S|L;49TXhPzwFZoE5bB`k!&L z5Pa6)8&Q^}wwN^}hOHWsHzE$#?KsMoO~|n9ovEl+6y$Y{lI*oOI(+A@5}l72lw?YTJ&= z=It%DuU~TTYv>MP@TSu)33$s;yNXD+Zg&-K2`fA!bi*^Q#4ZEp54|Z1$*qgel8HZ) z3U37`pzSlk`2k_{>Pc1RmB#}=g)zGbZ9+G#_NeJ-8czR+o&%2ueCoZwEiV5a;H}fP z*gD(&bFK&$7Op)~ zPV`py{=T%bTBQx_`a*-`1L1ICQK~*#9vI`bzWu!mBC?xLu{EZqz!%pkXGG9z;s-x^ z`V;Fann1+j*Hy-))L=?+jRNG|j2KN0y@=xFwbuJ>AL$^km7ky4E(!+8<#S5{86GbN#DV z`JQeo-qou~P7brx#JA0as|M6JrwO{^^UZM;@v=I-}B8WiVI8P~(c z!O|&{IAN4c*ps5%VJ$3`jX#fo%yRpnP^GEOj#tl-fK=|=dThCbk<_lQJ7l2E6y&$% zOy{z<6gVF+{rnz$wh4*ipOdU$VqJS))6q`+%qE(lBVmfB3Oy?|eF+I-FosXNM#Bt7 z&et&4G-Q^Ty-GN_o|(|G5%Ya-!l8D+p{q}x(vHDiy#2%3;&m!lSB8aYm#JlWKvpub z9$IQoh{?A)L>W!@j7}_yHyl^=K8kWRn3|^DbH)j<8Hopn9i&<~|A*#X_xaYIje@0h(EFvN zzl7palw2~I(f()RDTf$5s|J}l*jT|t4fAE+Ha+RJ;w#v)SbHxaL8YyQW?jgrZy$i< z;6Tc~-d3tveeR5rqDKemIT4E=jft2Y-VTtm;CH-$z@T?MCL>RGOBXJi8zKyLL6-VF z9PLxYT2Vi!brRLHkB;twgHHZn6=w-1PlZgk@qG;qO4)%LmKB(WhFrUJ+A*PF?{ya@ z;%ZkG_7p1HI|rLOu0tmdRV^c zZrTW7>*pYk=FMI5*QG}&P%#4qb=0kdok@z2Dfwg5oOv!R3tlDJ(8RLzP5*-}9BG?| zXmr_|_2;*fQe@@*LgmUzc8d3lniJwWm%ZIr@zvXwfArymgFm%g{>&eLbhYvKy69?4 zbw#`5pm*&L&rS&z7K)?CprF|a(*SqgnFxcf+mhFW(xo=_`+m(VwSm+7)xGo$Q>l>9 zrMhvq7x>1nZ0bT&vdVb;+zT2RX(^aDj5DQp#SL>O4Q1GQnQ}v}H?(iwmP{AOW<^2S zv`Xa82rPX1n(V?ApQoEGb4&w!dM+LM*ZM$Dj;|h>P#*(#Wb~j#r5B&|XE|gGaKqv& zJz{8P(+>Q6auRp3>gl;awpviI2ZQ(rVpc_^2avN1@n~|p*g&~d%z?KqnE{VJ0i*S3 zr1VdBJ~h&g@)L95KJ1~={nC&Z@50yP+VdjGyR9$#!G-skbHZ-D$FlrV2;=U{#B`fC zxS`jDWDBxP5$O&zZs1ndPxImPa`wewcAVILN zyZXC?q;}LYyI9L7RUSQK+e(4Cg5z$1l#=KC!yY0ZlIytzUQ?x_76RPr3q`TebNMd| zy~PTv7LU+RQ;yy_Ghyp}sMKmtVRQea!6?qq{W8-v$dXosdZBcPZOpP_mf;a$-zF~` z;3(b}w(K>2!1-{>tQ$wLhqX;J@%OZ1)^1C|U4ptTjH1LaNO$L8#_`Tjq=dL3^q3A^ zp84PH5#|K001jGCF&A(4vi``o{i#Qvmurt@ObbxE-@u!$3GQRgO<|ZwF5S+sqr?R~ z0vE|=D->0G^;=K<@iPKxVGO*k+7}ac!;`L^DOy zm_YDmxbq9<%X)rTCH+S_1>(DB-$L^sJH>v~>iWqX0cE%6BhBXUO1ai_Nz|yGgq9Ue zPg(_o^jjmlXi#bv^?X}HdyifBHj-aPPO;~1MONuF!(eT}^KRDu{mkdy$>IV<$LLv4 zQPI?rjD=bB-cQvGF>=k+Ok4NE9!_U_a&%ph1Ig?K_Z?$PDN}Arv5Mx-4zAF}_7jK7 z+l6P?Gmt^gA5a6fI+`_!h`z{*2l|AEWsE`A^?P4{$U|w1H?&R!%XpA%nk6pW#AG= z7oKm90-~#vTX*<%3$04*hN+UH%R?WbO(}vAewiy%~&oMj_zNdXs}4Lk2B|n$oIXY z93JNKg0@GaB_Q@qMHsvT?dSlaRC3ozv%-px-AQ<>o>N?k&-#f5-}s6@o1Y7RV@*q$ zuQj!)(XJsBA`m}IgAw<8)z=*e+>d@<`T4|pbX84nb&+H}LZm23fSqk_A(tB3vv0m$ zOm98~oR`Z5sjx!|y%+8)tL_!-0Pl!RP6!2Rm4IT0_AgFu6!K;7A~9&N@H#ufV$#zM zG4(5~amjGC(MdFCy^@K@!&3;{(A`_)bjm2`g(}kUIv#3>%2IAv%wZbx3;E9vXo{dt zj%AT*dc9(}v=8Ft+3-8{$pn_*IJzDdo9tr2!r~LzCuRR26Tbq_A}b+kXxKf$piriu zqIIMp{3;aKLYHlE1wq@FJYLI5R&fhq-R$D0W1KJAQC`v`J4!K&VxOda%NFqRO1urO z+&pV>sNUWEP^VBK2Vl%2qF|i7D(e@nA;RTMJsMaT<*QoUT|K=10@GFZnyYdP!m3{4 zG$wkzQ&*WIE2lGqo1ZWiEsD*wYmWUe%ED(7z&Z#tu^D;aIEvkrSEyE^=I`Yl_tU6a zRu+#0ivdTt^$6=c=EvcJMiaT&S(rWafvC^?u(w857+qJ@-S6{1>%A{evi=h;KleY7 zI8bKmA_ZP62JzcK1hMu*^k%Qf-QT^KwmDFEU&wc!E+2cfuB`?&!q4};|8*6Ej!G!t zfJpIza9V|?swuplCP}7sn*F<-z3aVPrrH0sSPbUWObEwEHeY4$Ewgg`*~F z_@R?NbDtunX4}Q&Ko(H%=hxK?9f=-rDQ)3RKZn13yR@AGlhW9ek-{LWTpkn8;GERB zqMhmnrWt3q_RF=t_I3TCuAWD>2&ZzyyhMBnac;=AW%i`QXaG<_CCZ3~@a)}!kY(o+ z2E6Daw02e$U3YxJ-pEXzvpA#cn>WXwdF>wu6uZnr zB*y^9UdN3tlaiON9jlx|$aCMlG;M-DXMe-FYp?6iZr1&|~$^R_Yh$@tTSN6(Ldrygy6RWoWRSEiyJ4hape zKAdm88ntj&I6b=xEU!?^&Bp1;A^2|~)pFqT>ZF(jb&=ry?s|$J7n5X{tz4ygUINJ{ zuH723Vx-Ma$$1I!uYW!TNgl-)7*mOwi%yaY3gNqndY6X1(R*LFcJD7w%09+a;1k~5 zOU>Q=QF4y6M@x7y=23w9rq~JBYEA>RprjU3?^!)e!%HDbnO5%q85O=0VRG~FVT3+m zu>DWSE#lRLW;ZlSWj%HRKay|Keup-<5MMaT5#MBD2Gb(|aN zgd&n%*t4^kQ9oJ- z@(=R8<&fDUD_NViDxfZkw3GB#vfyVE4of{R!nErZp}tQKc9pSB7Mbcd<@6UaFE^Qk zGj+axEb*WoiS_p>zDym{=DfG$BZ|8{-GEzE!@uKl@fnJrHgAW#PgMa43V z^*_(z_R_QTRi!DL0cfrk2&3w}bBny+*=V%uzT;R4c|B45!QXwTU5#ZQ(@Mq>UYRWD zai%d{oFh8pX8w9G;#vHC_S13+cnn6(rNsN@v`^uxUa|*9h}D6Q{9%}1iKjhMuD~Bw zFP;MJkXNo_-zzfjp+6GVV(e}+><~gf`$d{nwLfAb7E%5vJj3_P|O?;lGbkuHbo1Dd2)3MDmP(MF*McH?5@MfU4=n+Er7DOs- z+^z_7(bt^&a$-dm@TB(Q7m6oe+zBN48leHXd<8{M=Nx+d;{#m7&_0^=HdQwA@Om^iSx6L_=#7-l+?;yXaIt?W z&|rIirzo1N=TPHJ(c&7?*;Ds_y?tdvT-y?5;~E?Sgy8P(Zo%DM8+Q-xF2UX1-Q67m zG;RqY1eegbOuzf?oB0QGzVz2Vd)KL5Yt`DTSZNE_R9$8)bDpaKg*jB&%B?$vY%a#K z%uYLvldh-Oy>Htu7x615pl)#rTWWyE2pl*=AR8HyUmCo8x2?}lTqw(T(>8yqmA8|F z&AWB_o*LRnE!MK$W=$gaZAx+M&_-zo;BO$J}r_#hqf<<3A080dcHW( zV?%+@sIxfd^F}4yu~|p5OJ+h-oFA9mur=$RVh~p@cC9_vljoLcrS-j-Av4nHX<{{P z$PysaK)dUG;Qkc#ZEhhzGCO8>Rk2XV?+__2Ymg37M{n<9mPdca-*%*TqH_MnBRIy@ zvDMH7%;Hr1eB+P9=n?s`UM{=K8!Uf~E_wzpe+VhRHU2r_xQDB|F zz|l&VW>>X==Z51}&{n+cl4PD%2l-0nHedVk zyJen}^9(EQyOARPw}X_Ix6_|ZzU>CIb0Gi&YqZKDWGV-;V6$vLTzuQ6hE3bHQtPSy z$Fws>nDnSz^MX-ljXN&+!|3uQs5*RtM_o<^nUtMcR_B5R(=5okUACf{z~Ozf zB?&w{S1pU5_Wdh<dBOwGoP zTG8sLQT#Q5$xK#f$)F+TDI|FC!F;1;HNj6WGmMoqyZNr&Fw5)aZCj&Or7^)7J%RB~ zN{ku$?{m_+9{e0rzXcDq61Pq|l&)SbVs=JTkIl2FSS3fm#Q>KI6L>aj< z2&D4#fKU*brgfKOgoIoE~O>SN_XIM zT5y?-g(aP}%7-1Zag?|goAZ~miK#A&O^gwKFTue(c4(|rGf`S8Cq5Zw;aK;y9;fd` zvf=R2D9b$I$XNh85o;^$CYu*23ux(q1_}?YDrKy_gr)rkR@WUAoaapzxH+qjw-~mc zoigEQMMZP-lBCdtuNkPn(Ni)qYm{juXakiEGsX>Mn5EFlyAgzw*9Y_7BM>e(ko=w+h$YbPv)W?|3_bqU&^rKU3^ zsN>cO5NUnbYX5HV2Lac#Oj_8Q$B?7Yo30Gh&Rs`0s+$Sbk`#hRU7bEfNYB#(OJwT} z(9@3Pq@aN2!Ck#X}~mA{_}ytII%hl z5!ZN&O>8M@2N>?{4p$qJLZeK!9M(u_!RzY={0h*ak~(IQc!tWi47gu8;ez(v{LW8{ z>TN{N(tEGv|1N7ZKxkfT%>@0)whF&&v0vI`wP4(UMzri}7>;mTvq-4C_aL%$XoYoI zVa1B*AI_Y5wyiblWK6S0v}SSsLhdpYqelIw^?e>wA|eA8INaZ_cB4S}mK;?vuDl`z z0+8dSJJ3FsPt9Q{S#R&hrFxue)xlsmJ+_I!1?vSh3o$ipLfc^H$`A(JfcY&FL#2{+ zEE(Q+#2*yY;!gAD|NE+oYzY5$ZuOlSRb~gVLsh9`t?#Ha)WeCB%H%r-ct(iE1S2hf z4Fw|1uyLq`#|fTmZ^ zybkPrDhNALX>(Ue>mo{(s^rL987*G55>C$vP7FWKIh{)O`qnFoga*EnuILXgy5=!i zo}znneEyaKjRQd5XAR=hVuxGVzx;Kqui5%etha!4&W9pci2k2wHa$H#dD=}*b>DV$ zf}*_INZR3z&d7fvU;Y3mHfYo_grRT{1v;ja!GU30@*GWhMlYnx;kzbo&E=5W(!Og0 z4p9&ww4@H>E&pbm;m<1B@XyYuPriiX^KNdt7DM4ljmFFbQU`Ar!d_CVTPxarRVKiN zAD%6p6X|HDwCPH7lj~Ld`5WIIw8^yg2bI{{d16`^Q({Q6D1S2Tojh%do?M2H!j1y5 zQM+CPtrC6I_S*5$FR08n&wDW7;3JH7v1D9P`b{yjSQ)k2Oqk=gqRa;WNp1CrR<~Yx z+2S+pGxy`F7qWhVMNSQcbI;If{S><9vvbl~L zs&-yUjE^E{h=AAMHLmwFW^|I<&2i>xVNj>)LGzM%PJi?#EDX^h1u2*myB>}jC^;T2 z_8y)bf+|K};b`oh>wG|mbkg=DOewb%wkl6dJ9VvC*iGiEn;RmyUs*^NnI*lh6|pUG zZS&2i{p~RO4OJmcYwQqpZ|EMEPV)~kniorfF^YkFTl#siA1ZeX-COS$G%kcs{>W2k zCEBXKZ*2;@z~6GN&)H{~CIlJlwH+T&7vgFO)RoQy8n*i$-J}(mFb$Hs9i%qr^t3-d zefUql4gkOgbohuCMk@HtT}T6-3hpXX%@|7B%1?w6k_J+%tUdY)ow z6d6XtYvw_-Tyz}*vCJ%|xLELszxMnlDcGL3I{C(e)iv+dhG~)NceftgXb1)u+X;$- zr+1%Bo;RB=LLPlC`46C?enH-M*k9sRte6|-@U`@%8U?8}eW)xA-cCk< zn!W;R}5@=2c%c9`U%A~+@$ryrfWDD6suzK-2ikf{FWd?qPu-O7b8 z)z<)W_H(D?vMBtV{;b($In77GYTBb~-l9vE1a2ZjBHrsl|BM|XK#B%c93!Z>i_V>s z`8X=2c|xcuWn~T3W9QbMMkD9{r1{?Wn#D)@z&WLWw&rf@d>f1t65MdOetGE5jcYgY z=vmETt6r(mRkB^K&#|aRm&J6dl9OC?R}=j{O^z|;m_GR&{vngNmY`GVjTBmOYP^8l zkqAx~ZVKu)o!bGuSgB)rg67Vbe;|*+UQN>&{S%z{%!yW8@vz2bwO15OLc!;QUk~fE zL|YE|GSze%=83kJF`JZVZCiB_WZQAE^d944+S)w!hK7a@Z?fNaJX^NT+nwlP=?Nf; zMXN7ZATG)_VovM6n_1BZzxvU@F%=b_T3(@F`dUDYRMwshbV;vUqjj!bxH?aySs$GDsF_781Ux4`Yxg!6C%@=L++Wzv_21 z6~cvl`G^9n!kPQp5}rl=E=KaQifrZ%xOt1g=p~1Bo8(U$Uzam$)TnGV)2Y;sYc<<2 zD;$kS3I&PnXXgR5i^i^$tc}`bB}4-OeWZP(XyB!P(8r zt`*s+Yc7fw#XJC@>wHn}(?CgevqeGs2EAARQf+Fu3Rabc2e#$YXhK&npl>1$raMz0u8gTB$qFl=K}00{thkuigK(Td$wbFK_in$sfi6p~OENTKCn` zPF*&WhLA}rY<=dovbr1Lv-*?Tv=3JfirTvDPs|L0`*8OmG#klQUI;RnbPb`*(N%6B zd%is2(EmiQ6=yS9oRkR)DO~Ts=>uYB2}eFvW>Vo~5;xsnkD5yFpV;7w+TEC;7`HA; zB2AX~$QCez z+#*z2YyuLy(!rh0QIw~L$H*!O6n?2c3dC-ovrU;e*H*Qqvh7aP+v;!kZP$CD519-T z!&N2`mXr)l{{kdpLciKCLGZpB`b;z?glgLew(X+yO~gNWs;$Ln0a^ju#dlmYG^fp~ z+K&W$27eSC4(7>4*Z<}JbcOBEHm$|~o*}N=D2RqX~6P6h{Q1Bf+SgGE#$LF!}^?rf7 zN+Bj(+8`$K;Yy!m|KSG`T7*9fW&699gvptw{x3%2xT_<$_7f_{@NqYsbUi_Q$?j>J z`_ci7p8r;B!{~6q8RsXrB<$aUfK_s3T4iM#P0D3YA<>us)Nj{+en|Xjm7vTS{6?Q{ zI*0}1*msAfbSX40rbCWMFKuf?DG*ulv7XANM}vl4hhH;;-58-c5+-KiI||^Q4_f|J zAOmDzO$CL6A-Jvctw9b7F5^@G&EpAX)@nx)L0+n$haN4Ql7-Y2CGE4`hT~BwA%ljq z;9L~)+YC*f8>;53X5vGhS0O6H}Yl~TB#Ez9g#&Ry*|X5*mdI*Y@PEdDHoU_2E}L!!2%FQuxx~Wo;&phAKS;i zHUgp*%ghkxX)PN`wqt>`HbUFz0fT7Ph9I>f7>qSav#!wwSQtmk4(^SqG*w$M9j5%5 zYDu7%{mF7~E;fCZI%qG_ep<_S)qS->x-B+7H5(H=v0%iYMs1BdReyfkM!wBmR^!de z((FLhGRCNuXRn&)+BO&r?GZn_y;OEsuXO4{CMvhDpz|k4Dgm+xTMt)x=$M#8Wxd)^ ziW}=q2Y5AqIT(w5e65OQws zZyG#zHr{?{l$eB)QtI0EF1nF^6_?Zh`~~7hR~lmGTIyLi_n0rtbep_kt0Q+^d!JP` zUj){mG5$;4W43DhDw{V>$BdJJN$=ig(n?=~Q;DR0^Ie-6Rcp$Ff1S8A?PXrZ5M(09 z)Lpg_Xb1;azt>u&aPGIGh@6B0FKM7_Brd%5Bj^3kr_R4`hG*e@o5$m{13`yogPmLZ zFE2!~WGij$K#rQ!Pv%_CRUTqFw$PIYx2%c>?f(z1kfFGD)GW_Ay1k)K${WN!ld)>( zBYX)>@wKT-)#n~RK)7$>6On3^Ug1Zgpdw;MzdqaLc-e*Az`ohQ%gBgCT-v|TZB6?X zQ-P>j%~$!eW(Ddfy-~8Rf>ynJ@GK1GZq&?DYhE0uatNXR7WNKIrRn@Ns_3q1gAjC# z*cfJ2gsS5ydh*R*AmDGW4U${ZJa6gTVp?O!ljMi|CyR#Z%1S1LDjo^`p1r@r1`&EU zAjQ&Oak(uZC($!*6?P3+vEa(MVDh_>piIPjr=4-0_wPK;Py4W6t^u{Mb3eU8p@<+9 zJ3!3&=8VAe0F4cvfgjIdN|SsInO%Cs%FXU4YEIfMmcz>M#NmB?qfoIfd^B?p;>J>?N{m=k>D zIw-RktntAq-WkSvBf62(@TVo>lpF%7}by$sy-;2-RAtFwWzAq!NvhA zCk;b;@6c~s7GhPbrYYSrWpFA~@+2Ix%E)MB{G&VxsjVucatCCiAB{XJ;0%Ti-WM;b zYtSeg+|jf{BM%*$38>l;TJ;reZS!cF3zq3Pnt0#24ow_b zRWJS*<^6~>j*Y-r)21=CVi4@~B8fym=nQ!6reP_=+er^GtV?=G$6<1EbNQh|R93K{?(?b2MkCva zIe5cACmr|!g(USPUM&$STN9kz;OL<>_gi}D`FpKWiQ;-G(Jl7caSGn87MaZAm`BBT zq<)7llktM83KT8cZmES4kl}3zBL-F8$ScUvp;++9I$=;Kuwkk$Z@*yg9e2jhy+p=; zyF=1fWH5XU+LYSbDjPc@v>buFS+0nGT*s~-jBlxqB=n;sh&pkPj}78nOvSyw(gMB? zeLuOKdfj>jul<`l6G_v0dtSEZ7RXQs6lRf&m$ZUYt?U;FOb4~f+rP$+1cAQB_JvXy zbi3lJC&Sybq(|B>abHLa20UPVBUr09l0t-{qlqF}Na=XDtGXtww-c7v!NV?Wb2aBS zVs|@`syi8PBCF2bs&ZBX@a4_#e|LyR<-tdD|=MBdbOc;8y7_wWo;} zwjde!z7Gy*^$cmXf+C)_HmW=OoW}I#qA<&9;`7unqcQ175izg}PmvZbg#THGk;F?= zk6!VWAUGz`pFe_sk_{m$2}Plz24l)z-F<2}xIH#MLyyye{@_7g;~^*8;?bJptBPrs zjIK7l6g9@bJQw**NxO~Bmwm@=**$sFnD3VMh1 zbO?{Vu<_+}H!GgPWgCg?zs|xHwpP=yvA)dbRyHUpz@|OPZI3&@gt@jpQrh7~a;V90z=L z<~+SxBlrPm6V#6RuHNwZE(ow7{sB%-d3Q{@<({Y2T6er1#KiZz`o=K0y;);?5GuBD zkeH=$1z-=CbHE|k^NfKm+!-&>;dpSJ7rCDAI2g^UGRn?8Lb#mA<*uJi}t_ZN~BjU zyFGHjaDa{RK0r}Ss~7%;l1ej0od!p}w9YiXWnt_hV?)bew6tIsSR zm4c9^>u>BgHx^q}GkDjV@h1e%&R`Lf;=i{NuiA0gsCZ-wwQY$EH2sBhI!*msZ00=} z)XHX1S3cr6B@VSba`FAndoYCD8YgbTE_XXHBocxsATamm+ZV5^U%L|aO0%U*)}p0Q z!Nq~h5%j)3O<7}V?6Zx>mbc_a(*)XR_t&=dV ztT4kEXmJ%s$``M{k5it#o*C+EPH9Tk3qtDa3)n`uFK*8^O7?a|x}Po&Ygx3Dx~-+C z*uK}&uCA4&GGQcP-WF$jlB$dgtejIv@L$O_fW*M48%D6+nI{PlM z9q?}G_Y`X^zDpTJAEK=$Gw&GovL!>!%F?7GeO8W15_l>h*!>J(>3_m<^!o{q#!Mng zP8JyDRw=Mrno-P$>VNs<flB#v1B}mv>3}nB$FnPB7I@f z86Tc_-jS4uMFznoLP-|BZw!@ZTXM0lJ}h3r?MfddtvBnH-{+ss9#BPj>>w1DtS6Ma zhsUdZUt{#uRKfF2gHiw6)SeRkml3mqmi4L>K%ogWgS?}NQ}iIt*>7aP1YEl=EBz0K zz?%%04 z!!fGVl$sU{jx85DQK4IPa*`(D^<)p#D=_fiH^~j8d^MR+a zh8J{x#y7^uveMdFGVxv~MTncgRN!Py111athdJq}X>`gQUT-4pkk-O+D#LTQ_+ z7-$JBmV;%t9j2{>t@(h^oufE;UlbxH=-r2>wX4-nd!ub7RPb2VgsSsT8e^CEM@SpV zdUNLy81ztCe=p8>oci7p-=`h@cbDP+EfQbfD(vI5`>*~Ecs`ED2GZE^?l)Sfh+=Uq z!&l)~sd=JMIsMj-0_+1~FqIe9yf4Btu22RZ4Oq`q+Bu z{ys1gm5vIJo>rJ5>b(I~CH}g8Q3OF>@T#MlRD6splNeCYO{>BH5$t z(BcoR{>Lwp%2u0S+tRS*liQ2yegWFj=v56B*xfz1tc1J`Jd3GZYIY4PtVw;@Z-UE_ zCb5~B?i)#ho%-%Pw!c0z8R)?_Dw)g?4=3r78$6w@NPL#08Z_~WucgnXA%?yX?0>yz z*n8gBZ@Aai`L~a-c4=H4LUZr*zL!zI`>+>&Wfd)%nmP6{0-m-5Nnh4K{gqZ=Z<$&l ztmX@X_tQS}?h9mB4n?kMhDM-s=z@I!yu9+9Tdx^ka8nR9l0iD7fK+xAwJ6}PI+LEA zpD!E8%9lb=aN;`5tY<82XH1Pc%$Vk|ZlXG{qo$3TbckeVqySl1(lJ)p5j9JwCXaTT zE}@z66PziT<*?M|Iz5mr*9|XOJO!oVq->Ec8J`4=%X-i1O4*YwS8AYyMR{VU_zxJk zf_1oxFAslpc6a9=zV)e%mFr(!g=mMRCh&ukpygsTXD79iLum|<5MfQS8%f99v=a(@ znED?<4L?KmFZWM=5W{OJY)#1r>`VYT9JoO(11NB=3$z-@D5|h(ai=Zs*Bc{SPGCs3 z*Dm-^ujy62-_rNm?R~q!$md7e9v<=+L>Ma`^b;?Y(rvv9|2{3pQOO^rp;4uS$H3t^ zZKJV;_iGU-!n-B{4$*dCUh<9vk|hUSzwL+qZVe1}B6p+pZ2RahWNyZ|!if%2Y)A_wMbF*Q5fr!u(S5#7(k2-r)BZO-u4`Rx;8?KJRhnth7CJ$b}zu~a~(a`J2apI zbC>Sx{d9}OU4!em-I*|EX2UR=N-vU%tR^Ryp*^I;g+cqg*{I=_)PMmKQb9$4VnjNu z_d)?3;`%BTEsC^{8m4f5FIgzLuYkx$N(q4rLwkXRaCp6gA$a)KgIJicCV>f@q^_`` zLwd}6XZdl1i^xuePY+087_*rKf0wD#g6-L5%JfEQuPe`;cL}tY3l!QIF1A=zFlfyR z^>Aiwy*$F=1_wpM;E?Wg+3J*BPUm>8?oJ0HUHn5v;6kaOgkMY56vU0|Mf|~#nE)LJdcKEtyw%?pZ`aog|I>NB{xhaM@DTo~;N|5#J7~epV6xORLuq$L znu@wI+$kEFi^m>kYm^an634lH!|Z*U%kMGqm7LkIFM1gaUkDhDk{x}v>1r0Aft3yS zb5*Z|N|-6e)4~NOYq^^Eg?r;gU=s-)-fN|a$<+<6PN5zKvSXhdE1_eHws^JJg!bDp zEP~HX`gjhq9@PvA{U4t*5|@#K&&BXEdli3lnzR7-0#JtK7KQ0RN5iXmRA+;*jG3a8 zCTh;}ya6{D_fCOv%N2>N^;*0JsQ5ZX$pB-I&GW*|I=ve9`Um75(_1BOPrE8zPUTs? z*PWirzPpCcBHdow#)^i9{=<;t3T(dQ>2Y^^wR8wFd*3&1^F$N~Ok~5e?o|%mq>Sp_ z8Hn4fz2%b7WJSfS`Rlel;Pp`g)%)$YN7&$cynq5-)&`1$xOTz`oAL4Y+QAI_>2lmz zN2;dqdjj6o<6KL|E~S$YhZ@l z;T~=j3MLQIxAmFP>CZZ`xa*g?SZYcM^;i^&w4}*^>Gt6;e12pk6zKHeM#`YSQRf?M z#C|VOyS{%twqO4ULFzzEt{={rm@;RtAn$U8_{3?;WUn7CMY|uX*XIZ&!;-uS9)7eu zle`KfUiw`b1yVsW!+%g0*gREcoYQdtybaE2z;oe4(6`MSEx>Gs$-mjh`;i5H%h3`HzUFh zgZA#m;9@Pu<+vo&q1~Y^pd}hjOr~PQIL1MA^ZCNVQzOq1%8tqJVOO6wz@3EOvC(4K z$V8Hzn^y7#t)5_skvnf0+QyRQS&C|5t&FJ z&0<(PuD|?ZuE5bTPd)B%9QZpouztDvKZOa5iUH#>h~*6>(A4K~d=DqVcl4XveC0>& z+1(*(Cb}4If4YOFT#oYGS#P#bi69J94y8%N&bwintK)??B1pbNLzYKmORiiP?o`@Y z5tz^zqw$m0Uu1`($7Z5u(CBs!1?Fgi`#Ho=U4XsQbJ?G;xJz`X4b*)9OxnPnpZ;p5 zXToMTwyH)9Nx>}6AtmEcF+-2K>w!poRutmaMIt)i*%%~m zMlp{scY46TjlEspOP*hGm;a@lNRsZ*n8%dgIgB6CBS#qCrPM;y;?$I~GD%x{xLc`r z^~6;92TO0WL9k_tTkMGDc$CPUeqjFk-4|HL{s*iCX2YuJz?Y+4Y0aL)_f@1<-RkEhoLzJ}W=#dg{$%RY7_l*U~c4 zNX+P1RryhqR6V5h`|SE7Vb2`lDVU%=2Y0oGt9|POry_nPh6Df+s4??ZdxvOs5wN+L zBF_|yiT0bvx0+o-r;9_=z~HZ~?o@I~6+3=5v??n9Yv?mc!07@6hYWprO2sh;B|L)T{t|uekl^h7h@1fV zaX&;JHbeReHPU#S!&zVGcHLScqYsX@80d4Q55-1648va^I!TBp55d%kEhv@qGy(FM zYu&4=ry|QJ$=F14QvDJ%-F9f)iC=f%o?J%D#&XSW%;A=?39%UCO$efm80?P$X(?k7 zHeiz*1)X{UsSHmTj!_m|EDOIX6PtuV)2S=hmrYpSXq8*jn+bVUM~soz7a_sJ^2@5k zFfQ-)zYlf1Egd|Q+;KtlzyGLC0{KT)h0~e!g*YxtVzLE|n>7T*Z zz|v&faD-NTtWnI2J-*qJcu%6g0KFVM9$^}jAOLv+$xDYNLM0yYM3d5*#n{{ew zrnGJkR9+;EBL(o$#2rMXN?%rBD@=Wz+28jpp|Yl6f^~J*=(<;9{24@skvn-@GijfQ zaJGPM+mVAM7;a}wGV)ky)bo9HR!=^HAy{lQ-^%Q=Jai9ga}B4`pMizJOnzUj@0Fo^ zL7^0R<0(`3W@HXR<#}KI*b21s4`2sti~mn(Lf2{Yye;xfGS(*_D8(!792U~)*>XJA z9jj-;P`0K(`jhK3tc7t=GDRY3OS1toMpT`)?98!nRJ=i9X2)0jrRrMI^9Lj5-gy2! zwQU{tXQ%;M*q=yp^$3q-u+J-8;nlnQX3l}$WitJq&g zjRfsGoT~8@NU0}mzNurXgksy5dT{hxn9>s;xP zDJThQ2?1&$~CCu~~XU{&R8?0nxdhR!I6rX8f!WelH8Od)x-Uv!m2g znUWi;f^DK&HZ>)3<@W+YktsIRzWL$^icmvq*_TJ2vfnsn9A=Uiqg}v zov*0|T`g;B435U<3fg9Lp)?lbcNlU4h0V_5NR-i=SO)3Sx7@bl_S5m9tXv!*U&Is| zI6ka6F4NPb4emZ_38vO*S?vYCa;ikzW;y4z7uD&?t7Y^mD+{@+JQRQ(6IBFGYO}+~ zp4adv3v+ij@`Ru55}gL_JLdC+^uPn)|K%SXTb+yVG{Ucs#(nO8#|H9K1H|a$5K#c5 zCtt3~%|JDWNuSGr!vV4`WWuWS>Q$mes}4ayj0Di~<#;eU_k|~R;y1S?fkf3cVi7Xz zBRmv^)r29@0E>dJRbQ7tu{`);26FB@3c9BQG-9!KX4#q<)&z(~g-nBDf03&qsxuqJ z?J*p%#i~Eh@t1Ht99=1!z%MIW+f@7o>U)}ntyZTr-^?aV-TX92;{BM)1o5iju2^`> zIq)TU?N}h*?PKaHDevxH)P?l%3`OdabDi&QzegsQ?{)bdp2)l4_fzt5aK!3B4{_&y z?Ct~NOb;V7)vOHfudK#P-#WZHuGn(RB@$%VB7r zkpn*Ih^cP9+VM3;eyrThQ|0nrjA*I$@)gwI_zFezF@bKbKfqxWs$N~jwtTL_{jV{1 z)32w_?2Qs`x?6hm(AA71ak%8PLOEn=T=Fd8-8`Y^hJsz6cNUSCtGqpakpRD9;!#Ls z{UbkQeo+X+yfcPWu5aMO!_#*gtfx2tbb<<;l`(qy8%t}#s@z?zRGpc>6}a9G-g1E> zfkyI^g+Dic%in;|@@3R-;c^%r*jat$62Xkn$kG7P@2hjC*y5^9vYE@stmb8Eeb3@K z7h+;Xq!p#bFj4Chz@^nrNBpu{0hC+A98>J07Cchltm3qgeY1#}XEv^b$u?xkBq>Qs z3U;#OM!EJR_$v@-YWe*Q@=@&Z2i`qgbneK!f7J!~GnpA1CSxP`L5FJ@>CY|HqH1Z(K441N z>1PQrG&CgNf* z8beUZ%S26z6%8Nw%Ibe75^TRzCensTx8Sz-Bgj~|_vs~YIJPg)2TKe-j8;4~Gix>| zY=26zs%Jrsh(Y&-+aW!lGKAicHo9&~O~(*^n!lNvLSES*v?{}BZ%G`F)+C!+K+3!t zl7-+UXetPz_PPi}RzBz-RxY7J?`b8{dQgmlJsTAIr@cU~_rK-M^_%#YV&yO!V}^cZ z(XS$N`P;f93?6jgHd(%NAV5RuPc3gPKfSzf*D1g6p8Pt#%qJ1?Y22#4@p^Vz|5y0( z@$HX$yP@xKnz2al-S7Z9+CXyZx-CtJ4lX?YEJv)UhujLaiq@?jcPt#f?FRxM&)Ws? zs)A;c>2i03?y$YbdaW#*ABbp9McsDA>p72bKhH#6v`P}<>Cm!dC|~fT2ijA5u`9lD zREjZiz!t7iLTL~2IN+j@NTnkWCQS~Xs*%^=gT3RjkAN1>zLd%D=X02UdxP-wmkkR_ zyZQy63lg@#V`)eBKOx=b|29}jhHO4z{`j*QUvlKwe_Mgxu=^4_bNHiy>f1~@23X1% z@eYA$xoz8ViGHueZ-ws|3(bZ`V^@ICHQKMVY)l51Gd(9|pA^hUkUhq~7Dbj#mW;^@ zK;$~C#?>Bc&v%EZFf(~@l?EnCWFvVjiD%a7L?b3Ue4W_7xcv>+ZP2KlTt?c=I4`S! zjAri@oFBhlU7F}lIM8ia@G4T%V)bs(Bkb?gAsoo>sAc|i=V8TT^KbI>@IQ))cXoc9 zzIj3^csW8Z=(#%@F?(MKdgLHLg%HD-`cmvNLm+2E-s%pR*ARR1wlLr|iHAEJZhop~D&56cn%?ZF7wk0ISE6- z8E*B0YI6;hCqOQf&Udye%Eb%=~r7nLr9s9nXzMO63 zoquhUTjn;V-FQuK+S)1om+b(7-|c?FJ4daH^tN^cK6YuNF&n=g%!JAhU`0O22jdl} z|DHKBNEIax(Z#k|Wc&4}#f}aC(F5n@xz(2KIJxORLL2Tb^qnGpX^xOACJ6`WIE1-Ww-5j(k%mHaQ0fSupncC0^W)9sEM^)hTgz6399I1I8*6mkY#M)J;h+E(CQTg9pawQS9>K(voV&Z0`9aS4Nw!>E+kFNAB4b*Y=z7M>gAae zpm$~n-}2vOS{4d^PUtX$cLPL%3 zTwR<@b;L-|XEjw!R}=LMJdRc7+u8^5~z=T-l?1h=N#R`pD_s}MMO n=^P_W0J(4Q|L=K{J$Z+rbzbCzmy1CGKpt5sCCPemlaT)d1Pn@? literal 54467 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 z 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 Z{{a?Pi&XB?tET_}002ovPDHLkV1kRqqP_qC delta 3162 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 Ai2wiq diff --git a/scratch-link-win/scratch-link.ico b/scratch-link-win/scratch-link.ico index 5d9a2704b93c6caffe3e92ee28ff2f5cd088946f..126b93e911abcbcebdaa35ff5ee5192f1a213bb1 100644 GIT binary patch literal 67384 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 O00f?{elF{r5}E*0jCVZ% literal 73875 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 Date: Sun, 24 May 2026 16:34:11 +0900 Subject: [PATCH 10/94] chore: upgrade to .NET 8 and WindowsAppSDK 1.5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TargetFramework net6.0 → net8.0-windows10.0.22621.0 - RuntimeIdentifiers win10-* → win-* (.NET 8 RID 정책 변경) - WindowsAppSDK 1.3.230331000 → 1.5.240311000 - SDK.BuildTools 10.0.22621.756 → 10.0.22621.3233 - System.IO.Ports 6.0.0 → 8.0.0, System.Management 6.0.2 → 8.0.0 - PublishProfiles win10-* → win-* 파일 이름 및 RID 일치 - wapproj AssetTargetFallback net6 → net8, publish profile 경로 수정 Win App Runtime 1.3 별도 설치 불필요 (1.5+ 이미 Windows에 탑재) .NET 6 SDK EOL 별도 설치 불필요 (SDK 10.x에서 net8.0 직접 빌드) Co-Authored-By: Claude Sonnet 4.6 --- SharedProps/WindowsSDK.props | 4 ++-- scratch-link-win-msix/scratch-link-win-msix.wapproj | 4 ++-- .../{win10-arm64.pubxml => win-arm64.pubxml} | 4 ++-- .../PublishProfiles/{win10-x64.pubxml => win-x64.pubxml} | 4 ++-- .../PublishProfiles/{win10-x86.pubxml => win-x86.pubxml} | 4 ++-- scratch-link-win/scratch-link-win.csproj | 8 ++++---- 6 files changed, 14 insertions(+), 14 deletions(-) rename scratch-link-win/Properties/PublishProfiles/{win10-arm64.pubxml => win-arm64.pubxml} (86%) rename scratch-link-win/Properties/PublishProfiles/{win10-x64.pubxml => win-x64.pubxml} (86%) rename scratch-link-win/Properties/PublishProfiles/{win10-x86.pubxml => win-x86.pubxml} (86%) diff --git a/SharedProps/WindowsSDK.props b/SharedProps/WindowsSDK.props index 695044af..86b662af 100644 --- a/SharedProps/WindowsSDK.props +++ b/SharedProps/WindowsSDK.props @@ -2,11 +2,11 @@ - + build - + build diff --git a/scratch-link-win-msix/scratch-link-win-msix.wapproj b/scratch-link-win-msix/scratch-link-win-msix.wapproj index 3f5c7b37..1cea3e77 100644 --- a/scratch-link-win-msix/scratch-link-win-msix.wapproj +++ b/scratch-link-win-msix/scratch-link-win-msix.wapproj @@ -45,7 +45,7 @@ 265ca433-8639-4e8d-a7f3-09b1b3495d92 10.0.22621.0 10.0.17763.0 - net6.0-windows$(TargetPlatformVersion);$(AssetTargetFallback) + net8.0-windows$(TargetPlatformVersion);$(AssetTargetFallback) en-US false ..\scratch-link-win\scratch-link-win.csproj @@ -98,7 +98,7 @@ True - Properties\PublishProfiles\win10-$(Platform).pubxml + Properties\PublishProfiles\win-$(Platform).pubxml diff --git a/scratch-link-win/Properties/PublishProfiles/win10-arm64.pubxml b/scratch-link-win/Properties/PublishProfiles/win-arm64.pubxml similarity index 86% rename from scratch-link-win/Properties/PublishProfiles/win10-arm64.pubxml rename to scratch-link-win/Properties/PublishProfiles/win-arm64.pubxml index 9855be36..0f38a644 100644 --- a/scratch-link-win/Properties/PublishProfiles/win10-arm64.pubxml +++ b/scratch-link-win/Properties/PublishProfiles/win-arm64.pubxml @@ -1,4 +1,4 @@ - + @@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. FileSystem ARM64 - win10-arm64 + win-arm64 bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ false diff --git a/scratch-link-win/Properties/PublishProfiles/win10-x64.pubxml b/scratch-link-win/Properties/PublishProfiles/win-x64.pubxml similarity index 86% rename from scratch-link-win/Properties/PublishProfiles/win10-x64.pubxml rename to scratch-link-win/Properties/PublishProfiles/win-x64.pubxml index 6d97548c..ac14247a 100644 --- a/scratch-link-win/Properties/PublishProfiles/win10-x64.pubxml +++ b/scratch-link-win/Properties/PublishProfiles/win-x64.pubxml @@ -1,4 +1,4 @@ - + @@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. FileSystem x64 - win10-x64 + win-x64 bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ false diff --git a/scratch-link-win/Properties/PublishProfiles/win10-x86.pubxml b/scratch-link-win/Properties/PublishProfiles/win-x86.pubxml similarity index 86% rename from scratch-link-win/Properties/PublishProfiles/win10-x86.pubxml rename to scratch-link-win/Properties/PublishProfiles/win-x86.pubxml index a6c966a4..3322027e 100644 --- a/scratch-link-win/Properties/PublishProfiles/win10-x86.pubxml +++ b/scratch-link-win/Properties/PublishProfiles/win-x86.pubxml @@ -1,4 +1,4 @@ - + @@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. FileSystem x86 - win10-x86 + win-x86 bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ false diff --git a/scratch-link-win/scratch-link-win.csproj b/scratch-link-win/scratch-link-win.csproj index 5eab41be..f0b0bf4f 100644 --- a/scratch-link-win/scratch-link-win.csproj +++ b/scratch-link-win/scratch-link-win.csproj @@ -1,8 +1,8 @@ WinExe - net6.0-windows10.0.22621.0 - win10-x86;win10-x64;win10-arm64 + net8.0-windows10.0.22621.0 + win-x86;win-x64;win-arm64 10.0.17763.0 ScratchLink.Win Alux Scratch Link @@ -41,7 +41,7 @@ - - + + From c8cce21cd1b4b0cf8b17c6f1749fdacf797b6401 Mon Sep 17 00:00:00 2001 From: hksong Date: Sun, 24 May 2026 16:42:59 +0900 Subject: [PATCH 11/94] fix: add Windows 10 compatibility GUID to app.manifest WinUI 3 requires both Windows 8 and Windows 10 supportedOS GUIDs. Without the Win 10 GUID, the OS may run the app in Win 8 compat mode, causing incorrect DPI/input/WinRT behavior on Windows 10 1809+ targets. Co-Authored-By: Claude Sonnet 4.6 --- scratch-link-win/app.manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/scratch-link-win/app.manifest b/scratch-link-win/app.manifest index 285545f7..dc82b519 100644 --- a/scratch-link-win/app.manifest +++ b/scratch-link-win/app.manifest @@ -8,6 +8,7 @@ For more info see https://docs.microsoft.com/windows/win32/sysinfo/targeting-your-application-at-windows-8-1 It is also necessary to support features in unpackaged applications, for example the custom titlebar implementation.--> + From b13f1c0fa8eaf85b6513b41d17907d514be36150 Mon Sep 17 00:00:00 2001 From: hksong Date: Sun, 24 May 2026 16:43:35 +0900 Subject: [PATCH 12/94] docs: remove WindowsDevSetup-VS2026.md from repo Moved to external documents directory. No longer tracked in the repo. Co-Authored-By: Claude Sonnet 4.6 --- Documentation/WindowsDevSetup-VS2026.md | 139 ------------------------ 1 file changed, 139 deletions(-) delete mode 100644 Documentation/WindowsDevSetup-VS2026.md diff --git a/Documentation/WindowsDevSetup-VS2026.md b/Documentation/WindowsDevSetup-VS2026.md deleted file mode 100644 index 75f95de1..00000000 --- a/Documentation/WindowsDevSetup-VS2026.md +++ /dev/null @@ -1,139 +0,0 @@ -# Windows 개발 환경 세팅 (Visual Studio 2026) - -이 문서는 **Visual Studio 2026** 으로 Scratch Link 윈도우 버전을 빌드/디버깅하기 위한 환경 세팅 절차를 정리한 것이다. Visual Studio 2022 와는 워크로드 이름과 일부 컴포넌트 구성이 달라서 별도 가이드가 필요하다. - -## 0. 사전 정보 - -- 솔루션 파일 `scratch-link.sln` 은 VS 2022 (v17) 포맷이지만 VS 2026 에서 그대로 열 수 있다. **버전 변환 프롬프트가 떠도 변환하지 말 것** (sln 포맷이 바뀌어 PR 이 지저분해진다). -- 윈도우 버전 프로젝트: - - `scratch-link-win` — WinUI 3 기반 본체 EXE - - `scratch-link-win-msix` — `.wapproj` (Desktop Bridge) 형식의 MSIX 패키징 프로젝트 - - `scratch-link-common` — 공유 C# 코드 (`.shproj`) -- 맥용 `scratch-link-mac` 은 솔루션을 열면 "Unsupported" 로 표시되는데 **정상이다**. 윈도우 VS 에서는 어차피 빌드하지 않으므로 무시한다 (솔루션에서 제거하지 말 것 — `.sln` 이 수정되어 git diff 에 잡힌다). - -## 1. Visual Studio Installer 워크로드 - -VS Installer 를 열고 **수정(Modify)** 으로 다음 워크로드를 체크한다. - -### 워크로드 (Workloads 탭) - -- ☑ **.NET 데스크톱 개발** (.NET desktop development) -- ☑ **C++를 사용한 데스크톱 개발** (Desktop development with C++) -- ☑ **WinUI 애플리케이션 개발** (WinUI application development) - - VS 2022 의 "Windows 응용 프로그램 개발" 워크로드가 VS 2026 에서 이 이름으로 바뀌었다. - -### 각 워크로드의 선택 사항 - -워크로드를 체크한 뒤 우측 "설치 세부 정보" 패널에서 추가로 다음 항목을 켠다. - -**`.NET 데스크톱 개발` 의 선택 사항:** - -- ☑ **MSIX Packaging Tools** — `.wapproj` 빌드에 필수. VS 2026 에서는 개별 구성 요소 검색에 안 나오고 이 워크로드 안에 들어 있다. - -**`WinUI 애플리케이션 개발` 의 선택 사항:** - -- ☑ **Windows 11 SDK (10.0.22621.0)** — `scratch-link-win.csproj` 의 `TargetFramework=net6.0-windows10.0.22621.0` 가 요구하는 SDK. - -`유니버설 Windows 플랫폼 도구` 는 이 프로젝트에 필요 없다. - -## 2. .NET 6 SDK 별도 설치 - -VS 2026 인스톨러에는 **.NET 6 런타임만 포함되어 있고 SDK 는 빠져 있다** (.NET 6 은 2024-11 EOL). 프로젝트가 `net6.0-windows10.0.22621.0` 을 타겟팅하므로 SDK 를 따로 받아야 한다. - -1. 접속 -2. 표에서 **Windows 행 → 설치 관리자(Installer) 열 → `x64`** 클릭 - - `전체 (dotnet-install scripts)` 는 CI/스크립트용이므로 선택하지 말 것 - - `바이너리(Binaries)` 도 압축본이므로 일반 설치엔 부적합 -3. 다운받은 `dotnet-sdk-6.0.xxx-win-x64.exe` 실행 -4. 설치 후 **새 PowerShell** 을 열어 확인: - - ```powershell - dotnet --list-sdks - ``` - - `6.0.xxx [C:\Program Files\dotnet\sdk]` 가 보이면 OK. - -## 3. Windows App Runtime 1.3 설치 - -이 프로젝트는 `Microsoft.WindowsAppSDK 1.3.230331000` 을 framework-dependent 모드로 참조한다 (`SharedProps/WindowsSDK.props`, `scratch-link-win.csproj` 의 `false`). 따라서 **Windows App Runtime 1.3 이 시스템에 설치되어 있어야** 디버그 실행이 된다. - -설치 안 된 상태에서 F5 를 누르면 다음 다이얼로그가 뜬다: - -> This application requires the Windows App Runtime Version 1.3 (MSIX package version >= 3000.820.152.0). Do you want to install a compatible Windows App Runtime now? - -다이얼로그에서 **예(Y)** 를 누르면 Microsoft 사이트로 안내된다. 자동 안내가 실패할 경우 수동 설치: - -1. 접속 -2. **"Windows App SDK 1.3"** 섹션을 찾아 **`WindowsAppRuntimeInstall-x64.exe`** 다운로드 (ARM PC 라면 `-arm64.exe`) -3. 실행하여 설치 -4. 설치 확인: - - ```powershell - Get-AppxPackage -Name "Microsoft.WindowsAppRuntime.1.3*" - ``` - - `Microsoft.WindowsAppRuntime.1.3.x64` 가 보이면 OK. - -> 이 런타임은 최종 사용자 PC 에도 필요하지만, 배포용 `.msixbundle` 은 자동으로 프레임워크 설치를 트리거하므로 일반 사용자는 따로 깔 필요가 없다. 개발자만 수동 설치한다. - -## 4. 솔루션 열기 - -1. `scratch-link.sln` 더블클릭으로 VS 2026 에서 열기 -2. "Migration Report" 가 뜨면 **OK** 로 닫는다. `scratch-link-mac` 이 Unsupported 로 나오는 것은 정상. -3. 솔루션 탐색기에서 `scratch-link-mac` 은 회색으로 표시된다 — 그대로 둔다. - -## 5. 빌드/실행 설정 - -VS 상단 툴바에서: - -| 항목 | 값 | -|---|---| -| Solution Configurations | **`Debug_Win`** | -| Solution Platforms | **`x64`** (또는 본인 PC 에 맞는 플랫폼) | -| Startup Project | **`scratch-link-win`** ← 중요 | - -**시작 프로젝트는 `scratch-link-win` 이어야 한다.** `scratch-link-win-msix` 를 시작 프로젝트로 잡으면 F5 시 다음 에러가 난다: - -``` -MddBootstrapInitialize called in a process with package identity -0x80070032 지원되지 않는 요청입니다 -``` - -이유: csproj 가 `None` (언패키지 모드) 로 빌드되는데, wapproj 가 그 EXE 를 MSIX 로 배포하면 패키지 ID 를 갖게 되어 `MddBootstrap.Initialize()` 호출이 충돌한다. `README.md` 의 "Windows platforms and installer size" 섹션 참고. - -### 시작 프로젝트 설정 방법 - -솔루션 탐색기에서 **`scratch-link-win` 우클릭 → Set as Startup Project**. 프로젝트 이름이 굵게(bold) 변하면 적용된 것. - -## 6. 워크플로우 - -| 목적 | Startup Project | Configuration | 결과물 | -|---|---|---|---| -| **일상 개발/디버깅 (F5)** | `scratch-link-win` | `Debug_Win` / `x64` | 언패키지 EXE 직접 실행. 평소 작업은 이걸로. | -| **MSIX 패키지 동작 확인** | `scratch-link-win-msix` | `Release_Win` / `x64` | publish profile (`Properties/PublishProfiles/win10-x64.pubxml`) 이 `WindowsPackageType=Desktop` 으로 오버라이드하여 진짜 패키지 빌드. | -| **배포용 msixbundle 생성** | `scratch-link-win-msix` | `Release_Win`, 모든 플랫폼 | x86/x64/ARM64 번들 `.msixbundle` 생성. | - -## 7. MSIX 사이드로드 준비 (선택) - -MSIX Debug 빌드는 임시 자체 서명 인증서로 서명된다 (`scratch-link-win-msix.wapproj` 의 `GenerateTemporaryStoreCertificate=True`). 자체 서명 MSIX 를 신뢰하려면: - -- `설정 → 개인 정보 및 보안 → 개발자용` → **개발자 모드 켜기** (또는 최소한 "사이드로드 앱" 허용) - -## 8. 자주 막히는 곳 - -| 증상 | 원인 / 해결 | -|---|---| -| `NETSDK1045: The current .NET SDK does not support targeting .NET 6.0` | .NET 6 SDK 미설치. §2 참고. | -| `Microsoft.DesktopBridge.props was not found` | MSIX Packaging Tools 누락. §1 의 ".NET 데스크톱 개발" 선택 사항 확인. | -| `Windows 10 SDK version 10.0.22621.0 was not found` | Windows 11 SDK 22621 미설치. §1 의 "WinUI 애플리케이션 개발" 선택 사항 확인. | -| `scratch-link-win-msix` 가 보이지 않거나 회색 | 솔루션 Configuration 이 `*_Win` 이 아닌 `*_Mac` 으로 되어 있을 때 흔하다. | -| F5 시 `MddBootstrapInitialize ... 0x80070032` | 시작 프로젝트가 wapproj 로 설정됨. §5 참고. | -| F5 시 "This application requires the Windows App Runtime 1.3" | 런타임 미설치. §3 참고. | -| StyleCop 경고가 에러로 처리됨 | 원본 동작. `SharedProps/StyleCop.props` 참고. 거슬리면 임시로 `TreatWarningsAsErrors` 만 끄기. | - -## 9. 참고 문서 - -- [`README.md`](../README.md) 의 "Windows platforms and installer size" 섹션 — 패키지 형태와 배포 크기 트레이드오프 배경 설명 -- [`scratch-link-win/scratch-link-win.csproj`](../scratch-link-win/scratch-link-win.csproj) — 본체 프로젝트 설정 -- [`scratch-link-win-msix/scratch-link-win-msix.wapproj`](../scratch-link-win-msix/scratch-link-win-msix.wapproj) — MSIX 패키징 프로젝트 설정 -- [`SharedProps/WindowsSDK.props`](../SharedProps/WindowsSDK.props) — Windows App SDK 버전 핀 From fc9409f525cfe4de45c165a0ab9a58f2d7ee7a2b Mon Sep 17 00:00:00 2001 From: hksong Date: Sun, 24 May 2026 16:47:36 +0900 Subject: [PATCH 13/94] fix: self-contained Windows App Runtime for Debug_Win builds Debug_Win: WindowsAppSDKSelfContained=true so F5 works on a fresh dev machine without pre-installing Windows App Runtime 1.5. Release_Win (MSIX): publish profiles override to false so the MSIX declares a runtime dependency and end-user installers stay lean. Co-Authored-By: Claude Sonnet 4.6 --- scratch-link-win/scratch-link-win.csproj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scratch-link-win/scratch-link-win.csproj b/scratch-link-win/scratch-link-win.csproj index f0b0bf4f..0be282fa 100644 --- a/scratch-link-win/scratch-link-win.csproj +++ b/scratch-link-win/scratch-link-win.csproj @@ -11,7 +11,10 @@ disable true None - false + + + true + false enable app.manifest AnyCPU From af4504e27d166a9286a69b871cee8e805312d970 Mon Sep 17 00:00:00 2001 From: hksong Date: Sun, 24 May 2026 16:52:42 +0900 Subject: [PATCH 14/94] fix: make WindowsAppSDKSelfContained true by default Previous condition only matched 'Debug_Win' but VS default config is 'Debug', so fresh builds got SelfContained=false and showed the Windows App Runtime install dialog on every first run. Setting true unconditionally in csproj; all publish profiles already override to false for MSIX packaging so release builds are unaffected. Co-Authored-By: Claude Sonnet 4.6 --- scratch-link-win/scratch-link-win.csproj | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scratch-link-win/scratch-link-win.csproj b/scratch-link-win/scratch-link-win.csproj index 0be282fa..651fbef9 100644 --- a/scratch-link-win/scratch-link-win.csproj +++ b/scratch-link-win/scratch-link-win.csproj @@ -11,10 +11,9 @@ disable true None - - - true - false + + + true enable app.manifest AnyCPU From 5101e737bf968afa0cc766887e0f1df5b82925f3 Mon Sep 17 00:00:00 2001 From: hksong Date: Sun, 24 May 2026 16:54:08 +0900 Subject: [PATCH 15/94] chore: remove Mac configurations and project from solution Windows-only fork does not need Debug_Mac, Release_Mac, Release_DevID_Mac, Release_MAS_Mac configurations or the scratch-link-mac project entry. Drops the VS config dropdown from 6 configs to 2 (Debug_Win, Release_Win). Co-Authored-By: Claude Sonnet 4.6 --- scratch-link.sln | 81 +----------------------------------------------- 1 file changed, 1 insertion(+), 80 deletions(-) diff --git a/scratch-link.sln b/scratch-link.sln index c252bf97..4b4387df 100644 --- a/scratch-link.sln +++ b/scratch-link.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31611.283 @@ -32,8 +32,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "scratch-link-common", "scratch-link-common\scratch-link-common.shproj", "{06B5D2A3-AD0A-4704-B00D-BCFF634E7709}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "scratch-link-mac", "scratch-link-mac\scratch-link-mac.csproj", "{CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SharedProps", "SharedProps", "{52974047-90CA-4584-811B-242220DB05AB}" ProjectSection(SolutionItems) = preProject SharedProps\CommonPackageRefs.props = SharedProps\CommonPackageRefs.props @@ -80,64 +78,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "windows-build", "windows-bu EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug_Mac|Any CPU = Debug_Mac|Any CPU - Debug_Mac|ARM64 = Debug_Mac|ARM64 - Debug_Mac|x64 = Debug_Mac|x64 - Debug_Mac|x86 = Debug_Mac|x86 Debug_Win|Any CPU = Debug_Win|Any CPU Debug_Win|ARM64 = Debug_Win|ARM64 Debug_Win|x64 = Debug_Win|x64 Debug_Win|x86 = Debug_Win|x86 - Release_DevID_Mac|Any CPU = Release_DevID_Mac|Any CPU - Release_DevID_Mac|ARM64 = Release_DevID_Mac|ARM64 - Release_DevID_Mac|x64 = Release_DevID_Mac|x64 - Release_DevID_Mac|x86 = Release_DevID_Mac|x86 - Release_Mac|Any CPU = Release_Mac|Any CPU - Release_Mac|ARM64 = Release_Mac|ARM64 - Release_Mac|x64 = Release_Mac|x64 - Release_Mac|x86 = Release_Mac|x86 - Release_MAS_Mac|Any CPU = Release_MAS_Mac|Any CPU - Release_MAS_Mac|ARM64 = Release_MAS_Mac|ARM64 - Release_MAS_Mac|x64 = Release_MAS_Mac|x64 - Release_MAS_Mac|x86 = Release_MAS_Mac|x86 Release_Win|Any CPU = Release_Win|Any CPU Release_Win|ARM64 = Release_Win|ARM64 Release_Win|x64 = Release_Win|x64 Release_Win|x86 = Release_Win|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Mac|Any CPU.ActiveCfg = Debug|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Mac|Any CPU.Build.0 = Debug|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Mac|ARM64.ActiveCfg = Debug|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Mac|x64.ActiveCfg = Debug|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Mac|x86.ActiveCfg = Debug|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Win|Any CPU.ActiveCfg = Debug|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Win|ARM64.ActiveCfg = Debug|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Win|x64.ActiveCfg = Debug|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Win|x86.ActiveCfg = Debug|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_DevID_Mac|Any CPU.ActiveCfg = Release_DevID|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_DevID_Mac|Any CPU.Build.0 = Release_DevID|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_DevID_Mac|ARM64.ActiveCfg = Release_DevID|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_DevID_Mac|x64.ActiveCfg = Release_DevID|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_DevID_Mac|x86.ActiveCfg = Release_DevID|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Mac|Any CPU.ActiveCfg = Release|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Mac|Any CPU.Build.0 = Release|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Mac|ARM64.ActiveCfg = Release|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Mac|x64.ActiveCfg = Release|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Mac|x86.ActiveCfg = Release|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_MAS_Mac|Any CPU.ActiveCfg = Release_MAS|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_MAS_Mac|Any CPU.Build.0 = Release_MAS|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_MAS_Mac|ARM64.ActiveCfg = Release_MAS|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_MAS_Mac|x64.ActiveCfg = Release_MAS|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_MAS_Mac|x86.ActiveCfg = Release_MAS|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Win|Any CPU.ActiveCfg = Release|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Win|ARM64.ActiveCfg = Release|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Win|x64.ActiveCfg = Release|Any CPU - {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Win|x86.ActiveCfg = Release|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Mac|Any CPU.ActiveCfg = Debug|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Mac|ARM64.ActiveCfg = Debug|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Mac|x64.ActiveCfg = Debug|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Mac|x86.ActiveCfg = Debug|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Win|Any CPU.ActiveCfg = Debug|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Win|Any CPU.Build.0 = Debug|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Win|ARM64.ActiveCfg = Debug|Any CPU @@ -146,18 +96,6 @@ Global {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Win|x64.Build.0 = Debug|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Win|x86.ActiveCfg = Debug|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Win|x86.Build.0 = Debug|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_DevID_Mac|Any CPU.ActiveCfg = Release|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_DevID_Mac|ARM64.ActiveCfg = Release|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_DevID_Mac|x64.ActiveCfg = Release|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_DevID_Mac|x86.ActiveCfg = Release|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Mac|Any CPU.ActiveCfg = Release|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Mac|ARM64.ActiveCfg = Release|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Mac|x64.ActiveCfg = Release|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Mac|x86.ActiveCfg = Release|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_MAS_Mac|Any CPU.ActiveCfg = Release|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_MAS_Mac|ARM64.ActiveCfg = Release|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_MAS_Mac|x64.ActiveCfg = Release|Any CPU - {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_MAS_Mac|x86.ActiveCfg = Release|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Win|Any CPU.ActiveCfg = Release|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Win|Any CPU.Build.0 = Release|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Win|ARM64.ActiveCfg = Release|Any CPU @@ -166,10 +104,6 @@ Global {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Win|x64.Build.0 = Release|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Win|x86.ActiveCfg = Release|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Win|x86.Build.0 = Release|Any CPU - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Mac|Any CPU.ActiveCfg = Debug_Win|Any CPU - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Mac|ARM64.ActiveCfg = Debug_Win|ARM64 - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Mac|x64.ActiveCfg = Debug_Win|x64 - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Mac|x86.ActiveCfg = Debug_Win|x86 {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Win|Any CPU.ActiveCfg = Debug_Win|Any CPU {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Win|ARM64.ActiveCfg = Debug_Win|ARM64 {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Win|ARM64.Build.0 = Debug_Win|ARM64 @@ -180,18 +114,6 @@ Global {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Win|x86.ActiveCfg = Debug_Win|x86 {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Win|x86.Build.0 = Debug_Win|x86 {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Win|x86.Deploy.0 = Debug_Win|x86 - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_DevID_Mac|Any CPU.ActiveCfg = Release_Win|Any CPU - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_DevID_Mac|ARM64.ActiveCfg = Release_Win|ARM64 - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_DevID_Mac|x64.ActiveCfg = Release_Win|x64 - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_DevID_Mac|x86.ActiveCfg = Release_Win|x86 - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Mac|Any CPU.ActiveCfg = Release_Win|Any CPU - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Mac|ARM64.ActiveCfg = Release_Win|ARM64 - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Mac|x64.ActiveCfg = Release_Win|x64 - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Mac|x86.ActiveCfg = Release_Win|x86 - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_MAS_Mac|Any CPU.ActiveCfg = Release_Win|Any CPU - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_MAS_Mac|ARM64.ActiveCfg = Release_Win|ARM64 - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_MAS_Mac|x64.ActiveCfg = Release_Win|x64 - {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_MAS_Mac|x86.ActiveCfg = Release_Win|x86 {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Win|Any CPU.ActiveCfg = Release_Win|Any CPU {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Win|ARM64.ActiveCfg = Release_Win|ARM64 {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Win|ARM64.Build.0 = Release_Win|ARM64 @@ -222,6 +144,5 @@ Global GlobalSection(SharedMSBuildProjectFiles) = preSolution scratch-link-common\scratch-link-common.projitems*{06b5d2a3-ad0a-4704-b00d-bcff634e7709}*SharedItemsImports = 13 scratch-link-common\scratch-link-common.projitems*{b21c2fce-7670-402a-b8ee-958f3896f237}*SharedItemsImports = 5 - scratch-link-common\scratch-link-common.projitems*{cdf7978e-13c6-40a9-81f9-2a3b4f7e861c}*SharedItemsImports = 4 EndGlobalSection EndGlobal From 5f6ee663dba8f33bef5954fafb3e9ce5b2ddfa2f Mon Sep 17 00:00:00 2001 From: hksong Date: Sun, 24 May 2026 16:55:56 +0900 Subject: [PATCH 16/94] Revert "chore: remove Mac configurations and project from solution" This reverts commit e3c5159137d2ead0e1445acbf23044a32826bbf9. --- scratch-link.sln | 81 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/scratch-link.sln b/scratch-link.sln index 4b4387df..c252bf97 100644 --- a/scratch-link.sln +++ b/scratch-link.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31611.283 @@ -32,6 +32,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "scratch-link-common", "scratch-link-common\scratch-link-common.shproj", "{06B5D2A3-AD0A-4704-B00D-BCFF634E7709}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "scratch-link-mac", "scratch-link-mac\scratch-link-mac.csproj", "{CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SharedProps", "SharedProps", "{52974047-90CA-4584-811B-242220DB05AB}" ProjectSection(SolutionItems) = preProject SharedProps\CommonPackageRefs.props = SharedProps\CommonPackageRefs.props @@ -78,16 +80,64 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "windows-build", "windows-bu EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug_Mac|Any CPU = Debug_Mac|Any CPU + Debug_Mac|ARM64 = Debug_Mac|ARM64 + Debug_Mac|x64 = Debug_Mac|x64 + Debug_Mac|x86 = Debug_Mac|x86 Debug_Win|Any CPU = Debug_Win|Any CPU Debug_Win|ARM64 = Debug_Win|ARM64 Debug_Win|x64 = Debug_Win|x64 Debug_Win|x86 = Debug_Win|x86 + Release_DevID_Mac|Any CPU = Release_DevID_Mac|Any CPU + Release_DevID_Mac|ARM64 = Release_DevID_Mac|ARM64 + Release_DevID_Mac|x64 = Release_DevID_Mac|x64 + Release_DevID_Mac|x86 = Release_DevID_Mac|x86 + Release_Mac|Any CPU = Release_Mac|Any CPU + Release_Mac|ARM64 = Release_Mac|ARM64 + Release_Mac|x64 = Release_Mac|x64 + Release_Mac|x86 = Release_Mac|x86 + Release_MAS_Mac|Any CPU = Release_MAS_Mac|Any CPU + Release_MAS_Mac|ARM64 = Release_MAS_Mac|ARM64 + Release_MAS_Mac|x64 = Release_MAS_Mac|x64 + Release_MAS_Mac|x86 = Release_MAS_Mac|x86 Release_Win|Any CPU = Release_Win|Any CPU Release_Win|ARM64 = Release_Win|ARM64 Release_Win|x64 = Release_Win|x64 Release_Win|x86 = Release_Win|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Mac|Any CPU.ActiveCfg = Debug|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Mac|Any CPU.Build.0 = Debug|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Mac|ARM64.ActiveCfg = Debug|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Mac|x64.ActiveCfg = Debug|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Mac|x86.ActiveCfg = Debug|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Win|Any CPU.ActiveCfg = Debug|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Win|ARM64.ActiveCfg = Debug|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Win|x64.ActiveCfg = Debug|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Debug_Win|x86.ActiveCfg = Debug|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_DevID_Mac|Any CPU.ActiveCfg = Release_DevID|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_DevID_Mac|Any CPU.Build.0 = Release_DevID|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_DevID_Mac|ARM64.ActiveCfg = Release_DevID|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_DevID_Mac|x64.ActiveCfg = Release_DevID|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_DevID_Mac|x86.ActiveCfg = Release_DevID|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Mac|Any CPU.ActiveCfg = Release|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Mac|Any CPU.Build.0 = Release|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Mac|ARM64.ActiveCfg = Release|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Mac|x64.ActiveCfg = Release|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Mac|x86.ActiveCfg = Release|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_MAS_Mac|Any CPU.ActiveCfg = Release_MAS|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_MAS_Mac|Any CPU.Build.0 = Release_MAS|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_MAS_Mac|ARM64.ActiveCfg = Release_MAS|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_MAS_Mac|x64.ActiveCfg = Release_MAS|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_MAS_Mac|x86.ActiveCfg = Release_MAS|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Win|Any CPU.ActiveCfg = Release|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Win|ARM64.ActiveCfg = Release|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Win|x64.ActiveCfg = Release|Any CPU + {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}.Release_Win|x86.ActiveCfg = Release|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Mac|Any CPU.ActiveCfg = Debug|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Mac|ARM64.ActiveCfg = Debug|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Mac|x64.ActiveCfg = Debug|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Mac|x86.ActiveCfg = Debug|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Win|Any CPU.ActiveCfg = Debug|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Win|Any CPU.Build.0 = Debug|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Win|ARM64.ActiveCfg = Debug|Any CPU @@ -96,6 +146,18 @@ Global {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Win|x64.Build.0 = Debug|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Win|x86.ActiveCfg = Debug|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Debug_Win|x86.Build.0 = Debug|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_DevID_Mac|Any CPU.ActiveCfg = Release|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_DevID_Mac|ARM64.ActiveCfg = Release|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_DevID_Mac|x64.ActiveCfg = Release|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_DevID_Mac|x86.ActiveCfg = Release|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Mac|Any CPU.ActiveCfg = Release|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Mac|ARM64.ActiveCfg = Release|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Mac|x64.ActiveCfg = Release|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Mac|x86.ActiveCfg = Release|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_MAS_Mac|Any CPU.ActiveCfg = Release|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_MAS_Mac|ARM64.ActiveCfg = Release|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_MAS_Mac|x64.ActiveCfg = Release|Any CPU + {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_MAS_Mac|x86.ActiveCfg = Release|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Win|Any CPU.ActiveCfg = Release|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Win|Any CPU.Build.0 = Release|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Win|ARM64.ActiveCfg = Release|Any CPU @@ -104,6 +166,10 @@ Global {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Win|x64.Build.0 = Release|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Win|x86.ActiveCfg = Release|Any CPU {B21C2FCE-7670-402A-B8EE-958F3896F237}.Release_Win|x86.Build.0 = Release|Any CPU + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Mac|Any CPU.ActiveCfg = Debug_Win|Any CPU + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Mac|ARM64.ActiveCfg = Debug_Win|ARM64 + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Mac|x64.ActiveCfg = Debug_Win|x64 + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Mac|x86.ActiveCfg = Debug_Win|x86 {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Win|Any CPU.ActiveCfg = Debug_Win|Any CPU {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Win|ARM64.ActiveCfg = Debug_Win|ARM64 {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Win|ARM64.Build.0 = Debug_Win|ARM64 @@ -114,6 +180,18 @@ Global {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Win|x86.ActiveCfg = Debug_Win|x86 {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Win|x86.Build.0 = Debug_Win|x86 {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Debug_Win|x86.Deploy.0 = Debug_Win|x86 + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_DevID_Mac|Any CPU.ActiveCfg = Release_Win|Any CPU + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_DevID_Mac|ARM64.ActiveCfg = Release_Win|ARM64 + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_DevID_Mac|x64.ActiveCfg = Release_Win|x64 + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_DevID_Mac|x86.ActiveCfg = Release_Win|x86 + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Mac|Any CPU.ActiveCfg = Release_Win|Any CPU + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Mac|ARM64.ActiveCfg = Release_Win|ARM64 + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Mac|x64.ActiveCfg = Release_Win|x64 + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Mac|x86.ActiveCfg = Release_Win|x86 + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_MAS_Mac|Any CPU.ActiveCfg = Release_Win|Any CPU + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_MAS_Mac|ARM64.ActiveCfg = Release_Win|ARM64 + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_MAS_Mac|x64.ActiveCfg = Release_Win|x64 + {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_MAS_Mac|x86.ActiveCfg = Release_Win|x86 {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Win|Any CPU.ActiveCfg = Release_Win|Any CPU {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Win|ARM64.ActiveCfg = Release_Win|ARM64 {265CA433-8639-4E8D-A7F3-09B1B3495D92}.Release_Win|ARM64.Build.0 = Release_Win|ARM64 @@ -144,5 +222,6 @@ Global GlobalSection(SharedMSBuildProjectFiles) = preSolution scratch-link-common\scratch-link-common.projitems*{06b5d2a3-ad0a-4704-b00d-bcff634e7709}*SharedItemsImports = 13 scratch-link-common\scratch-link-common.projitems*{b21c2fce-7670-402a-b8ee-958f3896f237}*SharedItemsImports = 5 + scratch-link-common\scratch-link-common.projitems*{cdf7978e-13c6-40a9-81f9-2a3b4f7e861c}*SharedItemsImports = 4 EndGlobalSection EndGlobal From e98576efaf821fcfb5680c679db35744c7405c0f Mon Sep 17 00:00:00 2001 From: hksong Date: Sun, 24 May 2026 17:14:57 +0900 Subject: [PATCH 17/94] fix: add fallback GitVersion target for VS 2026 MSBuild compatibility VS 2026 MSBuild resolves $(NuGetPackageRoot) differently from the CLI, causing the Exists() condition on the GitInfo.targets import to fail silently. This leaves GitVersion undefined and breaks the build. Add a fallback GitVersion target in ScratchVersion.targets that sets safe defaults (SemVer 0.0.0, triggering the 1.0.0 floor). GitInfo's own GitVersion is imported later via nuget.g.targets and overrides this fallback when the package loads correctly ("last definition wins"). Co-Authored-By: Claude Sonnet 4.6 --- SharedProps/ScratchVersion.targets | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/SharedProps/ScratchVersion.targets b/SharedProps/ScratchVersion.targets index 51cd3651..211fa17c 100644 --- a/SharedProps/ScratchVersion.targets +++ b/SharedProps/ScratchVersion.targets @@ -3,6 +3,24 @@ This file sets up version properties in our own Scratch way. --> + + + + 0 + 0 + 0 + + 0000000 + 0 + $([System.DateTime]::UtcNow.ToString("o")) + + + - - true + + + true + false enable app.manifest AnyCPU From 48dd2ede7c3ef2c2bbab798ad5df2637ff459b59 Mon Sep 17 00:00:00 2001 From: hksong Date: Sun, 24 May 2026 17:27:40 +0900 Subject: [PATCH 19/94] =?UTF-8?q?chore:=20upgrade=20WindowsAppSDK=201.5=20?= =?UTF-8?q?=E2=86=92=201.8=20and=20SDK.BuildTools?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps Microsoft.WindowsAppSDK from 1.5.240311000 to 1.8.260508005 and Microsoft.Windows.SDK.BuildTools from 10.0.22621.3233 to 10.0.28000.1839. Windows App Runtime 1.8 is more widely pre-installed on Windows 11 via Windows Update, eliminating the runtime-install dialog on most systems. Co-Authored-By: Claude Sonnet 4.6 --- SharedProps/WindowsSDK.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SharedProps/WindowsSDK.props b/SharedProps/WindowsSDK.props index 86b662af..f681e936 100644 --- a/SharedProps/WindowsSDK.props +++ b/SharedProps/WindowsSDK.props @@ -2,11 +2,11 @@ - + build - + build From 95e049fa0368bff6c85998b462a7e5d412fb80d8 Mon Sep 17 00:00:00 2001 From: hksong Date: Sun, 24 May 2026 17:36:46 +0900 Subject: [PATCH 20/94] docs: rewrite README for current project state Updates README to reflect actual project structure: - .NET 8 / WindowsAppSDK 1.8 (was .NET 6 / 1.2/1.3) - Repo directory tree with all components - Accurate system requirements (WAR 1.8, Win 10 1809+) - Dev setup quick-start pointing to WindowsDevSetup-VS2026.md - Build configuration table (Debug_Win / Release_Win) - Corrected packaging section Co-Authored-By: Claude Sonnet 4.6 --- README.md | 132 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 3382b52e..d1ddc615 100644 --- a/README.md +++ b/README.md @@ -1,100 +1,104 @@ # Alux Scratch Link -Alux Scratch Link는 Scratch 3.0과 PC에 연결된 하드웨어 주변기기를 중계하는 도우미 앱입니다. -[scratchfoundation/scratch-link](https://github.com/scratchfoundation/scratch-link)의 **Windows 전용 포크**이며, -원본의 AGPL-3.0-only 라이선스를 그대로 따릅니다. +Scratch 3.0과 PC에 연결된 하드웨어 주변기기를 중계하는 도우미 앱. +[scratchfoundation/scratch-link](https://github.com/scratchfoundation/scratch-link)의 **Windows 전용 포크**이며, 원본의 AGPL-3.0-only 라이선스를 그대로 따릅니다. -원본 Scratch Link와의 차이: +## 원본과의 차이 -- **Windows 전용** — macOS 빌드와 Safari 확장은 빼고 Windows 패키징에 집중합니다. -- **Serial 전송 추가** — 기존 BLE / Bluetooth Classic에 더해 USB 시리얼(CDC/CH340 등) 장치를 - `/scratch/serial` JSON-RPC 엔드포인트로 지원합니다. 구현은 `scratch-link-common/Serial/`과 - `scratch-link-win/Serial/`을 참고하세요. -- **포트 20211 사용** — 원본 Scratch Link(20110/20111)와 한 PC에서 공존할 수 있도록 별도 포트를 씁니다. +- **Windows 전용** — macOS 빌드와 Safari 확장은 제외. +- **Serial 전송 추가** — BLE / Bluetooth Classic에 더해 USB 시리얼(CDC/CH340 등) 장치를 `/scratch/serial` JSON-RPC 엔드포인트로 지원. 구현은 `scratch-link-common/Serial/`과 `scratch-link-win/Serial/` 참고. +- **포트 20211 사용** — 원본 Scratch Link(20110/20111)와 한 PC에서 공존 가능. +- **.NET 8 / WindowsAppSDK 1.8** — 원본의 .NET 6 / WindowsAppSDK 1.3에서 업그레이드. ## 시스템 요구사항 | | 최소 사양 | -| --- | --- | -| Windows | Windows 10 build 17763 | +|---|---| +| Windows | Windows 10 build 17763 (1809) 이상 | +| Windows App Runtime | 1.8 (Windows 11 최신 업데이트 시 자동 설치됨) | -Windows App Runtime 1.2가 필요하며 가능한 경우 자동 설치됩니다. 수동 설치가 필요하면 아키텍처에 맞게 받으세요: +Windows App Runtime 1.8이 없는 경우 앱 실행 시 설치 안내가 표시됩니다. 수동 설치: -* https://aka.ms/windowsappsdk/1.2/latest/windowsappruntimeinstall-x64.exe -* https://aka.ms/windowsappsdk/1.2/latest/windowsappruntimeinstall-x86.exe -* https://aka.ms/windowsappsdk/1.2/latest/windowsappruntimeinstall-ARM64.exe +- [Windows App SDK 다운로드 페이지](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/downloads)에서 1.8 런타임 설치 파일 다운로드 ## Scratch 3.0과 함께 쓰기 -1. Alux Scratch Link 설치 후 실행 +1. Alux Scratch Link 실행 2. [Scratch 3.0](https://scratch.mit.edu) 열기 -3. 블록 카테고리 아래쪽의 "확장 기능 추가" 버튼(블록 모양 + 아이콘) 선택 -4. micro:bit, LEGO EV3 같은 지원 확장 선택 +3. 블록 카테고리 아래 "확장 기능 추가" 선택 +4. micro:bit, LEGO EV3 등 지원 확장 선택 5. 안내에 따라 주변기기 연결 -6. 새 블록으로 프로젝트 작성. Alux Scratch Link가 Scratch와 하드웨어 사이의 통신을 중계합니다. -## 개발 +## 저장소 구조 -### 문서 +``` +scratch-link/ +├── scratch-link-win/ # WinUI 3 앱 본체 (EXE) +│ ├── BLE/ # Bluetooth Low Energy (Windows) +│ ├── BT/ # Bluetooth Classic (Windows) +│ ├── Serial/ # USB 시리얼 (Windows) +│ └── Properties/PublishProfiles/ # win-x64/x86/arm64 publish 프로필 +├── scratch-link-win-msix/ # MSIX 패키징 프로젝트 (.wapproj) +├── scratch-link-common/ # 플랫폼 공유 C# 코드 (.shproj) +│ ├── BLE/ # BLE 세션 공통 로직 +│ ├── BT/ # BT 세션 공통 로직 +│ ├── Serial/ # 시리얼 세션 공통 로직 +│ ├── JsonRpc/ # JSON-RPC 2.0 구현 +│ └── Extensions/ # 유틸리티 확장 메서드 +├── SharedProps/ # 공유 MSBuild 프로퍼티 +│ ├── WindowsSDK.props # WindowsAppSDK 버전 핀 +│ ├── ScratchVersion.targets # Git 기반 버전 자동 생성 +│ ├── CommonPackageRefs.props # 공유 NuGet 패키지 +│ └── StyleCop.props # 코드 스타일 분석 +├── Documentation/ # 프로토콜 문서 (Architecture, Bluetooth, Serial 등) +└── brand/ # 아이콘 소스 SVG 및 빌드 스크립트 +``` -전반적인 네트워크 프로토콜과 지원 하드웨어 프로토콜은 `Documentation/` 아래에 마크다운으로 정리되어 있습니다 -(Architecture, Bluetooth, BluetoothLE, NetworkProtocol, TestPlans). 프로토콜 호환성/안정성은 -중요한 우선순위이므로, 프로토콜을 바꾸는 PR은 충분한 정당화와 문서 갱신이 동반되어야 합니다. +## 개발 환경 구성 -문서 PR을 보내기 전 [markdownlint](https://www.npmjs.com/package/markdownlint)로 점검해주세요. +[../documents/WindowsDevSetup-VS2026.md](../documents/WindowsDevSetup-VS2026.md) 참고. -### 버전 번호 +요약: -이 포크는 [SharedProps/ScratchVersion.targets](SharedProps/ScratchVersion.targets)에서 base 버전을 -`1.0.0`으로 고정해두고, 빌드 번호는 git commit 수에서 가져옵니다. 결과 4-part 버전은 -`1.0.0.` 형태로 EXE 파일 속성과 트레이 메뉴에 노출됩니다. +1. Visual Studio 2026 워크로드: `.NET 데스크톱 개발`, `WinUI 애플리케이션 개발`, `C++ 데스크톱 개발` +2. Solution Configuration: `Debug_Win`, Platform: `x64` +3. Startup Project: `scratch-link-win` +4. F5로 실행 → 트레이 아이콘 확인 -정식 릴리즈를 끊을 때는 `git tag v1.1.0`처럼 semver 태그를 찍으세요. GitInfo가 태그를 감지하면 -위의 1.0.0 고정 로직이 자동으로 비켜나 태그값을 따라갑니다. +## 빌드 구성 -확장 버전 정보(`git describe`와 유사한 상세 문자열)는 트레이 메뉴의 버전 항목을 클릭해 -클립보드로 복사할 수 있습니다. +| Configuration | 용도 | +|---|---| +| `Debug_Win` | 일상 개발/디버깅 (F5) | +| `Release_Win` | 배포용 빌드 및 MSIX 패키징 | -### 브랜드 자산 +Startup Project를 `scratch-link-win-msix`로 설정하면 MSIX 패키지 빌드가 실행됩니다. 일반 디버깅은 반드시 `scratch-link-win`으로 설정할 것. -앱/트레이/MSIX에 쓰이는 모든 아이콘은 [brand/labs-l.svg](brand/labs-l.svg) 하나에서 파생됩니다. -SVG가 갱신되면 다음 명령으로 ICO/PNG를 재생성하세요: +## 버전 번호 -``` -pip install Pillow # 최초 1회 -python brand/build_icons.py -``` +`SharedProps/ScratchVersion.targets`에서 git 메타데이터를 기반으로 자동 생성됩니다. -생성물은 모두 커밋되어 있어 일반 빌드 시에는 이 스크립트를 돌릴 필요가 없습니다. +- git semver 태그가 없으면 `1.0.0.<커밋수>` 형태 +- 정식 릴리즈 시 `git tag v1.1.0`처럼 태그를 찍으면 해당 버전을 따라감 -### Windows 패키징과 설치 파일 크기 +상세 버전 문자열은 트레이 메뉴의 버전 항목을 클릭해 클립보드로 복사할 수 있습니다. -`PublishReadyToRun`(R2R) 설정은 ahead-of-time(AOT) 컴파일을 활성화합니다(반대는 JIT). 시작 시간 등 -성능에는 유리하지만, [R2R 바이너리는 IL 코드와 네이티브 코드를 모두 포함하기 때문에 -크기가 더 커집니다](https://learn.microsoft.com/en-us/dotnet/core/deploying/ready-to-run). +## 브랜드 자산 -.NET 5.0 이상에서는 설정에 따라 "Framework-Dependent Application" 또는 "Self-Contained Application"으로 -빌드할 수 있습니다. +모든 아이콘은 [brand/labs-l.svg](brand/labs-l.svg)에서 파생됩니다. SVG 변경 시: -* **Self-contained** — .NET 런타임을 함께 번들합니다. 플랫폼별(x86/x64/ARM64) `dotnet.exe`가 - 포함되어야 해서 빌드 결과가 커집니다. - * 네이티브 런타임 일부를 포함하므로 "AnyCPU"로는 빌드할 수 없습니다. - * 앱이 쓰는 부분만 남기는 "trimming"이 가능하지만, 그래도 framework-dependent보다는 큽니다. -* **Framework-dependent** — 런타임을 포함하지 않으며 별도 설치가 필요합니다. - * 생성된 MSIX는 필요 시 자동 설치를 트리거합니다(인터넷 연결 필요). - * 네이티브 부분이 없으므로 "AnyCPU"로 빌드할 수 있습니다. - * 원하면 특정 CPU로도 빌드 가능합니다. - * 디버깅 시에는 프로젝트 파일에서 `None` 설정이 필요합니다. +``` +pip install Pillow # 최초 1회 +python brand/build_icons.py +``` -패키징 시: +생성물(ICO/PNG)은 커밋되어 있으므로 일반 빌드 시에는 실행 불필요. -* MSIX 파일(`*.msix`)은 한 번에 하나의 플랫폼(x86, x64, ARM64)만 담을 수 있습니다. -* MSIX 번들(`*.msixbundle`)은 여러 MSIX를 묶을 수 있어 플랫폼별 MSIX를 한 번에 배포하기 좋습니다. +## 패키징 및 배포 -이상적으로는 단일 "AnyCPU" 빌드를 stub MSIX와 함께 묶어 플랫폼별 런타임을 설치하게 하면 -번들 크기를 최소화할 수 있습니다. 다만 이 구성은 추가 조사가 필요합니다. +현재 배포 방식은 **framework-dependent**입니다. Windows App Runtime 1.8이 없는 PC에서는 설치 안내가 표시됩니다. -대안으로, 플랫폼별 MSIX 안에 AnyCPU 빌드를 담을 수 있습니다. 이 경우 x86/x64/ARM64 세 카피를 묶어도 -플랫폼별 self-contained 번들보다 훨씬 작습니다. +- **MSIX 파일(`*.msix`)**: 단일 플랫폼(x86/x64/ARM64) +- **MSIX 번들(`*.msixbundle`)**: 여러 플랫폼을 하나로 묶어 배포 -R2R을 끄고 AnyCPU 빌드를 묶은 결과는, 같은 플랫폼 세트의 self-contained 번들 대비 약 12% 크기였습니다. +self-contained 배포(런타임 번들링)로 전환하면 설치 안내가 완전히 사라지지만, 바이너리 크기가 증가합니다. AnyCPU 빌드에서는 self-contained를 지원하지 않으므로 플랫폼별 빌드(x64/x86/ARM64)가 필요합니다. From b3b083a8fd8aad1ce4af75ddc61c9b7ae09271ec Mon Sep 17 00:00:00 2001 From: hksong Date: Sun, 24 May 2026 18:23:03 +0900 Subject: [PATCH 21/94] docs: update project metadata and dev setup guide - Rename package.json name/author/version to ALUX, Inc. / 1.0.0 - Update csproj and appxmanifest Company/PublisherDisplayName to ALUX, Inc. - Update README: AluxLabs branding, Alux product extensions, repo link to dev guide - Move dev setup guide into Documentation/ for proper git tracking Co-Authored-By: Claude Sonnet 4.6 --- Documentation/WindowsDevSetup-VS2026.md | 97 ++++++++++++++++++++++ README.md | 17 ++-- package.json | 8 +- scratch-link-win-msix/Package.appxmanifest | 2 +- scratch-link-win/scratch-link-win.csproj | 2 +- 5 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 Documentation/WindowsDevSetup-VS2026.md diff --git a/Documentation/WindowsDevSetup-VS2026.md b/Documentation/WindowsDevSetup-VS2026.md new file mode 100644 index 00000000..150da42b --- /dev/null +++ b/Documentation/WindowsDevSetup-VS2026.md @@ -0,0 +1,97 @@ +# Windows 개발 환경 세팅 (Visual Studio 2026) + +Visual Studio 2026으로 Alux Scratch Link를 빌드/디버깅하기 위한 환경 세팅 절차. + +## 0. 사전 정보 + +- 솔루션 파일 `scratch-link.sln`은 VS 2026에서 그대로 열 수 있다. **버전 변환 프롬프트가 떠도 변환하지 말 것** (sln 포맷이 바뀌어 PR이 지저분해진다). +- 윈도우 관련 프로젝트: + - `scratch-link-win` — WinUI 3 기반 본체 EXE (net8.0-windows) + - `scratch-link-win-msix` — `.wapproj` (Desktop Bridge) 형식의 MSIX 패키징 프로젝트 + - `scratch-link-common` — 공유 C# 코드 (`.shproj`, 공유 아이템 프로젝트) +- `scratch-link-mac`은 솔루션을 열면 "Unsupported"로 표시되는데 **정상이다**. Windows VS에서는 어차피 빌드하지 않으므로 무시한다 (솔루션에서 제거하지 말 것). + +## 1. Visual Studio Installer 워크로드 + +VS Installer를 열고 **수정(Modify)**으로 다음 워크로드를 체크한다. + +### 워크로드 (Workloads 탭) + +- ☑ **.NET 데스크톱 개발** (.NET desktop development) +- ☑ **C++를 사용한 데스크톱 개발** (Desktop development with C++) +- ☑ **WinUI 애플리케이션 개발** (WinUI application development) + +### 각 워크로드의 선택 사항 + +**`.NET 데스크톱 개발`의 선택 사항:** + +- ☑ **MSIX Packaging Tools** — `.wapproj` 빌드에 필수. + +**`WinUI 애플리케이션 개발`의 선택 사항:** + +- ☑ **Windows 11 SDK (10.0.22621.0)** — `scratch-link-win.csproj`의 `TargetFramework=net8.0-windows10.0.22621.0`이 요구하는 SDK. + +> `.NET 8 SDK`는 VS 2026에 포함되어 있으므로 별도 설치가 필요 없다. + +## 2. Windows App Runtime 확인 + +이 프로젝트는 `Microsoft.WindowsAppSDK 1.8`을 framework-dependent 모드로 참조한다. F5 실행 시 **Windows App Runtime 1.8이 시스템에 설치되어 있어야** 한다. + +**Windows 11 최신 업데이트 적용 환경이라면 이미 설치되어 있을 가능성이 높다.** + +확인 방법: + +```powershell +Get-AppxPackage -Name "Microsoft.WindowsAppRuntime.1.8*" +``` + +`Microsoft.WindowsAppRuntime.1.8_*` 패키지가 보이면 OK. + +없으면 [Windows App SDK 다운로드 페이지](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/downloads)에서 1.8 런타임 설치 파일을 받아 실행한다. + +## 3. 솔루션 열기 + +1. `scratch-link.sln` 더블클릭으로 VS 2026에서 열기 +2. "Migration Report"가 뜨면 **OK**로 닫는다. `scratch-link-mac`이 Unsupported로 나오는 것은 정상. +3. **솔루션 탐색기**에서 `scratch-link-win`을 우클릭 → **Set as Startup Project**. 프로젝트 이름이 굵게(bold) 변하면 적용된 것. + +## 4. 빌드/실행 설정 + +VS 상단 툴바에서: + +| 항목 | 값 | +|---|---| +| Solution Configurations | **`Debug_Win`** | +| Solution Platforms | **`x64`** (또는 본인 PC에 맞는 플랫폼) | +| Startup Project | **`scratch-link-win`** | + +> **시작 프로젝트는 반드시 `scratch-link-win`이어야 한다.** `scratch-link-win-msix`로 F5를 누르면 패키지 ID 충돌로 `MddBootstrapInitialize 0x80070032` 에러가 난다. + +이후 **F5**로 빌드 및 실행. 트레이 아이콘이 나타나면 정상 동작. + +## 5. 워크플로우 + +| 목적 | Startup Project | Configuration | 결과물 | +|---|---|---|---| +| **일상 개발/디버깅 (F5)** | `scratch-link-win` | `Debug_Win` / `x64` | 언패키지 EXE 직접 실행 | +| **MSIX 패키지 빌드** | `scratch-link-win-msix` | `Release_Win` / `x64` | publish profile (`win-x64.pubxml`)로 MSIX 생성 | +| **배포용 msixbundle** | `scratch-link-win-msix` | `Release_Win`, 전 플랫폼 | x86/x64/ARM64 `.msixbundle` 생성 | + +## 6. 알려진 이슈 + +| 증상 | 원인 / 해결 | +|---|---| +| `Microsoft.DesktopBridge.props was not found` | MSIX Packaging Tools 누락. §1의 ".NET 데스크톱 개발" 선택 사항 확인. | +| `Windows 10 SDK version 10.0.22621.0 was not found` | Windows 11 SDK 22621 미설치. §1의 "WinUI 애플리케이션 개발" 선택 사항 확인. | +| F5 시 `MddBootstrapInitialize ... 0x80070032` | 시작 프로젝트가 wapproj로 설정됨. §4 참고. | +| F5 시 "This application requires the Windows App Runtime 1.8" | 런타임 미설치. §2 참고. | +| `scratch-link-win-msix`가 회색으로 비활성화 | Configuration이 `*_Win`이 아닌 다른 것으로 되어 있음. `Debug_Win` 또는 `Release_Win`으로 전환. | +| CS 빌드 에러 (System.Management, Fleck 등 누락) | NuGet 캐시 불일치. CLI에서 `dotnet restore --force scratch-link-win/scratch-link-win.csproj` 실행 후 VS 재시작. | +| 빌드 시 `프로젝트에 'GitVersion' 대상이 없습니다` | VS 2026 MSBuild의 NuGetPackageRoot 경로 차이로 GitInfo.targets가 로드 안 되는 경우. `SharedProps/ScratchVersion.targets`에 fallback 타겟이 있어 정상 동작하므로 무시해도 된다. | + +## 7. 참고 + +- [`scratch-link-win/scratch-link-win.csproj`](../scratch-link-win/scratch-link-win.csproj) — 본체 프로젝트 설정 +- [`scratch-link-win-msix/scratch-link-win-msix.wapproj`](../scratch-link-win-msix/scratch-link-win-msix.wapproj) — MSIX 패키징 설정 +- [`SharedProps/WindowsSDK.props`](../SharedProps/WindowsSDK.props) — Windows App SDK 버전 핀 +- [`SharedProps/ScratchVersion.targets`](../SharedProps/ScratchVersion.targets) — 버전 자동 생성 로직 diff --git a/README.md b/README.md index d1ddc615..a04249c2 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,14 @@ Windows App Runtime 1.8이 없는 경우 앱 실행 시 설치 안내가 표시 - [Windows App SDK 다운로드 페이지](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/downloads)에서 1.8 런타임 설치 파일 다운로드 -## Scratch 3.0과 함께 쓰기 +## AluxLabs와 함께 쓰기 + +AluxLabs는 Alux 전용 Scratch 3.0입니다. 1. Alux Scratch Link 실행 -2. [Scratch 3.0](https://scratch.mit.edu) 열기 +2. AluxLabs 열기 3. 블록 카테고리 아래 "확장 기능 추가" 선택 -4. micro:bit, LEGO EV3 등 지원 확장 선택 +4. CodeTinker, Connect, CodingDrone 등 지원 확장 선택 5. 안내에 따라 주변기기 연결 ## 저장소 구조 @@ -56,14 +58,7 @@ scratch-link/ ## 개발 환경 구성 -[../documents/WindowsDevSetup-VS2026.md](../documents/WindowsDevSetup-VS2026.md) 참고. - -요약: - -1. Visual Studio 2026 워크로드: `.NET 데스크톱 개발`, `WinUI 애플리케이션 개발`, `C++ 데스크톱 개발` -2. Solution Configuration: `Debug_Win`, Platform: `x64` -3. Startup Project: `scratch-link-win` -4. F5로 실행 → 트레이 아이콘 확인 +[Documentation/WindowsDevSetup-VS2026.md](Documentation/WindowsDevSetup-VS2026.md) 참고. ## 빌드 구성 diff --git a/package.json b/package.json index 9ba2d76b..e258a44e 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "scratch-link", - "version": "2.1.0-develop.10", - "description": "Scratch Link is not published as an NPM package. This file only exists to facilitate installation of devDependencies.", - "author": "Scratch Foundation", + "name": "alux-scratch-link", + "version": "1.0.0", + "description": "Alux Scratch Link is not published as an NPM package. This file only exists to facilitate installation of devDependencies.", + "author": "ALUX, Inc.", "license": "AGPL-3.0-only", "scripts": { "prepare": "husky install" diff --git a/scratch-link-win-msix/Package.appxmanifest b/scratch-link-win-msix/Package.appxmanifest index 72092f3a..87fb2128 100644 --- a/scratch-link-win-msix/Package.appxmanifest +++ b/scratch-link-win-msix/Package.appxmanifest @@ -13,7 +13,7 @@ Alux Scratch Link - Alux (based on Scratch Foundation) + ALUX, Inc. Images\StoreLogo.png diff --git a/scratch-link-win/scratch-link-win.csproj b/scratch-link-win/scratch-link-win.csproj index 24d6dc4b..64f68fa0 100644 --- a/scratch-link-win/scratch-link-win.csproj +++ b/scratch-link-win/scratch-link-win.csproj @@ -6,7 +6,7 @@ 10.0.17763.0 ScratchLink.Win Alux Scratch Link - Alux (based on Scratch Foundation) + ALUX, Inc. $(Company) disable true From 6a486d060d0cfc9c40cb3c9bc3f645aea0603263 Mon Sep 17 00:00:00 2001 From: hksong Date: Mon, 25 May 2026 13:30:43 +0900 Subject: [PATCH 22/94] docs(serial): add Alux fork-specific guides under Documentation/Alux/ Group all fork-specific documentation under a dedicated subfolder so that upstream scratchfoundation/scratch-link docs and Alux fork docs are visually and structurally distinguishable. This also lets upstream syncs ignore Documentation/Alux/ as a whole. Contents: - SerialApiReference.md: complete JSON-RPC API for the serial transport (discover, connect, write, startReading, stopReading, setKeepAlive, disconnect; notifications; recovery policy; pathHint matching semantics). - SerialKeepAliveGuide.md: explains the codetinker 1s-timeout problem, the keep-alive timer design, the DFU-safe interaction model (write-time reset, setKeepAlive toggle), and the wireTrace diagnostic option. - WindowsDevSetup-VS2026.md: moved into Alux/ alongside the new guides. README links the new folder so upstream-vs-fork doc origin is obvious. --- Documentation/Alux/SerialApiReference.md | 482 ++++++++++++++++++ Documentation/Alux/SerialKeepAliveGuide.md | 196 +++++++ .../{ => Alux}/WindowsDevSetup-VS2026.md | 0 README.md | 3 +- 4 files changed, 680 insertions(+), 1 deletion(-) create mode 100644 Documentation/Alux/SerialApiReference.md create mode 100644 Documentation/Alux/SerialKeepAliveGuide.md rename Documentation/{ => Alux}/WindowsDevSetup-VS2026.md (100%) diff --git a/Documentation/Alux/SerialApiReference.md b/Documentation/Alux/SerialApiReference.md new file mode 100644 index 00000000..9a3c1789 --- /dev/null +++ b/Documentation/Alux/SerialApiReference.md @@ -0,0 +1,482 @@ +# Serial Transport API Reference + +## JSON-RPC Methods + +### discover + +Discovers available serial ports. + +**Request:** +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "discover", + "params": { + "filters": [ + { + "usbVendorId": 6790, + "usbProductId": 29987, + "pathHint": "COM" + } + ] + } +} +``` + +**Parameters:** +- `filters` (array, optional) — Filter discovered ports. If omitted or empty, every enumerated USB serial port is reported. A port is reported when it matches **any** filter (filters are OR'd); within one filter, all specified fields must match (fields are AND'd). + +**Filter fields:** +- `usbVendorId` (int, optional) — USB Vendor ID as a decimal integer. Exact match. Omit to skip this check. +- `usbProductId` (int, optional) — USB Product ID as a decimal integer. Exact match. Omit to skip this check. +- `pathHint` (string, optional) — **Case-insensitive substring** match against the OS-level port path (`info.Path`, e.g. `"COM7"` on Windows). Not a prefix, not exact, not a regex. Example: `"COM"` matches `COM3`, `COM12`, etc. Omit to skip this check. + +**Response:** +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": {} +} +``` + +**Notifications:** +Discovered ports arrive as `didDiscoverPeripheral` notifications: +```json +{ + "jsonrpc": "2.0", + "method": "didDiscoverPeripheral", + "params": { + "peripheralId": "port-0", + "name": "COM7 (CH340)", + "path": "COM7", + "vendorId": "0x1a86", + "productId": "0x7523", + "rssi": 0 + } +} +``` + +--- + +### connect + +Opens a serial port connection. + +**Request:** +```json +{ + "jsonrpc": "2.0", + "id": 2, + "method": "connect", + "params": { + "peripheralId": "port-0", + "baudRate": 115200, + "dataBits": 8, + "parity": "none", + "stopBits": "one", + "flowControl": "none", + "peripheralType": "codetinker", + "keepAliveIntervalMs": 33, + "wireTrace": false + } +} +``` + +**Parameters:** +- `peripheralId` (string, required) — Port identifier from discovery +- `baudRate` (int, required) — Baud rate (e.g., 9600, 115200) +- `dataBits` (int, optional) — Data bits (default: 8) +- `parity` (string, optional) — "none" | "even" | "odd" | "mark" | "space" (default: "none") +- `stopBits` (string, optional) — "one" | "onePointFive" | "two" (default: "one") +- `flowControl` (string, optional) — "none" | "rtsCts" | "xonXoff" (default: "none") +- `peripheralType` (string, optional) — Device type identifier ("codetinker", "connect", "technic", etc.) +- `keepAliveIntervalMs` (int, optional) — Keep-alive interval in ms. Omit or null to disable. **Recommended: 33ms for Codetinker** +- `wireTrace` (bool, optional) — Diagnostic. When `true`, Link emits per-write/per-read hex dumps via `Trace.WriteLine` (visible in DebugView or attached debugger). Off by default. Use only for transport-level debugging; the dumps include payload bytes and can be verbose. + +**Response:** +```json +{ + "jsonrpc": "2.0", + "id": 2, + "result": {} +} +``` + +**Errors:** +```json +{ + "jsonrpc": "2.0", + "id": 2, + "error": { + "code": -32603, + "message": "could not open serial port COM7: Port already in use" + } +} +``` + +--- + +### write + +Sends data to the serial port. + +**Request:** +```json +{ + "jsonrpc": "2.0", + "id": 3, + "method": "write", + "params": { + "message": "AQIDBA==", + "encoding": "base64" + } +} +``` + +**Parameters:** +- `message` (string, required) — Data to send (base64-encoded) +- `encoding` (string, required) — Always "base64" + +**Response:** +```json +{ + "jsonrpc": "2.0", + "id": 3, + "result": { + "sentBytes": 4 + } +} +``` + +**Side Effects:** +- Resets the keep-alive timer +- Last sent packet is cached for keep-alive resend + +--- + +### startReading + +Enables data reception (usually implicit after connect). + +**Request:** +```json +{ + "jsonrpc": "2.0", + "id": 4, + "method": "startReading", + "params": {} +} +``` + +**Response:** +```json +{ + "jsonrpc": "2.0", + "id": 4, + "result": {} +} +``` + +--- + +### stopReading + +Disables data reception (keep-alive timer continues running). + +**Request:** +```json +{ + "jsonrpc": "2.0", + "id": 5, + "method": "stopReading", + "params": {} +} +``` + +**Response:** +```json +{ + "jsonrpc": "2.0", + "id": 5, + "result": {} +} +``` + +--- + +### setKeepAlive + +Toggle or reconfigure keep-alive at runtime, without disconnecting. Use to disable keep-alive before a firmware update and re-enable it afterwards, or to change the interval mid-session. + +**Request — disable:** +```json +{ + "jsonrpc": "2.0", + "id": 6, + "method": "setKeepAlive", + "params": { "intervalMs": null } +} +``` + +**Request — enable / change interval:** +```json +{ + "jsonrpc": "2.0", + "id": 7, + "method": "setKeepAlive", + "params": { "intervalMs": 33 } +} +``` + +**Parameters:** +- `intervalMs` (int or null, required) — Interval in milliseconds. `null`, `0`, or negative values **disable** keep-alive. Positive values (re)start it with the given interval. + +**Response:** +```json +{ + "jsonrpc": "2.0", + "id": 7, + "result": { "intervalMs": 33 } +} +``` + +The `result.intervalMs` echoes the **applied** interval (`null` when disabled). Use this to confirm the operation took effect. + +**Side Effects:** +- If keep-alive was already running, the existing timer is stopped (blocking on any in-flight tick) before the new one starts. The call is fully idempotent. +- The cached last-TX packet is **preserved** across the toggle, so re-enabling keep-alive immediately resumes resending the same packet. + +**Typical DFU sequence (client-side):** +```javascript +// 1. Disable keep-alive before bootloader entry +await link.send("setKeepAlive", { intervalMs: null }); + +// 2. Run firmware update (writes/reads as usual) +await runDfu(...); + +// 3. Re-enable keep-alive for normal operation +await link.send("setKeepAlive", { intervalMs: 33 }); +``` + +--- + +### disconnect + +Closes the serial port connection. + +**Request:** +```json +{ + "jsonrpc": "2.0", + "id": 6, + "method": "disconnect", + "params": {} +} +``` + +**Response:** +```json +{ + "jsonrpc": "2.0", + "id": 6, + "result": {} +} +``` + +**Side Effects:** +- Stops the keep-alive timer +- Closes the port +- Does NOT fire `serialDidDisconnect` notification (client-initiated close) + +--- + +## Notifications + +### didDiscoverPeripheral + +Sent for each discovered serial port during discovery. + +```json +{ + "jsonrpc": "2.0", + "method": "didDiscoverPeripheral", + "params": { + "peripheralId": "port-0", + "name": "COM7 (CH340)", + "path": "COM7", + "vendorId": "0x1a86", + "productId": "0x7523", + "rssi": 0 + } +} +``` + +--- + +### serialDidReceiveData + +Sent when data is received on the serial port. + +```json +{ + "jsonrpc": "2.0", + "method": "serialDidReceiveData", + "params": { + "message": "SG93IGFyZSB5b3U/", + "encoding": "base64" + } +} +``` + +--- + +### serialDidDisconnect + +Sent when the connection is lost (external cause, not client-initiated). + +```json +{ + "jsonrpc": "2.0", + "method": "serialDidDisconnect", + "params": { + "reason": "device", + "message": "Port was removed" + } +} +``` + +**Disconnect Reasons:** +- `"device"` — Device physically disconnected or a read-side `IOException` occurred (cable unplug, USB stack hiccup, driver error, transient USB noise that the kernel surfaced as an I/O error) +- `"error"` — Unexpected non-I/O exception in the read loop +- `"user"` — User action (rare) +- `"shutdown"` — Application shutting down + +**Recovery policy (current):** + +Scratch Link does **not** retry on I/O errors. The moment the kernel surfaces a read-side `IOException`, Link: +1. Fires `serialDidDisconnect` with `reason: "device"`. +2. Closes the port. +3. Stops the keep-alive timer and the RX loop. + +The client (aluxlabs) is responsible for any reconnect logic — including any debounce or retry policy for transient USB noise. + +This is a deliberate design choice for v1: keep Link's transport thin and predictable, let the client decide policy. If transient-disconnect reports start to accumulate from the field, we can re-negotiate a Link-side retry (e.g. one 200 ms re-open before surfacing the disconnect) and add a `retryOnIoError` connect parameter to opt in. Until then, **assume immediate disconnect on any I/O error.** + +--- + +## Complete Example: Codetinker Connection + +```javascript +// 1. Discover ports +{ + "jsonrpc": "2.0", + "id": 1, + "method": "discover", + "params": {} +} +// → didDiscoverPeripheral: { peripheralId: "port-0", name: "COM7 (CH340)", ... } + +// 2. Connect with keep-alive +{ + "jsonrpc": "2.0", + "id": 2, + "method": "connect", + "params": { + "peripheralId": "port-0", + "baudRate": 115200, + "peripheralType": "codetinker", + "keepAliveIntervalMs": 33 + } +} +// → result: {} +// → Keep-alive timer starts, will resend last TX packet every 33ms if idle + +// 3. Send command +{ + "jsonrpc": "2.0", + "id": 3, + "method": "write", + "params": { + "message": "AQIDBA==", + "encoding": "base64" + } +} +// → result: { sentBytes: 4 } +// → Keep-alive timer resets (cached packet = AQIDBA==) + +// 4. Receive response +// ← serialDidReceiveData: { message: "BwgJCg==", encoding: "base64" } + +// 5. Disconnect +{ + "jsonrpc": "2.0", + "id": 4, + "method": "disconnect", + "params": {} +} +// → result: {} +// → Keep-alive timer stops +``` + +--- + +## Error Codes + +| Code | Message | Description | +|------|---------|-------------| +| -32600 | Invalid Request | Malformed JSON-RPC | +| -32601 | Method not found | Unknown method | +| -32602 | Invalid params | Missing required parameter | +| -32603 | Internal error | Port error, invalid state, etc. | + +--- + +## Recommendations + +### For Codetinker +```json +{ + "baudRate": 115200, + "peripheralType": "codetinker", + "keepAliveIntervalMs": 33 +} +``` + +### For Generic Serial Devices (no keep-alive) +```json +{ + "baudRate": 9600 +} +``` + +### For Firmware Updates + +Two layers of protection: + +1. **Automatic (no client change needed).** Each `write` resets the keep-alive interval, so a burst of writes (DFU chunks) suppresses the resend until the line goes idle again. +2. **Explicit (recommended for wireless DFU).** Before bootloader entry, call `setKeepAlive` with `intervalMs: null` to disable keep-alive entirely. Re-enable after DFU completes. This eliminates any chance of a resend racing with a bootloader handshake on a slow wireless link. + +```javascript +await link.send("setKeepAlive", { intervalMs: null }); +// ... run DFU ... +await link.send("setKeepAlive", { intervalMs: 33 }); +``` + +### For Transport-Level Debugging + +Enable `wireTrace: true` on `connect` to get per-write/per-read hex dumps via `Trace.WriteLine`. Output is visible in [DebugView](https://learn.microsoft.com/sysinternals/downloads/debugview) (run as admin, "Capture Win32") or any attached debugger. Format: + +``` +wire-trace TX 12B 4c 4f 41 44 ... +wire-trace RX 31B 3c 1e af 00 ... +wire-trace TX(keep-alive) 4B aa bb cc dd +``` + +Buffers longer than 256 bytes are truncated with `…(+NB)` suffix. Compare these against the client's own per-message log to localize any drops or corruption. + +--- + +**API Version**: 1.1 +**Last Updated**: 2026-05-25 diff --git a/Documentation/Alux/SerialKeepAliveGuide.md b/Documentation/Alux/SerialKeepAliveGuide.md new file mode 100644 index 00000000..0050ff3b --- /dev/null +++ b/Documentation/Alux/SerialKeepAliveGuide.md @@ -0,0 +1,196 @@ +# Serial Keep-Alive Implementation Guide + +## Overview + +The Scratch Link serial transport now supports **keep-alive** functionality to prevent device timeout. This is particularly useful for devices like Codetinker that disconnect if no response is received within 1 second. + +## Problem Statement + +Some hardware devices (e.g., Codetinker with CH340 USB-to-serial) require continuous communication: +- If no packet is received for > 1 second, the device considers the connection lost +- This triggers device-side notifications (e.g., buzzer sound) +- Regular idle periods during normal operation cause unnecessary timeouts + +## Solution + +The keep-alive mechanism automatically resends the **last transmitted (TX) packet** at a configurable interval. This keeps the device "alive" without interfering with actual communication. + +### Key Features + +✅ **Automatic resend** — Last sent packet is cached and resent periodically +✅ **No interference with active communication** — Timer resets on every write, so frequent communication automatically pauses keep-alive +✅ **Firmware update safe** — During firmware updates (DFU), frequent writes prevent keep-alive from firing +✅ **Optional and configurable** — Can be enabled/disabled per connection + +## Usage + +### Serial Connection Request + +When connecting to a serial device, include the `keepAliveIntervalMs` parameter: + +```json +{ + "baudRate": 115200, + "peripheralType": "codetinker", + "keepAliveIntervalMs": 33 +} +``` + +### Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `baudRate` | int | Yes | Baud rate (e.g., 115200) | +| `peripheralType` | string | No | Device type identifier (e.g., "codetinker", "connect", "technic") | +| `keepAliveIntervalMs` | int \| null | No | Keep-alive interval in milliseconds. `null` or omitted = disabled. Set to 33ms for Codetinker. | + +### Examples + +#### Codetinker (with keep-alive) +```json +{ + "baudRate": 115200, + "peripheralType": "codetinker", + "keepAliveIntervalMs": 33 +} +``` + +#### Generic device (no keep-alive) +```json +{ + "baudRate": 9600 +} +``` + +#### Other device with custom interval +```json +{ + "baudRate": 57600, + "peripheralType": "custom", + "keepAliveIntervalMs": 100 +} +``` + +## How It Works + +### 1. Keep-Alive Enabled +``` +Time: 0ms → Client sends packet A +Time: 33ms → (no activity) Keep-alive resends packet A +Time: 66ms → (no activity) Keep-alive resends packet A +Time: 150ms → Client sends packet B → Timer resets +Time: 183ms → (no activity) Keep-alive resends packet B +... +``` + +### 2. During Firmware Update (DFU) +``` +Time: 0ms → DFU write #1 → Timer resets +Time: 10ms → DFU write #2 → Timer resets +Time: 20ms → DFU write #3 → Timer resets +... +Result: Keep-alive never fires because writes are too frequent +``` + +## Technical Details + +### Timer Reset Behavior + +The keep-alive timer **resets** whenever: +- A write request is issued (`write` JSON-RPC method) +- A packet is successfully sent + +This means: +- **Idle state** — Keep-alive kicks in after `keepAliveIntervalMs` milliseconds of inactivity +- **Active state** — During firmware updates or frequent communication, keep-alive is effectively paused +- **No explicit disable needed** — The mechanism self-manages based on activity + +### Architecture + +``` +SerialSession (abstract) +├── StartKeepAlive(interval) → Start timer with interval +├── StopKeepAlive() → Stop and dispose timer +├── ResetKeepAliveTimer() → Restart timer (called on write) +└── ResendLastData() → Resend cached packet (called by timer) + +Platform-specific implementation (WinSerialSession, etc.) +├── StartKeepAlive() in DoConnect() +└── StopKeepAlive() in DoDisconnect() +``` + +## Firmware Update Safety + +**Q: Won't keep-alive packets interfere with firmware updates?** + +A: There are two layers of protection. + +**Layer 1 — Automatic (no client change needed).** During an active DFU burst: +1. Each `write` request resets the keep-alive timer. +2. DFU chunks arrive faster than the keep-alive interval, so the timer never expires. +3. The first write after the burst is the only one that re-arms keep-alive. + +**Layer 2 — Explicit toggle (recommended for wireless DFU).** For setups where the bootloader handshake travels over a slow wireless link (e.g. USB dongle → wireless → CPU), there is a brief idle window between "wake bootloader" and the first DFU command where keep-alive *could* fire. Eliminate it by calling `setKeepAlive` to disable keep-alive before bootloader entry and re-enable it after DFU completes: + +```javascript +await link.send("setKeepAlive", { intervalMs: null }); +// ... run DFU ... +await link.send("setKeepAlive", { intervalMs: 33 }); +``` + +See [SerialApiReference.md](SerialApiReference.md#setkeepalive) for the full method spec. + +## Diagnosing Transport Issues + +If you suspect bytes are being dropped, corrupted, or stalled in the Link layer, enable `wireTrace: true` on `connect`: + +```json +{ + "baudRate": 115200, + "peripheralType": "codetinker", + "keepAliveIntervalMs": 33, + "wireTrace": true +} +``` + +Link will emit hex dumps via `Trace.WriteLine` for every TX/RX (including keep-alive resends). View them in [DebugView](https://learn.microsoft.com/sysinternals/downloads/debugview) or an attached debugger. Compare to the client's own message log to pinpoint where data diverges. + +## Troubleshooting + +### Device still times out +- Verify `keepAliveIntervalMs` is set in the connect request +- Check if the device actually requires keep-alive (some devices don't) +- Try a shorter interval (e.g., 25ms instead of 33ms) + +### Excessive resends visible in logs +- This is expected behavior +- Keep-alive packets only resend when there's no other activity +- During normal operation, keep-alive should rarely fire + +### Firmware update hangs or fails +- Ensure the device supports the DFU protocol +- Verify connection parameters (baud rate, etc.) +- Check device logs for error messages + +## Related Features + +### Phase B: Firmware Transport Abstraction +- `FirmwareTransportPort` interface (planned) +- WebSerial adapter (planned) +- WebSocketLink adapter (planned) +- firmware-updater.ts transport-agnostic implementation (planned) + +The keep-alive mechanism works transparently with future firmware update features. + +## Support + +For issues or questions about keep-alive functionality: +1. Check device documentation for timeout requirements +2. Enable debug logging to see keep-alive packets +3. Contact ALUX Labs support + +--- + +**Version**: 1.0 +**Last Updated**: 2026-05-24 +**Affected Devices**: Codetinker, and any device with sub-second timeout requirements diff --git a/Documentation/WindowsDevSetup-VS2026.md b/Documentation/Alux/WindowsDevSetup-VS2026.md similarity index 100% rename from Documentation/WindowsDevSetup-VS2026.md rename to Documentation/Alux/WindowsDevSetup-VS2026.md diff --git a/README.md b/README.md index a04249c2..276c9e32 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,8 @@ scratch-link/ │ ├── ScratchVersion.targets # Git 기반 버전 자동 생성 │ ├── CommonPackageRefs.props # 공유 NuGet 패키지 │ └── StyleCop.props # 코드 스타일 분석 -├── Documentation/ # 프로토콜 문서 (Architecture, Bluetooth, Serial 등) +├── Documentation/ # upstream 원본 프로토콜 문서 +│ └── Alux/ # 이 포크 전용 문서 (upstream 동기화 시 제외) └── brand/ # 아이콘 소스 SVG 및 빌드 스크립트 ``` From 2603512272b11e5abbcae97e4ef90c96d1f39123 Mon Sep 17 00:00:00 2001 From: hksong Date: Mon, 25 May 2026 13:31:58 +0900 Subject: [PATCH 23/94] feat(serial): add peripheralType, thread-safe keep-alive with runtime setKeepAlive, and wireTrace diagnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds three connect-time options and one runtime RPC to the serial transport so that wireless devices like Codetinker — which require "<" 1s between TX packets or they signal a timeout alarm — can be driven safely while still allowing transports that have to send arbitrary byte streams (e.g. firmware update) to suppress the keep-alive on demand. Connect parameters: - peripheralType (string, optional): identifies the device class ("codetinker", "connect", "technic", …). Logged at connect time; reserved for future per-device policy. - keepAliveIntervalMs (int, optional): if set, the most recently sent TX packet is re-sent at this interval to keep the device from timing out during idle periods. Null or non-positive disables. - wireTrace (bool, optional): emits per-write/per-read hex dumps via Trace.WriteLine for transport-level debugging. Off by default. Runtime RPC: - setMode-style toggle via setKeepAlive { intervalMs }: lets the client disable keep-alive before a firmware update (intervalMs=null) and re-enable it after (intervalMs=33). The cached last-TX packet is preserved across the toggle, the call is idempotent, and stopping blocks on any in-flight tick so no resend ever races with a disconnect. Thread-safety: - SemaphoreSlim serializes HandleWrite vs. keep-alive ticks so two DoWrite invocations never overlap and corrupt the stream. - The keep-alive timer fires an async-void callback with skip-on-busy semantics (WaitAsync(0)), making it idle-only — write bursts (DFU chunks) automatically suppress resends until the line goes idle. - HandleWrite resets the timer on every write so the resend never fires mid-burst even at the boundaries. - StopKeepAlive uses Timer.Dispose(WaitHandle) to block until the current tick finishes; ResetKeepAliveTimer swallows ObjectDisposedException for the race window with stop. - Dispose(bool) is overridden to tear down the timer and dispose the semaphore in the correct order; platform subclasses still close their port handle. Structured Trace logs for start, stop, double-start, and resend failure surface keep-alive behaviour in production logs. --- .../Serial/SerialOpenParams.cs | 20 ++ scratch-link-common/Serial/SerialSession.cs | 321 +++++++++++++++++- scratch-link-win/Serial/WinSerialSession.cs | 8 + 3 files changed, 347 insertions(+), 2 deletions(-) diff --git a/scratch-link-common/Serial/SerialOpenParams.cs b/scratch-link-common/Serial/SerialOpenParams.cs index 2b52f66e..4cae9411 100644 --- a/scratch-link-common/Serial/SerialOpenParams.cs +++ b/scratch-link-common/Serial/SerialOpenParams.cs @@ -34,4 +34,24 @@ internal class SerialOpenParams /// Gets or sets the flow control: "none", "rtsCts", or "xonXoff". Defaults to "none". ///

public string FlowControl { get; set; } + + /// + /// Gets or sets the peripheral type (e.g. "codetinker", "connect", "technic"). Optional. + /// + public string PeripheralType { get; set; } + + /// + /// Gets or sets the keep-alive interval in milliseconds. If set, the session will + /// automatically resend the last sent packet at this interval to prevent + /// device timeout. Optional; null disables keep-alive. + /// + public int? KeepAliveIntervalMs { get; set; } + + /// + /// Gets or sets a value indicating whether wire-level TX/RX hex dumps are + /// emitted via for this session. + /// Diagnostic only; off by default. Enable when debugging suspected + /// transport-level corruption or loss. + /// + public bool WireTrace { get; set; } } diff --git a/scratch-link-common/Serial/SerialSession.cs b/scratch-link-common/Serial/SerialSession.cs index b6f9ce01..5b50ba43 100644 --- a/scratch-link-common/Serial/SerialSession.cs +++ b/scratch-link-common/Serial/SerialSession.cs @@ -5,10 +5,12 @@ namespace ScratchLink.Serial; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Text.Json; using System.Text.Json.Serialization; +using System.Threading; using System.Threading.Tasks; using Fleck; using ScratchLink.Extensions; @@ -24,6 +26,24 @@ namespace ScratchLink.Serial; internal abstract class SerialSession : PeripheralSession where TPort : class { + // Coordinates concurrent writes from HandleWrite and keep-alive ticks + // so that two DoWrite invocations never overlap and corrupt the stream. + private readonly SemaphoreSlim writeSemaphore = new SemaphoreSlim(1, 1); + + // Guards keep-alive lifecycle state (timer, interval, lastSentData) + // so that Start/Stop/Reset and the timer callback observe a consistent view. + private readonly object stateLock = new object(); + + private byte[] lastSentData; + private Timer keepAliveTimer; + private int keepAliveIntervalMs; + private bool keepAliveActive; + + // Wire-level TX/RX hex dump for diagnostic builds. Set from connect params. + // volatile so the flag is observed on any thread (HandleWrite, ReadLoop, ticks) + // without taking stateLock for the hot path. + private volatile bool wireTrace; + /// /// Initializes a new instance of the class. /// @@ -36,6 +56,7 @@ public SerialSession(IWebSocketConnection webSocket) this.Handlers["disconnect"] = this.HandleDisconnect; this.Handlers["startReading"] = this.HandleStartReading; this.Handlers["stopReading"] = this.HandleStopReading; + this.Handlers["setKeepAlive"] = this.HandleSetKeepAlive; } /// @@ -67,6 +88,12 @@ protected Task HandleDiscover(string methodName, JsonElement? args) protected override Task DoConnect(TPort port, JsonElement? args) { var openParams = ParseOpenParams(args); + this.wireTrace = openParams.WireTrace; + if (this.wireTrace) + { + Trace.WriteLine("wire-trace: enabled for this session"); + } + return this.DoConnect(port, openParams); } @@ -82,7 +109,10 @@ protected override Task DoConnect(TPort port, JsonElement? args) /// /// Implement the JSON-RPC "write" request. Decodes the base64 payload and - /// forwards to the platform implementation. + /// forwards to the platform implementation. Serializes writes against the + /// keep-alive timer, caches the payload as the most recent TX packet, and + /// resets the keep-alive interval so that idle-only resends are not triggered + /// during active bursts (e.g. firmware updates). /// /// The name of the method being called ("write"). /// A JSON object containing message and encoding. @@ -95,7 +125,29 @@ protected async Task HandleWrite(string methodName, JsonElement? args) } var buffer = EncodingHelpers.DecodeBuffer(args.Value); - var sentBytes = await this.DoWrite(buffer); + + await this.writeSemaphore.WaitAsync().ConfigureAwait(false); + int sentBytes; + try + { + lock (this.stateLock) + { + this.lastSentData = buffer; + } + + this.ResetKeepAliveTimer(); + + if (this.wireTrace) + { + Trace.WriteLine($"wire-trace TX {buffer.Length}B {FormatHex(buffer)}"); + } + + sentBytes = await this.DoWrite(buffer).ConfigureAwait(false); + } + finally + { + this.writeSemaphore.Release(); + } return new Dictionary { ["sentBytes"] = sentBytes }; } @@ -151,6 +203,45 @@ protected virtual Task HandleStopReading(string methodName, JsonElement? return Task.FromResult(new Dictionary()); } + /// + /// Implement the JSON-RPC "setKeepAlive" request. Lets the client toggle or + /// reconfigure keep-alive at runtime — e.g. disable before a firmware update + /// (via intervalMs: null or 0) and re-enable afterwards. + /// Idempotent: calling with the same interval as the current one restarts the + /// timer cleanly; calling with null/0 while disabled is a no-op. + /// + /// The name of the method being called ("setKeepAlive"). + /// A JSON object with intervalMs (int or null). Null/0/negative disables. + /// An object echoing the resulting intervalMs (or null when disabled). + protected Task HandleSetKeepAlive(string methodName, JsonElement? args) + { + int? requested = null; + if (args != null) + { + var prop = args.Value.TryGetProperty("intervalMs"); + if (prop.HasValue && prop.Value.ValueKind != JsonValueKind.Null) + { + requested = prop.Value.GetInt32(); + } + } + + // Always stop first so the request is fully idempotent — repeated calls + // with the same interval rebuild the timer cleanly, and calls with a + // different interval don't leave the old one running. + this.StopKeepAlive(); + + int? applied = null; + if (requested.HasValue && requested.Value > 0) + { + this.StartKeepAlive(requested.Value); + applied = requested.Value; + } + + var appliedText = applied?.ToString() ?? "null"; + Trace.WriteLine($"keep-alive: setKeepAlive applied intervalMs={appliedText}"); + return Task.FromResult(new Dictionary { ["intervalMs"] = applied }); + } + /// /// Report received bytes to the client as a serialDidReceiveData /// notification. The payload is base64-encoded. @@ -159,6 +250,11 @@ protected virtual Task HandleStopReading(string methodName, JsonElement? /// A representing the asynchronous operation. protected async Task DidReceiveData(byte[] data) { + if (this.wireTrace) + { + Trace.WriteLine($"wire-trace RX {data.Length}B {FormatHex(data)}"); + } + var encoded = EncodingHelpers.EncodeBuffer(data, "base64"); await this.SendNotification("serialDidReceiveData", new SerialDataReceived { @@ -210,6 +306,89 @@ protected async Task OnPortDiscovered(TPort port, string path, string displayNam }); } + /// + /// Start the keep-alive timer. When set, the most recently sent TX packet + /// is re-sent at the specified interval to satisfy devices that disconnect + /// on long idle periods (e.g. Codetinker requires < 1s gaps). + /// + /// Interval in milliseconds. Null or non-positive values disable keep-alive. + protected void StartKeepAlive(int? keepAliveIntervalMs) + { + if (keepAliveIntervalMs == null || keepAliveIntervalMs.Value <= 0) + { + return; + } + + var interval = keepAliveIntervalMs.Value; + + lock (this.stateLock) + { + if (this.keepAliveActive) + { + Trace.WriteLine("keep-alive: StartKeepAlive called while already active; ignoring"); + return; + } + + this.keepAliveIntervalMs = interval; + this.keepAliveActive = true; + this.keepAliveTimer = new Timer(this.OnKeepAliveTick, null, interval, interval); + } + + Trace.WriteLine($"keep-alive: started ({interval}ms)"); + } + + /// + /// Stop the keep-alive timer and block until any in-flight callback completes. + /// Safe to call multiple times. + /// + protected void StopKeepAlive() + { + Timer toDispose; + lock (this.stateLock) + { + if (!this.keepAliveActive) + { + return; + } + + this.keepAliveActive = false; + toDispose = this.keepAliveTimer; + this.keepAliveTimer = null; + } + + if (toDispose != null) + { + // Block until any in-flight callback finishes so that no resend + // races against the platform disconnect / port disposal. + using var waitHandle = new ManualResetEvent(false); + if (toDispose.Dispose(waitHandle)) + { + waitHandle.WaitOne(); + } + } + + Trace.WriteLine("keep-alive: stopped"); + } + + /// + /// Release keep-alive resources. Platform subclasses should still override + /// to release their port handles; this base implementation guarantees the + /// keep-alive timer is stopped and the write semaphore is disposed. + /// + /// True if called from . + protected override void Dispose(bool disposing) + { + if (disposing && !this.DisposedValue) + { + // StopKeepAlive blocks on in-flight callbacks, so by the time we + // dispose the semaphore no tick can still be holding it. + this.StopKeepAlive(); + this.writeSemaphore.Dispose(); + } + + base.Dispose(disposing); + } + private static IReadOnlyList ParseFilters(JsonElement? args) { var result = new List(); @@ -253,9 +432,147 @@ private static SerialOpenParams ParseOpenParams(JsonElement? args) Parity = args?.TryGetProperty("parity")?.GetString() ?? "none", StopBits = args?.TryGetProperty("stopBits")?.GetString() ?? "one", FlowControl = args?.TryGetProperty("flowControl")?.GetString() ?? "none", + PeripheralType = args?.TryGetProperty("peripheralType")?.GetString(), + KeepAliveIntervalMs = args?.TryGetProperty("keepAliveIntervalMs")?.GetInt32(), + WireTrace = args?.TryGetProperty("wireTrace")?.GetBoolean() ?? false, }; } + /// + /// Format a byte buffer as a space-separated, lowercase hex string for diagnostic + /// logs. Long buffers are truncated to the first bytes + /// with a tail marker indicating how many bytes were elided, so trace lines stay + /// bounded even on large transfers (e.g. firmware update chunks). + /// + /// Buffer to format. May be empty; must not be null. + /// Maximum number of bytes to render verbatim before truncation. + /// Hex preview suitable for . + private static string FormatHex(byte[] data, int maxBytes = 256) + { + if (data == null || data.Length == 0) + { + return string.Empty; + } + + var take = data.Length <= maxBytes ? data.Length : maxBytes; + var sb = new System.Text.StringBuilder(take * 3); + for (var i = 0; i < take; i++) + { + if (i > 0) + { + sb.Append(' '); + } + + sb.Append(data[i].ToString("x2", System.Globalization.CultureInfo.InvariantCulture)); + } + + if (data.Length > take) + { + sb.Append($" …(+{data.Length - take}B)"); + } + + return sb.ToString(); + } + + /// + /// Reset the keep-alive timer to fire one full interval from now. + /// Called from so that bursts of writes + /// (e.g. firmware update chunks) suppress the resend until the line goes idle. + /// + private void ResetKeepAliveTimer() + { + Timer timer; + int interval; + lock (this.stateLock) + { + if (!this.keepAliveActive || this.keepAliveTimer == null) + { + return; + } + + timer = this.keepAliveTimer; + interval = this.keepAliveIntervalMs; + } + + try + { + timer.Change(interval, interval); + } + catch (ObjectDisposedException) + { + // Raced with StopKeepAlive; the timer is gone, nothing to do. + } + } + + /// + /// Timer callback that resends the last TX packet. Skips silently if another + /// write is already in progress, if the session is no longer connected, or + /// if no packet has been sent yet. + /// + private async void OnKeepAliveTick(object state) + { + byte[] data; + lock (this.stateLock) + { + if (!this.keepAliveActive) + { + return; + } + + data = this.lastSentData; + } + + if (data == null || data.Length == 0 || !this.IsConnected) + { + return; + } + + // Skip if a real write (or another tick) holds the semaphore. This is + // what makes keep-alive idle-only: during a write burst the semaphore + // is busy and ticks no-op. + if (!await this.writeSemaphore.WaitAsync(0).ConfigureAwait(false)) + { + return; + } + + try + { + // Re-check after acquiring the lock; state may have changed while waiting. + if (!this.keepAliveActive || !this.IsConnected) + { + return; + } + + if (this.wireTrace) + { + Trace.WriteLine($"wire-trace TX(keep-alive) {data.Length}B {FormatHex(data)}"); + } + + await this.DoWrite(data).ConfigureAwait(false); + } + catch (ObjectDisposedException) + { + // Session disposed mid-tick; safe to ignore. + } + catch (Exception e) + { + // Never let exceptions escape an async-void Timer callback or the + // process will terminate. Log and let the next tick try again. + Trace.WriteLine($"keep-alive: resend failed: {e.GetType().Name}: {e.Message}"); + } + finally + { + try + { + this.writeSemaphore.Release(); + } + catch (ObjectDisposedException) + { + // Semaphore disposed during shutdown; safe to ignore. + } + } + } + /// /// Payload of a serialDidReceiveData notification. /// diff --git a/scratch-link-win/Serial/WinSerialSession.cs b/scratch-link-win/Serial/WinSerialSession.cs index 06cf5c58..9b6bd2e1 100644 --- a/scratch-link-win/Serial/WinSerialSession.cs +++ b/scratch-link-win/Serial/WinSerialSession.cs @@ -66,6 +66,11 @@ protected override Task DoConnect(WinSerialPortInfo info, SerialOpenPara throw JsonRpc2Error.InvalidRequest("already connected").ToException(); } + if (!string.IsNullOrEmpty(openParams.PeripheralType)) + { + Trace.WriteLine($"Connecting to {info.Path} with peripheral type: {openParams.PeripheralType}"); + } + try { this.port = new SerialPort(info.Path) @@ -95,6 +100,8 @@ protected override Task DoConnect(WinSerialPortInfo info, SerialOpenPara var token = this.rxCts.Token; this.rxLoop = Task.Run(() => this.ReadLoop(token)); + this.StartKeepAlive(openParams.KeepAliveIntervalMs); + return Task.FromResult(new Dictionary()); } @@ -126,6 +133,7 @@ protected override async Task DoWrite(byte[] data) /// protected override async Task DoDisconnect() { + this.StopKeepAlive(); var loop = this.rxLoop; this.CloseConnectionSilently(); From 3cfaf7cce9995000ca2a68bda44d8a54183b6146 Mon Sep 17 00:00:00 2001 From: hksong Date: Mon, 25 May 2026 13:32:30 +0900 Subject: [PATCH 24/94] fix(serial): serialize SerialPort Read/Write with BytesToRead polling to eliminate driver race MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .NET 8 SerialPort + CH340/CP210x drivers throw spurious TimeoutException on the read side whenever a Write fires while a blocking Read is in flight, regardless of whether the Write uses BaseStream.WriteAsync or the synchronous SerialPort.Write. Symptom in production: with keep-alive on at 33ms, the burst comes at the write cadence and the client disconnects after ~1.4s, breaking wireless DFU. Diagnosed by disabling keep-alive — the burst disappears and only normal 500ms idle timeouts remain (caught and ignored). Fix: guarantee Read and Write are never in flight at the same time on the same handle. ReadLoop: - Poll SerialPort.BytesToRead (a cheap status query that does not hold the I/O surface) and only call Read when bytes are actually available, so Read returns immediately rather than blocking on a timeout. - Read is wrapped in ioLock so it never overlaps DoWrite. - When idle, wait on the cancellation token's WaitHandle for ~10ms instead of issuing a blocking Read; this also removes the cosmetic 500ms idle TimeoutException spam previously seen in the debugger. DoWrite: - Switch from BaseStream.WriteAsync to the synchronous SerialPort.Write so Read and Write travel through the same SerialPort cache layer rather than mixing BaseStream and cache-layer APIs. - Wrap the synchronous Write in ioLock and dispatch on the ThreadPool via Task.Run to preserve the async signature. - Re-check IsOpen inside the lock; catch InvalidOperationException (which the synchronous Write can throw on a closed port) and map it to the existing invalid-request error path. Because ReadLoop only acquires ioLock when data is present, the lock hold time is dominated by the immediate-return Read; keep-alive writes at 33ms see sub-millisecond contention. Verified in production with both wired and wireless (USB dongle) DFU: the TimeoutException burst is gone, bootloader entry succeeds, and post-firmware reinit reconnects cleanly. --- scratch-link-win/Serial/WinSerialSession.cs | 105 ++++++++++++++++++-- 1 file changed, 98 insertions(+), 7 deletions(-) diff --git a/scratch-link-win/Serial/WinSerialSession.cs b/scratch-link-win/Serial/WinSerialSession.cs index 9b6bd2e1..d319eeef 100644 --- a/scratch-link-win/Serial/WinSerialSession.cs +++ b/scratch-link-win/Serial/WinSerialSession.cs @@ -22,6 +22,15 @@ namespace ScratchLink.Win.Serial; /// internal class WinSerialSession : SerialSession { + // Serializes SerialPort.Read and SerialPort.Write so the two never run + // concurrently on the same handle. .NET 8 SerialPort + CH340/CP210x driver + // combinations produce a TimeoutException burst on the read side whenever + // a write fires during an active blocking Read, even with ReadTimeout=500 + // and the synchronous Write API. Pairing this with BytesToRead polling + // (only call Read when data is actually available) keeps the lock held + // for a very short time, so keep-alive writes are not noticeably delayed. + private readonly object ioLock = new object(); + private SerialPort port; private CancellationTokenSource rxCts; private Task rxLoop; @@ -114,14 +123,38 @@ protected override async Task DoWrite(byte[] data) throw JsonRpc2Error.InvalidRequest("cannot write when not connected").ToException(); } + // Use the synchronous SerialPort.Write under ioLock so that it cannot + // overlap with a concurrent SerialPort.Read in ReadLoop. Mixing the + // two on the same handle (with any combination of sync/async APIs) + // causes the read side to throw TimeoutException bursts at the write + // cadence — observed at 33 ms with keep-alive enabled and the cause + // of DFU breakage on devices like Codetinker. ReadLoop only enters + // the lock when BytesToRead > 0 so this lock is held very briefly + // and keep-alive writes are not noticeably delayed. try { - await currentPort.BaseStream.WriteAsync(data, 0, data.Length); + await Task.Run(() => + { + lock (this.ioLock) + { + if (!currentPort.IsOpen) + { + throw new InvalidOperationException("port closed"); + } + + currentPort.Write(data, 0, data.Length); + } + }).ConfigureAwait(false); } catch (ObjectDisposedException) { throw JsonRpc2Error.InternalError("write failed: port was disposed").ToException(); } + catch (InvalidOperationException) + { + // Port was closed between the IsOpen check above and Write. + throw JsonRpc2Error.InvalidRequest("cannot write when not connected").ToException(); + } catch (IOException e) { throw JsonRpc2Error.InternalError($"write failed: {e.Message}").ToException(); @@ -198,18 +231,76 @@ private void ReadLoop(CancellationToken ct) break; } + // Poll BytesToRead instead of issuing a blocking Read with a timeout. + // A blocking Read holds the SerialPort I/O surface and races with any + // concurrent Write (e.g. the keep-alive timer), producing spurious + // TimeoutException bursts that look like the read loop is dying. + // BytesToRead is a cheap status query that does not hold the I/O + // surface, so the loop only enters the critical section (under + // ioLock) when data is actually available, and Read returns + // immediately because we know there's something to drain. + int available; + try + { + available = currentPort.BytesToRead; + } + catch (ObjectDisposedException) + { + // Derives from InvalidOperationException; catch first. + break; + } + catch (InvalidOperationException) + { + break; + } + catch (IOException) when (ct.IsCancellationRequested) + { + break; + } + catch (IOException e) + { + Trace.WriteLine($"Serial BytesToRead IOException on {currentPort.PortName}: {e.Message}"); + _ = this.DidDisconnect("device", e.Message); + this.CloseConnectionSilently(); + break; + } + + if (available <= 0) + { + // Idle. Sleep briefly so we don't spin the CPU; cancellation + // is observed via the token. + try + { + if (ct.WaitHandle.WaitOne(10)) + { + break; + } + } + catch (ObjectDisposedException) + { + break; + } + + continue; + } + int n; try { - // SerialPort.BaseStream.ReadAsync on .NET 6 reliably throws - // ERROR_OPERATION_ABORTED on the first call against CH340 ports - // (even without a CancellationToken, even with DTR/RTS pinned low). - // Use the synchronous Read with a finite ReadTimeout so the loop - // wakes periodically and shutdown can be observed via ct. - n = currentPort.Read(buf, 0, buf.Length); + lock (this.ioLock) + { + if (!currentPort.IsOpen) + { + break; + } + + n = currentPort.Read(buf, 0, Math.Min(available, buf.Length)); + } } catch (TimeoutException) { + // Defensive: shouldn't happen now that we only Read when data is available, + // but keep the safety net. continue; } catch (OperationCanceledException) From 6c2fa1bbec7ff32407876a1f0c12767fa32bb04b Mon Sep 17 00:00:00 2001 From: hksong Date: Mon, 25 May 2026 13:38:36 +0900 Subject: [PATCH 25/94] =?UTF-8?q?chore:=20CHANGELOG.md=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20=EB=B0=8F=20CLAUDE.md=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit upstream 자동 생성 변경 이력 파일을 제거하고, 이 프로젝트에 맞는 Claude 행동 규칙 문서(CLAUDE.md)를 추가한다. --- CHANGELOG.md | 497 --------------------------------------------------- CLAUDE.md | 97 ++++++++++ 2 files changed, 97 insertions(+), 497 deletions(-) delete mode 100644 CHANGELOG.md create mode 100644 CLAUDE.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 43748a8b..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,497 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. See -[Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -# [2.1.0-develop.10](https:/home/circleci/project/semantic-release-remote/compare/v2.1.0-develop.9...v2.1.0-develop.10) (2023-09-25) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.6.10 ([911bbba](https:/home/circleci/project/semantic-release-remote/commit/911bbbab8a4ff484a450e688b5953a3fd3a4e7d3)) -* **deps:** update dependency scratch-vm to v1.6.11 ([5544897](https:/home/circleci/project/semantic-release-remote/commit/5544897487c66def49af50c1a07e65c75af86335)) -* **deps:** update dependency scratch-vm to v1.6.12 ([5948b02](https:/home/circleci/project/semantic-release-remote/commit/5948b02473773f33f581a9731a28f86a26612881)) -* **deps:** update dependency scratch-vm to v1.6.13 ([31bc061](https:/home/circleci/project/semantic-release-remote/commit/31bc061932429a387a607256d6a37355ea6bf6a2)) -* **deps:** update dependency scratch-vm to v1.6.14 ([1323ac0](https:/home/circleci/project/semantic-release-remote/commit/1323ac0d39ea4f68bcd0a39621cae87ce1e42507)) -* **deps:** update dependency scratch-vm to v1.6.15 ([9d9a801](https:/home/circleci/project/semantic-release-remote/commit/9d9a8014727aa23601e42292d3d6f423eb164f53)) -* **deps:** update dependency scratch-vm to v1.6.16 ([b2d429e](https:/home/circleci/project/semantic-release-remote/commit/b2d429e426416ebef6e32183df68fbae8dbb2c3c)) -* **deps:** update dependency scratch-vm to v1.6.17 ([239e35a](https:/home/circleci/project/semantic-release-remote/commit/239e35a28f27ce7686a36831cf8f098954e1a1be)) -* **deps:** update dependency scratch-vm to v1.6.18 ([9bb27fa](https:/home/circleci/project/semantic-release-remote/commit/9bb27fa0c5d5d74cc8d9e1486cb130fff27b7a74)) -* **deps:** update dependency scratch-vm to v1.6.19 ([8a72117](https:/home/circleci/project/semantic-release-remote/commit/8a7211749f93ad2b1b9f563dc19d8a109ab33090)) - -# [2.1.0-develop.9](https:/home/circleci/project/semantic-release-remote/compare/v2.1.0-develop.8...v2.1.0-develop.9) (2023-09-09) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.6.9 ([d6db186](https:/home/circleci/project/semantic-release-remote/commit/d6db1861a274be97474a4a0a3f89ec4a51b2dde6)) - -# [2.1.0-develop.8](https:/home/circleci/project/semantic-release-remote/compare/v2.1.0-develop.7...v2.1.0-develop.8) (2023-09-02) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.6.8 ([e0f852d](https:/home/circleci/project/semantic-release-remote/commit/e0f852d8eb165e93cb181cc36c84bd0c21ccb27a)) - -# [2.1.0-develop.7](https:/home/circleci/project/semantic-release-remote/compare/v2.1.0-develop.6...v2.1.0-develop.7) (2023-08-30) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.6.7 ([21a5e3d](https:/home/circleci/project/semantic-release-remote/commit/21a5e3d69882a6f1f683d5b84ca4cde08b48cb10)) - -# [2.1.0-develop.6](https:/home/circleci/project/semantic-release-remote/compare/v2.1.0-develop.5...v2.1.0-develop.6) (2023-08-28) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.6.6 ([9365bad](https:/home/circleci/project/semantic-release-remote/commit/9365bad80e094d09a55e12f0fc1cd299714745be)) - -# [2.1.0-develop.5](https:/home/circleci/project/semantic-release-remote/compare/v2.1.0-develop.4...v2.1.0-develop.5) (2023-08-27) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.6.5 ([97159bb](https:/home/circleci/project/semantic-release-remote/commit/97159bbabae791f1848795765444b414221dfc9d)) - -# [2.1.0-develop.4](https:/home/circleci/project/semantic-release-remote/compare/v2.1.0-develop.3...v2.1.0-develop.4) (2023-08-23) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.6.4 ([78f868b](https:/home/circleci/project/semantic-release-remote/commit/78f868b724a0e3bcc28e80f7d4e82965f461c95d)) - -# [2.1.0-develop.3](https:/home/circleci/project/semantic-release-remote/compare/v2.1.0-develop.2...v2.1.0-develop.3) (2023-08-21) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.6.2 ([9cb3de7](https:/home/circleci/project/semantic-release-remote/commit/9cb3de7d5589a7e4b68e984655b5173dadabed24)) -* **deps:** update dependency scratch-vm to v1.6.3 ([c325210](https:/home/circleci/project/semantic-release-remote/commit/c325210a8c8cdf4f94896d39998bbddf2fc1b9f9)) - -# [2.1.0-develop.2](https:/home/circleci/project/semantic-release-remote/compare/v2.1.0-develop.1...v2.1.0-develop.2) (2023-08-09) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.6.1 ([eeba9f3](https:/home/circleci/project/semantic-release-remote/commit/eeba9f36fef825e1cbd02322db488cc75f467049)) - -# [2.1.0-develop.1](https:/home/circleci/project/semantic-release-remote/compare/v2.0.3-develop.8...v2.1.0-develop.1) (2023-08-08) - - -### Features - -* **deps:** update dependency scratch-vm to v1.6.0 ([f85e72c](https:/home/circleci/project/semantic-release-remote/commit/f85e72c48afbe1f4ae95b83f8166b6b0afd06751)) - -## [2.0.3-develop.8](https:/home/circleci/project/semantic-release-remote/compare/v2.0.3-develop.7...v2.0.3-develop.8) (2023-08-08) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.98 ([42d8912](https:/home/circleci/project/semantic-release-remote/commit/42d8912b824ed9c18f9a5585050df77d77057d8f)) - -## [2.0.3-develop.7](https:/home/circleci/project/semantic-release-remote/compare/v2.0.3-develop.6...v2.0.3-develop.7) (2023-08-06) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.97 ([490155c](https:/home/circleci/project/semantic-release-remote/commit/490155c249ea5495081d16681540feec5471be88)) - -## [2.0.3-develop.6](https:/home/circleci/project/semantic-release-remote/compare/v2.0.3-develop.5...v2.0.3-develop.6) (2023-08-05) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.96 ([9a46cbd](https:/home/circleci/project/semantic-release-remote/commit/9a46cbdd45d6f0955d070e5b1c2c75e343deef6a)) - -## [2.0.3-develop.5](https:/home/circleci/project/semantic-release-remote/compare/v2.0.3-develop.4...v2.0.3-develop.5) (2023-08-04) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.95 ([71a0b81](https:/home/circleci/project/semantic-release-remote/commit/71a0b81b456b5b60a84011a76c209a1074776697)) - -## [2.0.3-develop.4](https:/home/circleci/project/semantic-release-remote/compare/v2.0.3-develop.3...v2.0.3-develop.4) (2023-08-03) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.94 ([414055a](https:/home/circleci/project/semantic-release-remote/commit/414055a3cd3824379dde09c5a34a41658b372bc9)) - -## [2.0.3-develop.3](https:/home/circleci/project/semantic-release-remote/compare/v2.0.3-develop.2...v2.0.3-develop.3) (2023-08-02) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.93 ([cd024c6](https:/home/circleci/project/semantic-release-remote/commit/cd024c6698914ef7ff8854f10753ff2ff13f2e8c)) - -## [2.0.3-develop.2](https:/home/circleci/project/semantic-release-remote/compare/v2.0.3-develop.1...v2.0.3-develop.2) (2023-08-01) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.92 ([26f1c6a](https:/home/circleci/project/semantic-release-remote/commit/26f1c6ae250ed240a5159a20a634264bfd98480b)) - -## [2.0.3-develop.1](https:/home/circleci/project/semantic-release-remote/compare/v2.0.2...v2.0.3-develop.1) (2023-07-27) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.43 ([b75b289](https:/home/circleci/project/semantic-release-remote/commit/b75b2896a580e76282344e8b5c6ee404de85adfa)) -* **deps:** update dependency scratch-vm to v1.5.91 ([524712f](https:/home/circleci/project/semantic-release-remote/commit/524712fa1716ac952f984511c18ab8d53f2155ae)) -* **win:** apply the calculated version number to packaging output ([57a6ebc](https:/home/circleci/project/semantic-release-remote/commit/57a6ebc1df4e7bf32e599e4b6a93b149f3f34053)) -* **WinBLE:** disconnect event handlers during session dispose ([3b15ac5](https:/home/circleci/project/semantic-release-remote/commit/3b15ac5e3988b6596eb1c3d6417dca89e68a38f8)) -* **Win:** fix sizing problem in context menu ([c35c934](https:/home/circleci/project/semantic-release-remote/commit/c35c93496a58349c0fd9b0341a23a94cb4107e36)) - -## [2.0.2-develop.4](https:/home/circleci/project/semantic-release-remote/compare/v2.0.2-develop.3...v2.0.2-develop.4) (2023-07-26) - - -### Bug Fixes - -* **win:** apply the calculated version number to packaging output ([57a6ebc](https:/home/circleci/project/semantic-release-remote/commit/57a6ebc1df4e7bf32e599e4b6a93b149f3f34053)) - -## [2.0.2-develop.3](https:/home/circleci/project/semantic-release-remote/compare/v2.0.2-develop.2...v2.0.2-develop.3) (2023-07-05) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.43 ([b75b289](https:/home/circleci/project/semantic-release-remote/commit/b75b2896a580e76282344e8b5c6ee404de85adfa)) - -## [2.0.2-develop.2](https:/home/circleci/project/semantic-release-remote/compare/v2.0.2-develop.1...v2.0.2-develop.2) (2023-06-09) - - -### Bug Fixes - -* **Win:** fix sizing problem in context menu ([c35c934](https:/home/circleci/project/semantic-release-remote/commit/c35c93496a58349c0fd9b0341a23a94cb4107e36)) - -## [2.0.2-develop.1](https:/home/circleci/project/semantic-release-remote/compare/v2.0.1...v2.0.2-develop.1) (2023-06-08) - - -### Bug Fixes - -* **WinBLE:** disconnect event handlers during session dispose ([3b15ac5](https:/home/circleci/project/semantic-release-remote/commit/3b15ac5e3988b6596eb1c3d6417dca89e68a38f8)) - -## [2.0.1](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0...v2.0.1) (2023-05-25) - - -### Bug Fixes - -* **mac:** even more versioning fixes ([07c035d](https:/home/circleci/project/semantic-release-remote/commit/07c035dea84a16ce02368cc1bb5f7f32ff1b3885)) - -# [2.0.0](https:/home/circleci/project/semantic-release-remote/compare/v1.4.0...v2.0.0) (2023-05-25) - - -### Bug Fixes - -* always call context.completeRequest, even when not returning a value ([9cabb03](https:/home/circleci/project/semantic-release-remote/commit/9cabb03495b089cdc23fb257a0c3fea7e603c225)) -* **build:** fix missing CFBundleVersion in Safari extension ([7a67ea1](https:/home/circleci/project/semantic-release-remote/commit/7a67ea18025396c26a359f435a2c1cb1ed7ab8c3)) -* calculate build number from label ([2eb8015](https:/home/circleci/project/semantic-release-remote/commit/2eb8015d457263111219f2fc4a5e7d5505c6efb4)) -* **ci:** speculative fix for Homebrew failing on CI ([4b12ce4](https:/home/circleci/project/semantic-release-remote/commit/4b12ce4d1501eaea92ee76c1e11fc808ccc7ad11)) -* **ci:** update VS Mac installer script for 17.4 ([9221e1e](https:/home/circleci/project/semantic-release-remote/commit/9221e1e68a0c5cb8e35777c914fd9e17e954a5d7)) -* **common:** make session immediately so we don't miss the first message ([d53d5c8](https:/home/circleci/project/semantic-release-remote/commit/d53d5c8a9dd02563c5e75208cfc7125386d5f85a)) -* **common:** remove `EventAwaiter(EventHandler, ...` ([9032a01](https:/home/circleci/project/semantic-release-remote/commit/9032a013c8b5dc967f5a53a50546499b55af6b55)) -* **deps:** update dependency scratch-vm to v1.5.28 ([441b7fd](https:/home/circleci/project/semantic-release-remote/commit/441b7fdf3572b093d3b4c0c1022e5472dbcdaff9)) -* **deps:** update dependency scratch-vm to v1.5.31 ([2c60027](https:/home/circleci/project/semantic-release-remote/commit/2c60027674e6cb3f0942d2c380b01b765bef12f8)) -* **deps:** update dependency scratch-vm to v1.5.32 ([964a53f](https:/home/circleci/project/semantic-release-remote/commit/964a53f0ed1e594d1cf3e983c9830402ce743f05)) -* **deps:** update dependency scratch-vm to v1.5.33 ([1c3a4cf](https:/home/circleci/project/semantic-release-remote/commit/1c3a4cfd0b13ca938cd53b44e26491415ea80e43)) -* **deps:** update dependency scratch-vm to v1.5.34 ([b19fe2a](https:/home/circleci/project/semantic-release-remote/commit/b19fe2a64639e4ff17cd965d82965bfea6ce0603)) -* **deps:** update dependency scratch-vm to v1.5.35 ([7543466](https:/home/circleci/project/semantic-release-remote/commit/7543466407de1f1f297afd148f07036bd977109b)) -* **deps:** update dependency scratch-vm to v1.5.36 ([cbc0e7c](https:/home/circleci/project/semantic-release-remote/commit/cbc0e7ca8f472199acc52a2e408a878e462d0240)) -* **deps:** update dependency scratch-vm to v1.5.37 ([79af6ab](https:/home/circleci/project/semantic-release-remote/commit/79af6ab191eb881c14e0403a5524c4da42e865d6)) -* **deps:** update dependency scratch-vm to v1.5.38 ([f200619](https:/home/circleci/project/semantic-release-remote/commit/f2006198489bc938ce4c46ec879fe4d182ec8c5f)) -* **deps:** update dependency scratch-vm to v1.5.40 ([f2b6787](https:/home/circleci/project/semantic-release-remote/commit/f2b67876984b75fca7286902be800d584959f58a)) -* **deps:** update dependency scratch-vm to v1.5.41 ([5e25dba](https:/home/circleci/project/semantic-release-remote/commit/5e25dba6cceb03df542aa1e4d920326f3f0b534e)) -* **deps:** update dependency scratch-vm to v1.5.42 ([7d8d1b2](https:/home/circleci/project/semantic-release-remote/commit/7d8d1b25a873866aef4cf9fe12a664ab94ada90d)) -* disable BLE restore to fix 'Bluetooth unavailable' issue ([8fdc3d1](https:/home/circleci/project/semantic-release-remote/commit/8fdc3d166edb6fb49b25ed2f467a0f77227dc630)) -* dispose of cbManager on session shutdown ([5423e78](https:/home/circleci/project/semantic-release-remote/commit/5423e7800ba21bdb50874d23a88d0cee64c2c54d)) -* don't embed IOBluetooth.framework ([563070d](https:/home/circleci/project/semantic-release-remote/commit/563070d67e5a88cc96a196759f2d2b59b0f4706b)) -* **extension:** inject project marketing version into web extension manifest ([6aa609d](https:/home/circleci/project/semantic-release-remote/commit/6aa609d100961b7f74f4345c28137393988a2835)) -* fix DisposedException by removing cancellation token ([eed937f](https:/home/circleci/project/semantic-release-remote/commit/eed937fd185f58295733e63dc8879a32e5a5ee10)) -* fix minor MAS compliance issues ([149076c](https:/home/circleci/project/semantic-release-remote/commit/149076c07aa6c6e725e09130ee23a397b3e6e9eb)) -* generate icons directly from SVGs for better quality ([8d3b8ce](https:/home/circleci/project/semantic-release-remote/commit/8d3b8ce38a1000552d92bdce7da1cf98fbd9b134)) -* implement a BT connection dance that works on macOS 10 and 12 ([159ca00](https:/home/circleci/project/semantic-release-remote/commit/159ca006789956de12e4282b2d088217eb5bb17a)) -* **Mac:** add real Bluetooth permissions request messages ([39cdf3c](https:/home/circleci/project/semantic-release-remote/commit/39cdf3cd509a1c475dbc80b08d919607a6ac1f22)) -* **Mac:** add real icons for Safari extension ([f081c71](https:/home/circleci/project/semantic-release-remote/commit/f081c7130d97a86f55259bd76eef4fdd51bd1856)) -* **MacBLE:** allow more time for the Bluetooth state to settle ([d2c1cf9](https:/home/circleci/project/semantic-release-remote/commit/d2c1cf97845060e88a00d69a66c13580abb7c74e)) -* **macBLE:** fix 'API MISUSE' log message ([b46f435](https:/home/circleci/project/semantic-release-remote/commit/b46f4359f6ed9feb8734cfbc66d9936af6303201)) -* **macBLE:** handle UpdatedState even if it fires during CBCentralManager ctor ([d2df409](https:/home/circleci/project/semantic-release-remote/commit/d2df40995861311b02875c03c2f2151038e3c8e5)) -* **macBT:** add 'Options' / PIN instructions to pairing dialog ([d58f5d2](https:/home/circleci/project/semantic-release-remote/commit/d58f5d243aeafb7756c987350b439b698c7eaa7d)) -* **MacBT:** dispose of inquiry & channel properly ([b3c48ef](https:/home/circleci/project/semantic-release-remote/commit/b3c48ef1662a93776e68181a5e745a4b88b9670d)) -* **MacBT:** make BT disconnect/reconnect more reliable, especially after pairing ([53bbe3b](https:/home/circleci/project/semantic-release-remote/commit/53bbe3b6e39fc9b27bf11119c888c4b36a39771c)) -* **macBT:** poll to reliably detect RFCOMM channel open ([d42cfdb](https:/home/circleci/project/semantic-release-remote/commit/d42cfdb63751ce511f2053ff4130e2a41b99a751)) -* **Mac:** correct target macOS version ([71e7a13](https:/home/circleci/project/semantic-release-remote/commit/71e7a1303397c7138604131c89bbdcf5793adc9a)) -* **Mac:** embed Safari helper extension into the Scratch Link app bundle ([9c6bb30](https:/home/circleci/project/semantic-release-remote/commit/9c6bb30273b4597e1e3ddd451167cffe6231a854)) -* **mac:** fix CI artifact renaming ([7a05fdd](https:/home/circleci/project/semantic-release-remote/commit/7a05fdda50fc7a498bbdc6d4068cf305177669b7)) -* **Mac:** fix Safari, especially Link->Client notifications ([5bae1ea](https:/home/circleci/project/semantic-release-remote/commit/5bae1ea319dd96eed6a92074a1ba59ecdaca89ca)) -* **mac:** fix tccd error message about kTCCServiceAppleEvents ([bdfc8c0](https:/home/circleci/project/semantic-release-remote/commit/bdfc8c08a6caae205e599b9cca28aedc627d1589)) -* **Mac:** hide Safari extensions for non-MAS builds ([58138c5](https:/home/circleci/project/semantic-release-remote/commit/58138c5c89d17ff6d4dfd40d1bfa3ad95c88f27b)) -* **Mac:** make sure GetSettledBluetoothState() doesn't miss an event ([124b6a0](https:/home/circleci/project/semantic-release-remote/commit/124b6a0cef58bd027249656ac4d183f76454d8f5)) -* **Mac:** properly Dispose() of the status bar item ([4cb46b5](https:/home/circleci/project/semantic-release-remote/commit/4cb46b56588d74cd8cf54e79f36a7a6fafe53f59)) -* **Mac:** remove browser_action popup ([9717935](https:/home/circleci/project/semantic-release-remote/commit/971793558fdf949622c79e28db93dd43083c8938)) -* **Mac:** Safari extension improvements ([14f9f99](https:/home/circleci/project/semantic-release-remote/commit/14f9f99b8cb25e7704e53f31f6589f7205b4c66a)) -* **Mac:** show Safari extension menu only if supported ([d019142](https:/home/circleci/project/semantic-release-remote/commit/d01914241789fc639def818f8553799b2915c198)) -* make CI robust against VS updates ([950d3de](https:/home/circleci/project/semantic-release-remote/commit/950d3deb307226403b537874cadb1f64d2886ac6)) -* make didDiscoverPeripheral a notification ([e51fa01](https:/home/circleci/project/semantic-release-remote/commit/e51fa01b799fcc2c9030a66c4bfe448f4aabbc08)) -* **menu:** 'Manage Safari Extensions' => 'Manage Safari Extensions...' ([dc5c481](https:/home/circleci/project/semantic-release-remote/commit/dc5c48127842be5e3f756f077a0d1e284d1002e8)) -* more BT connection tweaks ([7a1e0d0](https:/home/circleci/project/semantic-release-remote/commit/7a1e0d014a05f3af968d998c2caf888987501618)) -* resolve crash on session close while connecting ([32f8981](https:/home/circleci/project/semantic-release-remote/commit/32f89814873eb19045cffcfe40a3c96f70bce54b)) -* **Safari:** add timeout for initial connection ([e1c9de0](https:/home/circleci/project/semantic-release-remote/commit/e1c9de00f1dbf55c1da8bd2bd935f23015b34450)) -* **Safari:** close session if Scratch Link goes away ([83f85f0](https:/home/circleci/project/semantic-release-remote/commit/83f85f028996d12e2a7d6f2b6c4f93608d60bef8)) -* **safari:** don't cause Safari to steal focus for every Scratch Link -> page message ([f17184f](https:/home/circleci/project/semantic-release-remote/commit/f17184f5a1e163232a0ee76133cd2953bb382a0d)) -* use semantic-release version for build ([17709dd](https:/home/circleci/project/semantic-release-remote/commit/17709dd709a59a1b4d5fa10b4a4ed50834ffd893)) -* **version:** embed GitVersion info correctly and document version scheme ([6501e49](https:/home/circleci/project/semantic-release-remote/commit/6501e49073ac852e71ccd048973fb7b5a383c506)) -* **webextension:** close session on client unload ([caac99e](https:/home/circleci/project/semantic-release-remote/commit/caac99e9c0fa15a940642dc5c9063dba45a40b5f)) -* **webextension:** keep Safari sessions alive for longer than 5 seconds ([4981508](https:/home/circleci/project/semantic-release-remote/commit/498150869982c3d21f5463cf646e337fd789b970)) -* **webextension:** limit number of outstanding poll requests ([c5137bb](https:/home/circleci/project/semantic-release-remote/commit/c5137bb7a06c1701592669196508ae9b26ee97be)) -* **win:** build framework-dependent AnyCPU for further install size reduction ([b1f776c](https:/home/circleci/project/semantic-release-remote/commit/b1f776c19f07652ea09c3152325a35578f9fdcf1)) -* **win:** discover both paired and unpaired BT devices ([23ff634](https:/home/circleci/project/semantic-release-remote/commit/23ff634560930041ebb66ae6476839825bb713ba)) -* **win:** don't crash if BT connect fails ([522f65f](https:/home/circleci/project/semantic-release-remote/commit/522f65f199741e2e704f716952a2db8c7508640f)) -* **windows:** fix *.msixupload generation ([3a1c172](https:/home/circleci/project/semantic-release-remote/commit/3a1c1727bcfbe46aa549a4c15b3b0f7e750b0527)) -* **windows:** fix incorrect root namespace ([e25a604](https:/home/circleci/project/semantic-release-remote/commit/e25a604be0238ef3501447df411c7816aea31f26)) -* **windows:** implement WinBLESession.Dispose ([9a0e1f7](https:/home/circleci/project/semantic-release-remote/commit/9a0e1f7ec1202ae24abc5ca988c4fa54c822bffd)) -* **Win:** fix larger icon sizes being ignored sometimes ([e79252f](https:/home/circleci/project/semantic-release-remote/commit/e79252f2ddf2e15987aab8e2205a95aceaa80cb1)) -* **Win:** set assembly attributes including version info ([8379c15](https:/home/circleci/project/semantic-release-remote/commit/8379c153d9b4273bf0e2814a3ebf6be3f2d3e260)) -* **win:** set WindowsPackageType=None to fix debugging ([4b151e1](https:/home/circleci/project/semantic-release-remote/commit/4b151e1884915a39f059d696a968557f04e4ff7b)) -* work around macOS 12 OpenRfcommChannelSync timeout ([68e7efc](https:/home/circleci/project/semantic-release-remote/commit/68e7efc069e8188dd7ee4d0b0e5deff43d7bdd14)) - - -### chore - -* clean slate for Scratch Link 2.0 ([f30cff3](https:/home/circleci/project/semantic-release-remote/commit/f30cff3e5b0fbd2fda423e8609cbd6576c45131a)) - - -### Features - -* add Windows tray icon ([29b961b](https:/home/circleci/project/semantic-release-remote/commit/29b961b8bb86070fb67012def05f195b75438086)) -* **MacBT:** display pairing help when connecting to unpaired peripheral ([feb100e](https:/home/circleci/project/semantic-release-remote/commit/feb100e3c0e40ce34759246ca27b247ecbb201fc)) -* **Safari:** inject client script into page if script ID is present ([9bc1ef4](https:/home/circleci/project/semantic-release-remote/commit/9bc1ef433ced60b1dc40dc68d0ffe833ce137199)) -* **Win:** add proper Windows icon for app and tray ([e0e96c2](https:/home/circleci/project/semantic-release-remote/commit/e0e96c23e791eef77e136f4188a0fa621c1f0cb3)) -* **win:** convert BT session for Scratch Link 2.0 ([b2bc874](https:/home/circleci/project/semantic-release-remote/commit/b2bc874b7dea108b10fe2eaa4cd8cdd42a1b4f76)) -* **windows:** BLE session first draft ([224e694](https:/home/circleci/project/semantic-release-remote/commit/224e6948749997395102f2c2de2e12163627c37a)) -* **windows:** build and run ScratchApp, receive WS connections ([05d2866](https:/home/circleci/project/semantic-release-remote/commit/05d2866f2bca7f3bee8af67e0769458b7c4399e9)) -* **windows:** generate image assets for MSIX ([d77a006](https:/home/circleci/project/semantic-release-remote/commit/d77a0064a0cd25bac8b8b2b7e3c7d0b146ead69a)) - - -### Performance Improvements - -* **Win:** shrink tray icon, speed up svg-convert.sh ([adeaf1d](https:/home/circleci/project/semantic-release-remote/commit/adeaf1da6b1f48ce993391aa764a0acf53898f74)) - - -### BREAKING CHANGES - -* Scratch Link 2.0 will drop support for some older -versions of macOS. - -# [2.0.0-develop.18](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.17...v2.0.0-develop.18) (2023-05-24) - - -### Bug Fixes - -* **build:** fix missing CFBundleVersion in Safari extension ([7a67ea1](https:/home/circleci/project/semantic-release-remote/commit/7a67ea18025396c26a359f435a2c1cb1ed7ab8c3)) - -# [2.0.0-develop.17](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.16...v2.0.0-develop.17) (2023-04-29) - - -### Bug Fixes - -* **Win:** fix larger icon sizes being ignored sometimes ([e79252f](https:/home/circleci/project/semantic-release-remote/commit/e79252f2ddf2e15987aab8e2205a95aceaa80cb1)) -* **Win:** set assembly attributes including version info ([8379c15](https:/home/circleci/project/semantic-release-remote/commit/8379c153d9b4273bf0e2814a3ebf6be3f2d3e260)) - - -### Features - -* add Windows tray icon ([29b961b](https:/home/circleci/project/semantic-release-remote/commit/29b961b8bb86070fb67012def05f195b75438086)) -* **Win:** add proper Windows icon for app and tray ([e0e96c2](https:/home/circleci/project/semantic-release-remote/commit/e0e96c23e791eef77e136f4188a0fa621c1f0cb3)) - - -### Performance Improvements - -* **Win:** shrink tray icon, speed up svg-convert.sh ([adeaf1d](https:/home/circleci/project/semantic-release-remote/commit/adeaf1da6b1f48ce993391aa764a0acf53898f74)) - -# [2.0.0-develop.16](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.15...v2.0.0-develop.16) (2023-04-24) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.42 ([7d8d1b2](https:/home/circleci/project/semantic-release-remote/commit/7d8d1b25a873866aef4cf9fe12a664ab94ada90d)) - -# [2.0.0-develop.15](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.14...v2.0.0-develop.15) (2023-04-22) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.41 ([5e25dba](https:/home/circleci/project/semantic-release-remote/commit/5e25dba6cceb03df542aa1e4d920326f3f0b534e)) - -# [2.0.0-develop.14](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.13...v2.0.0-develop.14) (2023-04-22) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.40 ([f2b6787](https:/home/circleci/project/semantic-release-remote/commit/f2b67876984b75fca7286902be800d584959f58a)) - -# [2.0.0-develop.13](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.12...v2.0.0-develop.13) (2023-04-21) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.38 ([f200619](https:/home/circleci/project/semantic-release-remote/commit/f2006198489bc938ce4c46ec879fe4d182ec8c5f)) - -# [2.0.0-develop.12](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.11...v2.0.0-develop.12) (2023-04-21) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.37 ([79af6ab](https:/home/circleci/project/semantic-release-remote/commit/79af6ab191eb881c14e0403a5524c4da42e865d6)) - -# [2.0.0-develop.11](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.10...v2.0.0-develop.11) (2023-04-20) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.36 ([cbc0e7c](https:/home/circleci/project/semantic-release-remote/commit/cbc0e7ca8f472199acc52a2e408a878e462d0240)) - -# [2.0.0-develop.10](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.9...v2.0.0-develop.10) (2023-04-19) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.35 ([7543466](https:/home/circleci/project/semantic-release-remote/commit/7543466407de1f1f297afd148f07036bd977109b)) - -# [2.0.0-develop.9](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.8...v2.0.0-develop.9) (2023-04-19) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.34 ([b19fe2a](https:/home/circleci/project/semantic-release-remote/commit/b19fe2a64639e4ff17cd965d82965bfea6ce0603)) - -# [2.0.0-develop.8](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.7...v2.0.0-develop.8) (2023-04-17) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.33 ([1c3a4cf](https:/home/circleci/project/semantic-release-remote/commit/1c3a4cfd0b13ca938cd53b44e26491415ea80e43)) - -# [2.0.0-develop.7](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.6...v2.0.0-develop.7) (2023-04-15) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.32 ([964a53f](https:/home/circleci/project/semantic-release-remote/commit/964a53f0ed1e594d1cf3e983c9830402ce743f05)) - -# [2.0.0-develop.6](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.5...v2.0.0-develop.6) (2023-04-14) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.31 ([2c60027](https:/home/circleci/project/semantic-release-remote/commit/2c60027674e6cb3f0942d2c380b01b765bef12f8)) - -# [2.0.0-develop.5](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.4...v2.0.0-develop.5) (2023-04-06) - - -### Bug Fixes - -* generate icons directly from SVGs for better quality ([8d3b8ce](https:/home/circleci/project/semantic-release-remote/commit/8d3b8ce38a1000552d92bdce7da1cf98fbd9b134)) -* **mac:** fix CI artifact renaming ([7a05fdd](https:/home/circleci/project/semantic-release-remote/commit/7a05fdda50fc7a498bbdc6d4068cf305177669b7)) -* **win:** build framework-dependent AnyCPU for further install size reduction ([b1f776c](https:/home/circleci/project/semantic-release-remote/commit/b1f776c19f07652ea09c3152325a35578f9fdcf1)) -* **win:** discover both paired and unpaired BT devices ([23ff634](https:/home/circleci/project/semantic-release-remote/commit/23ff634560930041ebb66ae6476839825bb713ba)) -* **win:** don't crash if BT connect fails ([522f65f](https:/home/circleci/project/semantic-release-remote/commit/522f65f199741e2e704f716952a2db8c7508640f)) -* **windows:** fix *.msixupload generation ([3a1c172](https:/home/circleci/project/semantic-release-remote/commit/3a1c1727bcfbe46aa549a4c15b3b0f7e750b0527)) -* **windows:** fix incorrect root namespace ([e25a604](https:/home/circleci/project/semantic-release-remote/commit/e25a604be0238ef3501447df411c7816aea31f26)) -* **windows:** implement WinBLESession.Dispose ([9a0e1f7](https:/home/circleci/project/semantic-release-remote/commit/9a0e1f7ec1202ae24abc5ca988c4fa54c822bffd)) -* **win:** set WindowsPackageType=None to fix debugging ([4b151e1](https:/home/circleci/project/semantic-release-remote/commit/4b151e1884915a39f059d696a968557f04e4ff7b)) - - -### Features - -* **win:** convert BT session for Scratch Link 2.0 ([b2bc874](https:/home/circleci/project/semantic-release-remote/commit/b2bc874b7dea108b10fe2eaa4cd8cdd42a1b4f76)) -* **windows:** BLE session first draft ([224e694](https:/home/circleci/project/semantic-release-remote/commit/224e6948749997395102f2c2de2e12163627c37a)) -* **windows:** build and run ScratchApp, receive WS connections ([05d2866](https:/home/circleci/project/semantic-release-remote/commit/05d2866f2bca7f3bee8af67e0769458b7c4399e9)) -* **windows:** generate image assets for MSIX ([d77a006](https:/home/circleci/project/semantic-release-remote/commit/d77a0064a0cd25bac8b8b2b7e3c7d0b146ead69a)) - -# [2.0.0-develop.4](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.3...v2.0.0-develop.4) (2023-04-06) - - -### Bug Fixes - -* calculate build number from label ([2eb8015](https:/home/circleci/project/semantic-release-remote/commit/2eb8015d457263111219f2fc4a5e7d5505c6efb4)) - -# [2.0.0-develop.3](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.2...v2.0.0-develop.3) (2023-04-06) - - -### Bug Fixes - -* **deps:** update dependency scratch-vm to v1.5.28 ([441b7fd](https:/home/circleci/project/semantic-release-remote/commit/441b7fdf3572b093d3b4c0c1022e5472dbcdaff9)) - -# [2.0.0-develop.2](https:/home/circleci/project/semantic-release-remote/compare/v2.0.0-develop.1...v2.0.0-develop.2) (2023-04-06) - - -### Bug Fixes - -* use semantic-release version for build ([17709dd](https:/home/circleci/project/semantic-release-remote/commit/17709dd709a59a1b4d5fa10b4a4ed50834ffd893)) - -# [2.0.0-develop.1](https:/home/circleci/project/semantic-release-remote/compare/v1.4.0...v2.0.0-develop.1) (2023-04-06) - - -### Bug Fixes - -* always call context.completeRequest, even when not returning a value ([9cabb03](https:/home/circleci/project/semantic-release-remote/commit/9cabb03495b089cdc23fb257a0c3fea7e603c225)) -* **ci:** speculative fix for Homebrew failing on CI ([4b12ce4](https:/home/circleci/project/semantic-release-remote/commit/4b12ce4d1501eaea92ee76c1e11fc808ccc7ad11)) -* **ci:** update VS Mac installer script for 17.4 ([9221e1e](https:/home/circleci/project/semantic-release-remote/commit/9221e1e68a0c5cb8e35777c914fd9e17e954a5d7)) -* **common:** make session immediately so we don't miss the first message ([d53d5c8](https:/home/circleci/project/semantic-release-remote/commit/d53d5c8a9dd02563c5e75208cfc7125386d5f85a)) -* **common:** remove `EventAwaiter(EventHandler, ...` ([9032a01](https:/home/circleci/project/semantic-release-remote/commit/9032a013c8b5dc967f5a53a50546499b55af6b55)) -* disable BLE restore to fix 'Bluetooth unavailable' issue ([8fdc3d1](https:/home/circleci/project/semantic-release-remote/commit/8fdc3d166edb6fb49b25ed2f467a0f77227dc630)) -* dispose of cbManager on session shutdown ([5423e78](https:/home/circleci/project/semantic-release-remote/commit/5423e7800ba21bdb50874d23a88d0cee64c2c54d)) -* don't embed IOBluetooth.framework ([563070d](https:/home/circleci/project/semantic-release-remote/commit/563070d67e5a88cc96a196759f2d2b59b0f4706b)) -* **extension:** inject project marketing version into web extension manifest ([6aa609d](https:/home/circleci/project/semantic-release-remote/commit/6aa609d100961b7f74f4345c28137393988a2835)) -* fix DisposedException by removing cancellation token ([eed937f](https:/home/circleci/project/semantic-release-remote/commit/eed937fd185f58295733e63dc8879a32e5a5ee10)) -* fix minor MAS compliance issues ([149076c](https:/home/circleci/project/semantic-release-remote/commit/149076c07aa6c6e725e09130ee23a397b3e6e9eb)) -* implement a BT connection dance that works on macOS 10 and 12 ([159ca00](https:/home/circleci/project/semantic-release-remote/commit/159ca006789956de12e4282b2d088217eb5bb17a)) -* **Mac:** add real Bluetooth permissions request messages ([39cdf3c](https:/home/circleci/project/semantic-release-remote/commit/39cdf3cd509a1c475dbc80b08d919607a6ac1f22)) -* **Mac:** add real icons for Safari extension ([f081c71](https:/home/circleci/project/semantic-release-remote/commit/f081c7130d97a86f55259bd76eef4fdd51bd1856)) -* **MacBLE:** allow more time for the Bluetooth state to settle ([d2c1cf9](https:/home/circleci/project/semantic-release-remote/commit/d2c1cf97845060e88a00d69a66c13580abb7c74e)) -* **macBLE:** fix 'API MISUSE' log message ([b46f435](https:/home/circleci/project/semantic-release-remote/commit/b46f4359f6ed9feb8734cfbc66d9936af6303201)) -* **macBLE:** handle UpdatedState even if it fires during CBCentralManager ctor ([d2df409](https:/home/circleci/project/semantic-release-remote/commit/d2df40995861311b02875c03c2f2151038e3c8e5)) -* **macBT:** add 'Options' / PIN instructions to pairing dialog ([d58f5d2](https:/home/circleci/project/semantic-release-remote/commit/d58f5d243aeafb7756c987350b439b698c7eaa7d)) -* **MacBT:** dispose of inquiry & channel properly ([b3c48ef](https:/home/circleci/project/semantic-release-remote/commit/b3c48ef1662a93776e68181a5e745a4b88b9670d)) -* **MacBT:** make BT disconnect/reconnect more reliable, especially after pairing ([53bbe3b](https:/home/circleci/project/semantic-release-remote/commit/53bbe3b6e39fc9b27bf11119c888c4b36a39771c)) -* **macBT:** poll to reliably detect RFCOMM channel open ([d42cfdb](https:/home/circleci/project/semantic-release-remote/commit/d42cfdb63751ce511f2053ff4130e2a41b99a751)) -* **Mac:** correct target macOS version ([71e7a13](https:/home/circleci/project/semantic-release-remote/commit/71e7a1303397c7138604131c89bbdcf5793adc9a)) -* **Mac:** embed Safari helper extension into the Scratch Link app bundle ([9c6bb30](https:/home/circleci/project/semantic-release-remote/commit/9c6bb30273b4597e1e3ddd451167cffe6231a854)) -* **Mac:** fix Safari, especially Link->Client notifications ([5bae1ea](https:/home/circleci/project/semantic-release-remote/commit/5bae1ea319dd96eed6a92074a1ba59ecdaca89ca)) -* **mac:** fix tccd error message about kTCCServiceAppleEvents ([bdfc8c0](https:/home/circleci/project/semantic-release-remote/commit/bdfc8c08a6caae205e599b9cca28aedc627d1589)) -* **Mac:** hide Safari extensions for non-MAS builds ([58138c5](https:/home/circleci/project/semantic-release-remote/commit/58138c5c89d17ff6d4dfd40d1bfa3ad95c88f27b)) -* **Mac:** make sure GetSettledBluetoothState() doesn't miss an event ([124b6a0](https:/home/circleci/project/semantic-release-remote/commit/124b6a0cef58bd027249656ac4d183f76454d8f5)) -* **Mac:** properly Dispose() of the status bar item ([4cb46b5](https:/home/circleci/project/semantic-release-remote/commit/4cb46b56588d74cd8cf54e79f36a7a6fafe53f59)) -* **Mac:** remove browser_action popup ([9717935](https:/home/circleci/project/semantic-release-remote/commit/971793558fdf949622c79e28db93dd43083c8938)) -* **Mac:** Safari extension improvements ([14f9f99](https:/home/circleci/project/semantic-release-remote/commit/14f9f99b8cb25e7704e53f31f6589f7205b4c66a)) -* **Mac:** show Safari extension menu only if supported ([d019142](https:/home/circleci/project/semantic-release-remote/commit/d01914241789fc639def818f8553799b2915c198)) -* make CI robust against VS updates ([950d3de](https:/home/circleci/project/semantic-release-remote/commit/950d3deb307226403b537874cadb1f64d2886ac6)) -* make didDiscoverPeripheral a notification ([e51fa01](https:/home/circleci/project/semantic-release-remote/commit/e51fa01b799fcc2c9030a66c4bfe448f4aabbc08)) -* **menu:** 'Manage Safari Extensions' => 'Manage Safari Extensions...' ([dc5c481](https:/home/circleci/project/semantic-release-remote/commit/dc5c48127842be5e3f756f077a0d1e284d1002e8)) -* more BT connection tweaks ([7a1e0d0](https:/home/circleci/project/semantic-release-remote/commit/7a1e0d014a05f3af968d998c2caf888987501618)) -* resolve crash on session close while connecting ([32f8981](https:/home/circleci/project/semantic-release-remote/commit/32f89814873eb19045cffcfe40a3c96f70bce54b)) -* **Safari:** add timeout for initial connection ([e1c9de0](https:/home/circleci/project/semantic-release-remote/commit/e1c9de00f1dbf55c1da8bd2bd935f23015b34450)) -* **Safari:** close session if Scratch Link goes away ([83f85f0](https:/home/circleci/project/semantic-release-remote/commit/83f85f028996d12e2a7d6f2b6c4f93608d60bef8)) -* **safari:** don't cause Safari to steal focus for every Scratch Link -> page message ([f17184f](https:/home/circleci/project/semantic-release-remote/commit/f17184f5a1e163232a0ee76133cd2953bb382a0d)) -* **version:** embed GitVersion info correctly and document version scheme ([6501e49](https:/home/circleci/project/semantic-release-remote/commit/6501e49073ac852e71ccd048973fb7b5a383c506)) -* **webextension:** close session on client unload ([caac99e](https:/home/circleci/project/semantic-release-remote/commit/caac99e9c0fa15a940642dc5c9063dba45a40b5f)) -* **webextension:** keep Safari sessions alive for longer than 5 seconds ([4981508](https:/home/circleci/project/semantic-release-remote/commit/498150869982c3d21f5463cf646e337fd789b970)) -* **webextension:** limit number of outstanding poll requests ([c5137bb](https:/home/circleci/project/semantic-release-remote/commit/c5137bb7a06c1701592669196508ae9b26ee97be)) -* work around macOS 12 OpenRfcommChannelSync timeout ([68e7efc](https:/home/circleci/project/semantic-release-remote/commit/68e7efc069e8188dd7ee4d0b0e5deff43d7bdd14)) - - -### chore - -* clean slate for Scratch Link 2.0 ([f30cff3](https:/home/circleci/project/semantic-release-remote/commit/f30cff3e5b0fbd2fda423e8609cbd6576c45131a)) - - -### Features - -* **MacBT:** display pairing help when connecting to unpaired peripheral ([feb100e](https:/home/circleci/project/semantic-release-remote/commit/feb100e3c0e40ce34759246ca27b247ecbb201fc)) -* **Safari:** inject client script into page if script ID is present ([9bc1ef4](https:/home/circleci/project/semantic-release-remote/commit/9bc1ef433ced60b1dc40dc68d0ffe833ce137199)) - - -### BREAKING CHANGES - -* Scratch Link 2.0 will drop support for some older -versions of macOS. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..7c4fa5cb --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,97 @@ +# AluxCoding Scratch Link — Claude 행동 규칙 + +Windows-only desktop app. Scratch 3.0 ↔ 하드웨어(BLE, Bluetooth Classic, USB Serial) 중계. +C# / .NET 8 + WinUI 3, Visual Studio Solution. + +--- + +## 1. 최우선 규칙 (위반 시 즉시 수정) + +- **`Console.*` 사용 금지** → `Trace.WriteLine()` (`System.Diagnostics`) 사용 (§4 참조) +- **`scratch-link-common`이 `scratch-link-win`을 참조 금지** → 의존 방향은 `scratch-link-win → scratch-link-common` 단방향 (§8 참조) +- **`SharedProps/*.props` / `*.targets` 직접 편집 시 주의** → 전체 빌드에 영향. 개별 csproj에서 중복 선언 금지 +- **기존 아키텍처·패턴을 우회하는 수정 금지** (§8 참조) → 새 코드·수정 코드에 적용. 기존 위반은 명시 요청 없이 건드리지 않는다. 단, 수정 범위 안에서 우회 코드를 발견하면 사용자에게 알리고 처리 여부를 묻는다. + +## 2. Using 지시문 규칙 + +- `using` 선언은 반드시 **namespace 내부**에 배치 (`.editorconfig` 강제) +- 멤버 접근 시 `this.` 한정자 필수: 필드(`this.field`), 메서드(`this.Method()`), 프로퍼티(`this.Property`), 이벤트(`this.Event`) +- 불필요한 `using` 추가 금지 — 미사용 using은 컴파일 경고 원인 + +## 3. 코드 스타일 + +- 인덴트: 4 스페이스 (탭 금지) +- 줄 끝: LF (XML / CSPROJ / WAPPROJ 제외 — CRLF) +- 인코딩: UTF-8 +- StyleCop Analyzers 준수 필수 +- `interface` 명명: `I` 접두사 (예: `ISession`, `IPeripheralSession`) +- 미사용 변수·using 금지 (`CS8600`, `IDE0005` 등 경고 발생) + +## 4. 금지 패턴 + +- **`Console.*` 사용 금지** → `Trace.WriteLine()` 사용 + - **예외 — 임시 진단용**: `System.Diagnostics.Debug.WriteLine("[DEBUG-XXX] ...")` 형태로 한정 허용. `[DEBUG-XXX]` 식별 prefix 필수 (grep 가능). **커밋 전 반드시 전부 제거**. +- **`dynamic` 타입 남용 금지** → 구체적 타입 또는 제네릭 사용 +- **`#pragma warning disable` 무분별 사용 금지** → 근본 원인 해결 우선 +- **`types.cs` / `type.cs` 파일 생성 금지** → 타입·인터페이스는 사용하는 클래스 파일 안에 함께 정의 (코로케이션) +- **일반 주석(`//`)은 한 줄 max, "WHY"만** → 기본은 주석 없음. WHY가 비자명할 때만 한 줄 추가. WHAT 설명 / 현재 작업·callers 참조 금지. 설계 의도는 commit message / PR description으로. +- **XML doc(`///`)은 public API에 한해 단일 `` 허용** → 단, caller 참조(`"Used by X"`) 및 코드에서 자명한 WHAT 설명 금지. 비자명한 동작·제약·사이드이펙트만 기술한다. +- **공용 코드 (`scratch-link-common`) 의 주석·식별자에서 특정 프로토콜 구현 세부 언급 금지** → 일반화된 패턴 설명으로 표현하고, 구체적 예시는 해당 세션 클래스 안에서만 든다. + +## 5. 작업 전 확인사항 + +코드 작성·수정 전에 반드시 확인: + +1. 수정 대상 파일을 먼저 읽고 기존 패턴을 파악한다 +2. **`scratch-link-common` vs `scratch-link-win` 중 어느 쪽에 위치해야 하는지 판단한다** — 플랫폼 API(Windows.Devices.*, WinUI) 없이 동작 가능하면 common, 그렇지 않으면 win +3. 관련 타입·인터페이스가 이미 있는지 확인한다 +4. `SharedProps/`에 이미 선언된 속성·패키지 참조인지 확인한다 + +## 6. 작업 후 검증 체크리스트 + +- [ ] `Console.*`를 사용하지 않았는가? (임시 `[DEBUG-*]` 로그 전부 제거 확인) +- [ ] StyleCop 오류가 없는가? +- [ ] `using` 선언이 namespace 내부에 있는가? +- [ ] 멤버 접근에 `this.` 한정자를 사용했는가? +- [ ] 미사용 변수·using이 없는가? +- [ ] 의존 방향 규칙을 지켰는가? (`scratch-link-common`이 `scratch-link-win`을 참조하지 않음) +- [ ] `SharedProps/`에 이미 선언된 속성을 개별 csproj에 중복 선언하지 않았는가? +- [ ] 일반 주석(`//`)이 WHY만 담고 있는가? (WHAT / caller 참조 없음) +- [ ] XML doc(`///`)이 있다면 public API이고, caller 참조 및 자명한 WHAT 설명이 없는가? +- [ ] 기존 코드 패턴과 일관성이 있는가? + +## 7. 커밋 규칙 + +``` +feat(serial): USB Serial 트랜스포트 세션 추가 +fix(ble): BLE 연결 재시도 로직 오류 수정 +refactor(common): JSON-RPC 핸들러 구조 개선 +docs(architecture): Serial 프로토콜 설계 문서 업데이트 +``` + +- 접두사: `feat`, `fix`, `refactor`, `docs`, `chore`, `style`, `test`, `ci` +- scope 예시: `ble`, `bt`, `serial`, `common`, `win`, `jsonrpc`, `msix` +- 설명·본문·꼬리말은 한국어 + +## 8. 프로젝트 구조 핵심 + +- `scratch-link-common/` — 플랫폼 공통 C# Shared Project (BLE/BT/Serial 프로토콜 추상화, JSON-RPC 2.0, WebSocket 핸들링). **재사용 가능한 단위로 분리**, Windows API에 종속되지 않는다. +- `scratch-link-win/` — WinUI 3 플랫폼 구현 (Windows.Devices.* API 연동, 트레이 아이콘, 앱 진입점). **비즈니스 로직은 최소화**, 가능한 한 `scratch-link-common`으로 위임. +- `scratch-link-win-msix/` — MSIX 패키징 프로젝트. 직접 코드 편집 대상이 아니다. +- `SharedProps/` — MSBuild 공유 속성 (SDK 버전, NuGet 패키지 참조, 버전 자동화). 개별 csproj에서 중복 선언 금지. +- `Documentation/` — 아키텍처·프로토콜 설계 문서. 관련 코드 변경 시 함께 업데이트한다. +- **의존 방향: `scratch-link-win` → `scratch-link-common` 단방향** (§1 절대 규칙). 이유: common이 win을 참조하면 플랫폼 독립성이 깨지고 순환 의존이 발생한다. + +## 9. 개발 명령어 + +```bash +# 권장: Visual Studio 2022+에서 scratch-link.sln 열기 +# 빌드 구성: Debug_Win / Release_Win + +dotnet build -c Debug_Win # 디버그 빌드 +dotnet build -c Release_Win # 릴리즈 빌드 +dotnet run --project scratch-link-win -c Debug_Win # 실행 + +# 아이콘 생성 (cairosvg, ImageMagick, optipng 필요) +make icons +``` From 7605e20ede5d40065364e474872fbb7b1021c1a2 Mon Sep 17 00:00:00 2001 From: hksong Date: Mon, 25 May 2026 13:46:47 +0900 Subject: [PATCH 26/94] chore: ignore ref/ for local-only debug captures Personal debug captures (VS DebugView output, browser console logs, etc.) live under ref/ during diagnosis but should never be committed. Excluding the whole directory so accidental 'git add -A' won't pull them in. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 4b69c948..61bc5b4b 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,6 @@ Package.StoreAssociation.xml UpgradeLog*.htm _UpgradeReport_Files/ Backup*/ + +# Local-only debug captures (DebugView dumps, browser console logs, etc.) +ref/ From 26711a7c929edbd3a849eb9b14bae4784733d596 Mon Sep 17 00:00:00 2001 From: hksong Date: Mon, 25 May 2026 14:55:58 +0900 Subject: [PATCH 27/94] style(serial): tighten comments to match CLAUDE.md guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 본 세션에서 추가/수정한 Serial 관련 코드의 주석을 CLAUDE.md §4 규칙에 맞춰 정리한다. - 공용 코드(scratch-link-common)에서 특정 프로토콜/디바이스 언급 제거: SerialOpenParams.PeripheralType 문서, StartKeepAlive 문서에서 "codetinker" 같은 device-specific 예시를 빼고 일반화된 표현으로 바꾼다. - 일반 주석(//)을 한 줄로 축약: 멀티라인 설계 의도 설명은 commit log / 문서로 옮기고, 인라인 주석은 WHY 한 줄만 남긴다 (writeSemaphore/stateLock/ wireTrace 필드 주석, HandleSetKeepAlive idempotent 주석, StopKeepAlive block 주석, Dispose 주석, OnKeepAliveTick idle-only/re-check/escape 주석, WinSerialSession ioLock/DoWrite/ReadLoop polling 주석 등). - XML doc 단순화: 자명한 WHAT 설명과 caller 참조("Called from X")를 제거하고, 비자명한 동작·제약·사이드이펙트만 단일 로 남긴다. StyleCop SA1611/SA1615 충족을 위해 /는 짧게 유지. 동작/API 변경 없음. 빌드 클린(우리 코드 관련 새 warning 없음). --- .../Serial/SerialOpenParams.cs | 14 ++- scratch-link-common/Serial/SerialSession.cs | 96 ++++++------------- scratch-link-win/Serial/WinSerialSession.cs | 32 +------ 3 files changed, 41 insertions(+), 101 deletions(-) diff --git a/scratch-link-common/Serial/SerialOpenParams.cs b/scratch-link-common/Serial/SerialOpenParams.cs index 4cae9411..53316356 100644 --- a/scratch-link-common/Serial/SerialOpenParams.cs +++ b/scratch-link-common/Serial/SerialOpenParams.cs @@ -36,22 +36,20 @@ internal class SerialOpenParams public string FlowControl { get; set; } /// - /// Gets or sets the peripheral type (e.g. "codetinker", "connect", "technic"). Optional. + /// Gets or sets the client-supplied peripheral type identifier. Optional; used for diagnostic logging only. /// public string PeripheralType { get; set; } /// - /// Gets or sets the keep-alive interval in milliseconds. If set, the session will - /// automatically resend the last sent packet at this interval to prevent - /// device timeout. Optional; null disables keep-alive. + /// Gets or sets the keep-alive interval in milliseconds. If positive, the most recently + /// sent TX packet is automatically re-sent at this interval while the line is idle. + /// Null or non-positive disables the timer. /// public int? KeepAliveIntervalMs { get; set; } /// - /// Gets or sets a value indicating whether wire-level TX/RX hex dumps are - /// emitted via for this session. - /// Diagnostic only; off by default. Enable when debugging suspected - /// transport-level corruption or loss. + /// Gets or sets a value indicating whether wire-level TX/RX hex dumps are emitted via + /// . Diagnostic only; off by default. /// public bool WireTrace { get; set; } } diff --git a/scratch-link-common/Serial/SerialSession.cs b/scratch-link-common/Serial/SerialSession.cs index 5b50ba43..48dce96a 100644 --- a/scratch-link-common/Serial/SerialSession.cs +++ b/scratch-link-common/Serial/SerialSession.cs @@ -26,12 +26,10 @@ namespace ScratchLink.Serial; internal abstract class SerialSession : PeripheralSession where TPort : class { - // Coordinates concurrent writes from HandleWrite and keep-alive ticks - // so that two DoWrite invocations never overlap and corrupt the stream. + // Serializes DoWrite calls so two writes never overlap and corrupt the stream. private readonly SemaphoreSlim writeSemaphore = new SemaphoreSlim(1, 1); - // Guards keep-alive lifecycle state (timer, interval, lastSentData) - // so that Start/Stop/Reset and the timer callback observe a consistent view. + // Guards keep-alive lifecycle fields shared with the timer callback. private readonly object stateLock = new object(); private byte[] lastSentData; @@ -39,9 +37,7 @@ internal abstract class SerialSession : PeripheralSession private int keepAliveIntervalMs; private bool keepAliveActive; - // Wire-level TX/RX hex dump for diagnostic builds. Set from connect params. - // volatile so the flag is observed on any thread (HandleWrite, ReadLoop, ticks) - // without taking stateLock for the hot path. + // volatile so threads outside stateLock see the latest value on the hot path. private volatile bool wireTrace; /// @@ -108,15 +104,12 @@ protected override Task DoConnect(TPort port, JsonElement? args) protected abstract Task DoConnect(TPort port, SerialOpenParams openParams); /// - /// Implement the JSON-RPC "write" request. Decodes the base64 payload and - /// forwards to the platform implementation. Serializes writes against the - /// keep-alive timer, caches the payload as the most recent TX packet, and - /// resets the keep-alive interval so that idle-only resends are not triggered - /// during active bursts (e.g. firmware updates). + /// JSON-RPC write handler. Caches the payload as the most recent TX packet + /// and resets the keep-alive timer so resends are suppressed during active bursts. /// - /// The name of the method being called ("write"). - /// A JSON object containing message and encoding. - /// An object with sentBytes equal to the number of bytes written. + /// Dispatched method name. + /// Decoded request params. + /// sentBytes wrapper. protected async Task HandleWrite(string methodName, JsonElement? args) { if (args == null) @@ -204,15 +197,13 @@ protected virtual Task HandleStopReading(string methodName, JsonElement? } /// - /// Implement the JSON-RPC "setKeepAlive" request. Lets the client toggle or - /// reconfigure keep-alive at runtime — e.g. disable before a firmware update - /// (via intervalMs: null or 0) and re-enable afterwards. - /// Idempotent: calling with the same interval as the current one restarts the - /// timer cleanly; calling with null/0 while disabled is a no-op. + /// JSON-RPC setKeepAlive handler. intervalMs: positive (re)starts, null/0/negative disables. + /// Idempotent: stop-then-start so repeated calls leave only one timer alive. + /// Response echoes the applied interval (null when disabled). /// - /// The name of the method being called ("setKeepAlive"). - /// A JSON object with intervalMs (int or null). Null/0/negative disables. - /// An object echoing the resulting intervalMs (or null when disabled). + /// Dispatched method name. + /// Decoded request params. + /// Echo of the applied interval. protected Task HandleSetKeepAlive(string methodName, JsonElement? args) { int? requested = null; @@ -225,9 +216,7 @@ protected Task HandleSetKeepAlive(string methodName, JsonElement? args) } } - // Always stop first so the request is fully idempotent — repeated calls - // with the same interval rebuild the timer cleanly, and calls with a - // different interval don't leave the old one running. + // Stop-then-start makes the call idempotent regardless of current state. this.StopKeepAlive(); int? applied = null; @@ -307,11 +296,10 @@ protected async Task OnPortDiscovered(TPort port, string path, string displayNam } /// - /// Start the keep-alive timer. When set, the most recently sent TX packet - /// is re-sent at the specified interval to satisfy devices that disconnect - /// on long idle periods (e.g. Codetinker requires < 1s gaps). + /// Start the keep-alive timer at . Null or non-positive disables. + /// No-op if already running. /// - /// Interval in milliseconds. Null or non-positive values disable keep-alive. + /// Interval in milliseconds; null/non-positive disables. protected void StartKeepAlive(int? keepAliveIntervalMs) { if (keepAliveIntervalMs == null || keepAliveIntervalMs.Value <= 0) @@ -338,8 +326,8 @@ protected void StartKeepAlive(int? keepAliveIntervalMs) } /// - /// Stop the keep-alive timer and block until any in-flight callback completes. - /// Safe to call multiple times. + /// Stop the keep-alive timer and block until any in-flight tick finishes. + /// Safe to call repeatedly. /// protected void StopKeepAlive() { @@ -358,8 +346,7 @@ protected void StopKeepAlive() if (toDispose != null) { - // Block until any in-flight callback finishes so that no resend - // races against the platform disconnect / port disposal. + // Block so no resend races a subsequent disconnect or port disposal. using var waitHandle = new ManualResetEvent(false); if (toDispose.Dispose(waitHandle)) { @@ -370,18 +357,12 @@ protected void StopKeepAlive() Trace.WriteLine("keep-alive: stopped"); } - /// - /// Release keep-alive resources. Platform subclasses should still override - /// to release their port handles; this base implementation guarantees the - /// keep-alive timer is stopped and the write semaphore is disposed. - /// - /// True if called from . + /// protected override void Dispose(bool disposing) { if (disposing && !this.DisposedValue) { - // StopKeepAlive blocks on in-flight callbacks, so by the time we - // dispose the semaphore no tick can still be holding it. + // Order matters: StopKeepAlive waits for in-flight ticks before we dispose the semaphore they use. this.StopKeepAlive(); this.writeSemaphore.Dispose(); } @@ -439,14 +420,8 @@ private static SerialOpenParams ParseOpenParams(JsonElement? args) } /// - /// Format a byte buffer as a space-separated, lowercase hex string for diagnostic - /// logs. Long buffers are truncated to the first bytes - /// with a tail marker indicating how many bytes were elided, so trace lines stay - /// bounded even on large transfers (e.g. firmware update chunks). + /// Hex preview for diagnostic logs, capped at with a tail marker. /// - /// Buffer to format. May be empty; must not be null. - /// Maximum number of bytes to render verbatim before truncation. - /// Hex preview suitable for . private static string FormatHex(byte[] data, int maxBytes = 256) { if (data == null || data.Length == 0) @@ -475,9 +450,7 @@ private static string FormatHex(byte[] data, int maxBytes = 256) } /// - /// Reset the keep-alive timer to fire one full interval from now. - /// Called from so that bursts of writes - /// (e.g. firmware update chunks) suppress the resend until the line goes idle. + /// Push the next tick one full interval forward so that ongoing write bursts suppress the resend. /// private void ResetKeepAliveTimer() { @@ -500,15 +473,10 @@ private void ResetKeepAliveTimer() } catch (ObjectDisposedException) { - // Raced with StopKeepAlive; the timer is gone, nothing to do. + // Raced with StopKeepAlive. } } - /// - /// Timer callback that resends the last TX packet. Skips silently if another - /// write is already in progress, if the session is no longer connected, or - /// if no packet has been sent yet. - /// private async void OnKeepAliveTick(object state) { byte[] data; @@ -527,9 +495,7 @@ private async void OnKeepAliveTick(object state) return; } - // Skip if a real write (or another tick) holds the semaphore. This is - // what makes keep-alive idle-only: during a write burst the semaphore - // is busy and ticks no-op. + // WaitAsync(0) makes the tick idle-only: during a write burst the semaphore is busy and we no-op. if (!await this.writeSemaphore.WaitAsync(0).ConfigureAwait(false)) { return; @@ -537,7 +503,6 @@ private async void OnKeepAliveTick(object state) try { - // Re-check after acquiring the lock; state may have changed while waiting. if (!this.keepAliveActive || !this.IsConnected) { return; @@ -552,12 +517,11 @@ private async void OnKeepAliveTick(object state) } catch (ObjectDisposedException) { - // Session disposed mid-tick; safe to ignore. + // Session disposed mid-tick. } catch (Exception e) { - // Never let exceptions escape an async-void Timer callback or the - // process will terminate. Log and let the next tick try again. + // async-void Timer callback: an escaped exception terminates the process, so log and move on. Trace.WriteLine($"keep-alive: resend failed: {e.GetType().Name}: {e.Message}"); } finally @@ -568,7 +532,7 @@ private async void OnKeepAliveTick(object state) } catch (ObjectDisposedException) { - // Semaphore disposed during shutdown; safe to ignore. + // Semaphore disposed during shutdown. } } } diff --git a/scratch-link-win/Serial/WinSerialSession.cs b/scratch-link-win/Serial/WinSerialSession.cs index d319eeef..6104731e 100644 --- a/scratch-link-win/Serial/WinSerialSession.cs +++ b/scratch-link-win/Serial/WinSerialSession.cs @@ -22,13 +22,7 @@ namespace ScratchLink.Win.Serial; /// internal class WinSerialSession : SerialSession { - // Serializes SerialPort.Read and SerialPort.Write so the two never run - // concurrently on the same handle. .NET 8 SerialPort + CH340/CP210x driver - // combinations produce a TimeoutException burst on the read side whenever - // a write fires during an active blocking Read, even with ReadTimeout=500 - // and the synchronous Write API. Pairing this with BytesToRead polling - // (only call Read when data is actually available) keeps the lock held - // for a very short time, so keep-alive writes are not noticeably delayed. + // Serializes Read and Write on the same handle: concurrent calls trigger a TimeoutException burst on the read side with CH340/CP210x drivers. private readonly object ioLock = new object(); private SerialPort port; @@ -123,14 +117,7 @@ protected override async Task DoWrite(byte[] data) throw JsonRpc2Error.InvalidRequest("cannot write when not connected").ToException(); } - // Use the synchronous SerialPort.Write under ioLock so that it cannot - // overlap with a concurrent SerialPort.Read in ReadLoop. Mixing the - // two on the same handle (with any combination of sync/async APIs) - // causes the read side to throw TimeoutException bursts at the write - // cadence — observed at 33 ms with keep-alive enabled and the cause - // of DFU breakage on devices like Codetinker. ReadLoop only enters - // the lock when BytesToRead > 0 so this lock is held very briefly - // and keep-alive writes are not noticeably delayed. + // Sync Write under ioLock; see ioLock declaration for why. Task.Run keeps the async signature off the dispatcher thread. try { await Task.Run(() => @@ -231,14 +218,7 @@ private void ReadLoop(CancellationToken ct) break; } - // Poll BytesToRead instead of issuing a blocking Read with a timeout. - // A blocking Read holds the SerialPort I/O surface and races with any - // concurrent Write (e.g. the keep-alive timer), producing spurious - // TimeoutException bursts that look like the read loop is dying. - // BytesToRead is a cheap status query that does not hold the I/O - // surface, so the loop only enters the critical section (under - // ioLock) when data is actually available, and Read returns - // immediately because we know there's something to drain. + // Poll BytesToRead so Read is only called when there's data to drain — keeps ioLock hold time minimal. int available; try { @@ -267,8 +247,7 @@ private void ReadLoop(CancellationToken ct) if (available <= 0) { - // Idle. Sleep briefly so we don't spin the CPU; cancellation - // is observed via the token. + // Wait on ct.WaitHandle so cancellation wakes the loop immediately; otherwise sleep 10ms. try { if (ct.WaitHandle.WaitOne(10)) @@ -299,8 +278,7 @@ private void ReadLoop(CancellationToken ct) } catch (TimeoutException) { - // Defensive: shouldn't happen now that we only Read when data is available, - // but keep the safety net. + // Defensive: BytesToRead gate should prevent this. continue; } catch (OperationCanceledException) From e6d50d42eed2f575305a07d363b172148018bbf2 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 May 2026 11:56:16 +0900 Subject: [PATCH 28/94] =?UTF-8?q?feat(serial):=20triggerDTRReset=20RPC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=ED=94=84=EB=A1=9C=ED=86=A0?= =?UTF-8?q?=EC=BD=9C=20=EB=B2=84=EC=A0=84=201.3=20bump?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AVR 부트로더 진입과 Nemo cold-boot wake-up에 필요한 DTR pulse를 WebSocketLink 경로에서도 수행할 수 있도록 triggerDTRReset RPC를 구현. - Session.cs: NetworkProtocolVersion "1.2" → "1.3" - SerialSession: triggerDTRReset 핸들러 등록 + DoTriggerDTRReset 추상 메서드 선언. writeSemaphore 획득 하에 실행해 write와 DTR 시퀀스가 겹치지 않도록 직렬화. - WinSerialSession: DoTriggerDTRReset 구현 — DTR=true → 50ms → DTR=false. 포트 미연결 시 -32603, OS 시그널 오류 시 -32603 반환. Co-Authored-By: Claude Sonnet 4.6 --- scratch-link-common/Serial/SerialSession.cs | 33 +++++++++++++++++++++ scratch-link-common/Session.cs | 2 +- scratch-link-win/Serial/WinSerialSession.cs | 21 +++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/scratch-link-common/Serial/SerialSession.cs b/scratch-link-common/Serial/SerialSession.cs index 48dce96a..be43c4f3 100644 --- a/scratch-link-common/Serial/SerialSession.cs +++ b/scratch-link-common/Serial/SerialSession.cs @@ -53,6 +53,7 @@ public SerialSession(IWebSocketConnection webSocket) this.Handlers["startReading"] = this.HandleStartReading; this.Handlers["stopReading"] = this.HandleStopReading; this.Handlers["setKeepAlive"] = this.HandleSetKeepAlive; + this.Handlers["triggerDTRReset"] = this.HandleTriggerDTRReset; } /// @@ -231,6 +232,38 @@ protected Task HandleSetKeepAlive(string methodName, JsonElement? args) return Task.FromResult(new Dictionary { ["intervalMs"] = applied }); } + /// + /// JSON-RPC triggerDTRReset handler. Acquires the write semaphore so no + /// write overlaps the DTR pulse sequence, then delegates to . + /// + /// Dispatched method name. + /// Unused. + /// An empty result, returned after the DTR pulse sequence completes. + protected async Task HandleTriggerDTRReset(string methodName, JsonElement? args) + { + Trace.WriteLine("triggerDTRReset: executing DTR pulse"); + + await this.writeSemaphore.WaitAsync().ConfigureAwait(false); + try + { + await this.DoTriggerDTRReset().ConfigureAwait(false); + } + finally + { + this.writeSemaphore.Release(); + } + + return new Dictionary(); + } + + /// + /// Platform-specific implementation for the DTR reset pulse. Asserts DTR for 50 ms + /// then releases it. Must throw on failure so the + /// caller receives a well-formed JSON-RPC error response. + /// + /// A representing the asynchronous operation. + protected abstract Task DoTriggerDTRReset(); + /// /// Report received bytes to the client as a serialDidReceiveData /// notification. The payload is base64-encoded. diff --git a/scratch-link-common/Session.cs b/scratch-link-common/Session.cs index 92d8c682..3e305f19 100644 --- a/scratch-link-common/Session.cs +++ b/scratch-link-common/Session.cs @@ -33,7 +33,7 @@ public class Session : IDisposable /// Specifies the Scratch Link network protocol version. Note that this is not the application version. /// Keep this in sync with the version number in `NetworkProtocol.md`. /// - protected const string NetworkProtocolVersion = "1.2"; + protected const string NetworkProtocolVersion = "1.3"; /// /// Default timeout for remote requests. diff --git a/scratch-link-win/Serial/WinSerialSession.cs b/scratch-link-win/Serial/WinSerialSession.cs index 6104731e..04244721 100644 --- a/scratch-link-win/Serial/WinSerialSession.cs +++ b/scratch-link-win/Serial/WinSerialSession.cs @@ -170,6 +170,27 @@ protected override async Task DoDisconnect() } } + /// + protected override async Task DoTriggerDTRReset() + { + var currentPort = this.port; + if (currentPort == null || !currentPort.IsOpen) + { + throw JsonRpc2Error.InternalError("No connected peripheral").ToException(); + } + + try + { + currentPort.DtrEnable = true; + await Task.Delay(50).ConfigureAwait(false); + currentPort.DtrEnable = false; + } + catch (Exception e) when (e is ObjectDisposedException || e is InvalidOperationException || e is IOException) + { + throw JsonRpc2Error.InternalError($"setSignals failed: {e.Message}").ToException(); + } + } + /// protected override void Dispose(bool disposing) { From 637742c902e5f16290d44a04fc39cbde9bcd674d Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 11:58:47 +0900 Subject: [PATCH 29/94] =?UTF-8?q?docs(cicd):=20S3=20+=20CloudFront=20?= =?UTF-8?q?=EB=B0=B0=ED=8F=AC=20=ED=8C=8C=EC=9D=B4=ED=94=84=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=20=EC=84=A4=EA=B3=84=20=EB=AC=B8=EC=84=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git tag 푸시 → Windows MSIX 빌드 → S3 업로드 → CloudFront 배포 파이프라인의 인프라·워크플로·버킷 레이아웃·후속 작업 범위를 정리. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-05-26-cicd-s3-cloudfront-design.md | 301 ++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md diff --git a/docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md b/docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md new file mode 100644 index 00000000..e6bf57ab --- /dev/null +++ b/docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md @@ -0,0 +1,301 @@ +# CI/CD → S3 → CloudFront 배포 파이프라인 설계 + +- 작성일: 2026-05-26 +- 작성자: jysong (with Claude) +- 상태: 초안 (사용자 리뷰 대기) + +## 1. 목표 + +git tag 푸시 한 번으로 다음이 자동 수행된다. + +1. Windows에서 `.msixbundle` 빌드 +2. AWS S3 버킷(`scratch-link.aluxcoding.com` / `dev-scratch-link.aluxcoding.com`)에 업로드 +3. CloudFront를 통해 `https://scratch-link.aluxcoding.com/latest.msixbundle` 같은 고정 URL로 사용자가 다운로드 +4. 최신 버전 메타(`latest.json`)도 함께 갱신 + +이번 범위에서는 **빌드·업로드·CDN 배포까지만** 다룬다. MSIX 코드 사이닝과 `.appinstaller` 자동 업데이트는 [§9 후속 작업](#9-후속-작업-범위-밖)에 따로 기록. + +## 2. 결정된 사항 요약 + +| 항목 | 결정 | +|---|---| +| Cloud provider | AWS (account `593793057142`, region `ap-northeast-2`) | +| Infra 프로비저닝 방식 | **aws-cli 스크립트** (Terraform/CDK 미사용) | +| 트리거 | semver git tag 푸시 | +| 채널 라우팅 | stable 태그(`v1.2.0`) → prod, prerelease 태그(`v1.2.0-*`) → dev | +| 사용자 URL | `https://scratch-link.aluxcoding.com/latest.msixbundle` (고정) | +| 버킷 네이밍 | `scratch-link.aluxcoding.com`, `dev-scratch-link.aluxcoding.com` (조직 관습 일치) | +| Origin 패턴 | S3 website endpoint + 퍼블릭 버킷 (조직 기존 28개 distribution과 동일) | +| ACM 인증서 | 기존 `*.aluxcoding.com` (us-east-1, ARN `arn:aws:acm:us-east-1:593793057142:certificate/0b58642f-b20f-451b-8257-aa366ba5fc0c`) 재사용 | +| Route 53 | 기존 `aluxcoding.com.` zone(`Z0327990CY2GCD1RONPB`)에 A/AAAA Alias 추가 | +| IAM | 전용 user `gh-actions-scratch-link` 신규 생성. 두 버킷 + 두 distribution에 한해 최소 권한 | +| GitHub Actions 인증 | 위 IAM user의 access key를 **GitHub Organization Secret**으로 등록 | +| 기존 `ci.yml` | 완전 삭제 후 신규 `release.yml` 작성 | +| 코드 사이닝 | 이번 범위 제외. 빌드는 `GenerateTemporaryStoreCertificate=True` 기본값 유지 | + +## 3. AWS 인프라 + +### 3.1 리소스 목록 (신규 생성 6종 × 환경 2개) + +각 환경(prod/dev)당 다음을 생성한다. + +1. **S3 버킷** — 이름 = 도메인. `BlockPublicAccess` 해제, static website hosting 활성화, public-read 버킷 정책 +2. **CloudFront distribution** — origin = S3 website endpoint (`.s3-website.ap-northeast-2.amazonaws.com`), alias = 도메인, viewer cert = 기존 ACM, 기본 캐시 정책 (TTL은 §6에서 객체 단위 Cache-Control로 제어) +3. **Route 53 A/AAAA Alias** — `aluxcoding.com.` zone에 도메인 → CloudFront 매핑 + +공유 리소스 (한 번만): + +4. **IAM user** `gh-actions-scratch-link` + access key + 인라인 정책 (양 환경의 권한을 한꺼번에) + +### 3.2 IAM 정책 (전체) + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "S3UploadProd", + "Effect": "Allow", + "Action": ["s3:PutObject", "s3:DeleteObject", "s3:ListBucket"], + "Resource": [ + "arn:aws:s3:::scratch-link.aluxcoding.com", + "arn:aws:s3:::scratch-link.aluxcoding.com/*", + "arn:aws:s3:::dev-scratch-link.aluxcoding.com", + "arn:aws:s3:::dev-scratch-link.aluxcoding.com/*" + ] + }, + { + "Sid": "CloudFrontInvalidate", + "Effect": "Allow", + "Action": ["cloudfront:CreateInvalidation", "cloudfront:GetInvalidation"], + "Resource": [ + "arn:aws:cloudfront::593793057142:distribution/", + "arn:aws:cloudfront::593793057142:distribution/" + ] + } + ] +} +``` + +분포 ID(`PROD_DIST_ID`, `DEV_DIST_ID`)는 셋업 스크립트가 출력한 값을 정책에 반영하는 2-단계 절차로 처리한다 (§4.2). + +### 3.3 OAC를 안 쓰는 이유 + +조직 내 기존 28개 CloudFront distribution이 모두 S3 website + 퍼블릭 버킷 패턴. 일관성을 우선해 같은 패턴 채택. OAC(Origin Access Control)로의 마이그레이션은 별도 작업으로 분리. 참고로 OAC가 더 안전한 이유는 S3 버킷을 비공개로 유지하면서 CloudFront만 접근할 수 있게 강제할 수 있기 때문. + +## 4. 일회성 셋업 스크립트 + +### 4.1 위치 및 구성 + +``` +scripts/aws/ + setup-cdn.sh # 메인 entry. prod/dev 두 환경 모두 생성 + policies/ + bucket-policy.json.tpl # public-read 정책 템플릿 + iam-policy.json.tpl # IAM 인라인 정책 템플릿 + cloudfront-config.json.tpl # distribution 생성 입력 +``` + +- 실행 주체: **AWS 관리자 권한이 있는 로컬 사용자** (예: 현재 `jysong`). GitHub Actions에서 실행하지 않는다 — IAM user를 만드는 일은 일회성이고 CI에 그런 권한을 주는 게 위험 +- bash, aws-cli v2, `jq` 필요 +- **멱등**: 이미 존재하는 리소스는 skip (각 step 전에 describe로 존재 확인) +- 실행 후 콘솔에 다음을 출력: + - prod/dev CloudFront Distribution ID + - prod/dev CloudFront Domain (`d*.cloudfront.net`) + - IAM access key ID + secret (1회만 보임) + - 다음 수동 단계 안내 ("GitHub Org Secret에 등록", "정책에 distribution ID 채우기") + +### 4.2 실행 순서 (스크립트 내부) + +1. S3 버킷 2개 생성 + website hosting 활성화 + public-access-block 해제 + public-read bucket policy 적용 +2. CloudFront distribution 2개 생성 → ID 캡처 +3. Route 53 A/AAAA Alias 2개 등록 +4. IAM user 생성 + access key 발급 +5. 위에서 얻은 distribution ID로 IAM 인라인 정책 렌더링 → put-user-policy +6. 결과 요약 출력 + +원자성 보장은 안 함(스크립트 중간 실패 시 부분 생성 상태 가능). 멱등성에 의지해서 다시 실행하면 이어서 진행됨. + +## 5. GitHub Actions 워크플로 + +### 5.1 파일 + +- 기존 `.github/workflows/ci.yml` **삭제** +- 기존 `.github/workflows/signature-assistant.yml` 그대로 둠 (관련 없음) +- 기존 `.github/actions/macos-build/` **삭제**, `.github/actions/windows-build/`는 참고만 하고 새로 직접 구성 +- 신규 `.github/workflows/release.yml` 작성 + +### 5.2 트리거 + +```yaml +on: + push: + tags: + - 'v*.*.*' # stable: v1.2.0 + - 'v*.*.*-*' # prerelease: v1.2.0-beta.1, v1.2.0-rc.1 + workflow_dispatch: # 수동 재실행 안전망 + inputs: + channel: + type: choice + options: [auto, stable, dev] + default: auto +``` + +채널 결정 로직(워크플로 안의 step): +- `workflow_dispatch.inputs.channel != auto` → 입력값 사용 +- 태그에 `-` 포함 → `dev` +- 그 외 → `stable` + +채널에 따라 다음 env가 분기: +- `BUCKET` = `scratch-link.aluxcoding.com` or `dev-scratch-link.aluxcoding.com` +- `DISTRIBUTION_ID` = (Org Secret에서 채널별 ID) +- `BASE_URL` = `https://` + +### 5.3 단일 job 구조 (`windows-latest`) + +``` +1. actions/checkout@v4 (fetch-depth=0, tag fetch 위해) +2. actions/setup-dotnet@v4 → 8.0.x +3. microsoft/setup-msbuild@v2 +4. 채널·버전 산출 (bash step) → $GITHUB_ENV에 BUCKET, VERSION 등 export +5. msbuild scratch-link-win-msix/scratch-link-win-msix.wapproj \ + -maxCpuCount -restore -t:Build \ + -p:SolutionDir="$PWD\\" \ + -p:Configuration=Release_Win \ + -p:AppxBundlePlatforms="x86|x64|ARM64" \ + -p:AppxBundle=Always \ + -p:UapAppxPackageBuildMode=StoreAndSideload +6. 산출물 정리 (pwsh): + Artifacts/Scratch-Link-.msixbundle + Artifacts/Scratch-Link-.msixupload + Artifacts/SHA256SUMS.txt + Artifacts/latest.json +7. aws-actions/configure-aws-credentials@v4 (org secret access key) +8. aws s3 cp × 2: + ① Artifacts/ → s3://$BUCKET/archive/v/ (Cache-Control: max-age=31536000, immutable) + ② Scratch-Link-.msixbundle → s3://$BUCKET/latest.msixbundle + latest.json → s3://$BUCKET/latest.json + (Cache-Control: max-age=300, public) +9. aws cloudfront create-invalidation --distribution-id $DISTRIBUTION_ID --paths "/latest.msixbundle" "/latest.json" +``` + +> GitHub Release 생성(`gh release create`)은 본 범위에서 제외한다. 필요해지면 step 10으로 추가하는 변경이 작음. + +### 5.4 사용할 GitHub Secrets + +Organization 수준에서 다음 secret을 본 리포지토리에 노출시킨다. + +| Secret 이름 | 값 | +|---|---| +| `AWS_ACCESS_KEY_ID` | 셋업 스크립트가 출력한 ID | +| `AWS_SECRET_ACCESS_KEY` | 셋업 스크립트가 출력한 secret | +| `AWS_REGION` | `ap-northeast-2` | +| `CF_DIST_ID_PROD` | 셋업 스크립트가 출력한 prod distribution ID | +| `CF_DIST_ID_DEV` | 셋업 스크립트가 출력한 dev distribution ID | + +> **주의**: Org 시크릿에 이미 등록된 기존 `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY`가 다른 리포에서 사용 중이면 키 이름 충돌이 생길 수 있다. 충돌 시 본 워크플로에서는 `SCRATCH_LINK_AWS_*` 접두사로 분리한다. + +## 6. 버킷 객체 레이아웃 & 캐시 정책 + +``` +/ + latest.msixbundle Cache-Control: public, max-age=300 ← 5분 캐시 (안전 마진) + latest.json Cache-Control: public, max-age=300 + archive/ + v1.2.0/ + Scratch-Link-1.2.0.msixbundle Cache-Control: public, max-age=31536000, immutable + Scratch-Link-1.2.0.msixupload (Store 업로드용 보관, 같은 캐시) + SHA256SUMS.txt + v1.2.0-beta.1/ + ... +``` + +- 사용자가 보는 `latest.*`는 매 릴리스마다 덮어쓰기 → CloudFront invalidation 필수 +- `archive/v/...`는 한 번 올리면 영원히 안 변함 → immutable, invalidation 불필요 +- 두 객체만 invalidate (월 1000건 무료 한도 안에서 충분) + +### 6.1 `latest.json` 스키마 + +```json +{ + "version": "1.2.0", + "publishedAt": "2026-05-26T07:13:42Z", + "channel": "stable", + "url": "https://scratch-link.aluxcoding.com/archive/v1.2.0/Scratch-Link-1.2.0.msixbundle", + "sha256": "f2c4...", + "size": 18234567, + "minWindowsBuild": 17763, + "windowsAppRuntime": "1.8" +} +``` + +용도: +- 다운로드 사이트에서 최신 버전 표시 및 라벨링 +- 추후 인앱 자동 업데이트 검사에 동일 스키마 재사용 + +`url`은 매 릴리스마다 archive 경로를 가리키도록 갱신 — `latest.msixbundle`(고정 URL)과 둘 다 제공. 고정 URL은 단순 다운로드 버튼용, archive URL은 버전 명시가 필요한 곳용. + +## 7. 빌드 머신 환경 + +`windows-latest` 러너에 다음이 사전 설치되어 있음을 전제로 한다. + +- .NET 8 SDK +- Windows SDK 10.0.22621 +- MSBuild (Visual Studio 2022 Enterprise 워크로드 포함) +- `aws` CLI v2 + +확인 step을 워크플로 초입에 넣어 누락 시 조기 실패시킨다 (`dotnet --version`, `msbuild -version`). + +## 8. 변경되는 파일 목록 + +``` +신규: + .github/workflows/release.yml + scripts/aws/setup-cdn.sh + scripts/aws/policies/bucket-policy.json.tpl + scripts/aws/policies/iam-policy.json.tpl + scripts/aws/policies/cloudfront-config.json.tpl + scripts/aws/README.md ← 셋업 절차·시크릿 등록·트러블슈팅 + docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md (본 문서) + +삭제: + .github/workflows/ci.yml + .github/actions/macos-build/ + .github/actions/windows-build/ + +변경: + README.md ← 다운로드 URL 안내 한 줄 추가 +``` + +## 9. 후속 작업 (범위 밖) + +본 설계는 의도적으로 다음을 다루지 않는다. 각 항목은 별도 spec으로 분리한다. + +### 9.1 MSIX 코드 사이닝 + +현재 빌드는 `GenerateTemporaryStoreCertificate=True`로 임시 자체서명만 함. **일반 사용자는 받은 `.msixbundle`을 설치할 수 없다** (Trusted Root에 인증서가 없으므로). 결정 필요 사항: +- 어떤 인증서를 쓸지 (EV / 일반 코드사이닝 / Store 등록) +- 인증서 자료(PFX, 암호) 보관 위치 (GitHub Secret / AWS Secrets Manager) +- 워크플로에 `signtool.exe sign` 단계 추가 + +이 결정 전까지 본 파이프라인의 산출물은 **내부 테스트용**으로만 유효. + +### 9.2 MSIX `.appinstaller` 자동 업데이트 + +`.appinstaller` XML을 같이 배포하면, 사용자가 한 번 설치한 뒤로는 Windows가 자동으로 새 버전을 받는다. 코드 사이닝과 짝지어 적용해야 의미가 있다. + +### 9.3 OAC 마이그레이션 + +조직 전체 정책으로 결정될 사안. + +### 9.4 GitHub Actions OIDC 전환 + +현재는 IAM user + 장기 access key. 향후 OIDC로 전환하면 access key 로테이션 부담이 사라진다. + +## 10. 검증 시나리오 (구현 완료 시) + +1. **prerelease 시나리오**: `git tag v0.0.1-test.1 && git push origin v0.0.1-test.1` → dev 버킷에 객체 도착 → `https://dev-scratch-link.aluxcoding.com/latest.json`이 `0.0.1-test.1` 표시 → `latest.msixbundle` 다운로드 가능 +2. **stable 시나리오**: `git tag v0.0.1 && git push origin v0.0.1` → prod 버킷에 동일 +3. **권한 시나리오**: IAM user로 다른 버킷(`scratch.aluxcoding.com` 등)에 `aws s3 cp` 시도 → AccessDenied 확인 +4. **캐시 시나리오**: `latest.msixbundle` 갱신 후 5분 이내 새 버전이 CDN에 반영 +5. **archive 영구 보관**: 한 달 후에도 `archive/v0.0.1/Scratch-Link-0.0.1.msixbundle` 접근 가능 From 10edf70f2497300767772f7cc0a825fc76f42df8 Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 11:59:59 +0900 Subject: [PATCH 30/94] =?UTF-8?q?docs(cicd):=20WAF=20=EC=A0=9C=EC=99=B8=20?= =?UTF-8?q?=EB=B2=94=EC=9C=84=20=EB=AA=85=EC=8B=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 후속 작업 섹션에 WAF가 이번 범위에서 빠지는 이유와 재검토 트리거 조건을 기록. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../specs/2026-05-26-cicd-s3-cloudfront-design.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md b/docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md index e6bf57ab..08d12c05 100644 --- a/docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md +++ b/docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md @@ -292,6 +292,13 @@ Organization 수준에서 다음 secret을 본 리포지토리에 노출시킨 현재는 IAM user + 장기 access key. 향후 OIDC로 전환하면 access key 로테이션 부담이 사라진다. +### 9.5 WAF (AWS WAFv2) + +CloudFront 앞단에 WebACL 부착은 **이번 범위에서 제외**한다. 사용자가 받는 것은 정적 `.msixbundle` 파일 1개와 `latest.json` 1개뿐이라, 입력 검증·SQLi·XSS 같은 WAF 본연의 보호 대상이 없다. 비용·복잡도만 늘어남. 향후 다음 중 하나가 발생하면 재검토: +- 봇 트래픽이 비정상적으로 늘어 대역폭 비용이 문제됨 +- 특정 국가에서의 다운로드를 차단해야 하는 요구사항 발생 +- 인증된 다운로드(서명된 URL 등) 도입 + ## 10. 검증 시나리오 (구현 완료 시) 1. **prerelease 시나리오**: `git tag v0.0.1-test.1 && git push origin v0.0.1-test.1` → dev 버킷에 객체 도착 → `https://dev-scratch-link.aluxcoding.com/latest.json`이 `0.0.1-test.1` 표시 → `latest.msixbundle` 다운로드 가능 From 748c48ba484bd9faeba3b1f3cff41017ad0264bf Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 May 2026 13:06:11 +0900 Subject: [PATCH 31/94] =?UTF-8?q?docs(rebrand):=20AluxLabs=20Link=20?= =?UTF-8?q?=EB=A6=AC=EB=B8=8C=EB=9E=9C=EB=94=A9=20=EC=9E=91=EC=97=85=20?= =?UTF-8?q?=EA=B3=84=ED=9A=8D=EC=84=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 원본 scratch-link 포크를 "AluxLabs Link"로 분리하기 위한 전수 변경 계획. 식별자 매핑, 작업 순서, 파일별 변경 목록, AGPL 준수 가이드라인, 검증 체크리스트, NOTICE 템플릿을 포함한다. Co-Authored-By: Claude Opus 4.7 (1M context) --- Documentation/Alux/RebrandingPlan.md | 381 +++++++++++++++++++++++++++ 1 file changed, 381 insertions(+) create mode 100644 Documentation/Alux/RebrandingPlan.md diff --git a/Documentation/Alux/RebrandingPlan.md b/Documentation/Alux/RebrandingPlan.md new file mode 100644 index 00000000..2a6848f9 --- /dev/null +++ b/Documentation/Alux/RebrandingPlan.md @@ -0,0 +1,381 @@ +# 리브랜딩 작업 계획서 — scratch-link → AluxLabs Link + +원본 `scratch-link` (Scratch Foundation, AGPL-3.0) 의 Windows 포크를 **"AluxLabs Link"** 라는 독립 제품으로 분리하기 위한 전수 변경 목록. + +## 1. 목표와 결정 사항 + +| 항목 | 결정값 | 비고 | +|---|---|---| +| 사용자 표시명 | **AluxLabs Link** | 트레이, 인스톨러, About 등 모든 UI | +| 회사명 | ALUX, Inc. | 이미 적용된 상태 | +| 상표 회피 | 제품명에 "Scratch" 단어 **사용 금지** | nominative fair use 도 안전 마진 위해 회피 | +| Scratch 호환성 표현 | 문서에 한정해 "Scratch 와 호환됨" 정도만 | "for Scratch" / "Scratch-compatible" 같이 endorsement 로 읽히는 표현 회피 | +| 라이선스 | AGPL-3.0-only 유지 | 원본과 동일. 파생 저작물 의무 준수 | +| 원본 attribution | 모든 파일의 `// Copyright (c) Scratch Foundation` 헤더 **보존** | AGPL §5 요구 | + +### 1.1 식별자 매핑 (소스 of truth) + +| 종류 | 기존 | 신규 | +|---|---|---| +| 사용자 표시명 (Display) | `Alux Scratch Link` / `scratch-link` | `AluxLabs Link` | +| 어셈블리명 (`AssemblyName`) | `Alux Scratch Link` | `AluxLabs Link` | +| 루트 네임스페이스 | `ScratchLink` | `AluxLabs.Link` | +| Windows 네임스페이스 | `ScratchLink.Win` | `AluxLabs.Link.Win` | +| 핵심 클래스 | `ScratchLinkApp` | `AluxLabsLinkApp` | +| 솔루션 파일 | `scratch-link.sln` | `aluxlabs-link.sln` | +| 폴더 (Windows 본체) | `scratch-link-win/` | `aluxlabs-link-win/` | +| 폴더 (공통 코드) | `scratch-link-common/` | `aluxlabs-link-common/` | +| 폴더 (MSIX) | `scratch-link-win-msix/` | `aluxlabs-link-win-msix/` | +| 프로젝트 파일 | `scratch-link-win.csproj` 등 | `aluxlabs-link-win.csproj` 등 | +| 아이콘 파일 | `scratch-link.ico` / `scratch-link-tray.ico` | `aluxlabs-link.ico` / `aluxlabs-link-tray.ico` | +| MSIX Package Identity `Name` | `ScratchFoundation.1711508CFD202` | `ALUXInc.AluxLabsLink` (임시. Partner Center 등록 시 발급값으로 교체) | +| MSIX Package Identity `Publisher` | `CN=2EC43DF1-469A-4119-9AB9-568A0A1FF65F` | 서명 인증서 Subject 의 CN (자체 서명 cert 또는 Store 발급값) | +| WebSocket 포트 | 20211 (변경 없음) | 동일 — Scratch 와 연결되는 endpoint | +| WebSocket path (`/scratch/ble` 등) | 변경 없음 | 동일 — Scratch 의 클라이언트 API 규약 | + +## 2. 절대 변경 금지 (AGPL §5 / 상표 표시) + +다음 항목은 라이선스/상표 의무 때문에 **건드리면 안 된다**. + +| 항목 | 위치 | 이유 | +|---|---|---| +| AGPL 라이선스 전문 | `LICENSE` | AGPL §5 — 라이선스 텍스트 동봉 의무 | +| 상표 정책 문서 | `TRADEMARK` | Scratch Foundation 상표권 명시 — 삭제 시 법적 분쟁 위험 | +| 파일 헤더 `// ` | 모든 원본 유래 `.cs` | AGPL §5 — 원저작자 표시 보존 | +| `// Copyright (c) Scratch Foundation. All rights reserved.` | 모든 원본 유래 `.cs` | 동일 | +| `// Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only.` | ALUX 신규 작성 파일의 헤더 | 이미 정확한 attribution. 유지 | +| 프로토콜 식별자 문자열 | `/scratch/ble`, `/scratch/bt`, `/scratch/serial` (WebSocket path) | Scratch 클라이언트와의 wire-level 호환성 | +| 프로토콜 문서 | `Documentation/Architecture.md`, `Documentation/BluetoothLE.md`, `Documentation/Bluetooth.md`, `Documentation/NetworkProtocol.md`, `Documentation/TestPlans.md` | 원본 프로토콜 명세 — 사실상 historical reference. "Scratch Link" 단어를 protocol 명칭으로 보고 그대로 둠 | +| `Documentation/Alux/SerialApiReference.md` 등에서 protocol 을 가리키는 "Scratch Link" 언급 | 동일 docs 일부 | 같은 이유. 단 우리 제품을 가리키는 부분은 변경 | +| 코드 안 doc comment 의 "Scratch Link protocol" / "Scratch Link sessions" | `Session.cs:28,33`, `EncodingHelpers.cs:14,15`, `BLESession.cs:52`, `ScratchLinkApp.cs:13` 등 | 프로토콜의 일반명칭으로 해석. 변경 시 `Scratch Link 프로토콜` 등으로 명시화 가능 (선택) | + +### 2.1 신규 추가 권장 (AGPL §5) + +- **`NOTICE` 파일 신규 작성** — fork 출처와 변경자 명시. 본문 예시는 §7 참조 +- 기존 원본 파일을 ALUX 가 **상당히 수정**한 경우 헤더 아래 한 줄 추가 (선택): + `// Modified by ALUX, Inc. on 2026-MM-DD: <간단한 사유>` + +## 3. 작업 범위 — 포함 / 제외 + +### 3.1 포함 (Windows 빌드 체인) + +`scratch-link.sln` 에 포함되고 Windows 빌드에 영향: + +- 루트 파일: `LICENSE`, `TRADEMARK`, `README.md`, `package.json`, `Makefile`, `playground.html`, `playground.js`, `.editorconfig`, `stylecop.json`, `release.config.js`, `renovate.json5`, `global.d.ts` +- `scratch-link-common/` (`.shproj`, `.projitems`, 모든 `.cs`) +- `scratch-link-win/` (`.csproj`, `.xaml`, 모든 `.cs`, `app.manifest`, 아이콘) +- `scratch-link-win-msix/` (`.wapproj`, `Package.appxmanifest`, 이미지) +- `SharedProps/` (`.props`, `.targets`) +- `Documentation/Alux/` 전체 +- `.github/actions/windows-build/action.yml` +- `brand/build_icons.py` +- `CLAUDE.md` + +### 3.2 제외 (이번 작업에서 손대지 않음) + +| 항목 | 이유 | +|---|---| +| `scratch-link-mac/` 전체 | Mac 빌드 안 함. 솔루션에 "Unsupported" 로만 표시 | +| `Scratch Link Safari Helper/` 전체 | Mac Safari 확장. Windows 무관 | +| `scratch-link/` (MAUI 폴더) | 솔루션에서 빠진 레거시 코드. 별도 정리 권장 | +| `fastlane/` | Mac 서명 자동화 | +| `bin/`, `obj/`, `.vs/`, `*.user` | 자동 생성. 빌드 시 재생성 | +| `Scratch Link Safari Helper/` 안의 모든 파일명 | Mac 전용 | +| `.github/actions/macos-build/action.yml` | Mac CI | +| `Documentation/Architecture.md` 등 upstream 원본 문서 | §2 — 프로토콜 명세, AGPL attribution | + +> Mac 프로젝트는 같은 `scratch-link-common` 을 import 하기 때문에, common 폴더/파일명을 바꾸면 `scratch-link-mac.csproj:212` 의 `Import Project="..\scratch-link-common\scratch-link-common.projitems"` 가 깨진다. Mac 은 어차피 안 빌드되므로 무시 가능하지만, 정리 차원에서 같이 업데이트하거나 솔루션에서 Mac 프로젝트를 빼는 것도 검토. + +## 4. 작업 순서 (의존성 고려) + +순서 잘못 잡으면 빌드가 깨지거나 식별자 충돌이 난다. 권장 순서: + +| 단계 | 작업 | 빌드 영향 | +|---|---|---| +| 1 | MSIX Identity 임시값으로 변경 (cert 결정 전이라도 `ALUXInc.AluxLabsLink` + `CN=ALUX, Inc.` 자체 서명 임시 cert) | MSIX 빌드만 영향. EXE 빌드 무관 | +| 2 | UI 노출 문자열 변경 (DisplayName, ToolTip, About) | 빌드 영향 미미 | +| 3 | NOTICE 파일 신규 작성 + README 어트리뷰션 보강 | 빌드 무관 | +| 4 | `AssemblyName` / `RootNamespace` 변경 → `bin/obj` 전체 삭제 후 재빌드 | csproj 단위 | +| 5 | 모든 `.cs` 의 `namespace`, `using` 일괄 치환 (`ScratchLink` → `AluxLabs.Link`) | 빌드 깨짐 → 일관 치환 후 회복 | +| 6 | 클래스 `ScratchLinkApp` → `AluxLabsLinkApp` 리네임 | 빌드 깨짐 → 사용처 동시 치환 | +| 7 | XAML 의 `x:Class`, `xmlns:local` 갱신 | XAML 컴파일 | +| 8 | `.cs` 파일명 변경 (`ScratchLinkApp.cs` → `AluxLabsLinkApp.cs`) | 무영향 (csproj 가 와일드카드 include 면) | +| 9 | 아이콘 파일명 변경 + csproj 의 `Content Include` / `ApplicationIcon` 동시 갱신 | 빌드 | +| 10 | 프로젝트 파일명 변경 (`*.csproj`, `*.wapproj`, `*.shproj`, `.projitems`) + `.sln` 의 경로 동시 갱신 (ProjectGuid 보존) | 솔루션 로드 | +| 11 | 폴더명 변경 + `.sln` / csproj 의 모든 `..\scratch-link-*\` 경로 갱신 | 솔루션 | +| 12 | 솔루션 파일명 변경 (`scratch-link.sln` → `aluxlabs-link.sln`) | 마지막 | +| 13 | `Documentation/Alux/*.md`, `CLAUDE.md`, `README.md`, `.github/actions/windows-build/action.yml` 의 경로/이름 참조 갱신 | 문서 | +| 14 | 전체 빌드 검증 (Debug_Win / Release_Win 양쪽) | 최종 | + +> **VS 의 리팩토링 기능 우선 활용**: 5~7 단계는 Visual Studio 의 "Rename" (F2) 가 가장 안전. namespace 변경 시 VS 가 `using` 까지 자동 갱신. sed 일괄 치환은 마지막 보루. + +> **Git 커밋 분리 권장**: 단계별로 커밋. 한 커밋에 모두 몰면 충돌 시 분리 불가. 권장 단위: (a) MSIX identity 만, (b) UI 문자열 만, (c) AssemblyName/네임스페이스, (d) 파일/폴더 rename, (e) 문서 갱신. + +## 5. 파일별 변경 목록 + +### 5.1 MSIX Identity (Tier A — 최우선) + +#### [scratch-link-win-msix/Package.appxmanifest](../../scratch-link-win-msix/Package.appxmanifest) + +| 라인 | 현재 | 변경 | +|---|---|---| +| 10 | `Name="ScratchFoundation.1711508CFD202"` | `Name="ALUXInc.AluxLabsLink"` (Store 발급 시 교체) | +| 11 | `Publisher="CN=2EC43DF1-469A-4119-9AB9-568A0A1FF65F"` | 서명 인증서 Subject CN 으로 교체 | +| 15 | `Alux Scratch Link` | `AluxLabs Link` | +| 16 | `ALUX, Inc.` | (그대로) | +| 34 | `DisplayName="Alux Scratch Link"` | `DisplayName="AluxLabs Link"` | +| 35 | `Description="Alux Scratch Link"` | `Description="AluxLabs Link"` | + +#### [scratch-link-win/app.manifest](../../scratch-link-win/app.manifest) + +| 라인 | 현재 | 변경 | +|---|---|---| +| 3 | `name="Alux Scratch Link.app"` | `name="AluxLabs Link.app"` | + +### 5.2 UI 노출 문자열 (Tier B) + +#### [scratch-link-win/TrayIcon.xaml](../../scratch-link-win/TrayIcon.xaml) + +| 라인 | 현재 | 변경 | +|---|---|---| +| 7 | `xmlns:local="using:ScratchLink.Win"` | `xmlns:local="using:AluxLabs.Link.Win"` | +| 10 | `x:Key="ScratchLinkTaskbarIcon"` | `x:Key="AluxLabsLinkTaskbarIcon"` (App.xaml.cs:95 도 동시 갱신) | +| 12 | `ToolTipText="Alux Scratch Link"` | `ToolTipText="AluxLabs Link"` | +| 14 | `IconSource="scratch-link-tray.ico"` | `IconSource="aluxlabs-link-tray.ico"` | +| 26 | `Label="Alux Scratch Link 1.0.0.0"` | `Label="AluxLabs Link 1.0.0.0"` | + +### 5.3 csproj / 어셈블리 메타데이터 (Tier B) + +#### [scratch-link-win/scratch-link-win.csproj](../../scratch-link-win/scratch-link-win.csproj) + +| 라인 | 현재 | 변경 | +|---|---|---| +| 7 | `ScratchLink.Win` | `AluxLabs.Link.Win` | +| 8 | `Alux Scratch Link` | `AluxLabs Link` | +| 21 | `scratch-link.ico` | `aluxlabs-link.ico` | +| 23 | `Import Project="..\scratch-link-common\scratch-link-common.projitems"` | 폴더/파일 리네임 후 `..\aluxlabs-link-common\aluxlabs-link-common.projitems` | +| 37 | `` | `` | +| 38 | `` | `` | + +#### [scratch-link-win-msix/scratch-link-win-msix.wapproj](../../scratch-link-win-msix/scratch-link-win-msix.wapproj) + +| 라인 | 현재 | 변경 | +|---|---|---| +| 51 | `..\scratch-link-win\scratch-link-win.csproj` | `..\aluxlabs-link-win\aluxlabs-link-win.csproj` | +| 99 | `` | `..\aluxlabs-link-win\aluxlabs-link-win.csproj` | + +#### [SharedProps/ScratchVersion.targets](../../SharedProps/ScratchVersion.targets) + +| 라인 | 현재 | 변경 | +|---|---|---| +| 47 | 코멘트: `"Alux Scratch Link 1.0.0.x"` | `"AluxLabs Link 1.0.0.x"` | + +> 파일명 `ScratchVersion.targets` 자체는 MSBuild target name 이므로 굳이 안 바꿔도 됨. 바꾸려면 `AluxLabsVersion.targets` 로 변경하고 모든 `` 갱신. + +### 5.4 C# 네임스페이스 일괄 치환 (Tier C — 가장 큰 작업) + +**치환 규칙**: + +| 기존 | 신규 | +|---|---| +| `namespace ScratchLink;` | `namespace AluxLabs.Link;` | +| `namespace ScratchLink.Win;` | `namespace AluxLabs.Link.Win;` | +| `namespace ScratchLink.Win.BLE;` | `namespace AluxLabs.Link.Win.BLE;` | +| `namespace ScratchLink.Win.BT;` | `namespace AluxLabs.Link.Win.BT;` | +| `namespace ScratchLink.Win.Serial;` | `namespace AluxLabs.Link.Win.Serial;` | +| `namespace ScratchLink.BLE;` | `namespace AluxLabs.Link.BLE;` | +| `namespace ScratchLink.BT;` | `namespace AluxLabs.Link.BT;` | +| `namespace ScratchLink.Serial;` | `namespace AluxLabs.Link.Serial;` | +| `namespace ScratchLink.JsonRpc;` | `namespace AluxLabs.Link.JsonRpc;` | +| `namespace ScratchLink.JsonRpc.Converters;` | `namespace AluxLabs.Link.JsonRpc.Converters;` | +| `namespace ScratchLink.Extensions;` | `namespace AluxLabs.Link.Extensions;` | +| `using ScratchLink;` / `using ScratchLink.*;` | 모두 대응되는 `AluxLabs.Link*` 로 | +| 클래스 `ScratchLinkApp` | `AluxLabsLinkApp` | + +**영향 파일 목록** (전수, 약 50개 — `using` 만 갱신되는 케이스 포함): + +`scratch-link-common/`: +- ScratchLinkApp.cs (파일명도 변경 → AluxLabsLinkApp.cs) +- Session.cs +- SessionManager.cs +- PeripheralSession.cs +- WebSocketListener.cs +- EncodingHelpers.cs +- EventAwaiter.cs +- BLE/IBLEEndpoint.cs +- BLE/BLESession.cs +- BLE/GattHelpers.cs +- BT/BTSession.cs +- Serial/SerialSession.cs +- Serial/SerialOpenParams.cs +- Serial/SerialDiscoveryFilter.cs +- JsonRpc/JsonRpc2Message.cs +- JsonRpc/JsonRpc2Request.cs +- JsonRpc/JsonRpc2Response.cs +- JsonRpc/JsonRpc2Error.cs +- JsonRpc/JsonRpc2Exception.cs +- JsonRpc/Converters/JsonRpc2MessageConverter.cs +- JsonRpc/Converters/JsonRpc2ValueConverter.cs +- Extensions/ContainerExtensions.cs +- Extensions/JsonExtensions.cs +- Extensions/SemaphoreSlimExtensions.cs + +`scratch-link-win/`: +- App.xaml.cs (line 5, 11, 12, 27, 57, 95) +- App.xaml (line 5, 8 — `x:Class`, `xmlns:local`) +- TrayIcon.xaml (line 7 — `xmlns:local`) +- WinSessionManager.cs +- BLE/WinBLESession.cs +- BLE/WinBLEEndpoint.cs +- BLE/WinGattHelpers.cs +- BT/WinBTSession.cs +- Serial/WinSerialSession.cs +- Serial/WinSerialPortInfo.cs +- Serial/WinSerialPortEnumerator.cs + +`scratch-link-common/scratch-link-common.projitems`: +- 라인 9: `ScratchLink` → `AluxLabs.Link` +- 라인 30: `` → 파일명 변경 시 동시 갱신 + +### 5.5 파일명 변경 (Tier D) + +| 기존 | 신규 | +|---|---| +| `scratch-link-common/ScratchLinkApp.cs` | `aluxlabs-link-common/AluxLabsLinkApp.cs` | +| `scratch-link-common/scratch-link-common.shproj` | `aluxlabs-link-common/aluxlabs-link-common.shproj` | +| `scratch-link-common/scratch-link-common.projitems` | `aluxlabs-link-common/aluxlabs-link-common.projitems` | +| `scratch-link-win/scratch-link-win.csproj` | `aluxlabs-link-win/aluxlabs-link-win.csproj` | +| `scratch-link-win/scratch-link.ico` | `aluxlabs-link-win/aluxlabs-link.ico` | +| `scratch-link-win/scratch-link-tray.ico` | `aluxlabs-link-win/aluxlabs-link-tray.ico` | +| `scratch-link-win-msix/scratch-link-win-msix.wapproj` | `aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj` | +| `scratch-link.sln` | `aluxlabs-link.sln` | + +### 5.6 폴더 변경 (Tier D) + +| 기존 | 신규 | +|---|---| +| `scratch-link-common/` | `aluxlabs-link-common/` | +| `scratch-link-win/` | `aluxlabs-link-win/` | +| `scratch-link-win-msix/` | `aluxlabs-link-win-msix/` | + +> 폴더 rename 시 `.sln` 의 모든 프로젝트 경로, 모든 csproj/projitems 의 `..\` 상대 경로, `.github/actions/windows-build/action.yml` 의 빌드 명령 경로 모두 동시 갱신 필요. ProjectGuid 는 **절대 바꾸지 말 것** — 솔루션이 GUID 로 프로젝트를 식별하기 때문. + +### 5.7 .sln 파일 (Tier E) + +#### [scratch-link.sln](../../scratch-link.sln) + +| 라인 | 변경 | +|---|---| +| 33 | `"scratch-link-common", "scratch-link-common\scratch-link-common.shproj", ...` → `"aluxlabs-link-common", "aluxlabs-link-common\aluxlabs-link-common.shproj", ...` (GUID 유지) | +| 53 | `"scratch-link-win", "scratch-link-win\scratch-link-win.csproj", ...` → `"aluxlabs-link-win", "aluxlabs-link-win\aluxlabs-link-win.csproj", ...` (GUID 유지) | +| 55 | `"scratch-link-win-msix", "scratch-link-win-msix\scratch-link-win-msix.wapproj", ...` → 동일 패턴 | +| 223~225 | `scratch-link-common\scratch-link-common.projitems*{guid}*SharedItemsImports` 경로 갱신 | + +> Mac 프로젝트 (`scratch-link-mac`, line 35) 는 그대로 두되, 안의 `Import Project="..\scratch-link-common\..."` 참조가 깨지므로 솔루션 빌드 시 unloaded 상태가 됨. Windows 빌드에는 영향 없음. + +### 5.8 GitHub Actions (Tier F) + +#### [.github/actions/windows-build/action.yml](../../.github/actions/windows-build/action.yml) + +| 라인 | 현재 | 변경 | +|---|---|---| +| 22 | `msbuild scratch-link-win-msix/scratch-link-win-msix.wapproj ...` | `msbuild aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj ...` | +| 28 | `mv -v scratch-link-win-msix/AppPackages/scratch-link-win-msix_*_${{...}}.msixupload Artifacts/` | 경로/패턴 갱신 | +| 30 | `for PKGPATH in scratch-link-win-msix/AppPackages/scratch-link-win-msix_*_..._Win_Test/scratch-link-win-msix_*_..._Win.msixbundle; do` | 동일 | +| 33 | 정규식 `scratch-link-win-msix_([.0-9]+)_(.*)_..._Win.msixbundle$` | `aluxlabs-link-win-msix_...` | +| 39, 41 | `mv -v "$PKGPATH" "Artifacts/Scratch Link ${PKGVERSION}.msixbundle"` | `"Artifacts/AluxLabs Link ${PKGVERSION}.msixbundle"` | + +### 5.9 문서 / 메타데이터 (Tier F) + +| 파일 | 변경 사항 | +|---|---| +| [README.md](../../README.md) | 제목 `# Alux Scratch Link` → `# AluxLabs Link`. 본문의 "Alux Scratch Link" 모든 인스턴스. fork 출처 attribution 강화 (§7 NOTICE 텍스트 참조). 저장소 구조 트리의 폴더명 갱신. | +| [CLAUDE.md](../../CLAUDE.md) | 폴더명/프로젝트명 언급 갱신. `scratch-link-common`, `scratch-link-win`, `scratch-link-win-msix` → 신규 이름 | +| [Documentation/Alux/WindowsDevSetup-VS2026.md](WindowsDevSetup-VS2026.md) | 라인 3, 7, 9~12, 32, 54~56, 66, 68, 76~78, 88~89, 94~95 — 폴더/파일/제품명 갱신 | +| [Documentation/Alux/SerialKeepAliveGuide.md](SerialKeepAliveGuide.md) | 라인 5 의 "Scratch Link serial transport" — protocol 표현은 유지하거나 "AluxLabs Link 의 serial transport (Scratch Link serial protocol 구현)" 식으로 명확화 | +| [Documentation/Alux/SerialApiReference.md](SerialApiReference.md) | 라인 358 의 "Scratch Link does not retry..." → "AluxLabs Link does not retry..." (구현 동작 설명이므로 우리 제품명으로) | +| [package.json](../../package.json) | `"name": "alux-scratch-link"` → `"name": "aluxlabs-link"`. description 갱신 | +| [Makefile](../../Makefile) | `scratch-link` 관련 타겟 경로 갱신 (Windows 빌드에 직접 관여하지는 않음 — icons 등) | +| [brand/build_icons.py](../../brand/build_icons.py) | 출력 파일명 `scratch-link.ico` / `scratch-link-tray.ico` → `aluxlabs-link.ico` / `aluxlabs-link-tray.ico` | +| `playground.html` / `playground.js` | 원본 테스트 페이지. "Scratch Link" 단어가 *우리 앱*을 가리키는 부분만 갱신. 프로토콜 설명 부분은 유지 | + +## 6. 작업 후 검증 체크리스트 + +- [ ] `Documentation/Architecture.md`, `BluetoothLE.md`, `NetworkProtocol.md`, `TestPlans.md`, `Bluetooth.md` 의 원본 텍스트는 **변경되지 않았다** +- [ ] `LICENSE`, `TRADEMARK` 는 **변경되지 않았다** +- [ ] 모든 `.cs` 파일의 `// ` 헤더가 **유지되었다** +- [ ] `NOTICE` 파일이 새로 생성되었고 fork 출처가 명시되었다 +- [ ] `README.md` 에 fork 출처 + AGPL 라이선스 표시 + 상표 무관 disclaimer 가 있다 +- [ ] `grep -ri "Alux Scratch Link"` 결과 0건 (build 산출물 제외) +- [ ] `grep -ri "scratch-link"` 결과 — 원본 attribution 헤더와 프로토콜 명세 문서를 제외하면 0건 +- [ ] `grep -ri "ScratchLink"` 결과 — 위와 동일 기준 +- [ ] MSIX Package Identity 의 `Name`/`Publisher` 가 원본 ScratchFoundation 값이 **아니다** +- [ ] `dotnet build -c Debug_Win` 성공 +- [ ] `msbuild aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj -p:Configuration=Release_Win -p:Platform=x64` 성공 +- [ ] 생성된 `.msixbundle` 파일명에 "AluxLabs Link" 가 들어가고 "Scratch" 가 들어가지 **않는다** +- [ ] MSIX 설치 후 시작 메뉴 / 트레이 / About 의 표시명이 모두 "AluxLabs Link" 다 +- [ ] 트레이 아이콘 우클릭 → 버전 복사 후 클립보드에 "AluxLabs Link" 가 들어 있다 +- [ ] 기존 PC 에 원본 Scratch Link 가 설치돼 있어도 충돌 없이 사이드바이사이드 설치된다 +- [ ] WebSocket 포트 20211, path `/scratch/ble`, `/scratch/bt`, `/scratch/serial` 가 그대로 동작한다 (Scratch 호환성) + +## 7. NOTICE 파일 신규 작성 (§2.1) + +`NOTICE` 파일을 저장소 루트에 신규 생성. 권장 내용: + +``` +AluxLabs Link +Copyright (c) 2026 ALUX, Inc. + +This product is derived from scratch-link by the Scratch Foundation +(https://github.com/scratchfoundation/scratch-link), originally licensed +under the GNU Affero General Public License v3.0 (AGPL-3.0-only). + +This product is also distributed under the AGPL-3.0-only license. +See the LICENSE file for the full license text. + +The following modifications have been made by ALUX, Inc.: + - Removed macOS support and Safari Helper extension + - Added USB Serial transport support + - Changed default WebSocket port to 20211 to allow coexistence with + the original Scratch Link on the same machine + - Upgraded to .NET 8 and Windows App SDK 1.8 + - (etc.) + +"Scratch" is a trademark of the Scratch Foundation. AluxLabs Link is +not affiliated with, endorsed by, or sponsored by the Scratch Foundation. +References to the "Scratch Link protocol" in source code documentation +refer to the network protocol established by the original scratch-link +project, used here for client compatibility. +``` + +README 상단에도 다음 블록을 추가 (이미 일부 표현 있음 — 통합/강화): + +```markdown +This is a Windows-only fork of [scratch-link](https://github.com/scratchfoundation/scratch-link) +by the Scratch Foundation, redistributed under the AGPL-3.0-only license. + +"Scratch" is a trademark of the Scratch Foundation. This product is not +affiliated with, endorsed by, or sponsored by the Scratch Foundation. +``` + +## 8. 리스크 / 함정 + +| 위험 | 대응 | +|---|---| +| ProjectGuid 변경으로 .sln 깨짐 | GUID 는 **유지**. 이름과 경로만 변경 | +| Mac 프로젝트 (`scratch-link-mac`) 의 `Import Project="..\scratch-link-common\..."` 경로 깨짐 | Windows 빌드 영향 없음. Mac 안 쓰면 무시 가능. 깔끔히 정리하려면 솔루션에서 Mac 프로젝트 제거 또는 동일 경로 갱신 | +| Visual Studio 캐시 (`.vs/`) 가 옛 경로 보존 | rename 후 `.vs/` 폴더 삭제 후 솔루션 재오픈 | +| `bin/obj` 의 옛 어셈블리명 산출물 잔존 | rename 후 두 폴더 모두 삭제 | +| MSIX 의 데이터 폴더 위치 변경 | `Identity Name` 이 바뀌면 `%LOCALAPPDATA%\Packages\` 경로가 새로 생김. 기존 데이터 마이그레이션 불필요 (개발 중인 fork 이므로) | +| GitHub Actions workflow 가 옛 경로로 실행되어 CI 실패 | `.github/actions/windows-build/action.yml` 의 경로/패턴 정규식 동시 갱신 후 push | +| 원본 Scratch Foundation 의 copyright header 를 실수로 제거 | grep 으로 사전 검증. `grep -rn "Copyright (c) Scratch Foundation"` 결과가 변경 전과 동일해야 함 | +| 프로토콜 doc comment 에서 "Scratch Link" 를 제품명인 줄 알고 변경 | §2 의 "프로토콜 식별자" 항목 참고. 모호하면 `Scratch Link protocol` 로 명시화 | +| Partner Center 등록 후 받은 Identity Name/Publisher 와 임시값 충돌 | Store 발급값을 받은 시점에 manifest 의 두 줄만 다시 교체. 다른 식별자 영향 없음 | + +## 9. Out-of-scope — 별도 작업 검토 + +- `scratch-link/` MAUI 폴더 제거 여부 (현재 솔루션에 포함 안 되지만 디스크에 잔존) +- `scratch-link-mac/` 솔루션에서 분리 또는 별도 저장소로 옮기기 +- `Scratch Link Safari Helper/` 폴더 통째 제거 +- `fastlane/` 폴더 제거 +- Documentation 폴더의 upstream 원본 문서들을 `Documentation/Upstream/` 같은 서브폴더로 정리 (구분 명확화) From 5a7fb808212096cc972a976b1bade519dcc1d390 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 May 2026 13:21:48 +0900 Subject: [PATCH 32/94] =?UTF-8?q?docs(rebrand):=20NOTICE=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20README=20=EB=9D=BC=EC=9D=B4=EC=84=A0?= =?UTF-8?q?=EC=8A=A4=C2=B7=EC=83=81=ED=91=9C=20=EA=B3=A0=EC=A7=80=20?= =?UTF-8?q?=EB=B3=B4=EA=B0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 원본 scratch-link 의 fork 출처, AGPL-3.0-only 라이선스, 소스 코드 위치, 주요 수정 사항, Scratch 상표 무관 disclaimer 를 명시한다. 영문 정본(NOTICE)과 한국어 참고 번역(NOTICE.ko)을 분리. README 상단에 동일 내용을 blockquote 로 요약 표시하고, 제품명을 "AluxLabs Link" 로 표기 통일. Co-Authored-By: Claude Opus 4.7 (1M context) --- NOTICE | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ NOTICE.ko | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 9 ++++++--- 3 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 NOTICE create mode 100644 NOTICE.ko diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000..3b4d76f0 --- /dev/null +++ b/NOTICE @@ -0,0 +1,49 @@ +AluxLabs Link +Copyright (c) 2026 ALUX, Inc. + +This file is the authoritative version. A Korean translation is +available at NOTICE.ko (for reference only). + + +Origin and license + +This product is derived from scratch-link by the Scratch Foundation +(https://github.com/scratchfoundation/scratch-link), originally licensed +under the GNU Affero General Public License v3.0 (AGPL-3.0-only). + +AluxLabs Link is also distributed under the AGPL-3.0-only license. +See the LICENSE file for the full license text. + +The complete corresponding source code of this product, including all +modifications by ALUX, Inc., is publicly available at: + https://github.com/aluxrobot/scratch-link + + +Significant modifications by ALUX, Inc. + +- Windows-only distribution; the upstream macOS application and Safari + Helper extension are not included in this fork +- Added USB Serial transport (/scratch/serial endpoint) with discovery, + read/write, keep-alive, and DTR reset support +- Changed the default WebSocket port from 20110/20111 to 20211 so that + AluxLabs Link can coexist with the original Scratch Link on the same + machine +- Upgraded the runtime from .NET 6 / Windows App SDK 1.3 to + .NET 8 / Windows App SDK 1.8 +- Rebranded as "AluxLabs Link" with a separate MSIX package identity to + prevent installation conflict with the original +- Various stability and code-quality improvements + +Per AGPL-3.0 Section 5, the original copyright notices and per-file +attributions ("Copyright (c) Scratch Foundation") are retained in all +source files derived from the upstream project. + + +Trademark notice + +"Scratch" is a trademark of the Scratch Foundation. AluxLabs Link is +not affiliated with, endorsed by, or sponsored by the Scratch Foundation. + +References to the "Scratch Link protocol" in source code and +documentation refer to the network protocol established by the original +scratch-link project, used here solely for client compatibility. diff --git a/NOTICE.ko b/NOTICE.ko new file mode 100644 index 00000000..577394e9 --- /dev/null +++ b/NOTICE.ko @@ -0,0 +1,49 @@ +AluxLabs Link +Copyright (c) 2026 ALUX, Inc. + +본 문서는 참고용 한국어 번역입니다. 정본(authoritative)은 NOTICE 파일을 +참조하십시오. 번역과 정본이 충돌할 경우 정본을 우선합니다. + + +출처 및 라이선스 + +본 제품은 Scratch Foundation 의 scratch-link +(https://github.com/scratchfoundation/scratch-link) 에서 파생되었으며, +원본은 GNU Affero General Public License v3.0 (AGPL-3.0-only) 으로 +배포되었습니다. + +AluxLabs Link 역시 동일한 AGPL-3.0-only 라이선스로 배포됩니다. +전체 라이선스 텍스트는 LICENSE 파일을 참조하십시오. + +본 제품의 전체 대응 소스 코드 (ALUX, Inc. 의 모든 수정 사항 포함) 는 +다음 위치에서 공개되고 있습니다: + https://github.com/aluxrobot/scratch-link + + +ALUX, Inc. 의 주요 수정 사항 + +- Windows 전용 배포 — 원본의 macOS 앱과 Safari Helper 확장은 본 포크에 + 포함되지 않음 +- USB Serial 트랜스포트 추가 (/scratch/serial 엔드포인트) — 디스커버리, + 읽기/쓰기, keep-alive, DTR reset 지원 +- 기본 WebSocket 포트를 20110/20111 에서 20211 로 변경 — 원본 Scratch + Link 와 한 PC 에서 공존 가능 +- 런타임을 .NET 6 / Windows App SDK 1.3 에서 .NET 8 / Windows App SDK + 1.8 로 업그레이드 +- "AluxLabs Link" 로 리브랜드 및 별도 MSIX 패키지 식별자 사용 — 원본과의 + 설치 충돌 방지 +- 그 외 안정성·코드 품질 개선 + +AGPL-3.0 §5 에 따라, 원본 코드에서 파생된 모든 소스 파일의 원저작권 +표시 ("Copyright (c) Scratch Foundation") 와 파일별 attribution 은 +보존됩니다. + + +상표 고지 + +"Scratch" 는 Scratch Foundation 의 상표입니다. AluxLabs Link 는 Scratch +Foundation 과 어떠한 제휴·후원·인증 관계도 없습니다. + +소스 코드와 문서에 나오는 "Scratch Link protocol" 이라는 표현은 원본 +scratch-link 프로젝트가 정립한 네트워크 프로토콜을 가리키며, 클라이언트 +호환성 확보 목적으로만 사용됩니다. diff --git a/README.md b/README.md index 276c9e32..e4962fb9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ -# Alux Scratch Link +# AluxLabs Link Scratch 3.0과 PC에 연결된 하드웨어 주변기기를 중계하는 도우미 앱. -[scratchfoundation/scratch-link](https://github.com/scratchfoundation/scratch-link)의 **Windows 전용 포크**이며, 원본의 AGPL-3.0-only 라이선스를 그대로 따릅니다. + +> 본 제품은 Scratch Foundation 의 [scratch-link](https://github.com/scratchfoundation/scratch-link) (AGPL-3.0-only) 에서 파생된 Windows 전용 포크이며, 동일한 **AGPL-3.0-only** 라이선스로 배포됩니다. 변경 내역·소스 위치·상표 고지는 [NOTICE](NOTICE) ([한국어](NOTICE.ko)), 전체 라이선스 텍스트는 [LICENSE](LICENSE) 를 참조하십시오. +> +> "Scratch" 는 Scratch Foundation 의 상표입니다. 본 제품은 Scratch Foundation 과 제휴·후원·인증 관계가 없으며, 호환성 확보를 위해 원본 프로토콜을 구현한 독립적인 파생 저작물입니다. ## 원본과의 차이 @@ -25,7 +28,7 @@ Windows App Runtime 1.8이 없는 경우 앱 실행 시 설치 안내가 표시 AluxLabs는 Alux 전용 Scratch 3.0입니다. -1. Alux Scratch Link 실행 +1. AluxLabs Link 실행 2. AluxLabs 열기 3. 블록 카테고리 아래 "확장 기능 추가" 선택 4. CodeTinker, Connect, CodingDrone 등 지원 확장 선택 From 53bfd57d0ffe5be008d1acd6f9e5bc42a58cc216 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 May 2026 13:23:51 +0900 Subject: [PATCH 33/94] =?UTF-8?q?refactor(msix):=20MSIX=20Package=20Identi?= =?UTF-8?q?ty=20=EB=A5=BC=20ALUX=20=EC=8B=9D=EB=B3=84=EC=9E=90=EB=A1=9C=20?= =?UTF-8?q?=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 원본 Scratch Foundation 의 스토어 Identity (Name="ScratchFoundation.1711508CFD202", Publisher="CN=2EC43DF1-469A-4119-9AB9-568A0A1FF65F") 를 ALUX 의 임시 식별자로 교체. Windows MSIX 는 (Name, Publisher) 쌍을 앱의 unique key 로 쓰므로, 원본 그대로면 원본 Scratch Link 와 같은 앱으로 인식되어 설치 충돌· 스토어 등록 불가 문제가 발생한다. Publisher CN 은 자체 서명 임시값. Partner Center 등록 또는 정식 코드 서명 인증서 발급 시 해당 발급값으로 다시 교체할 예정. Co-Authored-By: Claude Opus 4.7 (1M context) --- scratch-link-win-msix/Package.appxmanifest | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scratch-link-win-msix/Package.appxmanifest b/scratch-link-win-msix/Package.appxmanifest index 87fb2128..7218e4cb 100644 --- a/scratch-link-win-msix/Package.appxmanifest +++ b/scratch-link-win-msix/Package.appxmanifest @@ -7,8 +7,8 @@ IgnorableNamespaces="uap rescap"> From d46d3aa33bd0eef200436446ed07998f73d11b7b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 May 2026 13:27:11 +0900 Subject: [PATCH 34/94] =?UTF-8?q?refactor(rebrand):=20UI=20=EB=85=B8?= =?UTF-8?q?=EC=B6=9C=20=EC=A0=9C=ED=92=88=EB=AA=85=EC=9D=84=20"AluxLabs=20?= =?UTF-8?q?Link"=20=EB=A1=9C=20=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 사용자에게 직접 표시되는 문자열만 갱신 (Plan §4 Step 2): - Package.appxmanifest: DisplayName / Description 3곳 - app.manifest: assemblyIdentity name - TrayIcon.xaml: 트레이 ToolTip / 버전 라벨 - ScratchVersion.targets: 코멘트의 예시 문자열 AssemblyName / RootNamespace / 파일·폴더명 / 코드 네임스페이스는 별도 단계에서 처리 (bin/obj 재빌드 필요). Co-Authored-By: Claude Opus 4.7 (1M context) --- SharedProps/ScratchVersion.targets | 2 +- scratch-link-win-msix/Package.appxmanifest | 6 +++--- scratch-link-win/TrayIcon.xaml | 4 ++-- scratch-link-win/app.manifest | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/SharedProps/ScratchVersion.targets b/SharedProps/ScratchVersion.targets index 211fa17c..c8591f76 100644 --- a/SharedProps/ScratchVersion.targets +++ b/SharedProps/ScratchVersion.targets @@ -44,7 +44,7 @@ This file sets up version properties in our own Scratch way. diff --git a/scratch-link-win-msix/Package.appxmanifest b/scratch-link-win-msix/Package.appxmanifest index 7218e4cb..0da14be2 100644 --- a/scratch-link-win-msix/Package.appxmanifest +++ b/scratch-link-win-msix/Package.appxmanifest @@ -12,7 +12,7 @@ Version="1.0.0.0" /> - Alux Scratch Link + AluxLabs Link ALUX, Inc. Images\StoreLogo.png @@ -31,8 +31,8 @@ Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$"> diff --git a/scratch-link-win/TrayIcon.xaml b/scratch-link-win/TrayIcon.xaml index 40fdf892..f1f8bcf1 100644 --- a/scratch-link-win/TrayIcon.xaml +++ b/scratch-link-win/TrayIcon.xaml @@ -9,7 +9,7 @@ diff --git a/scratch-link-win/app.manifest b/scratch-link-win/app.manifest index dc82b519..ac7ff71d 100644 --- a/scratch-link-win/app.manifest +++ b/scratch-link-win/app.manifest @@ -1,6 +1,6 @@ - + From e046f82d25c75fce37ac1bb762f22e33ce44f196 Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:36:12 +0900 Subject: [PATCH 35/94] =?UTF-8?q?docs(cicd):=20S3=20+=20CloudFront=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=B4=ED=94=84=EB=9D=BC=EC=9D=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EA=B3=84=ED=9A=8D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 19개 task로 분해: - 기존 CI 제거 (Task 1) - AWS 셋업 스크립트 및 lib/policies 구성 (Task 2~10) - runbook (Task 11) - 로컬 셋업 실행 및 GitHub Secret 등록 (Task 12) - release.yml 점진 구축 (Task 13~16) - 태그 푸시 검증 (Task 17) - README 업데이트와 PR 생성 (Task 18~19) --- .../plans/2026-05-26-cicd-s3-cloudfront.md | 1555 +++++++++++++++++ 1 file changed, 1555 insertions(+) create mode 100644 docs/superpowers/plans/2026-05-26-cicd-s3-cloudfront.md diff --git a/docs/superpowers/plans/2026-05-26-cicd-s3-cloudfront.md b/docs/superpowers/plans/2026-05-26-cicd-s3-cloudfront.md new file mode 100644 index 00000000..8303855c --- /dev/null +++ b/docs/superpowers/plans/2026-05-26-cicd-s3-cloudfront.md @@ -0,0 +1,1555 @@ +# CI/CD → S3 → CloudFront 파이프라인 구현 계획 + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** semver git tag 푸시 한 번으로 Windows MSIX 빌드 → S3 업로드 → CloudFront 배포가 자동 수행되는 파이프라인을 만든다. + +**Architecture:** AWS 인프라(S3·CloudFront·Route 53·IAM)는 `scripts/aws/setup-cdn.sh` 하나로 일회성 프로비저닝. 빌드/배포는 `.github/workflows/release.yml` 단일 워크플로에서 `windows-latest` 러너로 처리. 채널 라우팅은 태그 형태(`v1.2.0` vs `v1.2.0-*`)로 결정한다. + +**Tech Stack:** AWS CLI v2, bash, jq (로컬), GitHub Actions, MSBuild + .NET 8 SDK (windows-latest 러너 내장), `aws-actions/configure-aws-credentials@v4`, `actions/checkout@v4`. + +**참고 문서:** [docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md](../specs/2026-05-26-cicd-s3-cloudfront-design.md) + +--- + +## File Structure + +``` +NEW: + scripts/aws/setup-cdn.sh # 메인 일회성 셋업 스크립트 + scripts/aws/lib/common.sh # 공통 유틸 함수 (logging, env vars) + scripts/aws/lib/bucket.sh # S3 버킷 생성·정책 함수 + scripts/aws/lib/cloudfront.sh # CloudFront distribution 생성 함수 + scripts/aws/lib/route53.sh # Route 53 alias 생성 함수 + scripts/aws/lib/iam.sh # IAM user·policy·access key 함수 + scripts/aws/policies/bucket-policy.json.tpl # 퍼블릭 read S3 버킷 정책 템플릿 + scripts/aws/policies/iam-policy.json.tpl # gh-actions-scratch-link 인라인 정책 템플릿 + scripts/aws/policies/cloudfront-config.json.tpl # CloudFront distribution 생성 입력 템플릿 + scripts/aws/README.md # 셋업 절차 runbook + .github/workflows/release.yml # 빌드 + 업로드 + invalidate + +DELETE: + .github/workflows/ci.yml + .github/actions/macos-build/ # 디렉토리 전체 + .github/actions/windows-build/ # 디렉토리 전체 + +MODIFY: + README.md # 다운로드 URL 안내 추가 (마지막 task) +``` + +각 파일은 한 가지 책임만 갖는다. 셋업 스크립트는 함수 단위로 `lib/`에 분리해 가독성·테스트 가능성을 확보. + +--- + +## Task 1: 기존 CI 자산 삭제 + +기존 `ci.yml`이 macOS + Windows 둘 다 빌드하고 semantic-release npm 흐름에 묶여 있어 재사용보다 삭제가 깔끔. signature-assistant.yml은 별개 기능이라 유지. + +**Files:** +- Delete: `.github/workflows/ci.yml` +- Delete: `.github/actions/macos-build/` (디렉토리) +- Delete: `.github/actions/windows-build/` (디렉토리) + +- [ ] **Step 1.1: 삭제 전 백업 확인 (git이 추적 중인지)** + +Run: +```bash +git ls-files .github/workflows/ci.yml .github/actions/ +``` +Expected: 세 경로 모두 출력됨 (삭제해도 git 히스토리에 남아 복구 가능 확인). + +- [ ] **Step 1.2: 파일·디렉토리 삭제** + +Run: +```bash +git rm .github/workflows/ci.yml +git rm -r .github/actions/macos-build +git rm -r .github/actions/windows-build +``` + +- [ ] **Step 1.3: 확인** + +Run: +```bash +git status --short .github/ +``` +Expected: `D .github/workflows/ci.yml` 및 두 액션 디렉토리 하위 파일들의 `D` 출력. `.github/workflows/signature-assistant.yml`은 그대로 있어야 함. + +- [ ] **Step 1.4: 커밋** + +```bash +git commit -m "$(cat <<'EOF' +chore(ci): macOS·Windows 통합 워크플로 및 composite actions 제거 + +신규 release.yml(태그 트리거)로 대체 예정. signature-assistant.yml은 별개 기능이라 유지. +EOF +)" +``` + +--- + +## Task 2: 셋업 스크립트 디렉토리 구조와 공통 유틸 생성 + +`setup-cdn.sh`가 호출할 함수들을 `lib/`에 모듈 단위로 둔다. 먼저 공통 유틸부터. + +**Files:** +- Create: `scripts/aws/lib/common.sh` + +- [ ] **Step 2.1: 디렉토리 생성** + +Run: +```bash +mkdir -p scripts/aws/lib scripts/aws/policies +``` + +- [ ] **Step 2.2: `lib/common.sh` 작성** + +내용: +```bash +#!/usr/bin/env bash +# 공통 유틸: 로깅, 환경 변수, 사전 점검. +# 호출 측에서 `source "$(dirname "$0")/lib/common.sh"`로 사용. + +# bash 4+ 필요 (associative array 등) +if (( BASH_VERSINFO[0] < 4 )); then + echo "ERROR: bash 4 이상 필요 (현재: $BASH_VERSION). macOS는 'brew install bash' 후 /opt/homebrew/bin/bash로 실행." >&2 + exit 1 +fi + +set -euo pipefail + +# 색상 로그 +RED=$'\033[31m'; GREEN=$'\033[32m'; YELLOW=$'\033[33m'; BLUE=$'\033[34m'; RESET=$'\033[0m' +log_info() { printf "%s[INFO]%s %s\n" "$BLUE" "$RESET" "$*" >&2; } +log_warn() { printf "%s[WARN]%s %s\n" "$YELLOW" "$RESET" "$*" >&2; } +log_error() { printf "%s[ERROR]%s %s\n" "$RED" "$RESET" "$*" >&2; } +log_ok() { printf "%s[OK]%s %s\n" "$GREEN" "$RESET" "$*" >&2; } + +# 필수 외부 명령 점검 +require_cmd() { + local missing=() + for cmd in "$@"; do + if ! command -v "$cmd" >/dev/null 2>&1; then + missing+=("$cmd") + fi + done + if (( ${#missing[@]} > 0 )); then + log_error "다음 명령이 없습니다: ${missing[*]}" + exit 1 + fi +} + +# AWS 호출자 식별 출력 (실수 방지) +print_aws_identity() { + local id_json + id_json=$(aws sts get-caller-identity) + local account user + account=$(jq -r '.Account' <<<"$id_json") + user=$(jq -r '.Arn' <<<"$id_json") + log_info "AWS Account: $account" + log_info "Caller: $user" +} + +# 환경(prod/dev) → 도메인·버킷명 매핑 +domain_for_env() { + case "$1" in + prod) echo "scratch-link.aluxcoding.com" ;; + dev) echo "dev-scratch-link.aluxcoding.com" ;; + *) log_error "알 수 없는 환경: $1"; return 1 ;; + esac +} + +# 공용 상수 +export AWS_REGION="${AWS_REGION:-ap-northeast-2}" +export ACM_CERT_ARN="${ACM_CERT_ARN:-arn:aws:acm:us-east-1:593793057142:certificate/0b58642f-b20f-451b-8257-aa366ba5fc0c}" +export ROUTE53_ZONE_ID="${ROUTE53_ZONE_ID:-Z0327990CY2GCD1RONPB}" +export IAM_USER_NAME="${IAM_USER_NAME:-gh-actions-scratch-link}" +``` + +- [ ] **Step 2.3: 실행 권한 부여** + +Run: +```bash +chmod +x scripts/aws/lib/common.sh +``` + +- [ ] **Step 2.4: shellcheck (있으면) 점검** + +Run: +```bash +command -v shellcheck >/dev/null && shellcheck scripts/aws/lib/common.sh || echo "shellcheck 미설치 — 건너뜀" +``` +Expected: shellcheck가 있으면 경고 없음, 없으면 메시지만 출력하고 종료 0. + +- [ ] **Step 2.5: 커밋** + +```bash +git add scripts/aws/lib/common.sh +git commit -m "chore(aws): 셋업 스크립트 공통 유틸 추가" +``` + +--- + +## Task 3: S3 버킷 정책 템플릿 작성 + +조직 기존 패턴과 동일한 퍼블릭 read 정책. 버킷 이름 placeholder만 치환. + +**Files:** +- Create: `scripts/aws/policies/bucket-policy.json.tpl` + +- [ ] **Step 3.1: 템플릿 작성** + +내용: +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "PublicReadGetObject", + "Effect": "Allow", + "Principal": "*", + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::__BUCKET__/*" + } + ] +} +``` + +- [ ] **Step 3.2: jq로 치환 검증** + +Run: +```bash +sed 's/__BUCKET__/scratch-link.aluxcoding.com/g' scripts/aws/policies/bucket-policy.json.tpl | jq . +``` +Expected: JSON 파싱 OK, Resource 값이 `arn:aws:s3:::scratch-link.aluxcoding.com/*`. + +- [ ] **Step 3.3: 커밋** + +```bash +git add scripts/aws/policies/bucket-policy.json.tpl +git commit -m "chore(aws): S3 버킷 public-read 정책 템플릿" +``` + +--- + +## Task 4: S3 버킷 생성 함수 작성 + +멱등성: 이미 있으면 skip. public access block 해제, website hosting 활성화, public-read 정책 적용까지 한 번에. + +**Files:** +- Create: `scripts/aws/lib/bucket.sh` + +- [ ] **Step 4.1: `lib/bucket.sh` 작성** + +내용: +```bash +#!/usr/bin/env bash +# S3 버킷 생성·구성 함수. setup-cdn.sh에서 source. + +# 인자: $1 = 버킷명 +ensure_bucket() { + local bucket="$1" + local region="$AWS_REGION" + + if aws s3api head-bucket --bucket "$bucket" 2>/dev/null; then + log_info "버킷 이미 존재: $bucket — 생성 skip" + else + log_info "버킷 생성: $bucket (region=$region)" + aws s3api create-bucket \ + --bucket "$bucket" \ + --region "$region" \ + --create-bucket-configuration "LocationConstraint=$region" \ + >/dev/null + log_ok "버킷 생성됨: $bucket" + fi + + log_info "Public Access Block 해제: $bucket" + aws s3api put-public-access-block \ + --bucket "$bucket" \ + --public-access-block-configuration \ + "BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false" + + log_info "Public-read 정책 적용: $bucket" + local policy_json + policy_json=$(sed "s/__BUCKET__/$bucket/g" "$(dirname "${BASH_SOURCE[0]}")/../policies/bucket-policy.json.tpl") + aws s3api put-bucket-policy --bucket "$bucket" --policy "$policy_json" + + log_info "Website hosting 활성화: $bucket" + aws s3 website "s3://$bucket/" --index-document index.html --error-document error.html + # MSIX 다운로드 용도라 index/error 페이지는 실제로 안 쓰이지만, website endpoint 활성화에 필수. + + log_ok "버킷 구성 완료: $bucket" +} +``` + +- [ ] **Step 4.2: shellcheck 점검** + +Run: +```bash +command -v shellcheck >/dev/null && shellcheck -x scripts/aws/lib/bucket.sh || true +``` +Expected: 경고 없음 (또는 SC1091 외 없음 — common.sh source 경로 관련). + +- [ ] **Step 4.3: 커밋** + +```bash +git add scripts/aws/lib/bucket.sh +git commit -m "chore(aws): S3 버킷 생성·구성 함수" +``` + +--- + +## Task 5: CloudFront distribution config 템플릿 작성 + +S3 website endpoint를 origin으로 하는 distribution. ACM 인증서·SSL 정책 포함. + +**Files:** +- Create: `scripts/aws/policies/cloudfront-config.json.tpl` + +- [ ] **Step 5.1: 템플릿 작성** + +내용: +```json +{ + "CallerReference": "__CALLER_REF__", + "Comment": "__COMMENT__", + "Aliases": { + "Quantity": 1, + "Items": ["__DOMAIN__"] + }, + "DefaultRootObject": "", + "Origins": { + "Quantity": 1, + "Items": [ + { + "Id": "s3-website-origin", + "DomainName": "__ORIGIN_DOMAIN__", + "CustomOriginConfig": { + "HTTPPort": 80, + "HTTPSPort": 443, + "OriginProtocolPolicy": "http-only", + "OriginSslProtocols": { "Quantity": 1, "Items": ["TLSv1.2"] }, + "OriginReadTimeout": 30, + "OriginKeepaliveTimeout": 5 + }, + "ConnectionAttempts": 3, + "ConnectionTimeout": 10 + } + ] + }, + "DefaultCacheBehavior": { + "TargetOriginId": "s3-website-origin", + "ViewerProtocolPolicy": "redirect-to-https", + "AllowedMethods": { + "Quantity": 2, + "Items": ["GET", "HEAD"], + "CachedMethods": { "Quantity": 2, "Items": ["GET", "HEAD"] } + }, + "Compress": true, + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6" + }, + "PriceClass": "PriceClass_200", + "Enabled": true, + "ViewerCertificate": { + "ACMCertificateArn": "__CERT_ARN__", + "SSLSupportMethod": "sni-only", + "MinimumProtocolVersion": "TLSv1.2_2021" + }, + "HttpVersion": "http2and3", + "IsIPV6Enabled": true +} +``` + +> CachePolicyId `658327ea-f89d-4fab-a63d-7e88639e58f6`은 AWS 관리형 "CachingOptimized" 정책 ID (전 리전 공통, 고정값). +> PriceClass_200은 한국·일본·미국·유럽 포함, 남미·아프리카 제외 (비용 절감). + +- [ ] **Step 5.2: jq 파싱 검증** + +Run: +```bash +sed -e 's/__CALLER_REF__/test-1/g' \ + -e 's/__COMMENT__/test/g' \ + -e 's/__DOMAIN__/test.example.com/g' \ + -e 's/__ORIGIN_DOMAIN__/test.example.com.s3-website.ap-northeast-2.amazonaws.com/g' \ + -e 's|__CERT_ARN__|arn:aws:acm:us-east-1:1:certificate/x|g' \ + scripts/aws/policies/cloudfront-config.json.tpl | jq . +``` +Expected: JSON 파싱 OK. + +- [ ] **Step 5.3: 커밋** + +```bash +git add scripts/aws/policies/cloudfront-config.json.tpl +git commit -m "chore(aws): CloudFront distribution 생성 입력 템플릿" +``` + +--- + +## Task 6: CloudFront distribution 생성 함수 작성 + +멱등성: 같은 alias로 이미 존재하면 ID만 반환. distribution ID와 도메인을 stdout으로 출력해 호출 측이 캡처. + +**Files:** +- Create: `scripts/aws/lib/cloudfront.sh` + +- [ ] **Step 6.1: `lib/cloudfront.sh` 작성** + +내용: +```bash +#!/usr/bin/env bash +# CloudFront distribution 생성. setup-cdn.sh에서 source. + +# 인자: $1 = 도메인 (== alias, == 버킷명) +# $2 = comment (UI에서 식별용) +# 출력: stdout 한 줄. "DIST_ID\tCF_DOMAIN" (tab 구분) +ensure_distribution() { + local domain="$1" + local comment="$2" + local origin_domain="${domain}.s3-website.${AWS_REGION}.amazonaws.com" + + local existing + existing=$(aws cloudfront list-distributions \ + --query "DistributionList.Items[?contains(Aliases.Items, \`$domain\`)].{Id:Id,Domain:DomainName}" \ + --output json) + + local count + count=$(jq 'length' <<<"$existing") + + if [[ "$count" -ge 1 ]]; then + local dist_id dist_domain + dist_id=$(jq -r '.[0].Id' <<<"$existing") + dist_domain=$(jq -r '.[0].Domain' <<<"$existing") + log_info "CloudFront 이미 존재 ($domain): $dist_id" >&2 + printf "%s\t%s\n" "$dist_id" "$dist_domain" + return 0 + fi + + log_info "CloudFront distribution 생성: $domain" + local tpl="$(dirname "${BASH_SOURCE[0]}")/../policies/cloudfront-config.json.tpl" + local caller_ref + caller_ref="scratch-link-$(date +%s)-$$" + + local config_json + config_json=$(sed \ + -e "s/__CALLER_REF__/$caller_ref/g" \ + -e "s|__COMMENT__|$comment|g" \ + -e "s/__DOMAIN__/$domain/g" \ + -e "s/__ORIGIN_DOMAIN__/$origin_domain/g" \ + -e "s|__CERT_ARN__|$ACM_CERT_ARN|g" \ + "$tpl") + + local result + result=$(aws cloudfront create-distribution \ + --distribution-config "$config_json" \ + --output json) + + local dist_id dist_domain + dist_id=$(jq -r '.Distribution.Id' <<<"$result") + dist_domain=$(jq -r '.Distribution.DomainName' <<<"$result") + + log_ok "CloudFront 생성됨 ($domain): $dist_id / $dist_domain" >&2 + log_warn "Distribution 배포(In-Progress → Deployed)에는 5~15분 소요." >&2 + + printf "%s\t%s\n" "$dist_id" "$dist_domain" +} +``` + +- [ ] **Step 6.2: shellcheck** + +Run: +```bash +command -v shellcheck >/dev/null && shellcheck -x scripts/aws/lib/cloudfront.sh || true +``` + +- [ ] **Step 6.3: 커밋** + +```bash +git add scripts/aws/lib/cloudfront.sh +git commit -m "chore(aws): CloudFront distribution 생성 함수" +``` + +--- + +## Task 7: Route 53 alias 생성 함수 작성 + +기존 zone `aluxcoding.com.`에 A/AAAA Alias 추가. 멱등성: 같은 이름이 같은 타겟이면 skip. + +**Files:** +- Create: `scripts/aws/lib/route53.sh` + +- [ ] **Step 7.1: `lib/route53.sh` 작성** + +내용: +```bash +#!/usr/bin/env bash +# Route 53 A/AAAA alias 생성. setup-cdn.sh에서 source. + +# 인자: $1 = 도메인 (예: scratch-link.aluxcoding.com) +# $2 = CloudFront 도메인 (예: d123abc.cloudfront.net) +ensure_route53_alias() { + local domain="$1" + local cf_domain="$2" + # CloudFront는 hosted zone ID가 전 리전 동일: Z2FDTNDATAQYW2 + local cf_zone="Z2FDTNDATAQYW2" + + # 기존 레코드 확인 + local existing + existing=$(aws route53 list-resource-record-sets \ + --hosted-zone-id "$ROUTE53_ZONE_ID" \ + --query "ResourceRecordSets[?Name=='${domain}.' && (Type=='A' || Type=='AAAA')]" \ + --output json) + + local existing_count + existing_count=$(jq 'length' <<<"$existing") + + if [[ "$existing_count" -ge 2 ]]; then + # A + AAAA 둘 다 있고, target이 일치하면 skip + local existing_target + existing_target=$(jq -r '.[0].AliasTarget.DNSName // ""' <<<"$existing") + if [[ "$existing_target" == "${cf_domain}." ]]; then + log_info "Route 53 alias 이미 존재 ($domain → $cf_domain) — skip" + return 0 + fi + log_warn "Route 53 alias가 다른 타겟을 가리키고 있음 ($existing_target). 덮어쓰기 진행." + fi + + log_info "Route 53 A/AAAA alias 추가: $domain → $cf_domain" + + local change_batch + change_batch=$(cat </dev/null + + log_ok "Route 53 alias 등록됨 ($domain)" +} +``` + +- [ ] **Step 7.2: shellcheck** + +Run: +```bash +command -v shellcheck >/dev/null && shellcheck -x scripts/aws/lib/route53.sh || true +``` + +- [ ] **Step 7.3: 커밋** + +```bash +git add scripts/aws/lib/route53.sh +git commit -m "chore(aws): Route 53 alias 생성 함수" +``` + +--- + +## Task 8: IAM 인라인 정책 템플릿 작성 + +두 버킷 + 두 distribution에 한해 최소 권한. + +**Files:** +- Create: `scripts/aws/policies/iam-policy.json.tpl` + +- [ ] **Step 8.1: 템플릿 작성** + +내용: +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "S3Upload", + "Effect": "Allow", + "Action": ["s3:PutObject", "s3:DeleteObject", "s3:ListBucket"], + "Resource": [ + "arn:aws:s3:::scratch-link.aluxcoding.com", + "arn:aws:s3:::scratch-link.aluxcoding.com/*", + "arn:aws:s3:::dev-scratch-link.aluxcoding.com", + "arn:aws:s3:::dev-scratch-link.aluxcoding.com/*" + ] + }, + { + "Sid": "CloudFrontInvalidate", + "Effect": "Allow", + "Action": ["cloudfront:CreateInvalidation", "cloudfront:GetInvalidation"], + "Resource": [ + "arn:aws:cloudfront::__ACCOUNT__:distribution/__PROD_DIST_ID__", + "arn:aws:cloudfront::__ACCOUNT__:distribution/__DEV_DIST_ID__" + ] + } + ] +} +``` + +- [ ] **Step 8.2: 커밋** + +```bash +git add scripts/aws/policies/iam-policy.json.tpl +git commit -m "chore(aws): gh-actions-scratch-link IAM 정책 템플릿" +``` + +--- + +## Task 9: IAM user/policy/access key 함수 작성 + +멱등성: user 있으면 skip, policy는 항상 put (idempotent), access key는 발급 후 1회만 출력. + +**Files:** +- Create: `scripts/aws/lib/iam.sh` + +- [ ] **Step 9.1: `lib/iam.sh` 작성** + +내용: +```bash +#!/usr/bin/env bash +# IAM user·policy·access key 함수. setup-cdn.sh에서 source. + +# IAM user 생성 (멱등). 출력 없음. +ensure_iam_user() { + if aws iam get-user --user-name "$IAM_USER_NAME" >/dev/null 2>&1; then + log_info "IAM user 이미 존재: $IAM_USER_NAME — skip" + return 0 + fi + log_info "IAM user 생성: $IAM_USER_NAME" + aws iam create-user --user-name "$IAM_USER_NAME" >/dev/null + log_ok "IAM user 생성됨: $IAM_USER_NAME" +} + +# 인라인 정책 attach (idempotent — put-user-policy는 덮어쓰기). +# 인자: $1 = AWS Account ID, $2 = PROD_DIST_ID, $3 = DEV_DIST_ID +attach_iam_policy() { + local account="$1" + local prod_id="$2" + local dev_id="$3" + local tpl="$(dirname "${BASH_SOURCE[0]}")/../policies/iam-policy.json.tpl" + + log_info "IAM 인라인 정책 attach (gh-actions-scratch-link 정책)" + local policy_json + policy_json=$(sed \ + -e "s/__ACCOUNT__/$account/g" \ + -e "s/__PROD_DIST_ID__/$prod_id/g" \ + -e "s/__DEV_DIST_ID__/$dev_id/g" \ + "$tpl") + + aws iam put-user-policy \ + --user-name "$IAM_USER_NAME" \ + --policy-name "scratch-link-cdn-deploy" \ + --policy-document "$policy_json" + log_ok "IAM 정책 attach 완료" +} + +# access key 발급 또는 기존 키 안내. +# 기존 키가 있으면 secret을 다시 볼 수 없으므로, 사용자에게 옵션을 묻는다. +# 출력: stdout 한 줄. "ACCESS_KEY_ID\tSECRET_ACCESS_KEY" (신규 발급 시) 또는 빈 줄 (skip). +ensure_access_key() { + local existing + existing=$(aws iam list-access-keys --user-name "$IAM_USER_NAME" \ + --query 'AccessKeyMetadata[].AccessKeyId' --output json) + local count + count=$(jq 'length' <<<"$existing") + + if [[ "$count" -ge 1 ]]; then + log_warn "IAM user에 access key가 이미 ${count}개 있음: $(jq -r 'join(", ")' <<<"$existing")" + log_warn "기존 키의 secret은 재조회 불가. 분실 시 'aws iam delete-access-key' 후 재실행." + log_warn "신규 키 발급 원하면 환경변수 FORCE_NEW_KEY=1로 재실행 (단, IAM 한도 2개)." + if [[ "${FORCE_NEW_KEY:-}" != "1" ]]; then + printf "\n" + return 0 + fi + fi + + log_info "access key 발급: $IAM_USER_NAME" + local result + result=$(aws iam create-access-key --user-name "$IAM_USER_NAME" --output json) + local key_id secret + key_id=$(jq -r '.AccessKey.AccessKeyId' <<<"$result") + secret=$(jq -r '.AccessKey.SecretAccessKey' <<<"$result") + log_ok "신규 access key 발급됨: $key_id" + printf "%s\t%s\n" "$key_id" "$secret" +} +``` + +- [ ] **Step 9.2: shellcheck** + +Run: +```bash +command -v shellcheck >/dev/null && shellcheck -x scripts/aws/lib/iam.sh || true +``` + +- [ ] **Step 9.3: 커밋** + +```bash +git add scripts/aws/lib/iam.sh +git commit -m "chore(aws): IAM user·정책·access key 함수" +``` + +--- + +## Task 10: 메인 셋업 스크립트 작성 + +`lib/*.sh`를 조립해 prod + dev 양쪽을 한 번에 프로비저닝하고 secret 등록용 값을 마지막에 출력. + +**Files:** +- Create: `scripts/aws/setup-cdn.sh` + +- [ ] **Step 10.1: `setup-cdn.sh` 작성** + +내용: +```bash +#!/usr/bin/env bash +# Scratch Link CDN AWS 인프라 일회성 셋업. +# 멱등: 다시 실행해도 안전. 자세한 절차는 scripts/aws/README.md 참고. + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# shellcheck source=lib/common.sh +source "$SCRIPT_DIR/lib/common.sh" +# shellcheck source=lib/bucket.sh +source "$SCRIPT_DIR/lib/bucket.sh" +# shellcheck source=lib/cloudfront.sh +source "$SCRIPT_DIR/lib/cloudfront.sh" +# shellcheck source=lib/route53.sh +source "$SCRIPT_DIR/lib/route53.sh" +# shellcheck source=lib/iam.sh +source "$SCRIPT_DIR/lib/iam.sh" + +require_cmd aws jq sed +print_aws_identity + +read -r -p "위 계정·사용자로 진행할까요? (y/N) " confirm +if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then + log_info "취소" + exit 0 +fi + +# 1. S3 버킷 +for env in prod dev; do + domain=$(domain_for_env "$env") + ensure_bucket "$domain" +done + +# 2. CloudFront distribution +declare -A DIST_ID DIST_DOMAIN +for env in prod dev; do + domain=$(domain_for_env "$env") + comment="scratch-link CDN ($env)" + result=$(ensure_distribution "$domain" "$comment") + DIST_ID[$env]=$(cut -f1 <<<"$result") + DIST_DOMAIN[$env]=$(cut -f2 <<<"$result") +done + +# 3. Route 53 alias +for env in prod dev; do + domain=$(domain_for_env "$env") + ensure_route53_alias "$domain" "${DIST_DOMAIN[$env]}" +done + +# 4. IAM user +ensure_iam_user +ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) +attach_iam_policy "$ACCOUNT_ID" "${DIST_ID[prod]}" "${DIST_ID[dev]}" + +# 5. access key +key_line=$(ensure_access_key) + +# 6. 요약 출력 (사용자가 GitHub Secret으로 옮길 정보) +cat >&2 <&2 <&2 <&2 </dev/null && shellcheck -x scripts/aws/setup-cdn.sh || true +``` + +- [ ] **Step 10.4: dry-run (구문 확인 정도)** + +Run: +```bash +bash -n scripts/aws/setup-cdn.sh && echo "syntax OK" +``` +Expected: `syntax OK`. + +- [ ] **Step 10.5: 커밋** + +```bash +git add scripts/aws/setup-cdn.sh +git commit -m "feat(aws): scratch-link CDN 일회성 셋업 스크립트" +``` + +--- + +## Task 11: 셋업 runbook 작성 + +스크립트 실행 절차·전제조건·시크릿 등록·트러블슈팅을 한 문서에. + +**Files:** +- Create: `scripts/aws/README.md` + +- [ ] **Step 11.1: README 작성** + +내용: +```markdown +# Scratch Link CDN AWS Setup + +`scratch-link.aluxcoding.com` (prod) / `dev-scratch-link.aluxcoding.com` (dev) 두 환경의 S3·CloudFront·Route 53·IAM 리소스를 한 번에 프로비저닝하는 스크립트. + +설계 문서: [`docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md`](../../docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md) + +## 전제 + +- aws-cli v2, jq, bash 4+ (macOS는 `brew install bash`) +- AWS 관리자 권한 (IAM user/policy 생성 가능) +- Account `593793057142`, region `ap-northeast-2` +- ACM `*.aluxcoding.com` 인증서가 us-east-1에 존재 (이미 발급되어 있음) +- Route 53 `aluxcoding.com.` zone (이미 있음) + +## 실행 + +```bash +cd +./scripts/aws/setup-cdn.sh +``` + +스크립트가 AWS 호출자(account, user)를 보여주고 진행 여부를 물어봅니다. 잘못된 계정이면 `n`을 입력해 취소. + +## 산출 + +마지막에 출력되는 5개 값을 GitHub **Organization** Secrets에 등록: + +| Secret 이름 | 출처 | +|---|---| +| `AWS_REGION` | 고정 `ap-northeast-2` | +| `AWS_ACCESS_KEY_ID` | 스크립트 출력 | +| `AWS_SECRET_ACCESS_KEY` | 스크립트 출력 (1회만 보임) | +| `CF_DIST_ID_PROD` | 스크립트 출력 | +| `CF_DIST_ID_DEV` | 스크립트 출력 | + +등록 경로: GitHub Org → Settings → Secrets and variables → Actions → New organization secret. 본 리포지토리(`aluxrobot/scratch-link`)를 접근 가능 리포에 추가. + +> 기존 Org Secret에 `AWS_ACCESS_KEY_ID` 이름이 이미 다른 키로 등록돼 있으면, 본 워크플로용 이름을 `SCRATCH_LINK_AWS_ACCESS_KEY_ID` 등으로 바꿔 등록하고 `release.yml`의 secret 참조도 같이 바꾸세요. + +## 멱등성 + +- 모든 리소스는 존재 확인 후 skip +- IAM 정책은 항상 덮어쓰기 (안전) +- IAM access key는 이미 있으면 skip (secret 재조회 불가). 강제 신규 발급: `FORCE_NEW_KEY=1 ./scripts/aws/setup-cdn.sh` + +## CloudFront 전파 대기 + +생성 직후 `In-Progress` 상태. Deployed 될 때까지 5~15분. + +```bash +aws cloudfront get-distribution --id $CF_DIST_ID_PROD --query 'Distribution.Status' +``` + +`Deployed`가 뜨면 https://scratch-link.aluxcoding.com/ 접근 가능 (단, DNS 전파도 같이 필요. 보통 즉시 ~ 수 분). + +## 롤백·재구성 + +생성된 리소스를 일괄 제거하는 스크립트는 만들지 않음. 필요 시: + +```bash +# CloudFront disable + delete +aws cloudfront update-distribution --id --if-match --distribution-config +aws cloudfront delete-distribution --id --if-match + +# Route 53 레코드 삭제 +aws route53 change-resource-record-sets --hosted-zone-id Z0327990CY2GCD1RONPB --change-batch + +# S3 버킷 비우고 삭제 +aws s3 rm s3://scratch-link.aluxcoding.com --recursive +aws s3api delete-bucket --bucket scratch-link.aluxcoding.com + +# IAM user +aws iam delete-user-policy --user-name gh-actions-scratch-link --policy-name scratch-link-cdn-deploy +aws iam delete-access-key --user-name gh-actions-scratch-link --access-key-id +aws iam delete-user --user-name gh-actions-scratch-link +``` + +## 트러블슈팅 + +| 증상 | 원인 / 조치 | +|---|---| +| `BucketAlreadyOwnedByYou` 외의 `BucketAlreadyExists` | 글로벌하게 같은 이름의 버킷이 다른 계정에서 사용 중. 도메인 이름을 바꿔야 함. | +| CloudFront 생성 시 `CNAMEAlreadyExists` | 다른 distribution이 같은 alias를 들고 있음. 기존 distribution을 disable/delete 또는 alias 회수 필요. | +| `InvalidViewerCertificate` | ACM 인증서가 us-east-1이 아니거나 ISSUED 상태가 아님. `ACM_CERT_ARN` 재확인. | +| `MalformedPolicyDocument` | IAM 정책 템플릿의 placeholder 미치환. `setup-cdn.sh`가 sed 치환을 정상 수행했는지 stderr 로그 확인. | +``` + +- [ ] **Step 11.2: 커밋** + +```bash +git add scripts/aws/README.md +git commit -m "docs(aws): CDN 셋업 runbook" +``` + +--- + +## Task 12: 셋업 스크립트 로컬 실행 (수동, 일회성) + +여기까지가 인프라. 이제 실제로 AWS에 리소스를 만든다. 비용 발생 — CloudFront, Route53 호스팅 비용은 호출당. 진행 전 확인할 것. + +- [ ] **Step 12.1: AWS 호출자 검증** + +Run: +```bash +aws sts get-caller-identity +``` +Expected: Account `593793057142`, user `jysong` (또는 동등 관리자 권한 user). + +- [ ] **Step 12.2: 스크립트 실행** + +Run: +```bash +./scripts/aws/setup-cdn.sh +``` +Expected: 마지막 요약 박스에 5개 값 출력. 중간 단계에서 `[OK]` 로그 다수. + +- [ ] **Step 12.3: 결과 검증 — S3** + +Run: +```bash +aws s3api head-bucket --bucket scratch-link.aluxcoding.com && echo OK +aws s3api head-bucket --bucket dev-scratch-link.aluxcoding.com && echo OK +aws s3api get-bucket-website --bucket scratch-link.aluxcoding.com +``` +Expected: 두 버킷 OK 출력, website 설정에 `IndexDocument` 존재. + +- [ ] **Step 12.4: 결과 검증 — CloudFront** + +Run: +```bash +aws cloudfront list-distributions \ + --query 'DistributionList.Items[?contains(Aliases.Items, `scratch-link.aluxcoding.com`)].{Id:Id,Status:Status,Domain:DomainName}' \ + --output table +``` +Expected: 1개 행, Status는 `Deployed` 또는 `InProgress`. + +- [ ] **Step 12.5: 결과 검증 — Route 53** + +Run: +```bash +aws route53 list-resource-record-sets --hosted-zone-id Z0327990CY2GCD1RONPB \ + --query "ResourceRecordSets[?starts_with(Name, 'scratch-link.aluxcoding.com') || starts_with(Name, 'dev-scratch-link.aluxcoding.com')]" \ + --output json | jq -r '.[] | "\(.Name) \(.Type) -> \(.AliasTarget.DNSName // "n/a")"' +``` +Expected: 4줄 (A/AAAA × 2 도메인). + +- [ ] **Step 12.6: 결과 검증 — IAM** + +Run: +```bash +aws iam get-user --user-name gh-actions-scratch-link --query 'User.Arn' +aws iam get-user-policy --user-name gh-actions-scratch-link --policy-name scratch-link-cdn-deploy \ + --query 'PolicyDocument' | jq . +``` +Expected: ARN 출력 + 정책 JSON에 distribution ID가 채워져 있음 (placeholder 없음). + +- [ ] **Step 12.7: GitHub Org Secret 등록 (수동, 브라우저)** + +GitHub Org Settings → Secrets and variables → Actions → New organization secret 에서 다음 5개 등록: +- `AWS_REGION` +- `AWS_ACCESS_KEY_ID` +- `AWS_SECRET_ACCESS_KEY` +- `CF_DIST_ID_PROD` +- `CF_DIST_ID_DEV` + +각 secret에 `aluxrobot/scratch-link` 리포 접근 허용. + +> 이 단계는 코드 변경 없음. 완료 후 다음 task로. + +--- + +## Task 13: release 워크플로 스켈레톤 작성 (트리거 + 채널 결정) + +빌드·업로드 step은 다음 task에서 채우고, 먼저 트리거와 채널 결정 로직을 검증 가능한 형태로 만든다. + +**Files:** +- Create: `.github/workflows/release.yml` + +- [ ] **Step 13.1: 워크플로 스켈레톤 작성** + +내용: +```yaml +name: Release + +on: + push: + tags: + - 'v*.*.*' + - 'v*.*.*-*' + workflow_dispatch: + inputs: + channel: + description: 'Override channel (auto/stable/dev). auto=태그 형식으로 결정' + type: choice + options: [auto, stable, dev] + default: auto + ref: + description: '수동 실행 시 사용할 ref (태그/브랜치). 비우면 워크플로 ref 사용' + type: string + default: '' + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false + +permissions: + contents: read + +jobs: + release: + runs-on: windows-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event.inputs.ref || github.ref }} + + - name: Resolve channel and version + id: meta + run: | + set -euo pipefail + # 채널 결정 + input="${{ github.event.inputs.channel }}" + tag_name="${GITHUB_REF_NAME:-}" + if [[ "$input" == "stable" || "$input" == "dev" ]]; then + channel="$input" + elif [[ "$tag_name" =~ ^v[0-9]+\.[0-9]+\.[0-9]+- ]]; then + channel="dev" + elif [[ "$tag_name" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + channel="stable" + else + channel="dev" # workflow_dispatch + auto + non-tag ref → 안전한 쪽 + fi + # 버전 산출 (태그면 v 제거, 아니면 git describe) + if [[ "$tag_name" =~ ^v ]]; then + version="${tag_name#v}" + else + version="$(git describe --tags --always --dirty)" + fi + # 채널별 버킷·distribution + if [[ "$channel" == "stable" ]]; then + bucket="scratch-link.aluxcoding.com" + dist_id="${{ secrets.CF_DIST_ID_PROD }}" + else + bucket="dev-scratch-link.aluxcoding.com" + dist_id="${{ secrets.CF_DIST_ID_DEV }}" + fi + { + echo "channel=$channel" + echo "version=$version" + echo "bucket=$bucket" + echo "dist_id=$dist_id" + } | tee -a "$GITHUB_OUTPUT" + + - name: Show resolved metadata + run: | + echo "channel = ${{ steps.meta.outputs.channel }}" + echo "version = ${{ steps.meta.outputs.version }}" + echo "bucket = ${{ steps.meta.outputs.bucket }}" + echo "dist_id = (마스킹됨)" +``` + +> 빌드/업로드 step은 다음 task에서 추가. 지금은 채널 결정만 검증. + +- [ ] **Step 13.2: 워크플로 YAML 구문 검증** + +Run: +```bash +python3 -c "import yaml,sys; yaml.safe_load(open('.github/workflows/release.yml')); print('OK')" +``` +Expected: `OK`. (yaml 모듈 없으면 `pip3 install pyyaml`) + +- [ ] **Step 13.3: 커밋** + +```bash +git add .github/workflows/release.yml +git commit -m "feat(ci): release.yml 트리거·채널 결정 스켈레톤" +``` + +- [ ] **Step 13.4: 브랜치 푸시 + workflow_dispatch로 검증 (인프라 변경 없는 dry-run)** + +Run: +```bash +git push -u origin "$(git branch --show-current)" +``` + +GitHub UI → Actions → Release → Run workflow → channel=`dev`, ref=현재 브랜치명 → 실행. + +Expected: 워크플로가 성공 종료. `Show resolved metadata` step 로그에 `channel = dev`, `version = ...`, `bucket = dev-scratch-link.aluxcoding.com` 출력. + +> 빌드 step이 아직 없어서 이 단계는 채널 결정만 검증. + +--- + +## Task 14: 빌드 step 추가 (.NET + msbuild + MSIX) + +기존 `windows-build` 액션의 msbuild 호출을 참고해 step 단위로 풀어쓴다. + +**Files:** +- Modify: `.github/workflows/release.yml` + +- [ ] **Step 14.1: meta step 뒤에 빌드 step 추가** + +`Show resolved metadata` step 뒤에 다음 step들을 추가: + +```yaml + - name: Setup .NET 8 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v2 + + - name: Verify build toolchain + shell: pwsh + run: | + dotnet --version + msbuild -version + aws --version + + - name: Restore NuGet cache + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json', '**/*.csproj', '**/*.props') }} + restore-keys: ${{ runner.os }}-nuget- + + - name: Build MSIX bundle + shell: pwsh + env: + SOLUTION_DIR: ${{ github.workspace }} + run: | + msbuild scratch-link-win-msix/scratch-link-win-msix.wapproj ` + -maxCpuCount ` + -restore ` + -t:Build ` + -p:SolutionDir="$env:SOLUTION_DIR\" ` + -p:Configuration=Release_Win ` + -p:AppxBundlePlatforms="x86|x64|ARM64" ` + -p:AppxBundle=Always ` + -p:UapAppxPackageBuildMode=StoreAndSideload +``` + +- [ ] **Step 14.2: YAML 구문 검증** + +Run: +```bash +python3 -c "import yaml; yaml.safe_load(open('.github/workflows/release.yml')); print('OK')" +``` + +- [ ] **Step 14.3: 커밋** + +```bash +git add .github/workflows/release.yml +git commit -m "feat(ci): release.yml MSIX 빌드 step 추가" +``` + +- [ ] **Step 14.4: workflow_dispatch로 빌드 검증** + +GitHub UI → Run workflow (channel=dev, ref=현재 브랜치). + +Expected: `Build MSIX bundle` step이 성공. 로그 끝쪽에 `scratch-link-win-msix\AppPackages\...msixbundle` 생성 메시지. + +> 실패 시 보통 다음 중 하나: +> - WindowsAppSDK 1.8 NuGet 복원 실패 → restore step 로그 확인 +> - StyleCop 경고가 error로 승격 → 코드 문제이므로 워크플로 외 해결 +> - `Package.appxmanifest` 버전 주입 오류 → ScratchVersion.targets 동작 확인 + +--- + +## Task 15: 산출물 정리 + latest.json 생성 step 추가 + +빌드가 만든 패키지를 `Artifacts/`로 옮기고 `SHA256SUMS.txt` + `latest.json`을 생성. + +**Files:** +- Modify: `.github/workflows/release.yml` + +- [ ] **Step 15.1: 빌드 step 뒤에 정리 step 추가** + +`Build MSIX bundle` 뒤에: + +```yaml + - name: Collect artifacts + shell: bash + run: | + set -euo pipefail + mkdir -p Artifacts + + version="${{ steps.meta.outputs.version }}" + channel="${{ steps.meta.outputs.channel }}" + bundle_src=$(find scratch-link-win-msix/AppPackages -type f -name '*.msixbundle' | head -n1) + upload_src=$(find scratch-link-win-msix/AppPackages -type f -name '*.msixupload' | head -n1) + + if [[ -z "$bundle_src" || -z "$upload_src" ]]; then + echo "::error::빌드 산출물(.msixbundle / .msixupload)을 찾지 못함" + ls -R scratch-link-win-msix/AppPackages || true + exit 1 + fi + + bundle_dst="Artifacts/Scratch-Link-${version}.msixbundle" + upload_dst="Artifacts/Scratch-Link-${version}.msixupload" + cp "$bundle_src" "$bundle_dst" + cp "$upload_src" "$upload_dst" + + # 체크섬 + (cd Artifacts && sha256sum "$(basename "$bundle_dst")" "$(basename "$upload_dst")") > Artifacts/SHA256SUMS.txt + + # latest.json + sha=$(sha256sum "$bundle_dst" | awk '{print $1}') + size=$(stat -c %s "$bundle_dst" 2>/dev/null || stat -f %z "$bundle_dst") + published=$(date -u +%Y-%m-%dT%H:%M:%SZ) + archive_url="https://${{ steps.meta.outputs.bucket }}/archive/v${version}/$(basename "$bundle_dst")" + + jq -n \ + --arg version "$version" \ + --arg publishedAt "$published" \ + --arg channel "$channel" \ + --arg url "$archive_url" \ + --arg sha256 "$sha" \ + --argjson size "$size" \ + '{version:$version, publishedAt:$publishedAt, channel:$channel, url:$url, sha256:$sha256, size:$size, minWindowsBuild:17763, windowsAppRuntime:"1.8"}' \ + > Artifacts/latest.json + + ls -la Artifacts/ + cat Artifacts/latest.json +``` + +- [ ] **Step 15.2: YAML 구문 검증** + +Run: +```bash +python3 -c "import yaml; yaml.safe_load(open('.github/workflows/release.yml')); print('OK')" +``` + +- [ ] **Step 15.3: 커밋** + +```bash +git add .github/workflows/release.yml +git commit -m "feat(ci): MSIX 산출물 정리 및 latest.json 생성" +``` + +- [ ] **Step 15.4: workflow_dispatch 검증** + +Run workflow. Expected: `Collect artifacts` step 로그 끝에 `latest.json` 내용 출력. version, channel, url, sha256, size가 채워져 있음. + +--- + +## Task 16: S3 업로드 + CloudFront invalidation step 추가 + +archive 경로(immutable) + `latest.*`(짧은 캐시) 두 흐름. + +**Files:** +- Modify: `.github/workflows/release.yml` + +- [ ] **Step 16.1: Collect artifacts 뒤에 업로드 step 추가** + +```yaml + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Upload archive (immutable) + shell: bash + run: | + set -euo pipefail + version="${{ steps.meta.outputs.version }}" + bucket="${{ steps.meta.outputs.bucket }}" + aws s3 cp Artifacts/ "s3://${bucket}/archive/v${version}/" \ + --recursive \ + --exclude "latest.json" \ + --cache-control "public, max-age=31536000, immutable" \ + --metadata-directive REPLACE + + - name: Upload latest pointers (short cache) + shell: bash + run: | + set -euo pipefail + version="${{ steps.meta.outputs.version }}" + bucket="${{ steps.meta.outputs.bucket }}" + aws s3 cp "Artifacts/Scratch-Link-${version}.msixbundle" \ + "s3://${bucket}/latest.msixbundle" \ + --cache-control "public, max-age=300" \ + --content-type "application/vnd.ms-appx" + aws s3 cp Artifacts/latest.json \ + "s3://${bucket}/latest.json" \ + --cache-control "public, max-age=300" \ + --content-type "application/json" + + - name: Invalidate CloudFront latest paths + shell: bash + run: | + set -euo pipefail + aws cloudfront create-invalidation \ + --distribution-id "${{ steps.meta.outputs.dist_id }}" \ + --paths "/latest.msixbundle" "/latest.json" \ + --query 'Invalidation.{Id:Id,Status:Status}' \ + --output table +``` + +- [ ] **Step 16.2: YAML 구문 검증 + 커밋** + +Run: +```bash +python3 -c "import yaml; yaml.safe_load(open('.github/workflows/release.yml')); print('OK')" +git add .github/workflows/release.yml +git commit -m "feat(ci): S3 업로드 및 CloudFront invalidation" +``` + +- [ ] **Step 16.3: workflow_dispatch 전체 흐름 검증 (dev 채널)** + +Run workflow with channel=`dev`, ref=현재 브랜치. (workflow_dispatch니까 태그가 아니어도 됨.) + +Expected: 모든 step 성공. 마지막 invalidation step 로그에 Id + Status `InProgress`. + +- [ ] **Step 16.4: dev 버킷 객체 확인** + +Run (로컬): +```bash +aws s3 ls s3://dev-scratch-link.aluxcoding.com/ --recursive +``` +Expected: `latest.msixbundle`, `latest.json`, `archive/v/...` 객체들. + +- [ ] **Step 16.5: dev CDN에서 다운로드 확인** + +Run (로컬): +```bash +curl -sIL https://dev-scratch-link.aluxcoding.com/latest.json | grep -E '^(HTTP|Cache-Control|Content-Type)' +curl -s https://dev-scratch-link.aluxcoding.com/latest.json | jq . +``` +Expected: HTTP 200, `Cache-Control: public, max-age=300`, JSON 본문에 version·url 등 출력. + +> CloudFront 전파가 끝났는지 + DNS가 풀렸는지가 전제. `Deployed` 상태 확인은 Task 12.4 명령. + +--- + +## Task 17: 정식 태그로 stable 경로 검증 + +prerelease 태그가 아닌 stable 태그를 한 번 푸시해 prod 경로가 동작하는지 확인. + +> 이 단계는 실제 release를 만드는 것이라 신중. 검증 후 필요하면 prod 버킷 객체와 태그를 정리할 수 있음. + +- [ ] **Step 17.1: 검증용 prerelease 태그 푸시 (dev 자동 트리거 확인)** + +Run: +```bash +git tag v0.0.1-test.1 +git push origin v0.0.1-test.1 +``` +Expected: GitHub Actions에 `Release` 워크플로가 자동 트리거. 채널 자동 인식 → dev. + +검증: `aws s3 ls s3://dev-scratch-link.aluxcoding.com/archive/v0.0.1-test.1/`. + +- [ ] **Step 17.2: 검증용 stable 태그 푸시 (prod 자동 트리거 확인)** + +Run: +```bash +git tag v0.0.1-rc-prod.1 # 본 태그도 prerelease 형태라 dev로 가야 함 +``` + +위는 의도적 dev 라우팅 확인용. 실제 prod 검증은: + +```bash +git tag v0.0.1 +git push origin v0.0.1 +``` +Expected: 워크플로 자동 실행 → channel=stable → prod 버킷·distribution 사용. + +검증: +```bash +aws s3 ls s3://scratch-link.aluxcoding.com/ +curl -s https://scratch-link.aluxcoding.com/latest.json | jq . +``` +Expected: 두 파일 + archive, latest.json의 channel=`stable`. + +- [ ] **Step 17.3: 정리 — 검증 태그·객체 삭제 (선택)** + +검증용 태그가 git 히스토리에 남는 게 싫으면: +```bash +git tag -d v0.0.1-test.1 v0.0.1 +git push origin :v0.0.1-test.1 :v0.0.1 +``` +S3에서도 archive 객체 삭제: +```bash +aws s3 rm s3://dev-scratch-link.aluxcoding.com/archive/v0.0.1-test.1/ --recursive +aws s3 rm s3://scratch-link.aluxcoding.com/archive/v0.0.1/ --recursive +``` + +`latest.*`는 다음 진짜 릴리스가 덮어쓰므로 남겨두어도 무방. + +--- + +## Task 18: README 다운로드 안내 추가 + +사용자가 어디서 받는지 README에 한 줄. + +**Files:** +- Modify: `README.md` + +- [ ] **Step 18.1: 다운로드 섹션 추가** + +`README.md`의 "패키징 및 배포" 섹션 위에 새 섹션 삽입: + +```markdown +## 다운로드 + +| 채널 | URL | +|---|---| +| Stable | https://scratch-link.aluxcoding.com/latest.msixbundle | +| Prerelease (개발판) | https://dev-scratch-link.aluxcoding.com/latest.msixbundle | + +최신 버전 메타: `latest.json` (같은 디렉토리). 특정 버전: `archive/v/...`. + +> 현재 빌드는 임시 자체서명 인증서로 서명되어 있어 일반 사용자 PC에서는 설치 전 인증서를 Trusted Root에 수동 설치해야 합니다. 정식 코드사이닝은 별도 작업으로 진행 예정. + +``` + +- [ ] **Step 18.2: 커밋** + +```bash +git add README.md +git commit -m "docs: 다운로드 URL 안내 추가" +``` + +--- + +## Task 19: PR 생성 + +브랜치 `feature/cicd-s3-cloudfront`를 develop으로 머지. + +- [ ] **Step 19.1: 브랜치 push (이미 됐으면 skip)** + +Run: +```bash +git push -u origin feature/cicd-s3-cloudfront +``` + +- [ ] **Step 19.2: PR 생성** + +Run: +```bash +gh pr create --base develop --title "feat(cicd): S3 + CloudFront 배포 파이프라인" --body "$(cat <<'EOF' +## Summary +- 기존 `ci.yml`·`macos-build`·`windows-build` 액션 제거 +- AWS S3·CloudFront·Route 53·IAM 일회성 셋업 스크립트(`scripts/aws/setup-cdn.sh`) 추가 +- `release.yml` 신규: semver 태그 푸시 → MSIX 빌드 → S3 업로드 → CloudFront invalidation +- `scratch-link.aluxcoding.com` (stable) / `dev-scratch-link.aluxcoding.com` (prerelease) 라우팅 +- 설계 문서: `docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md` +- 후속 작업(범위 외): 코드 사이닝, `.appinstaller` 자동 업데이트, OAC/OIDC 전환, WAF + +## Test plan +- [x] dev 채널 workflow_dispatch 성공 +- [x] dev 채널 자동 태그 트리거 성공 (`v0.0.1-test.1`) +- [x] prod 채널 자동 태그 트리거 성공 (`v0.0.1`) +- [x] CDN 다운로드 동작 확인 (`curl latest.json`) +- [x] IAM user 권한이 두 버킷·두 distribution에만 한정됨 확인 +EOF +)" +``` + +--- + +## Self-Review (작성 후 확인 완료) + +**Spec coverage** — spec의 모든 섹션이 task로 매핑됨: +- §3 AWS 인프라 → Task 2~10 +- §4 셋업 스크립트 → Task 10, runbook은 Task 11 +- §5 워크플로 → Task 13~16 +- §6 버킷 레이아웃·캐시 정책 → Task 15, 16 +- §7 빌드 환경 점검 → Task 14 (Verify build toolchain) +- §8 변경 파일 목록 → Task 1(삭제), Task 18(README) +- §9 후속 작업 → PR 본문에 명시 +- §10 검증 시나리오 → Task 17 + +**Placeholder scan** — TODO/TBD/"적절히" 없음. 모든 코드는 그대로 복붙 가능. + +**Type consistency** — `domain_for_env`, `ensure_bucket`, `ensure_distribution`, `ensure_route53_alias`, `ensure_iam_user`, `attach_iam_policy`, `ensure_access_key` 함수 시그니처가 setup-cdn.sh의 호출 측과 일치. 환경 변수명(`AWS_REGION`, `ACM_CERT_ARN`, `ROUTE53_ZONE_ID`, `IAM_USER_NAME`)이 common.sh 정의와 호출 측 일치. GitHub Secret 이름(`CF_DIST_ID_PROD/DEV`, `AWS_ACCESS_KEY_ID/SECRET/REGION`)이 setup 스크립트 출력 안내 → README → 워크플로 사이에 일관. + +**Scope** — 단일 임플 플랜으로 적정. 19개 task, 인프라 5개 + 워크플로 4개 + 검증 3개 + 메타 7개. 각 task는 2~10분 내 완료 가능. From 5697e2e5dddd1921fc53ee5cad4f24b9a8b73c3f Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:40:40 +0900 Subject: [PATCH 36/94] =?UTF-8?q?chore(ci):=20=EA=B8=B0=EC=A1=B4=20?= =?UTF-8?q?=ED=86=B5=ED=95=A9=20=EC=9B=8C=ED=81=AC=ED=94=8C=EB=A1=9C=20?= =?UTF-8?q?=EB=B0=8F=20composite=20actions=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 신규 release.yml(태그 트리거)로 대체 예정. signature-assistant.yml은 별개 기능이라 유지. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/actions/macos-build/action.yml | 68 -------- .github/actions/windows-build/action.yml | 43 ----- .github/workflows/ci.yml | 201 ----------------------- 3 files changed, 312 deletions(-) delete mode 100644 .github/actions/macos-build/action.yml delete mode 100644 .github/actions/windows-build/action.yml delete mode 100644 .github/workflows/ci.yml diff --git a/.github/actions/macos-build/action.yml b/.github/actions/macos-build/action.yml deleted file mode 100644 index 603cdc15..00000000 --- a/.github/actions/macos-build/action.yml +++ /dev/null @@ -1,68 +0,0 @@ -#Xamarin.Mac -> 6.12 -#iOS 16.2 -> 16.4 -#macOS (Cocoa) 9.1 -> 9.3 -#.NET -> 6.0 -#.NET -> 7.0 -#Visual Studio 17.5 -> 17.6 -name: Build for macOS -description: Core build steps for macOS -inputs: - configuration: - description: The configuration to build, like "Debug" - required: true - default: Debug - artifact_tag: - description: A string to tag the build artifact, like "Debug" or "MAS" - required: false - default: "" - sign: - description: Whether to sign the build artifact ("YES" or "NO") - required: false - default: "NO" - AC_USERNAME: - description: App Store Connect user name - required: false - default: "" - AC_PASSWORD: - description: App Store Connect password - required: false - default: "not set" -runs: - using: composite - steps: - # Note that runs.env doesn't work in composite actions - - name: "Build for Mac: ${{ inputs.configuration }}" - env: - AC_USERNAME: ${{ inputs.AC_USERNAME }} - AC_PASSWORD: ${{ inputs.AC_PASSWORD }} - CODE_SIGNING_ALLOWED: ${{ inputs.sign }} - CODE_SIGNING_REQUIRED: ${{ inputs.sign }} - ARTIFACT_TAG: ${{ inputs.configuration == 'Release_DevID' && 'notarizeMe' || inputs.artifact_tag }} - shell: bash - run: | - set -x # debug trace - msbuild -m -t:Restore -p:Configuration=${{ inputs.configuration }}_Mac scratch-link.sln - '/Applications/Visual Studio.app/Contents/MacOS/vstool' build -t:Build -c:'${{ inputs.configuration }}_Mac' "${PWD}/scratch-link.sln" - # "for" is just a convenient way to resolve the glob to a variable so we can DRY the filename for "if" and "mv" - for PKGPATH in scratch-link-mac/bin/"${{ inputs.configuration }}"/"Scratch Link"*.pkg; do - if [ -r "$PKGPATH" ]; then - # Get filename without path - PKGFILE="${PKGPATH##*/}" - if [ -n "${{ inputs.artifact_tag }}" ]; then - # change "Scratch Link-1.2.3" to "Scratch Link-Debug-1.2.3" - PKGFILE="${PKGFILE/Scratch Link/Scratch Link-${{ inputs.artifact_tag }}}" - fi - mkdir -p Artifacts - fi - # this is outside the "if" to force an error if the file doesn't exist - mv -v "$PKGPATH" "Artifacts/${PKGFILE}" - done - - name: "Notarize build artifact" - if: env.ARTIFACT_TAG == 'notarizeMe' - shell: bash - run: | - for PKGPATH in Artifacts/"Scratch Link-notarizeMe"*.pkg; do - PKGFILE="${PKGPATH##*/}" - scratch-link-mac/notarize.sh edu.mit.scratch.scratch-link "${PKGPATH}" "${PKGPATH}" /tmp || rm -f "${PKGPATH}" - mv -v "${PKGPATH}" "Artifacts/${PKGFILE/Scratch Link-notarizeMe/Scratch Link}" - done diff --git a/.github/actions/windows-build/action.yml b/.github/actions/windows-build/action.yml deleted file mode 100644 index a00fc4b9..00000000 --- a/.github/actions/windows-build/action.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Build for Windows -description: Core build steps for Windows -inputs: - configuration: - description: The configuration to build, like "Debug" - required: true - default: Debug - artifact_tag: - description: A string to tag the build artifact, like "Debug" or "MAS" - required: false - default: "" -runs: - using: composite - steps: - - name: "Build for Windows: ${{ inputs.configuration }}" - shell: pwsh - run: | - # Build the MSIX project instead of the Solution because msbuild gets grumpy about the Mac project. - # That means SolutionDir needs to be set artificially, though. - # The `UapAppxPackageBuildMode=StoreAndSideload` means it'll build both MSIXUpload and MSIXBundle. - # The StoreUpload mode does that too, but that might be a bug, and semantically "StoreAndSideload" is what we want. - msbuild scratch-link-win-msix/scratch-link-win-msix.wapproj -maxCpuCount -restore -t:Build -p:SolutionDir="$PWD\" -p:Configuration="${{ inputs.configuration }}_Win" -p:AppxBundlePlatforms="x86|x64|ARM64" -p:AppxBundle=Always -p:UapAppxPackageBuildMode=StoreAndSideload - - name: "Move Windows artifacts into place: ${{ inputs.configuration }}" - shell: bash - run: | - mkdir -p Artifacts - # The store package is fine as is: no user will see this filename. - mv -v scratch-link-win-msix/AppPackages/scratch-link-win-msix_*_${{ inputs.configuration }}_Win.msixupload Artifacts/ - # Transform the bundle for a more user-friendly filename - for PKGPATH in scratch-link-win-msix/AppPackages/scratch-link-win-msix_*_${{ inputs.configuration }}_Win_Test/scratch-link-win-msix_*_${{ inputs.configuration }}_Win.msixbundle; do - if [ -r "$PKGPATH" ]; then - PKGFILE="${PKGPATH##*/}" - [[ $PKGFILE =~ scratch-link-win-msix_([.0-9]+)_(.*)_${{ inputs.configuration }}_Win.msixbundle$ ]] - PKGVERSION=${BASH_REMATCH[1]} - PKGPLATFORMS=${BASH_REMATCH[2]} - fi - # do the move outside the "if" above to force an error if the file doesn't exist - if [ -z "${{ inputs.artifact_tag }}" ]; then - mv -v "$PKGPATH" "Artifacts/Scratch Link ${PKGVERSION}.msixbundle" - else - mv -v "$PKGPATH" "Artifacts/Scratch Link ${PKGVERSION} ${{ inputs.artifact_tag }}.msixbundle" - fi - done diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 31164b11..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,201 +0,0 @@ -name: CI build - -on: - push: # Runs whenever a commit is pushed to the repository, including for a PR - workflow_call: # Runs when this workflow is called from another workflow - workflow_dispatch: # Allows you to run this workflow manually from the Actions tab - -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -permissions: - contents: write # publish a GitHub release - issues: write # comment on released issues - pull-requests: write # comment on released pull requests - -jobs: - # Keep in mind: - # 60 seconds on Ubuntu = 1 minute charged to account - # 60 seconds on Windows = 2 minutes charged to account - # 60 seconds on macOS = 10 minutes charged to account - semver: - runs-on: ubuntu-latest - outputs: - version: ${{ steps.semver.outputs.SCRATCH_VERSION }} - hash: ${{ steps.semver.outputs.SCRATCH_HASH }} - steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 - - uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 # v3 - with: - cache: 'npm' - node-version-file: '.nvmrc' - - run: npm ci - - name: Make local 'remote' for semantic-release - run: | - # semantic-release tracks channels with notes, so we need to grab those from the real remote - # semantic-release also wants to inspect every branch listed in its "branches" setting - git fetch -uf origin main:main develop:develop 'refs/notes/*:refs/notes/*' - git clone . --bare --mirror semantic-release-remote # mirror copies notes - git remote set-url origin "file://$(realpath semantic-release-remote)" # semantic-release needs a proper URL - - name: Stage semantic-release version commit - # In release branches, this will calculate the version and save that to package.json so the build can use it. - # In other branches, it'll just check the semantic-release config. - # Note that if semantic-release makes changes it will automatically push them. - # That's the whole reason for the weird "local remote" stuff. - # See also: https://github.com/semantic-release/semantic-release/issues/964 - run: npx --no -- semantic-release - - name: Output semantic-release version - id: semver - run: | - cat < "$GITHUB_OUTPUT" - SCRATCH_VERSION=$(node -p "require('./package.json').version") - SCRATCH_HASH=$(git rev-parse --short HEAD) - EOF - - name: Create artifact for semantic-release 'remote' - run: tar czvf semantic-release-remote.tgz semantic-release-remote - - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4 - with: - name: semantic-release-remote - path: semantic-release-remote.tgz - retention-days: 1 # relevant if a failure prevents the delete step below - build: - needs: semver - defaults: - run: - shell: bash # even on Windows, unless otherwise specified - env: - SCRATCH_SHOULD_SIGN: "NO" # TODO - MATCH_STORAGE_MODE: git - MATCH_GIT_URL: ${{ secrets.FL_GIT_URL }} - MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} - FASTLANE_ACCESS_KEY: ${{ secrets.FASTLANE_ACCESS_KEY }} - strategy: - fail-fast: false - matrix: - image: [windows-latest, macos-latest] - runs-on: ${{ matrix.image }} - steps: - ### Shared prologue - - #- name: Setup upterm session - # uses: lhotari/action-upterm@v1 - # with: - # limit-access-to-users: cwillisf - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 - - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 - with: - name: semantic-release-remote - path: . - - name: Restore semantic-release 'remote' - run: | - # this `tar` command replaces the usual "checkout" step - tar xzvf semantic-release-remote.tgz - rm semantic-release-remote.tgz - - name: Pull semantic-release changes from local 'remote' - run: | - git remote add semantic-release semantic-release-remote - git pull --tags semantic-release ${{ github.ref_name }} - git fetch semantic-release 'refs/notes/*:refs/notes/*' # semantic-release tracks channels with notes - - ### macOS setup - - - name: "macOS: Setup keys for Fastlane" - if: runner.os == 'macOS' && env.FASTLANE_ACCESS_KEY != '' - uses: webfactory/ssh-agent@d4b9b8ff72958532804b70bbe600ad43b36d5f2e # v0.8.0 - with: - ssh-private-key: ${{ secrets.FASTLANE_ACCESS_KEY }} - - name: "macOS: Fastlane Match" - if: runner.os == 'macOS' && env.MATCH_PASSWORD != '' - shell: bash - run: fastlane circleci - - name: "macOS: Setup Xamarin" - if: runner.os == 'macOS' - shell: bash - run: | - #cat "$VM_ASSETS/select-xamarin-sdk-v2.sh" - #ls /Library/Frameworks/{Mono,Xamarin.Mac,Xamarin.iOS,Xamarin.Android}.framework/Versions/ - # For Xcode 13.2 / macOS 11: --mono=6.12 --mac=8.8 --ios=15.8 - # For Xcode 14.2 / macOS 12: --mono=6.12 --mac=9.1 --ios=16.2 - $VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --mac=9.1 --ios=16.2 - - ### Windows setup - - - name: "Windows: Add msbuild to PATH" - if: runner.os == 'Windows' - uses: microsoft/setup-msbuild@34cfbaee7f672c76950673338facd8a73f637506 # v1.1 - - ### Shared setup - - - name: Setup dotnet - uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3 - with: - dotnet-version: '6.0.x' - - uses: actions/cache@e12d46a63a90f2fae62d114769bbf2a179198b5c # v3 - with: - path: ~/.nuget/packages - # Look to see if there is a cache hit for the corresponding requirements file - key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} - restore-keys: ${{ runner.os }}-nuget - - ### macOS build - - - name: Build for macOS debug - if: runner.os == 'macOS' && env.SCRATCH_SHOULD_SIGN != 'YES' - uses: ./.github/actions/macos-build - with: - configuration: Debug - artifact_tag: Debug - sign: ${{ env.SCRATCH_SHOULD_SIGN }} - AC_USERNAME: ${{ secrets.AC_USERNAME }} - AC_PASSWORD: ${{ secrets.AC_PASSWORD }} - - name: Build for macOS direct download - if: runner.os == 'macOS' && env.SCRATCH_SHOULD_SIGN == 'YES' - uses: ./.github/actions/macos-build - with: - configuration: Release_DevID - artifact_tag: '' - sign: ${{ env.SCRATCH_SHOULD_SIGN }} - AC_USERNAME: ${{ secrets.AC_USERNAME }} - AC_PASSWORD: ${{ secrets.AC_PASSWORD }} - - name: Build for Mac App Store - if: runner.os == 'macOS' && env.SCRATCH_SHOULD_SIGN == 'YES' - uses: ./.github/actions/macos-build - with: - configuration: Release_MAS - artifact_tag: MAS - sign: ${{ env.SCRATCH_SHOULD_SIGN }} - AC_USERNAME: ${{ secrets.AC_USERNAME }} - AC_PASSWORD: ${{ secrets.AC_PASSWORD }} - - ### Windows build - - - name: Build for Windows debug - if: runner.os == 'Windows' && env.SCRATCH_SHOULD_SIGN != 'YES' - uses: ./.github/actions/windows-build - with: - configuration: Debug - artifact_tag: Debug - - name: Build for Windows release - if: runner.os == 'Windows' && env.SCRATCH_SHOULD_SIGN == 'YES' - uses: ./.github/actions/windows-build - with: - configuration: Release - artifact_tag: '' - - ### Shared epilogue - - - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4 - with: - name: "Scratch ${{ needs.semver.outputs.version }} (${{ needs.semver.outputs.hash }})" - path: Artifacts/ - - finish: - if: always() # even if the build fails - runs-on: ubuntu-latest - needs: build - steps: - - uses: geekyeggo/delete-artifact@54ab544f12cdb7b71613a16a2b5a37a9ade990af # v2 - with: - name: semantic-release-remote - failOnError: false From 65df9eb0c9f9b2c91354ebedb76eef8c24f6b77c Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:44:05 +0900 Subject: [PATCH 37/94] =?UTF-8?q?chore(aws):=20=EC=85=8B=EC=97=85=20?= =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=A6=BD=ED=8A=B8=20=EA=B3=B5=ED=86=B5=20?= =?UTF-8?q?=EC=9C=A0=ED=8B=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/aws/lib/common.sh | 58 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100755 scripts/aws/lib/common.sh diff --git a/scripts/aws/lib/common.sh b/scripts/aws/lib/common.sh new file mode 100755 index 00000000..af50b29d --- /dev/null +++ b/scripts/aws/lib/common.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# 공통 유틸: 로깅, 환경 변수, 사전 점검. +# 호출 측에서 `source "$(dirname "$0")/lib/common.sh"`로 사용. + +# bash 4+ 필요 (associative array 등) +if (( BASH_VERSINFO[0] < 4 )); then + echo "ERROR: bash 4 이상 필요 (현재: $BASH_VERSION). macOS는 'brew install bash' 후 /opt/homebrew/bin/bash로 실행." >&2 + exit 1 +fi + +set -euo pipefail + +# 색상 로그 +RED=$'\033[31m'; GREEN=$'\033[32m'; YELLOW=$'\033[33m'; BLUE=$'\033[34m'; RESET=$'\033[0m' +log_info() { printf "%s[INFO]%s %s\n" "$BLUE" "$RESET" "$*" >&2; } +log_warn() { printf "%s[WARN]%s %s\n" "$YELLOW" "$RESET" "$*" >&2; } +log_error() { printf "%s[ERROR]%s %s\n" "$RED" "$RESET" "$*" >&2; } +log_ok() { printf "%s[OK]%s %s\n" "$GREEN" "$RESET" "$*" >&2; } + +# 필수 외부 명령 점검 +require_cmd() { + local missing=() + for cmd in "$@"; do + if ! command -v "$cmd" >/dev/null 2>&1; then + missing+=("$cmd") + fi + done + if (( ${#missing[@]} > 0 )); then + log_error "다음 명령이 없습니다: ${missing[*]}" + exit 1 + fi +} + +# AWS 호출자 식별 출력 (실수 방지) +print_aws_identity() { + local id_json + id_json=$(aws sts get-caller-identity) + local account user + account=$(jq -r '.Account' <<<"$id_json") + user=$(jq -r '.Arn' <<<"$id_json") + log_info "AWS Account: $account" + log_info "Caller: $user" +} + +# 환경(prod/dev) → 도메인·버킷명 매핑 +domain_for_env() { + case "$1" in + prod) echo "scratch-link.aluxcoding.com" ;; + dev) echo "dev-scratch-link.aluxcoding.com" ;; + *) log_error "알 수 없는 환경: $1"; return 1 ;; + esac +} + +# 공용 상수 +export AWS_REGION="${AWS_REGION:-ap-northeast-2}" +export ACM_CERT_ARN="${ACM_CERT_ARN:-arn:aws:acm:us-east-1:593793057142:certificate/0b58642f-b20f-451b-8257-aa366ba5fc0c}" +export ROUTE53_ZONE_ID="${ROUTE53_ZONE_ID:-Z0327990CY2GCD1RONPB}" +export IAM_USER_NAME="${IAM_USER_NAME:-gh-actions-scratch-link}" From 1105972d2bc690b9ce5393a8011038da2d60154e Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:46:07 +0900 Subject: [PATCH 38/94] =?UTF-8?q?chore(aws):=20S3=20=EB=B2=84=ED=82=B7=20p?= =?UTF-8?q?ublic-read=20=EC=A0=95=EC=B1=85=20=ED=85=9C=ED=94=8C=EB=A6=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/aws/policies/bucket-policy.json.tpl | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 scripts/aws/policies/bucket-policy.json.tpl diff --git a/scripts/aws/policies/bucket-policy.json.tpl b/scripts/aws/policies/bucket-policy.json.tpl new file mode 100644 index 00000000..75aebe70 --- /dev/null +++ b/scripts/aws/policies/bucket-policy.json.tpl @@ -0,0 +1,12 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "PublicReadGetObject", + "Effect": "Allow", + "Principal": "*", + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::__BUCKET__/*" + } + ] +} From 0221109735d50c715337f12a48b7a4bf2213e6fc Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:47:23 +0900 Subject: [PATCH 39/94] =?UTF-8?q?chore(aws):=20S3=20=EB=B2=84=ED=82=B7=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=C2=B7=EA=B5=AC=EC=84=B1=20=ED=95=A8=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/aws/lib/bucket.sh | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 scripts/aws/lib/bucket.sh diff --git a/scripts/aws/lib/bucket.sh b/scripts/aws/lib/bucket.sh new file mode 100644 index 00000000..8e8dd4a9 --- /dev/null +++ b/scripts/aws/lib/bucket.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# S3 버킷 생성·구성 함수. setup-cdn.sh에서 source. + +# 인자: $1 = 버킷명 +ensure_bucket() { + local bucket="$1" + local region="$AWS_REGION" + + if aws s3api head-bucket --bucket "$bucket" 2>/dev/null; then + log_info "버킷 이미 존재: $bucket — 생성 skip" + else + log_info "버킷 생성: $bucket (region=$region)" + aws s3api create-bucket \ + --bucket "$bucket" \ + --region "$region" \ + --create-bucket-configuration "LocationConstraint=$region" \ + >/dev/null + log_ok "버킷 생성됨: $bucket" + fi + + log_info "Public Access Block 해제: $bucket" + aws s3api put-public-access-block \ + --bucket "$bucket" \ + --public-access-block-configuration \ + "BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false" + + log_info "Public-read 정책 적용: $bucket" + local policy_json + policy_json=$(sed "s/__BUCKET__/$bucket/g" "$(dirname "${BASH_SOURCE[0]}")/../policies/bucket-policy.json.tpl") + aws s3api put-bucket-policy --bucket "$bucket" --policy "$policy_json" + + log_info "Website hosting 활성화: $bucket" + aws s3 website "s3://$bucket/" --index-document index.html --error-document error.html + # MSIX 다운로드 용도라 index/error 페이지는 실제로 안 쓰이지만, website endpoint 활성화에 필수. + + log_ok "버킷 구성 완료: $bucket" +} From a7c52f2ecfd7e5395c13f71027d63b49cf432c2a Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:48:24 +0900 Subject: [PATCH 40/94] =?UTF-8?q?chore(aws):=20CloudFront=20distribution?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=EC=9E=85=EB=A0=A5=20=ED=85=9C=ED=94=8C?= =?UTF-8?q?=EB=A6=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- .../aws/policies/cloudfront-config.json.tpl | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 scripts/aws/policies/cloudfront-config.json.tpl diff --git a/scripts/aws/policies/cloudfront-config.json.tpl b/scripts/aws/policies/cloudfront-config.json.tpl new file mode 100644 index 00000000..d33d6590 --- /dev/null +++ b/scripts/aws/policies/cloudfront-config.json.tpl @@ -0,0 +1,48 @@ +{ + "CallerReference": "__CALLER_REF__", + "Comment": "__COMMENT__", + "Aliases": { + "Quantity": 1, + "Items": ["__DOMAIN__"] + }, + "DefaultRootObject": "", + "Origins": { + "Quantity": 1, + "Items": [ + { + "Id": "s3-website-origin", + "DomainName": "__ORIGIN_DOMAIN__", + "CustomOriginConfig": { + "HTTPPort": 80, + "HTTPSPort": 443, + "OriginProtocolPolicy": "http-only", + "OriginSslProtocols": { "Quantity": 1, "Items": ["TLSv1.2"] }, + "OriginReadTimeout": 30, + "OriginKeepaliveTimeout": 5 + }, + "ConnectionAttempts": 3, + "ConnectionTimeout": 10 + } + ] + }, + "DefaultCacheBehavior": { + "TargetOriginId": "s3-website-origin", + "ViewerProtocolPolicy": "redirect-to-https", + "AllowedMethods": { + "Quantity": 2, + "Items": ["GET", "HEAD"], + "CachedMethods": { "Quantity": 2, "Items": ["GET", "HEAD"] } + }, + "Compress": true, + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6" + }, + "PriceClass": "PriceClass_200", + "Enabled": true, + "ViewerCertificate": { + "ACMCertificateArn": "__CERT_ARN__", + "SSLSupportMethod": "sni-only", + "MinimumProtocolVersion": "TLSv1.2_2021" + }, + "HttpVersion": "http2and3", + "IsIPV6Enabled": true +} From ace93fc91d20b8b3f24f66fe73431a001ea56aa3 Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:49:35 +0900 Subject: [PATCH 41/94] =?UTF-8?q?chore(aws):=20CloudFront=20distribution?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=ED=95=A8=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/aws/lib/cloudfront.sh | 56 +++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 scripts/aws/lib/cloudfront.sh diff --git a/scripts/aws/lib/cloudfront.sh b/scripts/aws/lib/cloudfront.sh new file mode 100644 index 00000000..b4cfe22c --- /dev/null +++ b/scripts/aws/lib/cloudfront.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# CloudFront distribution 생성. setup-cdn.sh에서 source. + +# 인자: $1 = 도메인 (== alias, == 버킷명) +# $2 = comment (UI에서 식별용) +# 출력: stdout 한 줄. "DIST_ID\tCF_DOMAIN" (tab 구분) +ensure_distribution() { + local domain="$1" + local comment="$2" + local origin_domain="${domain}.s3-website.${AWS_REGION}.amazonaws.com" + + local existing + existing=$(aws cloudfront list-distributions \ + --query "DistributionList.Items[?contains(Aliases.Items, \`$domain\`)].{Id:Id,Domain:DomainName}" \ + --output json) + + local count + count=$(jq 'length' <<<"$existing") + + if [[ "$count" -ge 1 ]]; then + local dist_id dist_domain + dist_id=$(jq -r '.[0].Id' <<<"$existing") + dist_domain=$(jq -r '.[0].Domain' <<<"$existing") + log_info "CloudFront 이미 존재 ($domain): $dist_id" >&2 + printf "%s\t%s\n" "$dist_id" "$dist_domain" + return 0 + fi + + log_info "CloudFront distribution 생성: $domain" + local tpl="$(dirname "${BASH_SOURCE[0]}")/../policies/cloudfront-config.json.tpl" + local caller_ref + caller_ref="scratch-link-$(date +%s)-$$" + + local config_json + config_json=$(sed \ + -e "s/__CALLER_REF__/$caller_ref/g" \ + -e "s|__COMMENT__|$comment|g" \ + -e "s/__DOMAIN__/$domain/g" \ + -e "s/__ORIGIN_DOMAIN__/$origin_domain/g" \ + -e "s|__CERT_ARN__|$ACM_CERT_ARN|g" \ + "$tpl") + + local result + result=$(aws cloudfront create-distribution \ + --distribution-config "$config_json" \ + --output json) + + local dist_id dist_domain + dist_id=$(jq -r '.Distribution.Id' <<<"$result") + dist_domain=$(jq -r '.Distribution.DomainName' <<<"$result") + + log_ok "CloudFront 생성됨 ($domain): $dist_id / $dist_domain" >&2 + log_warn "Distribution 배포(In-Progress → Deployed)에는 5~15분 소요." >&2 + + printf "%s\t%s\n" "$dist_id" "$dist_domain" +} From 0ba15e26ccdfa86e59c2ed7b87b678eabf893ce6 Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:50:41 +0900 Subject: [PATCH 42/94] =?UTF-8?q?chore(aws):=20Route=2053=20alias=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=ED=95=A8=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/aws/lib/route53.sh | 74 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 scripts/aws/lib/route53.sh diff --git a/scripts/aws/lib/route53.sh b/scripts/aws/lib/route53.sh new file mode 100644 index 00000000..ca4890e9 --- /dev/null +++ b/scripts/aws/lib/route53.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# Route 53 A/AAAA alias 생성. setup-cdn.sh에서 source. + +# 인자: $1 = 도메인 (예: scratch-link.aluxcoding.com) +# $2 = CloudFront 도메인 (예: d123abc.cloudfront.net) +ensure_route53_alias() { + local domain="$1" + local cf_domain="$2" + # CloudFront는 hosted zone ID가 전 리전 동일: Z2FDTNDATAQYW2 + local cf_zone="Z2FDTNDATAQYW2" + + # 기존 레코드 확인 + local existing + existing=$(aws route53 list-resource-record-sets \ + --hosted-zone-id "$ROUTE53_ZONE_ID" \ + --query "ResourceRecordSets[?Name=='${domain}.' && (Type=='A' || Type=='AAAA')]" \ + --output json) + + local existing_count + existing_count=$(jq 'length' <<<"$existing") + + if [[ "$existing_count" -ge 2 ]]; then + # A + AAAA 둘 다 있고, target이 일치하면 skip + local existing_target + existing_target=$(jq -r '.[0].AliasTarget.DNSName // ""' <<<"$existing") + if [[ "$existing_target" == "${cf_domain}." ]]; then + log_info "Route 53 alias 이미 존재 ($domain → $cf_domain) — skip" + return 0 + fi + log_warn "Route 53 alias가 다른 타겟을 가리키고 있음 ($existing_target). 덮어쓰기 진행." + fi + + log_info "Route 53 A/AAAA alias 추가: $domain → $cf_domain" + + local change_batch + change_batch=$(cat </dev/null + + log_ok "Route 53 alias 등록됨 ($domain)" +} From 87c0e724f13b9593c248a8921dc82b6a86783b7a Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:51:17 +0900 Subject: [PATCH 43/94] =?UTF-8?q?chore(aws):=20gh-actions-scratch-link=20I?= =?UTF-8?q?AM=20=EC=A0=95=EC=B1=85=20=ED=85=9C=ED=94=8C=EB=A6=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/aws/policies/iam-policy.json.tpl | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 scripts/aws/policies/iam-policy.json.tpl diff --git a/scripts/aws/policies/iam-policy.json.tpl b/scripts/aws/policies/iam-policy.json.tpl new file mode 100644 index 00000000..de2d0c85 --- /dev/null +++ b/scripts/aws/policies/iam-policy.json.tpl @@ -0,0 +1,25 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "S3Upload", + "Effect": "Allow", + "Action": ["s3:PutObject", "s3:DeleteObject", "s3:ListBucket"], + "Resource": [ + "arn:aws:s3:::scratch-link.aluxcoding.com", + "arn:aws:s3:::scratch-link.aluxcoding.com/*", + "arn:aws:s3:::dev-scratch-link.aluxcoding.com", + "arn:aws:s3:::dev-scratch-link.aluxcoding.com/*" + ] + }, + { + "Sid": "CloudFrontInvalidate", + "Effect": "Allow", + "Action": ["cloudfront:CreateInvalidation", "cloudfront:GetInvalidation"], + "Resource": [ + "arn:aws:cloudfront::__ACCOUNT__:distribution/__PROD_DIST_ID__", + "arn:aws:cloudfront::__ACCOUNT__:distribution/__DEV_DIST_ID__" + ] + } + ] +} From 49c1ed585beb465b5daec262f3f4cad9014b34de Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 May 2026 13:52:12 +0900 Subject: [PATCH 44/94] =?UTF-8?q?refactor(rebrand):=20AssemblyName=20/=20R?= =?UTF-8?q?ootNamespace=20=EB=A5=BC=20AluxLabs=20Link=20=EB=A1=9C=20?= =?UTF-8?q?=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AssemblyName: "Alux Scratch Link" → "AluxLabs Link" → exe 파일명, AssemblyTitleAttribute, 트레이 메뉴 동적 라벨이 자동 갱신됨 - RootNamespace: ScratchLink.Win → AluxLabs.Link.Win → 새 파일 추가 시의 default namespace 만 영향. 기존 .cs 의 namespace ScratchLink.* 선언은 별도 단계에서 일괄 치환. bin/obj 정리 후 재빌드 검증 완료. Co-Authored-By: Claude Opus 4.7 (1M context) --- scratch-link-win/scratch-link-win.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scratch-link-win/scratch-link-win.csproj b/scratch-link-win/scratch-link-win.csproj index 64f68fa0..283747c5 100644 --- a/scratch-link-win/scratch-link-win.csproj +++ b/scratch-link-win/scratch-link-win.csproj @@ -4,8 +4,8 @@ net8.0-windows10.0.22621.0 win-x86;win-x64;win-arm64 10.0.17763.0 - ScratchLink.Win - Alux Scratch Link + AluxLabs.Link.Win + AluxLabs Link ALUX, Inc. $(Company) disable From 6797ab07c55e7a2ae9241f63c71dbf2531e15720 Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:52:34 +0900 Subject: [PATCH 45/94] =?UTF-8?q?chore(aws):=20IAM=20user=C2=B7=EC=A0=95?= =?UTF-8?q?=EC=B1=85=C2=B7access=20key=20=ED=95=A8=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/aws/lib/iam.sh | 66 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 scripts/aws/lib/iam.sh diff --git a/scripts/aws/lib/iam.sh b/scripts/aws/lib/iam.sh new file mode 100644 index 00000000..c91a1f06 --- /dev/null +++ b/scripts/aws/lib/iam.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# IAM user·policy·access key 함수. setup-cdn.sh에서 source. + +# IAM user 생성 (멱등). 출력 없음. +ensure_iam_user() { + if aws iam get-user --user-name "$IAM_USER_NAME" >/dev/null 2>&1; then + log_info "IAM user 이미 존재: $IAM_USER_NAME — skip" + return 0 + fi + log_info "IAM user 생성: $IAM_USER_NAME" + aws iam create-user --user-name "$IAM_USER_NAME" >/dev/null + log_ok "IAM user 생성됨: $IAM_USER_NAME" +} + +# 인라인 정책 attach (idempotent — put-user-policy는 덮어쓰기). +# 인자: $1 = AWS Account ID, $2 = PROD_DIST_ID, $3 = DEV_DIST_ID +attach_iam_policy() { + local account="$1" + local prod_id="$2" + local dev_id="$3" + local tpl="$(dirname "${BASH_SOURCE[0]}")/../policies/iam-policy.json.tpl" + + log_info "IAM 인라인 정책 attach (gh-actions-scratch-link 정책)" + local policy_json + policy_json=$(sed \ + -e "s/__ACCOUNT__/$account/g" \ + -e "s/__PROD_DIST_ID__/$prod_id/g" \ + -e "s/__DEV_DIST_ID__/$dev_id/g" \ + "$tpl") + + aws iam put-user-policy \ + --user-name "$IAM_USER_NAME" \ + --policy-name "scratch-link-cdn-deploy" \ + --policy-document "$policy_json" + log_ok "IAM 정책 attach 완료" +} + +# access key 발급 또는 기존 키 안내. +# 기존 키가 있으면 secret을 다시 볼 수 없으므로, 사용자에게 옵션을 묻는다. +# 출력: stdout 한 줄. "ACCESS_KEY_ID\tSECRET_ACCESS_KEY" (신규 발급 시) 또는 빈 줄 (skip). +ensure_access_key() { + local existing + existing=$(aws iam list-access-keys --user-name "$IAM_USER_NAME" \ + --query 'AccessKeyMetadata[].AccessKeyId' --output json) + local count + count=$(jq 'length' <<<"$existing") + + if [[ "$count" -ge 1 ]]; then + log_warn "IAM user에 access key가 이미 ${count}개 있음: $(jq -r 'join(", ")' <<<"$existing")" + log_warn "기존 키의 secret은 재조회 불가. 분실 시 'aws iam delete-access-key' 후 재실행." + log_warn "신규 키 발급 원하면 환경변수 FORCE_NEW_KEY=1로 재실행 (단, IAM 한도 2개)." + if [[ "${FORCE_NEW_KEY:-}" != "1" ]]; then + printf "\n" + return 0 + fi + fi + + log_info "access key 발급: $IAM_USER_NAME" + local result + result=$(aws iam create-access-key --user-name "$IAM_USER_NAME" --output json) + local key_id secret + key_id=$(jq -r '.AccessKey.AccessKeyId' <<<"$result") + secret=$(jq -r '.AccessKey.SecretAccessKey' <<<"$result") + log_ok "신규 access key 발급됨: $key_id" + printf "%s\t%s\n" "$key_id" "$secret" +} From 1951196ef5d48356c9c1aa5a17ad12e35c98cbc3 Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:54:03 +0900 Subject: [PATCH 46/94] =?UTF-8?q?feat(aws):=20scratch-link=20CDN=20?= =?UTF-8?q?=EC=9D=BC=ED=9A=8C=EC=84=B1=20=EC=85=8B=EC=97=85=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A6=BD=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/aws/setup-cdn.sh | 97 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100755 scripts/aws/setup-cdn.sh diff --git a/scripts/aws/setup-cdn.sh b/scripts/aws/setup-cdn.sh new file mode 100755 index 00000000..3484c7a0 --- /dev/null +++ b/scripts/aws/setup-cdn.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +# Scratch Link CDN AWS 인프라 일회성 셋업. +# 멱등: 다시 실행해도 안전. 자세한 절차는 scripts/aws/README.md 참고. + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# shellcheck source=lib/common.sh +source "$SCRIPT_DIR/lib/common.sh" +# shellcheck source=lib/bucket.sh +source "$SCRIPT_DIR/lib/bucket.sh" +# shellcheck source=lib/cloudfront.sh +source "$SCRIPT_DIR/lib/cloudfront.sh" +# shellcheck source=lib/route53.sh +source "$SCRIPT_DIR/lib/route53.sh" +# shellcheck source=lib/iam.sh +source "$SCRIPT_DIR/lib/iam.sh" + +require_cmd aws jq sed +print_aws_identity + +read -r -p "위 계정·사용자로 진행할까요? (y/N) " confirm +if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then + log_info "취소" + exit 0 +fi + +# 1. S3 버킷 +for env in prod dev; do + domain=$(domain_for_env "$env") + ensure_bucket "$domain" +done + +# 2. CloudFront distribution +declare -A DIST_ID DIST_DOMAIN +for env in prod dev; do + domain=$(domain_for_env "$env") + comment="scratch-link CDN ($env)" + result=$(ensure_distribution "$domain" "$comment") + DIST_ID[$env]=$(cut -f1 <<<"$result") + DIST_DOMAIN[$env]=$(cut -f2 <<<"$result") +done + +# 3. Route 53 alias +for env in prod dev; do + domain=$(domain_for_env "$env") + ensure_route53_alias "$domain" "${DIST_DOMAIN[$env]}" +done + +# 4. IAM user +ensure_iam_user +ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) +attach_iam_policy "$ACCOUNT_ID" "${DIST_ID[prod]}" "${DIST_ID[dev]}" + +# 5. access key +key_line=$(ensure_access_key) + +# 6. 요약 출력 (사용자가 GitHub Secret으로 옮길 정보) +cat >&2 <&2 <&2 <&2 < Date: Tue, 26 May 2026 13:56:39 +0900 Subject: [PATCH 47/94] =?UTF-8?q?docs(aws):=20CDN=20=EC=85=8B=EC=97=85=20r?= =?UTF-8?q?unbook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/aws/README.md | 85 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 scripts/aws/README.md diff --git a/scripts/aws/README.md b/scripts/aws/README.md new file mode 100644 index 00000000..b73d54c0 --- /dev/null +++ b/scripts/aws/README.md @@ -0,0 +1,85 @@ +# Scratch Link CDN AWS Setup + +`scratch-link.aluxcoding.com` (prod) / `dev-scratch-link.aluxcoding.com` (dev) 두 환경의 S3·CloudFront·Route 53·IAM 리소스를 한 번에 프로비저닝하는 스크립트. + +설계 문서: [`docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md`](../../docs/superpowers/specs/2026-05-26-cicd-s3-cloudfront-design.md) + +## 전제 + +- aws-cli v2, jq, bash 4+ (macOS는 `brew install bash`) +- AWS 관리자 권한 (IAM user/policy 생성 가능) +- Account `593793057142`, region `ap-northeast-2` +- ACM `*.aluxcoding.com` 인증서가 us-east-1에 존재 (이미 발급되어 있음) +- Route 53 `aluxcoding.com.` zone (이미 있음) + +## 실행 + +```bash +cd +./scripts/aws/setup-cdn.sh +``` + +스크립트가 AWS 호출자(account, user)를 보여주고 진행 여부를 물어봅니다. 잘못된 계정이면 `n`을 입력해 취소. + +## 산출 + +마지막에 출력되는 5개 값을 GitHub **Organization** Secrets에 등록: + +| Secret 이름 | 출처 | +|---|---| +| `AWS_REGION` | 고정 `ap-northeast-2` | +| `AWS_ACCESS_KEY_ID` | 스크립트 출력 | +| `AWS_SECRET_ACCESS_KEY` | 스크립트 출력 (1회만 보임) | +| `CF_DIST_ID_PROD` | 스크립트 출력 | +| `CF_DIST_ID_DEV` | 스크립트 출력 | + +등록 경로: GitHub Org → Settings → Secrets and variables → Actions → New organization secret. 본 리포지토리(`aluxrobot/scratch-link`)를 접근 가능 리포에 추가. + +> 기존 Org Secret에 `AWS_ACCESS_KEY_ID` 이름이 이미 다른 키로 등록돼 있으면, 본 워크플로용 이름을 `SCRATCH_LINK_AWS_ACCESS_KEY_ID` 등으로 바꿔 등록하고 `release.yml`의 secret 참조도 같이 바꾸세요. + +## 멱등성 + +- 모든 리소스는 존재 확인 후 skip +- IAM 정책은 항상 덮어쓰기 (안전) +- IAM access key는 이미 있으면 skip (secret 재조회 불가). 강제 신규 발급: `FORCE_NEW_KEY=1 ./scripts/aws/setup-cdn.sh` + +## CloudFront 전파 대기 + +생성 직후 `In-Progress` 상태. Deployed 될 때까지 5~15분. + +```bash +aws cloudfront get-distribution --id $CF_DIST_ID_PROD --query 'Distribution.Status' +``` + +`Deployed`가 뜨면 https://scratch-link.aluxcoding.com/ 접근 가능 (단, DNS 전파도 같이 필요. 보통 즉시 ~ 수 분). + +## 롤백·재구성 + +생성된 리소스를 일괄 제거하는 스크립트는 만들지 않음. 필요 시: + +```bash +# CloudFront disable + delete +aws cloudfront update-distribution --id --if-match --distribution-config +aws cloudfront delete-distribution --id --if-match + +# Route 53 레코드 삭제 +aws route53 change-resource-record-sets --hosted-zone-id Z0327990CY2GCD1RONPB --change-batch + +# S3 버킷 비우고 삭제 +aws s3 rm s3://scratch-link.aluxcoding.com --recursive +aws s3api delete-bucket --bucket scratch-link.aluxcoding.com + +# IAM user +aws iam delete-user-policy --user-name gh-actions-scratch-link --policy-name scratch-link-cdn-deploy +aws iam delete-access-key --user-name gh-actions-scratch-link --access-key-id +aws iam delete-user --user-name gh-actions-scratch-link +``` + +## 트러블슈팅 + +| 증상 | 원인 / 조치 | +|---|---| +| `BucketAlreadyOwnedByYou` 외의 `BucketAlreadyExists` | 글로벌하게 같은 이름의 버킷이 다른 계정에서 사용 중. 도메인 이름을 바꿔야 함. | +| CloudFront 생성 시 `CNAMEAlreadyExists` | 다른 distribution이 같은 alias를 들고 있음. 기존 distribution을 disable/delete 또는 alias 회수 필요. | +| `InvalidViewerCertificate` | ACM 인증서가 us-east-1이 아니거나 ISSUED 상태가 아님. `ACM_CERT_ARN` 재확인. | +| `MalformedPolicyDocument` | IAM 정책 템플릿의 placeholder 미치환. `setup-cdn.sh`가 sed 치환을 정상 수행했는지 stderr 로그 확인. | From fc90308a7706b93a2722478b3267927e3ae73a2f Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:58:44 +0900 Subject: [PATCH 48/94] =?UTF-8?q?feat(ci):=20release.yml=20=ED=8A=B8?= =?UTF-8?q?=EB=A6=AC=EA=B1=B0=C2=B7=EC=B1=84=EB=84=90=20=EA=B2=B0=EC=A0=95?= =?UTF-8?q?=20=EC=8A=A4=EC=BC=88=EB=A0=88=ED=86=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/release.yml | 82 +++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..09364e23 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,82 @@ +name: Release + +on: + push: + tags: + - 'v*.*.*' + - 'v*.*.*-*' + workflow_dispatch: + inputs: + channel: + description: 'Override channel (auto/stable/dev). auto=태그 형식으로 결정' + type: choice + options: [auto, stable, dev] + default: auto + ref: + description: '수동 실행 시 사용할 ref (태그/브랜치). 비우면 워크플로 ref 사용' + type: string + default: '' + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false + +permissions: + contents: read + +jobs: + release: + runs-on: windows-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event.inputs.ref || github.ref }} + + - name: Resolve channel and version + id: meta + run: | + set -euo pipefail + # 채널 결정 + input="${{ github.event.inputs.channel }}" + tag_name="${GITHUB_REF_NAME:-}" + if [[ "$input" == "stable" || "$input" == "dev" ]]; then + channel="$input" + elif [[ "$tag_name" =~ ^v[0-9]+\.[0-9]+\.[0-9]+- ]]; then + channel="dev" + elif [[ "$tag_name" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + channel="stable" + else + channel="dev" # workflow_dispatch + auto + non-tag ref → 안전한 쪽 + fi + # 버전 산출 (태그면 v 제거, 아니면 git describe) + if [[ "$tag_name" =~ ^v ]]; then + version="${tag_name#v}" + else + version="$(git describe --tags --always --dirty)" + fi + # 채널별 버킷·distribution + if [[ "$channel" == "stable" ]]; then + bucket="scratch-link.aluxcoding.com" + dist_id="${{ secrets.CF_DIST_ID_PROD }}" + else + bucket="dev-scratch-link.aluxcoding.com" + dist_id="${{ secrets.CF_DIST_ID_DEV }}" + fi + { + echo "channel=$channel" + echo "version=$version" + echo "bucket=$bucket" + echo "dist_id=$dist_id" + } | tee -a "$GITHUB_OUTPUT" + + - name: Show resolved metadata + run: | + echo "channel = ${{ steps.meta.outputs.channel }}" + echo "version = ${{ steps.meta.outputs.version }}" + echo "bucket = ${{ steps.meta.outputs.bucket }}" + echo "dist_id = (마스킹됨)" From eed718dccd3f3dc5a4bd32c25c344c18eff214ac Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 13:59:47 +0900 Subject: [PATCH 49/94] =?UTF-8?q?feat(ci):=20release.yml=20MSIX=20?= =?UTF-8?q?=EB=B9=8C=EB=93=9C=20step=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/release.yml | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 09364e23..d89cbafc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,3 +80,40 @@ jobs: echo "version = ${{ steps.meta.outputs.version }}" echo "bucket = ${{ steps.meta.outputs.bucket }}" echo "dist_id = (마스킹됨)" + + - name: Setup .NET 8 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v2 + + - name: Verify build toolchain + shell: pwsh + run: | + dotnet --version + msbuild -version + aws --version + + - name: Restore NuGet cache + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json', '**/*.csproj', '**/*.props') }} + restore-keys: ${{ runner.os }}-nuget- + + - name: Build MSIX bundle + shell: pwsh + env: + SOLUTION_DIR: ${{ github.workspace }} + run: | + msbuild scratch-link-win-msix/scratch-link-win-msix.wapproj ` + -maxCpuCount ` + -restore ` + -t:Build ` + -p:SolutionDir="$env:SOLUTION_DIR\" ` + -p:Configuration=Release_Win ` + -p:AppxBundlePlatforms="x86|x64|ARM64" ` + -p:AppxBundle=Always ` + -p:UapAppxPackageBuildMode=StoreAndSideload From b9d3de5fb235720f801da04a7f5053f39b45b020 Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 14:00:52 +0900 Subject: [PATCH 50/94] =?UTF-8?q?feat(ci):=20MSIX=20=EC=82=B0=EC=B6=9C?= =?UTF-8?q?=EB=AC=BC=20=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20latest.json=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/release.yml | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d89cbafc..bffb7ade 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -117,3 +117,47 @@ jobs: -p:AppxBundlePlatforms="x86|x64|ARM64" ` -p:AppxBundle=Always ` -p:UapAppxPackageBuildMode=StoreAndSideload + + - name: Collect artifacts + shell: bash + run: | + set -euo pipefail + mkdir -p Artifacts + + version="${{ steps.meta.outputs.version }}" + channel="${{ steps.meta.outputs.channel }}" + bundle_src=$(find scratch-link-win-msix/AppPackages -type f -name '*.msixbundle' | head -n1) + upload_src=$(find scratch-link-win-msix/AppPackages -type f -name '*.msixupload' | head -n1) + + if [[ -z "$bundle_src" || -z "$upload_src" ]]; then + echo "::error::빌드 산출물(.msixbundle / .msixupload)을 찾지 못함" + ls -R scratch-link-win-msix/AppPackages || true + exit 1 + fi + + bundle_dst="Artifacts/Scratch-Link-${version}.msixbundle" + upload_dst="Artifacts/Scratch-Link-${version}.msixupload" + cp "$bundle_src" "$bundle_dst" + cp "$upload_src" "$upload_dst" + + # 체크섬 + (cd Artifacts && sha256sum "$(basename "$bundle_dst")" "$(basename "$upload_dst")") > Artifacts/SHA256SUMS.txt + + # latest.json + sha=$(sha256sum "$bundle_dst" | awk '{print $1}') + size=$(stat -c %s "$bundle_dst" 2>/dev/null || stat -f %z "$bundle_dst") + published=$(date -u +%Y-%m-%dT%H:%M:%SZ) + archive_url="https://${{ steps.meta.outputs.bucket }}/archive/v${version}/$(basename "$bundle_dst")" + + jq -n \ + --arg version "$version" \ + --arg publishedAt "$published" \ + --arg channel "$channel" \ + --arg url "$archive_url" \ + --arg sha256 "$sha" \ + --argjson size "$size" \ + '{version:$version, publishedAt:$publishedAt, channel:$channel, url:$url, sha256:$sha256, size:$size, minWindowsBuild:17763, windowsAppRuntime:"1.8"}' \ + > Artifacts/latest.json + + ls -la Artifacts/ + cat Artifacts/latest.json From 1d7e7f14453c76e1fd996a807bfe1f3aafb5094c Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 14:01:53 +0900 Subject: [PATCH 51/94] =?UTF-8?q?feat(ci):=20S3=20=EC=97=85=EB=A1=9C?= =?UTF-8?q?=EB=93=9C=20=EB=B0=8F=20CloudFront=20invalidation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/release.yml | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bffb7ade..ba48c9f9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -161,3 +161,47 @@ jobs: ls -la Artifacts/ cat Artifacts/latest.json + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Upload archive (immutable) + shell: bash + run: | + set -euo pipefail + version="${{ steps.meta.outputs.version }}" + bucket="${{ steps.meta.outputs.bucket }}" + aws s3 cp Artifacts/ "s3://${bucket}/archive/v${version}/" \ + --recursive \ + --exclude "latest.json" \ + --cache-control "public, max-age=31536000, immutable" \ + --metadata-directive REPLACE + + - name: Upload latest pointers (short cache) + shell: bash + run: | + set -euo pipefail + version="${{ steps.meta.outputs.version }}" + bucket="${{ steps.meta.outputs.bucket }}" + aws s3 cp "Artifacts/Scratch-Link-${version}.msixbundle" \ + "s3://${bucket}/latest.msixbundle" \ + --cache-control "public, max-age=300" \ + --content-type "application/vnd.ms-appx" + aws s3 cp Artifacts/latest.json \ + "s3://${bucket}/latest.json" \ + --cache-control "public, max-age=300" \ + --content-type "application/json" + + - name: Invalidate CloudFront latest paths + shell: bash + run: | + set -euo pipefail + aws cloudfront create-invalidation \ + --distribution-id "${{ steps.meta.outputs.dist_id }}" \ + --paths "/latest.msixbundle" "/latest.json" \ + --query 'Invalidation.{Id:Id,Status:Status}' \ + --output table From d6b888417e7ebdf5235564ac383057ca186e1a33 Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 14:02:40 +0900 Subject: [PATCH 52/94] =?UTF-8?q?docs:=20=EB=8B=A4=EC=9A=B4=EB=A1=9C?= =?UTF-8?q?=EB=93=9C=20URL=20=EC=95=88=EB=82=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 276c9e32..1e2e5dec 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,17 @@ python brand/build_icons.py 생성물(ICO/PNG)은 커밋되어 있으므로 일반 빌드 시에는 실행 불필요. +## 다운로드 + +| 채널 | URL | +|---|---| +| Stable | https://scratch-link.aluxcoding.com/latest.msixbundle | +| Prerelease (개발판) | https://dev-scratch-link.aluxcoding.com/latest.msixbundle | + +최신 버전 메타: `latest.json` (같은 디렉토리). 특정 버전: `archive/v/...`. + +> 현재 빌드는 임시 자체서명 인증서로 서명되어 있어 일반 사용자 PC에서는 설치 전 인증서를 Trusted Root에 수동 설치해야 합니다. 정식 코드사이닝은 별도 작업으로 진행 예정. + ## 패키징 및 배포 현재 배포 방식은 **framework-dependent**입니다. Windows App Runtime 1.8이 없는 PC에서는 설치 안내가 표시됩니다. From 97962fe2bb8b4543dd85310cdb0f6831184eab1c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 May 2026 14:06:02 +0900 Subject: [PATCH 53/94] =?UTF-8?q?refactor(rebrand):=20C#=20=EB=84=A4?= =?UTF-8?q?=EC=9E=84=EC=8A=A4=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EB=B0=8F=20?= =?UTF-8?q?=ED=95=B5=EC=8B=AC=20=EC=8B=9D=EB=B3=84=EC=9E=90=EB=A5=BC=20Alu?= =?UTF-8?q?xLabs.Link=20=EB=A1=9C=20=EC=9D=BC=EA=B4=84=20=EC=B9=98?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scratch-link-common/, scratch-link-win/ 의 모든 .cs / .xaml / .projitems - namespace ScratchLink → AluxLabs.Link - namespace ScratchLink.Win → AluxLabs.Link.Win - namespace ScratchLink.{BLE,BT,Serial,JsonRpc,Extensions,...} → AluxLabs.Link.* 동일 구조 - using ScratchLink[.*] 일괄 갱신 - class ScratchLinkApp → AluxLabsLinkApp + 파일명 동기화 (scratch-link-common/ScratchLinkApp.cs → AluxLabsLinkApp.cs, git mv) - XAML x:Class, xmlns:local 갱신 (App.xaml, TrayIcon.xaml) - XAML 리소스 키 ScratchLinkTaskbarIcon → AluxLabsLinkTaskbarIcon - projitems Import_RootNamespace 갱신 원본 attribution 헤더 (// Copyright (c) Scratch Foundation) 와 "// Based on scratch-link by Scratch Foundation ..." 표시는 AGPL §5 에 따라 그대로 보존. dotnet build Debug_Win 성공 확인 (warning 14건은 사전 StyleCop 경고, 이번 변경분 무관). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../{ScratchLinkApp.cs => AluxLabsLinkApp.cs} | 16 ++++++++-------- scratch-link-common/BLE/BLESession.cs | 8 ++++---- scratch-link-common/BLE/GattHelpers.cs | 6 +++--- scratch-link-common/BLE/IBLEEndpoint.cs | 4 ++-- scratch-link-common/BT/BTSession.cs | 8 ++++---- scratch-link-common/EncodingHelpers.cs | 6 +++--- scratch-link-common/EventAwaiter.cs | 2 +- .../Extensions/ContainerExtensions.cs | 4 ++-- scratch-link-common/Extensions/JsonExtensions.cs | 4 ++-- .../Extensions/SemaphoreSlimExtensions.cs | 4 ++-- .../Converters/JsonRpc2MessageConverter.cs | 2 +- .../JsonRpc/Converters/JsonRpc2ValueConverter.cs | 4 ++-- scratch-link-common/JsonRpc/JsonRpc2Error.cs | 4 ++-- scratch-link-common/JsonRpc/JsonRpc2Exception.cs | 4 ++-- scratch-link-common/JsonRpc/JsonRpc2Message.cs | 4 ++-- scratch-link-common/JsonRpc/JsonRpc2Request.cs | 4 ++-- scratch-link-common/JsonRpc/JsonRpc2Response.cs | 4 ++-- scratch-link-common/PeripheralSession.cs | 6 +++--- .../Serial/SerialDiscoveryFilter.cs | 2 +- scratch-link-common/Serial/SerialOpenParams.cs | 2 +- scratch-link-common/Serial/SerialSession.cs | 6 +++--- scratch-link-common/Session.cs | 8 ++++---- scratch-link-common/SessionManager.cs | 4 ++-- scratch-link-common/WebSocketListener.cs | 4 ++-- .../scratch-link-common.projitems | 4 ++-- scratch-link-win/App.xaml | 4 ++-- scratch-link-win/App.xaml.cs | 12 ++++++------ scratch-link-win/BLE/WinBLEEndpoint.cs | 8 ++++---- scratch-link-win/BLE/WinBLESession.cs | 6 +++--- scratch-link-win/BLE/WinGattHelpers.cs | 6 +++--- scratch-link-win/BT/WinBTSession.cs | 8 ++++---- .../Serial/WinSerialPortEnumerator.cs | 4 ++-- scratch-link-win/Serial/WinSerialPortInfo.cs | 2 +- scratch-link-win/Serial/WinSerialSession.cs | 6 +++--- scratch-link-win/TrayIcon.xaml | 4 ++-- scratch-link-win/WinSessionManager.cs | 8 ++++---- 36 files changed, 96 insertions(+), 96 deletions(-) rename scratch-link-common/{ScratchLinkApp.cs => AluxLabsLinkApp.cs} (91%) diff --git a/scratch-link-common/ScratchLinkApp.cs b/scratch-link-common/AluxLabsLinkApp.cs similarity index 91% rename from scratch-link-common/ScratchLinkApp.cs rename to scratch-link-common/AluxLabsLinkApp.cs index fa7077a1..dd8d5c8d 100644 --- a/scratch-link-common/ScratchLinkApp.cs +++ b/scratch-link-common/AluxLabsLinkApp.cs @@ -1,25 +1,25 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink; +namespace AluxLabs.Link; using System; using System.Diagnostics; using Microsoft.Extensions.DependencyInjection; -using ScratchLink.BLE; +using AluxLabs.Link.BLE; /// /// Main entry point for Scratch Link and central service provider for dependency injection. /// -public class ScratchLinkApp +public class AluxLabsLinkApp { private const int WebSocketPort = 20211; private readonly SessionManager sessionManager; private readonly WebSocketListener webSocketListener; - private ScratchLinkApp(IServiceProvider platformServicesProvider) + private AluxLabsLinkApp(IServiceProvider platformServicesProvider) { Debug.AutoFlush = Trace.AutoFlush = true; @@ -41,7 +41,7 @@ private ScratchLinkApp(IServiceProvider platformServicesProvider) /// /// Gets the current app instance. /// - public static ScratchLinkApp Current { get; private set; } + public static AluxLabsLinkApp Current { get; private set; } /// /// Gets the platform-specific services provider. @@ -113,7 +113,7 @@ internal void SetGattHelpers() /// Builds a Scratch Link app host. /// /// A new Scratch Link app host. - internal ScratchLinkApp Build() + internal AluxLabsLinkApp Build() { var serviceCollection = new ServiceCollection(); var serviceProviderOptions = new ServiceProviderOptions { ValidateOnBuild = true, ValidateScopes = true }; @@ -122,7 +122,7 @@ internal ScratchLinkApp Build() .AddSingleton(typeof(SessionManager), this.sessionManagerType) .AddSingleton(this.gattHelpersBaseType, this.gattHelpersType) .BuildServiceProvider(); - return new ScratchLinkApp(servicesProvider); + return new AluxLabsLinkApp(servicesProvider); } } } diff --git a/scratch-link-common/BLE/BLESession.cs b/scratch-link-common/BLE/BLESession.cs index 37ea82cd..7b45c1c4 100644 --- a/scratch-link-common/BLE/BLESession.cs +++ b/scratch-link-common/BLE/BLESession.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.BLE; +namespace AluxLabs.Link.BLE; using System; using System.Collections.Generic; @@ -12,8 +12,8 @@ namespace ScratchLink.BLE; using System.Threading.Tasks; using Fleck; using Microsoft.Extensions.DependencyInjection; -using ScratchLink.Extensions; -using ScratchLink.JsonRpc; +using AluxLabs.Link.Extensions; +using AluxLabs.Link.JsonRpc; /// /// Implements the cross-platform portions of a BLE session. @@ -32,7 +32,7 @@ internal abstract class BLESession>(); + this.GattHelpers = AluxLabsLinkApp.Current.Services.GetService>(); this.AllowedServices = new (); this.Handlers["discover"] = this.HandleDiscover; this.Handlers["write"] = this.HandleWrite; diff --git a/scratch-link-common/BLE/GattHelpers.cs b/scratch-link-common/BLE/GattHelpers.cs index 9d58213c..576d8287 100644 --- a/scratch-link-common/BLE/GattHelpers.cs +++ b/scratch-link-common/BLE/GattHelpers.cs @@ -1,15 +1,15 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.BLE; +namespace AluxLabs.Link.BLE; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text.Json; using System.Text.RegularExpressions; -using ScratchLink.JsonRpc; +using AluxLabs.Link.JsonRpc; /// /// Helper methods to deal with GATT names and UUID values. diff --git a/scratch-link-common/BLE/IBLEEndpoint.cs b/scratch-link-common/BLE/IBLEEndpoint.cs index 53203797..1feea6a3 100644 --- a/scratch-link-common/BLE/IBLEEndpoint.cs +++ b/scratch-link-common/BLE/IBLEEndpoint.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.BLE; +namespace AluxLabs.Link.BLE; using System; using System.Threading.Tasks; diff --git a/scratch-link-common/BT/BTSession.cs b/scratch-link-common/BT/BTSession.cs index c97f07cf..2e1e19f4 100644 --- a/scratch-link-common/BT/BTSession.cs +++ b/scratch-link-common/BT/BTSession.cs @@ -1,16 +1,16 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.BT; +namespace AluxLabs.Link.BT; using System.Diagnostics; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; using Fleck; -using ScratchLink.Extensions; -using ScratchLink.JsonRpc; +using AluxLabs.Link.Extensions; +using AluxLabs.Link.JsonRpc; /// /// Implements the cross-platform portions of a Bluetooth Classic (RFCOMM) session. diff --git a/scratch-link-common/EncodingHelpers.cs b/scratch-link-common/EncodingHelpers.cs index 399095da..a0539fc2 100644 --- a/scratch-link-common/EncodingHelpers.cs +++ b/scratch-link-common/EncodingHelpers.cs @@ -2,13 +2,13 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink; +namespace AluxLabs.Link; using System; using System.Text; using System.Text.Json; -using ScratchLink.Extensions; -using ScratchLink.JsonRpc; +using AluxLabs.Link.Extensions; +using AluxLabs.Link.JsonRpc; /// /// Helpers for interacting with Scratch Link's message buffers. diff --git a/scratch-link-common/EventAwaiter.cs b/scratch-link-common/EventAwaiter.cs index e03c4751..9fb8d4c2 100644 --- a/scratch-link-common/EventAwaiter.cs +++ b/scratch-link-common/EventAwaiter.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink; +namespace AluxLabs.Link; using System; using System.Diagnostics; diff --git a/scratch-link-common/Extensions/ContainerExtensions.cs b/scratch-link-common/Extensions/ContainerExtensions.cs index 8d2a2fbb..29fb15f2 100644 --- a/scratch-link-common/Extensions/ContainerExtensions.cs +++ b/scratch-link-common/Extensions/ContainerExtensions.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Extensions; +namespace AluxLabs.Link.Extensions; using System.Collections.Generic; using System.Linq; diff --git a/scratch-link-common/Extensions/JsonExtensions.cs b/scratch-link-common/Extensions/JsonExtensions.cs index 54a34adc..f22f4ced 100644 --- a/scratch-link-common/Extensions/JsonExtensions.cs +++ b/scratch-link-common/Extensions/JsonExtensions.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Extensions; +namespace AluxLabs.Link.Extensions; using System.Text.Json; diff --git a/scratch-link-common/Extensions/SemaphoreSlimExtensions.cs b/scratch-link-common/Extensions/SemaphoreSlimExtensions.cs index 8744fdbe..58246c5e 100644 --- a/scratch-link-common/Extensions/SemaphoreSlimExtensions.cs +++ b/scratch-link-common/Extensions/SemaphoreSlimExtensions.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Extensions; +namespace AluxLabs.Link.Extensions; using System; using System.Threading; diff --git a/scratch-link-common/JsonRpc/Converters/JsonRpc2MessageConverter.cs b/scratch-link-common/JsonRpc/Converters/JsonRpc2MessageConverter.cs index e819a35f..e7e839e1 100644 --- a/scratch-link-common/JsonRpc/Converters/JsonRpc2MessageConverter.cs +++ b/scratch-link-common/JsonRpc/Converters/JsonRpc2MessageConverter.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.JsonRpc.Converters; +namespace AluxLabs.Link.JsonRpc.Converters; using System; using System.Text.Json; diff --git a/scratch-link-common/JsonRpc/Converters/JsonRpc2ValueConverter.cs b/scratch-link-common/JsonRpc/Converters/JsonRpc2ValueConverter.cs index b4953485..afdfe22e 100644 --- a/scratch-link-common/JsonRpc/Converters/JsonRpc2ValueConverter.cs +++ b/scratch-link-common/JsonRpc/Converters/JsonRpc2ValueConverter.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.JsonRpc.Converters; +namespace AluxLabs.Link.JsonRpc.Converters; using System; using System.Text.Json; diff --git a/scratch-link-common/JsonRpc/JsonRpc2Error.cs b/scratch-link-common/JsonRpc/JsonRpc2Error.cs index 0a2fb524..d4938888 100644 --- a/scratch-link-common/JsonRpc/JsonRpc2Error.cs +++ b/scratch-link-common/JsonRpc/JsonRpc2Error.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.JsonRpc; +namespace AluxLabs.Link.JsonRpc; using System.Text.Json.Serialization; diff --git a/scratch-link-common/JsonRpc/JsonRpc2Exception.cs b/scratch-link-common/JsonRpc/JsonRpc2Exception.cs index 2a63cbc2..36184198 100644 --- a/scratch-link-common/JsonRpc/JsonRpc2Exception.cs +++ b/scratch-link-common/JsonRpc/JsonRpc2Exception.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.JsonRpc; +namespace AluxLabs.Link.JsonRpc; using System; diff --git a/scratch-link-common/JsonRpc/JsonRpc2Message.cs b/scratch-link-common/JsonRpc/JsonRpc2Message.cs index 35847148..9e7b243e 100644 --- a/scratch-link-common/JsonRpc/JsonRpc2Message.cs +++ b/scratch-link-common/JsonRpc/JsonRpc2Message.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.JsonRpc; +namespace AluxLabs.Link.JsonRpc; using System.Collections.Generic; using System.Text.Json.Serialization; diff --git a/scratch-link-common/JsonRpc/JsonRpc2Request.cs b/scratch-link-common/JsonRpc/JsonRpc2Request.cs index 09a14df2..62b37d2a 100644 --- a/scratch-link-common/JsonRpc/JsonRpc2Request.cs +++ b/scratch-link-common/JsonRpc/JsonRpc2Request.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.JsonRpc; +namespace AluxLabs.Link.JsonRpc; using System.Text.Json.Serialization; diff --git a/scratch-link-common/JsonRpc/JsonRpc2Response.cs b/scratch-link-common/JsonRpc/JsonRpc2Response.cs index 518a272c..785ab352 100644 --- a/scratch-link-common/JsonRpc/JsonRpc2Response.cs +++ b/scratch-link-common/JsonRpc/JsonRpc2Response.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.JsonRpc; +namespace AluxLabs.Link.JsonRpc; using System.Text.Json.Serialization; diff --git a/scratch-link-common/PeripheralSession.cs b/scratch-link-common/PeripheralSession.cs index bb0bae84..62304c21 100644 --- a/scratch-link-common/PeripheralSession.cs +++ b/scratch-link-common/PeripheralSession.cs @@ -2,15 +2,15 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink; +namespace AluxLabs.Link; using System; using System.Collections.Generic; using System.Text.Json; using System.Threading.Tasks; using Fleck; -using ScratchLink.Extensions; -using ScratchLink.JsonRpc; +using AluxLabs.Link.Extensions; +using AluxLabs.Link.JsonRpc; /// /// A kind of session which discovers and connects to peripheral devices by some sort of address. diff --git a/scratch-link-common/Serial/SerialDiscoveryFilter.cs b/scratch-link-common/Serial/SerialDiscoveryFilter.cs index 1e2efd37..38657cf0 100644 --- a/scratch-link-common/Serial/SerialDiscoveryFilter.cs +++ b/scratch-link-common/Serial/SerialDiscoveryFilter.cs @@ -3,7 +3,7 @@ // Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only. // -namespace ScratchLink.Serial; +namespace AluxLabs.Link.Serial; /// /// A single filter entry passed by the client in a serial "discover" request. diff --git a/scratch-link-common/Serial/SerialOpenParams.cs b/scratch-link-common/Serial/SerialOpenParams.cs index 53316356..eadde5d3 100644 --- a/scratch-link-common/Serial/SerialOpenParams.cs +++ b/scratch-link-common/Serial/SerialOpenParams.cs @@ -3,7 +3,7 @@ // Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only. // -namespace ScratchLink.Serial; +namespace AluxLabs.Link.Serial; /// /// Parameters extracted from a serial "connect" request. diff --git a/scratch-link-common/Serial/SerialSession.cs b/scratch-link-common/Serial/SerialSession.cs index be43c4f3..c872ec26 100644 --- a/scratch-link-common/Serial/SerialSession.cs +++ b/scratch-link-common/Serial/SerialSession.cs @@ -3,7 +3,7 @@ // Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only. // -namespace ScratchLink.Serial; +namespace AluxLabs.Link.Serial; using System; using System.Collections.Generic; @@ -13,8 +13,8 @@ namespace ScratchLink.Serial; using System.Threading; using System.Threading.Tasks; using Fleck; -using ScratchLink.Extensions; -using ScratchLink.JsonRpc; +using AluxLabs.Link.Extensions; +using AluxLabs.Link.JsonRpc; /// /// Cross-platform base for a USB Serial transport session. Uses Serial-specific diff --git a/scratch-link-common/Session.cs b/scratch-link-common/Session.cs index 3e305f19..807848a5 100644 --- a/scratch-link-common/Session.cs +++ b/scratch-link-common/Session.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink; +namespace AluxLabs.Link; using System; using System.Collections.Concurrent; @@ -12,9 +12,9 @@ namespace ScratchLink; using System.Threading; using System.Threading.Tasks; using Fleck; -using ScratchLink.Extensions; -using ScratchLink.JsonRpc; -using ScratchLink.JsonRpc.Converters; +using AluxLabs.Link.Extensions; +using AluxLabs.Link.JsonRpc; +using AluxLabs.Link.JsonRpc.Converters; using JsonRpcMethodHandler = System.Func< string, // method name diff --git a/scratch-link-common/SessionManager.cs b/scratch-link-common/SessionManager.cs index 2368288c..9619cb3d 100644 --- a/scratch-link-common/SessionManager.cs +++ b/scratch-link-common/SessionManager.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink; +namespace AluxLabs.Link; using System; using System.Collections.Concurrent; diff --git a/scratch-link-common/WebSocketListener.cs b/scratch-link-common/WebSocketListener.cs index b5988ec4..f392c1a4 100644 --- a/scratch-link-common/WebSocketListener.cs +++ b/scratch-link-common/WebSocketListener.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink; +namespace AluxLabs.Link; using System; using System.Threading; diff --git a/scratch-link-common/scratch-link-common.projitems b/scratch-link-common/scratch-link-common.projitems index 569953fd..4cbf917f 100644 --- a/scratch-link-common/scratch-link-common.projitems +++ b/scratch-link-common/scratch-link-common.projitems @@ -6,7 +6,7 @@ 06B5D2A3-AD0A-4704-B00D-BCFF634E7709 - ScratchLink + AluxLabs.Link @@ -27,7 +27,7 @@ - + diff --git a/scratch-link-win/App.xaml b/scratch-link-win/App.xaml index 27a0e9f0..7006f6f8 100644 --- a/scratch-link-win/App.xaml +++ b/scratch-link-win/App.xaml @@ -2,10 +2,10 @@ + xmlns:local="using:AluxLabs.Link.Win"> diff --git a/scratch-link-win/App.xaml.cs b/scratch-link-win/App.xaml.cs index 4e6af168..6461c8f6 100644 --- a/scratch-link-win/App.xaml.cs +++ b/scratch-link-win/App.xaml.cs @@ -2,14 +2,14 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Win; +namespace AluxLabs.Link.Win; using H.NotifyIcon; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Input; -using ScratchLink; -using ScratchLink.Win.BLE; +using AluxLabs.Link; +using AluxLabs.Link.Win.BLE; using System.Diagnostics; using System.Reflection; using Windows.ApplicationModel.DataTransfer; @@ -24,7 +24,7 @@ public partial class App : Application private readonly string versionQuad; private readonly string versionDetail; - private ScratchLinkApp app; + private AluxLabsLinkApp app; private TaskbarIcon trayIcon; /// @@ -54,7 +54,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs args) // Trace.Listeners.Add(??); Trace.WriteLine("Starting..."); - var appBuilder = new ScratchLinkApp.Builder(); + var appBuilder = new AluxLabsLinkApp.Builder(); appBuilder.SetArguments(Environment.GetCommandLineArgs()); appBuilder.SetSessionManager(); appBuilder.SetGattHelpers(); @@ -92,7 +92,7 @@ private void InitializeTrayIcon() var exitCommand = (XamlUICommand)this.Resources["ExitCommand"]; exitCommand.ExecuteRequested += this.ExitCommand_ExecuteRequested; - this.trayIcon = (TaskbarIcon)this.Resources["ScratchLinkTaskbarIcon"]; + this.trayIcon = (TaskbarIcon)this.Resources["AluxLabsLinkTaskbarIcon"]; // TODO: maybe we should enable efficiency mode when there are no connections? this.trayIcon.ForceCreate(enablesEfficiencyMode: false); diff --git a/scratch-link-win/BLE/WinBLEEndpoint.cs b/scratch-link-win/BLE/WinBLEEndpoint.cs index 82286f3e..e6ee86dc 100644 --- a/scratch-link-win/BLE/WinBLEEndpoint.cs +++ b/scratch-link-win/BLE/WinBLEEndpoint.cs @@ -1,11 +1,11 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Win.BLE; +namespace AluxLabs.Link.Win.BLE; -using ScratchLink.BLE; -using ScratchLink.JsonRpc; +using AluxLabs.Link.BLE; +using AluxLabs.Link.JsonRpc; using System; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; diff --git a/scratch-link-win/BLE/WinBLESession.cs b/scratch-link-win/BLE/WinBLESession.cs index 09e6c66f..07742075 100644 --- a/scratch-link-win/BLE/WinBLESession.cs +++ b/scratch-link-win/BLE/WinBLESession.cs @@ -2,11 +2,11 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Win.BLE; +namespace AluxLabs.Link.Win.BLE; using Fleck; -using ScratchLink.BLE; -using ScratchLink.JsonRpc; +using AluxLabs.Link.BLE; +using AluxLabs.Link.JsonRpc; using System; using System.Collections.Generic; using System.Runtime.InteropServices.WindowsRuntime; diff --git a/scratch-link-win/BLE/WinGattHelpers.cs b/scratch-link-win/BLE/WinGattHelpers.cs index 67b8bfba..074f481d 100644 --- a/scratch-link-win/BLE/WinGattHelpers.cs +++ b/scratch-link-win/BLE/WinGattHelpers.cs @@ -1,10 +1,10 @@ -// +// // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Win.BLE; +namespace AluxLabs.Link.Win.BLE; -using ScratchLink.BLE; +using AluxLabs.Link.BLE; /// /// Implement the Windows-specific GATT helpers. diff --git a/scratch-link-win/BT/WinBTSession.cs b/scratch-link-win/BT/WinBTSession.cs index 165aa5ca..4b8ac84e 100644 --- a/scratch-link-win/BT/WinBTSession.cs +++ b/scratch-link-win/BT/WinBTSession.cs @@ -2,12 +2,12 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Win.BT; +namespace AluxLabs.Link.Win.BT; using Fleck; -using ScratchLink.BT; -using ScratchLink.Extensions; -using ScratchLink.JsonRpc; +using AluxLabs.Link.BT; +using AluxLabs.Link.Extensions; +using AluxLabs.Link.JsonRpc; using System.Diagnostics; using Windows.Devices.Bluetooth; using Windows.Devices.Bluetooth.Rfcomm; diff --git a/scratch-link-win/Serial/WinSerialPortEnumerator.cs b/scratch-link-win/Serial/WinSerialPortEnumerator.cs index 4167521a..83d04c2d 100644 --- a/scratch-link-win/Serial/WinSerialPortEnumerator.cs +++ b/scratch-link-win/Serial/WinSerialPortEnumerator.cs @@ -3,7 +3,7 @@ // Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only. // -namespace ScratchLink.Win.Serial; +namespace AluxLabs.Link.Win.Serial; using System; using System.Collections.Generic; @@ -11,7 +11,7 @@ namespace ScratchLink.Win.Serial; using System.Globalization; using System.Management; using System.Text.RegularExpressions; -using ScratchLink.Serial; +using AluxLabs.Link.Serial; /// /// Enumerates USB serial ports on Windows via WMI (Win32_PnPEntity), extracting diff --git a/scratch-link-win/Serial/WinSerialPortInfo.cs b/scratch-link-win/Serial/WinSerialPortInfo.cs index b28f27d2..be8ce907 100644 --- a/scratch-link-win/Serial/WinSerialPortInfo.cs +++ b/scratch-link-win/Serial/WinSerialPortInfo.cs @@ -3,7 +3,7 @@ // Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only. // -namespace ScratchLink.Win.Serial; +namespace AluxLabs.Link.Win.Serial; /// /// A single port returned by . diff --git a/scratch-link-win/Serial/WinSerialSession.cs b/scratch-link-win/Serial/WinSerialSession.cs index 04244721..e11341ca 100644 --- a/scratch-link-win/Serial/WinSerialSession.cs +++ b/scratch-link-win/Serial/WinSerialSession.cs @@ -3,7 +3,7 @@ // Based on scratch-link by Scratch Foundation, licensed under AGPL-3.0-only. // -namespace ScratchLink.Win.Serial; +namespace AluxLabs.Link.Win.Serial; using System; using System.Collections.Generic; @@ -13,8 +13,8 @@ namespace ScratchLink.Win.Serial; using System.Threading; using System.Threading.Tasks; using Fleck; -using ScratchLink.JsonRpc; -using ScratchLink.Serial; +using AluxLabs.Link.JsonRpc; +using AluxLabs.Link.Serial; /// /// Implements a USB Serial session on Windows using diff --git a/scratch-link-win/TrayIcon.xaml b/scratch-link-win/TrayIcon.xaml index f1f8bcf1..2eca5e14 100644 --- a/scratch-link-win/TrayIcon.xaml +++ b/scratch-link-win/TrayIcon.xaml @@ -4,10 +4,10 @@ - -namespace ScratchLink.Win; +namespace AluxLabs.Link.Win; using Fleck; -using ScratchLink.Win.BLE; -using ScratchLink.Win.BT; -using ScratchLink.Win.Serial; +using AluxLabs.Link.Win.BLE; +using AluxLabs.Link.Win.BT; +using AluxLabs.Link.Win.Serial; /// /// Implements the Windows-specific functionality of the SessionManager. From 02d3cbd6d28c41b69912bcd304e8b3d9bab37ae0 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 May 2026 14:10:00 +0900 Subject: [PATCH 54/94] =?UTF-8?q?refactor(rebrand):=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=ED=8C=8C=EC=9D=BC=EB=AA=85=EC=9D=84=20aluxlabs-lin?= =?UTF-8?q?k*.ico=20=EB=A1=9C=20=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - scratch-link.ico → aluxlabs-link.ico (git mv) - scratch-link-tray.ico → aluxlabs-link-tray.ico (git mv) - scratch-link-win.csproj: ApplicationIcon, Content Include 갱신 - TrayIcon.xaml: IconSource 갱신 - brand/build_icons.py: docstring 및 ICO_TARGETS 키 갱신 - Makefile: WINDOWS_IMAGES 목록 및 svg2ico 호출 경로 갱신 dotnet build Debug_Win 성공 확인. Co-Authored-By: Claude Opus 4.7 (1M context) --- Makefile | 8 ++++---- brand/build_icons.py | 10 +++++----- scratch-link-win/TrayIcon.xaml | 2 +- ...scratch-link-tray.ico => aluxlabs-link-tray.ico} | Bin .../{scratch-link.ico => aluxlabs-link.ico} | Bin scratch-link-win/scratch-link-win.csproj | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) rename scratch-link-win/{scratch-link-tray.ico => aluxlabs-link-tray.ico} (100%) rename scratch-link-win/{scratch-link.ico => aluxlabs-link.ico} (100%) diff --git a/Makefile b/Makefile index 572ab6a3..63c6712d 100644 --- a/Makefile +++ b/Makefile @@ -45,8 +45,8 @@ MAC_IMAGES = \ Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-72.png WINDOWS_IMAGES = \ - scratch-link-win/scratch-link.ico \ - scratch-link-win/scratch-link-tray.ico \ + scratch-link-win/aluxlabs-link.ico \ + scratch-link-win/aluxlabs-link-tray.ico \ scratch-link-win-msix/Images/LockScreenLogo.scale-200.png \ scratch-link-win-msix/Images/SplashScreen.scale-200.png \ scratch-link-win-msix/Images/Square150x150Logo.scale-200.png \ @@ -124,8 +124,8 @@ $(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Exten # See also: # https://stackoverflow.com/q/3236115 # https://iconhandbook.co.uk/reference/chart/windows/ -$(eval $(call svg2ico,scratch-link-win/scratch-link.ico,Assets/square.svg,256 128 96 64 48 32 24 16)) -$(eval $(call svg2ico,scratch-link-win/scratch-link-tray.ico,Assets/simplified.svg,32 24 16)) +$(eval $(call svg2ico,scratch-link-win/aluxlabs-link.ico,Assets/square.svg,256 128 96 64 48 32 24 16)) +$(eval $(call svg2ico,scratch-link-win/aluxlabs-link-tray.ico,Assets/simplified.svg,32 24 16)) # Windows MSIX # TODO: does Microsoft really want DPI=72 for all of these? diff --git a/brand/build_icons.py b/brand/build_icons.py index 59081a85..e484d392 100644 --- a/brand/build_icons.py +++ b/brand/build_icons.py @@ -4,8 +4,8 @@ brand/labs-l.svg Outputs (overwrites in place; all paths relative to repo root): - scratch-link-win/scratch-link.ico app icon, 16..256 sizes - scratch-link-win/scratch-link-tray.ico tray icon, 16/24/32 + scratch-link-win/aluxlabs-link.ico app icon, 16..256 sizes + scratch-link-win/aluxlabs-link-tray.ico tray icon, 16/24/32 scratch-link-win-msix/Images/*.png MSIX tile/splash/store/lock assets How to run (from repo root): @@ -26,7 +26,7 @@ Editing the targets: To add or change output sizes, edit ICO_TARGETS / PNG_TARGETS below. - ICO sizes must match the slots the existing scratch-link*.ico files + ICO sizes must match the slots the existing aluxlabs-link*.ico files advertise; MSIX PNG dimensions are dictated by Windows (Square44x44Logo.scale-200 must be 88x88, etc.). """ @@ -47,8 +47,8 @@ MSIX = REPO / "scratch-link-win-msix" / "Images" ICO_TARGETS = { - WIN / "scratch-link.ico": [16, 24, 32, 48, 64, 96, 128, 256], - WIN / "scratch-link-tray.ico": [16, 24, 32], + WIN / "aluxlabs-link.ico": [16, 24, 32, 48, 64, 96, 128, 256], + WIN / "aluxlabs-link-tray.ico": [16, 24, 32], } PNG_TARGETS = { diff --git a/scratch-link-win/TrayIcon.xaml b/scratch-link-win/TrayIcon.xaml index 2eca5e14..2cfbab8b 100644 --- a/scratch-link-win/TrayIcon.xaml +++ b/scratch-link-win/TrayIcon.xaml @@ -11,7 +11,7 @@ Visibility="Visible" ToolTipText="AluxLabs Link" ContextMenuMode="SecondWindow" - IconSource="scratch-link-tray.ico" + IconSource="aluxlabs-link-tray.ico" tb:TaskbarIcon.ContextFlyout="{StaticResource ContextFlyout}" /> diff --git a/scratch-link-win/scratch-link-tray.ico b/scratch-link-win/aluxlabs-link-tray.ico similarity index 100% rename from scratch-link-win/scratch-link-tray.ico rename to scratch-link-win/aluxlabs-link-tray.ico diff --git a/scratch-link-win/scratch-link.ico b/scratch-link-win/aluxlabs-link.ico similarity index 100% rename from scratch-link-win/scratch-link.ico rename to scratch-link-win/aluxlabs-link.ico diff --git a/scratch-link-win/scratch-link-win.csproj b/scratch-link-win/scratch-link-win.csproj index 283747c5..7839f6c6 100644 --- a/scratch-link-win/scratch-link-win.csproj +++ b/scratch-link-win/scratch-link-win.csproj @@ -18,7 +18,7 @@ enable app.manifest AnyCPU - scratch-link.ico + aluxlabs-link.ico @@ -34,8 +34,8 @@ - - + + From ddb587edc9cfdd9463ed3f4b30aa817a9f8921f3 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 May 2026 14:13:58 +0900 Subject: [PATCH 55/94] =?UTF-8?q?refactor(rebrand):=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=20/=20=ED=94=84=EB=A1=9C=EC=A0=9D=ED=8A=B8=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20/=20=EC=86=94=EB=A3=A8=EC=85=98=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EB=AA=85=EC=9D=84=20aluxlabs-link-*=20=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 폴더: - scratch-link-common/ → aluxlabs-link-common/ - scratch-link-win/ → aluxlabs-link-win/ - scratch-link-win-msix/ → aluxlabs-link-win-msix/ 프로젝트 파일: - scratch-link-common.shproj → aluxlabs-link-common.shproj - scratch-link-common.projitems → aluxlabs-link-common.projitems - scratch-link-win.csproj → aluxlabs-link-win.csproj - scratch-link-win-msix.wapproj → aluxlabs-link-win-msix.wapproj 솔루션 파일: - scratch-link.sln → aluxlabs-link.sln Cross-reference 갱신: - .sln 의 프로젝트 entry 와 SharedMSBuildProjectFiles 경로 (ProjectGuid 유지) - .shproj 의 projitems Import 경로 - .csproj 의 projitems Import 경로 - .wapproj 의 EntryPointProjectUniqueName, ProjectReference 경로 - .github/actions/windows-build/action.yml 의 msbuild 경로, AppPackages 패턴, msixbundle 출력 파일명 ("AluxLabs Link ${VERSION}.msixbundle") scratch-link-mac (out of scope) 의 ..\scratch-link-common\... 참조는 유지 — 본 fork 에서 mac 빌드를 지원하지 않으므로 손대지 않음. dotnet build Debug_Win 성공 확인. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/actions/windows-build/action.yml | 12 ++++++------ .../AluxLabsLinkApp.cs | 0 .../BLE/BLESession.cs | 0 .../BLE/GattHelpers.cs | 0 .../BLE/IBLEEndpoint.cs | 0 .../BT/BTSession.cs | 0 .../EncodingHelpers.cs | 0 .../EventAwaiter.cs | 0 .../Extensions/ContainerExtensions.cs | 0 .../Extensions/JsonExtensions.cs | 0 .../Extensions/SemaphoreSlimExtensions.cs | 0 .../JsonRpc/Converters/JsonRpc2MessageConverter.cs | 0 .../JsonRpc/Converters/JsonRpc2ValueConverter.cs | 0 .../JsonRpc/JsonRpc2Error.cs | 0 .../JsonRpc/JsonRpc2Exception.cs | 0 .../JsonRpc/JsonRpc2Message.cs | 0 .../JsonRpc/JsonRpc2Request.cs | 0 .../JsonRpc/JsonRpc2Response.cs | 0 .../PeripheralSession.cs | 0 .../Serial/SerialDiscoveryFilter.cs | 0 .../Serial/SerialOpenParams.cs | 0 .../Serial/SerialSession.cs | 0 .../Session.cs | 0 .../SessionManager.cs | 0 .../WebSocketListener.cs | 0 .../aluxlabs-link-common.projitems | 0 .../aluxlabs-link-common.shproj | 2 +- .../.gitignore | 0 .../Images/LockScreenLogo.scale-200.png | Bin .../Images/SplashScreen.scale-200.png | Bin .../Images/Square150x150Logo.scale-200.png | Bin .../Images/Square44x44Logo.scale-200.png | Bin ...uare44x44Logo.targetsize-24_altform-unplated.png | Bin .../Images/StoreLogo.png | Bin .../Images/Wide310x150Logo.scale-200.png | Bin .../Package.appxmanifest | 0 .../aluxlabs-link-win-msix.wapproj | 4 ++-- {scratch-link-win => aluxlabs-link-win}/App.xaml | 0 {scratch-link-win => aluxlabs-link-win}/App.xaml.cs | 0 .../BLE/WinBLEEndpoint.cs | 0 .../BLE/WinBLESession.cs | 0 .../BLE/WinGattHelpers.cs | 0 .../BT/WinBTSession.cs | 0 .../Properties/PublishProfiles/win-arm64.pubxml | 0 .../Properties/PublishProfiles/win-x64.pubxml | 0 .../Properties/PublishProfiles/win-x86.pubxml | 0 .../Serial/WinSerialPortEnumerator.cs | 0 .../Serial/WinSerialPortInfo.cs | 0 .../Serial/WinSerialSession.cs | 0 .../TrayIcon.xaml | 0 .../WinSessionManager.cs | 0 .../aluxlabs-link-tray.ico | Bin .../aluxlabs-link-win.csproj | 2 +- .../aluxlabs-link.ico | Bin .../app.manifest | 0 scratch-link.sln => aluxlabs-link.sln | 12 ++++++------ 56 files changed, 16 insertions(+), 16 deletions(-) rename {scratch-link-common => aluxlabs-link-common}/AluxLabsLinkApp.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/BLE/BLESession.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/BLE/GattHelpers.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/BLE/IBLEEndpoint.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/BT/BTSession.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/EncodingHelpers.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/EventAwaiter.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/Extensions/ContainerExtensions.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/Extensions/JsonExtensions.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/Extensions/SemaphoreSlimExtensions.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/JsonRpc/Converters/JsonRpc2MessageConverter.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/JsonRpc/Converters/JsonRpc2ValueConverter.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/JsonRpc/JsonRpc2Error.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/JsonRpc/JsonRpc2Exception.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/JsonRpc/JsonRpc2Message.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/JsonRpc/JsonRpc2Request.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/JsonRpc/JsonRpc2Response.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/PeripheralSession.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/Serial/SerialDiscoveryFilter.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/Serial/SerialOpenParams.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/Serial/SerialSession.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/Session.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/SessionManager.cs (100%) rename {scratch-link-common => aluxlabs-link-common}/WebSocketListener.cs (100%) rename scratch-link-common/scratch-link-common.projitems => aluxlabs-link-common/aluxlabs-link-common.projitems (100%) rename scratch-link-common/scratch-link-common.shproj => aluxlabs-link-common/aluxlabs-link-common.shproj (93%) rename {scratch-link-win-msix => aluxlabs-link-win-msix}/.gitignore (100%) rename {scratch-link-win-msix => aluxlabs-link-win-msix}/Images/LockScreenLogo.scale-200.png (100%) rename {scratch-link-win-msix => aluxlabs-link-win-msix}/Images/SplashScreen.scale-200.png (100%) rename {scratch-link-win-msix => aluxlabs-link-win-msix}/Images/Square150x150Logo.scale-200.png (100%) rename {scratch-link-win-msix => aluxlabs-link-win-msix}/Images/Square44x44Logo.scale-200.png (100%) rename {scratch-link-win-msix => aluxlabs-link-win-msix}/Images/Square44x44Logo.targetsize-24_altform-unplated.png (100%) rename {scratch-link-win-msix => aluxlabs-link-win-msix}/Images/StoreLogo.png (100%) rename {scratch-link-win-msix => aluxlabs-link-win-msix}/Images/Wide310x150Logo.scale-200.png (100%) rename {scratch-link-win-msix => aluxlabs-link-win-msix}/Package.appxmanifest (100%) rename scratch-link-win-msix/scratch-link-win-msix.wapproj => aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj (97%) rename {scratch-link-win => aluxlabs-link-win}/App.xaml (100%) rename {scratch-link-win => aluxlabs-link-win}/App.xaml.cs (100%) rename {scratch-link-win => aluxlabs-link-win}/BLE/WinBLEEndpoint.cs (100%) rename {scratch-link-win => aluxlabs-link-win}/BLE/WinBLESession.cs (100%) rename {scratch-link-win => aluxlabs-link-win}/BLE/WinGattHelpers.cs (100%) rename {scratch-link-win => aluxlabs-link-win}/BT/WinBTSession.cs (100%) rename {scratch-link-win => aluxlabs-link-win}/Properties/PublishProfiles/win-arm64.pubxml (100%) rename {scratch-link-win => aluxlabs-link-win}/Properties/PublishProfiles/win-x64.pubxml (100%) rename {scratch-link-win => aluxlabs-link-win}/Properties/PublishProfiles/win-x86.pubxml (100%) rename {scratch-link-win => aluxlabs-link-win}/Serial/WinSerialPortEnumerator.cs (100%) rename {scratch-link-win => aluxlabs-link-win}/Serial/WinSerialPortInfo.cs (100%) rename {scratch-link-win => aluxlabs-link-win}/Serial/WinSerialSession.cs (100%) rename {scratch-link-win => aluxlabs-link-win}/TrayIcon.xaml (100%) rename {scratch-link-win => aluxlabs-link-win}/WinSessionManager.cs (100%) rename {scratch-link-win => aluxlabs-link-win}/aluxlabs-link-tray.ico (100%) rename scratch-link-win/scratch-link-win.csproj => aluxlabs-link-win/aluxlabs-link-win.csproj (93%) rename {scratch-link-win => aluxlabs-link-win}/aluxlabs-link.ico (100%) rename {scratch-link-win => aluxlabs-link-win}/app.manifest (100%) rename scratch-link.sln => aluxlabs-link.sln (94%) diff --git a/.github/actions/windows-build/action.yml b/.github/actions/windows-build/action.yml index a00fc4b9..e4ae0a7c 100644 --- a/.github/actions/windows-build/action.yml +++ b/.github/actions/windows-build/action.yml @@ -19,25 +19,25 @@ runs: # That means SolutionDir needs to be set artificially, though. # The `UapAppxPackageBuildMode=StoreAndSideload` means it'll build both MSIXUpload and MSIXBundle. # The StoreUpload mode does that too, but that might be a bug, and semantically "StoreAndSideload" is what we want. - msbuild scratch-link-win-msix/scratch-link-win-msix.wapproj -maxCpuCount -restore -t:Build -p:SolutionDir="$PWD\" -p:Configuration="${{ inputs.configuration }}_Win" -p:AppxBundlePlatforms="x86|x64|ARM64" -p:AppxBundle=Always -p:UapAppxPackageBuildMode=StoreAndSideload + msbuild aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj -maxCpuCount -restore -t:Build -p:SolutionDir="$PWD\" -p:Configuration="${{ inputs.configuration }}_Win" -p:AppxBundlePlatforms="x86|x64|ARM64" -p:AppxBundle=Always -p:UapAppxPackageBuildMode=StoreAndSideload - name: "Move Windows artifacts into place: ${{ inputs.configuration }}" shell: bash run: | mkdir -p Artifacts # The store package is fine as is: no user will see this filename. - mv -v scratch-link-win-msix/AppPackages/scratch-link-win-msix_*_${{ inputs.configuration }}_Win.msixupload Artifacts/ + mv -v aluxlabs-link-win-msix/AppPackages/aluxlabs-link-win-msix_*_${{ inputs.configuration }}_Win.msixupload Artifacts/ # Transform the bundle for a more user-friendly filename - for PKGPATH in scratch-link-win-msix/AppPackages/scratch-link-win-msix_*_${{ inputs.configuration }}_Win_Test/scratch-link-win-msix_*_${{ inputs.configuration }}_Win.msixbundle; do + for PKGPATH in aluxlabs-link-win-msix/AppPackages/aluxlabs-link-win-msix_*_${{ inputs.configuration }}_Win_Test/aluxlabs-link-win-msix_*_${{ inputs.configuration }}_Win.msixbundle; do if [ -r "$PKGPATH" ]; then PKGFILE="${PKGPATH##*/}" - [[ $PKGFILE =~ scratch-link-win-msix_([.0-9]+)_(.*)_${{ inputs.configuration }}_Win.msixbundle$ ]] + [[ $PKGFILE =~ aluxlabs-link-win-msix_([.0-9]+)_(.*)_${{ inputs.configuration }}_Win.msixbundle$ ]] PKGVERSION=${BASH_REMATCH[1]} PKGPLATFORMS=${BASH_REMATCH[2]} fi # do the move outside the "if" above to force an error if the file doesn't exist if [ -z "${{ inputs.artifact_tag }}" ]; then - mv -v "$PKGPATH" "Artifacts/Scratch Link ${PKGVERSION}.msixbundle" + mv -v "$PKGPATH" "Artifacts/AluxLabs Link ${PKGVERSION}.msixbundle" else - mv -v "$PKGPATH" "Artifacts/Scratch Link ${PKGVERSION} ${{ inputs.artifact_tag }}.msixbundle" + mv -v "$PKGPATH" "Artifacts/AluxLabs Link ${PKGVERSION} ${{ inputs.artifact_tag }}.msixbundle" fi done diff --git a/scratch-link-common/AluxLabsLinkApp.cs b/aluxlabs-link-common/AluxLabsLinkApp.cs similarity index 100% rename from scratch-link-common/AluxLabsLinkApp.cs rename to aluxlabs-link-common/AluxLabsLinkApp.cs diff --git a/scratch-link-common/BLE/BLESession.cs b/aluxlabs-link-common/BLE/BLESession.cs similarity index 100% rename from scratch-link-common/BLE/BLESession.cs rename to aluxlabs-link-common/BLE/BLESession.cs diff --git a/scratch-link-common/BLE/GattHelpers.cs b/aluxlabs-link-common/BLE/GattHelpers.cs similarity index 100% rename from scratch-link-common/BLE/GattHelpers.cs rename to aluxlabs-link-common/BLE/GattHelpers.cs diff --git a/scratch-link-common/BLE/IBLEEndpoint.cs b/aluxlabs-link-common/BLE/IBLEEndpoint.cs similarity index 100% rename from scratch-link-common/BLE/IBLEEndpoint.cs rename to aluxlabs-link-common/BLE/IBLEEndpoint.cs diff --git a/scratch-link-common/BT/BTSession.cs b/aluxlabs-link-common/BT/BTSession.cs similarity index 100% rename from scratch-link-common/BT/BTSession.cs rename to aluxlabs-link-common/BT/BTSession.cs diff --git a/scratch-link-common/EncodingHelpers.cs b/aluxlabs-link-common/EncodingHelpers.cs similarity index 100% rename from scratch-link-common/EncodingHelpers.cs rename to aluxlabs-link-common/EncodingHelpers.cs diff --git a/scratch-link-common/EventAwaiter.cs b/aluxlabs-link-common/EventAwaiter.cs similarity index 100% rename from scratch-link-common/EventAwaiter.cs rename to aluxlabs-link-common/EventAwaiter.cs diff --git a/scratch-link-common/Extensions/ContainerExtensions.cs b/aluxlabs-link-common/Extensions/ContainerExtensions.cs similarity index 100% rename from scratch-link-common/Extensions/ContainerExtensions.cs rename to aluxlabs-link-common/Extensions/ContainerExtensions.cs diff --git a/scratch-link-common/Extensions/JsonExtensions.cs b/aluxlabs-link-common/Extensions/JsonExtensions.cs similarity index 100% rename from scratch-link-common/Extensions/JsonExtensions.cs rename to aluxlabs-link-common/Extensions/JsonExtensions.cs diff --git a/scratch-link-common/Extensions/SemaphoreSlimExtensions.cs b/aluxlabs-link-common/Extensions/SemaphoreSlimExtensions.cs similarity index 100% rename from scratch-link-common/Extensions/SemaphoreSlimExtensions.cs rename to aluxlabs-link-common/Extensions/SemaphoreSlimExtensions.cs diff --git a/scratch-link-common/JsonRpc/Converters/JsonRpc2MessageConverter.cs b/aluxlabs-link-common/JsonRpc/Converters/JsonRpc2MessageConverter.cs similarity index 100% rename from scratch-link-common/JsonRpc/Converters/JsonRpc2MessageConverter.cs rename to aluxlabs-link-common/JsonRpc/Converters/JsonRpc2MessageConverter.cs diff --git a/scratch-link-common/JsonRpc/Converters/JsonRpc2ValueConverter.cs b/aluxlabs-link-common/JsonRpc/Converters/JsonRpc2ValueConverter.cs similarity index 100% rename from scratch-link-common/JsonRpc/Converters/JsonRpc2ValueConverter.cs rename to aluxlabs-link-common/JsonRpc/Converters/JsonRpc2ValueConverter.cs diff --git a/scratch-link-common/JsonRpc/JsonRpc2Error.cs b/aluxlabs-link-common/JsonRpc/JsonRpc2Error.cs similarity index 100% rename from scratch-link-common/JsonRpc/JsonRpc2Error.cs rename to aluxlabs-link-common/JsonRpc/JsonRpc2Error.cs diff --git a/scratch-link-common/JsonRpc/JsonRpc2Exception.cs b/aluxlabs-link-common/JsonRpc/JsonRpc2Exception.cs similarity index 100% rename from scratch-link-common/JsonRpc/JsonRpc2Exception.cs rename to aluxlabs-link-common/JsonRpc/JsonRpc2Exception.cs diff --git a/scratch-link-common/JsonRpc/JsonRpc2Message.cs b/aluxlabs-link-common/JsonRpc/JsonRpc2Message.cs similarity index 100% rename from scratch-link-common/JsonRpc/JsonRpc2Message.cs rename to aluxlabs-link-common/JsonRpc/JsonRpc2Message.cs diff --git a/scratch-link-common/JsonRpc/JsonRpc2Request.cs b/aluxlabs-link-common/JsonRpc/JsonRpc2Request.cs similarity index 100% rename from scratch-link-common/JsonRpc/JsonRpc2Request.cs rename to aluxlabs-link-common/JsonRpc/JsonRpc2Request.cs diff --git a/scratch-link-common/JsonRpc/JsonRpc2Response.cs b/aluxlabs-link-common/JsonRpc/JsonRpc2Response.cs similarity index 100% rename from scratch-link-common/JsonRpc/JsonRpc2Response.cs rename to aluxlabs-link-common/JsonRpc/JsonRpc2Response.cs diff --git a/scratch-link-common/PeripheralSession.cs b/aluxlabs-link-common/PeripheralSession.cs similarity index 100% rename from scratch-link-common/PeripheralSession.cs rename to aluxlabs-link-common/PeripheralSession.cs diff --git a/scratch-link-common/Serial/SerialDiscoveryFilter.cs b/aluxlabs-link-common/Serial/SerialDiscoveryFilter.cs similarity index 100% rename from scratch-link-common/Serial/SerialDiscoveryFilter.cs rename to aluxlabs-link-common/Serial/SerialDiscoveryFilter.cs diff --git a/scratch-link-common/Serial/SerialOpenParams.cs b/aluxlabs-link-common/Serial/SerialOpenParams.cs similarity index 100% rename from scratch-link-common/Serial/SerialOpenParams.cs rename to aluxlabs-link-common/Serial/SerialOpenParams.cs diff --git a/scratch-link-common/Serial/SerialSession.cs b/aluxlabs-link-common/Serial/SerialSession.cs similarity index 100% rename from scratch-link-common/Serial/SerialSession.cs rename to aluxlabs-link-common/Serial/SerialSession.cs diff --git a/scratch-link-common/Session.cs b/aluxlabs-link-common/Session.cs similarity index 100% rename from scratch-link-common/Session.cs rename to aluxlabs-link-common/Session.cs diff --git a/scratch-link-common/SessionManager.cs b/aluxlabs-link-common/SessionManager.cs similarity index 100% rename from scratch-link-common/SessionManager.cs rename to aluxlabs-link-common/SessionManager.cs diff --git a/scratch-link-common/WebSocketListener.cs b/aluxlabs-link-common/WebSocketListener.cs similarity index 100% rename from scratch-link-common/WebSocketListener.cs rename to aluxlabs-link-common/WebSocketListener.cs diff --git a/scratch-link-common/scratch-link-common.projitems b/aluxlabs-link-common/aluxlabs-link-common.projitems similarity index 100% rename from scratch-link-common/scratch-link-common.projitems rename to aluxlabs-link-common/aluxlabs-link-common.projitems diff --git a/scratch-link-common/scratch-link-common.shproj b/aluxlabs-link-common/aluxlabs-link-common.shproj similarity index 93% rename from scratch-link-common/scratch-link-common.shproj rename to aluxlabs-link-common/aluxlabs-link-common.shproj index c9150c9b..c5c6afc3 100644 --- a/scratch-link-common/scratch-link-common.shproj +++ b/aluxlabs-link-common/aluxlabs-link-common.shproj @@ -6,7 +6,7 @@ - + diff --git a/scratch-link-win-msix/.gitignore b/aluxlabs-link-win-msix/.gitignore similarity index 100% rename from scratch-link-win-msix/.gitignore rename to aluxlabs-link-win-msix/.gitignore diff --git a/scratch-link-win-msix/Images/LockScreenLogo.scale-200.png b/aluxlabs-link-win-msix/Images/LockScreenLogo.scale-200.png similarity index 100% rename from scratch-link-win-msix/Images/LockScreenLogo.scale-200.png rename to aluxlabs-link-win-msix/Images/LockScreenLogo.scale-200.png diff --git a/scratch-link-win-msix/Images/SplashScreen.scale-200.png b/aluxlabs-link-win-msix/Images/SplashScreen.scale-200.png similarity index 100% rename from scratch-link-win-msix/Images/SplashScreen.scale-200.png rename to aluxlabs-link-win-msix/Images/SplashScreen.scale-200.png diff --git a/scratch-link-win-msix/Images/Square150x150Logo.scale-200.png b/aluxlabs-link-win-msix/Images/Square150x150Logo.scale-200.png similarity index 100% rename from scratch-link-win-msix/Images/Square150x150Logo.scale-200.png rename to aluxlabs-link-win-msix/Images/Square150x150Logo.scale-200.png diff --git a/scratch-link-win-msix/Images/Square44x44Logo.scale-200.png b/aluxlabs-link-win-msix/Images/Square44x44Logo.scale-200.png similarity index 100% rename from scratch-link-win-msix/Images/Square44x44Logo.scale-200.png rename to aluxlabs-link-win-msix/Images/Square44x44Logo.scale-200.png diff --git a/scratch-link-win-msix/Images/Square44x44Logo.targetsize-24_altform-unplated.png b/aluxlabs-link-win-msix/Images/Square44x44Logo.targetsize-24_altform-unplated.png similarity index 100% rename from scratch-link-win-msix/Images/Square44x44Logo.targetsize-24_altform-unplated.png rename to aluxlabs-link-win-msix/Images/Square44x44Logo.targetsize-24_altform-unplated.png diff --git a/scratch-link-win-msix/Images/StoreLogo.png b/aluxlabs-link-win-msix/Images/StoreLogo.png similarity index 100% rename from scratch-link-win-msix/Images/StoreLogo.png rename to aluxlabs-link-win-msix/Images/StoreLogo.png diff --git a/scratch-link-win-msix/Images/Wide310x150Logo.scale-200.png b/aluxlabs-link-win-msix/Images/Wide310x150Logo.scale-200.png similarity index 100% rename from scratch-link-win-msix/Images/Wide310x150Logo.scale-200.png rename to aluxlabs-link-win-msix/Images/Wide310x150Logo.scale-200.png diff --git a/scratch-link-win-msix/Package.appxmanifest b/aluxlabs-link-win-msix/Package.appxmanifest similarity index 100% rename from scratch-link-win-msix/Package.appxmanifest rename to aluxlabs-link-win-msix/Package.appxmanifest diff --git a/scratch-link-win-msix/scratch-link-win-msix.wapproj b/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj similarity index 97% rename from scratch-link-win-msix/scratch-link-win-msix.wapproj rename to aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj index 1cea3e77..b7bc25d0 100644 --- a/scratch-link-win-msix/scratch-link-win-msix.wapproj +++ b/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj @@ -48,7 +48,7 @@ net8.0-windows$(TargetPlatformVersion);$(AssetTargetFallback) en-US false - ..\scratch-link-win\scratch-link-win.csproj + ..\aluxlabs-link-win\aluxlabs-link-win.csproj True False False @@ -96,7 +96,7 @@ - + True Properties\PublishProfiles\win-$(Platform).pubxml diff --git a/scratch-link-win/App.xaml b/aluxlabs-link-win/App.xaml similarity index 100% rename from scratch-link-win/App.xaml rename to aluxlabs-link-win/App.xaml diff --git a/scratch-link-win/App.xaml.cs b/aluxlabs-link-win/App.xaml.cs similarity index 100% rename from scratch-link-win/App.xaml.cs rename to aluxlabs-link-win/App.xaml.cs diff --git a/scratch-link-win/BLE/WinBLEEndpoint.cs b/aluxlabs-link-win/BLE/WinBLEEndpoint.cs similarity index 100% rename from scratch-link-win/BLE/WinBLEEndpoint.cs rename to aluxlabs-link-win/BLE/WinBLEEndpoint.cs diff --git a/scratch-link-win/BLE/WinBLESession.cs b/aluxlabs-link-win/BLE/WinBLESession.cs similarity index 100% rename from scratch-link-win/BLE/WinBLESession.cs rename to aluxlabs-link-win/BLE/WinBLESession.cs diff --git a/scratch-link-win/BLE/WinGattHelpers.cs b/aluxlabs-link-win/BLE/WinGattHelpers.cs similarity index 100% rename from scratch-link-win/BLE/WinGattHelpers.cs rename to aluxlabs-link-win/BLE/WinGattHelpers.cs diff --git a/scratch-link-win/BT/WinBTSession.cs b/aluxlabs-link-win/BT/WinBTSession.cs similarity index 100% rename from scratch-link-win/BT/WinBTSession.cs rename to aluxlabs-link-win/BT/WinBTSession.cs diff --git a/scratch-link-win/Properties/PublishProfiles/win-arm64.pubxml b/aluxlabs-link-win/Properties/PublishProfiles/win-arm64.pubxml similarity index 100% rename from scratch-link-win/Properties/PublishProfiles/win-arm64.pubxml rename to aluxlabs-link-win/Properties/PublishProfiles/win-arm64.pubxml diff --git a/scratch-link-win/Properties/PublishProfiles/win-x64.pubxml b/aluxlabs-link-win/Properties/PublishProfiles/win-x64.pubxml similarity index 100% rename from scratch-link-win/Properties/PublishProfiles/win-x64.pubxml rename to aluxlabs-link-win/Properties/PublishProfiles/win-x64.pubxml diff --git a/scratch-link-win/Properties/PublishProfiles/win-x86.pubxml b/aluxlabs-link-win/Properties/PublishProfiles/win-x86.pubxml similarity index 100% rename from scratch-link-win/Properties/PublishProfiles/win-x86.pubxml rename to aluxlabs-link-win/Properties/PublishProfiles/win-x86.pubxml diff --git a/scratch-link-win/Serial/WinSerialPortEnumerator.cs b/aluxlabs-link-win/Serial/WinSerialPortEnumerator.cs similarity index 100% rename from scratch-link-win/Serial/WinSerialPortEnumerator.cs rename to aluxlabs-link-win/Serial/WinSerialPortEnumerator.cs diff --git a/scratch-link-win/Serial/WinSerialPortInfo.cs b/aluxlabs-link-win/Serial/WinSerialPortInfo.cs similarity index 100% rename from scratch-link-win/Serial/WinSerialPortInfo.cs rename to aluxlabs-link-win/Serial/WinSerialPortInfo.cs diff --git a/scratch-link-win/Serial/WinSerialSession.cs b/aluxlabs-link-win/Serial/WinSerialSession.cs similarity index 100% rename from scratch-link-win/Serial/WinSerialSession.cs rename to aluxlabs-link-win/Serial/WinSerialSession.cs diff --git a/scratch-link-win/TrayIcon.xaml b/aluxlabs-link-win/TrayIcon.xaml similarity index 100% rename from scratch-link-win/TrayIcon.xaml rename to aluxlabs-link-win/TrayIcon.xaml diff --git a/scratch-link-win/WinSessionManager.cs b/aluxlabs-link-win/WinSessionManager.cs similarity index 100% rename from scratch-link-win/WinSessionManager.cs rename to aluxlabs-link-win/WinSessionManager.cs diff --git a/scratch-link-win/aluxlabs-link-tray.ico b/aluxlabs-link-win/aluxlabs-link-tray.ico similarity index 100% rename from scratch-link-win/aluxlabs-link-tray.ico rename to aluxlabs-link-win/aluxlabs-link-tray.ico diff --git a/scratch-link-win/scratch-link-win.csproj b/aluxlabs-link-win/aluxlabs-link-win.csproj similarity index 93% rename from scratch-link-win/scratch-link-win.csproj rename to aluxlabs-link-win/aluxlabs-link-win.csproj index 7839f6c6..9bb13a65 100644 --- a/scratch-link-win/scratch-link-win.csproj +++ b/aluxlabs-link-win/aluxlabs-link-win.csproj @@ -20,7 +20,7 @@ AnyCPU aluxlabs-link.ico - + diff --git a/scratch-link-win/aluxlabs-link.ico b/aluxlabs-link-win/aluxlabs-link.ico similarity index 100% rename from scratch-link-win/aluxlabs-link.ico rename to aluxlabs-link-win/aluxlabs-link.ico diff --git a/scratch-link-win/app.manifest b/aluxlabs-link-win/app.manifest similarity index 100% rename from scratch-link-win/app.manifest rename to aluxlabs-link-win/app.manifest diff --git a/scratch-link.sln b/aluxlabs-link.sln similarity index 94% rename from scratch-link.sln rename to aluxlabs-link.sln index c252bf97..bd29fcc0 100644 --- a/scratch-link.sln +++ b/aluxlabs-link.sln @@ -30,7 +30,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution TRADEMARK = TRADEMARK EndProjectSection EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "scratch-link-common", "scratch-link-common\scratch-link-common.shproj", "{06B5D2A3-AD0A-4704-B00D-BCFF634E7709}" +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "aluxlabs-link-common", "aluxlabs-link-common\aluxlabs-link-common.shproj", "{06B5D2A3-AD0A-4704-B00D-BCFF634E7709}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "scratch-link-mac", "scratch-link-mac\scratch-link-mac.csproj", "{CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}" EndProject @@ -50,9 +50,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fastlane", "fastlane", "{B8 fastlane\README.md = fastlane\README.md EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "scratch-link-win", "scratch-link-win\scratch-link-win.csproj", "{B21C2FCE-7670-402A-B8EE-958F3896F237}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "aluxlabs-link-win", "aluxlabs-link-win\aluxlabs-link-win.csproj", "{B21C2FCE-7670-402A-B8EE-958F3896F237}" EndProject -Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "scratch-link-win-msix", "scratch-link-win-msix\scratch-link-win-msix.wapproj", "{265CA433-8639-4E8D-A7F3-09B1B3495D92}" +Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "aluxlabs-link-win-msix", "aluxlabs-link-win-msix\aluxlabs-link-win-msix.wapproj", "{265CA433-8639-4E8D-A7F3-09B1B3495D92}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{05F0C24B-4EA1-4B11-9F86-DB3F1EDEE785}" ProjectSection(SolutionItems) = preProject @@ -220,8 +220,8 @@ Global SolutionGuid = {61F7FB11-1E47-470C-91E2-47F8143E1572} EndGlobalSection GlobalSection(SharedMSBuildProjectFiles) = preSolution - scratch-link-common\scratch-link-common.projitems*{06b5d2a3-ad0a-4704-b00d-bcff634e7709}*SharedItemsImports = 13 - scratch-link-common\scratch-link-common.projitems*{b21c2fce-7670-402a-b8ee-958f3896f237}*SharedItemsImports = 5 - scratch-link-common\scratch-link-common.projitems*{cdf7978e-13c6-40a9-81f9-2a3b4f7e861c}*SharedItemsImports = 4 + aluxlabs-link-common\aluxlabs-link-common.projitems*{06b5d2a3-ad0a-4704-b00d-bcff634e7709}*SharedItemsImports = 13 + aluxlabs-link-common\aluxlabs-link-common.projitems*{b21c2fce-7670-402a-b8ee-958f3896f237}*SharedItemsImports = 5 + aluxlabs-link-common\aluxlabs-link-common.projitems*{cdf7978e-13c6-40a9-81f9-2a3b4f7e861c}*SharedItemsImports = 4 EndGlobalSection EndGlobal From f4483feff4ca54b3a86216aaedff6d39d5710faa Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 14:20:05 +0900 Subject: [PATCH 56/94] =?UTF-8?q?chore(aws):=20=EC=8B=9C=ED=81=AC=EB=A6=BF?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D=20=EA=B2=BD=EB=A1=9C=EB=A5=BC=20repo-leve?= =?UTF-8?q?l=EB=A1=9C=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aluxrobot/scratch-link은 scratchfoundation public fork라 org 시크릿 (visibility=Private repositories)이 닿지 못함. 본 repo 한정 IAM user를 별도로 만드는 본 설계와도 스코프가 맞아 repo 시크릿으로 통일. Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/aws/README.md | 17 ++++++++++++++--- scripts/aws/setup-cdn.sh | 15 ++++++++++----- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/scripts/aws/README.md b/scripts/aws/README.md index b73d54c0..059140b3 100644 --- a/scripts/aws/README.md +++ b/scripts/aws/README.md @@ -23,7 +23,7 @@ cd ## 산출 -마지막에 출력되는 5개 값을 GitHub **Organization** Secrets에 등록: +마지막에 출력되는 5개 값을 **Repository Secrets** (org가 아닌 본 repo 한정)에 등록: | Secret 이름 | 출처 | |---|---| @@ -33,9 +33,20 @@ cd | `CF_DIST_ID_PROD` | 스크립트 출력 | | `CF_DIST_ID_DEV` | 스크립트 출력 | -등록 경로: GitHub Org → Settings → Secrets and variables → Actions → New organization secret. 본 리포지토리(`aluxrobot/scratch-link`)를 접근 가능 리포에 추가. +> **왜 repo 시크릿?** `aluxrobot/scratch-link`은 `scratchfoundation/scratch-link`의 **public fork**라 org 시크릿(visibility=Private repositories)이 닿지 못한다. 본 작업의 IAM user `gh-actions-scratch-link`도 이 repo 전용이라 시크릿도 같은 스코프에 두는 게 일관적. -> 기존 Org Secret에 `AWS_ACCESS_KEY_ID` 이름이 이미 다른 키로 등록돼 있으면, 본 워크플로용 이름을 `SCRATCH_LINK_AWS_ACCESS_KEY_ID` 등으로 바꿔 등록하고 `release.yml`의 secret 참조도 같이 바꾸세요. +### 등록 방법 두 가지 + +**(권장) gh CLI** — 값이 셸 히스토리에 안 남게: +```bash +gh secret set AWS_REGION --repo aluxrobot/scratch-link --body "ap-northeast-2" +gh secret set CF_DIST_ID_PROD --repo aluxrobot/scratch-link --body "" +gh secret set CF_DIST_ID_DEV --repo aluxrobot/scratch-link --body "" +gh secret set AWS_ACCESS_KEY_ID --repo aluxrobot/scratch-link # 프롬프트 +gh secret set AWS_SECRET_ACCESS_KEY --repo aluxrobot/scratch-link # 프롬프트 +``` + +**브라우저**: https://github.com/aluxrobot/scratch-link/settings/secrets/actions → "New repository secret". ## 멱등성 diff --git a/scripts/aws/setup-cdn.sh b/scripts/aws/setup-cdn.sh index 3484c7a0..13652802 100755 --- a/scripts/aws/setup-cdn.sh +++ b/scripts/aws/setup-cdn.sh @@ -59,7 +59,8 @@ key_line=$(ensure_access_key) cat >&2 < Date: Tue, 26 May 2026 14:23:32 +0900 Subject: [PATCH 57/94] =?UTF-8?q?docs(rebrand):=20=EB=AC=B8=EC=84=9C=20?= =?UTF-8?q?=EC=B5=9C=EC=A2=85=20=ED=8C=A8=EC=8A=A4=20=E2=80=94=20=ED=8F=B4?= =?UTF-8?q?=EB=8D=94/=ED=94=84=EB=A1=9C=EC=A0=9D=ED=8A=B8=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EB=B0=8F=20=EC=A0=9C=ED=92=88=EB=AA=85=20=ED=91=9C?= =?UTF-8?q?=EA=B8=B0=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 일괄 치환: - scratch-link-{common,win,win-msix} → aluxlabs-link-{...} 경로 - scratch-link.sln → aluxlabs-link.sln - "Alux Scratch Link" → "AluxLabs Link" 대상: - README.md (저장소 구조, 빌드 구성, Startup Project, 깨진 doc 링크 보정) - CLAUDE.md (폴더명 / 프로젝트 의존 방향 규칙 / 명령어 예시) - Documentation/Alux/WindowsDevSetup-VS2026.md (광범위) - Documentation/Alux/SerialKeepAliveGuide.md ("Scratch Link" → 우리 제품) - Documentation/Alux/SerialApiReference.md (동일) - Makefile (WINDOWS_IMAGES / MSIX 경로) - package.json (name, description) 유지 (KEEP): - 원본 scratch-link upstream URL 및 AGPL attribution - RebrandingPlan.md 의 매핑표 (historical) - Makefile 의 scratch-link-mac 경로 (out of scope) - playground.html 의 scratch-vm 모듈 경로 (upstream) - Scratch Link Safari Helper/ (out of scope) - package-lock.json (npm install 시 자동 재생성) dotnet build Debug_Win 성공 확인. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 20 +++++------ Documentation/Alux/SerialApiReference.md | 2 +- Documentation/Alux/SerialKeepAliveGuide.md | 2 +- Documentation/Alux/WindowsDevSetup-VS2026.md | 34 +++++++++--------- Makefile | 36 ++++++++++---------- README.md | 12 +++---- package.json | 4 +-- 7 files changed, 55 insertions(+), 55 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 7c4fa5cb..4d718d62 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,7 +8,7 @@ C# / .NET 8 + WinUI 3, Visual Studio Solution. ## 1. 최우선 규칙 (위반 시 즉시 수정) - **`Console.*` 사용 금지** → `Trace.WriteLine()` (`System.Diagnostics`) 사용 (§4 참조) -- **`scratch-link-common`이 `scratch-link-win`을 참조 금지** → 의존 방향은 `scratch-link-win → scratch-link-common` 단방향 (§8 참조) +- **`aluxlabs-link-common`이 `aluxlabs-link-win`을 참조 금지** → 의존 방향은 `aluxlabs-link-win → aluxlabs-link-common` 단방향 (§8 참조) - **`SharedProps/*.props` / `*.targets` 직접 편집 시 주의** → 전체 빌드에 영향. 개별 csproj에서 중복 선언 금지 - **기존 아키텍처·패턴을 우회하는 수정 금지** (§8 참조) → 새 코드·수정 코드에 적용. 기존 위반은 명시 요청 없이 건드리지 않는다. 단, 수정 범위 안에서 우회 코드를 발견하면 사용자에게 알리고 처리 여부를 묻는다. @@ -36,14 +36,14 @@ C# / .NET 8 + WinUI 3, Visual Studio Solution. - **`types.cs` / `type.cs` 파일 생성 금지** → 타입·인터페이스는 사용하는 클래스 파일 안에 함께 정의 (코로케이션) - **일반 주석(`//`)은 한 줄 max, "WHY"만** → 기본은 주석 없음. WHY가 비자명할 때만 한 줄 추가. WHAT 설명 / 현재 작업·callers 참조 금지. 설계 의도는 commit message / PR description으로. - **XML doc(`///`)은 public API에 한해 단일 `` 허용** → 단, caller 참조(`"Used by X"`) 및 코드에서 자명한 WHAT 설명 금지. 비자명한 동작·제약·사이드이펙트만 기술한다. -- **공용 코드 (`scratch-link-common`) 의 주석·식별자에서 특정 프로토콜 구현 세부 언급 금지** → 일반화된 패턴 설명으로 표현하고, 구체적 예시는 해당 세션 클래스 안에서만 든다. +- **공용 코드 (`aluxlabs-link-common`) 의 주석·식별자에서 특정 프로토콜 구현 세부 언급 금지** → 일반화된 패턴 설명으로 표현하고, 구체적 예시는 해당 세션 클래스 안에서만 든다. ## 5. 작업 전 확인사항 코드 작성·수정 전에 반드시 확인: 1. 수정 대상 파일을 먼저 읽고 기존 패턴을 파악한다 -2. **`scratch-link-common` vs `scratch-link-win` 중 어느 쪽에 위치해야 하는지 판단한다** — 플랫폼 API(Windows.Devices.*, WinUI) 없이 동작 가능하면 common, 그렇지 않으면 win +2. **`aluxlabs-link-common` vs `aluxlabs-link-win` 중 어느 쪽에 위치해야 하는지 판단한다** — 플랫폼 API(Windows.Devices.*, WinUI) 없이 동작 가능하면 common, 그렇지 않으면 win 3. 관련 타입·인터페이스가 이미 있는지 확인한다 4. `SharedProps/`에 이미 선언된 속성·패키지 참조인지 확인한다 @@ -54,7 +54,7 @@ C# / .NET 8 + WinUI 3, Visual Studio Solution. - [ ] `using` 선언이 namespace 내부에 있는가? - [ ] 멤버 접근에 `this.` 한정자를 사용했는가? - [ ] 미사용 변수·using이 없는가? -- [ ] 의존 방향 규칙을 지켰는가? (`scratch-link-common`이 `scratch-link-win`을 참조하지 않음) +- [ ] 의존 방향 규칙을 지켰는가? (`aluxlabs-link-common`이 `aluxlabs-link-win`을 참조하지 않음) - [ ] `SharedProps/`에 이미 선언된 속성을 개별 csproj에 중복 선언하지 않았는가? - [ ] 일반 주석(`//`)이 WHY만 담고 있는가? (WHAT / caller 참조 없음) - [ ] XML doc(`///`)이 있다면 public API이고, caller 참조 및 자명한 WHAT 설명이 없는가? @@ -75,22 +75,22 @@ docs(architecture): Serial 프로토콜 설계 문서 업데이트 ## 8. 프로젝트 구조 핵심 -- `scratch-link-common/` — 플랫폼 공통 C# Shared Project (BLE/BT/Serial 프로토콜 추상화, JSON-RPC 2.0, WebSocket 핸들링). **재사용 가능한 단위로 분리**, Windows API에 종속되지 않는다. -- `scratch-link-win/` — WinUI 3 플랫폼 구현 (Windows.Devices.* API 연동, 트레이 아이콘, 앱 진입점). **비즈니스 로직은 최소화**, 가능한 한 `scratch-link-common`으로 위임. -- `scratch-link-win-msix/` — MSIX 패키징 프로젝트. 직접 코드 편집 대상이 아니다. +- `aluxlabs-link-common/` — 플랫폼 공통 C# Shared Project (BLE/BT/Serial 프로토콜 추상화, JSON-RPC 2.0, WebSocket 핸들링). **재사용 가능한 단위로 분리**, Windows API에 종속되지 않는다. +- `aluxlabs-link-win/` — WinUI 3 플랫폼 구현 (Windows.Devices.* API 연동, 트레이 아이콘, 앱 진입점). **비즈니스 로직은 최소화**, 가능한 한 `aluxlabs-link-common`으로 위임. +- `aluxlabs-link-win-msix/` — MSIX 패키징 프로젝트. 직접 코드 편집 대상이 아니다. - `SharedProps/` — MSBuild 공유 속성 (SDK 버전, NuGet 패키지 참조, 버전 자동화). 개별 csproj에서 중복 선언 금지. - `Documentation/` — 아키텍처·프로토콜 설계 문서. 관련 코드 변경 시 함께 업데이트한다. -- **의존 방향: `scratch-link-win` → `scratch-link-common` 단방향** (§1 절대 규칙). 이유: common이 win을 참조하면 플랫폼 독립성이 깨지고 순환 의존이 발생한다. +- **의존 방향: `aluxlabs-link-win` → `aluxlabs-link-common` 단방향** (§1 절대 규칙). 이유: common이 win을 참조하면 플랫폼 독립성이 깨지고 순환 의존이 발생한다. ## 9. 개발 명령어 ```bash -# 권장: Visual Studio 2022+에서 scratch-link.sln 열기 +# 권장: Visual Studio 2022+에서 aluxlabs-link.sln 열기 # 빌드 구성: Debug_Win / Release_Win dotnet build -c Debug_Win # 디버그 빌드 dotnet build -c Release_Win # 릴리즈 빌드 -dotnet run --project scratch-link-win -c Debug_Win # 실행 +dotnet run --project aluxlabs-link-win -c Debug_Win # 실행 # 아이콘 생성 (cairosvg, ImageMagick, optipng 필요) make icons diff --git a/Documentation/Alux/SerialApiReference.md b/Documentation/Alux/SerialApiReference.md index 9a3c1789..975e40eb 100644 --- a/Documentation/Alux/SerialApiReference.md +++ b/Documentation/Alux/SerialApiReference.md @@ -355,7 +355,7 @@ Sent when the connection is lost (external cause, not client-initiated). **Recovery policy (current):** -Scratch Link does **not** retry on I/O errors. The moment the kernel surfaces a read-side `IOException`, Link: +AluxLabs Link does **not** retry on I/O errors. The moment the kernel surfaces a read-side `IOException`, Link: 1. Fires `serialDidDisconnect` with `reason: "device"`. 2. Closes the port. 3. Stops the keep-alive timer and the RX loop. diff --git a/Documentation/Alux/SerialKeepAliveGuide.md b/Documentation/Alux/SerialKeepAliveGuide.md index 0050ff3b..943b6571 100644 --- a/Documentation/Alux/SerialKeepAliveGuide.md +++ b/Documentation/Alux/SerialKeepAliveGuide.md @@ -2,7 +2,7 @@ ## Overview -The Scratch Link serial transport now supports **keep-alive** functionality to prevent device timeout. This is particularly useful for devices like Codetinker that disconnect if no response is received within 1 second. +AluxLabs Link's serial transport supports **keep-alive** functionality to prevent device timeout. This is particularly useful for devices like Codetinker that disconnect if no response is received within 1 second. ## Problem Statement diff --git a/Documentation/Alux/WindowsDevSetup-VS2026.md b/Documentation/Alux/WindowsDevSetup-VS2026.md index 150da42b..94979b10 100644 --- a/Documentation/Alux/WindowsDevSetup-VS2026.md +++ b/Documentation/Alux/WindowsDevSetup-VS2026.md @@ -1,14 +1,14 @@ # Windows 개발 환경 세팅 (Visual Studio 2026) -Visual Studio 2026으로 Alux Scratch Link를 빌드/디버깅하기 위한 환경 세팅 절차. +Visual Studio 2026으로 AluxLabs Link를 빌드/디버깅하기 위한 환경 세팅 절차. ## 0. 사전 정보 -- 솔루션 파일 `scratch-link.sln`은 VS 2026에서 그대로 열 수 있다. **버전 변환 프롬프트가 떠도 변환하지 말 것** (sln 포맷이 바뀌어 PR이 지저분해진다). +- 솔루션 파일 `aluxlabs-link.sln`은 VS 2026에서 그대로 열 수 있다. **버전 변환 프롬프트가 떠도 변환하지 말 것** (sln 포맷이 바뀌어 PR이 지저분해진다). - 윈도우 관련 프로젝트: - - `scratch-link-win` — WinUI 3 기반 본체 EXE (net8.0-windows) - - `scratch-link-win-msix` — `.wapproj` (Desktop Bridge) 형식의 MSIX 패키징 프로젝트 - - `scratch-link-common` — 공유 C# 코드 (`.shproj`, 공유 아이템 프로젝트) + - `aluxlabs-link-win` — WinUI 3 기반 본체 EXE (net8.0-windows) + - `aluxlabs-link-win-msix` — `.wapproj` (Desktop Bridge) 형식의 MSIX 패키징 프로젝트 + - `aluxlabs-link-common` — 공유 C# 코드 (`.shproj`, 공유 아이템 프로젝트) - `scratch-link-mac`은 솔루션을 열면 "Unsupported"로 표시되는데 **정상이다**. Windows VS에서는 어차피 빌드하지 않으므로 무시한다 (솔루션에서 제거하지 말 것). ## 1. Visual Studio Installer 워크로드 @@ -29,7 +29,7 @@ VS Installer를 열고 **수정(Modify)**으로 다음 워크로드를 체크한 **`WinUI 애플리케이션 개발`의 선택 사항:** -- ☑ **Windows 11 SDK (10.0.22621.0)** — `scratch-link-win.csproj`의 `TargetFramework=net8.0-windows10.0.22621.0`이 요구하는 SDK. +- ☑ **Windows 11 SDK (10.0.22621.0)** — `aluxlabs-link-win.csproj`의 `TargetFramework=net8.0-windows10.0.22621.0`이 요구하는 SDK. > `.NET 8 SDK`는 VS 2026에 포함되어 있으므로 별도 설치가 필요 없다. @@ -51,9 +51,9 @@ Get-AppxPackage -Name "Microsoft.WindowsAppRuntime.1.8*" ## 3. 솔루션 열기 -1. `scratch-link.sln` 더블클릭으로 VS 2026에서 열기 +1. `aluxlabs-link.sln` 더블클릭으로 VS 2026에서 열기 2. "Migration Report"가 뜨면 **OK**로 닫는다. `scratch-link-mac`이 Unsupported로 나오는 것은 정상. -3. **솔루션 탐색기**에서 `scratch-link-win`을 우클릭 → **Set as Startup Project**. 프로젝트 이름이 굵게(bold) 변하면 적용된 것. +3. **솔루션 탐색기**에서 `aluxlabs-link-win`을 우클릭 → **Set as Startup Project**. 프로젝트 이름이 굵게(bold) 변하면 적용된 것. ## 4. 빌드/실행 설정 @@ -63,9 +63,9 @@ VS 상단 툴바에서: |---|---| | Solution Configurations | **`Debug_Win`** | | Solution Platforms | **`x64`** (또는 본인 PC에 맞는 플랫폼) | -| Startup Project | **`scratch-link-win`** | +| Startup Project | **`aluxlabs-link-win`** | -> **시작 프로젝트는 반드시 `scratch-link-win`이어야 한다.** `scratch-link-win-msix`로 F5를 누르면 패키지 ID 충돌로 `MddBootstrapInitialize 0x80070032` 에러가 난다. +> **시작 프로젝트는 반드시 `aluxlabs-link-win`이어야 한다.** `aluxlabs-link-win-msix`로 F5를 누르면 패키지 ID 충돌로 `MddBootstrapInitialize 0x80070032` 에러가 난다. 이후 **F5**로 빌드 및 실행. 트레이 아이콘이 나타나면 정상 동작. @@ -73,9 +73,9 @@ VS 상단 툴바에서: | 목적 | Startup Project | Configuration | 결과물 | |---|---|---|---| -| **일상 개발/디버깅 (F5)** | `scratch-link-win` | `Debug_Win` / `x64` | 언패키지 EXE 직접 실행 | -| **MSIX 패키지 빌드** | `scratch-link-win-msix` | `Release_Win` / `x64` | publish profile (`win-x64.pubxml`)로 MSIX 생성 | -| **배포용 msixbundle** | `scratch-link-win-msix` | `Release_Win`, 전 플랫폼 | x86/x64/ARM64 `.msixbundle` 생성 | +| **일상 개발/디버깅 (F5)** | `aluxlabs-link-win` | `Debug_Win` / `x64` | 언패키지 EXE 직접 실행 | +| **MSIX 패키지 빌드** | `aluxlabs-link-win-msix` | `Release_Win` / `x64` | publish profile (`win-x64.pubxml`)로 MSIX 생성 | +| **배포용 msixbundle** | `aluxlabs-link-win-msix` | `Release_Win`, 전 플랫폼 | x86/x64/ARM64 `.msixbundle` 생성 | ## 6. 알려진 이슈 @@ -85,13 +85,13 @@ VS 상단 툴바에서: | `Windows 10 SDK version 10.0.22621.0 was not found` | Windows 11 SDK 22621 미설치. §1의 "WinUI 애플리케이션 개발" 선택 사항 확인. | | F5 시 `MddBootstrapInitialize ... 0x80070032` | 시작 프로젝트가 wapproj로 설정됨. §4 참고. | | F5 시 "This application requires the Windows App Runtime 1.8" | 런타임 미설치. §2 참고. | -| `scratch-link-win-msix`가 회색으로 비활성화 | Configuration이 `*_Win`이 아닌 다른 것으로 되어 있음. `Debug_Win` 또는 `Release_Win`으로 전환. | -| CS 빌드 에러 (System.Management, Fleck 등 누락) | NuGet 캐시 불일치. CLI에서 `dotnet restore --force scratch-link-win/scratch-link-win.csproj` 실행 후 VS 재시작. | +| `aluxlabs-link-win-msix`가 회색으로 비활성화 | Configuration이 `*_Win`이 아닌 다른 것으로 되어 있음. `Debug_Win` 또는 `Release_Win`으로 전환. | +| CS 빌드 에러 (System.Management, Fleck 등 누락) | NuGet 캐시 불일치. CLI에서 `dotnet restore --force aluxlabs-link-win/aluxlabs-link-win.csproj` 실행 후 VS 재시작. | | 빌드 시 `프로젝트에 'GitVersion' 대상이 없습니다` | VS 2026 MSBuild의 NuGetPackageRoot 경로 차이로 GitInfo.targets가 로드 안 되는 경우. `SharedProps/ScratchVersion.targets`에 fallback 타겟이 있어 정상 동작하므로 무시해도 된다. | ## 7. 참고 -- [`scratch-link-win/scratch-link-win.csproj`](../scratch-link-win/scratch-link-win.csproj) — 본체 프로젝트 설정 -- [`scratch-link-win-msix/scratch-link-win-msix.wapproj`](../scratch-link-win-msix/scratch-link-win-msix.wapproj) — MSIX 패키징 설정 +- [`aluxlabs-link-win/aluxlabs-link-win.csproj`](../aluxlabs-link-win/aluxlabs-link-win.csproj) — 본체 프로젝트 설정 +- [`aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj`](../aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj) — MSIX 패키징 설정 - [`SharedProps/WindowsSDK.props`](../SharedProps/WindowsSDK.props) — Windows App SDK 버전 핀 - [`SharedProps/ScratchVersion.targets`](../SharedProps/ScratchVersion.targets) — 버전 자동 생성 로직 diff --git a/Makefile b/Makefile index 63c6712d..06c77a17 100644 --- a/Makefile +++ b/Makefile @@ -45,15 +45,15 @@ MAC_IMAGES = \ Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-72.png WINDOWS_IMAGES = \ - scratch-link-win/aluxlabs-link.ico \ - scratch-link-win/aluxlabs-link-tray.ico \ - scratch-link-win-msix/Images/LockScreenLogo.scale-200.png \ - scratch-link-win-msix/Images/SplashScreen.scale-200.png \ - scratch-link-win-msix/Images/Square150x150Logo.scale-200.png \ - scratch-link-win-msix/Images/Square44x44Logo.scale-200.png \ - scratch-link-win-msix/Images/Square44x44Logo.targetsize-24_altform-unplated.png \ - scratch-link-win-msix/Images/StoreLogo.png \ - scratch-link-win-msix/Images/Wide310x150Logo.scale-200.png + aluxlabs-link-win/aluxlabs-link.ico \ + aluxlabs-link-win/aluxlabs-link-tray.ico \ + aluxlabs-link-win-msix/Images/LockScreenLogo.scale-200.png \ + aluxlabs-link-win-msix/Images/SplashScreen.scale-200.png \ + aluxlabs-link-win-msix/Images/Square150x150Logo.scale-200.png \ + aluxlabs-link-win-msix/Images/Square44x44Logo.scale-200.png \ + aluxlabs-link-win-msix/Images/Square44x44Logo.targetsize-24_altform-unplated.png \ + aluxlabs-link-win-msix/Images/StoreLogo.png \ + aluxlabs-link-win-msix/Images/Wide310x150Logo.scale-200.png .PHONY: all clean mac windows @@ -124,16 +124,16 @@ $(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Exten # See also: # https://stackoverflow.com/q/3236115 # https://iconhandbook.co.uk/reference/chart/windows/ -$(eval $(call svg2ico,scratch-link-win/aluxlabs-link.ico,Assets/square.svg,256 128 96 64 48 32 24 16)) -$(eval $(call svg2ico,scratch-link-win/aluxlabs-link-tray.ico,Assets/simplified.svg,32 24 16)) +$(eval $(call svg2ico,aluxlabs-link-win/aluxlabs-link.ico,Assets/square.svg,256 128 96 64 48 32 24 16)) +$(eval $(call svg2ico,aluxlabs-link-win/aluxlabs-link-tray.ico,Assets/simplified.svg,32 24 16)) # Windows MSIX # TODO: does Microsoft really want DPI=72 for all of these? # See https://learn.microsoft.com/en-us/windows/apps/design/layout/screen-sizes-and-breakpoints-for-responsive-design#effective-pixels-and-scale-factor -$(eval $(call svg2png,scratch-link-win-msix/Images/LockScreenLogo.scale-200.png,Assets/rounded.svg,48,48,72)) -$(eval $(call svg2png,scratch-link-win-msix/Images/SplashScreen.scale-200.png,Assets/rounded.svg,1240,600,72)) -$(eval $(call svg2png,scratch-link-win-msix/Images/Square44x44Logo.scale-200.png,Assets/rounded.svg,88,88,72)) -$(eval $(call svg2png,scratch-link-win-msix/Images/Square44x44Logo.targetsize-24_altform-unplated.png,Assets/rounded.svg,24,24,72)) -$(eval $(call svg2png,scratch-link-win-msix/Images/Square150x150Logo.scale-200.png,Assets/rounded.svg,300,300,72)) -$(eval $(call svg2png,scratch-link-win-msix/Images/StoreLogo.png,Assets/rounded.svg,50,50,72)) -$(eval $(call svg2png,scratch-link-win-msix/Images/Wide310x150Logo.scale-200.png,Assets/rounded.svg,620,300,72)) +$(eval $(call svg2png,aluxlabs-link-win-msix/Images/LockScreenLogo.scale-200.png,Assets/rounded.svg,48,48,72)) +$(eval $(call svg2png,aluxlabs-link-win-msix/Images/SplashScreen.scale-200.png,Assets/rounded.svg,1240,600,72)) +$(eval $(call svg2png,aluxlabs-link-win-msix/Images/Square44x44Logo.scale-200.png,Assets/rounded.svg,88,88,72)) +$(eval $(call svg2png,aluxlabs-link-win-msix/Images/Square44x44Logo.targetsize-24_altform-unplated.png,Assets/rounded.svg,24,24,72)) +$(eval $(call svg2png,aluxlabs-link-win-msix/Images/Square150x150Logo.scale-200.png,Assets/rounded.svg,300,300,72)) +$(eval $(call svg2png,aluxlabs-link-win-msix/Images/StoreLogo.png,Assets/rounded.svg,50,50,72)) +$(eval $(call svg2png,aluxlabs-link-win-msix/Images/Wide310x150Logo.scale-200.png,Assets/rounded.svg,620,300,72)) diff --git a/README.md b/README.md index e4962fb9..93dcd5ba 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Scratch 3.0과 PC에 연결된 하드웨어 주변기기를 중계하는 도우 ## 원본과의 차이 - **Windows 전용** — macOS 빌드와 Safari 확장은 제외. -- **Serial 전송 추가** — BLE / Bluetooth Classic에 더해 USB 시리얼(CDC/CH340 등) 장치를 `/scratch/serial` JSON-RPC 엔드포인트로 지원. 구현은 `scratch-link-common/Serial/`과 `scratch-link-win/Serial/` 참고. +- **Serial 전송 추가** — BLE / Bluetooth Classic에 더해 USB 시리얼(CDC/CH340 등) 장치를 `/scratch/serial` JSON-RPC 엔드포인트로 지원. 구현은 `aluxlabs-link-common/Serial/`과 `aluxlabs-link-win/Serial/` 참고. - **포트 20211 사용** — 원본 Scratch Link(20110/20111)와 한 PC에서 공존 가능. - **.NET 8 / WindowsAppSDK 1.8** — 원본의 .NET 6 / WindowsAppSDK 1.3에서 업그레이드. @@ -38,13 +38,13 @@ AluxLabs는 Alux 전용 Scratch 3.0입니다. ``` scratch-link/ -├── scratch-link-win/ # WinUI 3 앱 본체 (EXE) +├── aluxlabs-link-win/ # WinUI 3 앱 본체 (EXE) │ ├── BLE/ # Bluetooth Low Energy (Windows) │ ├── BT/ # Bluetooth Classic (Windows) │ ├── Serial/ # USB 시리얼 (Windows) │ └── Properties/PublishProfiles/ # win-x64/x86/arm64 publish 프로필 -├── scratch-link-win-msix/ # MSIX 패키징 프로젝트 (.wapproj) -├── scratch-link-common/ # 플랫폼 공유 C# 코드 (.shproj) +├── aluxlabs-link-win-msix/ # MSIX 패키징 프로젝트 (.wapproj) +├── aluxlabs-link-common/ # 플랫폼 공유 C# 코드 (.shproj) │ ├── BLE/ # BLE 세션 공통 로직 │ ├── BT/ # BT 세션 공통 로직 │ ├── Serial/ # 시리얼 세션 공통 로직 @@ -62,7 +62,7 @@ scratch-link/ ## 개발 환경 구성 -[Documentation/WindowsDevSetup-VS2026.md](Documentation/WindowsDevSetup-VS2026.md) 참고. +[Documentation/Alux/WindowsDevSetup-VS2026.md](Documentation/Alux/WindowsDevSetup-VS2026.md) 참고. ## 빌드 구성 @@ -71,7 +71,7 @@ scratch-link/ | `Debug_Win` | 일상 개발/디버깅 (F5) | | `Release_Win` | 배포용 빌드 및 MSIX 패키징 | -Startup Project를 `scratch-link-win-msix`로 설정하면 MSIX 패키지 빌드가 실행됩니다. 일반 디버깅은 반드시 `scratch-link-win`으로 설정할 것. +Startup Project를 `aluxlabs-link-win-msix`로 설정하면 MSIX 패키지 빌드가 실행됩니다. 일반 디버깅은 반드시 `aluxlabs-link-win`으로 설정할 것. ## 버전 번호 diff --git a/package.json b/package.json index e258a44e..695fb05a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "alux-scratch-link", + "name": "aluxlabs-link", "version": "1.0.0", - "description": "Alux Scratch Link is not published as an NPM package. This file only exists to facilitate installation of devDependencies.", + "description": "AluxLabs Link is not published as an NPM package. This file only exists to facilitate installation of devDependencies.", "author": "ALUX, Inc.", "license": "AGPL-3.0-only", "scripts": { From 9161435f8a5758d412f8e2f0144165706e7e5adf Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 14:26:28 +0900 Subject: [PATCH 58/94] =?UTF-8?q?fix(aws):=20cloudfront=20=EB=A9=B1?= =?UTF-8?q?=EB=93=B1=20=EC=BF=BC=EB=A6=AC=EC=97=90=EC=84=9C=20null=20Alias?= =?UTF-8?q?es=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 다른 distribution에 aliases가 없을 때 JMESPath contains()가 null로 에러를 출력하던 문제 수정. `|| \`[]\``로 빈 배열 fallback. Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/aws/lib/cloudfront.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/aws/lib/cloudfront.sh b/scripts/aws/lib/cloudfront.sh index b4cfe22c..5ea19522 100644 --- a/scripts/aws/lib/cloudfront.sh +++ b/scripts/aws/lib/cloudfront.sh @@ -10,8 +10,9 @@ ensure_distribution() { local origin_domain="${domain}.s3-website.${AWS_REGION}.amazonaws.com" local existing + # `|| \`[]\``: alias 없는 다른 distribution의 null Items에서 contains() 에러를 회피. existing=$(aws cloudfront list-distributions \ - --query "DistributionList.Items[?contains(Aliases.Items, \`$domain\`)].{Id:Id,Domain:DomainName}" \ + --query "DistributionList.Items[?contains(Aliases.Items || \`[]\`, \`$domain\`)].{Id:Id,Domain:DomainName}" \ --output json) local count From c0f8435ce49463c36d1f53b572923a0fe284d22f Mon Sep 17 00:00:00 2001 From: songtomtom Date: Tue, 26 May 2026 14:42:00 +0900 Subject: [PATCH 59/94] =?UTF-8?q?fix(ci):=20CloudFront=20invalidation?= =?UTF-8?q?=EC=9D=84=20invalidation-batch=20JSON=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git Bash on Windows에서 native aws.exe로 인자 전달 시 따옴표가 path에 포함되어 InvalidArgument 에러 발생. 임시 JSON 파일을 file:// 로 전달하는 방식이 셸 quoting 영향에서 자유로움. CallerReference로 재실행 중복 방지. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/release.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ba48c9f9..378e1639 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -200,8 +200,16 @@ jobs: shell: bash run: | set -euo pipefail + # Git Bash on Windows에서 native aws.exe로 따옴표가 그대로 전달돼 invalid path가 되는 문제 회피. + # --invalidation-batch JSON 형태로 명시. CallerReference로 재실행 시 중복 방지. + cat > /tmp/cf-invalidation.json < Date: Tue, 26 May 2026 14:46:47 +0900 Subject: [PATCH 60/94] =?UTF-8?q?fix(ci):=20invalidation=20JSON=EC=9D=84?= =?UTF-8?q?=20workspace=20=EC=83=81=EB=8C=80=20=EA=B2=BD=EB=A1=9C=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /tmp는 Git Bash 가상 경로라 native aws.exe가 못 찾는 문제. workspace 상대 경로(cf-inv.json)로 두면 cwd 기준 정상 해석. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/release.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 378e1639..b20cfae8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -200,16 +200,13 @@ jobs: shell: bash run: | set -euo pipefail - # Git Bash on Windows에서 native aws.exe로 따옴표가 그대로 전달돼 invalid path가 되는 문제 회피. - # --invalidation-batch JSON 형태로 명시. CallerReference로 재실행 시 중복 방지. - cat > /tmp/cf-invalidation.json < cf-inv.json + cat cf-inv.json aws cloudfront create-invalidation \ --distribution-id "${{ steps.meta.outputs.dist_id }}" \ - --invalidation-batch file:///tmp/cf-invalidation.json \ + --invalidation-batch file://cf-inv.json \ --query 'Invalidation.{Id:Id,Status:Status}' \ --output table From 7e9f28bd6a280ca0720f79fedf1a3ea20df65251 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 May 2026 16:25:18 +0900 Subject: [PATCH 61/94] =?UTF-8?q?fix(msix):=20Publisher=20CN=20=EC=9D=98?= =?UTF-8?q?=20=EC=BD=A4=EB=A7=88=20=EC=A0=9C=EA=B1=B0=20=E2=80=94=20manife?= =?UTF-8?q?st=20=EC=8A=A4=ED=82=A4=EB=A7=88=20=EC=9C=84=EB=B0=98=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 원본 'CN=ALUX, Inc.' 는 escape 안 된 콤마가 MSIX manifest Publisher 패턴 정규식에 위반되어 빌드 시 validation error C00CE169 발생. 콤마 없는 'CN=ALUX Inc.' 로 변경. 정식 코드 서명 인증서 또는 Partner Center 발급값으로 교체 시 실제 인증서 subject 그대로 사용하면 됨. Co-Authored-By: Claude Opus 4.7 (1M context) --- aluxlabs-link-win-msix/Package.appxmanifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aluxlabs-link-win-msix/Package.appxmanifest b/aluxlabs-link-win-msix/Package.appxmanifest index 0da14be2..887e4fa7 100644 --- a/aluxlabs-link-win-msix/Package.appxmanifest +++ b/aluxlabs-link-win-msix/Package.appxmanifest @@ -8,7 +8,7 @@ From 5209ce6ff8d7a8bb27211379abb1ed9ef57282a6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 May 2026 16:25:21 +0900 Subject: [PATCH 62/94] =?UTF-8?q?chore(msix):=20publish=20profile=20?= =?UTF-8?q?=EC=9D=84=20self-contained=20=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit x64 / x86 / ARM64 모두 SelfContained=true, WindowsAppSDKSelfContained=true. 배포 시 사용자 PC 의 .NET 8 / WindowsAppSDK runtime 의존성 제거. 번들 크기 증가 (약 5MB → 85MB) 트레이드오프 있음. 학원·학교 등 인터넷 제한·관리 환경에서 의존성 자동 설치가 어려운 점을 우선. Co-Authored-By: Claude Opus 4.7 (1M context) --- aluxlabs-link-win/Properties/PublishProfiles/win-arm64.pubxml | 4 ++-- aluxlabs-link-win/Properties/PublishProfiles/win-x64.pubxml | 4 ++-- aluxlabs-link-win/Properties/PublishProfiles/win-x86.pubxml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aluxlabs-link-win/Properties/PublishProfiles/win-arm64.pubxml b/aluxlabs-link-win/Properties/PublishProfiles/win-arm64.pubxml index 0f38a644..986db155 100644 --- a/aluxlabs-link-win/Properties/PublishProfiles/win-arm64.pubxml +++ b/aluxlabs-link-win/Properties/PublishProfiles/win-arm64.pubxml @@ -11,8 +11,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121. false false - false - false + true + true Desktop diff --git a/aluxlabs-link-win/Properties/PublishProfiles/win-x64.pubxml b/aluxlabs-link-win/Properties/PublishProfiles/win-x64.pubxml index ac14247a..098e7246 100644 --- a/aluxlabs-link-win/Properties/PublishProfiles/win-x64.pubxml +++ b/aluxlabs-link-win/Properties/PublishProfiles/win-x64.pubxml @@ -11,8 +11,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121. false false - false - false + true + true Desktop diff --git a/aluxlabs-link-win/Properties/PublishProfiles/win-x86.pubxml b/aluxlabs-link-win/Properties/PublishProfiles/win-x86.pubxml index 3322027e..f1378419 100644 --- a/aluxlabs-link-win/Properties/PublishProfiles/win-x86.pubxml +++ b/aluxlabs-link-win/Properties/PublishProfiles/win-x86.pubxml @@ -11,8 +11,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121. false false - false - false + true + true Desktop From d417ee23a70c68a1f5ca0ae73cba54c946966678 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 May 2026 17:53:54 +0900 Subject: [PATCH 63/94] =?UTF-8?q?docs(deployment):=20=EC=B6=9C=ED=95=98=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=A4=91=20=EB=B0=9C=EA=B2=AC=EB=90=9C=20?= =?UTF-8?q?=EC=95=8C=EB=A0=A4=EC=A7=84=20=EC=9D=B4=EC=8A=88=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2026-05-26 리브랜드 시점의 검증 결과 기록: - Tooltip 미표시 (H.NotifyIcon 라이브러리 quirk, packaged only 정상) - MSIX packaged crash (dev PC 25H2, 정상 PC 미검증) - Ghost 패키지 해결됨 - 회귀 시도 실패 기록 — 빌드 환경 호환 문제 출하 형식 결정 (Portable / Inno Setup / MSIX / Store) 시 참고용. Co-Authored-By: Claude Opus 4.7 (1M context) --- Documentation/Alux/KnownIssues.md | 164 ++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 Documentation/Alux/KnownIssues.md diff --git a/Documentation/Alux/KnownIssues.md b/Documentation/Alux/KnownIssues.md new file mode 100644 index 00000000..2de37e02 --- /dev/null +++ b/Documentation/Alux/KnownIssues.md @@ -0,0 +1,164 @@ +# 알려진 이슈 — Deployment 관련 + +본 문서는 2026-05-26 리브랜드(`feature/rebrand-aluxlabs-link`) 시점에 deployment 검증 중 발견된 이슈와 검증 결과를 기록한다. **출하 형식·시점·코드 서명 정책 결정 시 참고용**. + +마지막 검증 commit: `5209ce6 chore(msix): publish profile 을 self-contained 로 변경` +검증 환경: Windows 11 25H2 build 26200 (개발 PC, 정상 PC 동일 build). + +--- + +## 1. Tooltip 미표시 (H.NotifyIcon.WinUI 라이브러리 이슈) + +### 증상 +트레이 아이콘 위에 마우스 호버 시 풍선 tooltip 이 표시되지 않는다. + +### 영향 범위 +**Unpackaged 모드 (F5 디버그 / Release portable EXE) 에서만 발생**. Packaged 모드 (MSIX-installed) 에서는 정상 동작. + +원본 Scratch Link 가 packaged 형태로 MS Store 에서 배포되어 동작하는 것은 이 패턴과 일치. + +### 검증 매트릭스 +| 시나리오 | Tooltip 동작 | +|---|---| +| F5 디버그 (unpackaged) | ✗ 안 뜸 | +| Release self-contained portable EXE 직접 실행 | ✗ 안 뜸 | +| MSIX install (packaged) | (실행 자체 별도 이슈로 미검증, 원본 Scratch Link 는 정상 동작) | +| 7b4c335 (pre-.NET-8 시점) F5 빌드 | ✗ 안 뜸 — 우리 fork 변경 이전부터 동일 | +| 다른 PC 의 원본 Scratch Link 1.4.3.0 (MS Store install) | ✓ 정상 | + +### 시도한 해결책 (모두 실패) +- XAML `ToolTipText` 명시 설정 — 이미 적용돼 있음. 반영 안 됨. +- 런타임에 `trayIcon.ToolTipText` 재할당 (`ForceCreate` 전/후 모두 시도). 값은 .NET property 레벨에서 변경되나 Windows shell 의 NOTIFYICONDATA 에는 반영 안 됨. +- `UpdateToolTip()` 메서드 호출 시도 — public API 에 노출되지 않음 (reflection 으로 메서드 목록 조사 완료, `UpdateIcon` 만 존재). +- NuGet 1.8.260508005 → 1.8.250907003 다운그레이드 — 효과 없음. +- Explorer.exe 재시작 (tray cache flush) — 효과 없음. +- Ghost 패키지 (`ScratchFoundation.1711508CFD202 1.0.0.0`) 제거 — 다른 이슈 해결됐으나 tooltip 영향 없음. + +### 추정 원인 +`H.NotifyIcon.WinUI` 2.0.108 의 ToolTipText property setter 가 Shell_NotifyIcon(NIM_MODIFY) 호출 시 `NIF_TIP` 플래그를 누락하거나, NIM_MODIFY 자체를 보내지 않는 라이브러리 버그. + +### 출하 영향 +**출하 차단 안 함**. 학원/학교 사용자에게 보이는 화면 (트레이 아이콘 우클릭 메뉴) 은 정상 동작하며, 메뉴의 첫 항목이 "AluxLabs Link " 으로 표시되어 식별 가능. + +### 향후 검토 +- H.NotifyIcon.WinUI 2.x 의 더 새 버전 (2.0.110 이후) 시도 — 1809 호환 유지 확인 필수 +- 라이브러리 교체 (H.NotifyIcon 의 `TrayToolTip` element 사용 또는 P/Invoke Shell_NotifyIcon 직접 호출) +- 사용자 피드백이 명시적으로 요구하지 않으면 우선순위 낮음 + +--- + +## 2. MSIX packaged 모드에서 시작 시 즉시 크래시 (Win11 25H2 특이성 추정) + +### 증상 +MSIX 로 packaged install 후 시작 메뉴에서 실행 시 트레이 아이콘이 등장하지 않고 즉시 종료. Event Log 에 다음 정보: + +``` +Faulting application: AluxLabs Link.exe v1.0.0.x +Faulting module: Microsoft.UI.Xaml.dll v3.1.8.0 (번들된 DLL) +Exception: 0xc000027b (STATUS_FATAL_USER_CALLBACK_EXCEPTION) +WER P5: combase.dll +WER P8: 0x80040111 (REGDB_E_CLASSNOTREG) +``` + +### 영향 범위 +- 개발 PC: Windows 11 25H2 build 26200 — 크래시 재현 +- 정상 PC 에서의 packaged install 검증 미완료 (cert 신뢰 단계에서 막혀 실제 install 까지 못 감) +- **Unpackaged 형태 (F5 / Release portable EXE) 는 정상 동작 — 정상 PC 와 dev PC 모두에서 검증됨** + +### 추정 원인 +WinUI 3 self-contained 패키징의 알려진 한계 — XAML metadata / COM 클래스 등록의 일부가 시스템 레지스트리에 의존. 번들된 DLL 의 클래스를 활성화하려 할 때 시스템 레지스트리에서 매칭되는 항목을 못 찾아 `REGDB_E_CLASSNOTREG` 발생. + +Windows 11 25H2 (build 26200) 의 특이성일 가능성도 배제 못 함. 동일 build 의 정상 PC 검증 미완. + +### 시도한 해결책 +- NuGet WindowsAppSDK 1.8.260508005 → 1.8.250907003 다운그레이드: 동일 크래시 (timestamp 만 바뀜) +- self-contained 활성화 (`true`, `true` in pubxml): 같은 크래시 +- Ghost 패키지 (`ScratchFoundation.1711508CFD202`) 제거: 원본 Scratch Link 설치 문제는 해결됐으나 우리 빌드의 크래시는 별개 +- .NET 6 + WAS 1.3 으로 stack 회귀 시도: **빌드 환경 비호환** — 옛 WAS NuGet 의 build target 이 .NET 10 SDK + VS 2026 (v18.0) 환경의 path 와 매칭 안 됨. WAS 1.5, 1.6 도 동일 결과. + +### 출하 영향 +- **Portable EXE 배포 (MSIX 없이) → 영향 없음** (검증 완료) +- **MSIX 사이드로드 배포 → 위험** (이 이슈 미해결 시 사용자 PC 에서도 같은 크래시 가능성) +- **MS Store 배포 → 미검증** (Partner Center 심사 환경에서 실행 시도 → 거기서 결과 판명) + +### 향후 검토 +1. 정상 PC 에서 우리 .msixbundle 의 진짜 install + 실행 검증 (cert 수동 import 통과 후) +2. 동일 build 의 다른 OS (24H2, Win10 22H2) 에서 검증 +3. 위 결과에 따라: + - 정상 PC 에서 동작 → dev PC 25H2 특이성 확정, 일반 사용자엔 OK + - 정상 PC 에서도 크래시 → 우리 빌드의 packaged 모드 호환 문제, 더 깊은 디버그 필요 + +--- + +## 3. Ghost 패키지로 인한 원본 Scratch Link 설치 차단 (해결됨) + +### 증상 +개발 PC 에서 MS Store 에서 원본 Scratch Link 설치 시도 시 실패. 정상 PC 에서는 정상. + +### 원인 +리브랜드 이전에 빌드/배포된 옛 fork 버전이 원본의 `ScratchFoundation.1711508CFD202` Identity 로 dev PC 에 등록돼 있었음. 자체 서명 cert 로 서명된 그 ghost 가 MS-signed 정식 release 의 install 을 Identity name 충돌로 차단. + +### 해결 +```powershell +Get-AppxPackage -AllUsers *ScratchFoundation* | Remove-AppxPackage -AllUsers +``` + +리브랜드 commit `53bfd57` (MSIX Package Identity → `ALUXInc.AluxLabsLink`) 이후로는 새 빌드가 이 Identity 를 더 이상 사용하지 않으므로 같은 문제 재발하지 않음. + +### 출하 영향 +없음. 과거 dev install 의 환경 정리 이슈로 해결됨. + +--- + +## 4. 검증된 사실 — 출하 결정 시 신뢰 가능 + +| 항목 | 상태 | +|---|---| +| 리브랜드 (식별자/이름/manifest/네임스페이스/폴더/문서) | ✅ 완료 (commit `7684c1c` 까지) | +| MSIX Identity 충돌 (Publisher CN, ScratchFoundation 잔존) | ✅ 해결 (commit `7e9f28b`) | +| Self-contained pubxml 설정 | ✅ 적용 (commit `5209ce6`) | +| Release self-contained portable EXE 빌드 | ✅ 성공 (`dotnet publish -c Release_Win -r win-x64 --self-contained true`) | +| Portable EXE 동작 (dev PC, Win11 25H2) | ✅ 트레이 정상 등장 | +| Portable EXE 동작 (정상 PC, Win11 25H2) | ✅ 트레이 정상 등장 | +| Tooltip 동작 (unpackaged) | ❌ Issue #1 deferred | +| MSIX install + 실행 (dev PC) | ❌ Issue #2 — 정상 PC 미검증 | + +--- + +## 5. 출하 형식 결정용 비교 + +| 출하 형식 | 1809 호환 | 코드 서명 | 사용자 UX | 현재 검증 상태 | +|---|---|---|---|---| +| Portable EXE + ZIP | ✓ | ⚠️ EXE 직접 서명 가능 | 압축 풀고 실행 (시작 메뉴 등록 X) | ✅ 동작 확인 | +| Inno Setup / NSIS installer | ✓ | ✓ 표준 .exe 서명 | "다음 → 완료" 마법사 | 미시도 | +| MSIX 사이드로드 | ✓ (이론) | ✓ 자체 cert 또는 EV/OV | 자체 서명 cert 신뢰 등록 필요 | Issue #2 미해결 | +| MS Store | ✓ | MS 가 자동 서명 | Store 에서 "Install" 한 번 | 미등록 | + +### 권장 출하 path +1. **단기 (학원 직배포)**: 코드 서명된 Inno Setup installer — Issue #2 우회, 가장 안정. **MSIX 의 알려진 한계 회피**. +2. **중기 (대규모 보급)**: MS Store 등록 검토 — MS 가 서명/runtime/업데이트 자동 처리. Issue #2 의 실제 영향은 Store 심사 단계에서 결과 확정. +3. **소규모 dev/베타**: Portable ZIP — 임시 검증용 + +--- + +## 6. 회귀 시도 (실패) — 향후 같은 시도 반복 방지 + +`.NET 8` + `WindowsAppSDK 1.8` stack 을 원본 `.NET 6` + `WindowsAppSDK 1.3` 으로 회귀 시도했으나 다음 이유로 빌드 자체 실패: + +- 옛 `Microsoft.WindowsAppSDK` NuGet (1.3, 1.5, 1.6 모두) 의 `MrtCore.PriGen.targets` 가 `Microsoft\VisualStudio\v17.0\AppxPackage\Microsoft.Build.Packaging.Pri.Tasks.dll` 경로를 가정하는데, 우리 환경 (.NET 10 SDK 10.0.300 + VS 2026 build 18.0) 의 실제 path 구조와 불일치. +- 진짜 stack 회귀하려면 **빌드 환경까지 회귀** (VS 2022 설치 + .NET 6 SDK 강제) 가 필요. 작업량 크고 다른 호환성 이슈 사슬 가능성. + +따라서 stack 회귀는 **포기**. 현재 `.NET 8` + `WindowsAppSDK 1.8.260508005` stack 으로 출하 형식을 결정하는 방향. + +--- + +## 7. 미커밋 변경 (회귀 시도) — 모두 revert 완료 + +본 문서 작성 시점 (commit `5209ce6` 직후) 에 회귀 시도로 한 다음 변경들은 **모두 `git restore .` 로 revert** 했다. 작업 트리 clean 상태: + +- `SharedProps/WindowsSDK.props`: WAS 1.8 → 1.3/1.5/1.6 (revert) +- `aluxlabs-link-win/aluxlabs-link-win.csproj`: net8.0 → net6.0, RuntimeIdentifiers win10- prefix (revert) +- 3 pubxml: self-contained=false (revert) +- `aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj`: AssetTargetFallback net6.0 (revert) + +git log 에 이 회귀 시도는 흔적 남지 않음. From 07a95d637b554281b6bb198314a35656fd66944f Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 May 2026 10:51:51 +0900 Subject: [PATCH 64/94] =?UTF-8?q?fix(serial):=20keep-alive=20RX-stall=20?= =?UTF-8?q?=EA=B0=80=EB=93=9C=EB=A1=9C=20BLE=20=EB=81=8A=EA=B9=80=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=20=EC=88=98=EC=8B=A0=20=EB=B3=B4=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 동글이 PC 명령 처리 중엔 BLE 자체 알림 송신을 후순위로 두는 동작 때문에 33 ms keep-alive가 BLE DISCONNECT(18B "d7 7d 0e ... BLE DISCONNECT") 송신 윈도우를 영구 차단하던 문제 해결. OnKeepAliveTick에 가드 3단계 추가: - RX-stall(>500 ms): RX 정지 감지 시 keep-alive 일시 정지 → 동글에 idle 윈도우 제공 - RX-yield(<200 ms): 진행 중 RX 보호. TX 후 900 ms 한도로 1초 device timeout 회피 - StartKeepAlive에서 RX/TX/KA timestamp seed → 첫 tick에서 stall 가드 오발동 방지 Co-Authored-By: Claude Opus 4.7 (1M context) --- scratch-link-common/Serial/SerialSession.cs | 46 +++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/scratch-link-common/Serial/SerialSession.cs b/scratch-link-common/Serial/SerialSession.cs index be43c4f3..d0722e6c 100644 --- a/scratch-link-common/Serial/SerialSession.cs +++ b/scratch-link-common/Serial/SerialSession.cs @@ -26,6 +26,16 @@ namespace ScratchLink.Serial; internal abstract class SerialSession : PeripheralSession where TPort : class { + // Yield keep-alive while RX is active so the peripheral can finish unsolicited notifications (e.g. BLE link-loss). + private const int KeepAliveRxYieldMs = 200; + + // Force keep-alive once the client has been idle this long, even if RX is still flowing, to stay under the device's 1 s RX timeout. + private const int KeepAliveTxIdleMs = 900; + + // Pause keep-alive once RX has stalled this long. Dongles defer BLE link-loss notifications while servicing PC commands; + // pausing gives the dongle the idle window it needs to push the notification. + private const int KeepAliveRxStallMs = 500; + // Serializes DoWrite calls so two writes never overlap and corrupt the stream. private readonly SemaphoreSlim writeSemaphore = new SemaphoreSlim(1, 1); @@ -37,6 +47,11 @@ internal abstract class SerialSession : PeripheralSession private int keepAliveIntervalMs; private bool keepAliveActive; + // 64-bit timestamps in DateTime.UtcNow.Ticks; accessed via Interlocked to keep reads/writes atomic on 32-bit runtimes. + private long lastRxTicks; + private long lastClientTxTicks; + private long lastKeepAliveSentTicks; + // volatile so threads outside stateLock see the latest value on the hot path. private volatile bool wireTrace; @@ -129,6 +144,7 @@ protected async Task HandleWrite(string methodName, JsonElement? args) this.lastSentData = buffer; } + Interlocked.Exchange(ref this.lastClientTxTicks, DateTime.UtcNow.Ticks); this.ResetKeepAliveTimer(); if (this.wireTrace) @@ -272,6 +288,8 @@ protected async Task HandleTriggerDTRReset(string methodName, JsonElemen /// A representing the asynchronous operation. protected async Task DidReceiveData(byte[] data) { + Interlocked.Exchange(ref this.lastRxTicks, DateTime.UtcNow.Ticks); + if (this.wireTrace) { Trace.WriteLine($"wire-trace RX {data.Length}B {FormatHex(data)}"); @@ -342,6 +360,13 @@ protected void StartKeepAlive(int? keepAliveIntervalMs) var interval = keepAliveIntervalMs.Value; + // Seed timestamps to "now" so the first tick doesn't see zero-initialized fields as ancient activity + // (which would otherwise mis-trigger the RX-stall guard before any RX has arrived). + var nowTicks = DateTime.UtcNow.Ticks; + Interlocked.Exchange(ref this.lastRxTicks, nowTicks); + Interlocked.Exchange(ref this.lastClientTxTicks, nowTicks); + Interlocked.Exchange(ref this.lastKeepAliveSentTicks, nowTicks); + lock (this.stateLock) { if (this.keepAliveActive) @@ -528,6 +553,26 @@ private async void OnKeepAliveTick(object state) return; } + // msSinceAnyTx tracks "any TX we issued recently" — client write OR previous keep-alive — so a single forced + // keep-alive resets the budget instead of unlocking the 33 ms cadence permanently. + var nowTicks = DateTime.UtcNow.Ticks; + var msSinceRx = (nowTicks - Interlocked.Read(ref this.lastRxTicks)) / TimeSpan.TicksPerMillisecond; + var msSinceClientTx = (nowTicks - Interlocked.Read(ref this.lastClientTxTicks)) / TimeSpan.TicksPerMillisecond; + var msSinceKeepAlive = (nowTicks - Interlocked.Read(ref this.lastKeepAliveSentTicks)) / TimeSpan.TicksPerMillisecond; + var msSinceAnyTx = Math.Min(msSinceClientTx, msSinceKeepAlive); + + // RX stalled too long: peripheral is silent (likely BLE link loss). Pause so the dongle can push its notification. + if (msSinceRx > KeepAliveRxStallMs) + { + return; + } + + // Yield to in-flight RX so we don't trample its TX window; capped by KeepAliveTxIdleMs to stay under the ~1 s device timeout. + if (msSinceRx < KeepAliveRxYieldMs && msSinceAnyTx < KeepAliveTxIdleMs) + { + return; + } + // WaitAsync(0) makes the tick idle-only: during a write burst the semaphore is busy and we no-op. if (!await this.writeSemaphore.WaitAsync(0).ConfigureAwait(false)) { @@ -547,6 +592,7 @@ private async void OnKeepAliveTick(object state) } await this.DoWrite(data).ConfigureAwait(false); + Interlocked.Exchange(ref this.lastKeepAliveSentTicks, DateTime.UtcNow.Ticks); } catch (ObjectDisposedException) { From 8d6991b6e0fbc0d9f4e4638eeb1c325b11ed771f Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 May 2026 11:26:27 +0900 Subject: [PATCH 65/94] =?UTF-8?q?refactor(rebrand):=20aluxlabs-link-*=20?= =?UTF-8?q?=EB=82=B4=EB=B6=80=20=EC=9E=94=EC=97=AC=20"Scratch=20Link"=20?= =?UTF-8?q?=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit XML doc summary 및 CLAUDE.md 헤더에 남아 있던 "Scratch Link" 표기를 "AluxLabs Link"로 통일. 식별자/카피라이트 헤더는 변경 대상이 아님. - CLAUDE.md: 헤더 "AluxCoding Scratch Link" → "AluxLabs Link" - AluxLabsLinkApp.cs: summary 4건 - Session.cs: summary 2건 - EncodingHelpers.cs: summary 2건 - BLE/BLESession.cs: summary 1건 Serial/*.cs 파일 헤더의 "// Based on scratch-link by Scratch Foundation" 주석은 fork 출처 표기로 의도적 보존. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 2 +- aluxlabs-link-common/AluxLabsLinkApp.cs | 8 ++++---- aluxlabs-link-common/BLE/BLESession.cs | 2 +- aluxlabs-link-common/EncodingHelpers.cs | 4 ++-- aluxlabs-link-common/Session.cs | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4d718d62..893270c0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,4 +1,4 @@ -# AluxCoding Scratch Link — Claude 행동 규칙 +# AluxLabs Link — Claude 행동 규칙 Windows-only desktop app. Scratch 3.0 ↔ 하드웨어(BLE, Bluetooth Classic, USB Serial) 중계. C# / .NET 8 + WinUI 3, Visual Studio Solution. diff --git a/aluxlabs-link-common/AluxLabsLinkApp.cs b/aluxlabs-link-common/AluxLabsLinkApp.cs index dd8d5c8d..ad7c0f64 100644 --- a/aluxlabs-link-common/AluxLabsLinkApp.cs +++ b/aluxlabs-link-common/AluxLabsLinkApp.cs @@ -10,7 +10,7 @@ namespace AluxLabs.Link; using AluxLabs.Link.BLE; /// -/// Main entry point for Scratch Link and central service provider for dependency injection. +/// Main entry point for AluxLabs Link and central service provider for dependency injection. /// public class AluxLabsLinkApp { @@ -67,7 +67,7 @@ public void Quit() } /// - /// Builds a Scratch Link app instance. + /// Builds an AluxLabs Link app instance. /// Fills the role of the .NET generic host or MauiAppBuilder. /// public class Builder @@ -110,9 +110,9 @@ internal void SetGattHelpers() } /// - /// Builds a Scratch Link app host. + /// Builds an AluxLabs Link app host. /// - /// A new Scratch Link app host. + /// A new AluxLabs Link app host. internal AluxLabsLinkApp Build() { var serviceCollection = new ServiceCollection(); diff --git a/aluxlabs-link-common/BLE/BLESession.cs b/aluxlabs-link-common/BLE/BLESession.cs index 7b45c1c4..2acffa7d 100644 --- a/aluxlabs-link-common/BLE/BLESession.cs +++ b/aluxlabs-link-common/BLE/BLESession.cs @@ -49,7 +49,7 @@ public BLESession(IWebSocketConnection webSocket) /// /// Gets the set of services which are allowed based on discovery filters. - /// See Scratch Link protocol documentation. + /// See AluxLabs Link protocol documentation. /// protected HashSet AllowedServices { get; } diff --git a/aluxlabs-link-common/EncodingHelpers.cs b/aluxlabs-link-common/EncodingHelpers.cs index a0539fc2..99f50fbc 100644 --- a/aluxlabs-link-common/EncodingHelpers.cs +++ b/aluxlabs-link-common/EncodingHelpers.cs @@ -11,8 +11,8 @@ namespace AluxLabs.Link; using AluxLabs.Link.JsonRpc; /// -/// Helpers for interacting with Scratch Link's message buffers. -/// A Scratch Link message buffer has a message property and optionally an encoding property. +/// Helpers for interacting with AluxLabs Link's message buffers. +/// An AluxLabs Link message buffer has a message property and optionally an encoding property. /// If the encoding property is missing, null, or empty, the message is a Unicode string. /// If the encoding property is "base64" then the message is a string in Base64 format. /// No other encodings are supported at this time. diff --git a/aluxlabs-link-common/Session.cs b/aluxlabs-link-common/Session.cs index 807848a5..b855ce99 100644 --- a/aluxlabs-link-common/Session.cs +++ b/aluxlabs-link-common/Session.cs @@ -25,12 +25,12 @@ namespace AluxLabs.Link; using RequestId = System.UInt32; /// -/// Base class for Scratch Link sessions. +/// Base class for AluxLabs Link sessions. /// public class Session : IDisposable { /// - /// Specifies the Scratch Link network protocol version. Note that this is not the application version. + /// Specifies the AluxLabs Link network protocol version. Note that this is not the application version. /// Keep this in sync with the version number in `NetworkProtocol.md`. /// protected const string NetworkProtocolVersion = "1.3"; From 0684691f619d59e09c2a0f573be25f0da5af3bff Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 May 2026 11:30:58 +0900 Subject: [PATCH 66/94] =?UTF-8?q?refactor(rebrand):=20scratch-link=20MAUI?= =?UTF-8?q?=20=ED=8F=B4=EB=8D=94=EB=A5=BC=20aluxlabs-link=20=EB=A1=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=84=A4=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 미사용 MAUI 실험 프로젝트 폴더와 csproj 를 새 브랜드 이름으로 통일. 솔루션 미등록 상태로 빌드 영향은 없으나, 향후 재활용 시 혼동을 막기 위해 폴더/파일명/식별자를 다른 프로젝트와 동일 패턴으로 정리. - 폴더: scratch-link/ → aluxlabs-link/ - 프로젝트: scratch-link.csproj → aluxlabs-link.csproj - C# namespace: ScratchLink[.*] → AluxLabs.Link[.*] - 클래스 참조: ScratchLinkApp → AluxLabsLinkApp - csproj: RootNamespace, ApplicationTitle, ApplicationId 갱신 - Package.appxmanifest: DisplayName / Publisher / PublisherDisplayName 통일 - app.manifest: assemblyIdentity name - MacCatalyst Info.plist: CFBundleIdentifier, CFBundleName MacCatalyst 빌드 검증은 후순위 (사용자 정책). Co-Authored-By: Claude Opus 4.7 (1M context) --- {scratch-link => aluxlabs-link}/MainPage.xaml | 2 +- {scratch-link => aluxlabs-link}/MainPage.xaml.cs | 2 +- {scratch-link => aluxlabs-link}/MauiProgram.cs | 4 ++-- .../Platforms/MacCatalyst/AppDelegate.cs | 8 ++++---- .../Platforms/MacCatalyst/Info.plist | 4 ++-- .../Platforms/MacCatalyst/Program.cs | 2 +- .../Platforms/Windows/App.xaml | 4 ++-- .../Platforms/Windows/App.xaml.cs | 4 ++-- .../Platforms/Windows/Package.appxmanifest | 12 ++++++------ .../Platforms/Windows/WinBLESession.cs | 2 +- .../Platforms/Windows/WinGattHelpers.cs | 2 +- .../Platforms/Windows/WindowsSessionManager.cs | 2 +- .../Platforms/Windows/app.manifest | 2 +- .../Properties/launchSettings.json | 0 .../Resources/Fonts/OpenSans-Regular.ttf | Bin .../Resources/Images/dotnet_bot.svg | 0 .../Resources/Raw/AboutAssets.txt | 0 .../Resources/Strings/AppResource.Designer.cs | 4 ++-- .../Resources/Strings/AppResource.resx | 0 .../Resources/appicon.svg | 0 .../Resources/appiconfg.svg | 0 .../aluxlabs-link.csproj | 6 +++--- 22 files changed, 30 insertions(+), 30 deletions(-) rename {scratch-link => aluxlabs-link}/MainPage.xaml (97%) rename {scratch-link => aluxlabs-link}/MainPage.xaml.cs (96%) rename {scratch-link => aluxlabs-link}/MauiProgram.cs (91%) rename {scratch-link => aluxlabs-link}/Platforms/MacCatalyst/AppDelegate.cs (88%) rename {scratch-link => aluxlabs-link}/Platforms/MacCatalyst/Info.plist (89%) rename {scratch-link => aluxlabs-link}/Platforms/MacCatalyst/Program.cs (96%) rename {scratch-link => aluxlabs-link}/Platforms/Windows/App.xaml (73%) rename {scratch-link => aluxlabs-link}/Platforms/Windows/App.xaml.cs (95%) rename {scratch-link => aluxlabs-link}/Platforms/Windows/Package.appxmanifest (87%) rename {scratch-link => aluxlabs-link}/Platforms/Windows/WinBLESession.cs (92%) rename {scratch-link => aluxlabs-link}/Platforms/Windows/WinGattHelpers.cs (92%) rename {scratch-link => aluxlabs-link}/Platforms/Windows/WindowsSessionManager.cs (94%) rename {scratch-link => aluxlabs-link}/Platforms/Windows/app.manifest (90%) rename {scratch-link => aluxlabs-link}/Properties/launchSettings.json (100%) rename {scratch-link => aluxlabs-link}/Resources/Fonts/OpenSans-Regular.ttf (100%) rename {scratch-link => aluxlabs-link}/Resources/Images/dotnet_bot.svg (100%) rename {scratch-link => aluxlabs-link}/Resources/Raw/AboutAssets.txt (100%) rename {scratch-link => aluxlabs-link}/Resources/Strings/AppResource.Designer.cs (94%) rename {scratch-link => aluxlabs-link}/Resources/Strings/AppResource.resx (100%) rename {scratch-link => aluxlabs-link}/Resources/appicon.svg (100%) rename {scratch-link => aluxlabs-link}/Resources/appiconfg.svg (100%) rename scratch-link/scratch-link.csproj => aluxlabs-link/aluxlabs-link.csproj (94%) diff --git a/scratch-link/MainPage.xaml b/aluxlabs-link/MainPage.xaml similarity index 97% rename from scratch-link/MainPage.xaml rename to aluxlabs-link/MainPage.xaml index 0744596d..d8b25aa4 100644 --- a/scratch-link/MainPage.xaml +++ b/aluxlabs-link/MainPage.xaml @@ -1,6 +1,6 @@ diff --git a/scratch-link/MainPage.xaml.cs b/aluxlabs-link/MainPage.xaml.cs similarity index 96% rename from scratch-link/MainPage.xaml.cs rename to aluxlabs-link/MainPage.xaml.cs index 5a9ac167..0dfdf151 100644 --- a/scratch-link/MainPage.xaml.cs +++ b/aluxlabs-link/MainPage.xaml.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink; +namespace AluxLabs.Link; /// /// This class holds the main UI for the application. diff --git a/scratch-link/MauiProgram.cs b/aluxlabs-link/MauiProgram.cs similarity index 91% rename from scratch-link/MauiProgram.cs rename to aluxlabs-link/MauiProgram.cs index c0d6703b..30d4bd87 100644 --- a/scratch-link/MauiProgram.cs +++ b/aluxlabs-link/MauiProgram.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink; +namespace AluxLabs.Link; /// /// This class hosts the cross-platform entry point. @@ -17,7 +17,7 @@ public static MauiAppBuilder CreateMauiAppBuilder() { var builder = MauiApp.CreateBuilder(); builder - .UseMauiApp() + .UseMauiApp() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); diff --git a/scratch-link/Platforms/MacCatalyst/AppDelegate.cs b/aluxlabs-link/Platforms/MacCatalyst/AppDelegate.cs similarity index 88% rename from scratch-link/Platforms/MacCatalyst/AppDelegate.cs rename to aluxlabs-link/Platforms/MacCatalyst/AppDelegate.cs index 71586c65..b0149c0c 100644 --- a/scratch-link/Platforms/MacCatalyst/AppDelegate.cs +++ b/aluxlabs-link/Platforms/MacCatalyst/AppDelegate.cs @@ -2,13 +2,13 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink; +namespace AluxLabs.Link; using CoreBluetooth; using Foundation; -using ScratchLink.BLE; -using ScratchLink.Platforms.MacCatalyst; -using ScratchLink.Platforms.MacCatalyst.BLE; +using AluxLabs.Link.BLE; +using AluxLabs.Link.Platforms.MacCatalyst; +using AluxLabs.Link.Platforms.MacCatalyst.BLE; /// /// The AppDelegate connects UIApplication to MauiApp on MacCatalyst. diff --git a/scratch-link/Platforms/MacCatalyst/Info.plist b/aluxlabs-link/Platforms/MacCatalyst/Info.plist similarity index 89% rename from scratch-link/Platforms/MacCatalyst/Info.plist rename to aluxlabs-link/Platforms/MacCatalyst/Info.plist index 3fb180e5..397a0361 100644 --- a/scratch-link/Platforms/MacCatalyst/Info.plist +++ b/aluxlabs-link/Platforms/MacCatalyst/Info.plist @@ -9,12 +9,12 @@ NSBluetoothAlwaysUsageDescription TODO: Info.plist NSBluetoothAlwaysUsageDescription CFBundleIdentifier - edu.mit.scratch.scratch-link + com.aluxlabs.link LSMinimumSystemVersion 10.15 CFBundleVersion 1 CFBundleName - Scratch Link + AluxLabs Link diff --git a/scratch-link/Platforms/MacCatalyst/Program.cs b/aluxlabs-link/Platforms/MacCatalyst/Program.cs similarity index 96% rename from scratch-link/Platforms/MacCatalyst/Program.cs rename to aluxlabs-link/Platforms/MacCatalyst/Program.cs index 5382d5ae..f6ab1a5a 100644 --- a/scratch-link/Platforms/MacCatalyst/Program.cs +++ b/aluxlabs-link/Platforms/MacCatalyst/Program.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink; +namespace AluxLabs.Link; using ObjCRuntime; using UIKit; diff --git a/scratch-link/Platforms/Windows/App.xaml b/aluxlabs-link/Platforms/Windows/App.xaml similarity index 73% rename from scratch-link/Platforms/Windows/App.xaml rename to aluxlabs-link/Platforms/Windows/App.xaml index 8052c897..273c9bd9 100644 --- a/scratch-link/Platforms/Windows/App.xaml +++ b/aluxlabs-link/Platforms/Windows/App.xaml @@ -1,8 +1,8 @@  + xmlns:local="using:AluxLabs.Link.WinUI"> diff --git a/scratch-link/Platforms/Windows/App.xaml.cs b/aluxlabs-link/Platforms/Windows/App.xaml.cs similarity index 95% rename from scratch-link/Platforms/Windows/App.xaml.cs rename to aluxlabs-link/Platforms/Windows/App.xaml.cs index 65055e17..6c0f34f4 100644 --- a/scratch-link/Platforms/Windows/App.xaml.cs +++ b/aluxlabs-link/Platforms/Windows/App.xaml.cs @@ -4,9 +4,9 @@ // To learn more about WinUI, the WinUI project structure, // and more about our project templates, see: http://aka.ms/winui-project-info. -namespace ScratchLink.WinUI; +namespace AluxLabs.Link.WinUI; -using ScratchLink.Platforms.Windows; +using AluxLabs.Link.Platforms.Windows; /// /// Provides application-specific behavior to supplement the default Application class. diff --git a/scratch-link/Platforms/Windows/Package.appxmanifest b/aluxlabs-link/Platforms/Windows/Package.appxmanifest similarity index 87% rename from scratch-link/Platforms/Windows/Package.appxmanifest rename to aluxlabs-link/Platforms/Windows/Package.appxmanifest index 7c7717b4..e78325f3 100644 --- a/scratch-link/Platforms/Windows/Package.appxmanifest +++ b/aluxlabs-link/Platforms/Windows/Package.appxmanifest @@ -8,12 +8,12 @@ - scratch-link - Microsoft + AluxLabs Link + ALUX, Inc. appiconStoreLogo.png @@ -31,8 +31,8 @@ Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$"> @@ -40,7 +40,7 @@ Wide310x150Logo="appiconWideTile.png" Square71x71Logo="appiconSmallTile.png" Square310x310Logo="appiconLargeTile.png" - ShortName="scratch-link"> + ShortName="AluxLabs Link"> diff --git a/scratch-link/Platforms/Windows/WinBLESession.cs b/aluxlabs-link/Platforms/Windows/WinBLESession.cs similarity index 92% rename from scratch-link/Platforms/Windows/WinBLESession.cs rename to aluxlabs-link/Platforms/Windows/WinBLESession.cs index fb72f066..f7bdf724 100644 --- a/scratch-link/Platforms/Windows/WinBLESession.cs +++ b/aluxlabs-link/Platforms/Windows/WinBLESession.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Platforms.Windows; +namespace AluxLabs.Link.Platforms.Windows; using System.Net.WebSockets; diff --git a/scratch-link/Platforms/Windows/WinGattHelpers.cs b/aluxlabs-link/Platforms/Windows/WinGattHelpers.cs similarity index 92% rename from scratch-link/Platforms/Windows/WinGattHelpers.cs rename to aluxlabs-link/Platforms/Windows/WinGattHelpers.cs index 51c35010..21b19add 100644 --- a/scratch-link/Platforms/Windows/WinGattHelpers.cs +++ b/aluxlabs-link/Platforms/Windows/WinGattHelpers.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Platforms.Windows; +namespace AluxLabs.Link.Platforms.Windows; using System; diff --git a/scratch-link/Platforms/Windows/WindowsSessionManager.cs b/aluxlabs-link/Platforms/Windows/WindowsSessionManager.cs similarity index 94% rename from scratch-link/Platforms/Windows/WindowsSessionManager.cs rename to aluxlabs-link/Platforms/Windows/WindowsSessionManager.cs index 0694834f..287eea9b 100644 --- a/scratch-link/Platforms/Windows/WindowsSessionManager.cs +++ b/aluxlabs-link/Platforms/Windows/WindowsSessionManager.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Platforms.Windows; +namespace AluxLabs.Link.Platforms.Windows; using System.Net.WebSockets; diff --git a/scratch-link/Platforms/Windows/app.manifest b/aluxlabs-link/Platforms/Windows/app.manifest similarity index 90% rename from scratch-link/Platforms/Windows/app.manifest rename to aluxlabs-link/Platforms/Windows/app.manifest index e24770a4..cdd4675b 100644 --- a/scratch-link/Platforms/Windows/app.manifest +++ b/aluxlabs-link/Platforms/Windows/app.manifest @@ -1,6 +1,6 @@ - + diff --git a/scratch-link/Properties/launchSettings.json b/aluxlabs-link/Properties/launchSettings.json similarity index 100% rename from scratch-link/Properties/launchSettings.json rename to aluxlabs-link/Properties/launchSettings.json diff --git a/scratch-link/Resources/Fonts/OpenSans-Regular.ttf b/aluxlabs-link/Resources/Fonts/OpenSans-Regular.ttf similarity index 100% rename from scratch-link/Resources/Fonts/OpenSans-Regular.ttf rename to aluxlabs-link/Resources/Fonts/OpenSans-Regular.ttf diff --git a/scratch-link/Resources/Images/dotnet_bot.svg b/aluxlabs-link/Resources/Images/dotnet_bot.svg similarity index 100% rename from scratch-link/Resources/Images/dotnet_bot.svg rename to aluxlabs-link/Resources/Images/dotnet_bot.svg diff --git a/scratch-link/Resources/Raw/AboutAssets.txt b/aluxlabs-link/Resources/Raw/AboutAssets.txt similarity index 100% rename from scratch-link/Resources/Raw/AboutAssets.txt rename to aluxlabs-link/Resources/Raw/AboutAssets.txt diff --git a/scratch-link/Resources/Strings/AppResource.Designer.cs b/aluxlabs-link/Resources/Strings/AppResource.Designer.cs similarity index 94% rename from scratch-link/Resources/Strings/AppResource.Designer.cs rename to aluxlabs-link/Resources/Strings/AppResource.Designer.cs index 161bc19a..b989ea38 100644 --- a/scratch-link/Resources/Strings/AppResource.Designer.cs +++ b/aluxlabs-link/Resources/Strings/AppResource.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace ScratchLink.Resources.Strings { +namespace AluxLabs.Link.Resources.Strings { using System; @@ -39,7 +39,7 @@ internal AppResource() { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ScratchLink.Resources.Strings.AppResource", typeof(AppResource).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AluxLabs.Link.Resources.Strings.AppResource", typeof(AppResource).Assembly); resourceMan = temp; } return resourceMan; diff --git a/scratch-link/Resources/Strings/AppResource.resx b/aluxlabs-link/Resources/Strings/AppResource.resx similarity index 100% rename from scratch-link/Resources/Strings/AppResource.resx rename to aluxlabs-link/Resources/Strings/AppResource.resx diff --git a/scratch-link/Resources/appicon.svg b/aluxlabs-link/Resources/appicon.svg similarity index 100% rename from scratch-link/Resources/appicon.svg rename to aluxlabs-link/Resources/appicon.svg diff --git a/scratch-link/Resources/appiconfg.svg b/aluxlabs-link/Resources/appiconfg.svg similarity index 100% rename from scratch-link/Resources/appiconfg.svg rename to aluxlabs-link/Resources/appiconfg.svg diff --git a/scratch-link/scratch-link.csproj b/aluxlabs-link/aluxlabs-link.csproj similarity index 94% rename from scratch-link/scratch-link.csproj rename to aluxlabs-link/aluxlabs-link.csproj index 284a7448..20f5a270 100644 --- a/scratch-link/scratch-link.csproj +++ b/aluxlabs-link/aluxlabs-link.csproj @@ -4,16 +4,16 @@ net6.0-maccatalyst $(TargetFrameworks);net6.0-windows10.0.19041.0 Exe - ScratchLink + AluxLabs.Link true true enable - scratch-link + AluxLabs Link - com.companyname.scratch_link + com.aluxlabs.aluxlabs_link FE66BC68-E1DD-4401-AD63-28B130B5C86B From 2484d6be5db61127bbb1d5f296be71b2d2abc419 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 May 2026 11:37:30 +0900 Subject: [PATCH 67/94] =?UTF-8?q?refactor(rebrand):=20scratch-link-mac=20?= =?UTF-8?q?=ED=8F=B4=EB=8D=94=EB=A5=BC=20aluxlabs-link-mac=20=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=A6=AC=EB=84=A4=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 폴더·csproj·namespace·번들 식별자·문서 전반을 AluxLabs Link 브랜드로 통일. macOS/Xamarin.Mac 빌드 환경은 현재 미보유 상태이므로 실제 빌드/실행 검증은 향후 macOS 환경 확보 시 후속 작업으로 진행한다. - 폴더: scratch-link-mac/ → aluxlabs-link-mac/ - 프로젝트: scratch-link-mac.csproj → aluxlabs-link-mac.csproj - C# namespace: ScratchLink.Mac[.*] → AluxLabs.Link.Mac[.*] - 클래스 참조: ScratchLinkApp → AluxLabsLinkApp - csproj: RootNamespace, AssemblyName, DocumentationFile, projitems import 경로 - Info.plist: CFBundleName, CFBundleIdentifier - Entitlements.plist: application-identifier (team-identifier 는 유지) - AppDelegate: ExtensionBundleIdentifier - OSLogTraceListener: LogSubsystem - BundleInfo: defaultTitle - README.md: 제품명 표기 - aluxlabs-link.sln: mac 프로젝트 경로/이름 갱신 Safari Helper 폴더 경로 및 fastlane provisionprofile 경로는 각각 Step 5(Safari 리네임), Step 4(빌드/CI 메타 정리)에서 함께 처리하기 위해 의도적으로 보류. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../AppDelegate.cs | 12 ++++++------ .../AppIcon.appiconset/AppIcon-128.png | Bin .../AppIcon.appiconset/AppIcon-128@2x.png | Bin .../AppIcon.appiconset/AppIcon-16.png | Bin .../AppIcon.appiconset/AppIcon-16@2x.png | Bin .../AppIcon.appiconset/AppIcon-256.png | Bin .../AppIcon.appiconset/AppIcon-256@2x.png | Bin .../AppIcon.appiconset/AppIcon-32.png | Bin .../AppIcon.appiconset/AppIcon-32@2x.png | Bin .../AppIcon.appiconset/AppIcon-512.png | Bin .../AppIcon.appiconset/AppIcon-512@2x.png | Bin .../AppIcon.appiconset/Contents.json | 0 .../Assets.xcassets/Contents.json | 0 .../StatusBarIcon.iconset/icon_128x128.png | Bin .../StatusBarIcon.iconset/icon_128x128@2x.png | Bin .../StatusBarIcon.iconset/icon_16x16.png | Bin .../StatusBarIcon.iconset/icon_16x16@2x.png | Bin .../StatusBarIcon.iconset/icon_256x256.png | Bin .../StatusBarIcon.iconset/icon_256x256@2x.png | Bin .../StatusBarIcon.iconset/icon_32x32.png | Bin .../StatusBarIcon.iconset/icon_32x32@2x.png | Bin .../StatusBarIcon.iconset/icon_512x512.png | Bin .../StatusBarIcon.iconset/icon_512x512@2x.png | Bin .../BLE/CBCentralManagerEventDelegate.cs | 2 +- .../BLE/MacBLEEndpoint.cs | 4 ++-- .../BLE/MacBLESession.cs | 10 +++++----- .../BLE/MacGattHelpers.cs | 4 ++-- .../BT/MacBTSession.cs | 10 +++++----- .../BT/Rfcomm/RfcommChannelDataEventArgs.cs | 2 +- .../BT/Rfcomm/RfcommChannelEventArgs.cs | 2 +- .../BT/Rfcomm/RfcommChannelEventDelegate.cs | 2 +- .../Rfcomm/RfcommChannelOpenCompleteEventArgs.cs | 2 +- .../Rfcomm/RfcommChannelWriteCompleteEventArgs.cs | 2 +- .../BundleInfo.cs | 4 ++-- .../Entitlements.plist | 2 +- .../Extensions/DispatchQueueExtensions.cs | 2 +- .../Extensions/NSExtensions.cs | 2 +- .../IOReturn.cs | 2 +- .../Info.plist | 4 ++-- .../MacSessionManager.cs | 6 +++--- {scratch-link-mac => aluxlabs-link-mac}/Main.cs | 2 +- .../OSLogTraceListener.cs | 4 ++-- {scratch-link-mac => aluxlabs-link-mac}/README.md | 8 ++++---- .../aluxlabs-link-mac.csproj | 14 +++++++------- .../app.config | 0 .../notarize.sh | 0 aluxlabs-link.sln | 2 +- 47 files changed, 52 insertions(+), 52 deletions(-) rename {scratch-link-mac => aluxlabs-link-mac}/AppDelegate.cs (95%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/Contents.json (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/StatusBarIcon.iconset/icon_128x128.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/StatusBarIcon.iconset/icon_128x128@2x.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/StatusBarIcon.iconset/icon_16x16.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/StatusBarIcon.iconset/icon_16x16@2x.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/StatusBarIcon.iconset/icon_256x256.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/StatusBarIcon.iconset/icon_256x256@2x.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/StatusBarIcon.iconset/icon_32x32.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/StatusBarIcon.iconset/icon_32x32@2x.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/StatusBarIcon.iconset/icon_512x512.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/Assets.xcassets/StatusBarIcon.iconset/icon_512x512@2x.png (100%) rename {scratch-link-mac => aluxlabs-link-mac}/BLE/CBCentralManagerEventDelegate.cs (99%) rename {scratch-link-mac => aluxlabs-link-mac}/BLE/MacBLEEndpoint.cs (98%) rename {scratch-link-mac => aluxlabs-link-mac}/BLE/MacBLESession.cs (99%) rename {scratch-link-mac => aluxlabs-link-mac}/BLE/MacGattHelpers.cs (92%) rename {scratch-link-mac => aluxlabs-link-mac}/BT/MacBTSession.cs (98%) rename {scratch-link-mac => aluxlabs-link-mac}/BT/Rfcomm/RfcommChannelDataEventArgs.cs (92%) rename {scratch-link-mac => aluxlabs-link-mac}/BT/Rfcomm/RfcommChannelEventArgs.cs (92%) rename {scratch-link-mac => aluxlabs-link-mac}/BT/Rfcomm/RfcommChannelEventDelegate.cs (99%) rename {scratch-link-mac => aluxlabs-link-mac}/BT/Rfcomm/RfcommChannelOpenCompleteEventArgs.cs (93%) rename {scratch-link-mac => aluxlabs-link-mac}/BT/Rfcomm/RfcommChannelWriteCompleteEventArgs.cs (94%) rename {scratch-link-mac => aluxlabs-link-mac}/BundleInfo.cs (95%) rename {scratch-link-mac => aluxlabs-link-mac}/Entitlements.plist (91%) rename {scratch-link-mac => aluxlabs-link-mac}/Extensions/DispatchQueueExtensions.cs (98%) rename {scratch-link-mac => aluxlabs-link-mac}/Extensions/NSExtensions.cs (96%) rename {scratch-link-mac => aluxlabs-link-mac}/IOReturn.cs (97%) rename {scratch-link-mac => aluxlabs-link-mac}/Info.plist (93%) rename {scratch-link-mac => aluxlabs-link-mac}/MacSessionManager.cs (90%) rename {scratch-link-mac => aluxlabs-link-mac}/Main.cs (93%) rename {scratch-link-mac => aluxlabs-link-mac}/OSLogTraceListener.cs (90%) rename {scratch-link-mac => aluxlabs-link-mac}/README.md (50%) rename scratch-link-mac/scratch-link-mac.csproj => aluxlabs-link-mac/aluxlabs-link-mac.csproj (95%) rename {scratch-link-mac => aluxlabs-link-mac}/app.config (100%) rename {scratch-link-mac => aluxlabs-link-mac}/notarize.sh (100%) diff --git a/scratch-link-mac/AppDelegate.cs b/aluxlabs-link-mac/AppDelegate.cs similarity index 95% rename from scratch-link-mac/AppDelegate.cs rename to aluxlabs-link-mac/AppDelegate.cs index 353d5baa..d98a0560 100644 --- a/scratch-link-mac/AppDelegate.cs +++ b/aluxlabs-link-mac/AppDelegate.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac; +namespace AluxLabs.Link.Mac; using System; using System.Collections.Generic; @@ -12,16 +12,16 @@ namespace ScratchLink.Mac; using Foundation; using ObjCRuntime; using SafariServices; -using ScratchLink.Mac.BLE; +using AluxLabs.Link.Mac.BLE; /// -/// Scratch Link's implementation of the NSApplicationDelegate protocol. +/// AluxLabs Link's implementation of the NSApplicationDelegate protocol. /// [Register("AppDelegate")] public class AppDelegate : NSApplicationDelegate { // This identifier must match the PRODUCT_BUNDLE_IDENTIFIER setting for the extension's Xcode project - private const string ExtensionBundleIdentifier = "edu.mit.scratch.scratch-link.safari-extension"; + private const string ExtensionBundleIdentifier = "com.aluxlabs.link.safari-extension"; private const string VersionItemSelected = "versionItemSelected:"; private const string ExtensionItemSelected = "extensionItemSelected:"; @@ -29,7 +29,7 @@ public class AppDelegate : NSApplicationDelegate private NSStatusItem statusBarItem; - private ScratchLinkApp app; + private AluxLabsLinkApp app; /// /// Called when the app's initialization is complete but it hasn't received its first event. @@ -39,7 +39,7 @@ public override void DidFinishLaunching(NSNotification notification) { Trace.Listeners.Add(new OSLogTraceListener()); - var appBuilder = new ScratchLinkApp.Builder(); + var appBuilder = new AluxLabsLinkApp.Builder(); appBuilder.SetArguments(new NSProcessInfo().Arguments); appBuilder.SetSessionManager(); appBuilder.SetGattHelpers(); diff --git a/scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png b/aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png rename to aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png diff --git a/scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png b/aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png rename to aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png diff --git a/scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png b/aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png rename to aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png diff --git a/scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png b/aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png rename to aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png diff --git a/scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png b/aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png rename to aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png diff --git a/scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png b/aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png rename to aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png diff --git a/scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png b/aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png rename to aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png diff --git a/scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png b/aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png rename to aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png diff --git a/scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png b/aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png rename to aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png diff --git a/scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png b/aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png rename to aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png diff --git a/scratch-link-mac/Assets.xcassets/AppIcon.appiconset/Contents.json b/aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from scratch-link-mac/Assets.xcassets/AppIcon.appiconset/Contents.json rename to aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/scratch-link-mac/Assets.xcassets/Contents.json b/aluxlabs-link-mac/Assets.xcassets/Contents.json similarity index 100% rename from scratch-link-mac/Assets.xcassets/Contents.json rename to aluxlabs-link-mac/Assets.xcassets/Contents.json diff --git a/scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128.png b/aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128.png rename to aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128.png diff --git a/scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128@2x.png b/aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128@2x.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128@2x.png rename to aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128@2x.png diff --git a/scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16.png b/aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16.png rename to aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16.png diff --git a/scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16@2x.png b/aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16@2x.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16@2x.png rename to aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16@2x.png diff --git a/scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256.png b/aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256.png rename to aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256.png diff --git a/scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256@2x.png b/aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256@2x.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256@2x.png rename to aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256@2x.png diff --git a/scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32.png b/aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32.png rename to aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32.png diff --git a/scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32@2x.png b/aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32@2x.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32@2x.png rename to aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32@2x.png diff --git a/scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512.png b/aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512.png rename to aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512.png diff --git a/scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512@2x.png b/aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512@2x.png similarity index 100% rename from scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512@2x.png rename to aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512@2x.png diff --git a/scratch-link-mac/BLE/CBCentralManagerEventDelegate.cs b/aluxlabs-link-mac/BLE/CBCentralManagerEventDelegate.cs similarity index 99% rename from scratch-link-mac/BLE/CBCentralManagerEventDelegate.cs rename to aluxlabs-link-mac/BLE/CBCentralManagerEventDelegate.cs index b8d47ed8..d6a0ddbe 100644 --- a/scratch-link-mac/BLE/CBCentralManagerEventDelegate.cs +++ b/aluxlabs-link-mac/BLE/CBCentralManagerEventDelegate.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac.BLE; +namespace AluxLabs.Link.Mac.BLE; using System; using CoreBluetooth; diff --git a/scratch-link-mac/BLE/MacBLEEndpoint.cs b/aluxlabs-link-mac/BLE/MacBLEEndpoint.cs similarity index 98% rename from scratch-link-mac/BLE/MacBLEEndpoint.cs rename to aluxlabs-link-mac/BLE/MacBLEEndpoint.cs index 344f0f7e..3554b32c 100644 --- a/scratch-link-mac/BLE/MacBLEEndpoint.cs +++ b/aluxlabs-link-mac/BLE/MacBLEEndpoint.cs @@ -2,14 +2,14 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac.BLE; +namespace AluxLabs.Link.Mac.BLE; using System; using System.Threading; using System.Threading.Tasks; using CoreBluetooth; using Foundation; -using ScratchLink.BLE; +using AluxLabs.Link.BLE; /// /// Implement by wrapping . diff --git a/scratch-link-mac/BLE/MacBLESession.cs b/aluxlabs-link-mac/BLE/MacBLESession.cs similarity index 99% rename from scratch-link-mac/BLE/MacBLESession.cs rename to aluxlabs-link-mac/BLE/MacBLESession.cs index 3bc905e0..3a18b77d 100644 --- a/scratch-link-mac/BLE/MacBLESession.cs +++ b/aluxlabs-link-mac/BLE/MacBLESession.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac.BLE; +namespace AluxLabs.Link.Mac.BLE; using System; using System.Collections.Generic; @@ -14,10 +14,10 @@ namespace ScratchLink.Mac.BLE; using CoreFoundation; using Fleck; using Foundation; -using ScratchLink.BLE; -using ScratchLink.Extensions; -using ScratchLink.JsonRpc; -using ScratchLink.Mac.Extensions; +using AluxLabs.Link.BLE; +using AluxLabs.Link.Extensions; +using AluxLabs.Link.JsonRpc; +using AluxLabs.Link.Mac.Extensions; /// /// Implements a BLE session on MacOS. diff --git a/scratch-link-mac/BLE/MacGattHelpers.cs b/aluxlabs-link-mac/BLE/MacGattHelpers.cs similarity index 92% rename from scratch-link-mac/BLE/MacGattHelpers.cs rename to aluxlabs-link-mac/BLE/MacGattHelpers.cs index dda72c2f..bf82046f 100644 --- a/scratch-link-mac/BLE/MacGattHelpers.cs +++ b/aluxlabs-link-mac/BLE/MacGattHelpers.cs @@ -2,10 +2,10 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac.BLE; +namespace AluxLabs.Link.Mac.BLE; using CoreBluetooth; -using ScratchLink.BLE; +using AluxLabs.Link.BLE; /// /// Implement the MacOS-specific GATT helpers. diff --git a/scratch-link-mac/BT/MacBTSession.cs b/aluxlabs-link-mac/BT/MacBTSession.cs similarity index 98% rename from scratch-link-mac/BT/MacBTSession.cs rename to aluxlabs-link-mac/BT/MacBTSession.cs index 6ad77d05..c973ee11 100644 --- a/scratch-link-mac/BT/MacBTSession.cs +++ b/aluxlabs-link-mac/BT/MacBTSession.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac.BT; +namespace AluxLabs.Link.Mac.BT; using System; using System.Diagnostics; @@ -14,10 +14,10 @@ namespace ScratchLink.Mac.BT; using Fleck; using Foundation; using IOBluetooth; -using ScratchLink.BT; -using ScratchLink.JsonRpc; -using ScratchLink.Mac.BT.Rfcomm; -using ScratchLink.Mac.Extensions; +using AluxLabs.Link.BT; +using AluxLabs.Link.JsonRpc; +using AluxLabs.Link.Mac.BT.Rfcomm; +using AluxLabs.Link.Mac.Extensions; /// /// Implements a BT session on MacOS. diff --git a/scratch-link-mac/BT/Rfcomm/RfcommChannelDataEventArgs.cs b/aluxlabs-link-mac/BT/Rfcomm/RfcommChannelDataEventArgs.cs similarity index 92% rename from scratch-link-mac/BT/Rfcomm/RfcommChannelDataEventArgs.cs rename to aluxlabs-link-mac/BT/Rfcomm/RfcommChannelDataEventArgs.cs index 6b7cbe48..da8222f5 100644 --- a/scratch-link-mac/BT/Rfcomm/RfcommChannelDataEventArgs.cs +++ b/aluxlabs-link-mac/BT/Rfcomm/RfcommChannelDataEventArgs.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac.BT.Rfcomm; +namespace AluxLabs.Link.Mac.BT.Rfcomm; using System; diff --git a/scratch-link-mac/BT/Rfcomm/RfcommChannelEventArgs.cs b/aluxlabs-link-mac/BT/Rfcomm/RfcommChannelEventArgs.cs similarity index 92% rename from scratch-link-mac/BT/Rfcomm/RfcommChannelEventArgs.cs rename to aluxlabs-link-mac/BT/Rfcomm/RfcommChannelEventArgs.cs index 6ed3846e..bd6656b6 100644 --- a/scratch-link-mac/BT/Rfcomm/RfcommChannelEventArgs.cs +++ b/aluxlabs-link-mac/BT/Rfcomm/RfcommChannelEventArgs.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac.BT.Rfcomm; +namespace AluxLabs.Link.Mac.BT.Rfcomm; using System; using IOBluetooth; diff --git a/scratch-link-mac/BT/Rfcomm/RfcommChannelEventDelegate.cs b/aluxlabs-link-mac/BT/Rfcomm/RfcommChannelEventDelegate.cs similarity index 99% rename from scratch-link-mac/BT/Rfcomm/RfcommChannelEventDelegate.cs rename to aluxlabs-link-mac/BT/Rfcomm/RfcommChannelEventDelegate.cs index 479be3c9..1c538458 100644 --- a/scratch-link-mac/BT/Rfcomm/RfcommChannelEventDelegate.cs +++ b/aluxlabs-link-mac/BT/Rfcomm/RfcommChannelEventDelegate.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac.BT.Rfcomm; +namespace AluxLabs.Link.Mac.BT.Rfcomm; using System; using IOBluetooth; diff --git a/scratch-link-mac/BT/Rfcomm/RfcommChannelOpenCompleteEventArgs.cs b/aluxlabs-link-mac/BT/Rfcomm/RfcommChannelOpenCompleteEventArgs.cs similarity index 93% rename from scratch-link-mac/BT/Rfcomm/RfcommChannelOpenCompleteEventArgs.cs rename to aluxlabs-link-mac/BT/Rfcomm/RfcommChannelOpenCompleteEventArgs.cs index c88ce210..271075b5 100644 --- a/scratch-link-mac/BT/Rfcomm/RfcommChannelOpenCompleteEventArgs.cs +++ b/aluxlabs-link-mac/BT/Rfcomm/RfcommChannelOpenCompleteEventArgs.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac.BT.Rfcomm; +namespace AluxLabs.Link.Mac.BT.Rfcomm; using System; diff --git a/scratch-link-mac/BT/Rfcomm/RfcommChannelWriteCompleteEventArgs.cs b/aluxlabs-link-mac/BT/Rfcomm/RfcommChannelWriteCompleteEventArgs.cs similarity index 94% rename from scratch-link-mac/BT/Rfcomm/RfcommChannelWriteCompleteEventArgs.cs rename to aluxlabs-link-mac/BT/Rfcomm/RfcommChannelWriteCompleteEventArgs.cs index 24239bcd..8b5ecb44 100644 --- a/scratch-link-mac/BT/Rfcomm/RfcommChannelWriteCompleteEventArgs.cs +++ b/aluxlabs-link-mac/BT/Rfcomm/RfcommChannelWriteCompleteEventArgs.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac.BT.Rfcomm; +namespace AluxLabs.Link.Mac.BT.Rfcomm; using System; diff --git a/scratch-link-mac/BundleInfo.cs b/aluxlabs-link-mac/BundleInfo.cs similarity index 95% rename from scratch-link-mac/BundleInfo.cs rename to aluxlabs-link-mac/BundleInfo.cs index 70199acc..86745512 100644 --- a/scratch-link-mac/BundleInfo.cs +++ b/aluxlabs-link-mac/BundleInfo.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac; +namespace AluxLabs.Link.Mac; using System; using Foundation; @@ -12,7 +12,7 @@ namespace ScratchLink.Mac; /// public static class BundleInfo { - private static string defaultTitle = "Scratch Link"; + private static string defaultTitle = "AluxLabs Link"; private static string defaultVersion = "(unknown version)"; /// diff --git a/scratch-link-mac/Entitlements.plist b/aluxlabs-link-mac/Entitlements.plist similarity index 91% rename from scratch-link-mac/Entitlements.plist rename to aluxlabs-link-mac/Entitlements.plist index e396e9da..0481cab2 100644 --- a/scratch-link-mac/Entitlements.plist +++ b/aluxlabs-link-mac/Entitlements.plist @@ -13,7 +13,7 @@ com.apple.security.automation.apple-events com.apple.application-identifier - W7AR3WMP87.edu.mit.scratch.scratch-link + W7AR3WMP87.com.aluxlabs.link com.apple.developer.team-identifier W7AR3WMP87 diff --git a/scratch-link-mac/Extensions/DispatchQueueExtensions.cs b/aluxlabs-link-mac/Extensions/DispatchQueueExtensions.cs similarity index 98% rename from scratch-link-mac/Extensions/DispatchQueueExtensions.cs rename to aluxlabs-link-mac/Extensions/DispatchQueueExtensions.cs index 1edcc6b4..b21f6e68 100644 --- a/scratch-link-mac/Extensions/DispatchQueueExtensions.cs +++ b/aluxlabs-link-mac/Extensions/DispatchQueueExtensions.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac.Extensions; +namespace AluxLabs.Link.Mac.Extensions; using System; using System.Threading.Tasks; diff --git a/scratch-link-mac/Extensions/NSExtensions.cs b/aluxlabs-link-mac/Extensions/NSExtensions.cs similarity index 96% rename from scratch-link-mac/Extensions/NSExtensions.cs rename to aluxlabs-link-mac/Extensions/NSExtensions.cs index 17c73f4f..8638de0b 100644 --- a/scratch-link-mac/Extensions/NSExtensions.cs +++ b/aluxlabs-link-mac/Extensions/NSExtensions.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac.Extensions; +namespace AluxLabs.Link.Mac.Extensions; using Foundation; diff --git a/scratch-link-mac/IOReturn.cs b/aluxlabs-link-mac/IOReturn.cs similarity index 97% rename from scratch-link-mac/IOReturn.cs rename to aluxlabs-link-mac/IOReturn.cs index 4a028287..25c00a60 100644 --- a/scratch-link-mac/IOReturn.cs +++ b/aluxlabs-link-mac/IOReturn.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac; +namespace AluxLabs.Link.Mac; using System; using System.Runtime.InteropServices; diff --git a/scratch-link-mac/Info.plist b/aluxlabs-link-mac/Info.plist similarity index 93% rename from scratch-link-mac/Info.plist rename to aluxlabs-link-mac/Info.plist index 35fe3439..92dc068a 100644 --- a/scratch-link-mac/Info.plist +++ b/aluxlabs-link-mac/Info.plist @@ -3,9 +3,9 @@ CFBundleName - Scratch Link + AluxLabs Link CFBundleIdentifier - edu.mit.scratch.scratch-link + com.aluxlabs.link LSMinimumSystemVersion 10.13 CFBundleDevelopmentRegion diff --git a/scratch-link-mac/MacSessionManager.cs b/aluxlabs-link-mac/MacSessionManager.cs similarity index 90% rename from scratch-link-mac/MacSessionManager.cs rename to aluxlabs-link-mac/MacSessionManager.cs index 80e0ba0c..237bbe65 100644 --- a/scratch-link-mac/MacSessionManager.cs +++ b/aluxlabs-link-mac/MacSessionManager.cs @@ -2,11 +2,11 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac; +namespace AluxLabs.Link.Mac; using Fleck; -using ScratchLink.Mac.BLE; -using ScratchLink.Mac.BT; +using AluxLabs.Link.Mac.BLE; +using AluxLabs.Link.Mac.BT; /// /// Implements the Mac-specific functionality of the SessionManager. diff --git a/scratch-link-mac/Main.cs b/aluxlabs-link-mac/Main.cs similarity index 93% rename from scratch-link-mac/Main.cs rename to aluxlabs-link-mac/Main.cs index 0d5fcdea..4031b492 100644 --- a/scratch-link-mac/Main.cs +++ b/aluxlabs-link-mac/Main.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac; +namespace AluxLabs.Link.Mac; using AppKit; diff --git a/scratch-link-mac/OSLogTraceListener.cs b/aluxlabs-link-mac/OSLogTraceListener.cs similarity index 90% rename from scratch-link-mac/OSLogTraceListener.cs rename to aluxlabs-link-mac/OSLogTraceListener.cs index 586cbddc..99fe01f3 100644 --- a/scratch-link-mac/OSLogTraceListener.cs +++ b/aluxlabs-link-mac/OSLogTraceListener.cs @@ -2,7 +2,7 @@ // Copyright (c) Scratch Foundation. All rights reserved. // -namespace ScratchLink.Mac; +namespace AluxLabs.Link.Mac; using System; using System.Diagnostics; @@ -13,7 +13,7 @@ namespace ScratchLink.Mac; /// public class OSLogTraceListener : TraceListener { - private const string LogSubsystem = "org.scratch.link"; + private const string LogSubsystem = "com.aluxlabs.link"; private const string LogCategory = "app"; private readonly OSLog log; diff --git a/scratch-link-mac/README.md b/aluxlabs-link-mac/README.md similarity index 50% rename from scratch-link-mac/README.md rename to aluxlabs-link-mac/README.md index e7968ad7..2f27f831 100644 --- a/scratch-link-mac/README.md +++ b/aluxlabs-link-mac/README.md @@ -1,11 +1,11 @@ -# Notes for Scratch Link 2.0 on macOS +# Notes for AluxLabs Link 2.0 on macOS ## Requirements -* Scratch Link 2.0 itself targets macOS 10.13 and above +* AluxLabs Link 2.0 itself targets macOS 10.13 and above * The Safari extension requires macOS 10.15+ and Safari 14+ -* The Safari extension is only fully supported when Scratch Link 2.0 is installed through the Mac App Store +* The Safari extension is only fully supported when AluxLabs Link 2.0 is installed through the Mac App Store * Even if the extension is signed for Developer ID distribution, Safari will treat it as "unsigned" if it didn't come from the Mac App Store. * You can use the extension anyway by checking "Allow Unsigned Extensions" in Safari's developer menu. - * In non-MAS builds of Scratch Link 2.0, the menu item to manage the extension will appear if you hold Option. + * In non-MAS builds of AluxLabs Link 2.0, the menu item to manage the extension will appear if you hold Option. diff --git a/scratch-link-mac/scratch-link-mac.csproj b/aluxlabs-link-mac/aluxlabs-link-mac.csproj similarity index 95% rename from scratch-link-mac/scratch-link-mac.csproj rename to aluxlabs-link-mac/aluxlabs-link-mac.csproj index 27b06853..b09ed41b 100644 --- a/scratch-link-mac/scratch-link-mac.csproj +++ b/aluxlabs-link-mac/aluxlabs-link-mac.csproj @@ -6,8 +6,8 @@ {CDF7978E-13C6-40A9-81F9-2A3B4F7E861C} {A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Exe - ScratchLink.Mac - Scratch Link + AluxLabs.Link.Mac + AluxLabs Link v2.0 Xamarin.Mac Resources @@ -20,7 +20,7 @@ DEBUG;TRACE prompt 4 - bin\Debug\Scratch Link.xml + bin\Debug\AluxLabs Link.xml false Mac Developer true @@ -40,7 +40,7 @@ TRACE prompt 4 - bin\Release\Scratch Link.xml + bin\Release\AluxLabs Link.xml true true false @@ -65,7 +65,7 @@ SIGNED_DEVID;TRACE prompt 4 - bin\Release_DevID\Scratch Link.xml + bin\Release_DevID\AluxLabs Link.xml true true true @@ -91,7 +91,7 @@ SIGNED_MAS;TRACE prompt 4 - bin\Release_MAS\Scratch Link.xml + bin\Release_MAS\AluxLabs Link.xml true true true @@ -209,7 +209,7 @@ - + diff --git a/scratch-link-mac/app.config b/aluxlabs-link-mac/app.config similarity index 100% rename from scratch-link-mac/app.config rename to aluxlabs-link-mac/app.config diff --git a/scratch-link-mac/notarize.sh b/aluxlabs-link-mac/notarize.sh similarity index 100% rename from scratch-link-mac/notarize.sh rename to aluxlabs-link-mac/notarize.sh diff --git a/aluxlabs-link.sln b/aluxlabs-link.sln index bd29fcc0..bd550580 100644 --- a/aluxlabs-link.sln +++ b/aluxlabs-link.sln @@ -32,7 +32,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "aluxlabs-link-common", "aluxlabs-link-common\aluxlabs-link-common.shproj", "{06B5D2A3-AD0A-4704-B00D-BCFF634E7709}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "scratch-link-mac", "scratch-link-mac\scratch-link-mac.csproj", "{CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "aluxlabs-link-mac", "aluxlabs-link-mac\aluxlabs-link-mac.csproj", "{CDF7978E-13C6-40A9-81F9-2A3B4F7E861C}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SharedProps", "SharedProps", "{52974047-90CA-4584-811B-242220DB05AB}" ProjectSection(SolutionItems) = preProject From 26ae78c01d0659e266d46c5be48630f8c751c8d1 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 May 2026 11:47:29 +0900 Subject: [PATCH 68/94] =?UTF-8?q?refactor(rebrand):=20=EC=99=B8=EB=B6=80?= =?UTF-8?q?=20=EB=85=B8=EC=B6=9C=20=EC=8B=9D=EB=B3=84=EC=9E=90=20/=20?= =?UTF-8?q?=EB=A9=94=ED=83=80=20=ED=8C=8C=EC=9D=BC=20=EC=9D=BC=EA=B4=84=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit playground / global.d.ts 의 외부 노출 식별자와 메타 파일에 남아있던 옛 브랜드 표기를 모두 AluxLabs Link 패턴으로 통일. scratch-vm 측에서 새 이름을 인식·정리할 수 있도록 호환 가이드 문서 추가. - global.d.ts: ScratchLink* / ScratchBLE / ScratchBT / Scratch 컨테이너 → AluxLabs* - playground.html: title, placeholder, self.Scratch 초기화, Safari 확장 주입 ID - playground.js: Client / Socket / 전역 컨테이너 / 인스턴스 변수명 일괄 치환 - fastlane/Appfile: app_identifier 새 BundleID 적용 - brand/build_icons.py: scratch-link-win 경로 → aluxlabs-link-win - Documentation/Alux/WindowsDevSetup-VS2026.md: scratch-link-mac → aluxlabs-link-mac 호환성 문서 Documentation/Alux/ScratchVmInterop.md 추가: - 변경된 식별자 표 (Old → New) - scratch-vm 측 작업 요청 (필수 / 선택) - 와이어 프로토콜 / WebSocket 경로는 변경 없음 - 단기 호환용 클라이언트 alias 예시 npm 패키지 경로 (./node_modules/scratch-vm/...) 는 외부 패키지명이므로 보존. Co-Authored-By: Claude Opus 4.7 (1M context) --- Documentation/Alux/ScratchVmInterop.md | 119 +++++++++++++++++++ Documentation/Alux/WindowsDevSetup-VS2026.md | 4 +- brand/build_icons.py | 10 +- fastlane/Appfile | 2 +- global.d.ts | 12 +- playground.html | 8 +- playground.js | 72 +++++------ 7 files changed, 173 insertions(+), 54 deletions(-) create mode 100644 Documentation/Alux/ScratchVmInterop.md diff --git a/Documentation/Alux/ScratchVmInterop.md b/Documentation/Alux/ScratchVmInterop.md new file mode 100644 index 00000000..3cf4b752 --- /dev/null +++ b/Documentation/Alux/ScratchVmInterop.md @@ -0,0 +1,119 @@ +# scratch-vm 측 연동 식별자 변경 안내 + +본 문서는 `feature/rebrand-aluxlabs-link` 브랜치에서 진행된 AluxLabs Link 리브랜딩 과정에서 **scratch-vm 및 그 파생 라이브러리에 영향을 줄 수 있는 식별자 변경**을 정리한다. scratch-vm 측 (또는 자체 fork) 에서 호환 작업을 진행할 때 참고용. + +## 1. 배경 + +기존 scratch-link 는 브라우저/Scratch 에디터 측 코드가 다음 전역 식별자를 통해 link 와 통신했다: + +- `ScratchLinkWebSocket` (전역 클래스, WebSocket 트랜스포트) +- `ScratchLinkSafariSocket` (전역 클래스, Safari WebExtension 트랜스포트) +- `Scratch` (전역 컨테이너 객체, `Scratch.BLE`, `Scratch.BT` 형태로 link 클라이언트 인스턴스 보관) +- ` - + diff --git a/playground.js b/playground.js index 1ead032e..9b396dd5 100644 --- a/playground.js +++ b/playground.js @@ -2,8 +2,8 @@ // Expected globals: // - JSONRPC // - Scratch -// - ScratchLinkWebSocket -// - ScratchLinkSafariSocket (if Safari extension is present) +// - AluxLabsLinkWebSocket +// - AluxLabsLinkSafariSocket (if Safari extension is present) /// class LogDisplay { @@ -74,20 +74,20 @@ class DidReceiveCallEvent extends Event { } } -class ScratchLinkClient extends JSONRPC { +class AluxLabsLinkClient extends JSONRPC { /** * @param {string} type */ constructor(type) { super(); - this._scratchLinkPeripheralType = type; + this._aluxLabsLinkPeripheralType = type; this._events = new EventTarget(); - const ScratchLinkSafariSocket = self.Scratch && self.Scratch.ScratchLinkSafariSocket; - const useSafariSocket = ScratchLinkSafariSocket && ScratchLinkSafariSocket.isSafariHelperCompatible(); + const AluxLabsLinkSafariSocket = self.AluxLabs && self.AluxLabs.AluxLabsLinkSafariSocket; + const useSafariSocket = AluxLabsLinkSafariSocket && AluxLabsLinkSafariSocket.isSafariHelperCompatible(); addLine(`Using ${useSafariSocket ? 'Safari WebExtension' : 'WebSocket'}`); this._socket = useSafariSocket ? - new ScratchLinkSafariSocket(type) : - new ScratchLinkWebSocket(type); + new AluxLabsLinkSafariSocket(type) : + new AluxLabsLinkWebSocket(type); addLine(`Socket created for ${type}`); this._socket.setOnClose(e => { addLine(`Socket closed: ${stringify(e)}`); @@ -106,12 +106,12 @@ class ScratchLinkClient extends JSONRPC { } /** - * @returns {Promise} + * @returns {Promise} */ open () { return new Promise(resolve => { this._socket.setOnOpen(() => { - addLine(`Socket opened for ${this._scratchLinkPeripheralType}`); + addLine(`Socket opened for ${this._aluxLabsLinkPeripheralType}`); resolve(this); }); this._socket.open(); @@ -119,7 +119,7 @@ class ScratchLinkClient extends JSONRPC { } } -class ScratchBLE extends ScratchLinkClient { +class AluxLabsBLE extends AluxLabsLinkClient { constructor() { super('BLE'); @@ -183,7 +183,7 @@ class ScratchBLE extends ScratchLinkClient { } } -class ScratchBT extends ScratchLinkClient { +class AluxLabsBT extends AluxLabsLinkClient { constructor() { super('BT'); } @@ -246,7 +246,7 @@ function attachFunctionToButton(buttonId, func) { } /** - * @param {ScratchLinkClient} session + * @param {AluxLabsLinkClient} session */ function getVersion(session) { return session.sendRemoteRequest('getVersion').then( @@ -260,7 +260,7 @@ function getVersion(session) { } /** - * @param {ScratchLinkClient} session + * @param {AluxLabsLinkClient} session */ function pingMe (session) { return session.sendRemoteRequest('pingMe').then( @@ -274,12 +274,12 @@ function pingMe (session) { } function initBLE() { - if (self.Scratch.BLE) { - self.Scratch.BLE._socket.close(); + if (self.AluxLabs.BLE) { + self.AluxLabs.BLE._socket.close(); } addLine('Connecting...'); - self.Scratch.BLE = new ScratchBLE(); - return self.Scratch.BLE.open(); + self.AluxLabs.BLE = new AluxLabsBLE(); + return self.AluxLabs.BLE.open(); } const filterInputsBLE = []; @@ -410,7 +410,7 @@ function discoverBLE() { deviceDetails.optionalServices = optionalServicesBLE.value.trim().split(/\s+/); } - return Scratch.BLE.requestDevice( + return AluxLabs.BLE.requestDevice( deviceDetails ).then( x => { @@ -424,9 +424,9 @@ function discoverBLE() { function connectBLE() { // this should really be implicit in `requestDevice` but splitting it out helps with debugging - return Scratch.BLE.sendRemoteRequest( + return AluxLabs.BLE.sendRemoteRequest( 'connect', - { peripheralId: Scratch.BLE.discoveredPeripheralId } + { peripheralId: AluxLabs.BLE.discoveredPeripheralId } ).then( x => { addLine(`connect resolved to: ${stringify(x)}`); @@ -438,7 +438,7 @@ function connectBLE() { } function getServicesBLE() { - return Scratch.BLE.sendRemoteRequest( + return AluxLabs.BLE.sendRemoteRequest( 'getServices' ).then( x => { @@ -458,7 +458,7 @@ function setServiceMicroBit() { } function readMicroBit() { - return Scratch.BLE.read(0xf005, '5261da01-fa7e-42ab-850b-7c80220097cc', true).then( + return AluxLabs.BLE.read(0xf005, '5261da01-fa7e-42ab-850b-7c80220097cc', true).then( x => { addLine(`read resolved to: ${stringify(x)}`); }, @@ -470,7 +470,7 @@ function readMicroBit() { function writeMicroBit() { const message = _encodeMessage('LINK'); - return Scratch.BLE.write(0xf005, '5261da02-fa7e-42ab-850b-7c80220097cc', message, 'base64').then( + return AluxLabs.BLE.write(0xf005, '5261da02-fa7e-42ab-850b-7c80220097cc', message, 'base64').then( x => { addLine(`write resolved to: ${stringify(x)}`); }, @@ -515,8 +515,8 @@ function _encodeMessage(message) { } attachFunctionToButton('initBLE', initBLE); -attachFunctionToButton('getVersionBLE', () => getVersion(self.Scratch.BLE)); -attachFunctionToButton('pingBLE', () => pingMe(self.Scratch.BLE)); +attachFunctionToButton('getVersionBLE', () => getVersion(self.AluxLabs.BLE)); +attachFunctionToButton('pingBLE', () => pingMe(self.AluxLabs.BLE)); attachFunctionToButton('discoverBLE', discoverBLE); attachFunctionToButton('connectBLE', connectBLE); attachFunctionToButton('getServicesBLE', getServicesBLE); @@ -534,16 +534,16 @@ attachFunctionToButton('addFilterBLE', addFilterBLE); addFilterBLE(); function initBT() { - if (self.Scratch.BT) { - self.Scratch.BT._socket.close(); + if (self.AluxLabs.BT) { + self.AluxLabs.BT._socket.close(); } addLine('Connecting...'); - self.Scratch.BT = new ScratchBT(); - return self.Scratch.BT.open(); + self.AluxLabs.BT = new AluxLabsBT(); + return self.AluxLabs.BT.open(); } function discoverBT() { - return Scratch.BT.requestDevice({ + return AluxLabs.BT.requestDevice({ majorDeviceClass: 8, minorDeviceClass: 1 }).then( @@ -557,7 +557,7 @@ function discoverBT() { } function connectBT() { - return Scratch.BT.connectDevice({ + return AluxLabs.BT.connectDevice({ peripheralId: document.getElementById('peripheralId').value, pin: "1234" }).then( @@ -574,7 +574,7 @@ function connectBT() { * @param {any} message */ function sendMessage(message) { - return Scratch.BT.sendMessage({ + return AluxLabs.BT.sendMessage({ message: document.getElementById('messageBody').value, encoding: 'base64' }).then( @@ -588,7 +588,7 @@ function sendMessage(message) { } function beep() { - return Scratch.BT.sendMessage({ + return AluxLabs.BT.sendMessage({ message: 'DwAAAIAAAJQBgQKC6AOC6AM=', encoding: 'base64' }).then( @@ -603,11 +603,11 @@ function beep() { const closeButton = document.getElementById('closeBT'); closeButton.onclick = () => { - self.Scratch.BT.dispose(); + self.AluxLabs.BT.dispose(); }; attachFunctionToButton('initBT', initBT); -attachFunctionToButton('getVersionBT', () => getVersion(self.Scratch.BT)); +attachFunctionToButton('getVersionBT', () => getVersion(self.AluxLabs.BT)); attachFunctionToButton('discoverBT', discoverBT); attachFunctionToButton('connectBT', connectBT); attachFunctionToButton('send', sendMessage); From 9e1f2d984d5f3aa43d6d1dbd4f3816fb61b4dbd0 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 May 2026 11:48:44 +0900 Subject: [PATCH 69/94] =?UTF-8?q?refactor(rebrand):=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=86=A0=EC=BD=9C=C2=B7=EC=95=84=ED=82=A4=ED=85=8D=EC=B2=98=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=EC=9D=98=20=EC=A0=9C=ED=92=88=EB=AA=85=20?= =?UTF-8?q?=ED=91=9C=EA=B8=B0=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentation/{Architecture,Bluetooth,BluetoothLE,NetworkProtocol,TestPlans}.md 의 "Scratch Link" 표기를 모두 "AluxLabs Link" 로 일괄 치환. 와이어 프로토콜 의미와 메서드 이름은 그대로이며 표시명만 변경. Alux/* 사내 문서 안 옛 이름은 fork 출처·매핑 표·호환 가이드 등 의도된 보존이라 그대로 둠. Co-Authored-By: Claude Opus 4.7 (1M context) --- Documentation/Architecture.md | 22 +++++----- Documentation/Bluetooth.md | 26 ++++++------ Documentation/BluetoothLE.md | 70 ++++++++++++++++---------------- Documentation/NetworkProtocol.md | 50 +++++++++++------------ Documentation/TestPlans.md | 20 ++++----- 5 files changed, 94 insertions(+), 94 deletions(-) diff --git a/Documentation/Architecture.md b/Documentation/Architecture.md index 27058574..42a7ed90 100644 --- a/Documentation/Architecture.md +++ b/Documentation/Architecture.md @@ -1,4 +1,4 @@ -# Scratch Link 2.x Architecture +# AluxLabs Link 2.x Architecture ## Requirements @@ -10,7 +10,7 @@ * Communicate with the Scratch 3 app running on macOS or Windows * Must not require an active Internet connection * Avoid the need for an SSL certificate -* Support all peripherals which were supported by Scratch Link 1.x +* Support all peripherals which were supported by AluxLabs Link 1.x * Bluetooth LE * Bluetooth Classic @@ -45,12 +45,12 @@ Other browsers are capable of either `ws://` or WebExtension communication. Howe difficult (maybe impossible) to communicate over `stdio` as needed by WebExtension native messaging. Since Safari is the only browser which strictly needs this, and Safari needs a WebExtension wrapper app anyway, we can implement that wrapper using Swift or Objective C and use the macOS native WebSocket client. The only downside to the lack of a -WebExtension component for other browsers is that those other browsers will not be able to auto-launch Scratch Link. +WebExtension component for other browsers is that those other browsers will not be able to auto-launch AluxLabs Link. If this limitation is lifted in a future version of MAUI, we can add that as a nice-to-have. -The Scratch app for Mac & Windows can communicate with Scratch Link over a `ws://` connection, just like other +The Scratch app for Mac & Windows can communicate with AluxLabs Link over a `ws://` connection, just like other browsers. Because we're making a loopback connection over `ws://` we won't need to worry about DNS resolution, which -means we will be able to use Scratch Link in a truly offline environment without needing any DNS workarounds. +means we will be able to use AluxLabs Link in a truly offline environment without needing any DNS workarounds. ```mermaid graph TD; @@ -59,8 +59,8 @@ subgraph Clients Browsers["Other Browsers"] App["Scratch app"] end -SafariHelper["Scratch Link Safari WebExtension Helper"] -subgraph "Scratch Link" +SafariHelper["AluxLabs Link Safari WebExtension Helper"] +subgraph "AluxLabs Link" WebSocket["WebSocket listener"] RPC["JSON RPC message handler"] SessionManager @@ -102,7 +102,7 @@ WinBLE --> Windows.Devices.Bluetooth ## Previous Architecture -For reference, the architecture of Scratch Link 1.4 was as shown below. +For reference, the architecture of AluxLabs Link 1.4 was as shown below. ```mermaid graph TD; @@ -111,14 +111,14 @@ subgraph Clients Browsers["Other Browsers"] App["Scratch app"] end -subgraph "Scratch Link (Windows / C#)" +subgraph "AluxLabs Link (Windows / C#)" WinWebSocket["WebSocket listener"] WinRPC["JSON RPC message handler"] WinSessionManager["Session manager"] WinBT["BT Session"] WinBLE["BLE Session"] end -subgraph "Scratch Link (macOS / Swift)" +subgraph "AluxLabs Link (macOS / Swift)" MacWebSocket["WebSocket listener"] MacRPC["JSON RPC message handler"] MacSessionManager["Session manager"] @@ -160,4 +160,4 @@ Major differences include: * The macOS version is implemented in Swift and uses the `CoreBluetooth` API. * The Windows version is written in C# and uses the `Windows.Devices.Bluetooth` API. * Safari is unsupported due to the "secure contexts" requirement discussed in the "Implications" section above. - * Scratch Link 1.3 used `wss://` instead of `ws://`, so it supported Safari but required an SSL certificate. + * AluxLabs Link 1.3 used `wss://` instead of `ws://`, so it supported Safari but required an SSL certificate. diff --git a/Documentation/Bluetooth.md b/Documentation/Bluetooth.md index fafa72d5..64569548 100644 --- a/Documentation/Bluetooth.md +++ b/Documentation/Bluetooth.md @@ -1,14 +1,14 @@ # Bluetooth Peripheral Protocol This document describes the communication protocol used by a Scratch Extension (or the extension framework) to -communicate with a Bluetooth RFCOMM / BR / EDR peripheral using Scratch Link. This document builds on the "Network +communicate with a Bluetooth RFCOMM / BR / EDR peripheral using AluxLabs Link. This document builds on the "Network Protocol" document describing the portions of the protocol common to all peripheral types. -## Communication Interface (Scratch Extension to Scratch Link) +## Communication Interface (Scratch Extension to AluxLabs Link) -### Initiating Communication with Scratch Link +### Initiating Communication with AluxLabs Link -For Bluetooth (BT) connections, an extension connects to Scratch Link's WebSocket server at the path "/scratch/bt". +For Bluetooth (BT) connections, an extension connects to AluxLabs Link's WebSocket server at the path "/scratch/bt". ### Common Methods @@ -25,7 +25,7 @@ No additional version information is provided beyond the base implementation. TODO: describe Bluetooth discovery / filtering parameters. -JSON-RPC **request** sent from Scratch Extension to Scratch Link to initiate discovery. +JSON-RPC **request** sent from Scratch Extension to AluxLabs Link to initiate discovery. ```json5 { @@ -36,7 +36,7 @@ JSON-RPC **request** sent from Scratch Extension to Scratch Link to initiate dis } ``` -JSON-RPC **response** sent from Scratch Link to Scratch Extension upon successful initiation of discovery. This confirms +JSON-RPC **response** sent from AluxLabs Link to Scratch Extension upon successful initiation of discovery. This confirms the transition into the discovery state. ```json5 @@ -47,7 +47,7 @@ the transition into the discovery state. } ``` -JSON-RPC **response** sent from Scratch Link to Scratch Extension upon failure to initiate discovery. The connection +JSON-RPC **response** sent from AluxLabs Link to Scratch Extension upon failure to initiate discovery. The connection remains in the initial state. ```json5 @@ -65,10 +65,10 @@ remains in the initial state. Sending data to a connected peripheral shall be initiated by the Scratch Extension. This command requires two arguments: the message body and a supported encoding format. Attempting to "send" to a peripheral with an unsupported encoding or invalid message body will result in an error response. If the underlying peripheral connection has specific needs -regarding packet size (MTU), keep-alive, etc., those concerns shall be managed by Scratch Link in order to simulate a +regarding packet size (MTU), keep-alive, etc., those concerns shall be managed by AluxLabs Link in order to simulate a persistent free-form serial data stream. -JSON-RPC **request** sent from Scratch Extension to Scratch Link to send a serial message to a specified peripheral. +JSON-RPC **request** sent from Scratch Extension to AluxLabs Link to send a serial message to a specified peripheral. ```json5 { @@ -82,7 +82,7 @@ JSON-RPC **request** sent from Scratch Extension to Scratch Link to send a seria } ``` -JSON-RPC **response** sent from Scratch Link to Scratch Extension upon successful message send. +JSON-RPC **response** sent from AluxLabs Link to Scratch Extension upon successful message send. ```json5 { @@ -92,7 +92,7 @@ JSON-RPC **response** sent from Scratch Link to Scratch Extension upon successfu } ``` -JSON-RPC **response** sent from Scratch Link to Scratch Extension upon unsuccessful message send. +JSON-RPC **response** sent from AluxLabs Link to Scratch Extension upon unsuccessful message send. ```json5 { @@ -104,11 +104,11 @@ JSON-RPC **response** sent from Scratch Link to Scratch Extension upon unsuccess ### Receiving a Message -Receiving data from a connected peripheral shall be initiated by Scratch Link. This message requires two arguments: the +Receiving data from a connected peripheral shall be initiated by AluxLabs Link. This message requires two arguments: the message body and the encoding format (`base64`). The Scratch Extension is not expected to return a "callback" response when receiving a message. -JSON-RPC **notification** sent from Scratch Link to Scratch Extension on receipt of a serial message. +JSON-RPC **notification** sent from AluxLabs Link to Scratch Extension on receipt of a serial message. ```json5 { diff --git a/Documentation/BluetoothLE.md b/Documentation/BluetoothLE.md index 6bfe5664..fe474c2e 100644 --- a/Documentation/BluetoothLE.md +++ b/Documentation/BluetoothLE.md @@ -1,17 +1,17 @@ # Bluetooth LE Peripheral Protocol This document describes the communication protocol used by a Scratch Extension (or the extension framework) to -communicate with a Bluetooth Low Energy (BLE) peripheral's GATT interface using Scratch Link. This document builds on +communicate with a Bluetooth Low Energy (BLE) peripheral's GATT interface using AluxLabs Link. This document builds on the "Network Protocol" document describing the portions of the protocol common to all peripheral types. -## Communication Interface (Scratch Extension to Scratch Link) +## Communication Interface (Scratch Extension to AluxLabs Link) -In general, BLE support in Scratch Link is patterned after BLE support in Web bluetooth. The Web Bluetooth specification +In general, BLE support in AluxLabs Link is patterned after BLE support in Web bluetooth. The Web Bluetooth specification can be found here: -### Initiating Communication with Scratch Link +### Initiating Communication with AluxLabs Link -For BLE connections, an extension connects to Scratch Link's WebSocket server at the path "/scratch/ble". +For BLE connections, an extension connects to AluxLabs Link's WebSocket server at the path "/scratch/ble". ### Common Methods @@ -53,7 +53,7 @@ even if they are not used for filtering. See the "Service Names" section below f services in this list, or the "Connected State" section for more information about the relationship between the "services" filter property, the "optionalServices" parameter, and the services available to the Scratch Extension. -Example JSON-RPC **request** sent from Scratch Extension to Scratch Link to initiate discovery: +Example JSON-RPC **request** sent from Scratch Extension to AluxLabs Link to initiate discovery: ```json5 { @@ -107,7 +107,7 @@ calls "names" for GATT services. A GATT service name is one of the following: Each of the examples above specifies the same service. -Scratch Link shall resolve each name to a full UUID using the [getService]( +AluxLabs Link shall resolve each name to a full UUID using the [getService]( https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getservice) algorithm as described by the Web Bluetooth specification, which in practice is just shorthand for calling the [resolveUuidName]( https://webbluetoothcg.github.io/web-bluetooth/#resolveuuidname) algorithm and passing the [Service Assigned Numbers @@ -115,18 +115,18 @@ table](https://www.bluetooth.com/specifications/gatt/services) and "org.bluetoot ### Connected State -Connecting to a BLE peripheral with a "connect" request is the Scratch Link equivalent of the [Web Bluetooth +Connecting to a BLE peripheral with a "connect" request is the AluxLabs Link equivalent of the [Web Bluetooth `device.gatt.connect()`](https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect) call. After successfully connecting to a peripheral the Scratch Extension may access any **allowed** GATT service which the peripheral provides by reading and writing characteristics of those services, etc. -Scratch Link shall block access to certain GATT UUIDs (services, characteristics, etc.) as demanded by the [GATT +AluxLabs Link shall block access to certain GATT UUIDs (services, characteristics, etc.) as demanded by the [GATT Blocklist](https://webbluetoothcg.github.io/web-bluetooth/#the-gatt-blocklist). Such UUIDs are allowed in discovery filters but not allowed for actual communication. #### Allowed Services -Scratch Link shall reject any attempt by the Scratch Extension to access a GATT service unless the service is +AluxLabs Link shall reject any attempt by the Scratch Extension to access a GATT service unless the service is specifically allowed. A service is allowed if and only if: - it was named in the "services" array of **any** filter in the "discover" request, **or** @@ -151,7 +151,7 @@ Consider this request: } ``` -Suppose Scratch Link finds a peripheral with the name "My Peripheral" and reports that to the client in a +Suppose AluxLabs Link finds a peripheral with the name "My Peripheral" and reports that to the client in a "didDiscoverPeripheral" notification, then the Scratch Extension chooses to connect to the "My Peripheral" peripheral. The Scratch Extension will be allowed to contact the following services: @@ -164,7 +164,7 @@ discovery filter based on its name it might not implement any of these services. #### Enumerating Services -The Scratch Extension may query the list of allowed services by sending a "getServices" **request** to Scratch Link: +The Scratch Extension may query the list of allowed services by sending a "getServices" **request** to AluxLabs Link: ```json5 { @@ -175,7 +175,7 @@ The Scratch Extension may query the list of allowed services by sending a "getSe } ``` -On success, Scratch Link's **response** shall contain an array of service UUIDs as its result: +On success, AluxLabs Link's **response** shall contain an array of service UUIDs as its result: ```json5 { @@ -187,13 +187,13 @@ On success, Scratch Link's **response** shall contain an array of service UUIDs } ``` -The Scratch Extension is not required to enumerate a peripheral's services; Scratch Link shall not change the list of +The Scratch Extension is not required to enumerate a peripheral's services; AluxLabs Link shall not change the list of allowed services based on whether or not the Scratch Extension has requested enumeration. #### Enumerating Service Characteristics (not currently implemented) The Scratch Extension may query the list of characteristics available on an allowed service by sending a -"getCharacteristics" **request** to Scratch Link: +"getCharacteristics" **request** to AluxLabs Link: ```json5 { @@ -212,7 +212,7 @@ The "serviceId" property may be any valid GATT service name: - an integer representing a short ID, or - a string name from the [Service Assigned Numbers table](https://www.bluetooth.com/specifications/gatt/services). -On success, Scratch Link's **response** shall contain an array of characteristic UUIDs as its result: +On success, AluxLabs Link's **response** shall contain an array of characteristic UUIDs as its result: ```json5 { @@ -224,13 +224,13 @@ On success, Scratch Link's **response** shall contain an array of characteristic } ``` -The Scratch Extension is not required to enumerate a service's characteristics; Scratch Link shall not change the list +The Scratch Extension is not required to enumerate a service's characteristics; AluxLabs Link shall not change the list of allowed characteristics based on whether or not the Scratch Extension has requested enumeration. #### Writing to a Characteristic The Scratch Extension may write data to a characteristics available on an allowed service by sending a "write" -**request** to Scratch Link: +**request** to AluxLabs Link: ```json5 { @@ -264,25 +264,25 @@ The "characteristicId" property may be any valid GATT characteristic name: - a string name from the [Characteristic Assigned Numbers table]( https://www.bluetooth.com/specifications/gatt/characteristic). -The "encoding" property may be omitted; in this case the "message" is assumed to be a Unicode string. Scratch Link shall +The "encoding" property may be omitted; in this case the "message" is assumed to be a Unicode string. AluxLabs Link shall encode the string using UTF-8 and write the resulting bytes to the characteristic. Bluetooth LE supports writing a value to a characteristic with or without a response. The "withResponse" property controls which of these modes shall be used for a particular write. -- If true, Scratch Link shall write with response. That is, Scratch Link shall wait for the peripheral to confirm that - the write was received without error, and Scratch Link's response to the client shall report any error reported by the +- If true, AluxLabs Link shall write with response. That is, AluxLabs Link shall wait for the peripheral to confirm that + the write was received without error, and AluxLabs Link's response to the client shall report any error reported by the BLE peripheral. If the peripheral reports an error, that error shall be forwarded to the client as an error response to the "write" request. -- If false, Scratch Link shall write without response. That is, Scratch Link shall make a [best-effort +- If false, AluxLabs Link shall write without response. That is, AluxLabs Link shall make a [best-effort delivery](https://en.wikipedia.org/wiki/Best-effort_delivery) attempt then report success. There is no way for the peripheral to report an error in this mode. -- If absent, Scratch Link shall check if the characteristic appears to support writing without response. If so, - Scratch Link shall write without response. Otherwise, Scratch shall write with response. +- If absent, AluxLabs Link shall check if the characteristic appears to support writing without response. If so, + AluxLabs Link shall write without response. Otherwise, Scratch shall write with response. Generally, writing without response is significantly faster. -On success, Scratch Link's **response** shall contain the number of bytes written, which may differ from the number of +On success, AluxLabs Link's **response** shall contain the number of bytes written, which may differ from the number of characters in the string value of the initiating request's "message" property: ```json5 @@ -296,7 +296,7 @@ characters in the string value of the initiating request's "message" property: #### Reading from a Characteristic The Scratch Extension may read data from a characteristics available on an allowed service by sending a "read" -**request** to Scratch Link: +**request** to AluxLabs Link: ```json5 { @@ -328,11 +328,11 @@ The "characteristicId" property may be any valid GATT characteristic name: - an integer representing a short ID, or - a string name from the [Characteristic Assigned Numbers table](https://www.bluetooth.com/specifications/gatt/characteristic). -If the "encoding" property is present then Scratch Link should use the indicated encoding for the response, but Scratch -Link is not required to do so. If the "encoding" property is absent in the **request** Scratch Link may choose an +If the "encoding" property is present then AluxLabs Link should use the indicated encoding for the response, but Scratch +Link is not required to do so. If the "encoding" property is absent in the **request** AluxLabs Link may choose an encoding for the response. -On success, Scratch Link's **response** shall contain the data read from the characteristic: +On success, AluxLabs Link's **response** shall contain the data read from the characteristic: ```json5 { @@ -353,7 +353,7 @@ If the "startNotifications" property is both present and true in the **request** #### Value change notification -The Scratch Extension may request that Scratch Link shall continuously notify the Scratch Extension of changes in the +The Scratch Extension may request that AluxLabs Link shall continuously notify the Scratch Extension of changes in the characteristic's value by sending a "startNotifications" **request**. This shall continue until the Scratch Extension makes a "stopNotifications" request: @@ -386,11 +386,11 @@ The "characteristicId" property may be any valid GATT characteristic name: - an integer representing a short ID, or - a string name from the [Characteristic Assigned Numbers table](https://www.bluetooth.com/specifications/gatt/characteristic). -If the "encoding" property is present then Scratch Link should use the indicated encoding for notifications, but Scratch -Link is not required to do so. If the "encoding" property is absent in the **request** Scratch Link may choose an +If the "encoding" property is present then AluxLabs Link should use the indicated encoding for notifications, but Scratch +Link is not required to do so. If the "encoding" property is absent in the **request** AluxLabs Link may choose an encoding for the response. -Scratch Link notifies the Scratch Extension of value changes with **notification** messages in this form: +AluxLabs Link notifies the Scratch Extension of value changes with **notification** messages in this form: ```json5 { @@ -408,13 +408,13 @@ Scratch Link notifies the Scratch Extension of value changes with **notification If the "encoding" property is absent the Scratch Extension should assume that the "message" property contains a Unicode string. -Scratch Link shall only send such a notification when the value of a characteristic changes, and only for +AluxLabs Link shall only send such a notification when the value of a characteristic changes, and only for characteristics for which a "startNotifications" request (or a "read" request with the "startNotifications" flag set) has been made. Such notifications shall continue until the Scratch Extension makes a "stopNotifications" request. #### Stop Notifications -The Scratch Extension may end value change notifications by sending a "stopNotifications" **request** to Scratch Link: +The Scratch Extension may end value change notifications by sending a "stopNotifications" **request** to AluxLabs Link: ```json5 { diff --git a/Documentation/NetworkProtocol.md b/Documentation/NetworkProtocol.md index a8aa3504..b5ca54bb 100644 --- a/Documentation/NetworkProtocol.md +++ b/Documentation/NetworkProtocol.md @@ -1,7 +1,7 @@ # Network Protocol This document describes the communication protocol used by a Scratch Extension (or the extension framework) to -communicate with Scratch Link. Scratch Link supports multiple types of peripheral; this document describes the portions +communicate with AluxLabs Link. AluxLabs Link supports multiple types of peripheral; this document describes the portions of the protocol which are common across peripheral types. ## Protocol Versioning @@ -19,7 +19,7 @@ This version number shall follow the Semantic Versioning specification, found he - Version 1.3: - Bluetooth LE: - - Alter Scratch Link's handling of the `withResponse` flag on a `write` request. The flag now overrides Scratch + - Alter AluxLabs Link's handling of the `withResponse` flag on a `write` request. The flag now overrides Scratch Link's detection of GATT characteristic flags. - Version 1.2: - Add `manufacturerData` filtering for BLE discovery. @@ -41,13 +41,13 @@ specification, which describes three types of message: request, notification, an The JSON-RPC 2.0 specification may be found here: -## Communication Interface (Scratch Extension to Scratch Link) +## Communication Interface (Scratch Extension to AluxLabs Link) -### Initiating Communication with Scratch Link +### Initiating Communication with AluxLabs Link -Communication with Scratch Link is performed over WebSockets. When initiating a WebSocket connection between the Scratch -Extension and Scratch Link, the choice of path determines which Transport Protocol will be used. For example, when -initiating a BLE connection the extension connects to Scratch Link's WebSocket server at path `/scratch/ble`, and for +Communication with AluxLabs Link is performed over WebSockets. When initiating a WebSocket connection between the Scratch +Extension and AluxLabs Link, the choice of path determines which Transport Protocol will be used. For example, when +initiating a BLE connection the extension connects to AluxLabs Link's WebSocket server at path `/scratch/ble`, and for Bluetooth Classic (BT) connections the extension connects to the path `/scratch/bt`. ### Common Methods @@ -59,8 +59,8 @@ otherwise specified. *Added in network protocol version 1.2* -This is a JSON-RPC **request** sent from Scratch Extension to Scratch Link to retrieve version information about -Scratch Link itself. No parameters are necessary. +This is a JSON-RPC **request** sent from Scratch Extension to AluxLabs Link to retrieve version information about +AluxLabs Link itself. No parameters are necessary. ```json5 { @@ -70,7 +70,7 @@ Scratch Link itself. No parameters are necessary. } ``` -JSON-RPC **response** sent from Scratch Link to Scratch Extension . +JSON-RPC **response** sent from AluxLabs Link to Scratch Extension . ```json5 { @@ -90,7 +90,7 @@ protocol-specific documentation for details. In contrast to previously proposed protocols, this protocol dedicates a particular connection to the discovery of and interaction with exactly one peripheral. If an Extension wishes to interact with more than one peripheral simultaneously -then that Extension must open more than one connection to Scratch Link. +then that Extension must open more than one connection to AluxLabs Link. To this end, a particular socket connection may transition through several distinct states, each of which is described below. Each state supports a particular set of requests and notifications, and sending a request or notification not @@ -100,17 +100,17 @@ read or write data from or to a peripheral while the connection is in the "disco ### Initial State The connection begins in an initial, dormant state. The only message supported in this state is a discovery request, -which will transition the connection into the discovery state. Scratch Link may terminate a connection which does not +which will transition the connection into the discovery state. AluxLabs Link may terminate a connection which does not successfully enter the discovery state within a reasonable amount of time. A discovery request may include filtering information specific to the Transport Protocol associated with the connection. For example, a BLE discovery request might include the UUIDs of one or more required GATT services or characteristics. Note: discovery requests for wireless peripherals **must** include at least one non-trivial piece of filtering -information. Failure to provide such from the Scratch Extension shall result in Scratch Link refusing to perform a scan. +information. Failure to provide such from the Scratch Extension shall result in AluxLabs Link refusing to perform a scan. This is to help ensure the privacy and safety of the user. -JSON-RPC **request** sent from Scratch Extension to Scratch Link to initiate discovery. +JSON-RPC **request** sent from Scratch Extension to AluxLabs Link to initiate discovery. ```json5 { @@ -121,7 +121,7 @@ JSON-RPC **request** sent from Scratch Extension to Scratch Link to initiate dis } ``` -JSON-RPC **response** sent from Scratch Link to Scratch Extension upon successful initiation of discovery. This confirms +JSON-RPC **response** sent from AluxLabs Link to Scratch Extension upon successful initiation of discovery. This confirms the transition into the discovery state. ```json5 @@ -132,7 +132,7 @@ the transition into the discovery state. } ``` -JSON-RPC **response** sent from Scratch Link to Scratch Extension upon failure to initiate discovery. The connection +JSON-RPC **response** sent from AluxLabs Link to Scratch Extension upon failure to initiate discovery. The connection remains in the initial state. ```json5 @@ -145,19 +145,19 @@ remains in the initial state. ### Discovery State -The discovery state lasts until the Scratch Extension requests to connect to a peripheral or disconnects. Scratch Link +The discovery state lasts until the Scratch Extension requests to connect to a peripheral or disconnects. AluxLabs Link shall manage the initiation and/or renewal of scan, enumeration, or other peripheral discovery requests with the host system on an ongoing basis until the end of the discovery phase. If an unreasonable amount of time passes without the Scratch Extension issuing a successful "connect" request or -disconnecting from the socket, Scratch Link may end discovery and close the socket connection. This may help save +disconnecting from the socket, AluxLabs Link may end discovery and close the socket connection. This may help save battery power on mobile devices, for example. -This state supports the "didDiscoverPeripheral" notification (sent from Scratch Link to Scratch Extension) and the -"connect" request (sent from Scratch Extension to Scratch Link). +This state supports the "didDiscoverPeripheral" notification (sent from AluxLabs Link to Scratch Extension) and the +"connect" request (sent from Scratch Extension to AluxLabs Link). -JSON-RPC **notification** sent from Scratch Link to Scratch Extension upon discovery of peripherals. Note that this -message may be passed from Scratch Link to the Scratch Extension many times for as long as the discovery state is +JSON-RPC **notification** sent from AluxLabs Link to Scratch Extension upon discovery of peripherals. Note that this +message may be passed from AluxLabs Link to the Scratch Extension many times for as long as the discovery state is active. ```json5 @@ -186,7 +186,7 @@ Connection shall be initiated by the Scratch Extension by providing a specified connect. Attempting to connect to a peripheral which does not match the filtering information provided in the discovery request shall result in an error response. -JSON-RPC **request** sent from Scratch Extension to Scratch Link to connect to a peripheral. +JSON-RPC **request** sent from Scratch Extension to AluxLabs Link to connect to a peripheral. ```json5 { @@ -199,7 +199,7 @@ JSON-RPC **request** sent from Scratch Extension to Scratch Link to connect to a } ``` -JSON-RPC **response** sent from Scratch Link to Scratch Extension upon successful connection. This confirms the +JSON-RPC **response** sent from AluxLabs Link to Scratch Extension upon successful connection. This confirms the transition into the connected state. ```json5 @@ -210,7 +210,7 @@ transition into the connected state. } ``` -JSON-RPC **response** sent from Scratch Link to Scratch Extension upon connection failure. The discovery state shall +JSON-RPC **response** sent from AluxLabs Link to Scratch Extension upon connection failure. The discovery state shall remain active. ```json5 diff --git a/Documentation/TestPlans.md b/Documentation/TestPlans.md index be2fd1a6..92282f47 100644 --- a/Documentation/TestPlans.md +++ b/Documentation/TestPlans.md @@ -1,4 +1,4 @@ -# Testing Scratch Link +# Testing AluxLabs Link All tests require access to Scratch 3.0 through or similar. @@ -14,15 +14,15 @@ At least one of each: ## Test Cases -### Scratch Link startup & shutdown +### AluxLabs Link startup & shutdown -1. Start Scratch Link. -2. Click the Scratch Link icon and verify the version number. -3. Click "Exit" or "Quit" and verify that Scratch Link quits. +1. Start AluxLabs Link. +2. Click the AluxLabs Link icon and verify the version number. +3. Click "Exit" or "Quit" and verify that AluxLabs Link quits. ### BBC micro:bit -1. Start Scratch 3.0 & Scratch Link. +1. Start Scratch 3.0 & AluxLabs Link. 2. Load the "micro:bit" extension. 3. Connect to the micro:bit. 4. **Test the `display text` block.** @@ -36,7 +36,7 @@ At least one of each: ### LEGO WeDo 2.0 -1. Start Scratch 3.0 & Scratch Link. +1. Start Scratch 3.0 & AluxLabs Link. 2. Load the "LEGO WeDo 2.0" extension. 3. Connect to the WeDo 2. 4. **Test the `set light color to ()` block.** @@ -50,7 +50,7 @@ At least one of each: ### LEGO EV3 1. Turn on the EV3 -- startup takes a while. -2. Start Scratch 3.0 & Scratch Link. +2. Start Scratch 3.0 & AluxLabs Link. 3. Load the "LEGO MINDSTORMS EV3" extension. 4. Connect to the EV3. 5. **Test the `beep note () for () secs` block.** @@ -64,7 +64,7 @@ At least one of each: ### Bluetooth Toggle -1. Start Scratch 3.0 & Scratch Link. +1. Start Scratch 3.0 & AluxLabs Link. 2. Load the extension for any BLE or BT peripheral and connect to the peripheral. 3. Using the Windows or macOS controls, disable Bluetooth. 4. **Verify that Scratch displays a disconnect notification.** @@ -73,7 +73,7 @@ At least one of each: ### Computer Sleep -1. Start Scratch 3.0 & Scratch Link. +1. Start Scratch 3.0 & AluxLabs Link. 2. Load the extension for any BLE or BT peripheral and connect to the peripheral. 3. Cause your computer to enter sleep mode. 4. After a few seconds, wake your computer. From c1505cff9cd525779d81b71c3ed93894908767e2 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 May 2026 12:03:22 +0900 Subject: [PATCH 70/94] =?UTF-8?q?refactor(rebrand):=20Safari=20Helper=20?= =?UTF-8?q?=ED=8F=B4=EB=8D=94=20/=20=EC=8B=9D=EB=B3=84=EC=9E=90=20/=20?= =?UTF-8?q?=EC=99=B8=EB=B6=80=20=EC=B0=B8=EC=A1=B0=20=EC=9D=BC=EA=B4=84=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scratch Link Safari Helper 트리 전체를 AluxLabs Link Safari Helper 로 리네임하고, 그 안의 모든 Swift / pbxproj / xcscheme / xcconfig / plist / entitlements / Resources 안 식별자를 새 브랜드로 통일. 외부에서 이 폴더를 참조하던 메타도 함께 갱신. macOS / Xcode 빌드 환경은 현재 미보유 상태 이므로 실제 빌드/실행 검증은 향후 macOS 환경 확보 시 후속 작업. 폴더 / 파일 리네임: - 외부 폴더 + 내부 4개 sub-folder + xcodeproj 폴더 - xcscheme, .entitlements 3개, swift 테스트 3개 - Resources 안 scratch-link-extension*.js / scratch-link-safari-socket.mjs (kebab-case 파일명) 식별자 일괄 치환 (Safari Helper 트리 안 28개 파일): - Bundle ID: edu.mit.scratch.scratch-link* → com.aluxlabs.link* - Log subsystem: org.scratch.link → com.aluxlabs.link - Scratch_Link_Safari_* → AluxLabs_Link_Safari_* - Scratch Link Safari (Helper|Extension) → AluxLabs Link Safari ... - ScratchLog → AluxLabsLog, ScratchLink → AluxLabsLink - scratch-link / Scratch Link 잔여 일반 치환 외부 참조 갱신: - Makefile: scratch-link-mac / Scratch\ Link\ Safari\ * 경로 → AluxLabs 패턴 - .github/actions/macos-build/action.yml: sln / mac 폴더 / PKGFILE / notarize ID - aluxlabs-link-mac.csproj: Safari Helper path, Extension bundle name, xcodebuild 명령, fastlane provisionprofile 경로 남은 옛 이름은 모두 의도된 보존: - aluxlabs-link-*/Serial/*.cs 헤더 (fork 출처 attribution, AGPL-3.0) - NOTICE / NOTICE.ko / README.md (라이선스 / upstream 참조) - Documentation/Alux/{RebrandingPlan,ScratchVmInterop,KnownIssues}.md (매핑 표 / 호환 가이드 / 원본 Scratch Link 언급) - playground.html 안 node_modules/scratch-vm/... 경로 (외부 npm 패키지) - package-lock.json (npm metadata) Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/actions/macos-build/action.yml | 16 +- .../.gitignore | 0 ...luxLabs_Link_Safari_Extension.entitlements | 2 +- .../Info.plist | 0 .../JSON.swift | 2 +- .../AluxLabs Link Safari Extension}/Makefile | 0 .../Resources/_locales/en/messages.json | 4 +- .../aluxlabs-link-extension-background.js | 10 +- .../Resources/aluxlabs-link-extension.js | 64 ++--- .../Resources/images/icon-128.png | Bin .../Resources/images/icon-256.png | Bin .../Resources/images/icon-48.png | Bin .../Resources/images/icon-512.png | Bin .../Resources/images/icon-64.png | Bin .../Resources/images/icon-96.png | Bin .../Resources/images/toolbar-icon-16.png | Bin .../Resources/images/toolbar-icon-19.png | Bin .../Resources/images/toolbar-icon-32.png | Bin .../Resources/images/toolbar-icon-38.png | Bin .../Resources/images/toolbar-icon-48.png | Bin .../Resources/images/toolbar-icon-72.png | Bin .../Resources/manifest.json | 6 +- .../web/aluxlabs-link-safari-socket.mjs | 26 +- .../SafariWebExtensionHandler.swift | 10 +- .../ScratchLog.swift | 16 +- .../SessionDelegate.swift | 22 +- .../inject-version-info.sh | 2 +- .../project.pbxproj | 264 +++++++++--------- .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../AluxLabs Link Safari Helper.xcscheme | 30 +- .../AluxLabs Link Safari Helper.entitlements | 0 .../AluxLabs_Link_Safari_Helper.entitlements | 0 .../AppDelegate.swift | 2 +- .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 .../Assets.xcassets/Contents.json | 0 .../LargeIcon.imageset/Contents.json | 0 .../Base.lproj/Main.html | 8 +- .../Base.lproj/Main.storyboard | 14 +- .../Resources/Icon.png | Bin .../Resources/Script.js | 0 .../Resources/Style.css | 0 .../ViewController.swift | 4 +- .../AluxLabs_Link_Safari_HelperTests.swift | 8 +- .../AluxLabs_Link_Safari_HelperUITests.swift | 6 +- ...Link_Safari_HelperUITestsLaunchTests.swift | 6 +- .../All Configurations.xcconfig | 2 +- .../Configuration Files/Debug.xcconfig | 2 +- .../Configuration Files/Release.xcconfig | 2 +- .../Release_DevID.xcconfig | 4 +- .../Configuration Files/Release_MAS.xcconfig | 4 +- .../Configuration Files/Shipping.xcconfig | 4 +- .../Configuration Files/Version.xcconfig | 2 +- .../Safari WebExtension messaging.md | 4 +- Makefile | 128 ++++----- aluxlabs-link-mac/aluxlabs-link-mac.csproj | 12 +- 57 files changed, 343 insertions(+), 343 deletions(-) rename {Scratch Link Safari Helper => AluxLabs Link Safari Helper}/.gitignore (100%) rename Scratch Link Safari Helper/Scratch Link Safari Extension/Scratch_Link_Safari_Extension.entitlements => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/AluxLabs_Link_Safari_Extension.entitlements (86%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Info.plist (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/JSON.swift (91%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Makefile (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/_locales/en/messages.json (81%) rename Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/scratch-link-extension-background.js => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/aluxlabs-link-extension-background.js (90%) rename Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/scratch-link-extension.js => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/aluxlabs-link-extension.js (67%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/images/icon-128.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/images/icon-256.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/images/icon-48.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/images/icon-512.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/images/icon-64.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/images/icon-96.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/images/toolbar-icon-16.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/images/toolbar-icon-19.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/images/toolbar-icon-32.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/images/toolbar-icon-38.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/images/toolbar-icon-48.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/images/toolbar-icon-72.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/Resources/manifest.json (87%) rename Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/web/scratch-link-safari-socket.mjs => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/web/aluxlabs-link-safari-socket.mjs (90%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/SafariWebExtensionHandler.swift (94%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/ScratchLog.swift (53%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/SessionDelegate.swift (88%) rename {Scratch Link Safari Helper/Scratch Link Safari Extension => AluxLabs Link Safari Helper/AluxLabs Link Safari Extension}/inject-version-info.sh (97%) mode change 100755 => 100644 rename {Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj}/project.pbxproj (75%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj}/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj/xcshareddata/xcschemes/Scratch Link Safari Helper.xcscheme => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj/xcshareddata/xcschemes/AluxLabs Link Safari Helper.xcscheme (73%) rename Scratch Link Safari Helper/Scratch Link Safari Helper/Scratch Link Safari Helper.entitlements => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.entitlements (100%) rename Scratch Link Safari Helper/Scratch Link Safari Helper/Scratch_Link_Safari_Helper.entitlements => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/AluxLabs_Link_Safari_Helper.entitlements (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper}/AppDelegate.swift (93%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper}/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper}/Assets.xcassets/Contents.json (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper}/Assets.xcassets/LargeIcon.imageset/Contents.json (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper}/Base.lproj/Main.html (50%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper}/Base.lproj/Main.storyboard (88%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper}/Resources/Icon.png (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper}/Resources/Script.js (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper}/Resources/Style.css (100%) rename {Scratch Link Safari Helper/Scratch Link Safari Helper => AluxLabs Link Safari Helper/AluxLabs Link Safari Helper}/ViewController.swift (93%) rename Scratch Link Safari Helper/Scratch Link Safari HelperTests/Scratch_Link_Safari_HelperTests.swift => AluxLabs Link Safari Helper/AluxLabs Link Safari HelperTests/AluxLabs_Link_Safari_HelperTests.swift (86%) rename Scratch Link Safari Helper/Scratch Link Safari HelperUITests/Scratch_Link_Safari_HelperUITests.swift => AluxLabs Link Safari Helper/AluxLabs Link Safari HelperUITests/AluxLabs_Link_Safari_HelperUITests.swift (90%) rename Scratch Link Safari Helper/Scratch Link Safari HelperUITests/Scratch_Link_Safari_HelperUITestsLaunchTests.swift => AluxLabs Link Safari Helper/AluxLabs Link Safari HelperUITests/AluxLabs_Link_Safari_HelperUITestsLaunchTests.swift (81%) rename {Scratch Link Safari Helper => AluxLabs Link Safari Helper}/Configuration Files/All Configurations.xcconfig (90%) rename {Scratch Link Safari Helper => AluxLabs Link Safari Helper}/Configuration Files/Debug.xcconfig (95%) rename {Scratch Link Safari Helper => AluxLabs Link Safari Helper}/Configuration Files/Release.xcconfig (93%) rename {Scratch Link Safari Helper => AluxLabs Link Safari Helper}/Configuration Files/Release_DevID.xcconfig (70%) rename {Scratch Link Safari Helper => AluxLabs Link Safari Helper}/Configuration Files/Release_MAS.xcconfig (69%) rename {Scratch Link Safari Helper => AluxLabs Link Safari Helper}/Configuration Files/Shipping.xcconfig (84%) rename {Scratch Link Safari Helper => AluxLabs Link Safari Helper}/Configuration Files/Version.xcconfig (91%) rename {Scratch Link Safari Helper => AluxLabs Link Safari Helper}/Safari WebExtension messaging.md (95%) diff --git a/.github/actions/macos-build/action.yml b/.github/actions/macos-build/action.yml index 603cdc15..4105f330 100644 --- a/.github/actions/macos-build/action.yml +++ b/.github/actions/macos-build/action.yml @@ -41,16 +41,16 @@ runs: shell: bash run: | set -x # debug trace - msbuild -m -t:Restore -p:Configuration=${{ inputs.configuration }}_Mac scratch-link.sln - '/Applications/Visual Studio.app/Contents/MacOS/vstool' build -t:Build -c:'${{ inputs.configuration }}_Mac' "${PWD}/scratch-link.sln" + msbuild -m -t:Restore -p:Configuration=${{ inputs.configuration }}_Mac aluxlabs-link.sln + '/Applications/Visual Studio.app/Contents/MacOS/vstool' build -t:Build -c:'${{ inputs.configuration }}_Mac' "${PWD}/aluxlabs-link.sln" # "for" is just a convenient way to resolve the glob to a variable so we can DRY the filename for "if" and "mv" - for PKGPATH in scratch-link-mac/bin/"${{ inputs.configuration }}"/"Scratch Link"*.pkg; do + for PKGPATH in aluxlabs-link-mac/bin/"${{ inputs.configuration }}"/"AluxLabs Link"*.pkg; do if [ -r "$PKGPATH" ]; then # Get filename without path PKGFILE="${PKGPATH##*/}" if [ -n "${{ inputs.artifact_tag }}" ]; then - # change "Scratch Link-1.2.3" to "Scratch Link-Debug-1.2.3" - PKGFILE="${PKGFILE/Scratch Link/Scratch Link-${{ inputs.artifact_tag }}}" + # change "AluxLabs Link-1.2.3" to "AluxLabs Link-Debug-1.2.3" + PKGFILE="${PKGFILE/AluxLabs Link/AluxLabs Link-${{ inputs.artifact_tag }}}" fi mkdir -p Artifacts fi @@ -61,8 +61,8 @@ runs: if: env.ARTIFACT_TAG == 'notarizeMe' shell: bash run: | - for PKGPATH in Artifacts/"Scratch Link-notarizeMe"*.pkg; do + for PKGPATH in Artifacts/"AluxLabs Link-notarizeMe"*.pkg; do PKGFILE="${PKGPATH##*/}" - scratch-link-mac/notarize.sh edu.mit.scratch.scratch-link "${PKGPATH}" "${PKGPATH}" /tmp || rm -f "${PKGPATH}" - mv -v "${PKGPATH}" "Artifacts/${PKGFILE/Scratch Link-notarizeMe/Scratch Link}" + aluxlabs-link-mac/notarize.sh com.aluxlabs.link "${PKGPATH}" "${PKGPATH}" /tmp || rm -f "${PKGPATH}" + mv -v "${PKGPATH}" "Artifacts/${PKGFILE/AluxLabs Link-notarizeMe/AluxLabs Link}" done diff --git a/Scratch Link Safari Helper/.gitignore b/AluxLabs Link Safari Helper/.gitignore similarity index 100% rename from Scratch Link Safari Helper/.gitignore rename to AluxLabs Link Safari Helper/.gitignore diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Scratch_Link_Safari_Extension.entitlements b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/AluxLabs_Link_Safari_Extension.entitlements similarity index 86% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Scratch_Link_Safari_Extension.entitlements rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/AluxLabs_Link_Safari_Extension.entitlements index 4d459d9f..fd948774 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Extension/Scratch_Link_Safari_Extension.entitlements +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/AluxLabs_Link_Safari_Extension.entitlements @@ -9,7 +9,7 @@ com.apple.security.network.client com.apple.application-identifier - W7AR3WMP87.edu.mit.scratch.scratch-link.safari-extension + W7AR3WMP87.com.aluxlabs.link.safari-extension com.apple.developer.team-identifier W7AR3WMP87 diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Info.plist b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Info.plist similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Info.plist rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Info.plist diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/JSON.swift b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/JSON.swift similarity index 91% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/JSON.swift rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/JSON.swift index 7485437c..55bdaa3f 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Extension/JSON.swift +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/JSON.swift @@ -1,6 +1,6 @@ // // JSONPromise.swift -// Scratch Link Safari Extension +// AluxLabs Link Safari Extension // // Created by Christopher Willis-Ford on 3/30/22. // diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Makefile b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Makefile similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Makefile rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Makefile diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/_locales/en/messages.json b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/_locales/en/messages.json similarity index 81% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/_locales/en/messages.json rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/_locales/en/messages.json index 749a0aba..09caa613 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/_locales/en/messages.json +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/_locales/en/messages.json @@ -1,10 +1,10 @@ { "extension_name": { - "message": "Scratch Link", + "message": "AluxLabs Link", "description": "The display name for the extension." }, "extension_description": { - "message": "This extension allows Safari to communicate with Scratch Link.", + "message": "This extension allows Safari to communicate with AluxLabs Link.", "description": "Description of what the extension does." } } diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/scratch-link-extension-background.js b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/aluxlabs-link-extension-background.js similarity index 90% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/scratch-link-extension-background.js rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/aluxlabs-link-extension-background.js index c38e4cad..5443a729 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/scratch-link-extension-background.js +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/aluxlabs-link-extension-background.js @@ -43,18 +43,18 @@ browser.runtime.onMessage.addListener((request, sender, sendResponse) => { // handle a connection coming from a content script browser.runtime.onConnect.addListener(port => { // handle a message from the content script session associated with this port - port.onMessage.addListener(messageToScratchLink => { - const {session, method, params, id} = messageToScratchLink; + port.onMessage.addListener(messageToAluxLabsLink => { + const {session, method, params, id} = messageToAluxLabsLink; - // forward the message to the native app (which will forward it to Scratch Link) + // forward the message to the native app (which will forward it to AluxLabs Link) browser.runtime.sendNativeMessage(appId, { session, method, params, id - }, responseFromScratchLink => { + }, responseFromAluxLabsLink => { // send the native app's response back to the content script session - port.postMessage(responseFromScratchLink); + port.postMessage(responseFromAluxLabsLink); } ); } ); }); diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/scratch-link-extension.js b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/aluxlabs-link-extension.js similarity index 67% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/scratch-link-extension.js rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/aluxlabs-link-extension.js index ef98f595..6c5ee567 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/scratch-link-extension.js +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/aluxlabs-link-extension.js @@ -1,7 +1,7 @@ (function() { // If the native app sends a message to the background script, the Safari window pops to the front and steals focus. // Also, Safari unloads the native app if comms are idle for ~5 seconds. - // We can solve both of these problems by polling for messages from Scratch Link. + // We can solve both of these problems by polling for messages from AluxLabs Link. // Scratch projects generally run at 30 Hz max, so keep pollFrequency >= 30. // The browser will enforce some minimum amount of time (4 ms or more by spec), so at some point making this "faster" won't work. // TODO: consider polling for all sessions in this context at once instead of each independently. @@ -10,19 +10,19 @@ const pageSessions = new Map(); /** - * Check for an element in the document with id='scratch-link-extension-script'. + * Check for an element in the document with id='aluxlabs-link-extension-script'. * If found, inject the socket script into it. */ - const injectScratchLinkScript = () => { - const extensionScriptNode = document.getElementById("scratch-link-extension-script"); + const injectAluxLabsLinkScript = () => { + const extensionScriptNode = document.getElementById("aluxlabs-link-extension-script"); if (extensionScriptNode) { extensionScriptNode.innerHTML = ""; // make it safe to change "type" extensionScriptNode.type = "module"; extensionScriptNode.innerHTML = [ - `import("${browser.runtime.getURL("web/scratch-link-safari-socket.mjs")}").then(`, + `import("${browser.runtime.getURL("web/aluxlabs-link-safari-socket.mjs")}").then(`, " module => {", " self.Scratch = self.Scratch || {};", - " self.Scratch.ScratchLinkSafariSocket = module.ScratchLinkSafariSocket;", + " self.Scratch.AluxLabsLinkSafariSocket = module.AluxLabsLinkSafariSocket;", " }", ");" ].join("\n"); @@ -32,43 +32,43 @@ // This content script runs at "document_idle" (Document.readyState == complete) // so a static page should have this element ready by now. // If the script element is added dynamically, send the script injection message (see below). - injectScratchLinkScript(); + injectAluxLabsLinkScript(); // handle messages from the page self.addEventListener("message", event => { - const message = event.data["to-scratch-link"]; + const message = event.data["to-aluxlabs-link"]; if (message) { - onMessageToScratchLink(message, event.origin); - } else if (event.data["inject-scratch-link-script"]) { - injectScratchLinkScript(); + onMessageToAluxLabsLink(message, event.origin); + } else if (event.data["inject-aluxlabs-link-script"]) { + injectAluxLabsLinkScript(); } }); // handle messages from the background script browser.runtime.onMessage.addListener((outerMessage, sender, response) => { - const message = outerMessage["from-scratch-link"]; + const message = outerMessage["from-aluxlabs-link"]; if (message) { - // the client/page script needs the outerMessage so it can tell the message is from Scratch Link + // the client/page script needs the outerMessage so it can tell the message is from AluxLabs Link self.postMessage(outerMessage, self.origin); } }); /** - * Handles a message sent by the page and intended for Scratch Link. - * @param {object} messageToScratchLink - the "to-scratch-link" message from the page. + * Handles a message sent by the page and intended for AluxLabs Link. + * @param {object} messageToAluxLabsLink - the "to-aluxlabs-link" message from the page. * @param {string} origin - the origin of the page that sent the message. */ - const onMessageToScratchLink = async (messageToScratchLink, origin) => { - if (messageToScratchLink.method == "open") { - const openResponse = await browser.runtime.sendMessage(messageToScratchLink); + const onMessageToAluxLabsLink = async (messageToAluxLabsLink, origin) => { + if (messageToAluxLabsLink.method == "open") { + const openResponse = await browser.runtime.sendMessage(messageToAluxLabsLink); onSessionOpened(openResponse, origin); } else { - const sessionId = messageToScratchLink.session; + const sessionId = messageToAluxLabsLink.session; const port = pageSessions.get(sessionId); if (port) { - port.postMessage(messageToScratchLink); + port.postMessage(messageToAluxLabsLink); } else { - console.error("Scratch Link extension failed to find port for session", sessionId); + console.error("AluxLabs Link extension failed to find port for session", sessionId); } } }; @@ -77,7 +77,7 @@ // check for an error or otherwise bad response const sessionId = response.session; if (response.error || !sessionId || response.result !== sessionId) { - console.error("Scratch Link extension failed to open a session", response); + console.error("AluxLabs Link extension failed to open a session", response); return; } @@ -85,7 +85,7 @@ const port = browser.runtime.connect({name: sessionId.toString()}); pageSessions.set(sessionId, port); - // set up polling for messages from Scratch Link + // set up polling for messages from AluxLabs Link // we can reuse the same message repeatedly to save on GC const pollMessageId = 'web-extension-poll'; const sessionPollMessage = {method: 'poll', session: sessionId, id: pollMessageId}; @@ -107,27 +107,27 @@ // clean up on disconnect port.onDisconnect.addListener(() => { - console.log("Scratch Link extension disconnected a session", sessionId); + console.log("AluxLabs Link extension disconnected a session", sessionId); clearInterval(pollInterval); pageSessions.delete(response.session); }); - // forward messages from Scratch Link to the page - const onMessageFromScratchLink = messageFromScratchLink => { - switch (messageFromScratchLink.id) { + // forward messages from AluxLabs Link to the page + const onMessageFromAluxLabsLink = messageFromAluxLabsLink => { + switch (messageFromAluxLabsLink.id) { case pollMessageId: --pollPending; - handlePollResults(sessionId, messageFromScratchLink.result); + handlePollResults(sessionId, messageFromAluxLabsLink.result); break; default: - self.postMessage({"from-scratch-link": messageFromScratchLink}, origin); + self.postMessage({"from-aluxlabs-link": messageFromAluxLabsLink}, origin); break; } }; - port.onMessage.addListener(onMessageFromScratchLink); + port.onMessage.addListener(onMessageFromAluxLabsLink); // now that all the plumbing is ready, forward the 'open' message response to the page - onMessageFromScratchLink(response); + onMessageFromAluxLabsLink(response); }; const handlePollResults = (sessionId, messages) => { @@ -136,7 +136,7 @@ } for (let message of messages) { - self.postMessage({'from-scratch-link': { + self.postMessage({'from-aluxlabs-link': { session: sessionId, data: message }}, origin); diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/icon-128.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/icon-128.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/icon-128.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/icon-128.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/icon-256.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/icon-256.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/icon-256.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/icon-256.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/icon-48.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/icon-48.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/icon-48.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/icon-48.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/icon-512.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/icon-512.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/icon-512.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/icon-512.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/icon-64.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/icon-64.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/icon-64.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/icon-64.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/icon-96.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/icon-96.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/icon-96.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/icon-96.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/toolbar-icon-16.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/toolbar-icon-16.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/toolbar-icon-16.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/toolbar-icon-16.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/toolbar-icon-19.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/toolbar-icon-19.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/toolbar-icon-19.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/toolbar-icon-19.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/toolbar-icon-32.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/toolbar-icon-32.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/toolbar-icon-32.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/toolbar-icon-32.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/toolbar-icon-38.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/toolbar-icon-38.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/toolbar-icon-38.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/toolbar-icon-38.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/toolbar-icon-48.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/toolbar-icon-48.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/toolbar-icon-48.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/toolbar-icon-48.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/toolbar-icon-72.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/toolbar-icon-72.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/images/toolbar-icon-72.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/images/toolbar-icon-72.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/manifest.json b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/manifest.json similarity index 87% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/manifest.json rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/manifest.json index 4d1a476a..caee1069 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/manifest.json +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/manifest.json @@ -8,7 +8,7 @@ "version_name": "(placeholder for the user-friendly version number)", "web_accessible_resources": [ - "web/scratch-link-safari-socket.mjs" + "web/aluxlabs-link-safari-socket.mjs" ], "icons": { @@ -20,12 +20,12 @@ }, "background": { - "scripts": [ "scratch-link-extension-background.js" ], + "scripts": [ "aluxlabs-link-extension-background.js" ], "persistent": false }, "content_scripts": [{ - "js": [ "scratch-link-extension.js" ], + "js": [ "aluxlabs-link-extension.js" ], "matches": [ "" ] }], diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/web/scratch-link-safari-socket.mjs b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/web/aluxlabs-link-safari-socket.mjs similarity index 90% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/web/scratch-link-safari-socket.mjs rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/web/aluxlabs-link-safari-socket.mjs index db4871df..966c1271 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Extension/Resources/web/scratch-link-safari-socket.mjs +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/Resources/web/aluxlabs-link-safari-socket.mjs @@ -50,7 +50,7 @@ const registerResponseHandlers = function (handlers) { * @param {MessageEvent} event - the message event to handle */ const messageListener = function (event) { - const message = event.data['from-scratch-link']; + const message = event.data['from-aluxlabs-link']; if (!message) return; if (message.id && openRequests.has(message.id)) { const handlers = openRequests.get(message.id); @@ -78,9 +78,9 @@ const installListener = () => { }; /** - * ScratchLinkSafariSocket class: represents a Scratch Link session socket using the Safari extension as transport. + * AluxLabsLinkSafariSocket class: represents a AluxLabs Link session socket using the Safari extension as transport. */ -class ScratchLinkSafariSocket { +class AluxLabsLinkSafariSocket { /** * Check if it appears that the extension is active and this socket class can be used. @@ -93,7 +93,7 @@ class ScratchLinkSafariSocket { } /** - * Construct a new Scratch Link session socket. + * Construct a new AluxLabs Link session socket. * @param {string} type - the type of session, like 'ble' */ constructor (type) { @@ -107,7 +107,7 @@ class ScratchLinkSafariSocket { } /** - * Open communication with Scratch Link. + * Open communication with AluxLabs Link. * Calls the `onOpen` callback when the connection is established. */ open () { @@ -171,7 +171,7 @@ class ScratchLinkSafariSocket { } /** - * Send a message to Scratch Link + * Send a message to AluxLabs Link * @param {object} messageObject - a JSON-RPC 2.0 message object */ sendMessage (messageObject) { @@ -208,7 +208,7 @@ class ScratchLinkSafariSocket { } /** - * @param {function} callback - the function to call when a message is received from Scratch Link + * @param {function} callback - the function to call when a message is received from AluxLabs Link */ setHandleMessage (callback) { this._handleMessage = callback; @@ -230,21 +230,21 @@ class ScratchLinkSafariSocket { } _sendNotify (method, params = {}) { - this._toScratchLink(method, params, false); + this._toAluxLabsLink(method, params, false); } _sendRequest (method, params = {}) { - return this._toScratchLink(method, params, true); + return this._toAluxLabsLink(method, params, true); } /** - * Send a notification or request to Scratch Link. + * Send a notification or request to AluxLabs Link. * @param {string} method - the method to call * @param {object} params - optional parameters for the call * @param {boolean} expectResponse - true to send a request, false for a notification * @returns {Promise|undefined} - a Promise for the result of the request, if expectResponse is true */ - _toScratchLink (method, params, expectResponse) { + _toAluxLabsLink (method, params, expectResponse) { const message = { jsonrpc: '2.0', session: this._id, @@ -257,9 +257,9 @@ class ScratchLinkSafariSocket { message.id = registerResponseHandlers({resolve, reject}); }); } - self.postMessage({'to-scratch-link': message}, self.origin); + self.postMessage({'to-aluxlabs-link': message}, self.origin); return responsePromise; } } -export { ScratchLinkSafariSocket }; +export { AluxLabsLinkSafariSocket }; diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/SafariWebExtensionHandler.swift b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/SafariWebExtensionHandler.swift similarity index 94% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/SafariWebExtensionHandler.swift rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/SafariWebExtensionHandler.swift index 9ac92647..4d23bd31 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Extension/SafariWebExtensionHandler.swift +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/SafariWebExtensionHandler.swift @@ -1,6 +1,6 @@ // // SafariWebExtensionHandler.swift -// Scratch Link Safari Extension +// AluxLabs Link Safari Extension // // Created by Christopher Willis-Ford on 3/16/22. // @@ -37,17 +37,17 @@ class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { func beginRequest(with context: NSExtensionContext) { guard let message = getMessage(from: context) else { - ScratchLog.log("could not retrieve message", type: .error) + AluxLabsLog.log("could not retrieve message", type: .error) return } guard let jsonMessage = message as? JSONObject else { - ScratchLog.log("ignoring malformed message", type: .error) + AluxLabsLog.log("ignoring malformed message", type: .error) return } guard let method = jsonMessage["method"] as? String else { - ScratchLog.log("ignoring message without method", type: .error) + AluxLabsLog.log("ignoring message without method", type: .error) return } @@ -147,7 +147,7 @@ class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { } func unrecognizedMethod(with sessionID: UInt32?, method: String, params: JSONObject?, id: JSONValue?, completion: @escaping (JSONValueResult) -> Void) -> Void { - ScratchLog.log("Ignoring call to unrecognized method: %{public}@", type: .error, method) + AluxLabsLog.log("Ignoring call to unrecognized method: %{public}@", type: .error, method) return completion(.failure("unrecognized method")) } diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/ScratchLog.swift b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/ScratchLog.swift similarity index 53% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/ScratchLog.swift rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/ScratchLog.swift index 65859774..3087e7ac 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Extension/ScratchLog.swift +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/ScratchLog.swift @@ -1,6 +1,6 @@ // -// ScratchLog.swift -// Scratch Link Safari Extension +// AluxLabsLog.swift +// AluxLabs Link Safari Extension // // Created by Christopher Willis-Ford on 9/30/22. // @@ -8,23 +8,23 @@ import Foundation import os.log -class ScratchLog { - public static let logSubsystem = "org.scratch.link"; +class AluxLabsLog { + public static let logSubsystem = "com.aluxlabs.link"; public static let logCategory = "safari-extension"; - public static let shared = ScratchLog() + public static let shared = AluxLabsLog() public static func log(_ message: StaticString, type: OSLogType = .default, _ args: CVarArg...) { shared.doLog(message, type: type, args) } - private let scratchLog: OSLog + private let aluxLabsLog: OSLog private init() { - self.scratchLog = OSLog(subsystem: ScratchLog.logSubsystem, category: ScratchLog.logCategory) + self.aluxLabsLog = OSLog(subsystem: AluxLabsLog.logSubsystem, category: AluxLabsLog.logCategory) } private func doLog(_ message: StaticString, type: OSLogType = .default, _ args: CVarArg...) { - os_log(message, log: scratchLog, type: type, args) + os_log(message, log: aluxLabsLog, type: type, args) } } diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/SessionDelegate.swift b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/SessionDelegate.swift similarity index 88% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/SessionDelegate.swift rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/SessionDelegate.swift index a639a233..7de7720f 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Extension/SessionDelegate.swift +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/SessionDelegate.swift @@ -1,6 +1,6 @@ // // SessionDelegate.swift -// Scratch Link Safari Extension +// AluxLabs Link Safari Extension // // Created by Christopher Willis-Ford on 3/30/22. // @@ -102,7 +102,7 @@ class SessionDelegate: NSObject, URLSessionWebSocketDelegate { if let openCallback = openCallback { openCallback(.failure("closed")) } - ScratchLog.log("session closed", type: .info) + AluxLabsLog.log("session closed", type: .info) let oldCallbacks = closeCallbacks closeCallbacks = [] for callback in oldCallbacks { @@ -111,42 +111,42 @@ class SessionDelegate: NSObject, URLSessionWebSocketDelegate { } private func listen() { - let messageMalformed: StaticString = "received malformed message from Scratch Link" + let messageMalformed: StaticString = "received malformed message from AluxLabs Link" func receiveHandler(result: Result) -> Void { switch result { case .success(let response): switch response { case .string(let responseText): if let responseJSON = try? JSONSerialization.jsonObject(with: responseText.data(using: .utf8)!, options: []) as? JSONObject { - onMessageFromScratchLink(responseJSON) + onMessageFromAluxLabsLink(responseJSON) } else { - ScratchLog.log(messageMalformed, type: .error) + AluxLabsLog.log(messageMalformed, type: .error) } case .data(let responseData): if let responseJSON = try? JSONSerialization.jsonObject(with: responseData, options: []) as? JSONObject { - onMessageFromScratchLink(responseJSON) + onMessageFromAluxLabsLink(responseJSON) } else { - ScratchLog.log(messageMalformed, type: .error) + AluxLabsLog.log(messageMalformed, type: .error) } break // TODO: use responseData @unknown default: break // TODO: report error } case .failure(let error): - ScratchLog.log("error receiving from Scratch Link: %{public}@", type: .error, String(describing: error)) + AluxLabsLog.log("error receiving from AluxLabs Link: %{public}@", type: .error, String(describing: error)) } if webSocket?.state == .running { webSocket?.receive(completionHandler: receiveHandler) } else { - ScratchLog.log("closing session: socket not running", type: .error) - onMessageFromScratchLink(["method": "sessionDidClose"]) + AluxLabsLog.log("closing session: socket not running", type: .error) + onMessageFromAluxLabsLink(["method": "sessionDidClose"]) } } webSocket?.receive(completionHandler: receiveHandler) } - private func onMessageFromScratchLink(_ receivedJSON: JSONObject) { + private func onMessageFromAluxLabsLink(_ receivedJSON: JSONObject) { if receivedJSON["method"] == nil, let id = receivedJSON["id"] as? JSONValue, let pendingRequest = pendingRequests[id] { diff --git a/Scratch Link Safari Helper/Scratch Link Safari Extension/inject-version-info.sh b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/inject-version-info.sh old mode 100755 new mode 100644 similarity index 97% rename from Scratch Link Safari Helper/Scratch Link Safari Extension/inject-version-info.sh rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/inject-version-info.sh index 69e3c596..1e8dcc33 --- a/Scratch Link Safari Helper/Scratch Link Safari Extension/inject-version-info.sh +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Extension/inject-version-info.sh @@ -1,7 +1,7 @@ #!/bin/bash # inject-version-info.sh -# Scratch Link Safari Helper +# AluxLabs Link Safari Helper # # Created by Christopher Willis-Ford on 9/7/22. # diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj/project.pbxproj b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj/project.pbxproj similarity index 75% rename from Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj/project.pbxproj rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj/project.pbxproj index 76f5159e..d320afbf 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj/project.pbxproj +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj/project.pbxproj @@ -18,16 +18,16 @@ 69E961C227E28B86008CF7C0 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E961C127E28B86008CF7C0 /* ViewController.swift */; }; 69E961C527E28B86008CF7C0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 69E961C327E28B86008CF7C0 /* Main.storyboard */; }; 69E961C727E28B88008CF7C0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 69E961C627E28B88008CF7C0 /* Assets.xcassets */; }; - 69E961D327E28B88008CF7C0 /* Scratch_Link_Safari_HelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E961D227E28B88008CF7C0 /* Scratch_Link_Safari_HelperTests.swift */; }; - 69E961DD27E28B88008CF7C0 /* Scratch_Link_Safari_HelperUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E961DC27E28B88008CF7C0 /* Scratch_Link_Safari_HelperUITests.swift */; }; - 69E961DF27E28B88008CF7C0 /* Scratch_Link_Safari_HelperUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E961DE27E28B88008CF7C0 /* Scratch_Link_Safari_HelperUITestsLaunchTests.swift */; }; - 69E961E527E28B88008CF7C0 /* Scratch Link Safari Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 69E961E427E28B88008CF7C0 /* Scratch Link Safari Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 69E961D327E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E961D227E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperTests.swift */; }; + 69E961DD27E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E961DC27E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperUITests.swift */; }; + 69E961DF27E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E961DE27E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperUITestsLaunchTests.swift */; }; + 69E961E527E28B88008CF7C0 /* AluxLabs Link Safari Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 69E961E427E28B88008CF7C0 /* AluxLabs Link Safari Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 69E961EA27E28B88008CF7C0 /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E961E927E28B88008CF7C0 /* SafariWebExtensionHandler.swift */; }; 69E961ED27E28B88008CF7C0 /* _locales in Resources */ = {isa = PBXBuildFile; fileRef = 69E961EC27E28B88008CF7C0 /* _locales */; }; 69E961EF27E28B88008CF7C0 /* images in Resources */ = {isa = PBXBuildFile; fileRef = 69E961EE27E28B88008CF7C0 /* images */; }; - 69E961F327E28B88008CF7C0 /* scratch-link-extension.js in Resources */ = {isa = PBXBuildFile; fileRef = 69E961F227E28B88008CF7C0 /* scratch-link-extension.js */; }; - 69E961F527E28B88008CF7C0 /* scratch-link-extension-background.js in Resources */ = {isa = PBXBuildFile; fileRef = 69E961F427E28B88008CF7C0 /* scratch-link-extension-background.js */; }; - 69FCB6E028E750C400F753E6 /* ScratchLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69FCB6DF28E750C400F753E6 /* ScratchLog.swift */; }; + 69E961F327E28B88008CF7C0 /* aluxlabs-link-extension.js in Resources */ = {isa = PBXBuildFile; fileRef = 69E961F227E28B88008CF7C0 /* aluxlabs-link-extension.js */; }; + 69E961F527E28B88008CF7C0 /* aluxlabs-link-extension-background.js in Resources */ = {isa = PBXBuildFile; fileRef = 69E961F427E28B88008CF7C0 /* aluxlabs-link-extension-background.js */; }; + 69FCB6E028E750C400F753E6 /* AluxLabsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69FCB6DF28E750C400F753E6 /* AluxLabsLog.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -36,21 +36,21 @@ containerPortal = 69E961AA27E28B86008CF7C0 /* Project object */; proxyType = 1; remoteGlobalIDString = 69E961B127E28B86008CF7C0; - remoteInfo = "Scratch Link Safari Helper"; + remoteInfo = "AluxLabs Link Safari Helper"; }; 69E961D927E28B88008CF7C0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 69E961AA27E28B86008CF7C0 /* Project object */; proxyType = 1; remoteGlobalIDString = 69E961B127E28B86008CF7C0; - remoteInfo = "Scratch Link Safari Helper"; + remoteInfo = "AluxLabs Link Safari Helper"; }; 69E961E627E28B88008CF7C0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 69E961AA27E28B86008CF7C0 /* Project object */; proxyType = 1; remoteGlobalIDString = 69E961E327E28B88008CF7C0; - remoteInfo = "Scratch Link Safari Extension"; + remoteInfo = "AluxLabs Link Safari Extension"; }; /* End PBXContainerItemProxy section */ @@ -61,7 +61,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( - 69E961E527E28B88008CF7C0 /* Scratch Link Safari Extension.appex in Embed App Extensions */, + 69E961E527E28B88008CF7C0 /* AluxLabs Link Safari Extension.appex in Embed App Extensions */, ); name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -82,7 +82,7 @@ 69C52B3027F50E57006A46F3 /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = ""; }; 69E1236228A3536800F6AAD5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; 69E1236528A40EC000F6AAD5 /* web */ = {isa = PBXFileReference; lastKnownFileType = folder; path = web; sourceTree = ""; }; - 69E961B227E28B86008CF7C0 /* Scratch Link Safari Helper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Scratch Link Safari Helper.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 69E961B227E28B86008CF7C0 /* AluxLabs Link Safari Helper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AluxLabs Link Safari Helper.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 69E961B527E28B86008CF7C0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 69E961B927E28B86008CF7C0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = Base; path = ../Base.lproj/Main.html; sourceTree = ""; }; 69E961BB27E28B86008CF7C0 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = ""; }; @@ -91,23 +91,23 @@ 69E961C127E28B86008CF7C0 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 69E961C427E28B86008CF7C0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 69E961C627E28B88008CF7C0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 69E961C827E28B88008CF7C0 /* Scratch_Link_Safari_Helper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Scratch_Link_Safari_Helper.entitlements; sourceTree = ""; }; - 69E961C927E28B88008CF7C0 /* Scratch Link Safari Helper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Scratch Link Safari Helper.entitlements"; sourceTree = ""; }; - 69E961CE27E28B88008CF7C0 /* Scratch Link Safari HelperTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Scratch Link Safari HelperTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 69E961D227E28B88008CF7C0 /* Scratch_Link_Safari_HelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scratch_Link_Safari_HelperTests.swift; sourceTree = ""; }; - 69E961D827E28B88008CF7C0 /* Scratch Link Safari HelperUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Scratch Link Safari HelperUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 69E961DC27E28B88008CF7C0 /* Scratch_Link_Safari_HelperUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scratch_Link_Safari_HelperUITests.swift; sourceTree = ""; }; - 69E961DE27E28B88008CF7C0 /* Scratch_Link_Safari_HelperUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scratch_Link_Safari_HelperUITestsLaunchTests.swift; sourceTree = ""; }; - 69E961E427E28B88008CF7C0 /* Scratch Link Safari Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Scratch Link Safari Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; + 69E961C827E28B88008CF7C0 /* AluxLabs_Link_Safari_Helper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AluxLabs_Link_Safari_Helper.entitlements; sourceTree = ""; }; + 69E961C927E28B88008CF7C0 /* AluxLabs Link Safari Helper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "AluxLabs Link Safari Helper.entitlements"; sourceTree = ""; }; + 69E961CE27E28B88008CF7C0 /* AluxLabs Link Safari HelperTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "AluxLabs Link Safari HelperTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 69E961D227E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AluxLabs_Link_Safari_HelperTests.swift; sourceTree = ""; }; + 69E961D827E28B88008CF7C0 /* AluxLabs Link Safari HelperUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "AluxLabs Link Safari HelperUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 69E961DC27E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AluxLabs_Link_Safari_HelperUITests.swift; sourceTree = ""; }; + 69E961DE27E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AluxLabs_Link_Safari_HelperUITestsLaunchTests.swift; sourceTree = ""; }; + 69E961E427E28B88008CF7C0 /* AluxLabs Link Safari Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "AluxLabs Link Safari Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; 69E961E927E28B88008CF7C0 /* SafariWebExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariWebExtensionHandler.swift; sourceTree = ""; }; 69E961EC27E28B88008CF7C0 /* _locales */ = {isa = PBXFileReference; lastKnownFileType = folder; path = _locales; sourceTree = ""; }; 69E961EE27E28B88008CF7C0 /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; path = images; sourceTree = ""; }; 69E961F027E28B88008CF7C0 /* manifest.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = manifest.json; sourceTree = ""; }; - 69E961F227E28B88008CF7C0 /* scratch-link-extension.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "scratch-link-extension.js"; sourceTree = ""; }; - 69E961F427E28B88008CF7C0 /* scratch-link-extension-background.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "scratch-link-extension-background.js"; sourceTree = ""; }; + 69E961F227E28B88008CF7C0 /* aluxlabs-link-extension.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "aluxlabs-link-extension.js"; sourceTree = ""; }; + 69E961F427E28B88008CF7C0 /* aluxlabs-link-extension-background.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "aluxlabs-link-extension-background.js"; sourceTree = ""; }; 69E961FC27E28B88008CF7C0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 69E961FD27E28B88008CF7C0 /* Scratch_Link_Safari_Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Scratch_Link_Safari_Extension.entitlements; sourceTree = ""; }; - 69FCB6DF28E750C400F753E6 /* ScratchLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScratchLog.swift; sourceTree = ""; }; + 69E961FD27E28B88008CF7C0 /* AluxLabs_Link_Safari_Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AluxLabs_Link_Safari_Extension.entitlements; sourceTree = ""; }; + 69FCB6DF28E750C400F753E6 /* AluxLabsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AluxLabsLog.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -161,10 +161,10 @@ children = ( 69C52B2527ECCB57006A46F3 /* Safari WebExtension messaging.md */, 699401DA289DA5F300A46D3F /* Configuration Files */, - 69E961B427E28B86008CF7C0 /* Scratch Link Safari Helper */, - 69E961D127E28B88008CF7C0 /* Scratch Link Safari HelperTests */, - 69E961DB27E28B88008CF7C0 /* Scratch Link Safari HelperUITests */, - 69E961E827E28B88008CF7C0 /* Scratch Link Safari Extension */, + 69E961B427E28B86008CF7C0 /* AluxLabs Link Safari Helper */, + 69E961D127E28B88008CF7C0 /* AluxLabs Link Safari HelperTests */, + 69E961DB27E28B88008CF7C0 /* AluxLabs Link Safari HelperUITests */, + 69E961E827E28B88008CF7C0 /* AluxLabs Link Safari Extension */, 69E961B327E28B86008CF7C0 /* Products */, ); sourceTree = ""; @@ -172,26 +172,26 @@ 69E961B327E28B86008CF7C0 /* Products */ = { isa = PBXGroup; children = ( - 69E961B227E28B86008CF7C0 /* Scratch Link Safari Helper.app */, - 69E961CE27E28B88008CF7C0 /* Scratch Link Safari HelperTests.xctest */, - 69E961D827E28B88008CF7C0 /* Scratch Link Safari HelperUITests.xctest */, - 69E961E427E28B88008CF7C0 /* Scratch Link Safari Extension.appex */, + 69E961B227E28B86008CF7C0 /* AluxLabs Link Safari Helper.app */, + 69E961CE27E28B88008CF7C0 /* AluxLabs Link Safari HelperTests.xctest */, + 69E961D827E28B88008CF7C0 /* AluxLabs Link Safari HelperUITests.xctest */, + 69E961E427E28B88008CF7C0 /* AluxLabs Link Safari Extension.appex */, ); name = Products; sourceTree = ""; }; - 69E961B427E28B86008CF7C0 /* Scratch Link Safari Helper */ = { + 69E961B427E28B86008CF7C0 /* AluxLabs Link Safari Helper */ = { isa = PBXGroup; children = ( 69E961B527E28B86008CF7C0 /* AppDelegate.swift */, 69E961C127E28B86008CF7C0 /* ViewController.swift */, 69E961C327E28B86008CF7C0 /* Main.storyboard */, 69E961C627E28B88008CF7C0 /* Assets.xcassets */, - 69E961C827E28B88008CF7C0 /* Scratch_Link_Safari_Helper.entitlements */, - 69E961C927E28B88008CF7C0 /* Scratch Link Safari Helper.entitlements */, + 69E961C827E28B88008CF7C0 /* AluxLabs_Link_Safari_Helper.entitlements */, + 69E961C927E28B88008CF7C0 /* AluxLabs Link Safari Helper.entitlements */, 69E961B727E28B86008CF7C0 /* Resources */, ); - path = "Scratch Link Safari Helper"; + path = "AluxLabs Link Safari Helper"; sourceTree = ""; }; 69E961B727E28B86008CF7C0 /* Resources */ = { @@ -205,37 +205,37 @@ path = Resources; sourceTree = ""; }; - 69E961D127E28B88008CF7C0 /* Scratch Link Safari HelperTests */ = { + 69E961D127E28B88008CF7C0 /* AluxLabs Link Safari HelperTests */ = { isa = PBXGroup; children = ( - 69E961D227E28B88008CF7C0 /* Scratch_Link_Safari_HelperTests.swift */, + 69E961D227E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperTests.swift */, ); - path = "Scratch Link Safari HelperTests"; + path = "AluxLabs Link Safari HelperTests"; sourceTree = ""; }; - 69E961DB27E28B88008CF7C0 /* Scratch Link Safari HelperUITests */ = { + 69E961DB27E28B88008CF7C0 /* AluxLabs Link Safari HelperUITests */ = { isa = PBXGroup; children = ( - 69E961DC27E28B88008CF7C0 /* Scratch_Link_Safari_HelperUITests.swift */, - 69E961DE27E28B88008CF7C0 /* Scratch_Link_Safari_HelperUITestsLaunchTests.swift */, + 69E961DC27E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperUITests.swift */, + 69E961DE27E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperUITestsLaunchTests.swift */, ); - path = "Scratch Link Safari HelperUITests"; + path = "AluxLabs Link Safari HelperUITests"; sourceTree = ""; }; - 69E961E827E28B88008CF7C0 /* Scratch Link Safari Extension */ = { + 69E961E827E28B88008CF7C0 /* AluxLabs Link Safari Extension */ = { isa = PBXGroup; children = ( 69E1236228A3536800F6AAD5 /* Makefile */, 69C52B3027F50E57006A46F3 /* JSON.swift */, 69E961E927E28B88008CF7C0 /* SafariWebExtensionHandler.swift */, - 69FCB6DF28E750C400F753E6 /* ScratchLog.swift */, + 69FCB6DF28E750C400F753E6 /* AluxLabsLog.swift */, 69C52B2E27F502F2006A46F3 /* SessionDelegate.swift */, 69E961FC27E28B88008CF7C0 /* Info.plist */, - 69E961FD27E28B88008CF7C0 /* Scratch_Link_Safari_Extension.entitlements */, + 69E961FD27E28B88008CF7C0 /* AluxLabs_Link_Safari_Extension.entitlements */, 69E961EB27E28B88008CF7C0 /* Resources */, 694C924028C90B2A00182C58 /* inject-version-info.sh */, ); - path = "Scratch Link Safari Extension"; + path = "AluxLabs Link Safari Extension"; sourceTree = ""; }; 69E961EB27E28B88008CF7C0 /* Resources */ = { @@ -245,8 +245,8 @@ 69E961EC27E28B88008CF7C0 /* _locales */, 69E961EE27E28B88008CF7C0 /* images */, 69E961F027E28B88008CF7C0 /* manifest.json */, - 69E961F227E28B88008CF7C0 /* scratch-link-extension.js */, - 69E961F427E28B88008CF7C0 /* scratch-link-extension-background.js */, + 69E961F227E28B88008CF7C0 /* aluxlabs-link-extension.js */, + 69E961F427E28B88008CF7C0 /* aluxlabs-link-extension-background.js */, ); path = Resources; sourceTree = ""; @@ -254,9 +254,9 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 69E961B127E28B86008CF7C0 /* Scratch Link Safari Helper */ = { + 69E961B127E28B86008CF7C0 /* AluxLabs Link Safari Helper */ = { isa = PBXNativeTarget; - buildConfigurationList = 69E9620427E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "Scratch Link Safari Helper" */; + buildConfigurationList = 69E9620427E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "AluxLabs Link Safari Helper" */; buildPhases = ( 69E961AE27E28B86008CF7C0 /* Sources */, 69E961AF27E28B86008CF7C0 /* Frameworks */, @@ -268,14 +268,14 @@ dependencies = ( 69E961E727E28B88008CF7C0 /* PBXTargetDependency */, ); - name = "Scratch Link Safari Helper"; - productName = "Scratch Link Safari Helper"; - productReference = 69E961B227E28B86008CF7C0 /* Scratch Link Safari Helper.app */; + name = "AluxLabs Link Safari Helper"; + productName = "AluxLabs Link Safari Helper"; + productReference = 69E961B227E28B86008CF7C0 /* AluxLabs Link Safari Helper.app */; productType = "com.apple.product-type.application"; }; - 69E961CD27E28B88008CF7C0 /* Scratch Link Safari HelperTests */ = { + 69E961CD27E28B88008CF7C0 /* AluxLabs Link Safari HelperTests */ = { isa = PBXNativeTarget; - buildConfigurationList = 69E9620727E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "Scratch Link Safari HelperTests" */; + buildConfigurationList = 69E9620727E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "AluxLabs Link Safari HelperTests" */; buildPhases = ( 69E961CA27E28B88008CF7C0 /* Sources */, 69E961CB27E28B88008CF7C0 /* Frameworks */, @@ -286,14 +286,14 @@ dependencies = ( 69E961D027E28B88008CF7C0 /* PBXTargetDependency */, ); - name = "Scratch Link Safari HelperTests"; - productName = "Scratch Link Safari HelperTests"; - productReference = 69E961CE27E28B88008CF7C0 /* Scratch Link Safari HelperTests.xctest */; + name = "AluxLabs Link Safari HelperTests"; + productName = "AluxLabs Link Safari HelperTests"; + productReference = 69E961CE27E28B88008CF7C0 /* AluxLabs Link Safari HelperTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; - 69E961D727E28B88008CF7C0 /* Scratch Link Safari HelperUITests */ = { + 69E961D727E28B88008CF7C0 /* AluxLabs Link Safari HelperUITests */ = { isa = PBXNativeTarget; - buildConfigurationList = 69E9620A27E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "Scratch Link Safari HelperUITests" */; + buildConfigurationList = 69E9620A27E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "AluxLabs Link Safari HelperUITests" */; buildPhases = ( 69E961D427E28B88008CF7C0 /* Sources */, 69E961D527E28B88008CF7C0 /* Frameworks */, @@ -304,14 +304,14 @@ dependencies = ( 69E961DA27E28B88008CF7C0 /* PBXTargetDependency */, ); - name = "Scratch Link Safari HelperUITests"; - productName = "Scratch Link Safari HelperUITests"; - productReference = 69E961D827E28B88008CF7C0 /* Scratch Link Safari HelperUITests.xctest */; + name = "AluxLabs Link Safari HelperUITests"; + productName = "AluxLabs Link Safari HelperUITests"; + productReference = 69E961D827E28B88008CF7C0 /* AluxLabs Link Safari HelperUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; - 69E961E327E28B88008CF7C0 /* Scratch Link Safari Extension */ = { + 69E961E327E28B88008CF7C0 /* AluxLabs Link Safari Extension */ = { isa = PBXNativeTarget; - buildConfigurationList = 69E9620027E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "Scratch Link Safari Extension" */; + buildConfigurationList = 69E9620027E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "AluxLabs Link Safari Extension" */; buildPhases = ( 69E961E027E28B88008CF7C0 /* Sources */, 69E961E127E28B88008CF7C0 /* Frameworks */, @@ -322,9 +322,9 @@ ); dependencies = ( ); - name = "Scratch Link Safari Extension"; - productName = "Scratch Link Safari Extension"; - productReference = 69E961E427E28B88008CF7C0 /* Scratch Link Safari Extension.appex */; + name = "AluxLabs Link Safari Extension"; + productName = "AluxLabs Link Safari Extension"; + productReference = 69E961E427E28B88008CF7C0 /* AluxLabs Link Safari Extension.appex */; productType = "com.apple.product-type.app-extension"; }; /* End PBXNativeTarget section */ @@ -353,7 +353,7 @@ }; }; }; - buildConfigurationList = 69E961AD27E28B86008CF7C0 /* Build configuration list for PBXProject "Scratch Link Safari Helper" */; + buildConfigurationList = 69E961AD27E28B86008CF7C0 /* Build configuration list for PBXProject "AluxLabs Link Safari Helper" */; compatibilityVersion = "Xcode 13.0"; developmentRegion = en; hasScannedForEncodings = 0; @@ -366,10 +366,10 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 69E961B127E28B86008CF7C0 /* Scratch Link Safari Helper */, - 69E961CD27E28B88008CF7C0 /* Scratch Link Safari HelperTests */, - 69E961D727E28B88008CF7C0 /* Scratch Link Safari HelperUITests */, - 69E961E327E28B88008CF7C0 /* Scratch Link Safari Extension */, + 69E961B127E28B86008CF7C0 /* AluxLabs Link Safari Helper */, + 69E961CD27E28B88008CF7C0 /* AluxLabs Link Safari HelperTests */, + 69E961D727E28B88008CF7C0 /* AluxLabs Link Safari HelperUITests */, + 69E961E327E28B88008CF7C0 /* AluxLabs Link Safari Extension */, ); }; /* End PBXProject section */ @@ -406,11 +406,11 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 69E961F327E28B88008CF7C0 /* scratch-link-extension.js in Resources */, + 69E961F327E28B88008CF7C0 /* aluxlabs-link-extension.js in Resources */, 69E961EF27E28B88008CF7C0 /* images in Resources */, 69E1236628A40EC000F6AAD5 /* web in Resources */, 69E961ED27E28B88008CF7C0 /* _locales in Resources */, - 69E961F527E28B88008CF7C0 /* scratch-link-extension-background.js in Resources */, + 69E961F527E28B88008CF7C0 /* aluxlabs-link-extension-background.js in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -453,7 +453,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 69E961D327E28B88008CF7C0 /* Scratch_Link_Safari_HelperTests.swift in Sources */, + 69E961D327E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -461,8 +461,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 69E961DD27E28B88008CF7C0 /* Scratch_Link_Safari_HelperUITests.swift in Sources */, - 69E961DF27E28B88008CF7C0 /* Scratch_Link_Safari_HelperUITestsLaunchTests.swift in Sources */, + 69E961DD27E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperUITests.swift in Sources */, + 69E961DF27E28B88008CF7C0 /* AluxLabs_Link_Safari_HelperUITestsLaunchTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -471,7 +471,7 @@ buildActionMask = 2147483647; files = ( 69E961EA27E28B88008CF7C0 /* SafariWebExtensionHandler.swift in Sources */, - 69FCB6E028E750C400F753E6 /* ScratchLog.swift in Sources */, + 69FCB6E028E750C400F753E6 /* AluxLabsLog.swift in Sources */, 69C52B3127F50E57006A46F3 /* JSON.swift in Sources */, 69C52B2F27F502F2006A46F3 /* SessionDelegate.swift in Sources */, ); @@ -482,17 +482,17 @@ /* Begin PBXTargetDependency section */ 69E961D027E28B88008CF7C0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 69E961B127E28B86008CF7C0 /* Scratch Link Safari Helper */; + target = 69E961B127E28B86008CF7C0 /* AluxLabs Link Safari Helper */; targetProxy = 69E961CF27E28B88008CF7C0 /* PBXContainerItemProxy */; }; 69E961DA27E28B88008CF7C0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 69E961B127E28B86008CF7C0 /* Scratch Link Safari Helper */; + target = 69E961B127E28B86008CF7C0 /* AluxLabs Link Safari Helper */; targetProxy = 69E961D927E28B88008CF7C0 /* PBXContainerItemProxy */; }; 69E961E727E28B88008CF7C0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 69E961E327E28B88008CF7C0 /* Scratch Link Safari Extension */; + target = 69E961E327E28B88008CF7C0 /* AluxLabs Link Safari Extension */; targetProxy = 69E961E627E28B88008CF7C0 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -577,11 +577,11 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = "Scratch Link Safari Helper/Scratch Link Safari Helper.entitlements"; + CODE_SIGN_ENTITLEMENTS = "AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.entitlements"; COMBINE_HIDPI_IMAGES = YES; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_CFBundleDisplayName = "Scratch Link Safari Helper"; + INFOPLIST_KEY_CFBundleDisplayName = "AluxLabs Link Safari Helper"; INFOPLIST_KEY_NSMainStoryboardFile = Main; INFOPLIST_KEY_NSPrincipalClass = NSApplication; LD_RUNPATH_SEARCH_PATHS = ( @@ -594,7 +594,7 @@ "-framework", WebKit, ); - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; }; @@ -607,10 +607,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; GENERATE_INFOPLIST_FILE = YES; - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link.safari-helper.tests"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link.safari-helper.tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Scratch Link Safari Helper.app/Contents/MacOS/Scratch Link Safari Helper"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AluxLabs Link Safari Helper.app/Contents/MacOS/AluxLabs Link Safari Helper"; }; name = Release_MAS; }; @@ -620,10 +620,10 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; GENERATE_INFOPLIST_FILE = YES; - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link.safari-helper.uitests"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link.safari-helper.uitests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; - TEST_TARGET_NAME = "Scratch Link Safari Helper"; + TEST_TARGET_NAME = "AluxLabs Link Safari Helper"; }; name = Release_MAS; }; @@ -631,11 +631,11 @@ isa = XCBuildConfiguration; baseConfigurationReference = 699401DD289DA67700A46D3F /* Release_MAS.xcconfig */; buildSettings = { - CODE_SIGN_ENTITLEMENTS = "Scratch Link Safari Extension/Scratch_Link_Safari_Extension.entitlements"; + CODE_SIGN_ENTITLEMENTS = "AluxLabs Link Safari Extension/AluxLabs_Link_Safari_Extension.entitlements"; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = "Scratch Link Safari Extension/Info.plist"; - INFOPLIST_KEY_CFBundleDisplayName = "Scratch Link Safari Extension"; + INFOPLIST_FILE = "AluxLabs Link Safari Extension/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "AluxLabs Link Safari Extension"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -645,7 +645,7 @@ "-framework", SafariServices, ); - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link.safari-extension"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link.safari-extension"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; @@ -712,11 +712,11 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = "Scratch Link Safari Helper/Scratch Link Safari Helper.entitlements"; + CODE_SIGN_ENTITLEMENTS = "AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.entitlements"; COMBINE_HIDPI_IMAGES = YES; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_CFBundleDisplayName = "Scratch Link Safari Helper"; + INFOPLIST_KEY_CFBundleDisplayName = "AluxLabs Link Safari Helper"; INFOPLIST_KEY_NSMainStoryboardFile = Main; INFOPLIST_KEY_NSPrincipalClass = NSApplication; LD_RUNPATH_SEARCH_PATHS = ( @@ -729,7 +729,7 @@ "-framework", WebKit, ); - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; }; @@ -742,10 +742,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; GENERATE_INFOPLIST_FILE = YES; - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link.safari-helper.tests"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link.safari-helper.tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Scratch Link Safari Helper.app/Contents/MacOS/Scratch Link Safari Helper"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AluxLabs Link Safari Helper.app/Contents/MacOS/AluxLabs Link Safari Helper"; }; name = Release_DevID; }; @@ -755,10 +755,10 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; GENERATE_INFOPLIST_FILE = YES; - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link.safari-helper.uitests"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link.safari-helper.uitests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; - TEST_TARGET_NAME = "Scratch Link Safari Helper"; + TEST_TARGET_NAME = "AluxLabs Link Safari Helper"; }; name = Release_DevID; }; @@ -766,11 +766,11 @@ isa = XCBuildConfiguration; baseConfigurationReference = 699401DC289DA65C00A46D3F /* Release_DevID.xcconfig */; buildSettings = { - CODE_SIGN_ENTITLEMENTS = "Scratch Link Safari Extension/Scratch_Link_Safari_Extension.entitlements"; + CODE_SIGN_ENTITLEMENTS = "AluxLabs Link Safari Extension/AluxLabs_Link_Safari_Extension.entitlements"; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = "Scratch Link Safari Extension/Info.plist"; - INFOPLIST_KEY_CFBundleDisplayName = "Scratch Link Safari Extension"; + INFOPLIST_FILE = "AluxLabs Link Safari Extension/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "AluxLabs Link Safari Extension"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -780,7 +780,7 @@ "-framework", SafariServices, ); - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link.safari-extension"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link.safari-extension"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; @@ -897,11 +897,11 @@ isa = XCBuildConfiguration; baseConfigurationReference = 699401D9289DA5E600A46D3F /* Debug.xcconfig */; buildSettings = { - CODE_SIGN_ENTITLEMENTS = "Scratch Link Safari Extension/Scratch_Link_Safari_Extension.entitlements"; + CODE_SIGN_ENTITLEMENTS = "AluxLabs Link Safari Extension/AluxLabs_Link_Safari_Extension.entitlements"; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = "Scratch Link Safari Extension/Info.plist"; - INFOPLIST_KEY_CFBundleDisplayName = "Scratch Link Safari Extension"; + INFOPLIST_FILE = "AluxLabs Link Safari Extension/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "AluxLabs Link Safari Extension"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -911,7 +911,7 @@ "-framework", SafariServices, ); - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link.safari-extension"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link.safari-extension"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; @@ -922,11 +922,11 @@ isa = XCBuildConfiguration; baseConfigurationReference = 699401DB289DA64100A46D3F /* Release.xcconfig */; buildSettings = { - CODE_SIGN_ENTITLEMENTS = "Scratch Link Safari Extension/Scratch_Link_Safari_Extension.entitlements"; + CODE_SIGN_ENTITLEMENTS = "AluxLabs Link Safari Extension/AluxLabs_Link_Safari_Extension.entitlements"; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = "Scratch Link Safari Extension/Info.plist"; - INFOPLIST_KEY_CFBundleDisplayName = "Scratch Link Safari Extension"; + INFOPLIST_FILE = "AluxLabs Link Safari Extension/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "AluxLabs Link Safari Extension"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -936,7 +936,7 @@ "-framework", SafariServices, ); - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link.safari-extension"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link.safari-extension"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; @@ -950,11 +950,11 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = "Scratch Link Safari Helper/Scratch Link Safari Helper.entitlements"; + CODE_SIGN_ENTITLEMENTS = "AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.entitlements"; COMBINE_HIDPI_IMAGES = YES; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_CFBundleDisplayName = "Scratch Link Safari Helper"; + INFOPLIST_KEY_CFBundleDisplayName = "AluxLabs Link Safari Helper"; INFOPLIST_KEY_NSMainStoryboardFile = Main; INFOPLIST_KEY_NSPrincipalClass = NSApplication; LD_RUNPATH_SEARCH_PATHS = ( @@ -967,7 +967,7 @@ "-framework", WebKit, ); - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; }; @@ -980,11 +980,11 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = "Scratch Link Safari Helper/Scratch Link Safari Helper.entitlements"; + CODE_SIGN_ENTITLEMENTS = "AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.entitlements"; COMBINE_HIDPI_IMAGES = YES; ENABLE_HARDENED_RUNTIME = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_CFBundleDisplayName = "Scratch Link Safari Helper"; + INFOPLIST_KEY_CFBundleDisplayName = "AluxLabs Link Safari Helper"; INFOPLIST_KEY_NSMainStoryboardFile = Main; INFOPLIST_KEY_NSPrincipalClass = NSApplication; LD_RUNPATH_SEARCH_PATHS = ( @@ -997,7 +997,7 @@ "-framework", WebKit, ); - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; }; @@ -1010,10 +1010,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; GENERATE_INFOPLIST_FILE = YES; - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link.safari-helper.tests"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link.safari-helper.tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Scratch Link Safari Helper.app/Contents/MacOS/Scratch Link Safari Helper"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AluxLabs Link Safari Helper.app/Contents/MacOS/AluxLabs Link Safari Helper"; }; name = Debug; }; @@ -1024,10 +1024,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; GENERATE_INFOPLIST_FILE = YES; - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link.safari-helper.tests"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link.safari-helper.tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Scratch Link Safari Helper.app/Contents/MacOS/Scratch Link Safari Helper"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AluxLabs Link Safari Helper.app/Contents/MacOS/AluxLabs Link Safari Helper"; }; name = Release; }; @@ -1037,10 +1037,10 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; GENERATE_INFOPLIST_FILE = YES; - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link.safari-helper.uitests"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link.safari-helper.uitests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; - TEST_TARGET_NAME = "Scratch Link Safari Helper"; + TEST_TARGET_NAME = "AluxLabs Link Safari Helper"; }; name = Debug; }; @@ -1050,17 +1050,17 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; GENERATE_INFOPLIST_FILE = YES; - PRODUCT_BUNDLE_IDENTIFIER = "edu.mit.scratch.scratch-link.safari-helper.uitests"; + PRODUCT_BUNDLE_IDENTIFIER = "com.aluxlabs.link.safari-helper.uitests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; - TEST_TARGET_NAME = "Scratch Link Safari Helper"; + TEST_TARGET_NAME = "AluxLabs Link Safari Helper"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 69E961AD27E28B86008CF7C0 /* Build configuration list for PBXProject "Scratch Link Safari Helper" */ = { + 69E961AD27E28B86008CF7C0 /* Build configuration list for PBXProject "AluxLabs Link Safari Helper" */ = { isa = XCConfigurationList; buildConfigurations = ( 69E961FE27E28B88008CF7C0 /* Debug */, @@ -1071,7 +1071,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; - 69E9620027E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "Scratch Link Safari Extension" */ = { + 69E9620027E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "AluxLabs Link Safari Extension" */ = { isa = XCConfigurationList; buildConfigurations = ( 69E9620127E28B88008CF7C0 /* Debug */, @@ -1082,7 +1082,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; - 69E9620427E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "Scratch Link Safari Helper" */ = { + 69E9620427E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "AluxLabs Link Safari Helper" */ = { isa = XCConfigurationList; buildConfigurations = ( 69E9620527E28B88008CF7C0 /* Debug */, @@ -1093,7 +1093,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; - 69E9620727E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "Scratch Link Safari HelperTests" */ = { + 69E9620727E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "AluxLabs Link Safari HelperTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 69E9620827E28B88008CF7C0 /* Debug */, @@ -1104,7 +1104,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; - 69E9620A27E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "Scratch Link Safari HelperUITests" */ = { + 69E9620A27E28B88008CF7C0 /* Build configuration list for PBXNativeTarget "AluxLabs Link Safari HelperUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( 69E9620B27E28B88008CF7C0 /* Debug */, diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj/xcshareddata/xcschemes/Scratch Link Safari Helper.xcscheme b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj/xcshareddata/xcschemes/AluxLabs Link Safari Helper.xcscheme similarity index 73% rename from Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj/xcshareddata/xcschemes/Scratch Link Safari Helper.xcscheme rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj/xcshareddata/xcschemes/AluxLabs Link Safari Helper.xcscheme index 56655b44..3a8a3d07 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Helper.xcodeproj/xcshareddata/xcschemes/Scratch Link Safari Helper.xcscheme +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.xcodeproj/xcshareddata/xcschemes/AluxLabs Link Safari Helper.xcscheme @@ -15,9 +15,9 @@ + BuildableName = "AluxLabs Link Safari Helper.app" + BlueprintName = "AluxLabs Link Safari Helper" + ReferencedContainer = "container:AluxLabs Link Safari Helper.xcodeproj"> @@ -33,9 +33,9 @@ + BuildableName = "AluxLabs Link Safari HelperTests.xctest" + BlueprintName = "AluxLabs Link Safari HelperTests" + ReferencedContainer = "container:AluxLabs Link Safari Helper.xcodeproj"> + BuildableName = "AluxLabs Link Safari HelperUITests.xctest" + BlueprintName = "AluxLabs Link Safari HelperUITests" + ReferencedContainer = "container:AluxLabs Link Safari Helper.xcodeproj"> @@ -65,9 +65,9 @@ + BuildableName = "AluxLabs Link Safari Helper.app" + BlueprintName = "AluxLabs Link Safari Helper" + ReferencedContainer = "container:AluxLabs Link Safari Helper.xcodeproj"> @@ -82,9 +82,9 @@ + BuildableName = "AluxLabs Link Safari Helper.app" + BlueprintName = "AluxLabs Link Safari Helper" + ReferencedContainer = "container:AluxLabs Link Safari Helper.xcodeproj"> diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/Scratch Link Safari Helper.entitlements b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.entitlements similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/Scratch Link Safari Helper.entitlements rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper.entitlements diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/Scratch_Link_Safari_Helper.entitlements b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/AluxLabs_Link_Safari_Helper.entitlements similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/Scratch_Link_Safari_Helper.entitlements rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/AluxLabs_Link_Safari_Helper.entitlements diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/AppDelegate.swift b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/AppDelegate.swift similarity index 93% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/AppDelegate.swift rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/AppDelegate.swift index 05f756b3..2628cf1a 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Helper/AppDelegate.swift +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/AppDelegate.swift @@ -1,6 +1,6 @@ // // AppDelegate.swift -// Scratch Link Safari Helper +// AluxLabs Link Safari Helper // // Created by Christopher Willis-Ford on 3/16/22. // diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/Assets.xcassets/AccentColor.colorset/Contents.json b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/Assets.xcassets/AccentColor.colorset/Contents.json rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/Assets.xcassets/AppIcon.appiconset/Contents.json b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/Assets.xcassets/AppIcon.appiconset/Contents.json rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/Assets.xcassets/Contents.json b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Assets.xcassets/Contents.json similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/Assets.xcassets/Contents.json rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Assets.xcassets/Contents.json diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/Assets.xcassets/LargeIcon.imageset/Contents.json b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Assets.xcassets/LargeIcon.imageset/Contents.json similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/Assets.xcassets/LargeIcon.imageset/Contents.json rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Assets.xcassets/LargeIcon.imageset/Contents.json diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/Base.lproj/Main.html b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Base.lproj/Main.html similarity index 50% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/Base.lproj/Main.html rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Base.lproj/Main.html index 3dc19919..28c4f53c 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Helper/Base.lproj/Main.html +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Base.lproj/Main.html @@ -10,10 +10,10 @@ - Scratch Link Safari Helper Icon -

You can turn on Scratch Link Safari Helper’s extension in Safari Extensions preferences.

-

Scratch Link Safari Helper’s extension is currently on. You can turn it off in Safari Extensions preferences.

-

Scratch Link Safari Helper’s extension is currently off. You can turn it on in Safari Extensions preferences.

+ AluxLabs Link Safari Helper Icon +

You can turn on AluxLabs Link Safari Helper’s extension in Safari Extensions preferences.

+

AluxLabs Link Safari Helper’s extension is currently on. You can turn it off in Safari Extensions preferences.

+

AluxLabs Link Safari Helper’s extension is currently off. You can turn it on in Safari Extensions preferences.

diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/Base.lproj/Main.storyboard b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Base.lproj/Main.storyboard similarity index 88% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/Base.lproj/Main.storyboard rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Base.lproj/Main.storyboard index 4073c9bd..97e01f2d 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Helper/Base.lproj/Main.storyboard +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Base.lproj/Main.storyboard @@ -12,18 +12,18 @@ - + - + - + - + @@ -41,7 +41,7 @@ - + @@ -53,7 +53,7 @@ - + @@ -77,7 +77,7 @@ - + diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/Resources/Icon.png b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Resources/Icon.png similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/Resources/Icon.png rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Resources/Icon.png diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/Resources/Script.js b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Resources/Script.js similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/Resources/Script.js rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Resources/Script.js diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/Resources/Style.css b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Resources/Style.css similarity index 100% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/Resources/Style.css rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/Resources/Style.css diff --git a/Scratch Link Safari Helper/Scratch Link Safari Helper/ViewController.swift b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/ViewController.swift similarity index 93% rename from Scratch Link Safari Helper/Scratch Link Safari Helper/ViewController.swift rename to AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/ViewController.swift index cbb8101b..1848f0af 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari Helper/ViewController.swift +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari Helper/ViewController.swift @@ -1,6 +1,6 @@ // // ViewController.swift -// Scratch Link Safari Helper +// AluxLabs Link Safari Helper // // Created by Christopher Willis-Ford on 3/16/22. // @@ -9,7 +9,7 @@ import Cocoa import SafariServices import WebKit -let extensionBundleIdentifier = "edu.mit.scratch.scratch-link.safari-extension" +let extensionBundleIdentifier = "com.aluxlabs.link.safari-extension" class ViewController: NSViewController, WKNavigationDelegate, WKScriptMessageHandler { diff --git a/Scratch Link Safari Helper/Scratch Link Safari HelperTests/Scratch_Link_Safari_HelperTests.swift b/AluxLabs Link Safari Helper/AluxLabs Link Safari HelperTests/AluxLabs_Link_Safari_HelperTests.swift similarity index 86% rename from Scratch Link Safari Helper/Scratch Link Safari HelperTests/Scratch_Link_Safari_HelperTests.swift rename to AluxLabs Link Safari Helper/AluxLabs Link Safari HelperTests/AluxLabs_Link_Safari_HelperTests.swift index 5f256f3a..c570b2de 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari HelperTests/Scratch_Link_Safari_HelperTests.swift +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari HelperTests/AluxLabs_Link_Safari_HelperTests.swift @@ -1,14 +1,14 @@ // -// Scratch_Link_Safari_HelperTests.swift -// Scratch Link Safari HelperTests +// AluxLabs_Link_Safari_HelperTests.swift +// AluxLabs Link Safari HelperTests // // Created by Christopher Willis-Ford on 3/16/22. // import XCTest -@testable import Scratch_Link_Safari_Helper +@testable import AluxLabs_Link_Safari_Helper -class Scratch_Link_Safari_HelperTests: XCTestCase { +class AluxLabs_Link_Safari_HelperTests: XCTestCase { override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. diff --git a/Scratch Link Safari Helper/Scratch Link Safari HelperUITests/Scratch_Link_Safari_HelperUITests.swift b/AluxLabs Link Safari Helper/AluxLabs Link Safari HelperUITests/AluxLabs_Link_Safari_HelperUITests.swift similarity index 90% rename from Scratch Link Safari Helper/Scratch Link Safari HelperUITests/Scratch_Link_Safari_HelperUITests.swift rename to AluxLabs Link Safari Helper/AluxLabs Link Safari HelperUITests/AluxLabs_Link_Safari_HelperUITests.swift index eaf3c056..b606ba77 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari HelperUITests/Scratch_Link_Safari_HelperUITests.swift +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari HelperUITests/AluxLabs_Link_Safari_HelperUITests.swift @@ -1,13 +1,13 @@ // -// Scratch_Link_Safari_HelperUITests.swift -// Scratch Link Safari HelperUITests +// AluxLabs_Link_Safari_HelperUITests.swift +// AluxLabs Link Safari HelperUITests // // Created by Christopher Willis-Ford on 3/16/22. // import XCTest -class Scratch_Link_Safari_HelperUITests: XCTestCase { +class AluxLabs_Link_Safari_HelperUITests: XCTestCase { override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. diff --git a/Scratch Link Safari Helper/Scratch Link Safari HelperUITests/Scratch_Link_Safari_HelperUITestsLaunchTests.swift b/AluxLabs Link Safari Helper/AluxLabs Link Safari HelperUITests/AluxLabs_Link_Safari_HelperUITestsLaunchTests.swift similarity index 81% rename from Scratch Link Safari Helper/Scratch Link Safari HelperUITests/Scratch_Link_Safari_HelperUITestsLaunchTests.swift rename to AluxLabs Link Safari Helper/AluxLabs Link Safari HelperUITests/AluxLabs_Link_Safari_HelperUITestsLaunchTests.swift index b994df8b..e2bac207 100644 --- a/Scratch Link Safari Helper/Scratch Link Safari HelperUITests/Scratch_Link_Safari_HelperUITestsLaunchTests.swift +++ b/AluxLabs Link Safari Helper/AluxLabs Link Safari HelperUITests/AluxLabs_Link_Safari_HelperUITestsLaunchTests.swift @@ -1,13 +1,13 @@ // -// Scratch_Link_Safari_HelperUITestsLaunchTests.swift -// Scratch Link Safari HelperUITests +// AluxLabs_Link_Safari_HelperUITestsLaunchTests.swift +// AluxLabs Link Safari HelperUITests // // Created by Christopher Willis-Ford on 3/16/22. // import XCTest -class Scratch_Link_Safari_HelperUITestsLaunchTests: XCTestCase { +class AluxLabs_Link_Safari_HelperUITestsLaunchTests: XCTestCase { override class var runsForEachTargetApplicationUIConfiguration: Bool { true diff --git a/Scratch Link Safari Helper/Configuration Files/All Configurations.xcconfig b/AluxLabs Link Safari Helper/Configuration Files/All Configurations.xcconfig similarity index 90% rename from Scratch Link Safari Helper/Configuration Files/All Configurations.xcconfig rename to AluxLabs Link Safari Helper/Configuration Files/All Configurations.xcconfig index a4928ed0..4123717b 100644 --- a/Scratch Link Safari Helper/Configuration Files/All Configurations.xcconfig +++ b/AluxLabs Link Safari Helper/Configuration Files/All Configurations.xcconfig @@ -1,6 +1,6 @@ // // All Configurations.xcconfig -// Scratch Link Safari Helper +// AluxLabs Link Safari Helper // // Created by Christopher Willis-Ford on 8/5/22. // diff --git a/Scratch Link Safari Helper/Configuration Files/Debug.xcconfig b/AluxLabs Link Safari Helper/Configuration Files/Debug.xcconfig similarity index 95% rename from Scratch Link Safari Helper/Configuration Files/Debug.xcconfig rename to AluxLabs Link Safari Helper/Configuration Files/Debug.xcconfig index 7c297307..5e8a4688 100644 --- a/Scratch Link Safari Helper/Configuration Files/Debug.xcconfig +++ b/AluxLabs Link Safari Helper/Configuration Files/Debug.xcconfig @@ -1,6 +1,6 @@ // // Debug.xcconfig -// Scratch Link Safari Helper +// AluxLabs Link Safari Helper // // Created by Christopher Willis-Ford on 8/5/22. // diff --git a/Scratch Link Safari Helper/Configuration Files/Release.xcconfig b/AluxLabs Link Safari Helper/Configuration Files/Release.xcconfig similarity index 93% rename from Scratch Link Safari Helper/Configuration Files/Release.xcconfig rename to AluxLabs Link Safari Helper/Configuration Files/Release.xcconfig index b2c9788b..166d6816 100644 --- a/Scratch Link Safari Helper/Configuration Files/Release.xcconfig +++ b/AluxLabs Link Safari Helper/Configuration Files/Release.xcconfig @@ -1,6 +1,6 @@ // // Release.xcconfig -// Scratch Link Safari Helper +// AluxLabs Link Safari Helper // // Created by Christopher Willis-Ford on 8/5/22. // diff --git a/Scratch Link Safari Helper/Configuration Files/Release_DevID.xcconfig b/AluxLabs Link Safari Helper/Configuration Files/Release_DevID.xcconfig similarity index 70% rename from Scratch Link Safari Helper/Configuration Files/Release_DevID.xcconfig rename to AluxLabs Link Safari Helper/Configuration Files/Release_DevID.xcconfig index 6fdb93d4..3a6d9509 100644 --- a/Scratch Link Safari Helper/Configuration Files/Release_DevID.xcconfig +++ b/AluxLabs Link Safari Helper/Configuration Files/Release_DevID.xcconfig @@ -1,6 +1,6 @@ // // Release_DevID.xcconfig -// Scratch Link Safari Helper +// AluxLabs Link Safari Helper // // Created by Christopher Willis-Ford on 8/5/22. // @@ -12,4 +12,4 @@ #include "Shipping.xcconfig" CODE_SIGN_IDENTITY = Developer ID Application; -PROVISIONING_PROFILE_SPECIFIER = match Direct edu.mit.scratch.scratch-link.safari-extension macos; +PROVISIONING_PROFILE_SPECIFIER = match Direct com.aluxlabs.link.safari-extension macos; diff --git a/Scratch Link Safari Helper/Configuration Files/Release_MAS.xcconfig b/AluxLabs Link Safari Helper/Configuration Files/Release_MAS.xcconfig similarity index 69% rename from Scratch Link Safari Helper/Configuration Files/Release_MAS.xcconfig rename to AluxLabs Link Safari Helper/Configuration Files/Release_MAS.xcconfig index 70e66510..82ce7ce2 100644 --- a/Scratch Link Safari Helper/Configuration Files/Release_MAS.xcconfig +++ b/AluxLabs Link Safari Helper/Configuration Files/Release_MAS.xcconfig @@ -1,6 +1,6 @@ // // Release_MAS.xcconfig -// Scratch Link Safari Helper +// AluxLabs Link Safari Helper // // Created by Christopher Willis-Ford on 8/5/22. // @@ -12,4 +12,4 @@ #include "Shipping.xcconfig" CODE_SIGN_IDENTITY = Apple Distribution; -PROVISIONING_PROFILE_SPECIFIER = match AppStore edu.mit.scratch.scratch-link.safari-extension macos; +PROVISIONING_PROFILE_SPECIFIER = match AppStore com.aluxlabs.link.safari-extension macos; diff --git a/Scratch Link Safari Helper/Configuration Files/Shipping.xcconfig b/AluxLabs Link Safari Helper/Configuration Files/Shipping.xcconfig similarity index 84% rename from Scratch Link Safari Helper/Configuration Files/Shipping.xcconfig rename to AluxLabs Link Safari Helper/Configuration Files/Shipping.xcconfig index c0d26646..f0f2cf20 100644 --- a/Scratch Link Safari Helper/Configuration Files/Shipping.xcconfig +++ b/AluxLabs Link Safari Helper/Configuration Files/Shipping.xcconfig @@ -1,6 +1,6 @@ // // Shipping.xcconfig -// Scratch Link Safari Helper +// AluxLabs Link Safari Helper // // Created by Christopher Willis-Ford on 8/5/22. // @@ -11,7 +11,7 @@ // Enable secure timestamp for code signing OTHER_CODE_SIGN_FLAGS = --timestamp $(inherited); -PRODUCT_BUNDLE_IDENTIFIER = edu.mit.scratch.scratch-link.safari-extension; +PRODUCT_BUNDLE_IDENTIFIER = com.aluxlabs.link.safari-extension; DEVELOPMENT_TEAM = W7AR3WMP87; // Setting this to NO will prevent injection of the "com.apple.security.get-task-allow" entitlement diff --git a/Scratch Link Safari Helper/Configuration Files/Version.xcconfig b/AluxLabs Link Safari Helper/Configuration Files/Version.xcconfig similarity index 91% rename from Scratch Link Safari Helper/Configuration Files/Version.xcconfig rename to AluxLabs Link Safari Helper/Configuration Files/Version.xcconfig index 487e9a87..f070e1a3 100644 --- a/Scratch Link Safari Helper/Configuration Files/Version.xcconfig +++ b/AluxLabs Link Safari Helper/Configuration Files/Version.xcconfig @@ -1,6 +1,6 @@ // // Version.xcconfig -// Scratch Link Safari Helper +// AluxLabs Link Safari Helper // // Created by Christopher Willis-Ford on 8/5/22. // diff --git a/Scratch Link Safari Helper/Safari WebExtension messaging.md b/AluxLabs Link Safari Helper/Safari WebExtension messaging.md similarity index 95% rename from Scratch Link Safari Helper/Safari WebExtension messaging.md rename to AluxLabs Link Safari Helper/Safari WebExtension messaging.md index 8a89e2e2..960974d7 100644 --- a/Scratch Link Safari Helper/Safari WebExtension messaging.md +++ b/AluxLabs Link Safari Helper/Safari WebExtension messaging.md @@ -1,6 +1,6 @@ # Safari WebExtension messaging -The Scratch Link Safari Helper uses Safari's version of the WebExtension API. Communication between components is +The AluxLabs Link Safari Helper uses Safari's version of the WebExtension API. Communication between components is restricted and each component has its own set of communication channels. The components and communication channels are documented here to help make sense of the spaghetti. @@ -20,7 +20,7 @@ The components involved in extension communication include: `NSExtensionRequestHandling` Objective-C protocol. Safari's WebExtension implementation requires that an extension be hosted by a native application -- in this case, -Scratch Link. There are Safari-specific ways to communicate between the WebExtension and its host app, but Scratch +AluxLabs Link. There are Safari-specific ways to communicate between the WebExtension and its host app, but Scratch Link does not use those so they're not covered here. ```mermaid diff --git a/Makefile b/Makefile index 06c77a17..b331c94d 100644 --- a/Makefile +++ b/Makefile @@ -11,38 +11,38 @@ # - optipng MAC_IMAGES = \ - scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png \ - scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png \ - scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png \ - scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png \ - scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png \ - scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png \ - scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png \ - scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png \ - scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png \ - scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png \ - scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16.png \ - scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16@2x.png \ - scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32.png \ - scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32@2x.png \ - scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128.png \ - scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128@2x.png \ - scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256.png \ - scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256@2x.png \ - scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512.png \ - scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512@2x.png \ - Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/icon-48.png \ - Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/icon-64.png \ - Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/icon-96.png \ - Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/icon-128.png \ - Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/icon-256.png \ - Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/icon-512.png \ - Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-16.png \ - Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-19.png \ - Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-32.png \ - Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-38.png \ - Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-48.png \ - Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-72.png + aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png \ + aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png \ + aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png \ + aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png \ + aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png \ + aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png \ + aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png \ + aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png \ + aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png \ + aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png \ + aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16.png \ + aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16@2x.png \ + aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32.png \ + aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32@2x.png \ + aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128.png \ + aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128@2x.png \ + aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256.png \ + aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256@2x.png \ + aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512.png \ + aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512@2x.png \ + AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/icon-48.png \ + AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/icon-64.png \ + AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/icon-96.png \ + AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/icon-128.png \ + AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/icon-256.png \ + AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/icon-512.png \ + AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/toolbar-icon-16.png \ + AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/toolbar-icon-19.png \ + AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/toolbar-icon-32.png \ + AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/toolbar-icon-38.png \ + AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/toolbar-icon-48.png \ + AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/toolbar-icon-72.png WINDOWS_IMAGES = \ aluxlabs-link-win/aluxlabs-link.ico \ @@ -81,44 +81,44 @@ $(1): $(2) endef # macOS app icon -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png,Assets/rounded.svg,16,16,72)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png,Assets/rounded.svg,32,32,144)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png,Assets/rounded.svg,32,32,72)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png,Assets/rounded.svg,64,64,144)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png,Assets/rounded.svg,128,128,72)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png,Assets/rounded.svg,256,256,144)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png,Assets/rounded.svg,256,256,72)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png,Assets/rounded.svg,512,512,144)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png,Assets/rounded.svg,512,512,72)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png,Assets/rounded.svg,1024,1024,144)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png,Assets/rounded.svg,16,16,72)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png,Assets/rounded.svg,32,32,144)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png,Assets/rounded.svg,32,32,72)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png,Assets/rounded.svg,64,64,144)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png,Assets/rounded.svg,128,128,72)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png,Assets/rounded.svg,256,256,144)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png,Assets/rounded.svg,256,256,72)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png,Assets/rounded.svg,512,512,144)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png,Assets/rounded.svg,512,512,72)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png,Assets/rounded.svg,1024,1024,144)) # macOS app status bar icon -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16.png,Assets/glyph.svg,16,16,72)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16@2x.png,Assets/glyph.svg,32,32,144)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32.png,Assets/glyph.svg,32,32,72)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32@2x.png,Assets/glyph.svg,64,64,144)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128.png,Assets/glyph.svg,128,128,72)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128@2x.png,Assets/glyph.svg,256,256,144)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256.png,Assets/glyph.svg,256,256,72)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256@2x.png,Assets/glyph.svg,512,512,144)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512.png,Assets/glyph.svg,512,512,72)) -$(eval $(call svg2png,scratch-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512@2x.png,Assets/glyph.svg,1024,1024,144)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16.png,Assets/glyph.svg,16,16,72)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_16x16@2x.png,Assets/glyph.svg,32,32,144)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32.png,Assets/glyph.svg,32,32,72)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_32x32@2x.png,Assets/glyph.svg,64,64,144)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128.png,Assets/glyph.svg,128,128,72)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_128x128@2x.png,Assets/glyph.svg,256,256,144)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256.png,Assets/glyph.svg,256,256,72)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_256x256@2x.png,Assets/glyph.svg,512,512,144)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512.png,Assets/glyph.svg,512,512,72)) +$(eval $(call svg2png,aluxlabs-link-mac/Assets.xcassets/StatusBarIcon.iconset/icon_512x512@2x.png,Assets/glyph.svg,1024,1024,144)) # macOS Safari extension icon -$(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/icon-48.png,Assets/rounded.svg,48,48,72)) -$(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/icon-64.png,Assets/rounded.svg,64,64,72)) -$(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/icon-96.png,Assets/rounded.svg,96,96,72)) -$(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/icon-128.png,Assets/rounded.svg,128,128,72)) -$(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/icon-256.png,Assets/rounded.svg,256,256,72)) -$(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/icon-512.png,Assets/rounded.svg,512,512,72)) +$(eval $(call svg2png,AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/icon-48.png,Assets/rounded.svg,48,48,72)) +$(eval $(call svg2png,AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/icon-64.png,Assets/rounded.svg,64,64,72)) +$(eval $(call svg2png,AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/icon-96.png,Assets/rounded.svg,96,96,72)) +$(eval $(call svg2png,AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/icon-128.png,Assets/rounded.svg,128,128,72)) +$(eval $(call svg2png,AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/icon-256.png,Assets/rounded.svg,256,256,72)) +$(eval $(call svg2png,AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/icon-512.png,Assets/rounded.svg,512,512,72)) # macOS Safari extension toolbar icon -$(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-16.png,Assets/glyph.svg,16,16,72)) -$(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-19.png,Assets/glyph.svg,19,19,72)) -$(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-32.png,Assets/glyph.svg,32,32,72)) -$(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-38.png,Assets/glyph.svg,38,38,72)) -$(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-48.png,Assets/glyph.svg,48,48,72)) -$(eval $(call svg2png,Scratch\ Link\ Safari\ Helper/Scratch\ Link\ Safari\ Extension/Resources/images/toolbar-icon-72.png,Assets/glyph.svg,72,72,72)) +$(eval $(call svg2png,AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/toolbar-icon-16.png,Assets/glyph.svg,16,16,72)) +$(eval $(call svg2png,AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/toolbar-icon-19.png,Assets/glyph.svg,19,19,72)) +$(eval $(call svg2png,AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/toolbar-icon-32.png,Assets/glyph.svg,32,32,72)) +$(eval $(call svg2png,AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/toolbar-icon-38.png,Assets/glyph.svg,38,38,72)) +$(eval $(call svg2png,AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/toolbar-icon-48.png,Assets/glyph.svg,48,48,72)) +$(eval $(call svg2png,AluxLabs\ Link\ Safari\ Helper/AluxLabs\ Link\ Safari\ Extension/Resources/images/toolbar-icon-72.png,Assets/glyph.svg,72,72,72)) # Windows app & tray icons # See also: diff --git a/aluxlabs-link-mac/aluxlabs-link-mac.csproj b/aluxlabs-link-mac/aluxlabs-link-mac.csproj index b09ed41b..e55204f8 100644 --- a/aluxlabs-link-mac/aluxlabs-link-mac.csproj +++ b/aluxlabs-link-mac/aluxlabs-link-mac.csproj @@ -127,12 +127,12 @@ - $(SolutionDir)Scratch Link Safari Helper/build/$(Configuration)/ - Scratch Link Safari Extension.appex + $(SolutionDir)AluxLabs Link Safari Helper/build/$(Configuration)/ + AluxLabs Link Safari Extension.appex $(SafariHelperSrcDir)$(SafariHelperBundleName)/ - - + + @@ -147,8 +147,8 @@ - - + + From 988dc20dc6b27c02e53701422491c5fb8c47c1b6 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Jun 2026 17:08:21 +0900 Subject: [PATCH 71/94] =?UTF-8?q?fix(msix):=20MSIX=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=EB=A5=BC=20self-contained=EB=A1=9C=20=EB=B9=8C?= =?UTF-8?q?=EB=93=9C=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WindowsAppSDKSelfContained가 csproj/pubxml에만 설정돼 있어 wapproj의 매니페스트 생성 단계엔 반영되지 않았고, 그 결과 런타임 DLL을 동봉하면서도 Microsoft.WindowsAppRuntime 의존성을 선언하는 반쪽 상태였다. wapproj에 속성을 고정해 매니페스트에서 WindowsAppRuntime 의존성을 제거 — .NET 8 / Windows App Runtime 미설치 PC에서도 사이드로딩 설치 후 정상 실행됨을 실측 확인했다. _signing/(자체 서명 테스트 인증서·빌드 로그)는 커밋 제외. Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitignore | 3 +++ aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 61bc5b4b..4c90e4c9 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ Backup*/ # Local-only debug captures (DebugView dumps, browser console logs, etc.) ref/ + +# Test signing materials (self-signed test certs / build logs — never commit) +/aluxlabs-link-win-msix/_signing/ diff --git a/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj b/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj index b7bc25d0..69925582 100644 --- a/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj +++ b/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj @@ -48,6 +48,8 @@ net8.0-windows$(TargetPlatformVersion);$(AssetTargetFallback) en-US false + + true ..\aluxlabs-link-win\aluxlabs-link-win.csproj True False From 8f0dcfb31d9427a623ed582f85dea68243c28747 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Jun 2026 17:08:33 +0900 Subject: [PATCH 72/94] =?UTF-8?q?docs:=20aluxlabs-link-win-msix=20?= =?UTF-8?q?=ED=8E=B8=EC=A7=91=20=EA=B7=9C=EC=B9=99=20=EB=AC=B8=EA=B5=AC=20?= =?UTF-8?q?=EB=AA=85=ED=99=95=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "직접 코드 편집 대상이 아니다"가 정당한 배포 구성 변경까지 막는 것으로 읽혀, 앱·비즈니스 로직 금지는 유지하되 패키징·서명·self-contained·매니페스트 등 배포 구성 변경은 빌드 검증을 전제로 허용하도록 다듬었다. Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 893270c0..9b730ffa 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -77,7 +77,7 @@ docs(architecture): Serial 프로토콜 설계 문서 업데이트 - `aluxlabs-link-common/` — 플랫폼 공통 C# Shared Project (BLE/BT/Serial 프로토콜 추상화, JSON-RPC 2.0, WebSocket 핸들링). **재사용 가능한 단위로 분리**, Windows API에 종속되지 않는다. - `aluxlabs-link-win/` — WinUI 3 플랫폼 구현 (Windows.Devices.* API 연동, 트레이 아이콘, 앱 진입점). **비즈니스 로직은 최소화**, 가능한 한 `aluxlabs-link-common`으로 위임. -- `aluxlabs-link-win-msix/` — MSIX 패키징 프로젝트. 직접 코드 편집 대상이 아니다. +- `aluxlabs-link-win-msix/` — MSIX 패키징 프로젝트. 앱·비즈니스 로직을 넣지 않는다. 단, 패키징·서명·self-contained·매니페스트 등 배포 구성 변경은 필요 시 여기서 수정하되, 배포 전반에 영향을 주므로 변경 후 빌드된 패키지를 검증한다. - `SharedProps/` — MSBuild 공유 속성 (SDK 버전, NuGet 패키지 참조, 버전 자동화). 개별 csproj에서 중복 선언 금지. - `Documentation/` — 아키텍처·프로토콜 설계 문서. 관련 코드 변경 시 함께 업데이트한다. - **의존 방향: `aluxlabs-link-win` → `aluxlabs-link-common` 단방향** (§1 절대 규칙). 이유: common이 win을 참조하면 플랫폼 독립성이 깨지고 순환 의존이 발생한다. From f9567ade7393336c93be5c851c3bb405b25c4aec Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Jun 2026 17:35:53 +0900 Subject: [PATCH 73/94] =?UTF-8?q?fix(win):=20=ED=8A=B8=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=20=EC=95=84=EC=9D=B4=EC=BD=98=20=ED=88=B4=ED=8C=81=EC=9D=B4=20?= =?UTF-8?q?=ED=91=9C=EC=8B=9C=EB=90=98=EB=8F=84=EB=A1=9D=20H.NotifyIcon=20?= =?UTF-8?q?=EC=97=85=EA=B7=B8=EB=A0=88=EC=9D=B4=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit H.NotifyIcon.WinUI 2.0.108은 기본값으로 커스텀 XAML 툴팁을 사용하는데, 이 렌더링이 WinAppSDK 1.8 환경에서 동작하지 않아 트레이 호버 시 툴팁이 뜨지 않았다. 2.0.113부터 네이티브 OS 툴팁(NIF_SHOWTIP)을 기본 사용하도록 변경됐으므로 2.0.131로 올려 해결했다. VS 2026 빌드에서 툴팁 표시를 확인했다. 참고: HavenDV/H.NotifyIcon#94 Co-Authored-By: Claude Opus 4.8 (1M context) --- aluxlabs-link-win/aluxlabs-link-win.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aluxlabs-link-win/aluxlabs-link-win.csproj b/aluxlabs-link-win/aluxlabs-link-win.csproj index 9bb13a65..287358ee 100644 --- a/aluxlabs-link-win/aluxlabs-link-win.csproj +++ b/aluxlabs-link-win/aluxlabs-link-win.csproj @@ -43,7 +43,7 @@ - + From 81d49acfda40b5dc304f6bd008db6725f7242ff5 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Jun 2026 18:04:34 +0900 Subject: [PATCH 74/94] =?UTF-8?q?fix(msix):=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EB=B2=84=EC=A0=84=EC=9D=B4=200=20=EA=B3=A0=EC=A0=95?= =?UTF-8?q?=EB=90=98=EC=A7=80=20=EC=95=8A=EA=B3=A0=20=EC=BB=A4=EB=B0=8B=20?= =?UTF-8?q?=EC=88=98=EB=A1=9C=20=EC=9E=90=EB=8F=99=20=EC=A6=9D=EA=B0=80?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitInfo NuGet 타깃이 레거시 .wapproj 빌드 컨텍스트에서 로드되지 않아 빌드 번호가 0으로 떨어졌고, 그 결과 MSIX 패키지 버전이 항상 1.0.0.0으로 고정돼 빌드 간 식별·업그레이드가 불가능했다. fallback GitVersion 타깃이 git rev-list --count로 커밋 수를 직접 구하게 하여, GitInfo가 없어도 패키지 버전이 1.0.0.<커밋수>로 증가하도록 했다(EXE FileVersion과 일치). Co-Authored-By: Claude Opus 4.8 (1M context) --- SharedProps/ScratchVersion.targets | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/SharedProps/ScratchVersion.targets b/SharedProps/ScratchVersion.targets index c8591f76..c33a900b 100644 --- a/SharedProps/ScratchVersion.targets +++ b/SharedProps/ScratchVersion.targets @@ -10,6 +10,13 @@ This file sets up version properties in our own Scratch way. definition when available ("last definition wins" in MSBuild). --> + + + + + + + 0 0 @@ -18,6 +25,8 @@ This file sets up version properties in our own Scratch way. 0000000 0 $([System.DateTime]::UtcNow.ToString("o")) + $(_AluxGitCommits.Trim()) + $(_AluxGitCommit.Trim()) From d62099347f427afa6ba1f88e792a7501071bcf34 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Jun 2026 18:30:22 +0900 Subject: [PATCH 75/94] =?UTF-8?q?fix(win):=20=ED=8A=B8=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=20=EC=9A=B0=ED=81=B4=EB=A6=AD=20=EB=A9=94=EB=89=B4=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=C2=B7=EC=8A=A4=ED=81=AC=EB=A1=A4=EB=B0=94=20=EC=88=98?= =?UTF-8?q?=EC=A0=95,=20=EC=A3=BD=EC=9D=80=20=EC=9A=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ContextMenuMode를 SecondWindow에서 네이티브 PopupMenu로 전환해 별도 창 크기 계산 오류로 생기던 스크롤바와 트레이 뒤 잘못된 위치 문제를 해소했다. SecondWindow 너비 잘림(H.NotifyIcon#73) 우회용 width 측정 코드와 그로 인해 미사용이 된 using 2개도 제거했다. Co-Authored-By: Claude Opus 4.8 (1M context) --- aluxlabs-link-win/App.xaml.cs | 19 ------------------- aluxlabs-link-win/TrayIcon.xaml | 2 +- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/aluxlabs-link-win/App.xaml.cs b/aluxlabs-link-win/App.xaml.cs index 6461c8f6..10f321dd 100644 --- a/aluxlabs-link-win/App.xaml.cs +++ b/aluxlabs-link-win/App.xaml.cs @@ -6,14 +6,12 @@ namespace AluxLabs.Link.Win; using H.NotifyIcon; using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Input; using AluxLabs.Link; using AluxLabs.Link.Win.BLE; using System.Diagnostics; using System.Reflection; using Windows.ApplicationModel.DataTransfer; -using Windows.Foundation; /// /// Provides application-specific behavior to supplement the default Application class. @@ -72,23 +70,6 @@ private void InitializeTrayIcon() copyVersionCommand.Label = $"{this.appTitle} {this.versionQuad}"; copyVersionCommand.ExecuteRequested += this.CopyVersionCommand_ExecuteRequested; - // Without this code, the width gets set too small and the label gets cut off. - // This could be a different presentation of https://github.com/HavenDV/H.NotifyIcon/issues/73 - // Note that the "loop" should handle exactly one item due to the `Where` clause. - var menuFlyout = (MenuFlyout)this.Resources["ContextFlyout"]; - foreach (var menuItem in menuFlyout.Items.OfType() - .Where(item => (XamlUICommand)item.Command == copyVersionCommand)) - { - var infiniteSize = new Size(double.PositiveInfinity, double.PositiveInfinity); - menuItem.Icon.Measure(infiniteSize); - menuItem.Measure(infiniteSize); - menuItem.Width = - menuItem.Icon.Margin.Left + menuItem.Icon.DesiredSize.Width + menuItem.Icon.Margin.Right + - menuItem.Margin.Left + menuItem.Padding.Left + - menuItem.DesiredSize.Width + - menuItem.Padding.Right + menuItem.Margin.Right; - } - var exitCommand = (XamlUICommand)this.Resources["ExitCommand"]; exitCommand.ExecuteRequested += this.ExitCommand_ExecuteRequested; diff --git a/aluxlabs-link-win/TrayIcon.xaml b/aluxlabs-link-win/TrayIcon.xaml index 2cfbab8b..19505276 100644 --- a/aluxlabs-link-win/TrayIcon.xaml +++ b/aluxlabs-link-win/TrayIcon.xaml @@ -10,7 +10,7 @@ From cd2f73765d0f69f10907b68de2557fa61528cc09 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Jun 2026 18:30:31 +0900 Subject: [PATCH 76/94] =?UTF-8?q?style:=20=EC=9D=B4=EB=B2=88=20=EC=84=B8?= =?UTF-8?q?=EC=85=98=EC=97=90=20=EC=B6=94=EA=B0=80=ED=95=9C=20MSBuild=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=EC=9D=84=20WHY=20=EC=A4=91=EC=8B=AC=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=A0=95=EB=A6=AC=20(CLAUDE.md=20=C2=A74)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- SharedProps/ScratchVersion.targets | 2 +- aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SharedProps/ScratchVersion.targets b/SharedProps/ScratchVersion.targets index c33a900b..7c9ec9fb 100644 --- a/SharedProps/ScratchVersion.targets +++ b/SharedProps/ScratchVersion.targets @@ -10,7 +10,7 @@ This file sets up version properties in our own Scratch way. definition when available ("last definition wins" in MSBuild). --> - + diff --git a/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj b/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj index 69925582..064c7bb5 100644 --- a/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj +++ b/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj @@ -48,7 +48,7 @@ net8.0-windows$(TargetPlatformVersion);$(AssetTargetFallback) en-US false - + true ..\aluxlabs-link-win\aluxlabs-link-win.csproj True From 8e3cc02c39a0878320a0c03d258847080b13d0e3 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Jun 2026 13:26:12 +0900 Subject: [PATCH 77/94] =?UTF-8?q?feat(serial):=20=ED=8F=AC=ED=8A=B8=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=EC=9A=A9=20listSerialPorts=20RPC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20=EC=8B=9C=EB=A6=AC=EC=96=BC=20periphera?= =?UTF-8?q?lId=EB=A5=BC=20COM=EB=AA=85=EC=9C=BC=EB=A1=9C=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit picker UI에서 사용자가 연결할 COM 포트를 직접 고를 수 있도록, 매칭 포트 전체를 한 응답으로 돌려주는 listSerialPorts RPC를 추가한다. 자동 첫-포트 연결만 가능하던 기존 link 모드의 한계를 닫는다. - listSerialPorts: 현재 시점 매칭 포트 전체 스냅샷을 result.ports로 반환(스트리밍 없음). 매칭 없으면 빈 배열, 부수효과 없음(포트 open 안 함), 활성 연결 중 호출 안전. 반환 포트를 connect 레지스트리에 등록하고, 재호출 시 치환(stale id는 connect 시 -32600). - discover/list가 공유하는 DoEnumeratePorts 스냅샷 추상화로 열거 일원화. - PeripheralSession에 GeneratePeripheralId virtual 훅 추가. 시리얼만 COM path를 peripheralId로 사용(SoT 정렬), BLE/BT는 익명 GUID 유지. - SerialApiReference: listSerialPorts 섹션 추가 + connect 실패 에러 정정 (-32603 -> -32500, 상세는 error.data). Co-Authored-By: Claude Opus 4.8 (1M context) --- Documentation/Alux/SerialApiReference.md | 77 ++++++++-- aluxlabs-link-common/PeripheralSession.cs | 16 +- aluxlabs-link-common/Serial/SerialSession.cs | 151 ++++++++++++++++++- aluxlabs-link-win/Serial/WinSerialSession.cs | 7 +- 4 files changed, 231 insertions(+), 20 deletions(-) diff --git a/Documentation/Alux/SerialApiReference.md b/Documentation/Alux/SerialApiReference.md index 975e40eb..283755e5 100644 --- a/Documentation/Alux/SerialApiReference.md +++ b/Documentation/Alux/SerialApiReference.md @@ -60,6 +60,58 @@ Discovered ports arrive as `didDiscoverPeripheral` notifications: --- +### listSerialPorts + +Returns a one-shot snapshot of currently matching serial ports in the response (no streamed notifications), and registers each so a subsequent `connect` can resolve its `peripheralId`. Intended for a user-facing port picker. + +**Request:** +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "listSerialPorts", + "params": { + "filters": [ + { "usbVendorId": 6790, "usbProductId": 29987, "pathHint": "COM" } + ] + } +} +``` + +**Parameters:** +- `filters` (array, optional) — Same shape and semantics as `discover`. Omit or empty to return every enumerated USB serial port. Filters are OR'd; fields within a filter are AND'd. + +**Response:** +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "ports": [ + { + "peripheralId": "COM7", + "name": "USB-SERIAL CH340 (COM7)", + "path": "COM7", + "vendorId": "0x1A86", + "productId": "0x7523" + } + ] + } +} +``` + +- `result.ports` is the complete current snapshot. No matches → `{ "ports": [] }` (not an error). +- `peripheralId` is the COM port name; pass it back unchanged to `connect`. (Serial uses the COM path as the `peripheralId`; `discover` does the same.) +- `vendorId` / `productId` are omitted when unknown (e.g. non-USB ports). No `rssi` field (this is a snapshot, not a BLE-style discovery). +- **Side-effect-free:** does not open/close any port and does not disturb an in-progress session or its RX. Calling while connected is allowed — it returns the list only. +- **Re-call replaces the snapshot:** the registry is refreshed each call. A `peripheralId` present only in a prior snapshot becomes stale and fails `connect` with -32600. + +**Errors:** +- Invalid `filters` → -32602 (detail in `error.data`). +- Method not found on an older Link → -32601; clients fall back to the `discover` path. + +--- + ### connect Opens a serial port connection. @@ -105,13 +157,17 @@ Opens a serial port connection. ``` **Errors:** + +The human-readable detail is carried in `error.data`; `error.message` holds the JSON-RPC category string (e.g. `"Application Error"`). Read `error.data` for the user-facing message. + ```json { "jsonrpc": "2.0", "id": 2, "error": { - "code": -32603, - "message": "could not open serial port COM7: Port already in use" + "code": -32500, + "message": "Application Error", + "data": "could not open serial port COM7: Access to the path 'COM7' is denied." } } ``` @@ -424,12 +480,15 @@ This is a deliberate design choice for v1: keep Link's transport thin and predic ## Error Codes -| Code | Message | Description | +The human-readable detail is in `error.data`; `error.message` is the category string below. + +| Code | Message (category) | Description | |------|---------|-------------| -| -32600 | Invalid Request | Malformed JSON-RPC | -| -32601 | Method not found | Unknown method | -| -32602 | Invalid params | Missing required parameter | -| -32603 | Internal error | Port error, invalid state, etc. | +| -32500 | Application Error | Port open failed, port enumeration hard failure, etc. (detail in `data`) | +| -32600 | Invalid Request | Invalid state — e.g. peripheral not registered, already connected | +| -32601 | Method not found | Unknown method (older Link server) | +| -32602 | Invalid params | Missing/invalid parameter (e.g. missing `baudRate`, malformed `filters`) | +| -32603 | Internal error | Internal error during a write/read operation | --- @@ -478,5 +537,5 @@ Buffers longer than 256 bytes are truncated with `…(+NB)` suffix. Compare thes --- -**API Version**: 1.1 -**Last Updated**: 2026-05-25 +**API Version**: 1.2 +**Last Updated**: 2026-06-08 diff --git a/aluxlabs-link-common/PeripheralSession.cs b/aluxlabs-link-common/PeripheralSession.cs index 62304c21..6a314ce2 100644 --- a/aluxlabs-link-common/PeripheralSession.cs +++ b/aluxlabs-link-common/PeripheralSession.cs @@ -83,18 +83,30 @@ protected async Task HandleConnect(string methodName, JsonElement? args) /// A representing the result of the asynchronous operation. protected abstract Task DoConnect(TDiscoveredPeripheral discoveredPeripheral, JsonElement? args); + /// + /// Produce the session-scoped peripheral ID for a newly seen address. The default + /// anonymizes the address with a fresh GUID; a transport whose address is stable and + /// non-sensitive may override to use the address itself as the ID. + /// + /// The peripheral device's address. + /// The peripheral ID to associate with this address for the session. + protected virtual string GeneratePeripheralId(TPeripheralAddress peripheralAddress) + { + return Guid.NewGuid().ToString(); + } + /// /// Store the peripheral in the "discovered peripherals" list using a session-specific peripheral ID. /// Storing a peripheral with the same address several times during the same session will result in the same ID each time. /// /// The peripheral information being registered. /// The peripheral device's address. - /// An anonymized, session-specific peripheral ID. + /// A session-specific peripheral ID (anonymized unless is overridden). protected string RegisterPeripheral(TDiscoveredPeripheral discoveredPeripheral, TPeripheralAddress peripheralAddress) { if (!this.peripheralAddressToId.TryGetValue(peripheralAddress, out var peripheralId)) { - peripheralId = Guid.NewGuid().ToString(); + peripheralId = this.GeneratePeripheralId(peripheralAddress); this.peripheralAddressToId[peripheralAddress] = peripheralId; } diff --git a/aluxlabs-link-common/Serial/SerialSession.cs b/aluxlabs-link-common/Serial/SerialSession.cs index e8fbefd9..68280b46 100644 --- a/aluxlabs-link-common/Serial/SerialSession.cs +++ b/aluxlabs-link-common/Serial/SerialSession.cs @@ -63,6 +63,7 @@ public SerialSession(IWebSocketConnection webSocket) : base(webSocket) { this.Handlers["discover"] = this.HandleDiscover; + this.Handlers["listSerialPorts"] = this.HandleListSerialPorts; this.Handlers["write"] = this.HandleWrite; this.Handlers["disconnect"] = this.HandleDisconnect; this.Handlers["startReading"] = this.HandleStartReading; @@ -71,6 +72,13 @@ public SerialSession(IWebSocketConnection webSocket) this.Handlers["triggerDTRReset"] = this.HandleTriggerDTRReset; } + /// + protected override string GeneratePeripheralId(string peripheralAddress) + { + // A serial port path is stable and non-sensitive, so use it directly as the ID rather than an anonymized GUID. + return peripheralAddress; + } + /// /// Implement the JSON-RPC "discover" request. Parses the filter list and /// kicks off platform-specific enumeration. Discovered ports are streamed @@ -79,22 +87,62 @@ public SerialSession(IWebSocketConnection webSocket) /// The name of the method being called ("discover"). /// A JSON object optionally containing a filters array. /// A resolving to an empty result; discoveries are streamed via notifications. - protected Task HandleDiscover(string methodName, JsonElement? args) + protected async Task HandleDiscover(string methodName, JsonElement? args) { var filters = ParseFilters(args); Trace.WriteLine($"received serial discover request with {filters.Count} filter(s)"); this.ClearDiscoveredPeripherals(); - return this.DoDiscover(filters); + var ports = await this.DoEnumeratePorts(filters); + foreach (var port in ports) + { + await this.OnPortDiscovered(port.Port, port.Path, port.DisplayName, port.VendorIdHex, port.ProductIdHex); + } + + return new Dictionary(); + } + + /// + /// Implement the JSON-RPC "listSerialPorts" request. Returns a one-shot snapshot of + /// currently matching ports in the response (no streamed notifications) and registers + /// each so a subsequent connect can resolve its peripheral ID. + /// + /// The name of the method being called ("listSerialPorts"). + /// A JSON object optionally containing a filters array. + /// A resolving to a ports array of the matching ports. + protected async Task HandleListSerialPorts(string methodName, JsonElement? args) + { + var filters = ParseFilters(args); + Trace.WriteLine($"received listSerialPorts request with {filters.Count} filter(s)"); + + // Refresh the registry so an ID from a prior snapshot fails connect (-32600) instead of opening a vanished port. + this.ClearDiscoveredPeripherals(); + var ports = await this.DoEnumeratePorts(filters); + + var items = new List(ports.Count); + foreach (var port in ports) + { + var peripheralId = this.RegisterPeripheral(port.Port, port.Path); + items.Add(new SerialPortListItem + { + PeripheralId = peripheralId, + Name = port.DisplayName, + Path = port.Path, + VendorId = port.VendorIdHex, + ProductId = port.ProductIdHex, + }); + } + + return new SerialPortListResult { Ports = items }; } /// - /// Platform-specific implementation for port discovery. Implementations - /// should return promptly and stream results via . + /// Platform-specific one-shot enumeration of currently present serial ports matching + /// the filters. Returns a complete snapshot in one call; does not stream. /// /// The filter list from the client. Empty means "match all". - /// A representing the asynchronous operation. - protected abstract Task DoDiscover(IReadOnlyList filters); + /// A resolving to the matching ports. + protected abstract Task> DoEnumeratePorts(IReadOnlyList filters); /// protected override Task DoConnect(TPort port, JsonElement? args) @@ -697,4 +745,95 @@ protected class SerialPortDiscovered [JsonPropertyName("rssi")] public int RSSI { get; set; } } + + /// + /// A single port returned by , pairing the platform + /// port handle with the display metadata needed to report it. + /// + protected sealed class EnumeratedPort + { + /// + /// Initializes a new instance of the class. + /// + /// The platform-specific port handle. + /// The OS-level port path (e.g. "COM7"). + /// The user-visible name. + /// The USB vendor ID as a hex string, or null. + /// The USB product ID as a hex string, or null. + public EnumeratedPort(TPort port, string path, string displayName, string vendorIdHex, string productIdHex) + { + this.Port = port; + this.Path = path; + this.DisplayName = displayName; + this.VendorIdHex = vendorIdHex; + this.ProductIdHex = productIdHex; + } + + /// Gets the platform-specific port handle. + public TPort Port { get; } + + /// Gets the OS-level port path. + public string Path { get; } + + /// Gets the user-visible name. + public string DisplayName { get; } + + /// Gets the USB vendor ID as a hex string, or null. + public string VendorIdHex { get; } + + /// Gets the USB product ID as a hex string, or null. + public string ProductIdHex { get; } + } + + /// + /// Payload of a listSerialPorts response. + /// + protected class SerialPortListResult + { + /// + /// Gets or sets the snapshot of currently matching ports. + /// + [JsonPropertyName("ports")] + public List Ports { get; set; } + } + + /// + /// A single entry in a listSerialPorts response. Mirrors the + /// didDiscoverPeripheral fields without the RSSI placeholder. + /// + protected class SerialPortListItem + { + /// + /// Gets or sets the peripheral ID used by the client to connect. + /// + [JsonPropertyName("peripheralId")] + public string PeripheralId { get; set; } + + /// + /// Gets or sets the user-visible name of the port. + /// + [JsonPropertyName("name")] + public string Name { get; set; } + + /// + /// Gets or sets the OS-level port path (e.g. "COM7"). + /// + [JsonPropertyName("path")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Path { get; set; } + + /// + /// Gets or sets the USB vendor ID as a hex string, if known. + /// + [JsonPropertyName("vendorId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string VendorId { get; set; } + + /// + /// Gets or sets the USB product ID as a hex string, if known. + /// + [JsonPropertyName("productId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string ProductId { get; set; } + } } diff --git a/aluxlabs-link-win/Serial/WinSerialSession.cs b/aluxlabs-link-win/Serial/WinSerialSession.cs index e11341ca..9031c78f 100644 --- a/aluxlabs-link-win/Serial/WinSerialSession.cs +++ b/aluxlabs-link-win/Serial/WinSerialSession.cs @@ -42,10 +42,11 @@ public WinSerialSession(IWebSocketConnection webSocket) protected override bool IsConnected => this.port != null && this.port.IsOpen; /// - protected override async Task DoDiscover(IReadOnlyList filters) + protected override async Task> DoEnumeratePorts(IReadOnlyList filters) { var ports = await Task.Run(() => WinSerialPortEnumerator.Query(filters)); + var result = new List(ports.Count); foreach (var portInfo in ports) { var vendorHex = portInfo.VendorId.HasValue @@ -55,10 +56,10 @@ protected override async Task DoDiscover(IReadOnlyList(); + return result; } /// From a045cef7a52f49f11df7516b5a322bdfb586ae9f Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Jun 2026 13:34:07 +0900 Subject: [PATCH 78/94] =?UTF-8?q?docs(msix):=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=84=9C=EB=AA=85=20=EB=B0=8F=20MSIX=20=EB=B0=B0=ED=8F=AC?= =?UTF-8?q?=C2=B7=EC=9E=90=EB=8F=99=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= =?UTF-8?q?=20=EA=B0=80=EC=9D=B4=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sectigo OV(eToken) 서명 절차, signtool 사용법, Publisher 일치 규칙, .appinstaller 기반 자동 업데이트, 호스팅 선택지(GitHub / AWS S3) 정리. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Alux/CodeSigningAndDistribution.md | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 Documentation/Alux/CodeSigningAndDistribution.md diff --git a/Documentation/Alux/CodeSigningAndDistribution.md b/Documentation/Alux/CodeSigningAndDistribution.md new file mode 100644 index 00000000..b144e48c --- /dev/null +++ b/Documentation/Alux/CodeSigningAndDistribution.md @@ -0,0 +1,148 @@ +# 코드 서명 및 MSIX 배포 / 자동 업데이트 + +AluxLabs Link(`aluxlabs-link-win-msix`)를 코드 서명하고, sideload MSIX로 배포·자동 업데이트하는 절차. + +> ⚠️ 토큰 비밀번호·어드민 비밀번호 등 **비밀 값은 이 문서에 적지 않는다.** 별도의 비밀 보관처(비밀번호 관리자)에 둔다. + +## 0. 인증서 개요 + +- 종류: **Sectigo OV Code Signing** (Organization Validation) +- 형태: **하드웨어 토큰(eToken)** — 물리 USB 토큰 + `SafeNet Authentication Client` 필요 +- 동작 제약: + - 서명하려면 **토큰을 PC에 꽂고 SafeNet 클라이언트 + 토큰 비밀번호**가 있어야 한다. + - **토큰 비밀번호 3회 실패 시 잠김** → Sectigo 지원팀으로만 해제. 자동화 실패 루프 주의. + - SafeNet Authentication Client 다운로드: + +### OV의 한계 (알고 시작할 것) + +- **SmartScreen 평판은 즉시 생기지 않는다.** EV와 달리 다운로드·설치가 누적되어야 "알 수 없는 게시자" 경고가 사라진다. 초기 사용자는 경고를 볼 수 있다. +- **하드웨어 토큰이라 CI 자동 서명이 어렵다.** 현재는 **로컬 수동 서명**이 현실적. (자동화하려면 셀프호스트 러너에 토큰 연결 또는 클라우드 HSM 서명 서비스가 필요.) + +## 1. 서명 도구 — SignTool + +표준 도구는 **`signtool.exe`** (Windows SDK 포함). + +- 위치: `C:\Program Files (x86)\Windows Kits\10\bin\<버전>\x64\signtool.exe` +- PATH에 없으므로 **Visual Studio의 "Developer PowerShell" / "Developer Command Prompt"** 에서 실행하면 자동으로 잡힌다. + +서명: + +```powershell +signtool sign /fd SHA256 /a /n "ALUX Inc." ` + /tr http://timestamp.sectigo.com /td SHA256 ` + AluxLabsLink.msixbundle +``` + +- `/a` — 적합한 인증서 자동 선택 (토큰 인증서) +- `/n "ALUX Inc."` — Subject 이름으로 인증서 지정 +- `/tr` + `/td SHA256` — 타임스탬프. **필수** (인증서 만료 후에도 서명 유효 유지) +- `/fd SHA256` — 파일 다이제스트 알고리즘 + +확인: + +```powershell +signtool verify /pa /v AluxLabsLink.msixbundle +``` + +## 2. ⚠️ Publisher 일치 규칙 (MSIX 최대 함정) + +MSIX는 **서명 인증서의 Subject DN과 매니페스트 `Publisher`가 문자 그대로 정확히 일치**해야 한다. 공백·쉼표·순서까지 동일해야 하며, 안 맞으면 서명 실패 또는 설치 거부. + +현재 [`Package.appxmanifest`](../../aluxlabs-link-win-msix/Package.appxmanifest): + +```xml + +``` + +OV 인증서의 실제 Subject는 보통 더 길다 (예: `CN=ALUX Inc., O=ALUX Inc., L=..., S=..., C=KR`). + +**인증서 도착 후 절차:** + +1. 실제 Subject 전체 문자열 확인: + ```powershell + certutil -user -store My + # 또는 SafeNet Authentication Client에서 인증서 보기 + ``` +2. 매니페스트의 `Publisher`를 그 값과 **완전히 동일하게** 수정. +3. (자동 업데이트 사용 시) `.appinstaller`의 `Publisher`도 동일하게 맞춘다 (4절). + +## 3. MSIX 서명 켜기 (wapproj 설정) + +현재 [`aluxlabs-link-win-msix.wapproj`](../../aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj) 는 **서명 OFF + 임시 인증서** 상태: + +```xml +false +True +``` + +배포 빌드에서는 임시 인증서 대신 실제 OV 토큰으로 서명한다. 권장 방식은 **빌드는 서명 없이(`AppxPackageSigningEnabled=false`) 번들만 만들고, 빌드 후 `signtool`로 별도 서명**하는 것 (토큰 비밀번호 입력 시점을 분리할 수 있어 CI/수동 모두 유연). + +VS GUI로 할 경우: wapproj 우클릭 → **게시(Publish) → 앱 패키지 만들기** 마법사에서 토큰 인증서를 선택해 서명할 수도 있다. + +## 4. 자동 업데이트 — `.appinstaller` (App Installer) + +별도 업데이트 서버/백엔드 로직이 **필요 없다.** Windows 내장 App Installer가 버전 비교·다운로드·적용을 모두 처리한다. 우리는 **정적 파일만 호스팅**한다. + +### 동작 흐름 + +1. 사용자는 `.msixbundle`이 아니라 **`.appinstaller` URL로 최초 설치**한다. +2. App Installer가 해당 `.appinstaller` URI를 기억한다. +3. 앱 실행 시(또는 백그라운드 작업) Windows가 `.appinstaller`를 다시 받아 **`Version`과 설치된 버전을 스스로 비교**한다. +4. 더 높으면 새 번들을 받아 적용한다. + +### `.appinstaller` 예시 + +```xml + + + + + + + + +``` + +### 켜는 법 + +[`aluxlabs-link-win-msix.wapproj`](../../aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj) 에서: + +```xml +True +https://download.alux.../ +0 +``` + +`GenerateAppInstallerFile=True`로 켜면 MSBuild가 패키지 버전과 `.appinstaller`의 `Version`을 자동 동기화한다. 패키지 버전은 커밋 수로 자동 증가하도록 되어 있으므로(MSIX 패키징 설정 참조), 버전 숫자를 손으로 고칠 일이 없다. + +### 호스팅 선택지 (미정) + +업로드 위치는 아직 미정. **`.appinstaller`의 URL은 영원히 고정**이어야 한다(설치된 클라이언트가 그 URL을 기억해 업데이트를 확인). 반면 `.msixbundle` URL은 버전마다 바뀌어도 된다. + +| 방식 | 비용 | 비고 | +|---|---|---| +| **GitHub Pages + Releases** | 무료 | 이미 GitHub 사용. `.appinstaller`는 Pages(고정 URL), 번들은 Releases 에셋(버전 태그별) | +| **AWS S3 + CloudFront** | 저렴 | URL 고정·MIME·HTTPS 설정 가능, 커스텀 도메인 가능 | + +### 호스팅 요구사항 (공통) + +- 일반 웹서버면 **MIME 타입 등록 필수**: + - `.appinstaller` → `application/appinstaller` + - `.msixbundle` → `application/msix` +- **HTTPS 강력 권장.** + +## 5. 신규 버전 릴리스 체크리스트 + +1. [ ] 토큰 연결 + SafeNet 클라이언트 실행 확인 +2. [ ] Release 구성으로 `.msixbundle` 빌드 +3. [ ] `signtool`로 서명 (1절) — Publisher 일치 확인(2절) +4. [ ] `signtool verify /pa`로 서명 검증 +5. [ ] `.appinstaller` + `.msixbundle`을 호스팅 위치에 업로드 (버전 동기화 확인) +6. [ ] 기존 설치본에서 자동 업데이트 동작 확인 From d02c6a779ca19de314435f1a594a9c491af0ba9b Mon Sep 17 00:00:00 2001 From: songtomtom Date: Mon, 8 Jun 2026 17:11:37 +0900 Subject: [PATCH 79/94] =?UTF-8?q?docs:=20README=EC=97=90=20SignPath=20Foun?= =?UTF-8?q?dation=20=EC=BD=94=EB=93=9C=EC=82=AC=EC=9D=B4=EB=8B=9D=20?= =?UTF-8?q?=EB=AA=85=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SignPath Foundation OSS 신청서 제출에 필요한 다운로드 페이지의 코드사이닝 주체 명시 요건 충족. --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 93dcd5ba..85924f1d 100644 --- a/README.md +++ b/README.md @@ -101,3 +101,11 @@ python brand/build_icons.py - **MSIX 번들(`*.msixbundle`)**: 여러 플랫폼을 하나로 묶어 배포 self-contained 배포(런타임 번들링)로 전환하면 설치 안내가 완전히 사라지지만, 바이너리 크기가 증가합니다. AnyCPU 빌드에서는 self-contained를 지원하지 않으므로 플랫폼별 빌드(x64/x86/ARM64)가 필요합니다. + +## 코드사이닝 + +Windows 빌드(`*.msixbundle`)는 [SignPath Foundation](https://signpath.org)의 무료 OSS 코드사이닝 서비스로 서명됩니다. SignPath Foundation은 오픈소스 프로젝트에 EV 코드사이닝 인증서를 제공하는 비영리 단체이며, 본 프로젝트는 AGPL-3.0-only 라이선스로 공개돼 있어 그 자격을 충족합니다. + +*Code signing for Windows builds is provided by [SignPath Foundation](https://signpath.org), a non-profit foundation that provides free code signing certificates for open source projects.* + +> 승인 절차 완료 전까지는 임시 자체서명 인증서가 사용되며, 이 기간 동안 사용자는 인증서를 Trusted Root에 수동 설치해야 설치할 수 있습니다. From caca385bd0aaab084a0b3743c0655a66df608dc6 Mon Sep 17 00:00:00 2001 From: songtomtom Date: Mon, 8 Jun 2026 17:14:34 +0900 Subject: [PATCH 80/94] =?UTF-8?q?ci:=20=EB=A0=88=EA=B1=B0=EC=8B=9C=20ci.ym?= =?UTF-8?q?l=20=EC=9E=90=EB=8F=99=20=ED=8A=B8=EB=A6=AC=EA=B1=B0=20?= =?UTF-8?q?=EB=B9=84=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit upstream의 ci.yml은 main 브랜치·semantic-release·fastlane·macOS 빌드를 전제로 하는데, AluxLabs Link fork는 main 브랜치를 두지 않고 별도 release.yml(PR #5)로 빌드/배포를 진행한다. push 시마다 \`fatal: couldn't find remote ref main\` 으로 실패해 PR 체크가 무조건 빨갛게 표시되는 노이즈를 제거. workflow_dispatch만 남겨 수동 검증·디버깅 가능성은 유지. PR #5 머지 시 이 파일은 완전히 삭제될 예정. --- .github/workflows/ci.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 31164b11..25a970a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,11 @@ name: CI build on: - push: # Runs whenever a commit is pushed to the repository, including for a PR - workflow_call: # Runs when this workflow is called from another workflow - workflow_dispatch: # Allows you to run this workflow manually from the Actions tab + # AluxLabs Link fork에서는 upstream의 macOS/semantic-release 흐름이 동작하지 않아 + # 자동 트리거를 비활성화. release.yml(별도 PR)이 정식 빌드/배포를 담당. + # push: + # workflow_call: + workflow_dispatch: # 수동 실행만 허용 (검증·디버깅용) concurrency: group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' From 30c234fc5d39df0dfe8a8f61491e9d7c860c15c1 Mon Sep 17 00:00:00 2001 From: songtomtom Date: Mon, 8 Jun 2026 17:18:23 +0900 Subject: [PATCH 81/94] =?UTF-8?q?ci:=20signature-assistant.yml(upstream=20?= =?UTF-8?q?CLA=20=EB=B4=87)=20=EC=9E=90=EB=8F=99=20=ED=8A=B8=EB=A6=AC?= =?UTF-8?q?=EA=B1=B0=20=EB=B9=84=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scratch Foundation의 CLA 서명 검사 봇이 우리 fork에서는 동작 의미가 없고, scratchfoundation/scratch-agreements 접근 PAT가 설정돼 있지 않아 매번 실패함. PR 체크가 무조건 빨갛게 표시되는 노이즈 제거. workflow_dispatch만 남겨 필요 시 수동 실행 가능. --- .github/workflows/signature-assistant.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/signature-assistant.yml b/.github/workflows/signature-assistant.yml index acd2c3bb..be51a8c1 100644 --- a/.github/workflows/signature-assistant.yml +++ b/.github/workflows/signature-assistant.yml @@ -1,9 +1,13 @@ name: "Signature Assistant" on: - issue_comment: - types: [created] - pull_request_target: - types: [opened,closed,synchronize] + # Scratch Foundation의 CLA 서명 검사 봇. AluxLabs Link fork는 upstream에 기여하는 + # 워크플로가 아니므로 자동 트리거를 비활성화한다. (scratchfoundation/scratch-agreements + # 접근 PAT가 우리 저장소에 없어 매번 실패만 함.) + # issue_comment: + # types: [created] + # pull_request_target: + # types: [opened,closed,synchronize] + workflow_dispatch: # 수동 실행만 허용 permissions: actions: write From a043ffc38a6782ee9310695bdd160fa77978dec0 Mon Sep 17 00:00:00 2001 From: songtomtom Date: Mon, 8 Jun 2026 17:49:36 +0900 Subject: [PATCH 82/94] =?UTF-8?q?docs:=20README=20=EC=B5=9C=EC=83=81?= =?UTF-8?q?=EB=8B=A8=EC=97=90=20=EC=98=81=EB=AC=B8=20=EC=9A=94=EC=95=BD=20?= =?UTF-8?q?=EB=B0=95=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SignPath Foundation 심사 시 비영어권 README의 가독성을 보완하기 위한 안전 마진. 영문 요약에 프로젝트 성격, 라이선스(AGPL-3.0-only), upstream fork 관계, SignPath Foundation 코드사이닝 사실을 한 박스에 집약. --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index b1f1369c..d4e95755 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,14 @@ # AluxLabs Link +> **About this project (English summary)** +> AluxLabs Link is a Windows desktop application that bridges Scratch 3.0 +> with hardware peripherals (BLE, Bluetooth Classic, USB Serial). It is a +> Windows-focused, rebranded fork of Scratch Foundation's +> [scratch-link](https://github.com/scratchfoundation/scratch-link), +> distributed under the **AGPL-3.0-only** license. Windows builds are +> code-signed by [SignPath Foundation](https://signpath.org). The rest of +> this README is Korean-localized documentation. + Scratch 3.0과 PC에 연결된 하드웨어 주변기기를 중계하는 도우미 앱. > 본 제품은 Scratch Foundation 의 [scratch-link](https://github.com/scratchfoundation/scratch-link) (AGPL-3.0-only) 에서 파생된 Windows 전용 포크이며, 동일한 **AGPL-3.0-only** 라이선스로 배포됩니다. 변경 내역·소스 위치·상표 고지는 [NOTICE](NOTICE) ([한국어](NOTICE.ko)), 전체 라이선스 텍스트는 [LICENSE](LICENSE) 를 참조하십시오. From 28866e63ef4ecc58368c8035daf0652ba93810fa Mon Sep 17 00:00:00 2001 From: songtomtom Date: Mon, 8 Jun 2026 17:53:05 +0900 Subject: [PATCH 83/94] =?UTF-8?q?docs:=20SignPath=20Foundation=20OSS=20?= =?UTF-8?q?=EC=8B=A0=EC=B2=AD=EC=84=9C=20=EC=A0=9C=EC=B6=9C=20=EB=82=B4?= =?UTF-8?q?=EC=9A=A9=20=EA=B8=B0=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2026-06-08 제출 시점의 모든 필드 입력값, Description·Reputation 본문, 선행 PR 목록(#5, #9, #10, #11), 승인 후 후속 작업 TODO, 자격 박탈 시 대체 옵션을 한 문서에 보존. 향후 자격 갱신·재신청·다른 사이닝 옵션 전환 시 참고용. --- docs/signpath-application.md | 147 +++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 docs/signpath-application.md diff --git a/docs/signpath-application.md b/docs/signpath-application.md new file mode 100644 index 00000000..f9783478 --- /dev/null +++ b/docs/signpath-application.md @@ -0,0 +1,147 @@ +# SignPath Foundation OSS 무료 코드사이닝 신청서 + +**제출일**: 2026-06-08 +**제출 URL**: https://signpath.org/apply +**프로젝트**: AluxLabs Link (`aluxrobot/scratch-link`) +**예상 검토 기간**: 2~4주 + +--- + +## 배경 + +- 한국 법인은 Azure Trusted Signing(미국·캐나다·EU·UK 한정) 사용 불가 +- 상용 EV 인증서는 연 80~100만원 비용 +- AluxLabs Link는 AGPL-3.0-only OSS이므로 **SignPath Foundation OSS 플랜(무료)** 자격 충족 + - public GitHub repo ✅ + - OSI 승인 라이선스(AGPL-3.0) ✅ + - GitHub Actions CI 빌드 ✅ + - 활성 프로젝트 ✅ + +--- + +## 신청서 필드 입력값 + +| 필드 | 입력값 | +|---|---| +| Project Name ★ | `AluxLabs Link` | +| Repository URL ★ | `https://github.com/aluxrobot/scratch-link` | +| Homepage URL ★ | `https://github.com/aluxrobot/scratch-link` | +| Download URL | `https://scratch-link.aluxcoding.com/` | +| Privacy Policy URL | (비움) | +| Wikipedia URL | (비움) | +| Tagline ★ | `Windows desktop bridge between Scratch 3.0 and educational hardware (BLE, Bluetooth, USB Serial).` | +| Description ★ | (아래 본문) | +| Reputation ★ | (아래 본문) | +| Maintainer Type | `For-profit company or corporate-backed project` | +| Build System | `GitHub Actions` | +| First Name ★ | 본인 영문 이름 | +| Last Name ★ | 본인 영문 성 | +| Email ★ | 회사 이메일 또는 개인 이메일 | +| Company Name | `Alux Co., Ltd.` | +| Primary Discovery Channel ★ | `Google search` | +| Please specify the exact source | `Searched for free code signing alternatives after Azure Trusted Signing was found unavailable for Korean entities.` | +| Code of Conduct 동의 ★ | ✅ | +| 개인정보 처리 동의 ★ | ✅ | + +★ = 필수 + +--- + +## Description (제출 본문) + +``` +AluxLabs Link is a small Windows desktop application that bridges +Scratch 3.0 (a visual programming environment widely used in education) +with hardware peripherals — BLE devices, Bluetooth Classic devices, +and USB serial ports. + +This repository is a Windows-focused, rebranded fork of Scratch +Foundation's scratch-link project. The fork has been renamed to +"AluxLabs Link" to clearly distinguish it from upstream, while +remaining a derivative work under the same AGPL-3.0-only license. +It extends hardware support for educational robotics platforms +distributed in the Korean market and rebuilds the Windows app on +.NET 8 + WinUI 3 + Windows App SDK 1.8 (upstream was .NET 6). + +End users are students, teachers, and parents who install AluxLabs +Link to connect physical robots and sensors to Scratch 3.0 lessons +through Alux's educational curriculum. +``` + +--- + +## Reputation (제출 본문) + +``` +This project is a fork of "scratch-link" maintained by the Scratch +Foundation (https://github.com/scratchfoundation/scratch-link), +which is a core component of Scratch 3.0 — one of the most widely +used educational programming platforms in the world, reaching tens +of millions of learners. The upstream repository is the official +hardware bridge shipped on scratch.mit.edu. + +Our fork ("AluxLabs Link") targets the Korean educational market +through Alux, a Korean education company. The signed Windows builds +will be distributed to schools, after-school robotics academies, and +individual learners who use Alux's educational robot kits with +Scratch 3.0. Distribution channel is https://scratch-link.aluxcoding.com/ +served by our own CloudFront CDN. Expected reach: schools and +individual learners across South Korea using Alux's robotics +curriculum. + +The fork extends upstream's hardware support (adds USB Serial +transport, modernizes the Windows runtime to .NET 8 + WinUI 3 + +Windows App SDK 1.8), and is maintained as an active downstream +that tracks upstream where applicable. + +License: GNU AGPL-3.0 (inherited from upstream). +``` + +--- + +## 제출 시점의 사전 작업 (참고) + +신청 직전에 develop 브랜치에 반영해둔 사항 — 심사관이 repo 첫 화면에서 즉시 확인 가능하도록: + +1. **README 최상단 영문 요약 박스** (PR #11) + - 프로젝트 성격, 라이선스, upstream 관계, SignPath 사용 사실을 영문 1단락에 집약 + +2. **README `## 코드사이닝` 섹션** (PR #9) + - SignPath Foundation 코드사이닝 명시 (한·영 병기) + - Download URL 요건 충족: *"This page must mention that the project uses the SignPath Foundation for code signing."* + +3. **CI/CD 파이프라인 구축** (PR #5) + - `release.yml`로 tag 푸시 → MSIX 빌드 → S3 업로드 → CloudFront invalidation + - 빌드 산출물: `AluxLabs-Link-{version}.msixbundle` + +4. **upstream 잔재 워크플로 비활성화** (PR #10) + - 옛 `ci.yml`, `signature-assistant.yml`의 자동 트리거 주석 처리 + +--- + +## 승인 후 후속 작업 (TODO) + +- [ ] SignPath.io 조직 가입 안내 메일 수신 +- [ ] Signing Policy 설정: + - GitHub repo·branch 제한 (`aluxrobot/scratch-link`, `develop` 또는 tag만) + - 산출물 type·해시 검증 +- [ ] API Token + Organization ID + Project Slug 발급 +- [ ] GitHub Secrets 등록: + - `SIGNPATH_API_TOKEN` + - `SIGNPATH_ORG_ID` +- [ ] `release.yml`에 SignPath signing step 추가 (`signpath/github-action-submit-signing-request@v1`) +- [ ] dev 채널 빌드로 서명 동작 검증 +- [ ] README의 "승인 절차 완료 전까지는 임시 자체서명 인증서가 사용되며..." 안내문 제거 + +--- + +## 자격 박탈 / 정책 변경 시 대응 시나리오 + +만약 SignPath Foundation이 자격 재심사에서 박탈하거나 정책을 바꿀 경우: + +- **대체 1순위**: SSL.com eSigner EV (연 ~$590) +- **대체 2순위**: Certum Cloud EV (연 ~€269) +- **대체 3순위**: DigiCert KeyLocker EV (연 ~$700) + +모두 한국 법인 발급 가능, GitHub Actions 통합 지원. +`release.yml`의 signing step만 교체하면 전환 가능한 구조로 설계. From da7be80cfad0a579242856b928db52b5c3990db8 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Jun 2026 18:02:58 +0900 Subject: [PATCH 84/94] =?UTF-8?q?chore(msix):=20=EC=8B=A4=EC=A0=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EC=84=9C=EB=AA=85=20=EC=9D=B8=EC=A6=9D?= =?UTF-8?q?=EC=84=9C=EC=97=90=20=EB=A7=9E=EC=B6=B0=20Publisher=20=EC=8B=A0?= =?UTF-8?q?=EC=9B=90=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sectigo OV 인증서 Subject(CN="ALUX Co.,Ltd", O="ALUX Co.,Ltd", S=Seoul, C=KR)와 매니페스트 Publisher를 일치시킴 (MSIX 서명 필수 조건). 사용자 노출용 PublisherDisplayName은 브랜드명 "ALUX Inc."로 분리. Co-Authored-By: Claude Opus 4.8 (1M context) --- aluxlabs-link-win-msix/Package.appxmanifest | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aluxlabs-link-win-msix/Package.appxmanifest b/aluxlabs-link-win-msix/Package.appxmanifest index 887e4fa7..1d9f45d6 100644 --- a/aluxlabs-link-win-msix/Package.appxmanifest +++ b/aluxlabs-link-win-msix/Package.appxmanifest @@ -8,12 +8,12 @@ AluxLabs Link - ALUX, Inc. + ALUX Inc. Images\StoreLogo.png From d308f6afb2c518d8b99652eee08982213e9ccfa6 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Jun 2026 19:39:44 +0900 Subject: [PATCH 85/94] =?UTF-8?q?docs(msix):=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EB=B0=B0=ED=8F=AC=20=ED=99=95=EC=A0=95=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81=20+=20.appinstaller=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .appinstaller 정본 추가 (prod: scratch-assets/link, dev: dev-scratch-assets/link) - 호스팅 확정: 토큰 수동 배포는 scratch-assets/link, CI(scratch-link)와 분리 - Publisher 확정값(CN="ALUX Co.,Ltd"...) 및 서명 검증 결과 문서화 - 릴리스마다 버전 3곳 갱신 규칙, MIME 타입 명시 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Alux/CodeSigningAndDistribution.md | 120 ++++++++++-------- .../dist/AluxLabsLink.appinstaller | 18 +++ .../dist/AluxLabsLink.dev.appinstaller | 18 +++ 3 files changed, 100 insertions(+), 56 deletions(-) create mode 100644 aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller create mode 100644 aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller diff --git a/Documentation/Alux/CodeSigningAndDistribution.md b/Documentation/Alux/CodeSigningAndDistribution.md index b144e48c..6cbb9f6f 100644 --- a/Documentation/Alux/CodeSigningAndDistribution.md +++ b/Documentation/Alux/CodeSigningAndDistribution.md @@ -8,15 +8,30 @@ AluxLabs Link(`aluxlabs-link-win-msix`)를 코드 서명하고, sideload MSIX로 - 종류: **Sectigo OV Code Signing** (Organization Validation) - 형태: **하드웨어 토큰(eToken)** — 물리 USB 토큰 + `SafeNet Authentication Client` 필요 +- 인증서 Subject (= 매니페스트 Publisher와 일치시킬 값): **`CN="ALUX Co.,Ltd", O="ALUX Co.,Ltd", S=Seoul, C=KR`** +- 발급자: `Sectigo Public Code Signing CA R36` / 만료: **2027-07-01** (갱신 필요 시점) - 동작 제약: - 서명하려면 **토큰을 PC에 꽂고 SafeNet 클라이언트 + 토큰 비밀번호**가 있어야 한다. - - **토큰 비밀번호 3회 실패 시 잠김** → Sectigo 지원팀으로만 해제. 자동화 실패 루프 주의. + - **토큰 비밀번호 3회 실패 시 잠김** → Sectigo 지원팀으로만 해제. 비밀번호 창은 복사·붙여넣기 가능(오타 방지 권장). - SafeNet Authentication Client 다운로드: + - SafeNet 설치는 **Typical**(Microsoft Crypto Providers 포함) 선택 → `signtool`이 토큰 키에 접근 가능해진다. ### OV의 한계 (알고 시작할 것) - **SmartScreen 평판은 즉시 생기지 않는다.** EV와 달리 다운로드·설치가 누적되어야 "알 수 없는 게시자" 경고가 사라진다. 초기 사용자는 경고를 볼 수 있다. -- **하드웨어 토큰이라 CI 자동 서명이 어렵다.** 현재는 **로컬 수동 서명**이 현실적. (자동화하려면 셀프호스트 러너에 토큰 연결 또는 클라우드 HSM 서명 서비스가 필요.) +- **하드웨어 토큰이라 CI 자동 서명이 어렵다.** 토큰을 꽂은 머신에서만 서명되므로 **로컬 수동 서명**으로 운영한다. + +### 배포 트랙 분리 (중요) + +서명 주체가 둘이라 **버킷·신원을 분리**한다. 섞이면 패키지 신원이 충돌해 자동 업데이트가 깨진다. + +| 트랙 | 서명 | 버킷 | 주체 | +|---|---|---|---| +| **실제 배포** | **USB 토큰(Sectigo)** | `scratch-assets.aluxcoding.com/link/` (+ dev: `dev-scratch-assets.../link/`) | **수동** (이 문서) | +| CI/CD 테스트 | SignPath(신청 중) / 임시 인증서 | `scratch-link.aluxcoding.com` / `dev-scratch-link...` | GitHub Actions (`release.yml`) | + +- 두 트랙은 **인증서 Subject가 달라 Publisher도 다르다** → 서로 자동 업데이트 안 됨(의도된 분리). +- CI 버킷(`scratch-link`)은 `scripts/aws/setup-cdn.sh`가 관리. **토큰 배포는 그쪽을 건드리지 않는다.** ## 1. 서명 도구 — SignTool @@ -28,15 +43,16 @@ AluxLabs Link(`aluxlabs-link-win-msix`)를 코드 서명하고, sideload MSIX로 서명: ```powershell -signtool sign /fd SHA256 /a /n "ALUX Inc." ` +signtool sign /fd SHA256 /a /n "ALUX Co.,Ltd" ` /tr http://timestamp.sectigo.com /td SHA256 ` AluxLabsLink.msixbundle ``` - `/a` — 적합한 인증서 자동 선택 (토큰 인증서) -- `/n "ALUX Inc."` — Subject 이름으로 인증서 지정 +- `/n "ALUX Co.,Ltd"` — Subject 이름으로 인증서 지정 - `/tr` + `/td SHA256` — 타임스탬프. **필수** (인증서 만료 후에도 서명 유효 유지) - `/fd SHA256` — 파일 다이제스트 알고리즘 +- 실행 시 **SafeNet 비밀번호 창**이 팝업된다. (검증됨: 일반 PE 파일 시험 서명 성공 — 체인·타임스탬프 정상) 확인: @@ -48,23 +64,20 @@ signtool verify /pa /v AluxLabsLink.msixbundle MSIX는 **서명 인증서의 Subject DN과 매니페스트 `Publisher`가 문자 그대로 정확히 일치**해야 한다. 공백·쉼표·순서까지 동일해야 하며, 안 맞으면 서명 실패 또는 설치 거부. -현재 [`Package.appxmanifest`](../../aluxlabs-link-win-msix/Package.appxmanifest): +**확정값** — [`Package.appxmanifest`](../../aluxlabs-link-win-msix/Package.appxmanifest)의 `Publisher`는 인증서 Subject에 맞춰져 있다. 콤마가 값 안에 있어 XML에서는 따옴표를 `"`로 이스케이프한다: ```xml - + ``` -OV 인증서의 실제 Subject는 보통 더 길다 (예: `CN=ALUX Inc., O=ALUX Inc., L=..., S=..., C=KR`). +- `Publisher`(서명 신원)는 인증서와 일치 — **변경 금지**(바꾸면 패키지 신원이 바뀌어 자동 업데이트 끊김). +- 사용자에게 보이는 발행자 이름은 별개인 `ALUX Inc.` (브랜드명, sideload에서는 인증서와 무관). +- `.appinstaller`의 `Publisher`도 같은 값으로 맞춰져 있다 (4절). -**인증서 도착 후 절차:** - -1. 실제 Subject 전체 문자열 확인: - ```powershell - certutil -user -store My - # 또는 SafeNet Authentication Client에서 인증서 보기 - ``` -2. 매니페스트의 `Publisher`를 그 값과 **완전히 동일하게** 수정. -3. (자동 업데이트 사용 시) `.appinstaller`의 `Publisher`도 동일하게 맞춘다 (4절). +> 인증서 Subject 재확인이 필요하면: `certutil -user -store My` 또는 SafeNet Authentication Client에서 인증서 보기. ## 3. MSIX 서명 켜기 (wapproj 설정) @@ -90,59 +103,54 @@ VS GUI로 할 경우: wapproj 우클릭 → **게시(Publish) → 앱 패키지 3. 앱 실행 시(또는 백그라운드 작업) Windows가 `.appinstaller`를 다시 받아 **`Version`과 설치된 버전을 스스로 비교**한다. 4. 더 높으면 새 번들을 받아 적용한다. -### `.appinstaller` 예시 +### `.appinstaller` 파일 (확정·커밋됨) -```xml - - - - - - - - -``` +수동 운영이므로 MSBuild 자동 생성 대신 파일을 직접 관리한다. 저장소에 둔 정본: -### 켜는 법 +- prod: [`dist/AluxLabsLink.appinstaller`](../../aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller) → `scratch-assets.aluxcoding.com/link/` +- dev: [`dist/AluxLabsLink.dev.appinstaller`](../../aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller) → `dev-scratch-assets.aluxcoding.com/link/` -[`aluxlabs-link-win-msix.wapproj`](../../aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj) 에서: +스키마는 `2017/2` (Windows 1809+ 호환 — 매니페스트 MinVersion과 동일). `Publisher`는 인증서 Subject와 일치. -```xml -True -https://download.alux.../ -0 -``` +### ⚠️ 릴리스마다 고칠 곳 — 버전 3곳 + +`.appinstaller`의 버전이 **실제 빌드된 번들 버전과 정확히 일치**해야 Windows가 비교한다. 새 릴리스마다 다음 3곳을 그 버전으로 바꾼다: -`GenerateAppInstallerFile=True`로 켜면 MSBuild가 패키지 버전과 `.appinstaller`의 `Version`을 자동 동기화한다. 패키지 버전은 커밋 수로 자동 증가하도록 되어 있으므로(MSIX 패키징 설정 참조), 버전 숫자를 손으로 고칠 일이 없다. +1. `` — 루트 +2. `` — 번들 +3. `` — 파일명 -### 호스팅 선택지 (미정) +> **``의 `Uri`(고정 URL)는 절대 변경 금지** — 설치된 클라이언트가 기억하는 진입점이다. 바꾸는 건 버전과 번들 파일명뿐. -업로드 위치는 아직 미정. **`.appinstaller`의 URL은 영원히 고정**이어야 한다(설치된 클라이언트가 그 URL을 기억해 업데이트를 확인). 반면 `.msixbundle` URL은 버전마다 바뀌어도 된다. +버전은 git 태그 기반으로 산출된다(`ScratchVersion.targets`): 태그 없으면 `1.0.0.<커밋수>`, 정식 릴리스는 `git tag v1.2.0` → `1.2.0.x`. 빌드된 번들의 실제 버전·Publisher 확인: -| 방식 | 비용 | 비고 | -|---|---|---| -| **GitHub Pages + Releases** | 무료 | 이미 GitHub 사용. `.appinstaller`는 Pages(고정 URL), 번들은 Releases 에셋(버전 태그별) | -| **AWS S3 + CloudFront** | 저렴 | URL 고정·MIME·HTTPS 설정 가능, 커스텀 도메인 가능 | +```powershell +Get-AppLockerFileInformation -Path .\AluxLabs-Link-x.y.z.msixbundle | Select-Object -ExpandProperty Publisher +``` -### 호스팅 요구사항 (공통) +### 호스팅 — `scratch-assets/link/` (확정) + +토큰 배포는 `scratch-assets.aluxcoding.com/link/`(dev는 `dev-scratch-assets.../link/`)에 **수동 업로드**한다. 이 버킷은 이미 Scratch 자산(`driver/`, `firmware/`, `sb3/` 등)을 서빙 중이며 CI(`setup-cdn.sh`)가 건드리지 않는 곳이라 충돌이 없다. + +``` +scratch-assets.aluxcoding.com/ + link/ + AluxLabsLink.appinstaller # 고정 URL (진입점, 불변) + AluxLabs-Link-x.y.z.msixbundle # 토큰 서명된 번들 (버전별) +``` -- 일반 웹서버면 **MIME 타입 등록 필수**: +- **`.appinstaller` URL은 영원히 고정**. `.msixbundle` URL은 버전마다 바뀌어도 됨. +- **MIME 타입 필수** (이 버킷엔 아직 MSIX MIME이 없을 수 있음 → 업로드 시 `--content-type`으로 지정): - `.appinstaller` → `application/appinstaller` - - `.msixbundle` → `application/msix` -- **HTTPS 강력 권장.** + - `.msixbundle` → `application/vnd.ms-appx` +- CloudFront HTTPS 서빙 전제. -## 5. 신규 버전 릴리스 체크리스트 +## 5. 신규 버전 릴리스 체크리스트 (토큰 수동) 1. [ ] 토큰 연결 + SafeNet 클라이언트 실행 확인 2. [ ] Release 구성으로 `.msixbundle` 빌드 -3. [ ] `signtool`로 서명 (1절) — Publisher 일치 확인(2절) +3. [ ] `signtool`로 서명 (1절) — Publisher 일치(2절) 4. [ ] `signtool verify /pa`로 서명 검증 -5. [ ] `.appinstaller` + `.msixbundle`을 호스팅 위치에 업로드 (버전 동기화 확인) -6. [ ] 기존 설치본에서 자동 업데이트 동작 확인 +5. [ ] `.appinstaller`의 **버전 3곳 + 번들 파일명** 갱신 (위 규칙) +6. [ ] `scratch-assets/link/`에 `.appinstaller` + 서명된 번들 업로드 (`--content-type` 지정) +7. [ ] 기존 설치본에서 자동 업데이트 동작 확인 diff --git a/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller b/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller new file mode 100644 index 00000000..298bef74 --- /dev/null +++ b/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller @@ -0,0 +1,18 @@ + + + + + + + + + + + diff --git a/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller b/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller new file mode 100644 index 00000000..90850a9f --- /dev/null +++ b/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller @@ -0,0 +1,18 @@ + + + + + + + + + + + From f2a818f978b197bd2ec590e600b6ad84c128f731 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Jun 2026 20:21:00 +0900 Subject: [PATCH 86/94] =?UTF-8?q?chore(msix):=20=EB=B0=B0=ED=8F=AC=20?= =?UTF-8?q?=EC=95=84=ED=82=A4=ED=85=8D=EC=B2=98=20x86|x64=EB=A1=9C=20?= =?UTF-8?q?=EC=B6=95=EC=86=8C=20+=20.appinstaller=20=EB=B2=84=EC=A0=84=20?= =?UTF-8?q?=EA=B0=B1=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AppxBundlePlatforms에서 arm64 제외 (대상 사용자 없음, 번들 용량↓). CI release.yml은 플랫폼을 명시 지정하므로 영향 없음. - prod .appinstaller 버전을 실제 빌드(1.0.0.1028)에 맞춤. - dist/upload/(서명된 대용량 번들 스테이징)를 .gitignore에 추가. Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitignore | 3 +++ aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj | 2 +- aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 4c90e4c9..f1773c63 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ ref/ # Test signing materials (self-signed test certs / build logs — never commit) /aluxlabs-link-win-msix/_signing/ + +# Staged distribution bundles (서명된 .msixbundle — 대용량이라 커밋 금지. .appinstaller 템플릿은 dist/ 직하에 별도 커밋) +/aluxlabs-link-win-msix/dist/upload/ diff --git a/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj b/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj index 064c7bb5..6179cb65 100644 --- a/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj +++ b/aluxlabs-link-win-msix/aluxlabs-link-win-msix.wapproj @@ -55,7 +55,7 @@ False False True - x86|x64|arm64 + x86|x64 0 diff --git a/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller b/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller index 298bef74..9d343984 100644 --- a/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller +++ b/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller @@ -2,13 +2,13 @@ + Version="1.0.0.1028"> + Version="1.0.0.1028" + Uri="https://scratch-assets.aluxcoding.com/link/AluxLabs-Link-1.0.0.1028.msixbundle" /> From 2c0a048717b131a8a70c97963a8565902009db37 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 Jun 2026 15:46:35 +0900 Subject: [PATCH 87/94] =?UTF-8?q?docs(msix):=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EB=B0=B0=ED=8F=AC=20=ED=98=B8=EC=8A=A4=ED=8C=85=EC=9D=84=20scr?= =?UTF-8?q?atch-link=EB=A1=9C=20=ED=99=95=EC=A0=95=20+=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EA=B2=B0=EA=B3=BC=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .appinstaller 도메인 scratch-assets → scratch-link(공개 CDN 있는 곳). scratch-assets는 공개 DNS가 없어 제외, link 하위폴더 없이 루트 사용. - 문서: 호스팅 절을 aws s3 cp + CloudFront 무효화 절차로 갱신 (배포 ID, MIME 함정, /sha1 서명 권장, 인증서 지문 추가). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Alux/CodeSigningAndDistribution.md | 62 ++++++++++++------- .../dist/AluxLabsLink.appinstaller | 4 +- .../dist/AluxLabsLink.dev.appinstaller | 8 +-- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/Documentation/Alux/CodeSigningAndDistribution.md b/Documentation/Alux/CodeSigningAndDistribution.md index 6cbb9f6f..f558371d 100644 --- a/Documentation/Alux/CodeSigningAndDistribution.md +++ b/Documentation/Alux/CodeSigningAndDistribution.md @@ -10,6 +10,7 @@ AluxLabs Link(`aluxlabs-link-win-msix`)를 코드 서명하고, sideload MSIX로 - 형태: **하드웨어 토큰(eToken)** — 물리 USB 토큰 + `SafeNet Authentication Client` 필요 - 인증서 Subject (= 매니페스트 Publisher와 일치시킬 값): **`CN="ALUX Co.,Ltd", O="ALUX Co.,Ltd", S=Seoul, C=KR`** - 발급자: `Sectigo Public Code Signing CA R36` / 만료: **2027-07-01** (갱신 필요 시점) +- 지문(SHA1): `EB74741683C9CDCE4457571A7EDD075A835B02C6` — `signtool /sha1`에 사용 - 동작 제약: - 서명하려면 **토큰을 PC에 꽂고 SafeNet 클라이언트 + 토큰 비밀번호**가 있어야 한다. - **토큰 비밀번호 3회 실패 시 잠김** → Sectigo 지원팀으로만 해제. 비밀번호 창은 복사·붙여넣기 가능(오타 방지 권장). @@ -21,17 +22,18 @@ AluxLabs Link(`aluxlabs-link-win-msix`)를 코드 서명하고, sideload MSIX로 - **SmartScreen 평판은 즉시 생기지 않는다.** EV와 달리 다운로드·설치가 누적되어야 "알 수 없는 게시자" 경고가 사라진다. 초기 사용자는 경고를 볼 수 있다. - **하드웨어 토큰이라 CI 자동 서명이 어렵다.** 토큰을 꽂은 머신에서만 서명되므로 **로컬 수동 서명**으로 운영한다. -### 배포 트랙 분리 (중요) +### 배포 트랙 (한 버킷, 파일명으로 분리) -서명 주체가 둘이라 **버킷·신원을 분리**한다. 섞이면 패키지 신원이 충돌해 자동 업데이트가 깨진다. +서명 주체가 둘이지만 **버킷은 `scratch-link`(prod)/`dev-scratch-link`(dev)로 공통**이다. 파일명이 달라 충돌하지 않는다. -| 트랙 | 서명 | 버킷 | 주체 | +| 트랙 | 서명 | 파일 | 주체 | |---|---|---|---| -| **실제 배포** | **USB 토큰(Sectigo)** | `scratch-assets.aluxcoding.com/link/` (+ dev: `dev-scratch-assets.../link/`) | **수동** (이 문서) | -| CI/CD 테스트 | SignPath(신청 중) / 임시 인증서 | `scratch-link.aluxcoding.com` / `dev-scratch-link...` | GitHub Actions (`release.yml`) | +| **실제 배포** | **USB 토큰(Sectigo)** | `AluxLabsLink.appinstaller` + `AluxLabs-Link-<버전>.msixbundle` | **수동** (이 문서) | +| CI/CD 테스트 | SignPath(신청 중) / 임시 인증서 | `latest.msixbundle` + `latest.json` + `archive/` | GitHub Actions (`release.yml`) | - 두 트랙은 **인증서 Subject가 달라 Publisher도 다르다** → 서로 자동 업데이트 안 됨(의도된 분리). -- CI 버킷(`scratch-link`)은 `scripts/aws/setup-cdn.sh`가 관리. **토큰 배포는 그쪽을 건드리지 않는다.** +- CI 버킷은 `scripts/aws/setup-cdn.sh`가 만든 것. **CI 파일(`latest.*`, `archive/`)은 건드리지 않는다.** +- (`scratch-assets` 버킷도 검토했으나 공개 DNS가 없어 제외. `scratch-link`만 CloudFront로 공개 서빙됨.) ## 1. 서명 도구 — SignTool @@ -107,8 +109,8 @@ VS GUI로 할 경우: wapproj 우클릭 → **게시(Publish) → 앱 패키지 수동 운영이므로 MSBuild 자동 생성 대신 파일을 직접 관리한다. 저장소에 둔 정본: -- prod: [`dist/AluxLabsLink.appinstaller`](../../aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller) → `scratch-assets.aluxcoding.com/link/` -- dev: [`dist/AluxLabsLink.dev.appinstaller`](../../aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller) → `dev-scratch-assets.aluxcoding.com/link/` +- prod: [`dist/AluxLabsLink.appinstaller`](../../aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller) → `scratch-link.aluxcoding.com/` (루트) +- dev: [`dist/AluxLabsLink.dev.appinstaller`](../../aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller) → `dev-scratch-link.aluxcoding.com/` (루트) 스키마는 `2017/2` (Windows 1809+ 호환 — 매니페스트 MinVersion과 동일). `Publisher`는 인증서 Subject와 일치. @@ -128,29 +130,47 @@ VS GUI로 할 경우: wapproj 우클릭 → **게시(Publish) → 앱 패키지 Get-AppLockerFileInformation -Path .\AluxLabs-Link-x.y.z.msixbundle | Select-Object -ExpandProperty Publisher ``` -### 호스팅 — `scratch-assets/link/` (확정) +### 호스팅 — `scratch-link.aluxcoding.com` 루트 (확정) -토큰 배포는 `scratch-assets.aluxcoding.com/link/`(dev는 `dev-scratch-assets.../link/`)에 **수동 업로드**한다. 이 버킷은 이미 Scratch 자산(`driver/`, `firmware/`, `sb3/` 등)을 서빙 중이며 CI(`setup-cdn.sh`)가 건드리지 않는 곳이라 충돌이 없다. +토큰 배포는 **`scratch-link.aluxcoding.com`(prod) / `dev-scratch-link.aluxcoding.com`(dev) 루트**에 `aws s3 cp`로 수동 업로드한다. (이 도메인만 CloudFront로 공개 서빙됨 — `scratch-assets`는 공개 DNS가 없어 제외.) ``` -scratch-assets.aluxcoding.com/ - link/ - AluxLabsLink.appinstaller # 고정 URL (진입점, 불변) - AluxLabs-Link-x.y.z.msixbundle # 토큰 서명된 번들 (버전별) +scratch-link.aluxcoding.com/ + AluxLabsLink.appinstaller # 고정 URL (진입점, 불변) + AluxLabs-Link-x.y.z.msixbundle # 토큰 서명된 번들 (버전별) ``` +진입점 URL: `https://scratch-link.aluxcoding.com/AluxLabsLink.appinstaller` + - **`.appinstaller` URL은 영원히 고정**. `.msixbundle` URL은 버전마다 바뀌어도 됨. -- **MIME 타입 필수** (이 버킷엔 아직 MSIX MIME이 없을 수 있음 → 업로드 시 `--content-type`으로 지정): +- **MIME 타입 필수** — 콘솔 업로드는 `binary/octet-stream`이 붙어 깨진다. 반드시 `--content-type` 지정: - `.appinstaller` → `application/appinstaller` - `.msixbundle` → `application/vnd.ms-appx` -- CloudFront HTTPS 서빙 전제. +- 업로드 후 **CloudFront 무효화** 필수 (안 하면 옛 캐시가 잘못된 MIME로 남음). + - 배포 ID: prod `E3HEXR4KAZLITV`, dev `E1WMSQXPP9L5YF` + +업로드 + 무효화 명령 (CLI 자격증명 필요 — IAM 정책 `scripts/aws/policies/iam-policy.json.tpl`): + +```powershell +$v = "1.0.0.1028" # 실제 빌드 버전 +$b = "scratch-link.aluxcoding.com" # dev면 dev-scratch-link.aluxcoding.com +aws s3 cp "dist\upload\AluxLabs-Link-$v.msixbundle" "s3://$b/AluxLabs-Link-$v.msixbundle" --content-type application/vnd.ms-appx --cache-control "public, max-age=31536000, immutable" +aws s3 cp "dist\upload\AluxLabsLink.appinstaller" "s3://$b/AluxLabsLink.appinstaller" --content-type application/appinstaller --cache-control "public, max-age=300" +aws cloudfront create-invalidation --distribution-id E3HEXR4KAZLITV --paths "/AluxLabsLink.appinstaller" "/AluxLabs-Link-$v.msixbundle" +``` + +검증 (HTTP HEAD로 Content-Type 확인): +```powershell +Invoke-WebRequest -Method Head "https://scratch-link.aluxcoding.com/AluxLabsLink.appinstaller" -UseBasicParsing | % { $_.Headers['Content-Type'] } +``` ## 5. 신규 버전 릴리스 체크리스트 (토큰 수동) 1. [ ] 토큰 연결 + SafeNet 클라이언트 실행 확인 -2. [ ] Release 구성으로 `.msixbundle` 빌드 -3. [ ] `signtool`로 서명 (1절) — Publisher 일치(2절) +2. [ ] Release 구성으로 `.msixbundle` 빌드 (self-contained x86|x64) +3. [ ] `signtool`로 서명 — **`/sha1 <썸프린트>` 권장** (`/n` 이름 매칭은 간헐 실패) 4. [ ] `signtool verify /pa`로 서명 검증 -5. [ ] `.appinstaller`의 **버전 3곳 + 번들 파일명** 갱신 (위 규칙) -6. [ ] `scratch-assets/link/`에 `.appinstaller` + 서명된 번들 업로드 (`--content-type` 지정) -7. [ ] 기존 설치본에서 자동 업데이트 동작 확인 +5. [ ] 번들을 `dist/upload/AluxLabs-Link-<버전>.msixbundle`로 복사 +6. [ ] `.appinstaller`의 **버전 3곳 + 번들 파일명** 갱신 +7. [ ] `aws s3 cp`로 업로드(`--content-type`) → CloudFront 무효화 → HTTP HEAD 검증 +8. [ ] 기존 설치본에서 자동 업데이트 동작 확인 diff --git a/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller b/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller index 9d343984..fbe0d49c 100644 --- a/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller +++ b/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller @@ -1,14 +1,14 @@ + Uri="https://scratch-link.aluxcoding.com/AluxLabs-Link-1.0.0.1028.msixbundle" /> diff --git a/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller b/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller index 90850a9f..6098071f 100644 --- a/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller +++ b/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller @@ -1,14 +1,14 @@ + Uri="https://dev-scratch-link.aluxcoding.com/AluxLabsLink.appinstaller" + Version="1.0.0.1028"> + Version="1.0.0.1028" + Uri="https://dev-scratch-link.aluxcoding.com/AluxLabs-Link-1.0.0.1028.msixbundle" /> From b85aa5f3563d30f574959f2ea8e419f2a63c2a91 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 Jun 2026 17:26:15 +0900 Subject: [PATCH 88/94] =?UTF-8?q?chore(msix):=20make=20sync-s3=20=ED=83=80?= =?UTF-8?q?=EA=B2=9F=EC=9D=84=20=EC=98=AC=EB=B0=94=EB=A5=B8=20MIME=20+=20C?= =?UTF-8?q?loudFront=20=EB=AC=B4=ED=9A=A8=ED=99=94=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aws s3 sync는 Content-Type을 지정하지 못해 .appinstaller/.msixbundle에 binary/octet-stream이 붙어 설치가 깨졌다. 파일별 aws s3 cp(--content-type) + cloudfront create-invalidation로 교체. 번들 파일명은 dist/upload/에서 와일드카드로 자동 인식, 스테이징 비었으면 에러로 조기 중단. dev 타겟은 dev 도메인용 .appinstaller(dist/AluxLabsLink.dev.appinstaller)를 사용. Co-Authored-By: Claude Opus 4.8 (1M context) --- Makefile | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b331c94d..b40d558f 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,24 @@ WINDOWS_IMAGES = \ aluxlabs-link-win-msix/Images/StoreLogo.png \ aluxlabs-link-win-msix/Images/Wide310x150Logo.scale-200.png -.PHONY: all clean mac windows +.PHONY: all clean mac windows sync-s3 sync-s3-dev + +# S3 배포: dist/upload/의 서명된 번들 + .appinstaller를 scratch-link 버킷에 업로드. +# 운영: make sync-s3 → https://scratch-link.aluxcoding.com/ +# 개발: make sync-s3-dev → https://dev-scratch-link.aluxcoding.com/ +# 파일별 Content-Type 지정 + CloudFront 무효화까지 수행. (aws s3 sync는 MIME가 깨져 금지) +# aws.exe를 PATH에서 못 찾으면 기본 설치 경로(8.3 단축명, 공백 회피)로 폴백. +AWS ?= $(if $(wildcard C:/PROGRA~1/Amazon/AWSCLIV2/aws.exe),C:/PROGRA~1/Amazon/AWSCLIV2/aws.exe,aws) +S3_SRC ?= aluxlabs-link-win-msix/dist/upload/ +S3_BUNDLE ?= $(notdir $(wildcard $(S3_SRC)*.msixbundle)) +APPINSTALLER_DEV ?= aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller +S3_BUCKET ?= scratch-link.aluxcoding.com +S3_BUCKET_DEV ?= dev-scratch-link.aluxcoding.com +CF_DIST_ID ?= E3HEXR4KAZLITV +CF_DIST_ID_DEV ?= E1WMSQXPP9L5YF +CT_APPINSTALLER ?= application/appinstaller +CT_MSIXBUNDLE ?= application/vnd.ms-appx +AWS_REGION ?= ap-northeast-2 all: mac windows @@ -66,6 +83,18 @@ mac: $(MAC_IMAGES) windows: $(WINDOWS_IMAGES) +sync-s3: + $(if $(strip $(S3_BUNDLE)),,$(error $(S3_SRC) 에 *.msixbundle 없음 — 빌드/서명/스테이징 먼저)) + "$(AWS)" s3 cp "$(S3_SRC)$(S3_BUNDLE)" "s3://$(S3_BUCKET)/$(S3_BUNDLE)" --content-type $(CT_MSIXBUNDLE) --cache-control "public, max-age=31536000, immutable" --region $(AWS_REGION) + "$(AWS)" s3 cp "$(S3_SRC)AluxLabsLink.appinstaller" "s3://$(S3_BUCKET)/AluxLabsLink.appinstaller" --content-type $(CT_APPINSTALLER) --cache-control "public, max-age=300" --region $(AWS_REGION) + "$(AWS)" cloudfront create-invalidation --distribution-id $(CF_DIST_ID) --paths "/AluxLabsLink.appinstaller" "/$(S3_BUNDLE)" + +sync-s3-dev: + $(if $(strip $(S3_BUNDLE)),,$(error $(S3_SRC) 에 *.msixbundle 없음 — 빌드/서명/스테이징 먼저)) + "$(AWS)" s3 cp "$(S3_SRC)$(S3_BUNDLE)" "s3://$(S3_BUCKET_DEV)/$(S3_BUNDLE)" --content-type $(CT_MSIXBUNDLE) --cache-control "public, max-age=31536000, immutable" --region $(AWS_REGION) + "$(AWS)" s3 cp "$(APPINSTALLER_DEV)" "s3://$(S3_BUCKET_DEV)/AluxLabsLink.appinstaller" --content-type $(CT_APPINSTALLER) --cache-control "public, max-age=300" --region $(AWS_REGION) + "$(AWS)" cloudfront create-invalidation --distribution-id $(CF_DIST_ID_DEV) --paths "/AluxLabsLink.appinstaller" "/$(S3_BUNDLE)" + # Assumes the input SVG is square and that pixel [0,0] is a good background color # Pads the output horizontally, using the background color, to match the requested size # Usage: $(eval $(call svg2png,outpath/outfile.png,Assets/infile.svg,width,height,dpi)) From 088e72a2a66069e2d7c0b5985cceaeedb1f81e36 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 Jun 2026 18:07:16 +0900 Subject: [PATCH 89/94] =?UTF-8?q?fix(msix):=20make=20sync-s3=EC=9D=98=20Cl?= =?UTF-8?q?oudFront=20=EB=AC=B4=ED=9A=A8=ED=99=94=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EA=B9=A8=EC=A7=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-bash/MSYS sh가 무효화 경로 인자(/AluxLabsLink.appinstaller)를 Windows 경로로 변환해 "invalid invalidation paths"로 실패했다. export MSYS_NO_PATHCONV := 1 로 변환을 비활성화. (업로드 경로는 앞 / 가 없어 영향 없었고 무효화만 실패했음) Co-Authored-By: Claude Opus 4.8 (1M context) --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index b40d558f..2fef982d 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,8 @@ WINDOWS_IMAGES = \ # 개발: make sync-s3-dev → https://dev-scratch-link.aluxcoding.com/ # 파일별 Content-Type 지정 + CloudFront 무효화까지 수행. (aws s3 sync는 MIME가 깨져 금지) # aws.exe를 PATH에서 못 찾으면 기본 설치 경로(8.3 단축명, 공백 회피)로 폴백. +# git-bash/MSYS sh가 CloudFront 경로 인자(/foo)를 Windows 경로로 변환하는 것을 방지 (무효화 실패 원인). +export MSYS_NO_PATHCONV := 1 AWS ?= $(if $(wildcard C:/PROGRA~1/Amazon/AWSCLIV2/aws.exe),C:/PROGRA~1/Amazon/AWSCLIV2/aws.exe,aws) S3_SRC ?= aluxlabs-link-win-msix/dist/upload/ S3_BUNDLE ?= $(notdir $(wildcard $(S3_SRC)*.msixbundle)) From 7b8de4aaf7f19b70f4f49b8f02ffb4c6ccefd8d8 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 Jun 2026 18:28:18 +0900 Subject: [PATCH 90/94] =?UTF-8?q?chore(msix):=20.appinstaller=20=EB=B2=84?= =?UTF-8?q?=EC=A0=84=EC=9D=84=201.0.1.1031=EB=A1=9C=20=EA=B0=B1=EC=8B=A0?= =?UTF-8?q?=20(=EC=9E=90=EB=8F=99=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= =?UTF-8?q?=20=EA=B2=80=EC=A6=9D=20=EB=B0=B0=ED=8F=AC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit prod/dev .appinstaller를 실제 배포한 1.0.1.1031에 맞춤. 자동 업데이트 동작 검증을 위한 버전 상향 분. Co-Authored-By: Claude Opus 4.8 (1M context) --- aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller | 6 +++--- aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller b/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller index fbe0d49c..2b664f3a 100644 --- a/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller +++ b/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller @@ -2,13 +2,13 @@ + Version="1.0.1.1031"> + Version="1.0.1.1031" + Uri="https://scratch-link.aluxcoding.com/AluxLabs-Link-1.0.1.1031.msixbundle" /> diff --git a/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller b/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller index 6098071f..867e67d1 100644 --- a/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller +++ b/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller @@ -2,13 +2,13 @@ + Version="1.0.1.1031"> + Version="1.0.1.1031" + Uri="https://dev-scratch-link.aluxcoding.com/AluxLabs-Link-1.0.1.1031.msixbundle" /> From f1a45056fedab2c8664edb160d4877696c6479bb Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 Jun 2026 13:56:45 +0900 Subject: [PATCH 91/94] =?UTF-8?q?feat(win):=20=EB=B8=8C=EB=9D=BC=EC=9A=B0?= =?UTF-8?q?=EC=A0=80=20=EB=94=A5=EB=A7=81=ED=81=AC=20=EC=8B=A4=ED=96=89?= =?UTF-8?q?=EC=9A=A9=20=EC=BB=A4=EC=8A=A4=ED=85=80=20URL=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=86=A0=EC=BD=9C=20+=20=EB=8B=A8=EC=9D=BC=20?= =?UTF-8?q?=EC=9D=B8=EC=8A=A4=ED=84=B4=EC=8A=A4=20=EB=B3=B4=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 웹(scratch-gui)에서 버튼 클릭으로 Link를 실행할 수 있도록 aluxlabs-link:// 커스텀 URL 프로토콜을 등록한다. - Package.appxmanifest: windows.protocol 확장으로 aluxlabs-link 스킴 등록 - Program.cs: 자동 생성 Main 대신 커스텀 진입점에서 Application.Start 이전에 단일 인스턴스를 판정 — 비메인은 활성화를 메인으로 리다이렉트 후 종료하여 트레이/:20211 중복 기동을 차단 - csproj: DISABLE_XAML_GENERATED_MAIN 컴파일 상수로 XAML 생성 Main 억제 Co-Authored-By: Claude Opus 4.8 --- aluxlabs-link-win-msix/Package.appxmanifest | 8 +++++ aluxlabs-link-win/Program.cs | 38 +++++++++++++++++++++ aluxlabs-link-win/aluxlabs-link-win.csproj | 4 +++ 3 files changed, 50 insertions(+) create mode 100644 aluxlabs-link-win/Program.cs diff --git a/aluxlabs-link-win-msix/Package.appxmanifest b/aluxlabs-link-win-msix/Package.appxmanifest index 1d9f45d6..f33193e1 100644 --- a/aluxlabs-link-win-msix/Package.appxmanifest +++ b/aluxlabs-link-win-msix/Package.appxmanifest @@ -39,6 +39,14 @@ + + + + + AluxLabs Link + + + diff --git a/aluxlabs-link-win/Program.cs b/aluxlabs-link-win/Program.cs new file mode 100644 index 00000000..f65ae56a --- /dev/null +++ b/aluxlabs-link-win/Program.cs @@ -0,0 +1,38 @@ +// +// Copyright (c) Scratch Foundation. All rights reserved. +// + +namespace AluxLabs.Link.Win; + +using Microsoft.UI.Dispatching; +using Microsoft.UI.Xaml; +using Microsoft.Windows.AppLifecycle; +using WinRT; + +/// +/// Custom entry point that enforces single-instance activation before the XAML runtime starts. +/// +public static class Program +{ + [STAThread] + private static void Main() + { + var keyInstance = AppInstance.FindOrRegisterForKey("aluxlabs-link-main"); + + // Exit before the tray icon or :20211 listener start so a second launch can't duplicate them. + if (!keyInstance.IsCurrent) + { + var activatedArgs = AppInstance.GetCurrent().GetActivatedEventArgs(); + keyInstance.RedirectActivationToAsync(activatedArgs).AsTask().Wait(); + return; + } + + ComWrappersSupport.InitializeComWrappers(); + Application.Start(p => + { + var context = new DispatcherQueueSynchronizationContext(DispatcherQueue.GetForCurrentThread()); + SynchronizationContext.SetSynchronizationContext(context); + _ = new App(); + }); + } +} diff --git a/aluxlabs-link-win/aluxlabs-link-win.csproj b/aluxlabs-link-win/aluxlabs-link-win.csproj index 287358ee..04439db7 100644 --- a/aluxlabs-link-win/aluxlabs-link-win.csproj +++ b/aluxlabs-link-win/aluxlabs-link-win.csproj @@ -10,6 +10,10 @@ $(Company) disable true + + $(DefineConstants);DISABLE_XAML_GENERATED_MAIN None From 934d4e26d4301b12606f466fa7651e42d4c7a95f Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 Jun 2026 13:57:32 +0900 Subject: [PATCH 92/94] =?UTF-8?q?chore(msix):=20=EB=B2=84=EC=A0=84=20?= =?UTF-8?q?=EB=8B=A8=EC=9D=BC=20=EC=86=8C=EC=8A=A4=ED=99=94=20+=20.appinst?= =?UTF-8?q?aller=20=EC=9E=90=EB=8F=99=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 버전 triplet을 한 곳(Version.props)으로 모으고, 손으로 관리하던 .appinstaller를 빌드 산출물(번들 파일명)에서 자동 생성하도록 한다. - Version.props(신규): ReleaseTriplet 단일 소스. ScratchVersion.targets가 git floor 대신 이 값을 우선 사용 → assembly/manifest/번들명 자동 일치 - AluxLabsLink.appinstaller.template(신규): 호스트/버전/번들 placeholder로 prod/dev 두 개를 생성 - Makefile: show-version/set-version/release-patch·minor + appinstaller 타겟, sync-s3(-dev)이 staging 번들 기준으로 appinstaller 자동 생성·업로드 - 손으로 관리하던 dist/*.appinstaller 제거(템플릿 생성으로 대체) - ReleaseTriplet 1.0.1 → 1.1.0 (딥링크: 하위호환 새 기능, minor) Co-Authored-By: Claude Opus 4.8 --- Makefile | 43 +++++++++++++++++-- SharedProps/ScratchVersion.targets | 3 ++ SharedProps/Version.props | 11 +++++ ...ler => AluxLabsLink.appinstaller.template} | 8 ++-- .../dist/AluxLabsLink.dev.appinstaller | 18 -------- 5 files changed, 57 insertions(+), 26 deletions(-) create mode 100644 SharedProps/Version.props rename aluxlabs-link-win-msix/{dist/AluxLabsLink.appinstaller => AluxLabsLink.appinstaller.template} (64%) delete mode 100644 aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller diff --git a/Makefile b/Makefile index 2fef982d..1926f2c9 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ WINDOWS_IMAGES = \ aluxlabs-link-win-msix/Images/StoreLogo.png \ aluxlabs-link-win-msix/Images/Wide310x150Logo.scale-200.png -.PHONY: all clean mac windows sync-s3 sync-s3-dev +.PHONY: all clean mac windows sync-s3 sync-s3-dev appinstaller show-version set-version release-patch release-minor # S3 배포: dist/upload/의 서명된 번들 + .appinstaller를 scratch-link 버킷에 업로드. # 운영: make sync-s3 → https://scratch-link.aluxcoding.com/ @@ -67,7 +67,7 @@ export MSYS_NO_PATHCONV := 1 AWS ?= $(if $(wildcard C:/PROGRA~1/Amazon/AWSCLIV2/aws.exe),C:/PROGRA~1/Amazon/AWSCLIV2/aws.exe,aws) S3_SRC ?= aluxlabs-link-win-msix/dist/upload/ S3_BUNDLE ?= $(notdir $(wildcard $(S3_SRC)*.msixbundle)) -APPINSTALLER_DEV ?= aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller +APPINSTALLER_DEV ?= aluxlabs-link-win-msix/dist/upload/AluxLabsLink.dev.appinstaller S3_BUCKET ?= scratch-link.aluxcoding.com S3_BUCKET_DEV ?= dev-scratch-link.aluxcoding.com CF_DIST_ID ?= E3HEXR4KAZLITV @@ -76,6 +76,18 @@ CT_APPINSTALLER ?= application/appinstaller CT_MSIXBUNDLE ?= application/vnd.ms-appx AWS_REGION ?= ap-northeast-2 +# --- 버전 관리 + .appinstaller 생성 (Windows 전용) --- +# 단일 소스: SharedProps/Version.props 의 (= Major.Minor.Patch). 4번째 Build 는 커밋 수 자동. +# .appinstaller 는 staging 된 번들 파일명에서 버전을 그대로 읽어 생성 → 번들과 절대 어긋나지 않음. +VERSION_PROPS ?= SharedProps/Version.props +APPINSTALLER_TEMPLATE ?= aluxlabs-link-win-msix/AluxLabsLink.appinstaller.template +APPINSTALLER ?= aluxlabs-link-win-msix/dist/upload/AluxLabsLink.appinstaller +APPINSTALLER_HOST ?= scratch-link.aluxcoding.com +APPINSTALLER_HOST_DEV ?= dev-scratch-link.aluxcoding.com +RELEASE_TRIPLET = $(shell awk -F'[<>]' '/ReleaseTriplet/{print $$3}' $(VERSION_PROPS)) +GIT_COMMITS = $(shell git rev-list --count HEAD) +BUNDLE_VERSION = $(patsubst AluxLabs-Link-%.msixbundle,%,$(S3_BUNDLE)) + all: mac windows clean: @@ -85,18 +97,41 @@ mac: $(MAC_IMAGES) windows: $(WINDOWS_IMAGES) -sync-s3: +sync-s3: appinstaller $(if $(strip $(S3_BUNDLE)),,$(error $(S3_SRC) 에 *.msixbundle 없음 — 빌드/서명/스테이징 먼저)) "$(AWS)" s3 cp "$(S3_SRC)$(S3_BUNDLE)" "s3://$(S3_BUCKET)/$(S3_BUNDLE)" --content-type $(CT_MSIXBUNDLE) --cache-control "public, max-age=31536000, immutable" --region $(AWS_REGION) "$(AWS)" s3 cp "$(S3_SRC)AluxLabsLink.appinstaller" "s3://$(S3_BUCKET)/AluxLabsLink.appinstaller" --content-type $(CT_APPINSTALLER) --cache-control "public, max-age=300" --region $(AWS_REGION) "$(AWS)" cloudfront create-invalidation --distribution-id $(CF_DIST_ID) --paths "/AluxLabsLink.appinstaller" "/$(S3_BUNDLE)" -sync-s3-dev: +sync-s3-dev: appinstaller $(if $(strip $(S3_BUNDLE)),,$(error $(S3_SRC) 에 *.msixbundle 없음 — 빌드/서명/스테이징 먼저)) "$(AWS)" s3 cp "$(S3_SRC)$(S3_BUNDLE)" "s3://$(S3_BUCKET_DEV)/$(S3_BUNDLE)" --content-type $(CT_MSIXBUNDLE) --cache-control "public, max-age=31536000, immutable" --region $(AWS_REGION) "$(AWS)" s3 cp "$(APPINSTALLER_DEV)" "s3://$(S3_BUCKET_DEV)/AluxLabsLink.appinstaller" --content-type $(CT_APPINSTALLER) --cache-control "public, max-age=300" --region $(AWS_REGION) "$(AWS)" cloudfront create-invalidation --distribution-id $(CF_DIST_ID_DEV) --paths "/AluxLabsLink.appinstaller" "/$(S3_BUNDLE)" +show-version: + @echo "triplet (Version.props): $(RELEASE_TRIPLET)" + @echo "quad (+build): $(RELEASE_TRIPLET).$(GIT_COMMITS)" + @echo "staged bundle: $(if $(strip $(S3_BUNDLE)),$(S3_BUNDLE) [$(BUNDLE_VERSION)],(none in $(S3_SRC)))" + +set-version: + @echo "$(VERSION)" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$$' || { echo "ERROR: make set-version VERSION=x.y.z (예: 1.1.0)"; exit 1; } + sed -i 's|.*|$(VERSION)|' $(VERSION_PROPS) + @echo "Version.props -> $(VERSION)" + +release-patch: + $(MAKE) set-version VERSION=$(shell echo $(RELEASE_TRIPLET) | awk -F. '{print $$1"."$$2"."$$3+1}') + +release-minor: + $(MAKE) set-version VERSION=$(shell echo $(RELEASE_TRIPLET) | awk -F. '{print $$1"."$$2+1".0"}') + +# staging 된 번들에 맞춰 prod/dev .appinstaller 두 개를 템플릿에서 생성 +appinstaller: + $(if $(strip $(S3_BUNDLE)),,$(error $(S3_SRC) 에 *.msixbundle 없음 — 빌드/서명/스테이징 먼저)) + sed -e 's|__HOST__|$(APPINSTALLER_HOST)|g' -e 's|__VERSION__|$(BUNDLE_VERSION)|g' -e 's|__BUNDLE__|$(S3_BUNDLE)|g' "$(APPINSTALLER_TEMPLATE)" > "$(APPINSTALLER)" + sed -e 's|__HOST__|$(APPINSTALLER_HOST_DEV)|g' -e 's|__VERSION__|$(BUNDLE_VERSION)|g' -e 's|__BUNDLE__|$(S3_BUNDLE)|g' "$(APPINSTALLER_TEMPLATE)" > "$(APPINSTALLER_DEV)" + @echo "appinstaller 생성: $(BUNDLE_VERSION) (prod + dev)" + # Assumes the input SVG is square and that pixel [0,0] is a good background color # Pads the output horizontally, using the background color, to match the requested size # Usage: $(eval $(call svg2png,outpath/outfile.png,Assets/infile.svg,width,height,dpi)) diff --git a/SharedProps/ScratchVersion.targets b/SharedProps/ScratchVersion.targets index 7c9ec9fb..5cbed648 100644 --- a/SharedProps/ScratchVersion.targets +++ b/SharedProps/ScratchVersion.targets @@ -3,6 +3,7 @@ This file sets up version properties in our own Scratch way. --> + 1.0.0 $(GitSemVerMajor).$(GitSemVerMinor).$(GitSemVerPatch) + + $(ReleaseTriplet) $(ScratchVersionTriplet)$(GitSemVerDashLabel) $(GitCommit) $(ScratchVersionFull)+$(ScratchVersionHash) diff --git a/SharedProps/Version.props b/SharedProps/Version.props new file mode 100644 index 00000000..b291dd5a --- /dev/null +++ b/SharedProps/Version.props @@ -0,0 +1,11 @@ + + + + + 1.1.0 + + diff --git a/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller b/aluxlabs-link-win-msix/AluxLabsLink.appinstaller.template similarity index 64% rename from aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller rename to aluxlabs-link-win-msix/AluxLabsLink.appinstaller.template index 2b664f3a..9119bcfd 100644 --- a/aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller +++ b/aluxlabs-link-win-msix/AluxLabsLink.appinstaller.template @@ -1,14 +1,14 @@ + Uri="https://__HOST__/AluxLabsLink.appinstaller" + Version="__VERSION__"> + Version="__VERSION__" + Uri="https://__HOST__/__BUNDLE__" /> diff --git a/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller b/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller deleted file mode 100644 index 867e67d1..00000000 --- a/aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - From a59c3c2e400e94c9ffbd62bcb47e896c52b3537c Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 Jun 2026 14:02:06 +0900 Subject: [PATCH 93/94] =?UTF-8?q?docs(msix):=20=EC=84=9C=EB=AA=85=C2=B7?= =?UTF-8?q?=EB=B0=B0=ED=8F=AC=20=EB=AC=B8=EC=84=9C=EB=A5=BC=20=EB=B2=84?= =?UTF-8?q?=EC=A0=84=20=EC=9E=90=EB=8F=99=ED=99=94=EC=97=90=20=EB=A7=9E?= =?UTF-8?q?=EA=B2=8C=20=EA=B0=B1=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 934d4e2(버전 단일 소스화)로 .appinstaller가 자동 생성되고 수동 정본 파일이 제거됨에 따라, 낡은 '수동 3곳 편집' 안내를 갱신한다. - §4: 커밋된 정본 → 템플릿 자동 생성으로 정정 - §4: git 태그 기반 버전 → Version.props 단일 소스(make set-version) - §5: 릴리스 체크리스트를 make 기반(set-version → 빌드/서명 → sync-s3)으로 Co-Authored-By: Claude Opus 4.8 --- .../Alux/CodeSigningAndDistribution.md | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/Documentation/Alux/CodeSigningAndDistribution.md b/Documentation/Alux/CodeSigningAndDistribution.md index f558371d..de62cd0a 100644 --- a/Documentation/Alux/CodeSigningAndDistribution.md +++ b/Documentation/Alux/CodeSigningAndDistribution.md @@ -105,26 +105,30 @@ VS GUI로 할 경우: wapproj 우클릭 → **게시(Publish) → 앱 패키지 3. 앱 실행 시(또는 백그라운드 작업) Windows가 `.appinstaller`를 다시 받아 **`Version`과 설치된 버전을 스스로 비교**한다. 4. 더 높으면 새 번들을 받아 적용한다. -### `.appinstaller` 파일 (확정·커밋됨) +### `.appinstaller` 파일 (템플릿에서 자동 생성) -수동 운영이므로 MSBuild 자동 생성 대신 파일을 직접 관리한다. 저장소에 둔 정본: +`make`가 staging 된 번들 파일명에서 버전을 읽어 prod/dev 두 파일을 생성한다(수동 편집 없음). 정본은 템플릿이다: -- prod: [`dist/AluxLabsLink.appinstaller`](../../aluxlabs-link-win-msix/dist/AluxLabsLink.appinstaller) → `scratch-link.aluxcoding.com/` (루트) -- dev: [`dist/AluxLabsLink.dev.appinstaller`](../../aluxlabs-link-win-msix/dist/AluxLabsLink.dev.appinstaller) → `dev-scratch-link.aluxcoding.com/` (루트) +- 템플릿: [`AluxLabsLink.appinstaller.template`](../../aluxlabs-link-win-msix/AluxLabsLink.appinstaller.template) — 호스트/버전/번들 placeholder +- 생성물(gitignore): `dist/upload/AluxLabsLink.appinstaller` (prod) / `dist/upload/AluxLabsLink.dev.appinstaller` (dev) +- 생성: `make appinstaller` (또는 `make sync-s3`/`sync-s3-dev` 가 업로드 직전 자동 생성) 스키마는 `2017/2` (Windows 1809+ 호환 — 매니페스트 MinVersion과 동일). `Publisher`는 인증서 Subject와 일치. -### ⚠️ 릴리스마다 고칠 곳 — 버전 3곳 +### 버전 — 한 곳만 (Version.props) -`.appinstaller`의 버전이 **실제 빌드된 번들 버전과 정확히 일치**해야 Windows가 비교한다. 새 릴리스마다 다음 3곳을 그 버전으로 바꾼다: +`.appinstaller`의 버전·번들 파일명은 **빌드된 번들과 자동으로 일치**한다 — `make`가 staging 된 번들명(`AluxLabs-Link-<버전>.msixbundle`)에서 버전을 그대로 주입하기 때문. 손으로 맞출 곳은 없다. -1. `` — 루트 -2. `` — 번들 -3. `` — 파일명 +릴리스 버전(Major.Minor.Patch)은 **`SharedProps/Version.props` 한 곳**이 단일 소스다(`ScratchVersion.targets`가 읽어 assembly·매니페스트·번들명에 전파). 4번째 Build 자리는 커밋 수로 자동. -> **``의 `Uri`(고정 URL)는 절대 변경 금지** — 설치된 클라이언트가 기억하는 진입점이다. 바꾸는 건 버전과 번들 파일명뿐. +```powershell +make set-version VERSION=1.2.0 # 또는 make release-patch / release-minor +make show-version # 산출될 quad 확인 +``` + +> **``의 `Uri`(고정 URL)는 불변** — 설치된 클라이언트가 기억하는 진입점이다. 템플릿에 고정돼 있고, 버전·번들명만 주입된다. -버전은 git 태그 기반으로 산출된다(`ScratchVersion.targets`): 태그 없으면 `1.0.0.<커밋수>`, 정식 릴리스는 `git tag v1.2.0` → `1.2.0.x`. 빌드된 번들의 실제 버전·Publisher 확인: +빌드된 번들의 실제 버전·Publisher 확인: ```powershell Get-AppLockerFileInformation -Path .\AluxLabs-Link-x.y.z.msixbundle | Select-Object -ExpandProperty Publisher @@ -166,11 +170,11 @@ Invoke-WebRequest -Method Head "https://scratch-link.aluxcoding.com/AluxLabsLink ## 5. 신규 버전 릴리스 체크리스트 (토큰 수동) -1. [ ] 토큰 연결 + SafeNet 클라이언트 실행 확인 -2. [ ] Release 구성으로 `.msixbundle` 빌드 (self-contained x86|x64) -3. [ ] `signtool`로 서명 — **`/sha1 <썸프린트>` 권장** (`/n` 이름 매칭은 간헐 실패) -4. [ ] `signtool verify /pa`로 서명 검증 -5. [ ] 번들을 `dist/upload/AluxLabs-Link-<버전>.msixbundle`로 복사 -6. [ ] `.appinstaller`의 **버전 3곳 + 번들 파일명** 갱신 -7. [ ] `aws s3 cp`로 업로드(`--content-type`) → CloudFront 무효화 → HTTP HEAD 검증 -8. [ ] 기존 설치본에서 자동 업데이트 동작 확인 +1. [ ] `make set-version VERSION=x.y.z` (또는 release-patch/minor) — 버전 단일 소스 갱신 +2. [ ] 토큰 연결 + SafeNet 클라이언트 실행 확인 +3. [ ] Release 구성으로 `.msixbundle` 빌드 (self-contained x86|x64) → `AluxLabs-Link-x.y.z.<커밋수>.msixbundle` +4. [ ] `signtool`로 서명 — **`/sha1 <썸프린트>` 권장** (`/n` 이름 매칭은 간헐 실패) +5. [ ] `signtool verify /pa`로 서명 검증 +6. [ ] 서명된 번들을 `dist/upload/`로 복사 +7. [ ] `make sync-s3` (dev면 `sync-s3-dev`) — appinstaller 자동 생성 + 업로드 + CloudFront 무효화 +8. [ ] HTTP HEAD로 Content-Type 검증 + 기존 설치본 자동 업데이트 확인 From 2b482926537cc05607ed69c74363872bb1adcfd2 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 Jun 2026 16:21:00 +0900 Subject: [PATCH 94/94] =?UTF-8?q?fix(serial):=20keep-alive=EB=A5=BC=20?= =?UTF-8?q?=EA=B3=A0=EC=A0=95=20300ms=20=EC=9C=A0=ED=9C=B4=20=EA=B8=89?= =?UTF-8?q?=EC=97=AC=20=EC=A3=BC=EA=B8=B0=EB=A1=9C=20=EB=8B=A8=EC=88=9C?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 저사양 PC에서 클라이언트가 33ms write 주기를 못 지켜 1초 이상 TX가 끊기면 장치 RX 워치독(~1s)이 만료돼 경고음이 자주 울리던 문제 수정. 기존 RX 기반 가드 3종(RxYield 200 / TxIdle 900 / RxStall 500)은 워치독 대비 마진이 100ms뿐이고, RxStall 가드에 하드 데드라인이 없어 장치가 조용해지면 keep-alive가 무한 정지했다. 이를 단일 KeepAliveFeedIntervalMs(300ms) 바닥값으로 교체해, 마지막 TX(클라 write 또는 직전 resend) 이후 300ms가 지나면 RX 상태와 무관하게 재전송한다. 실효 워치독 ~900ms에 3배 여유라 저사양에서 틱이 늦어도 다음 발이 시간 안에 도착한다. - keepAliveIntervalMs의 의미: 재전송 주기 → 폴링 간격으로 변경 - 타임스탬프 게이트로 대체된 ResetKeepAliveTimer / keepAliveIntervalMs 필드 및 미사용 lastRxTicks 추적 제거 - 모든 keep-alive 장치에 일괄 적용 (codetinker 전용 아님) - 관련 문서(SerialKeepAliveGuide, SerialApiReference) 동작 설명 갱신 Co-Authored-By: Claude Opus 4.8 (1M context) --- Documentation/Alux/SerialApiReference.md | 8 +-- Documentation/Alux/SerialKeepAliveGuide.md | 57 ++++++++--------- aluxlabs-link-common/Serial/SerialSession.cs | 67 +++----------------- 3 files changed, 41 insertions(+), 91 deletions(-) diff --git a/Documentation/Alux/SerialApiReference.md b/Documentation/Alux/SerialApiReference.md index 283755e5..952e1e62 100644 --- a/Documentation/Alux/SerialApiReference.md +++ b/Documentation/Alux/SerialApiReference.md @@ -144,7 +144,7 @@ Opens a serial port connection. - `stopBits` (string, optional) — "one" | "onePointFive" | "two" (default: "one") - `flowControl` (string, optional) — "none" | "rtsCts" | "xonXoff" (default: "none") - `peripheralType` (string, optional) — Device type identifier ("codetinker", "connect", "technic", etc.) -- `keepAliveIntervalMs` (int, optional) — Keep-alive interval in ms. Omit or null to disable. **Recommended: 33ms for Codetinker** +- `keepAliveIntervalMs` (int, optional) — Enables keep-alive and sets the **poll granularity** in ms (how often Link checks for an idle link). Omit or null to disable. **Recommended: 33ms for Codetinker.** The actual resend cadence is a fixed internal ~300ms idle interval, sized under the device's ~1s RX watchdog; a small poll value just hits that deadline more precisely. - `wireTrace` (bool, optional) — Diagnostic. When `true`, Link emits per-write/per-read hex dumps via `Trace.WriteLine` (visible in DebugView or attached debugger). Off by default. Use only for transport-level debugging; the dumps include payload bytes and can be verbose. **Response:** @@ -447,7 +447,7 @@ This is a deliberate design choice for v1: keep Link's transport thin and predic } } // → result: {} -// → Keep-alive timer starts, will resend last TX packet every 33ms if idle +// → Keep-alive starts; polls every 33ms and resends the last TX packet after ~300ms of TX-idle // 3. Send command { @@ -460,7 +460,7 @@ This is a deliberate design choice for v1: keep Link's transport thin and predic } } // → result: { sentBytes: 4 } -// → Keep-alive timer resets (cached packet = AQIDBA==) +// → Keep-alive idle budget reset (cached packet = AQIDBA==) // 4. Receive response // ← serialDidReceiveData: { message: "BwgJCg==", encoding: "base64" } @@ -514,7 +514,7 @@ The human-readable detail is in `error.data`; `error.message` is the category st Two layers of protection: -1. **Automatic (no client change needed).** Each `write` resets the keep-alive interval, so a burst of writes (DFU chunks) suppresses the resend until the line goes idle again. +1. **Automatic (no client change needed).** Each `write` refreshes the last-TX timestamp, so a burst of writes (DFU chunks) keeps the link below the ~300ms idle threshold and suppresses the resend until the line goes idle again. 2. **Explicit (recommended for wireless DFU).** Before bootloader entry, call `setKeepAlive` with `intervalMs: null` to disable keep-alive entirely. Re-enable after DFU completes. This eliminates any chance of a resend racing with a bootloader handshake on a slow wireless link. ```javascript diff --git a/Documentation/Alux/SerialKeepAliveGuide.md b/Documentation/Alux/SerialKeepAliveGuide.md index 943b6571..6d85c277 100644 --- a/Documentation/Alux/SerialKeepAliveGuide.md +++ b/Documentation/Alux/SerialKeepAliveGuide.md @@ -13,13 +13,13 @@ Some hardware devices (e.g., Codetinker with CH340 USB-to-serial) require contin ## Solution -The keep-alive mechanism automatically resends the **last transmitted (TX) packet** at a configurable interval. This keeps the device "alive" without interfering with actual communication. +The keep-alive mechanism automatically resends the **last transmitted (TX) packet** whenever the link has been TX-idle for a fixed internal feed interval (~300ms), sized well under the device's ~1s RX watchdog. This keeps the device "alive" without interfering with actual communication. ### Key Features -✅ **Automatic resend** — Last sent packet is cached and resent periodically -✅ **No interference with active communication** — Timer resets on every write, so frequent communication automatically pauses keep-alive -✅ **Firmware update safe** — During firmware updates (DFU), frequent writes prevent keep-alive from firing +✅ **Automatic resend** — Last sent packet is cached and resent after the link goes TX-idle +✅ **No interference with active communication** — Every client write (and every resend) restarts the idle budget, so frequent communication keeps keep-alive silent +✅ **Firmware update safe** — During firmware updates (DFU), frequent writes keep the link below the idle threshold so keep-alive never fires ✅ **Optional and configurable** — Can be enabled/disabled per connection ## Usage @@ -42,7 +42,7 @@ When connecting to a serial device, include the `keepAliveIntervalMs` parameter: |-----------|------|----------|-------------| | `baudRate` | int | Yes | Baud rate (e.g., 115200) | | `peripheralType` | string | No | Device type identifier (e.g., "codetinker", "connect", "technic") | -| `keepAliveIntervalMs` | int \| null | No | Keep-alive interval in milliseconds. `null` or omitted = disabled. Set to 33ms for Codetinker. | +| `keepAliveIntervalMs` | int \| null | No | Enables keep-alive and sets the **poll granularity** in ms — how often Link checks whether the link went idle. `null`/omitted = disabled. Use 33ms for Codetinker. The actual resend cadence is a fixed internal ~300ms idle interval; a small poll value just hits that deadline more precisely. | ### Examples @@ -73,46 +73,45 @@ When connecting to a serial device, include the `keepAliveIntervalMs` parameter: ## How It Works -### 1. Keep-Alive Enabled +### 1. Keep-Alive Enabled (poll = 33ms, feed interval = 300ms) ``` -Time: 0ms → Client sends packet A -Time: 33ms → (no activity) Keep-alive resends packet A -Time: 66ms → (no activity) Keep-alive resends packet A -Time: 150ms → Client sends packet B → Timer resets -Time: 183ms → (no activity) Keep-alive resends packet B +Time: 0ms → Client sends packet A → idle budget reset +Time: 33–270ms → (polls fire, but <300ms idle) → no resend +Time: ~300ms → 300ms idle reached → Keep-alive resends packet A → budget reset +Time: ~600ms → still idle → Keep-alive resends packet A again +Time: 720ms → Client sends packet B → idle budget reset +Time: ~1020ms → still idle → Keep-alive resends packet B ... ``` ### 2. During Firmware Update (DFU) ``` -Time: 0ms → DFU write #1 → Timer resets -Time: 10ms → DFU write #2 → Timer resets -Time: 20ms → DFU write #3 → Timer resets +Time: 0ms → DFU write #1 → idle budget reset +Time: 10ms → DFU write #2 → idle budget reset +Time: 20ms → DFU write #3 → idle budget reset ... -Result: Keep-alive never fires because writes are too frequent +Result: Keep-alive never fires because the link never stays idle for 300ms ``` ## Technical Details -### Timer Reset Behavior +### Idle-Budget Behavior -The keep-alive timer **resets** whenever: -- A write request is issued (`write` JSON-RPC method) -- A packet is successfully sent +Link tracks the timestamp of the last TX — either a client `write` or a previous keep-alive resend. On each timer poll it resends only if that timestamp is older than the internal feed interval (~300ms). This means: -- **Idle state** — Keep-alive kicks in after `keepAliveIntervalMs` milliseconds of inactivity -- **Active state** — During firmware updates or frequent communication, keep-alive is effectively paused +- **Idle state** — Keep-alive resends ~300ms after the last TX, then every ~300ms while idle +- **Active state** — During firmware updates or frequent communication, writes keep the last-TX timestamp fresh, so keep-alive is effectively paused - **No explicit disable needed** — The mechanism self-manages based on activity +- **Resends count as TX** — A forced resend refreshes the same budget, so one resend doesn't unlock the raw poll cadence; feeds stay ~300ms apart ### Architecture ``` SerialSession (abstract) -├── StartKeepAlive(interval) → Start timer with interval +├── StartKeepAlive(interval) → Start poll timer at the client interval ├── StopKeepAlive() → Stop and dispose timer -├── ResetKeepAliveTimer() → Restart timer (called on write) -└── ResendLastData() → Resend cached packet (called by timer) +└── OnKeepAliveTick() → On each poll, resend cached packet if TX-idle ≥ feed interval Platform-specific implementation (WinSerialSession, etc.) ├── StartKeepAlive() in DoConnect() @@ -126,9 +125,9 @@ Platform-specific implementation (WinSerialSession, etc.) A: There are two layers of protection. **Layer 1 — Automatic (no client change needed).** During an active DFU burst: -1. Each `write` request resets the keep-alive timer. -2. DFU chunks arrive faster than the keep-alive interval, so the timer never expires. -3. The first write after the burst is the only one that re-arms keep-alive. +1. Each `write` request refreshes the last-TX timestamp. +2. DFU chunks arrive faster than the ~300ms feed interval, so the idle budget never expires. +3. Keep-alive only re-arms once the burst stops and the link sits idle for the feed interval. **Layer 2 — Explicit toggle (recommended for wireless DFU).** For setups where the bootloader handshake travels over a slow wireless link (e.g. USB dongle → wireless → CPU), there is a brief idle window between "wake bootloader" and the first DFU command where keep-alive *could* fire. Eliminate it by calling `setKeepAlive` to disable keep-alive before bootloader entry and re-enable it after DFU completes: @@ -191,6 +190,6 @@ For issues or questions about keep-alive functionality: --- -**Version**: 1.0 -**Last Updated**: 2026-05-24 +**Version**: 1.1 +**Last Updated**: 2026-06-11 **Affected Devices**: Codetinker, and any device with sub-second timeout requirements diff --git a/aluxlabs-link-common/Serial/SerialSession.cs b/aluxlabs-link-common/Serial/SerialSession.cs index 68280b46..e29c9e6a 100644 --- a/aluxlabs-link-common/Serial/SerialSession.cs +++ b/aluxlabs-link-common/Serial/SerialSession.cs @@ -26,15 +26,9 @@ namespace AluxLabs.Link.Serial; internal abstract class SerialSession : PeripheralSession where TPort : class { - // Yield keep-alive while RX is active so the peripheral can finish unsolicited notifications (e.g. BLE link-loss). - private const int KeepAliveRxYieldMs = 200; - - // Force keep-alive once the client has been idle this long, even if RX is still flowing, to stay under the device's 1 s RX timeout. - private const int KeepAliveTxIdleMs = 900; - - // Pause keep-alive once RX has stalled this long. Dongles defer BLE link-loss notifications while servicing PC commands; - // pausing gives the dongle the idle window it needs to push the notification. - private const int KeepAliveRxStallMs = 500; + // Resend the last TX packet at most once per this interval while the client is idle. Sized well under the + // device's ~1 s RX watchdog (minus TX/RX transmission time) so a late tick on a slow PC still lands in time. + private const int KeepAliveFeedIntervalMs = 300; // Serializes DoWrite calls so two writes never overlap and corrupt the stream. private readonly SemaphoreSlim writeSemaphore = new SemaphoreSlim(1, 1); @@ -44,11 +38,9 @@ internal abstract class SerialSession : PeripheralSession private byte[] lastSentData; private Timer keepAliveTimer; - private int keepAliveIntervalMs; private bool keepAliveActive; // 64-bit timestamps in DateTime.UtcNow.Ticks; accessed via Interlocked to keep reads/writes atomic on 32-bit runtimes. - private long lastRxTicks; private long lastClientTxTicks; private long lastKeepAliveSentTicks; @@ -169,7 +161,7 @@ protected override Task DoConnect(TPort port, JsonElement? args) /// /// JSON-RPC write handler. Caches the payload as the most recent TX packet - /// and resets the keep-alive timer so resends are suppressed during active bursts. + /// and stamps the client-TX time so keep-alive resends stay suppressed during active bursts. /// /// Dispatched method name. /// Decoded request params. @@ -193,7 +185,6 @@ protected async Task HandleWrite(string methodName, JsonElement? args) } Interlocked.Exchange(ref this.lastClientTxTicks, DateTime.UtcNow.Ticks); - this.ResetKeepAliveTimer(); if (this.wireTrace) { @@ -336,8 +327,6 @@ protected async Task HandleTriggerDTRReset(string methodName, JsonElemen /// A representing the asynchronous operation. protected async Task DidReceiveData(byte[] data) { - Interlocked.Exchange(ref this.lastRxTicks, DateTime.UtcNow.Ticks); - if (this.wireTrace) { Trace.WriteLine($"wire-trace RX {data.Length}B {FormatHex(data)}"); @@ -408,10 +397,9 @@ protected void StartKeepAlive(int? keepAliveIntervalMs) var interval = keepAliveIntervalMs.Value; - // Seed timestamps to "now" so the first tick doesn't see zero-initialized fields as ancient activity - // (which would otherwise mis-trigger the RX-stall guard before any RX has arrived). + // Seed timestamps to "now" so the first tick doesn't read zero-initialized fields as ancient TX activity + // and fire an immediate resend before the client has written anything. var nowTicks = DateTime.UtcNow.Ticks; - Interlocked.Exchange(ref this.lastRxTicks, nowTicks); Interlocked.Exchange(ref this.lastClientTxTicks, nowTicks); Interlocked.Exchange(ref this.lastKeepAliveSentTicks, nowTicks); @@ -423,7 +411,6 @@ protected void StartKeepAlive(int? keepAliveIntervalMs) return; } - this.keepAliveIntervalMs = interval; this.keepAliveActive = true; this.keepAliveTimer = new Timer(this.OnKeepAliveTick, null, interval, interval); } @@ -555,34 +542,6 @@ private static string FormatHex(byte[] data, int maxBytes = 256) return sb.ToString(); } - /// - /// Push the next tick one full interval forward so that ongoing write bursts suppress the resend. - /// - private void ResetKeepAliveTimer() - { - Timer timer; - int interval; - lock (this.stateLock) - { - if (!this.keepAliveActive || this.keepAliveTimer == null) - { - return; - } - - timer = this.keepAliveTimer; - interval = this.keepAliveIntervalMs; - } - - try - { - timer.Change(interval, interval); - } - catch (ObjectDisposedException) - { - // Raced with StopKeepAlive. - } - } - private async void OnKeepAliveTick(object state) { byte[] data; @@ -601,22 +560,14 @@ private async void OnKeepAliveTick(object state) return; } - // msSinceAnyTx tracks "any TX we issued recently" — client write OR previous keep-alive — so a single forced - // keep-alive resets the budget instead of unlocking the 33 ms cadence permanently. + // Hold off while a client write OR a prior keep-alive landed within the interval: normal write bursts keep this + // silent, and counting a resend as TX means one forced send resets the budget instead of unlocking the raw tick cadence. var nowTicks = DateTime.UtcNow.Ticks; - var msSinceRx = (nowTicks - Interlocked.Read(ref this.lastRxTicks)) / TimeSpan.TicksPerMillisecond; var msSinceClientTx = (nowTicks - Interlocked.Read(ref this.lastClientTxTicks)) / TimeSpan.TicksPerMillisecond; var msSinceKeepAlive = (nowTicks - Interlocked.Read(ref this.lastKeepAliveSentTicks)) / TimeSpan.TicksPerMillisecond; var msSinceAnyTx = Math.Min(msSinceClientTx, msSinceKeepAlive); - // RX stalled too long: peripheral is silent (likely BLE link loss). Pause so the dongle can push its notification. - if (msSinceRx > KeepAliveRxStallMs) - { - return; - } - - // Yield to in-flight RX so we don't trample its TX window; capped by KeepAliveTxIdleMs to stay under the ~1 s device timeout. - if (msSinceRx < KeepAliveRxYieldMs && msSinceAnyTx < KeepAliveTxIdleMs) + if (msSinceAnyTx < KeepAliveFeedIntervalMs) { return; }