npm package: @libs-ui/utils
Description: > Thư viện tập trung toàn bộ **utility functions** dùng chung cho các libs-ui trong project.
Latest version: 0.2.356-23

# @libs-ui/utils

> Thư viện tập trung toàn bộ **utility functions** dùng chung cho các libs-ui trong project.

**Version**: `0.2.355-10`

## Giới thiệu

Thư viện `@libs-ui/utils` cung cấp các hàm tiện ích dùng chung (format, transform, validate...) để:

- Giảm trùng lặp code utility trong nhiều libs khác nhau
- Dễ bảo trì và mở rộng khi cần thêm utility mới
- Chuẩn hóa cách xử lý dữ liệu trong toàn bộ project

## Cài đặt

```bash
npm install @libs-ui/utils
# hoặc
yarn add @libs-ui/utils
```

## Sử dụng

### Import

```typescript
import {
  isNil,
  isEmpty,
  get,
  set,
  cloneDeep,
  keyBy,
  groupBy,
  range,
  isEqual,
  uniqBy,
  base64Encode,
  base64Decode,
  convertBase64ToBlob,
  convertFileToBase64,
  UtilsCache,
  addArrayToSet,
  convertSetToArray,
  colorContrastFromOrigin,
  getColorById,
  detectAndCleanNearWhiteColors,
  UtilsCommunicateMicro,
  encrypt3rd,
  decrypt3rd,
  setKeyCrypto3rd,
  encrypt,
  decrypt,
  setKeyCrypto,
  md5,
  isDangerousObject,
  isPrimitiveType,
  isDOMObject,
  isFrameworkObject,
  getObjectSize,
  getDayjs,
  formatDate,
  isDifferenceDay,
  setDefaultTimeZone,
  getDeviceInfo,
  isTouchDevice,
  getViewport,
  setStylesElement,
  downloadFileByUrl,
  downloadFileByUrlUseXmlRequest,
} from '@libs-ui/utils';
```

### Ví dụ cơ bản

#### Base64 & File

````typescript
import { base64Encode, base64Decode, convertFileToBase64 } from '@libs-ui/utils';

// Mã hóa Unicode an toàn
const encoded = base64Encode('Xin chào 👋');
const decoded = base64Decode(encoded); // 'Xin chào 👋'

// Chuyển File sang Base64 để preview
const base64 = await convertFileToBase64(file);
// data:image/png;base64,iVBORw...

#### Language
```typescript
import { UtilsLanguageConstants } from '@libs-ui/utils';

// Dùng hằng số thay vì hardcode chuỗi
const viCode = UtilsLanguageConstants.VI;  // 'vi'
const enCode = UtilsLanguageConstants.EN;  // 'en'
const jaCode = UtilsLanguageConstants.JA;  // 'ja'

// Tự động phát hiện ngôn ngữ trình duyệt (fallback về 'en')
const lang = UtilsLanguageConstants.defaultLang();

// Kiểm tra hỗ trợ
UtilsLanguageConstants.isSupported('vi');  // true
UtilsLanguageConstants.isSupported('xx');  // false

// Tùy chỉnh danh sách ngôn ngữ hỗ trợ (gọi một lần lúc khởi động)
UtilsLanguageConstants.setSupportedLanguages(['vi', 'en']);

#### Random & String Protection
```typescript
import { protectString, revealString, createUniqueRandomIntGenerator } from '@libs-ui/utils';

// Obfuscate nhẹ cổng giao tiếp
const hidden = protectString('user-token-abc123');
const plain  = revealString(hidden); // 'user-token-abc123'

// Round-trip luôn trả về cỗi gốc
console.log(revealString(protectString('Xin chào')) === 'Xin chào'); // true

// Tạo số ngẫu nhiên không trùng trong 10 lần gần nhất
const nextId = createUniqueRandomIntGenerator(1, 100);
console.log(nextId()); // 42
console.log(nextId()); // 17  (khác 42)

#### Cache
```typescript
import { UtilsCache } from '@libs-ui/utils';

// LocalStorage (Đồng bộ)
UtilsCache.Set('key', { a: 1 }, 3600); // 1 giờ
const data = UtilsCache.Get('key');

// IndexedDB (Bất đồng bộ)
await UtilsCache.SetAsync('large_key', data);
const asyncData = await UtilsCache.GetAsync('large_key');

#### Collection
```typescript
import { addArrayToSet, convertSetToArray } from '@libs-ui/utils';

const s = new Set([1]);
addArrayToSet(s, [1, 2, 3]); // Set {1, 2, 3}

const arr = convertSetToArray(s, v => `Item ${v}`); // ["Item 1", "Item 2", "Item 3"]

#### Color
```typescript
import { colorContrastFromOrigin, getColorById } from '@libs-ui/utils';

// Tạo bảng màu
const palette = colorContrastFromOrigin('#226FF5');

// Lấy màu định danh theo ID
const userColor = getColorById('user_id_123');

/* ... */

#### Communicate Micro
```typescript
import { UtilsCommunicateMicro } from '@libs-ui/utils';

// Khởi tạo tại AppComponent
UtilsCommunicateMicro.initEvent(window, destroyRef);

// Lắng nghe
UtilsCommunicateMicro.GetMessage('DATA_SYNC').subscribe(e => {
  console.log(e.data.response);
});

// Gửi cho cha (ví dụ từ Iframe)
UtilsCommunicateMicro.PostMessageToParent({ type: 'DATA_SYNC', response: { id: 1 } });

#### Crypto 3rd
```typescript
import { encrypt3rd, decrypt3rd, setKeyCrypto3rd } from '@libs-ui/utils';

// Setup key (một lần)
setKeyCrypto3rd('12345678901234567890123456789012');

// Mã hóa
const secret = encrypt3rd('My Secret Data');

// Giải mã
const original = decrypt3rd(secret);

#### Crypto
```typescript
import { encrypt, decrypt, md5 } from '@libs-ui/utils';

// AES Internal
const secureData = encrypt('Secret');
const plain = decrypt(secureData);

// MD5 Hash
const hash = md5('hello');

#### Dangerous Object
```typescript
import { isDangerousObject, isPrimitiveType } from '@libs-ui/utils';

isDangerousObject(window); // true
isDangerousObject(document.body); // true
isPrimitiveType(123); // true
isPrimitiveType({}); // false

#### Data
```typescript
import { getObjectSize } from '@libs-ui/utils';

const size = getObjectSize({ a: 1 }); // "10 bytes"

#### Date
```typescript
import { formatDate, getDayjs } from '@libs-ui/utils';

// Format tiếng Việt
formatDate('2024-05-20', 'dmy', 'vi'); // "20 Thg 5, 2024"

// Lấy đối tượng Day.js (local timezone)
const now = getDayjs();

#### DOM
```typescript
import { getViewport, isTouchDevice } from '@libs-ui/utils';

const { width, height } = getViewport();
const isTouch = isTouchDevice();

#### Download
```typescript
import { downloadFileByUrl } from '@libs-ui/utils';

// Tải file PDF từ server
await downloadFileByUrl('https://example.com/report.pdf', 'report.pdf');

// Chỉ mở tầ mới (không download)
await downloadFileByUrl('https://example.com/doc.pdf', 'preview.pdf', true);

#### Regex Patterns
```typescript
import { patternEmail, patternMobilePhone, patternUrl } from '@libs-ui/utils';

// Kiểm tra email
const emailRe = patternEmail();
emailRe.test('user@gmail.com'); // true

// Kiểm tra số điện thoại VN
patternMobilePhone().test('0987654321'); // true

// Match pattern cụ thể
const templateRe = patternRuleFieldReplace(); // /[{]{2}[a-zA-Z_-]+[}]{2}/g
'hello {{name}}'.match(templateRe); // ['{{name}}']
```

#### Trace Stack
```typescript
import { traceStack } from '@libs-ui/utils';

function a() {
  b();
}

function b() {
  console.log(traceStack());
  // Output: ["a", "b"] (đã lọc các frame rác)
}
```

#### Two-Way Signal Object
```typescript
import { convertObjectToSignal, convertSignalToObject } from '@libs-ui/utils';

const obj = { name: 'Alice' };
const reactive = convertObjectToSignal<any>(obj);

reactive().name.set('Bob');

const plain = convertSignalToObject(reactive);
console.log(plain.name); // 'Bob'
```

#### URI
```typescript
import { encodeURI, decodeURI, endCodeUrl } from '@libs-ui/utils';

// Mã hóa/Giải mã
const encoded = encodeURI('Xin chào & Hẹn gặp lại!');
const decoded = decodeURI(encoded);

// Query String builder
const qs = endCodeUrl({ id: 1, q: 'tag' }, false); // "?id=1&q=tag"

#### URL
```typescript
import { normalizeUrl } from '@libs-ui/utils';

// Chuẩn hóa đường dẫn URL (gộp dấu // dư thừa)
const clean = normalizeUrl('http://example.com//api///users');
// Output: "http://example.com/api/users"
```

#### UUID
```typescript
import { uuid } from '@libs-ui/utils';

// Tạo unique ID (MD5 hash - 32 character)
const newId = uuid();
// Output: "a1b2c3d4..."
```

#### XSS Filter
```typescript
import { updateFunctionXssFilter, xssFilter } from '@libs-ui/utils';
import DOMPurify from 'dompurify';

// 1. Cấu hình ban đầu (Ví dụ: trong app.component.ts)
updateFunctionXssFilter(async (data: string) => DOMPurify.sanitize(data));

// 2. Sử dụng ở mọi nơi để làm sạch HTML
const cleanHTML = await xssFilter('<script>evil()</script><b>Good</b>');
// Output: "<b>Good</b>"
```

#### URL Search Params
```typescript
import { UtilsUrlSearchParams } from '@libs-ui/utils';

const usp = new UtilsUrlSearchParams('?id=1&name=test');
console.log(usp.get('id')); // "1"

usp.set('page', '2');
console.log(usp.toString()); // "id=1&name=test&page=2"
```
```
```
```
```
```
```
```
```
```
````

````

#### Kiểm tra giá trị

```typescript
import { isNil, isEmpty, isTruthy, isFalsy } from '@libs-ui/utils';

// Kiểm tra null/undefined
isNil(null); // true
isNil(undefined); // true
isNil(0); // false

// Kiểm tra rỗng
isEmpty(null); // true
isEmpty(''); // true
isEmpty({}); // true
isEmpty([]); // true
isEmpty({ a: 1 }); // false
```

#### Thao tác Object

```typescript
import { get, set, cloneDeep } from '@libs-ui/utils';

const user = {
  profile: {
    name: 'John',
    address: { city: 'Hanoi' },
  },
};

// Lấy giá trị theo path
get(user, 'profile.name'); // 'John'
get(user, 'profile.address.city'); // 'Hanoi'
get(user, 'profile.email', 'N/A'); // 'N/A' (default value)

// Thiết lập giá trị theo path
set(user, 'profile.name', 'Jane');
set(user, 'profile.age', 25);

// Clone sâu
const cloned = cloneDeep(user);
cloned.profile.name = 'Bob'; // Không ảnh hưởng user gốc
```

#### Thao tác Array

```typescript
import { keyBy, groupBy, range, uniqBy, isEqual } from '@libs-ui/utils';

const users = [
  { id: 1, name: 'John', type: 'admin' },
  { id: 2, name: 'Jane', type: 'user' },
  { id: 3, name: 'Bob', type: 'admin' },
];

// Chuyển array thành object
keyBy(users, 'id');
// { "1": {id:1,name:"John",type:"admin"}, "2": {...}, "3": {...} }

// Nhóm theo type
groupBy(users, 'type');
// { "admin": [{...}, {...}], "user": [{...}] }

// Tạo mảng số
range(5); // [0, 1, 2, 3, 4]
range(1, 5); // [1, 2, 3, 4]
range(0, 10, 2); // [0, 2, 4, 6, 8]

// Loại bỏ trùng lặp
uniqBy([{ id: 1 }, { id: 2 }, { id: 1 }], 'id'); // [{id:1}, {id:2}]

// So sánh deep equality
isEqual({ a: 1, b: 2 }, { a: 1, b: 2 }); // true
isEqual([1, 2, 3], [1, 2, 3]); // true
```

#### HTTP Query Params (Type-Safe)

```typescript
import { UtilsHttpParamsRequest, UtilsHttpParamsRequestInstance } from '@libs-ui/utils';

// Định nghĩa interface cho params
interface SearchParams {
  keyword: string;
  page: number;
  size: number;
}

// 1. Dùng fromObject với type safety
const params = new UtilsHttpParamsRequest<SearchParams>({
  fromObject: { keyword: 'Angular', page: 1, size: 20 },
});
params.toString(); // keyword=Angular&page=1&size=20

// 2. Factory function (không cần new)
const params2 = UtilsHttpParamsRequestInstance<SearchParams>({
  fromObject: { keyword: 'Angular', page: 1, size: 20 },
});

// 3. Method chaining
const params3 = new UtilsHttpParamsRequest().set('page', 1).set('size', 10).set('sort', 'name');

params3.delete('sort');
params3.toString(); // page=1&size=10

// 4. Wrap HttpParams có sẵn
import { HttpParams } from '@angular/common/http';
const base = new HttpParams().set('version', 'v2');
const wrapped = new UtilsHttpParamsRequest(undefined, base);
wrapped.get('version'); // 'v2'
```

#### GET_PATH_VARIABLE — Type-Safe Path Params

```typescript
import { GET_PATH_VARIABLE } from '@libs-ui/utils';

interface UserResource {
  userId: number;
  orgId: string;
}

// Tạo type với pattern "pathVariable-{key}"
type UserPathParams = GET_PATH_VARIABLE<UserResource>;
// Tương đương: { "pathVariable-userid": number; "pathVariable-orgid": string }

const pathParams: UserPathParams = {
  'pathVariable-userid': 123,
  'pathVariable-orgid': 'org-abc',
};
```

## Important Notes

⚠️ **Lưu ý quan trọng khi sử dụng**:

- Các functions hỗ trợ unwrap Signal tự động (trừ khi dùng option `ignoreUnWrapSignal`).
- `get()` và `set()` hỗ trợ path dạng string (vd: `"user.profile.name"`) hoặc array (vd: `["user", "profile", "name"]`).
- `cloneDeep()` có thể clone Signal, Date, RegExp, Map, Set và các object phức tạp khác.
- `isEqual()` có thể so sánh deep equality cho objects và arrays.
- `UtilsHttpParamsRequest` kế thừa `HttpParams` — compatible 100% với Angular HttpClient.
- `HttpParams` của Angular là **immutable**; `UtilsHttpParamsRequest` xử lý điều này nội bộ (tự assign lại `this.params` sau mỗi mutation).

## API Reference

Xem chi tiết API tại [Documentation](./docs/utils/utils.md) hoặc [Demo Live](http://localhost:4500/utils/helpers).

### Các Functions chính

| Function                                                | Mô tả                                        |
| ------------------------------------------------------- | -------------------------------------------- |
| `isNil(value, options?)`                                | Kiểm tra giá trị có phải null hoặc undefined |
| `isEmpty(value, options?)`                              | Kiểm tra giá trị có rỗng không               |
| `isTruthy(value, options?)`                             | Kiểm tra giá trị truthy                      |
| `isFalsy(value, options?)`                              | Kiểm tra giá trị falsy                       |
| `get(obj, path, defaultValue?, keepLastValueIfSignal?)` | Lấy giá trị theo path                        |
| `set(obj, path, value, options?)`                       | Thiết lập giá trị theo path                  |
| `cloneDeep(data, options?, seen?)`                      | Clone sâu object/array                       |
| `keyBy(data, key)`                                      | Chuyển array thành object                    |
| `groupBy(data, key)`                                    | Nhóm array theo key                          |
| `range(start, end?, step?)`                             | Tạo mảng số                                  |
| `isEqual(value1, value2, options?)`                     | So sánh deep equality                        |
| `uniqBy(data, key?)`                                    | Loại bỏ trùng lặp                            |
| `omitBy(objData, predicate)`                            | Loại bỏ thuộc tính theo điều kiện            |
| `generateInterface(obj, interfaceName)`                 | Tạo interface từ object                      |
| `base64Encode(value)`                                   | Mã hóa Base64 (hỗ trợ Unicode)               |
| `base64Decode(value)`                                   | Giải mã Base64 (hỗ trợ Unicode)              |
| `convertBase64ToBlob(data)`                             | Chuyển Base64 sang Blob                      |
| `convertFileToBase64(file)`                             | Chuyển File sang Base64 string               |
| `UtilsCache`                                            | Quản lý Cache (Sync & Async)                 |
| `addArrayToSet(set, data)`                              | Thêm mảng vào Set                            |
| `convertSetToArray(set, map?)`                          | Chuyển Set sang Array                        |
| `colorContrastFromOrigin(color)`                        | Tạo bảng sắc độ (shades/tints)               |
| `getColorById(str)`                                     | Hash chuỗi thành màu cố định                 |
| `detectAndCleanNearWhiteColors(style)`                  | Làm sạch CSS style khỏi màu gần trắng        |
| `UtilsCommunicateMicro`                                 | Giao tiếp Cross-window (mã hóa)              |
| `encrypt3rd(data)`                                      | Mã hóa AES-CBC                               |
| `decrypt3rd(data)`                                      | Giải mã AES-CBC                              |
| `encrypt(data)`                                         | Mã hóa AES nội bộ                            |
| `md5(data)`                                             | Hash MD5                                     |
| `isDangerousObject(obj)`                                | Kiểm tra Window/DOM/Global                   |
| `isPrimitiveType(val)`                                  | Kiểm tra kiểu dữ liệu nguyên thủy            |
| `getObjectSize(obj)`                                    | Đo dung lượng object                         |
| `formatDate(date, format?)`                             | Định dạng ngày tháng                         |
| `getDayjs(config?)`                                     | Khởi tạo Day.js instance                     |
| `getDeviceInfo()`                                       | Lấy thông tin thiết bị                       |
| `isTouchDevice()`                                       | Kiểm tra thiết bị cảm ứng                    |
| `getViewport()`                                         | Lấy kích thước Viewport                      |
| `downloadFileByUrl(url, name, onlyOpen?)`               | Tải file từ URL                              |
| `downloadFileByUrlUseXmlRequest(url, name)`             | Tải file bằng XMLHttpRequest                 |
| `downloadImageFromELement(img, type?, name?)`           | Lưu ảnh từ thẻ img                           |
| `isTypeImage(file)`                                     | Kiểm tra Blob/File là ảnh                    |
| `isTypeVideo(file)`                                     | Kiểm tra Blob/File là video                  |
| `getFileExtension(file)`                                | Lấy extension của file                       |
| `getLabelBySizeFile(size, toFixed?)`                    | Format kích thước byte                       |
| `convertBlobToFile(blob, name?)`                        | Chuyển Blob thành File                       |
| `formatNumber(value)`                                   | Chuẩn hóa chuỗi số theo locale               |
| `viewDataNumberByLanguage(val, neg, fixed?, ...)`       | Định dạng số theo VI/EN locale               |
| `UtilsLanguageConstants.{KEY}`                          | Hằng số mã ngôn ngữ ISO 639-1 (27 ngôn ngữ) |
| `UtilsLanguageConstants.defaultLang()`                  | Tự dò ngôn ngữ trình duyệt, fallback 'en'   |
| `UtilsLanguageConstants.isSupported(lang)`              | Kiểm tra ngôn ngữ có được hỗ trợ                |
| `UtilsLanguageConstants.setSupportedLanguages(langs)`   | Ghi đè danh sách ngôn ngữ hỗ trợ             |
| `protectString(input)`                                  | XOR + reverse + base64 encode (obfuscation) |
| `revealString(encoded)`                                 | Giải mã ngược lại protectString               |
| `createUniqueRandomIntGenerator(min, max)`              | Factory tạo số ngẫu nhiên không trùng (10 lần) |
| `patternEmail()`                                        | Regex kiểm tra email chuẩn                   |
| `patternUrl()`                                          | Regex kiểm tra URL đầy đủ                    |
| `patternMobilePhone()`                                  | Regex kiểm tra SĐT di động Việt Nam          |
| `patternNameUtf8()`                                     | Regex hỗ trợ tên tiếng Việt có dấu           |
| `patternEmoji()`                                        | Regex phát hiện ký tự emoji (global)         |
| `traceStack()`                                          | Trích xuất call stack sạch (lọc rác)         |
| `convertObjectToSignal()`                               | Biến object thành cấu trúc Signals lồng nhau |
| `convertSignalToObject()`                               | Chuyển cấu trúc signals về plain object      |
| `unwrapSignal()`                                        | Lấy giá trị cuối cùng từ (lồng) signal       |
| `normalizeUrl(rawUrl)`                                  | Chuẩn hóa URL, gộp dấu // trong pathname     |
| `uuid()`                                                | Tạo chuỗi định danh duy nhất (MD5 hash)      |
| `xssFilter(data)`                                       | Lọc chuỗi HTML khỏi XSS thông qua hàm custom |
| `updateFunctionXssFilter(fn)`                           | Cập nhật custom implementation cho xssFilter |

## Demo

- **Local Utilities**: [http://localhost:4500/utils/helpers](http://localhost:4500/utils/helpers)
- **Local Base64**: [http://localhost:4500/utils/base64](http://localhost:4500/utils/base64)
- **Local Cache**: [http://localhost:4500/utils/cache](http://localhost:4500/utils/cache)
- **Local Collection**: [http://localhost:4500/utils/collection](http://localhost:4500/utils/collection)
- **Local Color**: [http://localhost:4500/utils/color](http://localhost:4500/utils/color)
- **Local Micro Comms**: [http://localhost:4500/utils/communicate-micro](http://localhost:4500/utils/communicate-micro)
- **Local Crypto 3rd**: [http://localhost:4500/utils/crypto-3rd](http://localhost:4500/utils/crypto-3rd)
- **Local Crypto**: [http://localhost:4500/utils/crypto](http://localhost:4500/utils/crypto)
- **Local Dangerous Object**: [http://localhost:4500/utils/dangerous-object](http://localhost:4500/utils/dangerous-object)
- **Local Data**: [http://localhost:4500/utils/data](http://localhost:4500/utils/data)
- **Local Date**: [http://localhost:4500/utils/date](http://localhost:4500/utils/date)
- **Local DOM**: [http://localhost:4500/utils/dom](http://localhost:4500/utils/dom)
- **Local Download**: [http://localhost:4500/utils/download](http://localhost:4500/utils/download)
- **Local File**: [http://localhost:4500/utils/file](http://localhost:4500/utils/file)
- **Local Format Number**: [http://localhost:4500/utils/format-number](http://localhost:4500/utils/format-number)
- **Local Format Text**: [http://localhost:4500/utils/format-text](http://localhost:4500/utils/format-text)
- **Local Embed Frame**: [http://localhost:4500/utils/embed-frame](http://localhost:4500/utils/embed-frame)
- **Local Smart Axis Scale**: [http://localhost:4500/utils/smart-axis-scale](http://localhost:4500/utils/smart-axis-scale)
- **Local Language**: [http://localhost:4500/utils/language](http://localhost:4500/utils/language)
- **Local Random & String Protection**: [http://localhost:4500/utils/random](http://localhost:4500/utils/random)
- **Local Patterns (Regex)**: [http://localhost:4500/utils/pattern](http://localhost:4500/utils/pattern)
- **Local Trace Stack**: [http://localhost:4500/utils/trace](http://localhost:4500/utils/trace)
- **Local Two-Way Signal Object**: [http://localhost:4500/utils/two-way-signal-object](http://localhost:4500/utils/two-way-signal-object)
- **Local URI Utilities**: [http://localhost:4500/utils/uri](http://localhost:4500/utils/uri)
- **Local URL Utilities**: [http://localhost:4500/utils/url](http://localhost:4500/utils/url)
- **Local URL Search Params**: [http://localhost:4500/utils/url-search-params](http://localhost:4500/utils/url-search-params)
- **Local UUID Utilities**: [http://localhost:4500/utils/uuid](http://localhost:4500/utils/uuid)
- **Local Xss Filter Utilities**: [http://localhost:4500/utils/xss-filter](http://localhost:4500/utils/xss-filter)

### HTTP Params

| Class / Type                              | Mô tả                                                                                          |
| ----------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `UtilsHttpParamsRequest<Type>`            | Wrapper type-safe cho Angular HttpParams — hỗ trợ method chaining, fromObject với generic type |
| `UtilsHttpParamsRequestInstance<Type>()`  | Factory function tạo `UtilsHttpParamsRequest` không cần `new`                                  |
| `GET_PATH_VARIABLE<TypePath, TypeOther?>` | Utility type tạo map path-variable từ interface (pattern: `pathVariable-{key}`)                |
| `HttpParamsOptions<Type>`                 | Interface options cho constructor (`fromString`, `fromObject`, `encoder`)                      |

### InjectionTokens

| Token                                              | Mô tả                                                 |
| -------------------------------------------------- | ----------------------------------------------------- |
| `LINK_IMAGE_ERROR_TOKEN_INJECT`                    | InjectionToken cho link ảnh fallback                  |
| `PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT` | InjectionToken cấu hình mặc định process bar standard |
| `PROCESS_BAR_STEPS_CONFIG_DEFAULT_TOKEN_INJECT`    | InjectionToken cấu hình mặc định process bar steps    |

## Demo

- **Helpers utilities**: [http://localhost:4500/utils/helpers](http://localhost:4500/utils/helpers)
- **HTTP Params**: [http://localhost:4500/utils/http-params](http://localhost:4500/utils/http-params)
- **Injection Tokens**: [http://localhost:4500/utils/inject-token](http://localhost:4500/utils/inject-token)
- **Key Cache**: [http://localhost:4500/utils/key-cache](http://localhost:4500/utils/key-cache)
- **Key Code**: [http://localhost:4500/utils/key-code](http://localhost:4500/utils/key-code)
- **Production**: (Chưa có)

## Công nghệ sử dụng

- **Angular**: >=18.0.0
- **TypeScript**: Latest
- **RxJS**: ~7.8.0
- **dayjs**: 1.11.5
- **crypto-es**: ^2.1.0

## Tài liệu

Xem thêm tài liệu chi tiết tại [docs/utils/utils.md](../../docs/utils/utils.md).
````