@blastlabs/utils 1.11.0

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 (137) hide show
  1. package/README.md +267 -0
  2. package/dist/components/dev/ApiLogger.d.ts +136 -0
  3. package/dist/components/dev/ApiLogger.d.ts.map +1 -0
  4. package/dist/components/dev/ApiLogger.js +408 -0
  5. package/dist/components/dev/DevPanel.d.ts +32 -0
  6. package/dist/components/dev/DevPanel.d.ts.map +1 -0
  7. package/dist/components/dev/DevPanel.js +196 -0
  8. package/dist/components/dev/FormDevTools/FormDevTools.d.ts +136 -0
  9. package/dist/components/dev/FormDevTools/FormDevTools.d.ts.map +1 -0
  10. package/dist/components/dev/FormDevTools/FormDevTools.js +442 -0
  11. package/dist/components/dev/FormDevTools/index.d.ts +3 -0
  12. package/dist/components/dev/FormDevTools/index.d.ts.map +1 -0
  13. package/dist/components/dev/FormDevTools/index.js +1 -0
  14. package/dist/components/dev/FormDevTools/styles.d.ts +45 -0
  15. package/dist/components/dev/FormDevTools/styles.d.ts.map +1 -0
  16. package/dist/components/dev/FormDevTools/styles.js +197 -0
  17. package/dist/components/dev/IdSelector.d.ts +50 -0
  18. package/dist/components/dev/IdSelector.d.ts.map +1 -0
  19. package/dist/components/dev/IdSelector.js +129 -0
  20. package/dist/components/dev/WindowSizeDisplay.d.ts +44 -0
  21. package/dist/components/dev/WindowSizeDisplay.d.ts.map +1 -0
  22. package/dist/components/dev/WindowSizeDisplay.js +74 -0
  23. package/dist/components/dev/ZIndexDebugger.d.ts +32 -0
  24. package/dist/components/dev/ZIndexDebugger.d.ts.map +1 -0
  25. package/dist/components/dev/ZIndexDebugger.js +184 -0
  26. package/dist/components/dev/index.d.ts +15 -0
  27. package/dist/components/dev/index.d.ts.map +1 -0
  28. package/dist/components/dev/index.js +12 -0
  29. package/dist/components/index.d.ts +8 -0
  30. package/dist/components/index.d.ts.map +1 -0
  31. package/dist/components/index.js +7 -0
  32. package/dist/date/index.d.ts +64 -0
  33. package/dist/date/index.d.ts.map +1 -0
  34. package/dist/date/index.js +92 -0
  35. package/dist/date/index.test.d.ts +2 -0
  36. package/dist/date/index.test.d.ts.map +1 -0
  37. package/dist/date/index.test.js +166 -0
  38. package/dist/form/__tests__/formatter.test.d.ts +2 -0
  39. package/dist/form/__tests__/formatter.test.d.ts.map +1 -0
  40. package/dist/form/__tests__/formatter.test.js +74 -0
  41. package/dist/form/__tests__/helpers.test.d.ts +2 -0
  42. package/dist/form/__tests__/helpers.test.d.ts.map +1 -0
  43. package/dist/form/__tests__/helpers.test.js +42 -0
  44. package/dist/form/__tests__/validation.test.d.ts +2 -0
  45. package/dist/form/__tests__/validation.test.d.ts.map +1 -0
  46. package/dist/form/__tests__/validation.test.js +67 -0
  47. package/dist/form/formatter.d.ts +34 -0
  48. package/dist/form/formatter.d.ts.map +1 -0
  49. package/dist/form/formatter.js +76 -0
  50. package/dist/form/helpers.d.ts +16 -0
  51. package/dist/form/helpers.d.ts.map +1 -0
  52. package/dist/form/helpers.js +34 -0
  53. package/dist/form/index.d.ts +9 -0
  54. package/dist/form/index.d.ts.map +1 -0
  55. package/dist/form/index.js +11 -0
  56. package/dist/form/validation.d.ts +33 -0
  57. package/dist/form/validation.d.ts.map +1 -0
  58. package/dist/form/validation.js +56 -0
  59. package/dist/hooks/index.d.ts +19 -0
  60. package/dist/hooks/index.d.ts.map +1 -0
  61. package/dist/hooks/index.js +23 -0
  62. package/dist/hooks/useClickOutside.d.ts +49 -0
  63. package/dist/hooks/useClickOutside.d.ts.map +1 -0
  64. package/dist/hooks/useClickOutside.js +94 -0
  65. package/dist/hooks/useCopyToClipboard.d.ts +67 -0
  66. package/dist/hooks/useCopyToClipboard.d.ts.map +1 -0
  67. package/dist/hooks/useCopyToClipboard.js +79 -0
  68. package/dist/hooks/useDebounce.d.ts +47 -0
  69. package/dist/hooks/useDebounce.d.ts.map +1 -0
  70. package/dist/hooks/useDebounce.js +60 -0
  71. package/dist/hooks/useEventListener.d.ts +79 -0
  72. package/dist/hooks/useEventListener.d.ts.map +1 -0
  73. package/dist/hooks/useEventListener.js +33 -0
  74. package/dist/hooks/useIntersectionObserver.d.ts +109 -0
  75. package/dist/hooks/useIntersectionObserver.d.ts.map +1 -0
  76. package/dist/hooks/useIntersectionObserver.js +128 -0
  77. package/dist/hooks/useLocalStorage.d.ts +19 -0
  78. package/dist/hooks/useLocalStorage.d.ts.map +1 -0
  79. package/dist/hooks/useLocalStorage.js +91 -0
  80. package/dist/hooks/useMediaQuery.d.ts +56 -0
  81. package/dist/hooks/useMediaQuery.d.ts.map +1 -0
  82. package/dist/hooks/useMediaQuery.js +104 -0
  83. package/dist/hooks/usePrevious.d.ts +58 -0
  84. package/dist/hooks/usePrevious.d.ts.map +1 -0
  85. package/dist/hooks/usePrevious.js +67 -0
  86. package/dist/hooks/useSessionStorage.d.ts +19 -0
  87. package/dist/hooks/useSessionStorage.d.ts.map +1 -0
  88. package/dist/hooks/useSessionStorage.js +85 -0
  89. package/dist/hooks/useThrottle.d.ts +57 -0
  90. package/dist/hooks/useThrottle.d.ts.map +1 -0
  91. package/dist/hooks/useThrottle.js +80 -0
  92. package/dist/hooks/useToggle.d.ts +49 -0
  93. package/dist/hooks/useToggle.d.ts.map +1 -0
  94. package/dist/hooks/useToggle.js +56 -0
  95. package/dist/hooks/useWindowSize.d.ts +58 -0
  96. package/dist/hooks/useWindowSize.d.ts.map +1 -0
  97. package/dist/hooks/useWindowSize.js +79 -0
  98. package/dist/index.d.ts +6 -0
  99. package/dist/index.d.ts.map +1 -0
  100. package/dist/index.js +17 -0
  101. package/dist/mock/form.d.ts +41 -0
  102. package/dist/mock/form.d.ts.map +1 -0
  103. package/dist/mock/form.js +195 -0
  104. package/dist/mock/generators.d.ts +112 -0
  105. package/dist/mock/generators.d.ts.map +1 -0
  106. package/dist/mock/generators.js +195 -0
  107. package/dist/mock/index.d.ts +8 -0
  108. package/dist/mock/index.d.ts.map +1 -0
  109. package/dist/mock/index.js +9 -0
  110. package/dist/number/format.d.ts +116 -0
  111. package/dist/number/format.d.ts.map +1 -0
  112. package/dist/number/format.js +165 -0
  113. package/dist/number/index.d.ts +7 -0
  114. package/dist/number/index.d.ts.map +1 -0
  115. package/dist/number/index.js +7 -0
  116. package/dist/string/__tests__/case.test.d.ts +2 -0
  117. package/dist/string/__tests__/case.test.d.ts.map +1 -0
  118. package/dist/string/__tests__/case.test.js +61 -0
  119. package/dist/string/__tests__/manipulation.test.d.ts +2 -0
  120. package/dist/string/__tests__/manipulation.test.d.ts.map +1 -0
  121. package/dist/string/__tests__/manipulation.test.js +109 -0
  122. package/dist/string/__tests__/validation.test.d.ts +2 -0
  123. package/dist/string/__tests__/validation.test.d.ts.map +1 -0
  124. package/dist/string/__tests__/validation.test.js +101 -0
  125. package/dist/string/case.d.ts +42 -0
  126. package/dist/string/case.d.ts.map +1 -0
  127. package/dist/string/case.js +71 -0
  128. package/dist/string/index.d.ts +9 -0
  129. package/dist/string/index.d.ts.map +1 -0
  130. package/dist/string/index.js +11 -0
  131. package/dist/string/manipulation.d.ts +61 -0
  132. package/dist/string/manipulation.d.ts.map +1 -0
  133. package/dist/string/manipulation.js +106 -0
  134. package/dist/string/validation.d.ts +79 -0
  135. package/dist/string/validation.d.ts.map +1 -0
  136. package/dist/string/validation.js +115 -0
  137. package/package.json +86 -0
package/README.md ADDED
@@ -0,0 +1,267 @@
1
+ # goodchuck-utils
2
+
3
+ React 프로젝트에서 자주 사용하는 유틸리티 훅(Hooks)과 개발용 컴포넌트 모음입니다.
4
+
5
+ ## 설치
6
+
7
+ ```bash
8
+ npm install goodchuck-utils
9
+ # or
10
+ yarn add goodchuck-utils
11
+ # or
12
+ pnpm add goodchuck-utils
13
+ ```
14
+
15
+ ## 기능
16
+
17
+ ### 📦 Hooks
18
+
19
+ 프로젝트에서 자주 사용하는 커스텀 훅들을 제공합니다.
20
+
21
+ ```typescript
22
+ import { useDebounce, useToggle, useCopyToClipboard } from 'goodchuck-utils/hooks';
23
+ ```
24
+
25
+ #### 사용 가능한 Hooks
26
+
27
+ - **useDebounce** - 값의 변경을 지연시켜 성능 최적화
28
+ - **useThrottle** - 함수 실행 빈도를 제한하여 성능 최적화
29
+ - **useToggle** - boolean 상태를 쉽게 토글
30
+ - **useCopyToClipboard** - 클립보드 복사 기능
31
+ - **useWindowSize** - 윈도우 크기 추적
32
+ - **usePrevious** - 이전 값 추적
33
+ - **useIntersectionObserver** - Intersection Observer API 활용
34
+ - **useEventListener** - 이벤트 리스너 관리
35
+
36
+ ### 🛠️ Development Components
37
+
38
+ 개발 환경에서만 사용하는 유틸리티 컴포넌트들입니다.
39
+
40
+ ```typescript
41
+ import { DevPanel, FormDevTools, ApiLogger } from 'goodchuck-utils/components/dev';
42
+ ```
43
+
44
+ #### IdSelector
45
+
46
+ 개발 환경에서 여러 계정으로 빠르게 로그인할 수 있는 컴포넌트입니다.
47
+
48
+ ```tsx
49
+ import { IdSelector } from 'goodchuck-utils/components/dev';
50
+
51
+ const devAccounts = [
52
+ { id: 'admin', pw: 'admin123', memo: '관리자' },
53
+ { id: 'user1', pw: 'user123', memo: '일반 사용자' },
54
+ ];
55
+
56
+ function App() {
57
+ const handleLogin = async (id: string, pw: string) => {
58
+ // 로그인 로직
59
+ await loginApi(id, pw);
60
+ };
61
+
62
+ return (
63
+ <div>
64
+ {import.meta.env.DEV && (
65
+ <IdSelector onLogin={handleLogin} infos={devAccounts} />
66
+ )}
67
+ </div>
68
+ );
69
+ }
70
+ ```
71
+
72
+ #### FormDevTools
73
+
74
+ react-hook-form의 상태를 실시간으로 시각화하는 개발용 컴포넌트입니다.
75
+
76
+ ```tsx
77
+ import { useForm } from 'react-hook-form';
78
+ import { FormDevTools } from 'goodchuck-utils/components/dev';
79
+
80
+ function MyForm() {
81
+ const form = useForm({
82
+ defaultValues: {
83
+ username: '',
84
+ email: '',
85
+ age: 0,
86
+ }
87
+ });
88
+
89
+ return (
90
+ <form onSubmit={form.handleSubmit(onSubmit)}>
91
+ <input {...form.register('username')} />
92
+ <input {...form.register('email')} />
93
+ <button type="submit">Submit</button>
94
+
95
+ {import.meta.env.DEV && <FormDevTools form={form} />}
96
+ </form>
97
+ );
98
+ }
99
+ ```
100
+
101
+ **주요 기능:**
102
+ - 폼 값(values) 실시간 확인
103
+ - 에러(errors) 상태 확인
104
+ - 변경된 필드(dirtyFields) 추적
105
+ - 터치된 필드(touchedFields) 확인
106
+ - Mock 데이터 생성 기능
107
+ - 드래그 & 리사이즈 가능한 패널
108
+
109
+ #### ApiLogger
110
+
111
+ API 요청/응답을 로깅하고 모니터링하는 컴포넌트입니다.
112
+
113
+ ```tsx
114
+ import axios from 'axios';
115
+ import { ApiLogger, addApiLog } from 'goodchuck-utils/components/dev';
116
+
117
+ // Axios interceptor 설정
118
+ axios.interceptors.request.use(
119
+ (config) => {
120
+ config.metadata = { startTime: Date.now() };
121
+ return config;
122
+ },
123
+ (error) => Promise.reject(error)
124
+ );
125
+
126
+ axios.interceptors.response.use(
127
+ (response) => {
128
+ const duration = Date.now() - response.config.metadata?.startTime;
129
+
130
+ addApiLog({
131
+ method: response.config.method?.toUpperCase() || 'GET',
132
+ url: response.config.url || '',
133
+ status: response.status,
134
+ statusText: response.statusText,
135
+ duration,
136
+ requestBody: response.config.data,
137
+ responseBody: response.data,
138
+ });
139
+
140
+ return response;
141
+ },
142
+ (error) => {
143
+ const duration = Date.now() - error.config?.metadata?.startTime;
144
+
145
+ addApiLog({
146
+ method: error.config?.method?.toUpperCase() || 'GET',
147
+ url: error.config?.url || '',
148
+ status: error.response?.status,
149
+ statusText: error.response?.statusText,
150
+ duration,
151
+ requestBody: error.config?.data,
152
+ responseBody: error.response?.data,
153
+ error: error.message,
154
+ });
155
+
156
+ return Promise.reject(error);
157
+ }
158
+ );
159
+
160
+ function App() {
161
+ return (
162
+ <div>
163
+ {import.meta.env.DEV && <ApiLogger />}
164
+ </div>
165
+ );
166
+ }
167
+ ```
168
+
169
+ **주요 기능:**
170
+ - API 요청/응답 로그 수집
171
+ - 요청 메서드, URL, 상태 코드 표시
172
+ - 응답 시간(duration) 측정
173
+ - Request/Response Body 확인
174
+ - 로그 복사 및 삭제 기능
175
+
176
+ #### DevPanel
177
+
178
+ 여러 개발 도구를 하나의 패널에서 관리할 수 있는 통합 컴포넌트입니다.
179
+
180
+ ```tsx
181
+ import { DevPanel } from 'goodchuck-utils/components/dev';
182
+
183
+ function App() {
184
+ return (
185
+ <div>
186
+ {import.meta.env.DEV && <DevPanel />}
187
+ </div>
188
+ );
189
+ }
190
+ ```
191
+
192
+ **주요 기능:**
193
+ - 윈도우 크기 표시
194
+ - 렌더 카운트 표시
195
+ - LocalStorage 삭제
196
+ - SessionStorage 삭제
197
+
198
+ #### ZIndexDebugger
199
+
200
+ 페이지의 모든 z-index 값을 시각화하고 디버깅하는 도구입니다.
201
+
202
+ ```tsx
203
+ import { ZIndexDebugger } from 'goodchuck-utils/components/dev';
204
+
205
+ function App() {
206
+ return (
207
+ <div>
208
+ {import.meta.env.DEV && <ZIndexDebugger />}
209
+ </div>
210
+ );
211
+ }
212
+ ```
213
+
214
+ **주요 기능:**
215
+ - 모든 요소의 z-index 값 스캔
216
+ - 요소에 마우스 오버 시 하이라이트
217
+ - 클릭 시 해당 요소로 스크롤
218
+ - z-index 값 정렬 (높은 순/낮은 순)
219
+
220
+ #### WindowSizeDisplay
221
+
222
+ 현재 윈도우 크기를 화면에 표시하는 간단한 컴포넌트입니다.
223
+
224
+ ```tsx
225
+ import { WindowSizeDisplay } from 'goodchuck-utils/components/dev';
226
+
227
+ function App() {
228
+ return (
229
+ <div>
230
+ {import.meta.env.DEV && <WindowSizeDisplay />}
231
+ </div>
232
+ );
233
+ }
234
+ ```
235
+
236
+ ## 개발 환경 구분
237
+
238
+ ### Vite 프로젝트
239
+ ```tsx
240
+ {import.meta.env.DEV && <DevPanel />}
241
+ ```
242
+
243
+ ### Create React App 프로젝트
244
+ ```tsx
245
+ {process.env.NODE_ENV === 'development' && <DevPanel />}
246
+ ```
247
+
248
+ ## TypeScript 지원
249
+
250
+ 모든 컴포넌트와 훅은 TypeScript로 작성되었으며, 타입 정의가 포함되어 있습니다.
251
+
252
+ ```typescript
253
+ import type { FormDevToolsProps, ApiLogEntry } from 'goodchuck-utils/components/dev';
254
+ ```
255
+
256
+ ## 주의사항
257
+
258
+ - **개발용 컴포넌트(`components/dev`)는 프로덕션 환경에서 제외하는 것을 권장합니다.**
259
+ - 개발 환경 구분을 위해 `import.meta.env.DEV` (Vite) 또는 `process.env.NODE_ENV === 'development'` (CRA)를 사용하세요.
260
+
261
+ ## 라이선스
262
+
263
+ ISC
264
+
265
+ ## 기여
266
+
267
+ 이슈나 PR은 언제든 환영합니다!
@@ -0,0 +1,136 @@
1
+ import React from 'react';
2
+ export type ApiLogEntry = {
3
+ id: string;
4
+ timestamp: Date;
5
+ method: string;
6
+ url: string;
7
+ status?: number;
8
+ statusText?: string;
9
+ duration?: number;
10
+ requestBody?: unknown;
11
+ responseBody?: unknown;
12
+ error?: string;
13
+ };
14
+ type Props = {
15
+ /** 표시 위치 (기본값: 'bottom-right') */
16
+ position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
17
+ /** 최대 로그 개수 (기본값: 50) */
18
+ maxLogs?: number;
19
+ };
20
+ /**
21
+ * API 로그를 추가하는 함수
22
+ * fetch나 axios interceptor에서 호출하여 사용합니다.
23
+ */
24
+ export declare function addApiLog(log: Omit<ApiLogEntry, 'id' | 'timestamp'>): void;
25
+ /**
26
+ * 모든 API 로그를 초기화하는 함수
27
+ */
28
+ export declare function clearApiLogs(): void;
29
+ /**
30
+ * API 요청/응답을 로깅하는 개발용 컴포넌트
31
+ * Axios interceptor 또는 fetch wrapper와 함께 사용하여 API 호출을 모니터링합니다.
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * // Axios interceptor 사용 (가장 일반적)
36
+ * import axios from 'axios';
37
+ * import { ApiLogger, addApiLog } from 'goodchuck-utils/components/dev';
38
+ *
39
+ * // Request interceptor
40
+ * axios.interceptors.request.use(
41
+ * (config) => {
42
+ * config.metadata = { startTime: Date.now() };
43
+ * return config;
44
+ * },
45
+ * (error) => Promise.reject(error)
46
+ * );
47
+ *
48
+ * // Response interceptor
49
+ * axios.interceptors.response.use(
50
+ * (response) => {
51
+ * const duration = Date.now() - response.config.metadata?.startTime;
52
+ *
53
+ * addApiLog({
54
+ * method: response.config.method?.toUpperCase() || 'GET',
55
+ * url: response.config.url || '',
56
+ * status: response.status,
57
+ * statusText: response.statusText,
58
+ * duration,
59
+ * requestBody: response.config.data,
60
+ * responseBody: response.data,
61
+ * });
62
+ *
63
+ * return response;
64
+ * },
65
+ * (error) => {
66
+ * const duration = Date.now() - error.config?.metadata?.startTime;
67
+ *
68
+ * addApiLog({
69
+ * method: error.config?.method?.toUpperCase() || 'GET',
70
+ * url: error.config?.url || '',
71
+ * status: error.response?.status,
72
+ * statusText: error.response?.statusText,
73
+ * duration,
74
+ * requestBody: error.config?.data,
75
+ * responseBody: error.response?.data,
76
+ * error: error.message,
77
+ * });
78
+ *
79
+ * return Promise.reject(error);
80
+ * }
81
+ * );
82
+ *
83
+ * function App() {
84
+ * return (
85
+ * <div>
86
+ * {import.meta.env.DEV && <ApiLogger />}
87
+ * </div>
88
+ * );
89
+ * }
90
+ * ```
91
+ *
92
+ * @example
93
+ * ```tsx
94
+ * // fetch wrapper 사용
95
+ * import { addApiLog } from 'goodchuck-utils/components/dev';
96
+ *
97
+ * const originalFetch = window.fetch;
98
+ * window.fetch = async (...args) => {
99
+ * const startTime = Date.now();
100
+ * const [url, options] = args;
101
+ *
102
+ * try {
103
+ * const response = await originalFetch(...args);
104
+ * const duration = Date.now() - startTime;
105
+ *
106
+ * addApiLog({
107
+ * method: options?.method || 'GET',
108
+ * url: url.toString(),
109
+ * status: response.status,
110
+ * statusText: response.statusText,
111
+ * duration,
112
+ * requestBody: options?.body,
113
+ * });
114
+ *
115
+ * return response;
116
+ * } catch (error) {
117
+ * addApiLog({
118
+ * method: options?.method || 'GET',
119
+ * url: url.toString(),
120
+ * error: (error as Error).message,
121
+ * duration: Date.now() - startTime,
122
+ * });
123
+ * throw error;
124
+ * }
125
+ * };
126
+ * ```
127
+ *
128
+ * @example
129
+ * ```tsx
130
+ * // Create React App 프로젝트
131
+ * {process.env.NODE_ENV === 'development' && <ApiLogger position="bottom-left" />}
132
+ * ```
133
+ */
134
+ export default function ApiLogger({ position, maxLogs }: Props): React.JSX.Element;
135
+ export {};
136
+ //# sourceMappingURL=ApiLogger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiLogger.d.ts","sourceRoot":"","sources":["../../../src/components/dev/ApiLogger.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAC;AAGlE,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,kCAAkC;IAClC,QAAQ,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,CAAC;IACrE,yBAAyB;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAMF;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,CAAC,QASnE;AAED;;GAEG;AACH,wBAAgB,YAAY,SAG3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwGG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAAE,QAAyB,EAAE,OAAY,EAAE,EAAE,KAAK,qBAgXnF"}