wynkjs 1.0.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 (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +522 -0
  3. package/dist/database.d.ts +36 -0
  4. package/dist/database.d.ts.map +1 -0
  5. package/dist/database.js +162 -0
  6. package/dist/decorators/database.decorators.d.ts +55 -0
  7. package/dist/decorators/database.decorators.d.ts.map +1 -0
  8. package/dist/decorators/database.decorators.js +131 -0
  9. package/dist/decorators/exception.advanced.d.ts +160 -0
  10. package/dist/decorators/exception.advanced.d.ts.map +1 -0
  11. package/dist/decorators/exception.advanced.js +232 -0
  12. package/dist/decorators/exception.decorators.d.ts +121 -0
  13. package/dist/decorators/exception.decorators.d.ts.map +1 -0
  14. package/dist/decorators/exception.decorators.js +242 -0
  15. package/dist/decorators/guard.decorators.d.ts +43 -0
  16. package/dist/decorators/guard.decorators.d.ts.map +1 -0
  17. package/dist/decorators/guard.decorators.js +67 -0
  18. package/dist/decorators/http.decorators.d.ts +130 -0
  19. package/dist/decorators/http.decorators.d.ts.map +1 -0
  20. package/dist/decorators/http.decorators.js +209 -0
  21. package/dist/decorators/interceptor.advanced.d.ts +93 -0
  22. package/dist/decorators/interceptor.advanced.d.ts.map +1 -0
  23. package/dist/decorators/interceptor.advanced.js +228 -0
  24. package/dist/decorators/interceptor.decorators.d.ts +91 -0
  25. package/dist/decorators/interceptor.decorators.d.ts.map +1 -0
  26. package/dist/decorators/interceptor.decorators.js +163 -0
  27. package/dist/decorators/param.decorators.d.ts +144 -0
  28. package/dist/decorators/param.decorators.d.ts.map +1 -0
  29. package/dist/decorators/param.decorators.js +205 -0
  30. package/dist/decorators/pipe.advanced.d.ts +125 -0
  31. package/dist/decorators/pipe.advanced.d.ts.map +1 -0
  32. package/dist/decorators/pipe.advanced.js +263 -0
  33. package/dist/decorators/pipe.decorators.d.ts +226 -0
  34. package/dist/decorators/pipe.decorators.d.ts.map +1 -0
  35. package/dist/decorators/pipe.decorators.js +420 -0
  36. package/dist/dto.d.ts +83 -0
  37. package/dist/dto.d.ts.map +1 -0
  38. package/dist/dto.js +88 -0
  39. package/dist/factory.d.ts +76 -0
  40. package/dist/factory.d.ts.map +1 -0
  41. package/dist/factory.js +410 -0
  42. package/dist/index.d.ts +28 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +43 -0
  45. package/dist/pipes/validation.pipe.d.ts +91 -0
  46. package/dist/pipes/validation.pipe.d.ts.map +1 -0
  47. package/dist/pipes/validation.pipe.js +163 -0
  48. package/package.json +68 -0
@@ -0,0 +1,162 @@
1
+ /**
2
+ * WynkJS Database Pattern - EXAMPLE ONLY
3
+ *
4
+ * ⚠️ This file is NOT exported from WynkJS core.
5
+ * It's just an example pattern you can COPY to your project and customize.
6
+ *
7
+ * WHY NOT INCLUDED IN CORE?
8
+ * - Keeps WynkJS lightweight and fast (20x faster than NestJS!)
9
+ * - Gives you freedom to use ANY database library (Drizzle, Prisma, TypeORM, Mongoose, etc.)
10
+ * - No vendor lock-in
11
+ * - No unnecessary dependencies
12
+ *
13
+ * RECOMMENDED APPROACH:
14
+ * Use initializeDatabase() and getDatabase() from database.decorators.ts
15
+ * They're lightweight helpers already included in WynkJS core.
16
+ *
17
+ * BUT IF YOU PREFER A CLASS PATTERN, COPY THIS TO YOUR PROJECT:
18
+ */
19
+ export const DATABASE_CLASS_EXAMPLE = `
20
+ // src/db/database.ts (COPY THIS TO YOUR PROJECT)
21
+
22
+ import { Pool } from "pg";
23
+ import { drizzle } from "drizzle-orm/node-postgres";
24
+ import { userTable, otpTable } from '../users/tables';
25
+
26
+ const schema = { userTable, otpTable };
27
+
28
+ export class Database {
29
+ private static instance: any;
30
+ private static pool: Pool;
31
+
32
+ public static getInstance() {
33
+ if (!this.instance) {
34
+ this.pool = new Pool({
35
+ connectionString: process.env.DATABASE_URL!,
36
+ max: 20,
37
+ idleTimeoutMillis: 30000,
38
+ connectionTimeoutMillis: 2000,
39
+ ssl: { rejectUnauthorized: false },
40
+ });
41
+
42
+ this.instance = drizzle(this.pool, {
43
+ schema,
44
+ logger: true,
45
+ });
46
+
47
+ console.log("✅ Database connected");
48
+ }
49
+ return this.instance;
50
+ }
51
+
52
+ public static async close() {
53
+ if (this.pool) {
54
+ await this.pool.end();
55
+ this.instance = null;
56
+ console.log("Database connection closed");
57
+ }
58
+ }
59
+ }
60
+
61
+ // Usage in your index.ts:
62
+ // import { Database } from './db/database';
63
+ // const db = Database.getInstance();
64
+
65
+ // Usage in your services:
66
+ // import { Database } from '../db/database';
67
+ // const db = Database.getInstance();
68
+ // const users = await db.select().from(userTable);
69
+ `;
70
+ /**
71
+ * Example for other database libraries
72
+ */
73
+ export const PRISMA_EXAMPLE = `
74
+ // With Prisma (COPY TO YOUR PROJECT)
75
+
76
+ import { PrismaClient } from '@prisma/client';
77
+
78
+ export class Database {
79
+ private static instance: PrismaClient;
80
+
81
+ public static getInstance() {
82
+ if (!this.instance) {
83
+ this.instance = new PrismaClient();
84
+ console.log("✅ Prisma connected");
85
+ }
86
+ return this.instance;
87
+ }
88
+
89
+ public static async close() {
90
+ if (this.instance) {
91
+ await this.instance.$disconnect();
92
+ console.log("Prisma disconnected");
93
+ }
94
+ }
95
+ }
96
+ `;
97
+ export const TYPEORM_EXAMPLE = `
98
+ // With TypeORM (COPY TO YOUR PROJECT)
99
+
100
+ import { DataSource } from 'typeorm';
101
+ import { User, Post } from './entities';
102
+
103
+ export class Database {
104
+ private static instance: DataSource;
105
+
106
+ public static async getInstance() {
107
+ if (!this.instance) {
108
+ this.instance = new DataSource({
109
+ type: 'postgres',
110
+ url: process.env.DATABASE_URL,
111
+ entities: [User, Post],
112
+ synchronize: false,
113
+ });
114
+ await this.instance.initialize();
115
+ console.log("✅ TypeORM connected");
116
+ }
117
+ return this.instance;
118
+ }
119
+
120
+ public static async close() {
121
+ if (this.instance?.isInitialized) {
122
+ await this.instance.destroy();
123
+ console.log("TypeORM disconnected");
124
+ }
125
+ }
126
+ }
127
+ `;
128
+ export const MONGOOSE_EXAMPLE = `
129
+ // With Mongoose (COPY TO YOUR PROJECT)
130
+
131
+ import mongoose from 'mongoose';
132
+
133
+ export class Database {
134
+ public static async connect() {
135
+ if (mongoose.connection.readyState === 0) {
136
+ await mongoose.connect(process.env.MONGODB_URL!, {
137
+ maxPoolSize: 10,
138
+ });
139
+ console.log("✅ MongoDB connected");
140
+ }
141
+ }
142
+
143
+ public static async close() {
144
+ await mongoose.connection.close();
145
+ console.log("MongoDB disconnected");
146
+ }
147
+
148
+ public static getConnection() {
149
+ return mongoose.connection;
150
+ }
151
+ }
152
+ `;
153
+ /**
154
+ * README: How to use this file
155
+ *
156
+ * 1. Copy one of the examples above to your project (e.g., src/db/database.ts)
157
+ * 2. Customize it to your needs (connection string, pool config, etc.)
158
+ * 3. Import and use it in your services
159
+ *
160
+ * That's it! WynkJS doesn't force you to use any specific pattern.
161
+ * We give you the freedom to choose what works best for your project.
162
+ */
@@ -0,0 +1,55 @@
1
+ import "reflect-metadata";
2
+ /**
3
+ * Inject a table into constructor parameter
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * @injectable()
8
+ * class UserService {
9
+ * constructor(@InjectTable(userTable) private table: typeof userTable) {}
10
+ * }
11
+ * ```
12
+ */
13
+ export declare function InjectTable(table: any): ParameterDecorator;
14
+ /**
15
+ * Inject a model into constructor parameter
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * @injectable()
20
+ * class UserService {
21
+ * constructor(@InjectModel(User) private userModel: typeof User) {}
22
+ * }
23
+ * ```
24
+ */
25
+ export declare function InjectModel(model: any): ParameterDecorator;
26
+ /**
27
+ * Register multiple tables at once
28
+ * Call this at application startup
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * registerTables({
33
+ * userTable,
34
+ * postTable,
35
+ * commentTable,
36
+ * });
37
+ * ```
38
+ */
39
+ export declare function registerTables(tables: Record<string, any>): void;
40
+ /**
41
+ * Register multiple models at once
42
+ * Call this at application startup
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * registerModels({
47
+ * User,
48
+ * Post,
49
+ * Comment,
50
+ * });
51
+ * ```
52
+ */
53
+ export declare function registerModels(models: Record<string, any>): void;
54
+ export { injectable, inject, singleton, container } from "tsyringe";
55
+ //# sourceMappingURL=database.decorators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.decorators.d.ts","sourceRoot":"","sources":["../../core/decorators/database.decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAoE1B;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,GAAG,GAAG,kBAAkB,CAG1D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,GAAG,GAAG,kBAAkB,CAG1D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAOhE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAOhE;AAGD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,131 @@
1
+ import "reflect-metadata";
2
+ import { container, inject } from "tsyringe";
3
+ /**
4
+ * WynkJS Database Decorators
5
+ *
6
+ * Simple and lightweight decorators using tsyringe DI container.
7
+ * Works with ANY database pattern:
8
+ * - Drizzle ORM
9
+ * - Mongoose ODM
10
+ * - Prisma
11
+ * - TypeORM
12
+ * - Custom Database classes
13
+ *
14
+ * Usage:
15
+ * ```typescript
16
+ * @injectable()
17
+ * class UserService {
18
+ * constructor(@InjectTable(userTable) private table: typeof userTable) {}
19
+ * }
20
+ * ```
21
+ */
22
+ const TABLE_TOKEN_PREFIX = "TABLE_";
23
+ const MODEL_TOKEN_PREFIX = "MODEL_";
24
+ const TABLE_REGISTRY = new Map();
25
+ const MODEL_REGISTRY = new Map();
26
+ /**
27
+ * Create or get a unique token for a table
28
+ */
29
+ function getOrCreateTableToken(table) {
30
+ if (TABLE_REGISTRY.has(table)) {
31
+ return TABLE_REGISTRY.get(table);
32
+ }
33
+ // Generate a unique token
34
+ const token = TABLE_TOKEN_PREFIX + TABLE_REGISTRY.size;
35
+ TABLE_REGISTRY.set(table, token);
36
+ // Register the table immediately
37
+ if (!container.isRegistered(token)) {
38
+ container.register(token, { useValue: table });
39
+ }
40
+ return token;
41
+ }
42
+ /**
43
+ * Create or get a unique token for a model
44
+ */
45
+ function getOrCreateModelToken(model) {
46
+ if (MODEL_REGISTRY.has(model)) {
47
+ return MODEL_REGISTRY.get(model);
48
+ }
49
+ // Generate a unique token
50
+ const token = MODEL_TOKEN_PREFIX + MODEL_REGISTRY.size;
51
+ MODEL_REGISTRY.set(model, token);
52
+ // Register the model immediately
53
+ if (!container.isRegistered(token)) {
54
+ container.register(token, { useValue: model });
55
+ }
56
+ return token;
57
+ }
58
+ /**
59
+ * Inject a table into constructor parameter
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * @injectable()
64
+ * class UserService {
65
+ * constructor(@InjectTable(userTable) private table: typeof userTable) {}
66
+ * }
67
+ * ```
68
+ */
69
+ export function InjectTable(table) {
70
+ const token = getOrCreateTableToken(table);
71
+ return inject(token);
72
+ }
73
+ /**
74
+ * Inject a model into constructor parameter
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * @injectable()
79
+ * class UserService {
80
+ * constructor(@InjectModel(User) private userModel: typeof User) {}
81
+ * }
82
+ * ```
83
+ */
84
+ export function InjectModel(model) {
85
+ const token = getOrCreateModelToken(model);
86
+ return inject(token);
87
+ }
88
+ /**
89
+ * Register multiple tables at once
90
+ * Call this at application startup
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * registerTables({
95
+ * userTable,
96
+ * postTable,
97
+ * commentTable,
98
+ * });
99
+ * ```
100
+ */
101
+ export function registerTables(tables) {
102
+ for (const [name, table] of Object.entries(tables)) {
103
+ const token = getOrCreateTableToken(table);
104
+ if (!container.isRegistered(token)) {
105
+ container.register(token, { useValue: table });
106
+ }
107
+ }
108
+ }
109
+ /**
110
+ * Register multiple models at once
111
+ * Call this at application startup
112
+ *
113
+ * @example
114
+ * ```typescript
115
+ * registerModels({
116
+ * User,
117
+ * Post,
118
+ * Comment,
119
+ * });
120
+ * ```
121
+ */
122
+ export function registerModels(models) {
123
+ for (const [name, model] of Object.entries(models)) {
124
+ const token = getOrCreateModelToken(model);
125
+ if (!container.isRegistered(token)) {
126
+ container.register(token, { useValue: model });
127
+ }
128
+ }
129
+ }
130
+ // Re-export tsyringe decorators for convenience
131
+ export { injectable, inject, singleton, container } from "tsyringe";
@@ -0,0 +1,160 @@
1
+ import "reflect-metadata";
2
+ import { WynkExceptionFilter } from "./exception.decorators";
3
+ import { ExecutionContext } from "./guard.decorators";
4
+ import { NotFoundException, BadRequestException, UnauthorizedException, ForbiddenException } from "./exception.decorators";
5
+ /**
6
+ * Advanced Exception Filters for WynkJS Framework
7
+ * Specialized filters for different error scenarios
8
+ */
9
+ /**
10
+ * Validation Exception Filter - Handles validation errors
11
+ * @example
12
+ * @UseFilters(ValidationExceptionFilter)
13
+ * @Post()
14
+ * async create(@Body() data: any) {}
15
+ */
16
+ export declare class ValidationExceptionFilter implements WynkExceptionFilter<BadRequestException> {
17
+ catch(exception: BadRequestException, context: ExecutionContext): {
18
+ statusCode: number;
19
+ error: string;
20
+ message: string;
21
+ errors: any;
22
+ timestamp: string;
23
+ path: any;
24
+ };
25
+ }
26
+ /**
27
+ * Database Exception Filter - Handles database errors
28
+ * @example
29
+ * @UseFilters(DatabaseExceptionFilter)
30
+ * @Controller('/users')
31
+ * export class UserController {}
32
+ */
33
+ export declare class DatabaseExceptionFilter implements WynkExceptionFilter {
34
+ catch(exception: any, context: ExecutionContext): {
35
+ statusCode: number;
36
+ error: string;
37
+ message: string;
38
+ timestamp: string;
39
+ path: any;
40
+ };
41
+ }
42
+ /**
43
+ * Authentication Exception Filter - Handles auth errors
44
+ * @example
45
+ * @UseFilters(AuthenticationExceptionFilter)
46
+ * @Controller('/auth')
47
+ * export class AuthController {}
48
+ */
49
+ export declare class AuthenticationExceptionFilter implements WynkExceptionFilter<UnauthorizedException> {
50
+ catch(exception: UnauthorizedException, context: ExecutionContext): {
51
+ statusCode: number;
52
+ error: string;
53
+ message: string;
54
+ timestamp: string;
55
+ path: any;
56
+ hint: string;
57
+ };
58
+ }
59
+ /**
60
+ * Authorization Exception Filter - Handles permission errors
61
+ * @example
62
+ * @UseFilters(AuthorizationExceptionFilter)
63
+ * @Controller('/admin')
64
+ * export class AdminController {}
65
+ */
66
+ export declare class AuthorizationExceptionFilter implements WynkExceptionFilter<ForbiddenException> {
67
+ catch(exception: ForbiddenException, context: ExecutionContext): {
68
+ statusCode: number;
69
+ error: string;
70
+ message: string;
71
+ timestamp: string;
72
+ path: any;
73
+ requiredPermissions: any;
74
+ };
75
+ }
76
+ /**
77
+ * Not Found Exception Filter - Handles 404 errors
78
+ * @example
79
+ * @UseFilters(NotFoundExceptionFilter)
80
+ * @Get('/:id')
81
+ * async findOne(@Param('id') id: string) {}
82
+ */
83
+ export declare class NotFoundExceptionFilter implements WynkExceptionFilter<NotFoundException> {
84
+ catch(exception: NotFoundException, context: ExecutionContext): {
85
+ statusCode: number;
86
+ error: string;
87
+ message: string;
88
+ timestamp: string;
89
+ path: any;
90
+ suggestion: string;
91
+ };
92
+ }
93
+ /**
94
+ * Rate Limit Exception Filter - Handles rate limit errors
95
+ * @example
96
+ * @UseFilters(RateLimitExceptionFilter)
97
+ * @Post()
98
+ * async create() {}
99
+ */
100
+ export declare class RateLimitExceptionFilter implements WynkExceptionFilter {
101
+ catch(exception: any, context: ExecutionContext): {
102
+ statusCode: number;
103
+ error: string;
104
+ message: any;
105
+ timestamp: string;
106
+ path: any;
107
+ retryAfter: any;
108
+ hint: string;
109
+ };
110
+ }
111
+ /**
112
+ * Business Logic Exception Filter - Handles business rule violations
113
+ * @example
114
+ * @UseFilters(BusinessLogicExceptionFilter)
115
+ * @Post('/transfer')
116
+ * async transfer(@Body() data: any) {}
117
+ */
118
+ export declare class BusinessLogicExceptionFilter implements WynkExceptionFilter {
119
+ catch(exception: any, context: ExecutionContext): {
120
+ statusCode: any;
121
+ error: string;
122
+ message: any;
123
+ timestamp: string;
124
+ path: any;
125
+ rule: any;
126
+ details: any;
127
+ };
128
+ }
129
+ /**
130
+ * File Upload Exception Filter - Handles file upload errors
131
+ * @example
132
+ * @UseFilters(FileUploadExceptionFilter)
133
+ * @Post('/upload')
134
+ * async upload(@UploadedFile() file: any) {}
135
+ */
136
+ export declare class FileUploadExceptionFilter implements WynkExceptionFilter {
137
+ catch(exception: any, context: ExecutionContext): {
138
+ statusCode: number;
139
+ error: string;
140
+ message: string;
141
+ timestamp: string;
142
+ path: any;
143
+ };
144
+ }
145
+ /**
146
+ * Global Exception Filter - Catches all unhandled exceptions
147
+ * @example
148
+ * app.useGlobalFilters(new GlobalExceptionFilter());
149
+ */
150
+ export declare class GlobalExceptionFilter implements WynkExceptionFilter {
151
+ catch(exception: any, context: ExecutionContext): {
152
+ stack?: any;
153
+ statusCode: any;
154
+ error: any;
155
+ message: any;
156
+ timestamp: string;
157
+ path: any;
158
+ };
159
+ }
160
+ //# sourceMappingURL=exception.advanced.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exception.advanced.d.ts","sourceRoot":"","sources":["../../core/decorators/exception.advanced.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAEL,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAEnB,MAAM,wBAAwB,CAAC;AAEhC;;;GAGG;AAEH;;;;;;GAMG;AACH,qBAAa,yBACX,YAAW,mBAAmB,CAAC,mBAAmB,CAAC;IAEnD,KAAK,CAAC,SAAS,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB;;;;;;;;CAahE;AAED;;;;;;GAMG;AACH,qBAAa,uBAAwB,YAAW,mBAAmB;IACjE,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,gBAAgB;;;;;;;CAiChD;AAED;;;;;;GAMG;AACH,qBAAa,6BACX,YAAW,mBAAmB,CAAC,qBAAqB,CAAC;IAErD,KAAK,CAAC,SAAS,EAAE,qBAAqB,EAAE,OAAO,EAAE,gBAAgB;;;;;;;;CAalE;AAED;;;;;;GAMG;AACH,qBAAa,4BACX,YAAW,mBAAmB,CAAC,kBAAkB,CAAC;IAElD,KAAK,CAAC,SAAS,EAAE,kBAAkB,EAAE,OAAO,EAAE,gBAAgB;;;;;;;;CAe/D;AAED;;;;;;GAMG;AACH,qBAAa,uBACX,YAAW,mBAAmB,CAAC,iBAAiB,CAAC;IAEjD,KAAK,CAAC,SAAS,EAAE,iBAAiB,EAAE,OAAO,EAAE,gBAAgB;;;;;;;;CAa9D;AAED;;;;;;GAMG;AACH,qBAAa,wBAAyB,YAAW,mBAAmB;IAClE,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,gBAAgB;;;;;;;;;CAchD;AAED;;;;;;GAMG;AACH,qBAAa,4BAA6B,YAAW,mBAAmB;IACtE,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,gBAAgB;;;;;;;;;CAchD;AAED;;;;;;GAMG;AACH,qBAAa,yBAA0B,YAAW,mBAAmB;IACnE,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,gBAAgB;;;;;;;CAsBhD;AAED;;;;GAIG;AACH,qBAAa,qBAAsB,YAAW,mBAAmB;IAC/D,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,gBAAgB;;;;;;;;CA2BhD"}