@germondai/ts-utils 0.0.5 → 0.1.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.
package/dist/module.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from './runtime';
2
+ export * from './types';
package/dist/module.js CHANGED
@@ -1,11 +1,99 @@
1
- // src/runtime/collection.ts
2
- var hasDuplicates = (array, keyExtractor) => new Set(array.map((value, index) => keyExtractor?.(value, index, array) || value)).size < array.length;
1
+ // src/runtime/array.ts
2
+ var hasDuplicates = (array, keyExtractor) => new Set(array.map((value, index) => keyExtractor?.(value, index, array) ?? value)).size < array.length;
3
3
  var uniqueArray = (array, keyExtractor) => [
4
4
  ...new Map(array.map((value, index, array2) => [
5
- keyExtractor?.(value, index, array2) || value,
5
+ keyExtractor?.(value, index, array2) ?? value,
6
6
  value
7
7
  ])).values()
8
8
  ];
9
+ var chunk = (array, size) => {
10
+ if (size <= 0)
11
+ return [];
12
+ const result = [];
13
+ for (let i = 0;i < array.length; i += size) {
14
+ result.push(array.slice(i, i + size));
15
+ }
16
+ return result;
17
+ };
18
+ var shuffle = (array) => {
19
+ const result = [...array];
20
+ for (let i = result.length - 1;i > 0; i--) {
21
+ const j = Math.floor(Math.random() * (i + 1));
22
+ [result[i], result[j]] = [result[j], result[i]];
23
+ }
24
+ return result;
25
+ };
26
+ var groupBy = (array, key) => {
27
+ const getKey = typeof key === "function" ? key : (item) => String(item[key]);
28
+ const result = {};
29
+ for (const item of array) {
30
+ const k = getKey(item);
31
+ if (!result[k])
32
+ result[k] = [];
33
+ result[k].push(item);
34
+ }
35
+ return result;
36
+ };
37
+ var intersection = (...arrays) => {
38
+ if (arrays.length === 0)
39
+ return [];
40
+ return arrays.reduce((acc, arr) => acc.filter((item) => arr.includes(item)));
41
+ };
42
+ var difference = (a, b) => a.filter((item) => !b.includes(item));
43
+ var range = (start, end, step = 1) => {
44
+ if (step <= 0)
45
+ return [];
46
+ const result = [];
47
+ for (let i = start;i < end; i += step) {
48
+ result.push(i);
49
+ }
50
+ return result;
51
+ };
52
+ var sortBy = (array, key, order = "asc") => {
53
+ const getVal = typeof key === "function" ? key : (item) => item[key];
54
+ return [...array].sort((a, b) => {
55
+ const va = getVal(a);
56
+ const vb = getVal(b);
57
+ const cmp = va < vb ? -1 : va > vb ? 1 : 0;
58
+ return order === "desc" ? -cmp : cmp;
59
+ });
60
+ };
61
+ var compact = (array) => array.filter(Boolean);
62
+ var last = (array) => array[array.length - 1];
63
+ var sample = (array) => array.length === 0 ? undefined : array[Math.floor(Math.random() * array.length)];
64
+ // src/runtime/color.ts
65
+ var hexToRgb = (hex) => {
66
+ const cleaned = hex.replace(/^#/, "");
67
+ let fullHex;
68
+ if (cleaned.length === 3) {
69
+ fullHex = cleaned.split("").map((c) => c + c).join("");
70
+ } else if (cleaned.length === 6) {
71
+ fullHex = cleaned;
72
+ } else {
73
+ return null;
74
+ }
75
+ const num = parseInt(fullHex, 16);
76
+ if (isNaN(num))
77
+ return null;
78
+ return {
79
+ r: num >> 16 & 255,
80
+ g: num >> 8 & 255,
81
+ b: num & 255
82
+ };
83
+ };
84
+ var rgbToHex = (r, g, b) => "#" + [r, g, b].map((v) => Math.max(0, Math.min(255, Math.round(v)))).map((v) => v.toString(16).padStart(2, "0")).join("");
85
+ var lighten = (hex, amount) => {
86
+ const rgb = hexToRgb(hex);
87
+ if (!rgb)
88
+ return hex;
89
+ return rgbToHex(rgb.r + (255 - rgb.r) * amount, rgb.g + (255 - rgb.g) * amount, rgb.b + (255 - rgb.b) * amount);
90
+ };
91
+ var darken = (hex, amount) => {
92
+ const rgb = hexToRgb(hex);
93
+ if (!rgb)
94
+ return hex;
95
+ return rgbToHex(rgb.r * (1 - amount), rgb.g * (1 - amount), rgb.b * (1 - amount));
96
+ };
9
97
  // src/runtime/constants.ts
10
98
  var SUPPORTED_DISPLAYABLE_MEDIA_TYPES = {
11
99
  images: [
@@ -25,13 +113,14 @@ var SUPPORTED_DISPLAYABLE_MEDIA_TYPES = {
25
113
  ]
26
114
  };
27
115
  // src/runtime/convertor.ts
116
+ var splitWords = (input) => input.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").toLowerCase().split(/[\s_\-]+/).filter(Boolean);
28
117
  var toCamelCase = (input) => {
29
- const words = input.toLowerCase().split(/[\s_-]+/).filter(Boolean);
118
+ const words = splitWords(input);
30
119
  return words.map((word, index) => index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)).join("");
31
120
  };
32
- var toPascalCase = (input) => input.toLowerCase().split(/[\s_-]+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
33
- var toSnakeCase = (input) => input.toLowerCase().split(/[\s-]+/).filter(Boolean).join("_");
34
- var toKebabCase = (input) => input.toLowerCase().split(/[\s_]+/).filter(Boolean).join("-");
121
+ var toPascalCase = (input) => splitWords(input).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
122
+ var toSnakeCase = (input) => splitWords(input).join("_");
123
+ var toKebabCase = (input) => splitWords(input).join("-");
35
124
  var toTitleCase = (input) => input.toLowerCase().split(/\s+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
36
125
  var toSentenceCase = (input) => {
37
126
  const lower = input.toLowerCase();
@@ -67,9 +156,33 @@ var unescapeHTML = (str) => {
67
156
  };
68
157
  return str.replace(/&[a-zA-Z0-9#]+;/g, (entity) => unescapeMap[entity] || entity);
69
158
  };
159
+ // src/runtime/crypto.ts
160
+ var generateId = (length = 16) => {
161
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
162
+ let result = "";
163
+ for (let i = 0;i < length; i++) {
164
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
165
+ }
166
+ return result;
167
+ };
168
+ var hash = (str) => {
169
+ let h = 5381;
170
+ for (let i = 0;i < str.length; i++) {
171
+ h = (h << 5) + h + str.charCodeAt(i) >>> 0;
172
+ }
173
+ return h;
174
+ };
70
175
  // src/runtime/data.ts
71
- var clone = (data) => JSON.parse(JSON.stringify(data));
72
- var isEqual = (a, b) => {
176
+ var clone = (data) => {
177
+ if (data === null || typeof data !== "object")
178
+ return data;
179
+ try {
180
+ return structuredClone(data);
181
+ } catch {
182
+ return JSON.parse(JSON.stringify(data));
183
+ }
184
+ };
185
+ var isEqual = (a, b, seen = new WeakSet) => {
73
186
  if (a === b)
74
187
  return true;
75
188
  if (a == null || b == null)
@@ -77,11 +190,15 @@ var isEqual = (a, b) => {
77
190
  if (typeof a !== typeof b)
78
191
  return false;
79
192
  if (typeof a === "object") {
193
+ if (seen.has(a) || seen.has(b))
194
+ return a === b;
195
+ seen.add(a);
196
+ seen.add(b);
80
197
  if (Array.isArray(a) && Array.isArray(b)) {
81
198
  if (a.length !== b.length)
82
199
  return false;
83
200
  for (let i = 0;i < a.length; i++)
84
- if (!isEqual(a[i], b[i]))
201
+ if (!isEqual(a[i], b[i], seen))
85
202
  return false;
86
203
  return true;
87
204
  } else {
@@ -90,7 +207,7 @@ var isEqual = (a, b) => {
90
207
  if (keysA.length !== keysB.length)
91
208
  return false;
92
209
  for (const key of keysA)
93
- if (!keysB.includes(key) || !isEqual(a[key], b[key]))
210
+ if (!keysB.includes(key) || !isEqual(a[key], b[key], seen))
94
211
  return false;
95
212
  return true;
96
213
  }
@@ -108,6 +225,61 @@ var catchError = async (promise, errorsToCatch) => {
108
225
  throw error;
109
226
  }
110
227
  };
228
+ // src/runtime/function.ts
229
+ var debounce = (fn, ms) => {
230
+ let timer;
231
+ const debounced = (...args) => {
232
+ if (timer !== undefined)
233
+ clearTimeout(timer);
234
+ timer = setTimeout(() => fn(...args), ms);
235
+ };
236
+ debounced.cancel = () => {
237
+ if (timer !== undefined)
238
+ clearTimeout(timer);
239
+ timer = undefined;
240
+ };
241
+ return debounced;
242
+ };
243
+ var throttle = (fn, ms) => {
244
+ let timer;
245
+ let lastRun = 0;
246
+ const throttled = (...args) => {
247
+ const now = Date.now();
248
+ const remaining = ms - (now - lastRun);
249
+ if (remaining <= 0) {
250
+ if (timer !== undefined) {
251
+ clearTimeout(timer);
252
+ timer = undefined;
253
+ }
254
+ lastRun = now;
255
+ fn(...args);
256
+ } else if (timer === undefined) {
257
+ timer = setTimeout(() => {
258
+ lastRun = Date.now();
259
+ timer = undefined;
260
+ fn(...args);
261
+ }, remaining);
262
+ }
263
+ };
264
+ throttled.cancel = () => {
265
+ if (timer !== undefined)
266
+ clearTimeout(timer);
267
+ timer = undefined;
268
+ };
269
+ return throttled;
270
+ };
271
+ var once = (fn) => {
272
+ let called = false;
273
+ let result;
274
+ return (...args) => {
275
+ if (!called) {
276
+ called = true;
277
+ result = fn(...args);
278
+ }
279
+ return result;
280
+ };
281
+ };
282
+ var noop = () => {};
111
283
  // src/runtime/math.ts
112
284
  var rand = (n, m = 0) => Math.floor(Math.random() * (m - n + 1)) + n;
113
285
  var percentage = (value, maxValue, decimalPlaces = 2) => {
@@ -118,10 +290,175 @@ var percentage = (value, maxValue, decimalPlaces = 2) => {
118
290
  };
119
291
  var clamp = (num, min, max) => Math.min(Math.max(num, min), max);
120
292
  var formatNumber = (num) => num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
293
+ var sum = (numbers) => numbers.reduce((acc, n) => acc + n, 0);
294
+ var average = (numbers) => numbers.length === 0 ? 0 : sum(numbers) / numbers.length;
295
+ var median = (numbers) => {
296
+ if (numbers.length === 0)
297
+ return 0;
298
+ const sorted = [...numbers].sort((a, b) => a - b);
299
+ const mid = Math.floor(sorted.length / 2);
300
+ return sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
301
+ };
302
+ var min = (numbers) => numbers.length === 0 ? Infinity : Math.min(...numbers);
303
+ var max = (numbers) => numbers.length === 0 ? -Infinity : Math.max(...numbers);
304
+ var round = (value, decimals = 0) => {
305
+ const factor = Math.pow(10, decimals);
306
+ return Math.round(value * factor) / factor;
307
+ };
121
308
  // src/runtime/media.ts
122
309
  var isSupportedDisplayableMedia = (mime, type = { image: true, video: true }) => type.image && SUPPORTED_DISPLAYABLE_MEDIA_TYPES.images.includes(mime) || type.video && SUPPORTED_DISPLAYABLE_MEDIA_TYPES.videos.includes(mime);
310
+ // src/runtime/normalize.ts
311
+ var normalize = (value) => {
312
+ let normalized;
313
+ switch (typeof value) {
314
+ case "string":
315
+ normalized = value === "" ? null : value;
316
+ break;
317
+ case "number":
318
+ normalized = isNaN(value) ? null : value;
319
+ break;
320
+ case "boolean":
321
+ normalized = value;
322
+ break;
323
+ case "object":
324
+ if (value === null || value === undefined)
325
+ normalized = value ?? null;
326
+ else if (value instanceof Date)
327
+ normalized = isNaN(value.getTime()) ? null : value;
328
+ else if (Array.isArray(value))
329
+ normalized = value.length === 0 ? null : value;
330
+ else if (value instanceof Set)
331
+ normalized = value.size === 0 ? null : value;
332
+ else if (value instanceof Map)
333
+ normalized = value.size === 0 ? null : value;
334
+ else
335
+ normalized = Object.keys(value).length === 0 ? null : value;
336
+ break;
337
+ default:
338
+ normalized = value ?? null;
339
+ }
340
+ return normalized;
341
+ };
342
+ // src/runtime/object.ts
343
+ var pick = (obj, keys) => {
344
+ const result = {};
345
+ for (const key of keys) {
346
+ if (key in obj)
347
+ result[key] = obj[key];
348
+ }
349
+ return result;
350
+ };
351
+ var omit = (obj, keys) => {
352
+ const result = { ...obj };
353
+ for (const key of keys)
354
+ delete result[key];
355
+ return result;
356
+ };
357
+ var merge = (...objects) => {
358
+ const isPlainObject = (val) => val !== null && typeof val === "object" && val.constructor === Object;
359
+ const result = {};
360
+ for (const obj of objects) {
361
+ for (const key of Object.keys(obj)) {
362
+ const val = obj[key];
363
+ if (isPlainObject(val) && isPlainObject(result[key])) {
364
+ result[key] = merge(result[key], val);
365
+ } else {
366
+ result[key] = val;
367
+ }
368
+ }
369
+ }
370
+ return result;
371
+ };
372
+ var flattenObject = (obj, prefix = "") => {
373
+ const result = {};
374
+ for (const key of Object.keys(obj)) {
375
+ const fullKey = prefix ? `${prefix}.${key}` : key;
376
+ const val = obj[key];
377
+ if (val !== null && typeof val === "object" && val.constructor === Object) {
378
+ Object.assign(result, flattenObject(val, fullKey));
379
+ } else {
380
+ result[fullKey] = val;
381
+ }
382
+ }
383
+ return result;
384
+ };
385
+ var unflattenObject = (obj) => {
386
+ const result = {};
387
+ for (const key of Object.keys(obj)) {
388
+ const parts = key.split(".");
389
+ let current = result;
390
+ for (let i = 0;i < parts.length - 1; i++) {
391
+ if (!(parts[i] in current))
392
+ current[parts[i]] = {};
393
+ current = current[parts[i]];
394
+ }
395
+ current[parts[parts.length - 1]] = obj[key];
396
+ }
397
+ return result;
398
+ };
399
+ var isPlainObj = (val) => val !== null && typeof val === "object" && val.constructor === Object;
400
+ var deepEqual = (a, b) => {
401
+ if (a === b)
402
+ return true;
403
+ if (a == null || b == null)
404
+ return false;
405
+ if (typeof a !== typeof b)
406
+ return false;
407
+ if (Array.isArray(a) && Array.isArray(b)) {
408
+ if (a.length !== b.length)
409
+ return false;
410
+ return a.every((v, i) => deepEqual(v, b[i]));
411
+ }
412
+ if (isPlainObj(a) && isPlainObj(b)) {
413
+ const keysA = Object.keys(a);
414
+ const keysB = Object.keys(b);
415
+ if (keysA.length !== keysB.length)
416
+ return false;
417
+ return keysA.every((k) => keysB.includes(k) && deepEqual(a[k], b[k]));
418
+ }
419
+ return false;
420
+ };
421
+ var diff = (a, b) => {
422
+ const result = {};
423
+ const allKeys = new Set([...Object.keys(a), ...Object.keys(b)]);
424
+ for (const key of allKeys) {
425
+ const valA = a[key];
426
+ const valB = b[key];
427
+ if (deepEqual(valA, valB))
428
+ continue;
429
+ if (isPlainObj(valA) && isPlainObj(valB)) {
430
+ const nested = diff(valA, valB);
431
+ if (Object.keys(nested).length > 0) {
432
+ result[key] = nested;
433
+ }
434
+ } else {
435
+ result[key] = valB;
436
+ }
437
+ }
438
+ return result;
439
+ };
123
440
  // src/runtime/promise.ts
124
441
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
442
+ var retry = async (fn, options) => {
443
+ const { retries = 3, delay = 1000, backoff = false } = options ?? {};
444
+ let lastError;
445
+ for (let attempt = 0;attempt <= retries; attempt++) {
446
+ try {
447
+ return await fn();
448
+ } catch (error) {
449
+ lastError = error;
450
+ if (attempt < retries) {
451
+ const waitTime = backoff ? delay * Math.pow(2, attempt) : delay;
452
+ await sleep(waitTime);
453
+ }
454
+ }
455
+ }
456
+ throw lastError;
457
+ };
458
+ var timeout = (promise, ms, message) => Promise.race([
459
+ promise,
460
+ new Promise((_, reject) => setTimeout(() => reject(new Error(message ?? `Timed out after ${ms}ms`)), ms))
461
+ ]);
125
462
  // src/runtime/regex.ts
126
463
  var isEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
127
464
  var isUrl = (value) => /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/.test(value);
@@ -172,6 +509,48 @@ var toBytes = (size) => {
172
509
  return;
173
510
  }
174
511
  };
512
+ // src/runtime/string.ts
513
+ var reverse = (str) => [...str].reverse().join("");
514
+ var countOccurrences = (str, search) => {
515
+ if (search === "")
516
+ return 0;
517
+ let count = 0;
518
+ let pos = 0;
519
+ while ((pos = str.indexOf(search, pos)) !== -1) {
520
+ count++;
521
+ pos += search.length;
522
+ }
523
+ return count;
524
+ };
525
+ var pad = (str, length, char = " ", direction = "left") => {
526
+ if (str.length >= length)
527
+ return str;
528
+ const padChar = char[0] || " ";
529
+ switch (direction) {
530
+ case "right":
531
+ return str.padEnd(length, padChar);
532
+ case "both": {
533
+ const total = length - str.length;
534
+ const left = Math.floor(total / 2);
535
+ const right = total - left;
536
+ return padChar.repeat(left) + str + padChar.repeat(right);
537
+ }
538
+ default:
539
+ return str.padStart(length, padChar);
540
+ }
541
+ };
542
+ var mask = (str, visibleCount = 4, maskChar = "*") => {
543
+ if (str.length <= visibleCount)
544
+ return str;
545
+ const masked = maskChar[0].repeat(str.length - visibleCount);
546
+ return masked + str.slice(-visibleCount);
547
+ };
548
+ var initials = (name) => name.split(/\s+/).filter(Boolean).map((word) => word[0]).join("").toUpperCase();
549
+ var wordCount = (str) => {
550
+ const words = str.trim().split(/\s+/).filter(Boolean);
551
+ return str.trim() === "" ? 0 : words.length;
552
+ };
553
+ var isBlank = (str) => str.trim() === "";
175
554
  // src/runtime/time.ts
176
555
  var formatTime = (seconds) => {
177
556
  const hours = Math.floor(seconds / 3600);
@@ -187,15 +566,15 @@ var formatTime = (seconds) => {
187
566
  };
188
567
  var formatDuration = (ms) => {
189
568
  const sec = Math.floor(ms / 1000);
190
- const min = Math.floor(sec / 60);
191
- const hrs = Math.floor(min / 60);
569
+ const min2 = Math.floor(sec / 60);
570
+ const hrs = Math.floor(min2 / 60);
192
571
  const days = Math.floor(hrs / 24);
193
572
  if (days > 0)
194
573
  return `${days}d ${hrs % 24}h`;
195
574
  if (hrs > 0)
196
- return `${hrs}h ${min % 60}m`;
197
- if (min > 0)
198
- return `${min}m ${sec % 60}s`;
575
+ return `${hrs}h ${min2 % 60}m`;
576
+ if (min2 > 0)
577
+ return `${min2}m ${sec % 60}s`;
199
578
  return `${sec}s`;
200
579
  };
201
580
  var toSeconds = (time) => {
@@ -251,6 +630,13 @@ var isJSON = (value) => {
251
630
  return false;
252
631
  }
253
632
  };
633
+ var isFunction = (value) => typeof value === "function";
634
+ var isDate = (value) => value instanceof Date && !isNaN(value.getTime());
635
+ var isNumber = (value) => typeof value === "number" && !isNaN(value);
636
+ var isString = (value) => typeof value === "string";
637
+ var isBoolean = (value) => typeof value === "boolean";
638
+ var isNil = (value) => value === null || value === undefined;
639
+ var isRegExp = (value) => value instanceof RegExp;
254
640
  // src/runtime/url.ts
255
641
  var getQueryParams = (urlString) => {
256
642
  const url = new URL(urlString);
@@ -285,8 +671,10 @@ var buildUrl = (baseUrl, path, queryParams) => {
285
671
  return url.toString();
286
672
  };
287
673
  export {
674
+ wordCount,
288
675
  updateQueryParam,
289
676
  uniqueArray,
677
+ unflattenObject,
290
678
  unescapeHTML,
291
679
  truncate,
292
680
  toggleCase,
@@ -299,20 +687,49 @@ export {
299
687
  toConstantCase,
300
688
  toCamelCase,
301
689
  toBytes,
690
+ timeout,
691
+ throttle,
692
+ sum,
302
693
  stripTags,
694
+ splitWords,
695
+ sortBy,
303
696
  slugify,
304
697
  sleep,
698
+ shuffle,
699
+ sample,
700
+ round,
701
+ rgbToHex,
702
+ reverse,
703
+ retry,
305
704
  removeQueryParam,
705
+ range,
306
706
  rand,
707
+ pick,
307
708
  percentage,
709
+ pad,
710
+ once,
711
+ omit,
712
+ normalize,
713
+ noop,
714
+ min,
715
+ merge,
716
+ median,
717
+ max,
718
+ mask,
719
+ lighten,
720
+ last,
308
721
  isUrl,
309
722
  isUUID,
310
723
  isSupportedDisplayableMedia,
724
+ isString,
311
725
  isSlug,
726
+ isRegExp,
312
727
  isPrimitive,
313
728
  isPostalCode,
314
729
  isPhoneNumber,
315
730
  isObject,
731
+ isNumber,
732
+ isNil,
316
733
  isMacAddress,
317
734
  isJSON,
318
735
  isISODate,
@@ -320,24 +737,43 @@ export {
320
737
  isIPv4,
321
738
  isHexColor,
322
739
  isHex,
740
+ isFunction,
323
741
  isEqual,
324
742
  isEmpty,
325
743
  isEmail,
326
744
  isDomain,
745
+ isDate,
327
746
  isCreditCard,
747
+ isBoolean,
748
+ isBlank,
328
749
  isBase64,
329
750
  isArray,
751
+ intersection,
752
+ initials,
753
+ hexToRgb,
754
+ hash,
330
755
  hasDuplicates,
756
+ groupBy,
331
757
  getQueryParams,
758
+ generateId,
332
759
  formatTime,
333
760
  formatNumber,
334
761
  formatDuration,
335
762
  formatBytes,
763
+ flattenObject,
336
764
  escapeHTML,
765
+ difference,
766
+ diff,
767
+ debounce,
768
+ darken,
769
+ countOccurrences,
770
+ compact,
337
771
  clone,
338
772
  clamp,
773
+ chunk,
339
774
  catchError,
340
775
  capitalize,
341
776
  buildUrl,
777
+ average,
342
778
  SUPPORTED_DISPLAYABLE_MEDIA_TYPES
343
779
  };