@studious-lms/server 1.1.2 → 1.1.4

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/index.js CHANGED
@@ -8,13 +8,56 @@ import { appRouter } from './routers/_app.js';
8
8
  import { createTRPCContext, createCallerFactory } from './trpc.js';
9
9
  import { logger } from './utils/logger.js';
10
10
  import { setupSocketHandlers } from './socket/handlers.js';
11
+ import { bucket } from './lib/googleCloudStorage.js';
11
12
  dotenv.config();
12
13
  const app = express();
13
14
  // CORS middleware
14
15
  app.use(cors({
15
- origin: [process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000', 'http://localhost:3000'],
16
+ origin: [
17
+ 'http://localhost:3000', // Frontend development server
18
+ 'http://localhost:3001', // Server port
19
+ 'http://127.0.0.1:3000', // Alternative localhost
20
+ 'http://127.0.0.1:3001', // Alternative localhost
21
+ process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
22
+ ],
16
23
  credentials: true,
24
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
25
+ allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'x-user'],
26
+ optionsSuccessStatus: 200
17
27
  }));
28
+ // Handle preflight OPTIONS requests
29
+ app.options('*', (req, res) => {
30
+ const allowedOrigins = [
31
+ 'http://localhost:3000',
32
+ 'http://localhost:3001',
33
+ 'http://127.0.0.1:3000',
34
+ 'http://127.0.0.1:3001',
35
+ process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
36
+ ];
37
+ const origin = req.headers.origin;
38
+ if (origin && allowedOrigins.includes(origin)) {
39
+ res.header('Access-Control-Allow-Origin', origin);
40
+ }
41
+ else {
42
+ res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
43
+ }
44
+ res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
45
+ res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, x-user');
46
+ res.header('Access-Control-Allow-Credentials', 'true');
47
+ res.sendStatus(200);
48
+ });
49
+ // CORS debugging middleware
50
+ app.use((req, res, next) => {
51
+ if (req.method === 'OPTIONS' || req.path.includes('trpc')) {
52
+ logger.info('CORS Request', {
53
+ method: req.method,
54
+ path: req.path,
55
+ origin: req.headers.origin,
56
+ userAgent: req.headers['user-agent']
57
+ });
58
+ }
59
+ next();
60
+ });
18
61
  // Response time logging middleware
19
62
  app.use((req, res, next) => {
20
63
  const start = Date.now();
@@ -34,10 +77,16 @@ const httpServer = createServer(app);
34
77
  // Setup Socket.IO
35
78
  const io = new Server(httpServer, {
36
79
  cors: {
37
- origin: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000',
38
- methods: ['GET', 'POST'],
80
+ origin: [
81
+ 'http://localhost:3000', // Frontend development server
82
+ 'http://localhost:3001', // Server port
83
+ 'http://127.0.0.1:3000', // Alternative localhost
84
+ 'http://127.0.0.1:3001', // Alternative localhost
85
+ process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
86
+ ],
87
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
39
88
  credentials: true,
40
- allowedHeaders: ['Access-Control-Allow-Origin']
89
+ allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'Access-Control-Allow-Origin', 'x-user']
41
90
  },
42
91
  transports: ['websocket', 'polling'],
43
92
  pingTimeout: 60000,
@@ -52,6 +101,42 @@ io.engine.on('connection_error', (err) => {
52
101
  });
53
102
  // Setup socket handlers
54
103
  setupSocketHandlers(io);
104
+ // File serving endpoint for secure file access
105
+ app.get('/api/files/:filePath', async (req, res) => {
106
+ try {
107
+ const filePath = decodeURIComponent(req.params.filePath);
108
+ console.log('File request:', { filePath, originalPath: req.params.filePath });
109
+ // Get file from Google Cloud Storage
110
+ const file = bucket.file(filePath);
111
+ const [exists] = await file.exists();
112
+ console.log('File exists:', exists, 'for path:', filePath);
113
+ if (!exists) {
114
+ return res.status(404).json({ error: 'File not found', filePath });
115
+ }
116
+ // Get file metadata
117
+ const [metadata] = await file.getMetadata();
118
+ // Set appropriate headers
119
+ res.set({
120
+ 'Content-Type': metadata.contentType || 'application/octet-stream',
121
+ 'Content-Length': metadata.size,
122
+ 'Cache-Control': 'public, max-age=31536000', // 1 year cache
123
+ 'ETag': metadata.etag,
124
+ });
125
+ // Stream file to response
126
+ const stream = file.createReadStream();
127
+ stream.pipe(res);
128
+ stream.on('error', (error) => {
129
+ console.error('Error streaming file:', error);
130
+ if (!res.headersSent) {
131
+ res.status(500).json({ error: 'Error streaming file' });
132
+ }
133
+ });
134
+ }
135
+ catch (error) {
136
+ console.error('Error serving file:', error);
137
+ res.status(500).json({ error: 'Internal server error' });
138
+ }
139
+ });
55
140
  // Create caller
56
141
  const createCaller = createCallerFactory(appRouter);
57
142
  // Setup tRPC middleware
@@ -75,3 +160,13 @@ logger.info('Configurations', {
75
160
  NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
76
161
  LOG_MODE: process.env.LOG_MODE,
77
162
  });
163
+ // Log CORS configuration
164
+ logger.info('CORS Configuration', {
165
+ allowedOrigins: [
166
+ 'http://localhost:3000',
167
+ 'http://localhost:3001',
168
+ 'http://127.0.0.1:3000',
169
+ 'http://127.0.0.1:3001',
170
+ process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
171
+ ]
172
+ });
@@ -4,6 +4,11 @@ export interface FileData {
4
4
  size: number;
5
5
  data: string;
6
6
  }
7
+ export interface DirectFileData {
8
+ name: string;
9
+ type: string;
10
+ size: number;
11
+ }
7
12
  export interface UploadedFile {
8
13
  id: string;
9
14
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"fileUpload.d.ts","sourceRoot":"","sources":["../../src/lib/fileUpload.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,YAAY,CAAC,CA+FvB;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,QAAQ,EAAE,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAWzB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUlE"}
1
+ {"version":3,"file":"fileUpload.d.ts","sourceRoot":"","sources":["../../src/lib/fileUpload.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAEd;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,YAAY,CAAC,CAkHvB;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,QAAQ,EAAE,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAWzB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUlE"}
@@ -13,8 +13,22 @@ import { prisma } from "./prisma.js";
13
13
  */
14
14
  export async function uploadFile(file, userId, directory, assignmentId) {
15
15
  try {
16
+ // Validate file extension matches MIME type
17
+ const fileExtension = file.name.split('.').pop()?.toLowerCase();
18
+ const mimeType = file.type.toLowerCase();
19
+ const extensionMimeMap = {
20
+ 'jpg': ['image/jpeg'],
21
+ 'jpeg': ['image/jpeg'],
22
+ 'png': ['image/png'],
23
+ 'gif': ['image/gif'],
24
+ 'webp': ['image/webp']
25
+ };
26
+ if (fileExtension && extensionMimeMap[fileExtension]) {
27
+ if (!extensionMimeMap[fileExtension].includes(mimeType)) {
28
+ throw new Error(`File extension .${fileExtension} does not match MIME type ${mimeType}`);
29
+ }
30
+ }
16
31
  // Create a unique filename
17
- const fileExtension = file.name.split('.').pop();
18
32
  const uniqueFilename = `${uuidv4()}.${fileExtension}`;
19
33
  // // Construct the full path
20
34
  const filePath = directory
@@ -25,8 +39,9 @@ export async function uploadFile(file, userId, directory, assignmentId) {
25
39
  // // Generate and store thumbnail if supported
26
40
  let thumbnailId;
27
41
  try {
28
- // // Convert base64 to buffer for thumbnail generation
29
- const base64Data = file.data.split(',')[1];
42
+ // // Convert base64 to buffer for thumbnail generation
43
+ // Handle both data URI format (data:image/jpeg;base64,...) and raw base64
44
+ const base64Data = file.data.includes(',') ? file.data.split(',')[1] : file.data;
30
45
  const fileBuffer = Buffer.from(base64Data, 'base64');
31
46
  // // Generate thumbnail directly from buffer
32
47
  const thumbnailBuffer = await generateMediaThumbnail(fileBuffer, file.type);
@@ -52,6 +67,7 @@ export async function uploadFile(file, userId, directory, assignmentId) {
52
67
  }
53
68
  catch (error) {
54
69
  console.warn('Failed to generate thumbnail:', error);
70
+ // Continue without thumbnail - this is not a critical failure
55
71
  }
56
72
  // Create file record in database
57
73
  // const uploadedPath = '/dummyPath' + Math.random().toString(36).substring(2, 15);
@@ -1,3 +1,4 @@
1
+ export declare const bucket: import("@google-cloud/storage").Bucket;
1
2
  /**
2
3
  * Uploads a file to Google Cloud Storage
3
4
  * @param base64Data Base64 encoded file data
@@ -11,7 +12,7 @@ export declare function uploadFile(base64Data: string, filePath: string, content
11
12
  * @param filePath The path of the file in the bucket
12
13
  * @returns The signed URL
13
14
  */
14
- export declare function getSignedUrl(filePath: string): Promise<string>;
15
+ export declare function getSignedUrl(filePath: string, action?: 'read' | 'write', contentType?: string): Promise<string>;
15
16
  /**
16
17
  * Deletes a file from Google Cloud Storage
17
18
  * @param filePath The path of the file to delete
@@ -1 +1 @@
1
- {"version":3,"file":"googleCloudStorage.d.ts","sourceRoot":"","sources":["../../src/lib/googleCloudStorage.ts"],"names":[],"mappings":"AAgBA;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CA4BjB;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAepE;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhE"}
1
+ {"version":3,"file":"googleCloudStorage.d.ts","sourceRoot":"","sources":["../../src/lib/googleCloudStorage.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,MAAM,wCAAwD,CAAC;AAK5E;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CA4BjB;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,GAAG,OAAgB,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsB7H;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhE"}
@@ -1,3 +1,5 @@
1
+ import dotenv from 'dotenv';
2
+ dotenv.config();
1
3
  import { Storage } from '@google-cloud/storage';
2
4
  import { TRPCError } from '@trpc/server';
3
5
  const storage = new Storage({
@@ -7,7 +9,7 @@ const storage = new Storage({
7
9
  private_key: process.env.GOOGLE_CLOUD_PRIVATE_KEY?.replace(/\\n/g, '\n'),
8
10
  },
9
11
  });
10
- const bucket = storage.bucket(process.env.GOOGLE_CLOUD_BUCKET_NAME || '');
12
+ export const bucket = storage.bucket(process.env.GOOGLE_CLOUD_BUCKET_NAME);
11
13
  // Short expiration time for signed URLs (5 minutes)
12
14
  const SIGNED_URL_EXPIRATION = 5 * 60 * 1000;
13
15
  /**
@@ -48,13 +50,18 @@ export async function uploadFile(base64Data, filePath, contentType) {
48
50
  * @param filePath The path of the file in the bucket
49
51
  * @returns The signed URL
50
52
  */
51
- export async function getSignedUrl(filePath) {
53
+ export async function getSignedUrl(filePath, action = 'read', contentType) {
52
54
  try {
53
- const [url] = await bucket.file(filePath).getSignedUrl({
55
+ const options = {
54
56
  version: 'v4',
55
- action: 'read',
57
+ action: action,
56
58
  expires: Date.now() + SIGNED_URL_EXPIRATION,
57
- });
59
+ };
60
+ // For write operations, add content type if provided
61
+ if (action === 'write' && contentType) {
62
+ options.contentType = contentType;
63
+ }
64
+ const [url] = await bucket.file(filePath).getSignedUrl(options);
58
65
  return url;
59
66
  }
60
67
  catch (error) {
@@ -1597,6 +1597,7 @@ export declare const appRouter: import("@trpc/server").TRPCBuiltRouter<{
1597
1597
  classId: string;
1598
1598
  assignmentId: string;
1599
1599
  submissionId: string;
1600
+ feedback?: string | undefined;
1600
1601
  gradeReceived?: number | null | undefined;
1601
1602
  existingFileIds?: string[] | undefined;
1602
1603
  removedAttachments?: string[] | undefined;
@@ -2061,6 +2062,84 @@ export declare const appRouter: import("@trpc/server").TRPCBuiltRouter<{
2061
2062
  };
2062
2063
  meta: object;
2063
2064
  }>;
2065
+ detachGradingBoundary: import("@trpc/server").TRPCMutationProcedure<{
2066
+ input: {
2067
+ [x: string]: unknown;
2068
+ classId: string;
2069
+ assignmentId: string;
2070
+ };
2071
+ output: {
2072
+ section: {
2073
+ id: string;
2074
+ name: string;
2075
+ color: string | null;
2076
+ classId: string;
2077
+ order: number | null;
2078
+ } | null;
2079
+ teacher: {
2080
+ id: string;
2081
+ username: string;
2082
+ email: string;
2083
+ password: string;
2084
+ verified: boolean;
2085
+ role: import(".prisma/client").$Enums.UserRole;
2086
+ profileId: string | null;
2087
+ schoolId: string | null;
2088
+ };
2089
+ attachments: {
2090
+ path: string;
2091
+ type: string;
2092
+ id: string;
2093
+ name: string;
2094
+ size: number | null;
2095
+ uploadedAt: Date | null;
2096
+ assignmentId: string | null;
2097
+ submissionId: string | null;
2098
+ userId: string | null;
2099
+ thumbnailId: string | null;
2100
+ annotationId: string | null;
2101
+ classDraftId: string | null;
2102
+ folderId: string | null;
2103
+ }[];
2104
+ eventAttached: {
2105
+ id: string;
2106
+ name: string | null;
2107
+ color: string | null;
2108
+ location: string | null;
2109
+ startTime: Date;
2110
+ endTime: Date;
2111
+ remarks: string | null;
2112
+ classId: string | null;
2113
+ userId: string | null;
2114
+ } | null;
2115
+ gradingBoundary: {
2116
+ id: string;
2117
+ classId: string;
2118
+ structured: string;
2119
+ } | null;
2120
+ } & {
2121
+ type: import(".prisma/client").$Enums.AssignmentType;
2122
+ id: string;
2123
+ title: string;
2124
+ dueDate: Date;
2125
+ maxGrade: number | null;
2126
+ classId: string;
2127
+ eventId: string | null;
2128
+ markSchemeId: string | null;
2129
+ gradingBoundaryId: string | null;
2130
+ instructions: string;
2131
+ weight: number;
2132
+ graded: boolean;
2133
+ sectionId: string | null;
2134
+ template: boolean;
2135
+ createdAt: Date | null;
2136
+ modifiedAt: Date | null;
2137
+ teacherId: string;
2138
+ inProgress: boolean;
2139
+ order: number | null;
2140
+ };
2141
+ meta: object;
2142
+ }>;
2064
2143
  }>>;
2065
2144
  user: import("@trpc/server").TRPCBuiltRouter<{
2066
2145
  ctx: import("../trpc.js").Context;
@@ -2085,29 +2164,57 @@ export declare const appRouter: import("@trpc/server").TRPCBuiltRouter<{
2085
2164
  id: string;
2086
2165
  username: string;
2087
2166
  profile: {
2088
- id: string;
2089
- userId: string;
2090
- } | null;
2167
+ displayName: any;
2168
+ bio: any;
2169
+ location: any;
2170
+ website: any;
2171
+ profilePicture: string | null;
2172
+ profilePictureThumbnail: string | null;
2173
+ };
2091
2174
  };
2092
2175
  meta: object;
2093
2176
  }>;
2094
2177
  updateProfile: import("@trpc/server").TRPCMutationProcedure<{
2095
2178
  input: {
2096
- profile: Record<string, any>;
2179
+ profile?: {
2180
+ location?: string | null | undefined;
2181
+ displayName?: string | null | undefined;
2182
+ bio?: string | null | undefined;
2183
+ website?: string | null | undefined;
2184
+ } | undefined;
2097
2185
  profilePicture?: {
2098
- type: string;
2099
- name: string;
2100
- size: number;
2101
- data: string;
2186
+ filePath: string;
2187
+ fileName: string;
2188
+ fileType: string;
2189
+ fileSize: number;
2190
+ } | undefined;
2191
+ dicebearAvatar?: {
2192
+ url: string;
2102
2193
  } | undefined;
2103
2194
  };
2104
2195
  output: {
2105
2196
  id: string;
2106
2197
  username: string;
2107
2198
  profile: {
2108
- id: string;
2109
- userId: string;
2110
- } | null;
2199
+ displayName: any;
2200
+ bio: any;
2201
+ location: any;
2202
+ website: any;
2203
+ profilePicture: string | null;
2204
+ profilePictureThumbnail: string | null;
2205
+ };
2206
+ };
2207
+ meta: object;
2208
+ }>;
2209
+ getUploadUrl: import("@trpc/server").TRPCMutationProcedure<{
2210
+ input: {
2211
+ fileName: string;
2212
+ fileType: string;
2213
+ };
2214
+ output: {
2215
+ uploadUrl: string;
2216
+ filePath: string;
2217
+ fileName: string;
2111
2218
  };
2112
2219
  meta: object;
2113
2220
  }>;
@@ -2884,6 +2991,7 @@ export declare const appRouter: import("@trpc/server").TRPCBuiltRouter<{
2884
2991
  childFolders: number;
2885
2992
  };
2886
2993
  name: string;
2994
+ color: string | null;
2887
2995
  }[];
2888
2996
  parentFolder: {
2889
2997
  id: string;
@@ -4813,6 +4921,7 @@ export declare const createCaller: import("@trpc/server").TRPCRouterCaller<{
4813
4921
  classId: string;
4814
4922
  assignmentId: string;
4815
4923
  submissionId: string;
4924
+ feedback?: string | undefined;
4816
4925
  gradeReceived?: number | null | undefined;
4817
4926
  existingFileIds?: string[] | undefined;
4818
4927
  removedAttachments?: string[] | undefined;
@@ -5277,6 +5386,84 @@ export declare const createCaller: import("@trpc/server").TRPCRouterCaller<{
5277
5386
  };
5278
5387
  meta: object;
5279
5388
  }>;
5389
+ detachGradingBoundary: import("@trpc/server").TRPCMutationProcedure<{
5390
+ input: {
5391
+ [x: string]: unknown;
5392
+ classId: string;
5393
+ assignmentId: string;
5394
+ };
5395
+ output: {
5396
+ section: {
5397
+ id: string;
5398
+ name: string;
5399
+ color: string | null;
5400
+ classId: string;
5401
+ order: number | null;
5402
+ } | null;
5403
+ teacher: {
5404
+ id: string;
5405
+ username: string;
5406
+ email: string;
5407
+ password: string;
5408
+ verified: boolean;
5409
+ role: import(".prisma/client").$Enums.UserRole;
5410
+ profileId: string | null;
5411
+ schoolId: string | null;
5412
+ };
5413
+ attachments: {
5414
+ path: string;
5415
+ type: string;
5416
+ id: string;
5417
+ name: string;
5418
+ size: number | null;
5419
+ uploadedAt: Date | null;
5420
+ assignmentId: string | null;
5421
+ submissionId: string | null;
5422
+ userId: string | null;
5423
+ thumbnailId: string | null;
5424
+ annotationId: string | null;
5425
+ classDraftId: string | null;
5426
+ folderId: string | null;
5427
+ }[];
5428
+ eventAttached: {
5429
+ id: string;
5430
+ name: string | null;
5431
+ color: string | null;
5432
+ location: string | null;
5433
+ startTime: Date;
5434
+ endTime: Date;
5435
+ remarks: string | null;
5436
+ classId: string | null;
5437
+ userId: string | null;
5438
+ } | null;
5439
+ gradingBoundary: {
5440
+ id: string;
5441
+ classId: string;
5442
+ structured: string;
5443
+ } | null;
5444
+ } & {
5445
+ type: import(".prisma/client").$Enums.AssignmentType;
5446
+ id: string;
5447
+ title: string;
5448
+ dueDate: Date;
5449
+ maxGrade: number | null;
5450
+ classId: string;
5451
+ eventId: string | null;
5452
+ markSchemeId: string | null;
5453
+ gradingBoundaryId: string | null;
5454
+ instructions: string;
5455
+ weight: number;
5456
+ graded: boolean;
5457
+ sectionId: string | null;
5458
+ template: boolean;
5459
+ createdAt: Date | null;
5460
+ modifiedAt: Date | null;
5461
+ teacherId: string;
5462
+ inProgress: boolean;
5463
+ order: number | null;
5464
+ };
5465
+ meta: object;
5466
+ }>;
5280
5467
  }>>;
5281
5468
  user: import("@trpc/server").TRPCBuiltRouter<{
5282
5469
  ctx: import("../trpc.js").Context;
@@ -5301,29 +5488,57 @@ export declare const createCaller: import("@trpc/server").TRPCRouterCaller<{
5301
5488
  id: string;
5302
5489
  username: string;
5303
5490
  profile: {
5304
- id: string;
5305
- userId: string;
5306
- } | null;
5491
+ displayName: any;
5492
+ bio: any;
5493
+ location: any;
5494
+ website: any;
5495
+ profilePicture: string | null;
5496
+ profilePictureThumbnail: string | null;
5497
+ };
5307
5498
  };
5308
5499
  meta: object;
5309
5500
  }>;
5310
5501
  updateProfile: import("@trpc/server").TRPCMutationProcedure<{
5311
5502
  input: {
5312
- profile: Record<string, any>;
5503
+ profile?: {
5504
+ location?: string | null | undefined;
5505
+ displayName?: string | null | undefined;
5506
+ bio?: string | null | undefined;
5507
+ website?: string | null | undefined;
5508
+ } | undefined;
5313
5509
  profilePicture?: {
5314
- type: string;
5315
- name: string;
5316
- size: number;
5317
- data: string;
5510
+ filePath: string;
5511
+ fileName: string;
5512
+ fileType: string;
5513
+ fileSize: number;
5514
+ } | undefined;
5515
+ dicebearAvatar?: {
5516
+ url: string;
5318
5517
  } | undefined;
5319
5518
  };
5320
5519
  output: {
5321
5520
  id: string;
5322
5521
  username: string;
5323
5522
  profile: {
5324
- id: string;
5325
- userId: string;
5326
- } | null;
5523
+ displayName: any;
5524
+ bio: any;
5525
+ location: any;
5526
+ website: any;
5527
+ profilePicture: string | null;
5528
+ profilePictureThumbnail: string | null;
5529
+ };
5530
+ };
5531
+ meta: object;
5532
+ }>;
5533
+ getUploadUrl: import("@trpc/server").TRPCMutationProcedure<{
5534
+ input: {
5535
+ fileName: string;
5536
+ fileType: string;
5537
+ };
5538
+ output: {
5539
+ uploadUrl: string;
5540
+ filePath: string;
5541
+ fileName: string;
5327
5542
  };
5328
5543
  meta: object;
5329
5544
  }>;
@@ -6100,6 +6315,7 @@ export declare const createCaller: import("@trpc/server").TRPCRouterCaller<{
6100
6315
  childFolders: number;
6101
6316
  };
6102
6317
  name: string;
6318
+ color: string | null;
6103
6319
  }[];
6104
6320
  parentFolder: {
6105
6321
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"_app.d.ts","sourceRoot":"","sources":["../../src/routers/_app.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAU1E,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAapB,CAAC;AAGH,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC;AACzC,MAAM,MAAM,YAAY,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;AACxD,MAAM,MAAM,aAAa,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;AAG1D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAAiC,CAAC"}
1
+ {"version":3,"file":"_app.d.ts","sourceRoot":"","sources":["../../src/routers/_app.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAU1E,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAapB,CAAC;AAGH,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC;AACzC,MAAM,MAAM,YAAY,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;AACxD,MAAM,MAAM,aAAa,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;AAG1D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAAiC,CAAC"}