@hasna/recordings 0.3.2 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +38 -34
  2. package/bun.lock +96 -36
  3. package/dist/__tests__/helpers/source-assertions.d.ts +6 -4
  4. package/dist/__tests__/helpers/source-assertions.d.ts.map +1 -1
  5. package/dist/cli/index.js +182 -93
  6. package/dist/cli/macos-shortcut.d.ts +2 -2
  7. package/dist/db/pg-migrations.d.ts +1 -1
  8. package/dist/http/client.d.ts +0 -10
  9. package/dist/http/client.d.ts.map +1 -1
  10. package/dist/index.js +162 -73
  11. package/dist/lib/capture-probe.d.ts +3 -3
  12. package/dist/lib/capture-probe.d.ts.map +1 -1
  13. package/dist/lib/macos-bundle.d.ts +1 -1
  14. package/dist/lib/release-install-policy.d.ts +21 -0
  15. package/dist/lib/release-install-policy.d.ts.map +1 -1
  16. package/dist/mcp/index.js +144 -59
  17. package/dist/sdk/index.d.ts +2 -2
  18. package/dist/sdk/index.js +7 -3
  19. package/dist/sdk/v1.generated.d.ts.map +1 -1
  20. package/dist/server/cloud-config.d.ts +4 -19
  21. package/dist/server/cloud-config.d.ts.map +1 -1
  22. package/dist/server/cloud.d.ts +1 -1
  23. package/dist/server/cloud.d.ts.map +1 -1
  24. package/dist/server/index.js +168 -110
  25. package/dist/server/serve.d.ts.map +1 -1
  26. package/dist/storage.d.ts +1 -1
  27. package/dist/storage.d.ts.map +1 -1
  28. package/dist/storage.js +144 -60
  29. package/dist/store.d.ts.map +1 -1
  30. package/dist/version.d.ts +1 -1
  31. package/dist/version.d.ts.map +1 -1
  32. package/package.json +4 -3
  33. package/packaging/macos/build_release_pkg.sh +10 -4
  34. package/packaging/macos/managed_bootstrap.sh +4 -4
  35. package/packaging/macos/scripts/postinstall +2 -2
  36. package/packaging/macos/scripts/preinstall +2 -0
  37. package/scripts/generate-sdk.ts +17 -16
  38. package/scripts/install_macos_app.sh +22 -22
  39. package/scripts/macos_artifact.ts +48 -39
  40. package/scripts/migrate.ts +2 -2
  41. package/scripts/release-suite-gate.ts +181 -0
  42. package/scripts/set-version.ts +5 -5
  43. package/scripts/smoke_macos_app.sh +21 -21
  44. package/scripts/vacuity-manifests/version-sites.tsv +8 -4
  45. package/src/native/Recordings/RecordingsLib/Info.plist +3 -3
  46. package/src/native/Recordings/RecordingsTests/CLIRunnerTests.swift +2 -2
  47. package/src/native/Recordings/RecordingsTests/RecordingStartGateTests.swift +1 -1
  48. package/src/native/Recordings/Updater/BootstrapPreflight/BootstrapPreflightMain.swift +1 -1
  49. package/src/native/Recordings/Updater/Broker/ApplicationNamespace.swift +2 -2
  50. package/src/native/Recordings/Updater/Broker/BrokerMain.swift +1 -1
  51. package/src/native/Recordings/Updater/Broker/CanonicalTreeCopy.swift +1 -1
  52. package/src/native/Recordings/Updater/Broker/InstallJournal.swift +1 -1
  53. package/src/native/Recordings/Updater/BrokerTests/ActivationRecoveryPolicyTests.swift +2 -2
  54. package/src/native/Recordings/Updater/Protocol/UpdateProtocol.swift +1 -1
  55. package/src/native/Recordings/Updater/VerifierLauncher/RecordingsVerifierLauncher.c +2 -2
  56. package/src/native/Recordings/build.sh +14 -20
  57. package/dist/lib/retired-deployment-modes.d.ts +0 -24
  58. package/dist/lib/retired-deployment-modes.d.ts.map +0 -1
@@ -15,9 +15,13 @@
15
15
  # manifest is not wired into a package.json aggregate script.
16
16
  #
17
17
  # --- every version site agrees with package.json. Models 8de7068: one site bumped, the rest not.
18
- duplicate src/__tests__/version-site-guard.test.ts agree in the working tree, on the version package.json declares src/version.ts .15 1
19
- duplicate src/__tests__/version-site-guard.test.ts agree in the working tree, on the version package.json declares src/native/Recordings/RecordingsLib/Info.plist 0.2.15 1
20
- duplicate src/__tests__/version-site-guard.test.ts agree in the working tree, on the version package.json declares src/native/Recordings/RecordingsLib/Info.plist 0.2.15 2
18
+ # I38-00553 (2026-08-21): src/version.ts now DERIVES from package.json and holds no literal, so it
19
+ # is no longer a writer site (see set-version.ts) and cannot be mutated here. The residual drift
20
+ # class is the mirror direction: the package.json authority corrupted while the native sites stay
21
+ # put. Rows below were re-needled to the 0.3.5 tree.
22
+ delete src/__tests__/version-site-guard.test.ts agree in the working tree, on the version package.json declares package.json 0.3.5 1
23
+ duplicate src/__tests__/version-site-guard.test.ts agree in the working tree, on the version package.json declares src/native/Recordings/RecordingsLib/Info.plist 0.3.5 1
24
+ duplicate src/__tests__/version-site-guard.test.ts agree in the working tree, on the version package.json declares src/native/Recordings/RecordingsLib/Info.plist 0.3.5 2
21
25
  # --- a stale site is reported, not silently accepted: the mismatch filter removed.
22
26
  delete src/__tests__/version-site-guard.test.ts a single stale site is reported rather than silently accepted scripts/set-version.ts .filter((reading) => reading.version !== expected) 1
23
27
  # --- applyVersion writes every site in one pass: the per-file grouping removed.
@@ -58,4 +62,4 @@ delete src/__tests__/version-site-guard.test.ts applyVersion rewrites every site
58
62
  #
59
63
  # The generated SDK's version stamp -- a fifth copy of the release version that `versionSites`
60
64
  # deliberately does not write -- goes stale again.
61
- delete src/__tests__/version-site-guard.test.ts the generated SDK header carries the version package.json declares src/sdk/v1.generated.ts .15 1
65
+ delete src/__tests__/version-site-guard.test.ts the generated SDK header carries the version package.json declares src/sdk/v1.generated.ts 0.3.5 1
@@ -11,17 +11,17 @@
11
11
  <key>CFBundleName</key>
12
12
  <string>Recordings</string>
13
13
  <key>CFBundleDisplayName</key>
14
- <string>Recordings</string>
14
+ <string>Hasna Recordings</string>
15
15
  <key>CFBundleExecutable</key>
16
16
  <string>Recordings</string>
17
17
  <key>CFBundleIdentifier</key>
18
18
  <string>com.hasna.recordings</string>
19
19
  <key>CFBundleVersion</key>
20
- <string>0.3.2</string>
20
+ <string>0.3.8</string>
21
21
  <key>CFBundlePackageType</key>
22
22
  <string>APPL</string>
23
23
  <key>CFBundleShortVersionString</key>
24
- <string>0.3.2</string>
24
+ <string>0.3.8</string>
25
25
  <key>LSMinimumSystemVersion</key>
26
26
  <string>26.0</string>
27
27
  <key>NSMicrophoneUsageDescription</key>
@@ -8,7 +8,7 @@ struct CLIRunnerTests {
8
8
  func bundledCLIIsPreferred() throws {
9
9
  let root = FileManager.default.temporaryDirectory
10
10
  .appendingPathComponent("recordings-bundled-cli-\(UUID().uuidString)")
11
- let app = root.appendingPathComponent("Recordings.app")
11
+ let app = root.appendingPathComponent("HasnaRecordings.app")
12
12
  let helper = app.appendingPathComponent("Contents/Helpers/recordings")
13
13
  let home = root.appendingPathComponent("home")
14
14
  let external = home.appendingPathComponent(".bun/bin/recordings")
@@ -34,7 +34,7 @@ struct CLIRunnerTests {
34
34
  func packagedAppDoesNotUseGlobalFallback() throws {
35
35
  let root = FileManager.default.temporaryDirectory
36
36
  .appendingPathComponent("recordings-missing-companion-\(UUID().uuidString)")
37
- let app = root.appendingPathComponent("Recordings.app")
37
+ let app = root.appendingPathComponent("HasnaRecordings.app")
38
38
  let home = root.appendingPathComponent("home")
39
39
  let external = home.appendingPathComponent(".bun/bin/recordings")
40
40
  try FileManager.default.createDirectory(at: app, withIntermediateDirectories: true)
@@ -6,7 +6,7 @@ struct RecordingStartGateTests {
6
6
  @Test("permission-only launch skips global handlers and terminates after handling")
7
7
  func permissionHelperLaunchPlan() {
8
8
  let plan = PermissionRequestLaunchPlan(arguments: [
9
- "/Applications/Recordings.app/Contents/MacOS/Recordings",
9
+ "/Applications/HasnaRecordings.app/Contents/MacOS/Recordings",
10
10
  "--request-permissions",
11
11
  "--open-permission-settings",
12
12
  ])
@@ -51,7 +51,7 @@ enum RecordingsBootstrapPreflight {
51
51
  let manifest = try JSONDecoder().decode(ReleaseManifest.self, from: manifestData)
52
52
  try validateManifest(manifest, payload: payload)
53
53
 
54
- let app = arguments.payloadRoot + "/Applications/Recordings.app"
54
+ let app = arguments.payloadRoot + "/Applications/HasnaRecordings.app"
55
55
  let client = app + "/" + RecordingsUpdateConstants.updateClientRelativePath
56
56
  let broker = arguments.payloadRoot + "/Library/PrivilegedHelperTools/com.hasna.recordings.updater"
57
57
  let artifactVerifier = arguments.payloadRoot
@@ -7,7 +7,7 @@ import RecordingsUpdateProtocol
7
7
  /// operation; first installs use exclusive rename semantics and can never replace a
8
8
  /// leaf created concurrently in `/Applications`.
9
9
  final class ApplicationNamespace {
10
- private static let liveLeaf = "Recordings.app"
10
+ private static let liveLeaf = "HasnaRecordings.app"
11
11
  private static let previousLeaf = "previous.app"
12
12
  private static let failedCandidateLeaf = "failed-candidate.app"
13
13
 
@@ -22,7 +22,7 @@ final class ApplicationNamespace {
22
22
  .deletingLastPathComponent
23
23
  guard journal.applicationPath == RecordingsUpdateConstants.applicationPath,
24
24
  journal.candidateApplicationPath == expectedTransactionDirectory
25
- + "/candidate/Recordings.app",
25
+ + "/candidate/HasnaRecordings.app",
26
26
  journal.previousApplicationPath == nil ||
27
27
  journal.previousApplicationPath == expectedTransactionDirectory + "/previous.app"
28
28
  else {
@@ -276,7 +276,7 @@ final class UpdateBrokerSession: NSObject, RecordingsUpdateXPCProtocol {
276
276
  guard mkdir(candidateRoot, 0o700) == 0 else {
277
277
  throw BrokerOperationError.candidateRejected
278
278
  }
279
- let candidateApplication = candidateRoot + "/Recordings.app"
279
+ let candidateApplication = candidateRoot + "/HasnaRecordings.app"
280
280
  let verifierIDs = try verifierAccountIDs()
281
281
  try CanonicalTreeCopier.copyApplication(
282
282
  from: verifierOutput,
@@ -22,7 +22,7 @@ enum CanonicalTreeCopier {
22
22
  }
23
23
  defer { Darwin.close(source) }
24
24
  let destinationRoot = URL(fileURLWithPath: rootCandidatePath).deletingLastPathComponent().path
25
- guard URL(fileURLWithPath: rootCandidatePath).lastPathComponent == "Recordings.app" else {
25
+ guard URL(fileURLWithPath: rootCandidatePath).lastPathComponent == "HasnaRecordings.app" else {
26
26
  throw CanonicalCopyError.nonCanonicalRoot
27
27
  }
28
28
  let destination = Darwin.open(
@@ -253,7 +253,7 @@ struct DurableInstallJournal {
253
253
  let leaf = URL(fileURLWithPath: transactionDirectory).lastPathComponent
254
254
  guard leaf.hasPrefix("transaction-") else { throw InstallJournalError.invalidJournal }
255
255
  let transactionID = String(leaf.dropFirst("transaction-".count))
256
- let expectedCandidate = transactionDirectory + "/candidate/Recordings.app"
256
+ let expectedCandidate = transactionDirectory + "/candidate/HasnaRecordings.app"
257
257
  let activationPhases: Set<String> = [
258
258
  "prepared", "launch-barrier-pending", "launch-barrier-held",
259
259
  "swap-pending", "swapped", "previous-retaining",
@@ -201,8 +201,8 @@ struct ActivationRecoveryPolicyTests {
201
201
  "Contents/Helpers/recordings": 493,
202
202
  "Contents/Helpers/recordings-update-client": 493
203
203
  },
204
- "candidate_application_path": "/Library/Application Support/Hasna/Recordings/Updates/transaction-00000000-0000-0000-0000-000000000001/candidate/Recordings.app",
205
- "application_path": "/Applications/Recordings.app"
204
+ "candidate_application_path": "/Library/Application Support/Hasna/Recordings/Updates/transaction-00000000-0000-0000-0000-000000000001/candidate/HasnaRecordings.app",
205
+ "application_path": "/Applications/HasnaRecordings.app"
206
206
  }
207
207
  """#.utf8)
208
208
  let journal = try JSONDecoder().decode(BrokerInstallJournal.self, from: legacyJSON)
@@ -7,7 +7,7 @@ public enum RecordingsUpdateConstants {
7
7
  public static let rootMaintenanceSupported = false
8
8
  public static let keyRotationSupported = false
9
9
  public static let machServiceName = "com.hasna.recordings.updater"
10
- public static let applicationPath = "/Applications/Recordings.app"
10
+ public static let applicationPath = "/Applications/HasnaRecordings.app"
11
11
  public static let brokerExecutablePath = "/Library/PrivilegedHelperTools/com.hasna.recordings.updater"
12
12
  public static let stateRoot = "/Library/Application Support/Hasna/Recordings/Updates"
13
13
  public static let trustRoot = "/Library/Application Support/Hasna/Recordings/Trust"
@@ -729,7 +729,7 @@ int recordings_copy_canonical_application_tree(
729
729
  if (entry == NULL) break;
730
730
  if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
731
731
  visible_entries += 1;
732
- if (strcmp(entry->d_name, "Recordings.app") != 0) only_application = false;
732
+ if (strcmp(entry->d_name, "HasnaRecordings.app") != 0) only_application = false;
733
733
  }
734
734
  int status = errno;
735
735
  closedir(directory);
@@ -739,7 +739,7 @@ int recordings_copy_canonical_application_tree(
739
739
  status = copy_directory_at(
740
740
  verifier_output_directory_descriptor,
741
741
  root_candidate_directory_descriptor,
742
- "Recordings.app",
742
+ "HasnaRecordings.app",
743
743
  verifier_user_id,
744
744
  &budget
745
745
  );
@@ -1,5 +1,5 @@
1
1
  #!/bin/bash
2
- # Build, sign, notarize, and finalize a Recordings.app artifact.
2
+ # Build, sign, notarize, and finalize a HasnaRecordings.app artifact.
3
3
  # Usage: ./build.sh [debug|local] | ./build.sh release <initial-bootstrap|app-update>
4
4
 
5
5
  set -euo pipefail
@@ -119,16 +119,12 @@ if [ "$VARIANT" = "bar" ]; then
119
119
  VARIANT_SWIFT_FLAGS=(-Xswiftc -DRECORDINGS_BAR_ONLY)
120
120
  fi
121
121
  # Fleet naming rule (knowledge k_msxd5rz3_jfvl3i): every Hasna macOS app is
122
- # Hasna<Name>.app with 'Hasna' at the beginning. The full app keeps its historical
123
- # Recordings.app name (its rename is the rule's recorded follow-up decision); the
124
- # bar-only artifact is named per the rule NOW — HasnaRecordings.app. The 'bar' is the
125
- # variant, never a separate app name: bundle identifier stays com.hasna.recordings so
126
- # TCC keeps keying on bundle id + signing identity, and the executable inside the
127
- # bundle stays "Recordings".
128
- APP_BUNDLE_NAME="Recordings.app"
129
- if [ "$VARIANT" = "bar" ]; then
130
- APP_BUNDLE_NAME="HasnaRecordings.app"
131
- fi
122
+ # Hasna<Name>.app with 'Hasna' at the beginning. The bundle is named
123
+ # HasnaRecordings.app for BOTH variants (full and bar); the 'bar' is a variant, never
124
+ # a separate app name. Bundle identifier stays com.hasna.recordings so TCC keeps
125
+ # keying on bundle id + signing identity, and the executable inside the bundle stays
126
+ # "Recordings".
127
+ APP_BUNDLE_NAME="HasnaRecordings.app"
132
128
  readonly APP_BUNDLE_NAME
133
129
  APP_BASENAME="${APP_BUNDLE_NAME%.app}"
134
130
  PLIST_BUDDY="$(select_executable "/usr/libexec/PlistBuddy" "${RECORDINGS_TEST_PLIST_BUDDY_EXECUTABLE:-${PLIST_BUDDY:-}}")"
@@ -1260,7 +1256,7 @@ fi
1260
1256
 
1261
1257
  generate_and_verify_native_fs_guard
1262
1258
 
1263
- echo "Building Recordings.app ($MODE)..."
1259
+ echo "Building HasnaRecordings.app ($MODE)..."
1264
1260
  if [ "$MODE" = "release" ]; then
1265
1261
  OUTPUT_BUILD_DIR="$BUILD_ROOT/release-output"
1266
1262
  else
@@ -1426,15 +1422,15 @@ if [ "$MODE" = "release" ] && [ "$HOST_PLATFORM" = "Darwin" ]; then
1426
1422
  fi
1427
1423
  fi
1428
1424
  "$CP_EXECUTABLE" "$SOURCE_NATIVE_DIR/RecordingsLib/Info.plist" "$CONTENTS/Info.plist"
1425
+ # Bundle display name per the fleet naming rule (knowledge k_msxd5rz3_jfvl3i):
1426
+ # "Hasna Recordings" with 'Hasna' at the beginning, for both variants.
1427
+ "$PLIST_BUDDY" -c 'Set :CFBundleDisplayName Hasna Recordings' "$CONTENTS/Info.plist"
1429
1428
  if [ "$VARIANT" = "bar" ]; then
1430
1429
  # The bar is an accessory app: LSUIElement keeps it out of the Dock and the app
1431
1430
  # switcher, and the app's window-declaring control flow (RECORDINGS_BAR_ONLY)
1432
1431
  # keeps the workspace window absent. The bundle identifier stays com.hasna.recordings
1433
- # so TCC grants continue to key on bundle id + signing identity, and the bundle is
1434
- # named per the fleet rule (knowledge k_msxd5rz3_jfvl3i) — HasnaRecordings.app with
1435
- # the display name "Hasna Recordings"; 'Hasna' at the beginning of the name.
1432
+ # so TCC grants continue to key on bundle id + signing identity.
1436
1433
  "$PLIST_BUDDY" -c 'Add :LSUIElement bool true' "$CONTENTS/Info.plist"
1437
- "$PLIST_BUDDY" -c 'Set :CFBundleDisplayName Hasna Recordings' "$CONTENTS/Info.plist"
1438
1434
  fi
1439
1435
  VERSION="$("$PLIST_BUDDY" -c 'Print :CFBundleShortVersionString' "$CONTENTS/Info.plist")"
1440
1436
 
@@ -1670,8 +1666,6 @@ run_signed_helper_contract() {
1670
1666
  HOME="$contract_home"
1671
1667
  PATH="/usr/bin:/bin:/usr/sbin:/sbin"
1672
1668
  TMPDIR="$contract_home"
1673
- HASNA_RECORDINGS_CLIENT_STORE="sqlite"
1674
- RECORDINGS_CLIENT_STORE="sqlite"
1675
1669
  HASNA_RECORDINGS_DB_PATH="$contract_home/recordings.db"
1676
1670
  RECORDINGS_AUDIO_DIR="$contract_home/audio"
1677
1671
  )
@@ -1998,7 +1992,7 @@ if [ "$MODE" = "local" ]; then
1998
1992
  fi
1999
1993
 
2000
1994
  verify_signed_code "$HELPERS/recordings" "Companion CLI"
2001
- verify_signed_code "$APP_DIR" "Recordings.app"
1995
+ verify_signed_code "$APP_DIR" "HasnaRecordings.app"
2002
1996
  ARTIFACT_BASENAME="${APP_BASENAME}-${VERSION}-macos-${RELEASE_SUBTYPE}"
2003
1997
  NOTARY_ARCHIVE="$OUTPUT_BUILD_DIR/${ARTIFACT_BASENAME}-notarization.zip"
2004
1998
  FINAL_ARCHIVE="$OUTPUT_BUILD_DIR/${ARTIFACT_BASENAME}.zip"
@@ -2050,7 +2044,7 @@ run_xcrun stapler validate "$APP_DIR"
2050
2044
  run_release_sensitive_tool "$SPCTL_EXECUTABLE" --assess --type execute --verbose=2 "$APP_DIR"
2051
2045
  run_release_sensitive_tool "$SYSPOLICY_CHECK_EXECUTABLE" distribution "$APP_DIR"
2052
2046
  verify_signed_code "$HELPERS/recordings" "Companion CLI"
2053
- verify_signed_code "$APP_DIR" "Recordings.app"
2047
+ verify_signed_code "$APP_DIR" "HasnaRecordings.app"
2054
2048
  run_codesign --verify --deep --strict --verbose=2 "$APP_DIR"
2055
2049
 
2056
2050
  run_release_sensitive_tool "$DITTO_EXECUTABLE" -c -k --sequesterRsrc --keepParent "$APP_DIR" "$FINAL_ARCHIVE"
@@ -1,24 +0,0 @@
1
- export declare const RETIRED_DEPLOYMENT_MODES: readonly ["local", "self_hosted", "cloud", "remote", "hybrid"];
2
- export type RetiredDeploymentMode = (typeof RETIRED_DEPLOYMENT_MODES)[number];
3
- /** Fold case, surrounding space, and the `self-hosted`/`self_hosted` spelling split. */
4
- export declare function normalizeModeToken(value: string): string;
5
- /** The retired mode this value names, or null if it names something else. */
6
- export declare function asRetiredDeploymentMode(value: string): RetiredDeploymentMode | null;
7
- export interface RetiredModeReplacement {
8
- /** The variable the caller should set instead. */
9
- envKey: string;
10
- /** Value that replaces `local` — the on-this-box arm. */
11
- onBox: string;
12
- /** Value that replaces `self_hosted` / `cloud` / `remote` / `hybrid`. */
13
- offBox: string;
14
- }
15
- /**
16
- * The error a retired mode word must produce.
17
- *
18
- * It names three things a bare "unknown value" error does not: the variable that
19
- * carried the retired word, the variable to set instead, and the exact value —
20
- * because the operator reading this cannot be assumed to know the collapse
21
- * happened.
22
- */
23
- export declare function retiredDeploymentModeError(rawValue: string, sourceEnvKey: string, replacement: RetiredModeReplacement): Error;
24
- //# sourceMappingURL=retired-deployment-modes.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"retired-deployment-modes.d.ts","sourceRoot":"","sources":["../../src/lib/retired-deployment-modes.ts"],"names":[],"mappings":"AA8BA,eAAO,MAAM,wBAAwB,gEAM3B,CAAC;AAEX,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9E,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,6EAA6E;AAC7E,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAKnF;AAED,MAAM,WAAW,sBAAsB;IACrC,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,sBAAsB,GAClC,KAAK,CASP"}