@studious-lms/server 1.13.0 → 1.14.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/.dockerignore +28 -0
- package/.env.example +5 -0
- package/.github/workflows/deploy.yml +123 -0
- package/Dockerfile +54 -0
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/config/cors.d.ts.map +1 -1
- package/dist/lib/config/cors.js +31 -11
- package/dist/lib/config/cors.js.map +1 -1
- package/dist/lib/config/env.d.ts +17 -0
- package/dist/lib/config/env.d.ts.map +1 -1
- package/dist/lib/config/env.js +8 -2
- package/dist/lib/config/env.js.map +1 -1
- package/dist/lib/googleCloudStorage.d.ts +10 -0
- package/dist/lib/googleCloudStorage.d.ts.map +1 -1
- package/dist/lib/googleCloudStorage.js +22 -2
- package/dist/lib/googleCloudStorage.js.map +1 -1
- package/dist/lib/prisma.d.ts +104 -5
- package/dist/lib/prisma.d.ts.map +1 -1
- package/dist/lib/prisma.js +33 -2
- package/dist/lib/prisma.js.map +1 -1
- package/dist/models/agenda.d.ts +20 -20
- package/dist/models/announcement.d.ts +177 -69
- package/dist/models/announcement.d.ts.map +1 -1
- package/dist/models/assignment.d.ts +551 -353
- package/dist/models/assignment.d.ts.map +1 -1
- package/dist/models/attendance.d.ts +197 -71
- package/dist/models/attendance.d.ts.map +1 -1
- package/dist/models/auth.d.ts +348 -114
- package/dist/models/auth.d.ts.map +1 -1
- package/dist/models/class.d.ts +324 -198
- package/dist/models/class.d.ts.map +1 -1
- package/dist/models/class.js +2 -2
- package/dist/models/class.js.map +1 -1
- package/dist/models/cloudStorage.d.ts +146 -56
- package/dist/models/cloudStorage.d.ts.map +1 -1
- package/dist/models/comment.d.ts +267 -115
- package/dist/models/comment.d.ts.map +1 -1
- package/dist/models/conversation.d.ts +199 -73
- package/dist/models/conversation.d.ts.map +1 -1
- package/dist/models/department.d.ts +196 -70
- package/dist/models/department.d.ts.map +1 -1
- package/dist/models/event.d.ts +287 -125
- package/dist/models/event.d.ts.map +1 -1
- package/dist/models/file.d.ts +389 -263
- package/dist/models/file.d.ts.map +1 -1
- package/dist/models/folder.d.ts +433 -181
- package/dist/models/folder.d.ts.map +1 -1
- package/dist/models/labChat.d.ts +209 -83
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/marketing.d.ts +80 -26
- package/dist/models/marketing.d.ts.map +1 -1
- package/dist/models/message.d.ts +95 -41
- package/dist/models/message.d.ts.map +1 -1
- package/dist/models/newtonChat.d.ts +83 -29
- package/dist/models/newtonChat.d.ts.map +1 -1
- package/dist/models/notification.d.ts +61 -25
- package/dist/models/notification.d.ts.map +1 -1
- package/dist/models/school.d.ts +349 -133
- package/dist/models/school.d.ts.map +1 -1
- package/dist/models/section.d.ts +216 -72
- package/dist/models/section.d.ts.map +1 -1
- package/dist/models/tag.d.ts +156 -48
- package/dist/models/tag.d.ts.map +1 -1
- package/dist/models/user.d.ts +82 -28
- package/dist/models/user.d.ts.map +1 -1
- package/dist/models/worksheet.d.ts +1020 -411
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/models/worksheet.js +8 -2
- package/dist/models/worksheet.js.map +1 -1
- package/dist/pipelines/aiLabChat.d.ts +0 -8
- package/dist/pipelines/aiLabChat.d.ts.map +1 -1
- package/dist/pipelines/aiLabChat.js +50 -67
- package/dist/pipelines/aiLabChat.js.map +1 -1
- package/dist/pipelines/aiLabChatContract.d.ts +393 -388
- package/dist/pipelines/aiLabChatContract.d.ts.map +1 -1
- package/dist/pipelines/aiLabChatContract.js +63 -69
- package/dist/pipelines/aiLabChatContract.js.map +1 -1
- package/dist/pipelines/aiNewtonChat.d.ts.map +1 -1
- package/dist/pipelines/aiNewtonChat.js +41 -41
- package/dist/pipelines/aiNewtonChat.js.map +1 -1
- package/dist/pipelines/gradeWorksheet.d.ts +8 -8
- package/dist/pipelines/labChatPrompt.d.ts +10 -8
- package/dist/pipelines/labChatPrompt.d.ts.map +1 -1
- package/dist/pipelines/labChatPrompt.js +47 -67
- package/dist/pipelines/labChatPrompt.js.map +1 -1
- package/dist/pipelines/pdfToWorksheet.d.ts +2 -2
- package/dist/routers/_app.d.ts +2203 -1957
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +4 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/admin.d.ts +13 -13
- package/dist/routers/agenda.d.ts +18 -18
- package/dist/routers/announcement.d.ts +32 -32
- package/dist/routers/assignment.d.ts +335 -335
- package/dist/routers/attendance.d.ts +10 -10
- package/dist/routers/auth.d.ts +2 -2
- package/dist/routers/class.d.ts +147 -147
- package/dist/routers/comment.d.ts +22 -22
- package/dist/routers/conversation.d.ts +17 -17
- package/dist/routers/department.d.ts +34 -34
- package/dist/routers/discussion.d.ts +65 -53
- package/dist/routers/discussion.d.ts.map +1 -1
- package/dist/routers/discussion.js +6 -2
- package/dist/routers/discussion.js.map +1 -1
- package/dist/routers/embedding.d.ts +69 -0
- package/dist/routers/embedding.d.ts.map +1 -0
- package/dist/routers/embedding.js +143 -0
- package/dist/routers/embedding.js.map +1 -0
- package/dist/routers/event.d.ts +39 -39
- package/dist/routers/file.d.ts +12 -12
- package/dist/routers/folder.d.ts +38 -38
- package/dist/routers/labChat.d.ts +19 -19
- package/dist/routers/marketing.d.ts +2 -2
- package/dist/routers/message.d.ts +13 -13
- package/dist/routers/newtonChat.d.ts +4 -4
- package/dist/routers/notifications.d.ts +9 -9
- package/dist/routers/permissions.d.ts +14 -14
- package/dist/routers/school.d.ts +55 -55
- package/dist/routers/search.d.ts +22 -1
- package/dist/routers/search.d.ts.map +1 -1
- package/dist/routers/search.js +9 -3
- package/dist/routers/search.js.map +1 -1
- package/dist/routers/section.d.ts +4 -4
- package/dist/routers/studentProgress.d.ts +1 -1
- package/dist/routers/tag.d.ts +7 -7
- package/dist/routers/user.d.ts +10 -10
- package/dist/routers/worksheet.d.ts +95 -57
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/routers/worksheet.js +26 -2
- package/dist/routers/worksheet.js.map +1 -1
- package/dist/routes/aiStream.d.ts +2 -0
- package/dist/routes/aiStream.d.ts.map +1 -0
- package/dist/routes/aiStream.js +696 -0
- package/dist/routes/aiStream.js.map +1 -0
- package/dist/seedDatabase.d.ts +2 -2
- package/dist/seedDatabase.js +6 -6
- package/dist/seedDatabase.js.map +1 -1
- package/dist/services/adminInstitution.d.ts +8 -8
- package/dist/services/adminRunJob.d.ts +4 -4
- package/dist/services/agenda.d.ts +18 -18
- package/dist/services/aiChatStream.d.ts +68 -0
- package/dist/services/aiChatStream.d.ts.map +1 -0
- package/dist/services/aiChatStream.js +157 -0
- package/dist/services/aiChatStream.js.map +1 -0
- package/dist/services/aiModifierTools.d.ts +32 -0
- package/dist/services/aiModifierTools.d.ts.map +1 -0
- package/dist/services/aiModifierTools.js +165 -0
- package/dist/services/aiModifierTools.js.map +1 -0
- package/dist/services/aiProposalTools.d.ts +32 -0
- package/dist/services/aiProposalTools.d.ts.map +1 -0
- package/dist/services/aiProposalTools.js +207 -0
- package/dist/services/aiProposalTools.js.map +1 -0
- package/dist/services/aiStream.d.ts +22 -0
- package/dist/services/aiStream.d.ts.map +1 -0
- package/dist/services/aiStream.js +142 -0
- package/dist/services/aiStream.js.map +1 -0
- package/dist/services/aiTools.d.ts +16 -0
- package/dist/services/aiTools.d.ts.map +1 -0
- package/dist/services/aiTools.js +271 -0
- package/dist/services/aiTools.js.map +1 -0
- package/dist/services/announcement.d.ts +12 -12
- package/dist/services/announcement.d.ts.map +1 -1
- package/dist/services/announcement.js +7 -2
- package/dist/services/announcement.js.map +1 -1
- package/dist/services/assignment.d.ts +293 -293
- package/dist/services/assignment.d.ts.map +1 -1
- package/dist/services/assignment.js +28 -9
- package/dist/services/assignment.js.map +1 -1
- package/dist/services/attendance.d.ts +10 -10
- package/dist/services/auth.d.ts +2 -2
- package/dist/services/class.d.ts +138 -138
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +19 -3
- package/dist/services/class.js.map +1 -1
- package/dist/services/comment.d.ts +22 -22
- package/dist/services/conversation.d.ts +17 -17
- package/dist/services/department.d.ts +33 -33
- package/dist/services/discussion.d.ts +58 -58
- package/dist/services/discussion.d.ts.map +1 -1
- package/dist/services/discussion.js +8 -8
- package/dist/services/discussion.js.map +1 -1
- package/dist/services/discussionSummary.d.ts +21 -0
- package/dist/services/discussionSummary.d.ts.map +1 -0
- package/dist/services/discussionSummary.js +179 -0
- package/dist/services/discussionSummary.js.map +1 -0
- package/dist/services/embedding.d.ts +67 -0
- package/dist/services/embedding.d.ts.map +1 -0
- package/dist/services/embedding.js +226 -0
- package/dist/services/embedding.js.map +1 -0
- package/dist/services/event.d.ts +37 -37
- package/dist/services/file.d.ts +24 -24
- package/dist/services/folder.d.ts +36 -36
- package/dist/services/labChat.d.ts +19 -19
- package/dist/services/marketing.d.ts +2 -2
- package/dist/services/message.d.ts +11 -11
- package/dist/services/message.d.ts.map +1 -1
- package/dist/services/message.js +2 -2
- package/dist/services/message.js.map +1 -1
- package/dist/services/newtonChat.d.ts +4 -4
- package/dist/services/notification.d.ts +9 -9
- package/dist/services/notification.d.ts.map +1 -1
- package/dist/services/permissions.d.ts +14 -14
- package/dist/services/school.d.ts +50 -50
- package/dist/services/search.d.ts +12 -0
- package/dist/services/search.d.ts.map +1 -1
- package/dist/services/search.js +120 -2
- package/dist/services/search.js.map +1 -1
- package/dist/services/section.d.ts +3 -3
- package/dist/services/tag.d.ts +4 -4
- package/dist/services/user.d.ts +4 -4
- package/dist/services/user.d.ts.map +1 -1
- package/dist/services/user.js +10 -15
- package/dist/services/user.js.map +1 -1
- package/dist/services/worksheet.d.ts +60 -48
- package/dist/services/worksheet.d.ts.map +1 -1
- package/dist/services/worksheet.js +11 -4
- package/dist/services/worksheet.js.map +1 -1
- package/dist/utils/streamBroadcast.d.ts +11 -0
- package/dist/utils/streamBroadcast.d.ts.map +1 -0
- package/dist/utils/streamBroadcast.js +32 -0
- package/dist/utils/streamBroadcast.js.map +1 -0
- package/dist/workers/connection.d.ts +15 -0
- package/dist/workers/connection.d.ts.map +1 -1
- package/dist/workers/connection.js +20 -2
- package/dist/workers/connection.js.map +1 -1
- package/dist/workers/index.js +4 -2
- package/dist/workers/index.js.map +1 -1
- package/dist/workers/processors/createRunJobWorker.d.ts.map +1 -1
- package/dist/workers/processors/createRunJobWorker.js +31 -8
- package/dist/workers/processors/createRunJobWorker.js.map +1 -1
- package/dist/workers/processors/embedContent.d.ts +8 -0
- package/dist/workers/processors/embedContent.d.ts.map +1 -0
- package/dist/workers/processors/embedContent.js +76 -0
- package/dist/workers/processors/embedContent.js.map +1 -0
- package/dist/workers/queues.d.ts +6 -0
- package/dist/workers/queues.d.ts.map +1 -1
- package/dist/workers/queues.js +5 -3
- package/dist/workers/queues.js.map +1 -1
- package/package.json +5 -1
- package/prisma/migrations/20260609215135_init/migration.sql +1412 -0
- package/prisma/migrations/20260610130000_add_worksheet_tags/migration.sql +13 -0
- package/prisma/schema.prisma +38 -7
- package/src/index.ts +4 -0
- package/src/lib/config/cors.ts +32 -9
- package/src/lib/config/env.ts +6 -0
- package/src/lib/googleCloudStorage.ts +21 -0
- package/src/lib/prisma.ts +40 -1
- package/src/models/class.ts +3 -2
- package/src/models/worksheet.ts +5 -2
- package/src/pipelines/aiLabChat.ts +54 -79
- package/src/pipelines/aiLabChatContract.ts +69 -69
- package/src/pipelines/aiNewtonChat.ts +46 -43
- package/src/pipelines/labChatPrompt.ts +63 -88
- package/src/routers/_app.ts +2 -0
- package/src/routers/discussion.ts +7 -0
- package/src/routers/embedding.ts +159 -0
- package/src/routers/search.ts +10 -1
- package/src/routers/worksheet.ts +27 -0
- package/src/routes/aiStream.ts +789 -0
- package/src/seedDatabase.ts +4 -4
- package/src/services/aiChatStream.ts +219 -0
- package/src/services/aiModifierTools.ts +188 -0
- package/src/services/aiProposalTools.ts +272 -0
- package/src/services/aiStream.ts +175 -0
- package/src/services/aiTools.ts +290 -0
- package/src/services/announcement.ts +7 -0
- package/src/services/assignment.ts +28 -7
- package/src/services/class.ts +20 -1
- package/src/services/discussion.ts +9 -8
- package/src/services/discussionSummary.ts +226 -0
- package/src/services/embedding.ts +285 -0
- package/src/services/message.ts +2 -2
- package/src/services/search.ts +138 -0
- package/src/services/user.ts +9 -17
- package/src/services/worksheet.ts +9 -2
- package/src/utils/streamBroadcast.ts +48 -0
- package/src/workers/connection.ts +19 -0
- package/src/workers/index.ts +2 -0
- package/src/workers/processors/createRunJobWorker.ts +32 -6
- package/src/workers/processors/embedContent.ts +90 -0
- package/src/workers/queues.ts +5 -1
- package/tests/unit/pipelines/aiLabChatContract.test.ts +38 -21
- package/tests/unit/pipelines/labChatPrompt.test.ts +23 -36
- package/prisma/migrations/20250807062924_init/migration.sql +0 -436
- package/prisma/migrations/20250919063704_init2/migration.sql +0 -24
- package/prisma/migrations/20250920143543_add_profile_fields/migration.sql +0 -15
- package/prisma/migrations/20250922165147_add_chat_models/migration.sql +0 -68
- package/prisma/migrations/20250922165314_add_chat_roles/migration.sql +0 -5
- package/prisma/migrations/20250922171242_refactor_notification_system/migration.sql +0 -20
- package/prisma/migrations/20250922172208_add_mentions_system/migration.sql +0 -21
- package/prisma/migrations/20250925072732_add_lab_chat_system/migration.sql +0 -25
- package/prisma/migrations/20251020151505_add_upload_tracking_fields/migration.sql +0 -57
- package/prisma/migrations/20251109122857_annuoncements_comments/migration.sql +0 -30
- package/prisma/migrations/20251109135555_reactions_announcements_comments/migration.sql +0 -35
- package/prisma/migrations/20260410124000_add_submission_recommendation_state/migration.sql +0 -14
- package/prisma/migrations/20260415103500_add_session_type/migration.sql +0 -33
- package/prisma/migrations/20260415133000_add_ai_usage_logs/migration.sql +0 -19
- package/prisma/migrations/20260417083000_add_conversation_member_hidden_at/migration.sql +0 -2
- package/prisma/migrations/20260502230500_assignment_submission_comments/migration.sql +0 -60
- package/prisma/migrations/20260504071500_school_memberships/migration.sql +0 -81
- package/prisma/migrations/20260506162500_consolidate_run_job_and_unify_job_status/migration.sql +0 -166
- package/prisma/migrations/20260509220000_institution_overhaul/migration.sql +0 -184
- package/prisma/migrations/20260510170000_add_folder_permissions/migration.sql +0 -93
- package/prisma/migrations/20260510183000_add_discussions/migration.sql +0 -151
- /package/.github/workflows/{npm.yml → npm-publish.yml} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discussion.js","sources":["services/discussion.ts"],"sourceRoot":"/","sourcesContent":["import type { DiscussionType, Prisma, ReactionType } from \"@prisma/client\";\nimport { TRPCError } from \"@trpc/server\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { discussionChannel, pusher } from \"../lib/pusher.js\";\nimport { logger } from \"../utils/logger.js\";\nimport { classMemberOrSchoolAdminWhere, classTeacherOrSchoolAdminWhere } from \"../models/access.js\";\nimport { sendNotification } from \"./notification.js\";\n\nconst authorSelect = {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n profilePictureThumbnail: true,\n },\n },\n} as const;\n\nconst attachmentSelect = {\n id: true,\n name: true,\n type: true,\n size: true,\n path: true,\n uploadedAt: true,\n uploadStatus: true,\n thumbnailId: true,\n thumbnail: { select: { id: true, path: true } },\n} as const;\n\nconst reactionCounts = {\n THUMBSUP: 0,\n CELEBRATE: 0,\n CARE: 0,\n HEART: 0,\n IDEA: 0,\n HAPPY: 0,\n} satisfies Record<ReactionType, number>;\n\nconst discussionInclude = {\n author: { select: authorSelect },\n attachments: { select: attachmentSelect },\n tags: { select: { id: true, name: true, color: true } },\n reactions: { select: { type: true, userId: true } },\n _count: { select: { replies: { where: { deletedAt: null } } } },\n} as const;\n\nconst replyInclude = {\n author: { select: authorSelect },\n attachments: { select: attachmentSelect },\n reactions: { select: { type: true, userId: true } },\n} as const;\n\nconst unclaimedAttachmentWhere = {\n assignmentId: null,\n submissionId: null,\n annotationId: null,\n classDraftId: null,\n folderId: null,\n messageId: null,\n announcementId: null,\n discussionId: null,\n discussionReplyId: null,\n} satisfies Prisma.FileWhereInput;\n\ntype DiscussionWithInclude = Prisma.DiscussionGetPayload<{ include: typeof discussionInclude }>;\ntype ReplyWithInclude = Prisma.DiscussionReplyGetPayload<{ include: typeof replyInclude }>;\n\nexport type DiscussionReplyTree = ReturnType<typeof serializeReply> & {\n children: DiscussionReplyTree[];\n};\n\nfunction summarizeReactions(reactions: { type: ReactionType; userId: string }[], userId: string) {\n const counts = { ...reactionCounts };\n for (const reaction of reactions) {\n counts[reaction.type] += 1;\n }\n return {\n counts,\n userReaction: reactions.find((reaction) => reaction.userId === userId)?.type ?? null,\n total: reactions.length,\n };\n}\n\nfunction serializeDiscussion(discussion: DiscussionWithInclude, userId: string, unreadCount = 0) {\n return {\n id: discussion.id,\n classId: discussion.classId,\n authorId: discussion.authorId,\n title: discussion.title,\n body: discussion.body,\n type: discussion.type,\n isPinned: discussion.isPinned,\n isLocked: discussion.isLocked,\n allowReplies: discussion.allowReplies,\n createdAt: discussion.createdAt,\n updatedAt: discussion.updatedAt,\n lastActivityAt: discussion.lastActivityAt,\n author: discussion.author,\n attachments: discussion.attachments,\n tags: discussion.tags,\n replyCount: discussion._count.replies,\n hasAcceptedAnswer: false,\n reactions: summarizeReactions(discussion.reactions, userId),\n unreadCount,\n };\n}\n\nfunction serializeReply(reply: ReplyWithInclude, userId: string) {\n return {\n id: reply.id,\n discussionId: reply.discussionId,\n authorId: reply.authorId,\n parentId: reply.parentId,\n body: reply.deletedAt ? \"[deleted]\" : reply.body,\n deletedAt: reply.deletedAt,\n isAcceptedAnswer: reply.isAcceptedAnswer,\n createdAt: reply.createdAt,\n modifiedAt: reply.modifiedAt,\n author: reply.author,\n attachments: reply.deletedAt ? [] : reply.attachments,\n reactions: summarizeReactions(reply.reactions, userId),\n };\n}\n\nexport function buildReplyTree(replies: ReplyWithInclude[], userId: string): DiscussionReplyTree[] {\n const byId = new Map<string, DiscussionReplyTree>();\n const roots: DiscussionReplyTree[] = [];\n\n for (const reply of replies) {\n byId.set(reply.id, { ...serializeReply(reply, userId), children: [] });\n }\n\n for (const reply of replies) {\n const node = byId.get(reply.id)!;\n if (reply.parentId && byId.has(reply.parentId)) {\n byId.get(reply.parentId)!.children.push(node);\n } else {\n roots.push(node);\n }\n }\n\n return roots;\n}\n\nfunction isWithinAuthorEditWindow(createdAt: Date) {\n return Date.now() - createdAt.getTime() <= 24 * 60 * 60 * 1000;\n}\n\nexport async function getDiscussionClassAccess(classId: string, userId: string) {\n const classData = await prisma.class.findFirst({\n where: { id: classId, ...classMemberOrSchoolAdminWhere(userId) },\n select: {\n id: true,\n name: true,\n discussionsEnabled: true,\n studentsCanCreateDiscussions: true,\n studentsCanReply: true,\n students: { where: { id: userId }, select: { id: true } },\n teachers: { where: { id: userId }, select: { id: true } },\n school: {\n select: {\n memberships: {\n where: { userId, role: \"ADMIN\", status: \"ACTIVE\" },\n select: { userId: true },\n },\n },\n },\n },\n });\n\n if (!classData) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Not a member in this class\" });\n }\n if (!classData.discussionsEnabled) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Discussions are disabled for this class\" });\n }\n\n const isTeacher = classData.teachers.length > 0 || Boolean(classData.school?.memberships.length);\n const isStudent = classData.students.length > 0;\n\n return { ...classData, isTeacher, isStudent };\n}\n\nasync function getDiscussionForUser(discussionId: string, userId: string) {\n const discussion = await prisma.discussion.findUnique({\n where: { id: discussionId },\n include: {\n class: {\n select: {\n id: true,\n discussionsEnabled: true,\n studentsCanReply: true,\n teachers: { where: { id: userId }, select: { id: true } },\n students: { where: { id: userId }, select: { id: true } },\n school: {\n select: {\n memberships: {\n where: { userId, role: \"ADMIN\", status: \"ACTIVE\" },\n select: { userId: true },\n },\n },\n },\n },\n },\n },\n });\n\n if (!discussion) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Discussion not found\" });\n }\n\n const isTeacher = discussion.class.teachers.length > 0 || Boolean(discussion.class.school?.memberships.length);\n const isStudent = discussion.class.students.length > 0;\n if (!isTeacher && !isStudent) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Not a member in this class\" });\n }\n if (!discussion.class.discussionsEnabled) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Discussions are disabled for this class\" });\n }\n\n return { discussion, isTeacher, isStudent };\n}\n\nasync function claimDiscussionAttachments(\n tx: Prisma.TransactionClient,\n userId: string,\n discussionId: string,\n attachmentIds: string[] = []\n) {\n const uniqueIds = [...new Set(attachmentIds)];\n if (!uniqueIds.length) return;\n const { count } = await tx.file.updateMany({\n where: { id: { in: uniqueIds }, userId, uploadStatus: \"COMPLETED\", ...unclaimedAttachmentWhere },\n data: { discussionId },\n });\n if (count !== uniqueIds.length) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"Some attachments are missing, unfinished, or unavailable\" });\n }\n}\n\nasync function claimReplyAttachments(\n tx: Prisma.TransactionClient,\n userId: string,\n replyId: string,\n attachmentIds: string[] = []\n) {\n const uniqueIds = [...new Set(attachmentIds)];\n if (!uniqueIds.length) return;\n const { count } = await tx.file.updateMany({\n where: { id: { in: uniqueIds }, userId, uploadStatus: \"COMPLETED\", ...unclaimedAttachmentWhere },\n data: { discussionReplyId: replyId },\n });\n if (count !== uniqueIds.length) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"Some attachments are missing, unfinished, or unavailable\" });\n }\n}\n\nfunction triggerDiscussionEvent(classId: string, event: string, payload: unknown) {\n pusher.trigger(discussionChannel(classId), event, payload).catch((error) => {\n logger.error(\"Failed to trigger discussion pusher event\", { event, classId, error });\n });\n}\n\nasync function notify(receiverId: string | null | undefined, senderId: string, title: string, content: string) {\n if (!receiverId || receiverId === senderId) return;\n await sendNotification({ receiverId, title, content }).catch((error) => {\n logger.error(\"Failed to send discussion notification\", { receiverId, error });\n });\n}\n\nasync function notifyMentionedUsers(classId: string, senderId: string, body: string, link: string) {\n const usernames = [...new Set(Array.from(body.matchAll(/(^|\\s)@([a-zA-Z0-9_.-]{2,32})/g)).map((match) => match[2]))];\n if (!usernames.length) return;\n const members = await prisma.user.findMany({\n where: {\n username: { in: usernames },\n OR: [\n { teacherIn: { some: { id: classId } } },\n { studentIn: { some: { id: classId } } },\n { schoolMemberships: { some: { status: \"ACTIVE\", school: { classes: { some: { id: classId } } } } } },\n ],\n },\n select: { id: true },\n });\n await Promise.all(members.map((member) => notify(member.id, senderId, \"You were mentioned in a discussion\", link)));\n}\n\nasync function unreadCountsForDiscussions(userId: string, discussionIds: string[]) {\n if (!discussionIds.length) return new Map<string, number>();\n const reads = await prisma.discussionRead.findMany({\n where: { userId, discussionId: { in: discussionIds } },\n select: { discussionId: true, lastReadAt: true },\n });\n const readMap = new Map(reads.map((read) => [read.discussionId, read.lastReadAt]));\n const neverRead = discussionIds.filter((discussionId) => !readMap.has(discussionId));\n const readPredicates = Array.from(readMap.entries()).map(([discussionId, lastReadAt]) => ({\n discussionId,\n createdAt: { gt: lastReadAt },\n }));\n const counts = new Map<string, number>();\n\n const [neverReadCounts, readCounts] = await Promise.all([\n neverRead.length\n ? prisma.discussionReply.groupBy({\n by: [\"discussionId\"],\n where: { discussionId: { in: neverRead }, deletedAt: null, authorId: { not: userId } },\n _count: true,\n })\n : Promise.resolve([]),\n readPredicates.length\n ? prisma.discussionReply.groupBy({\n by: [\"discussionId\"],\n where: { deletedAt: null, authorId: { not: userId }, OR: readPredicates },\n _count: true,\n })\n : Promise.resolve([]),\n ]);\n\n for (const item of [...neverReadCounts, ...readCounts]) {\n counts.set(item.discussionId, item._count);\n }\n return counts;\n}\n\nexport async function listDiscussions(userId: string, input: {\n classId: string;\n tagId?: string;\n type?: DiscussionType;\n search?: string;\n sort: \"recent\" | \"activity\" | \"top\";\n cursor?: string;\n limit: number;\n}) {\n await getDiscussionClassAccess(input.classId, userId);\n const where: Prisma.DiscussionWhereInput = {\n classId: input.classId,\n ...(input.tagId ? { tags: { some: { id: input.tagId } } } : {}),\n ...(input.type ? { type: input.type } : {}),\n ...(input.search?.trim()\n ? {\n OR: [\n { title: { contains: input.search.trim(), mode: \"insensitive\" } },\n { body: { contains: input.search.trim(), mode: \"insensitive\" } },\n ],\n }\n : {}),\n };\n const orderBy: Prisma.DiscussionOrderByWithRelationInput[] =\n input.sort === \"recent\"\n ? [{ isPinned: \"desc\" }, { createdAt: \"desc\" }]\n : input.sort === \"top\"\n ? [{ isPinned: \"desc\" }, { replies: { _count: \"desc\" } }, { lastActivityAt: \"desc\" }]\n : [{ isPinned: \"desc\" }, { lastActivityAt: \"desc\" }];\n\n const items = await prisma.discussion.findMany({\n where,\n include: discussionInclude,\n orderBy,\n cursor: input.cursor ? { id: input.cursor } : undefined,\n skip: input.cursor ? 1 : 0,\n take: input.limit + 1,\n });\n const next = items.length > input.limit ? items.pop() : undefined;\n const unreadMap = await unreadCountsForDiscussions(userId, items.map((item) => item.id));\n const accepted = await prisma.discussionReply.groupBy({\n by: [\"discussionId\"],\n where: { discussionId: { in: items.map((item) => item.id) }, isAcceptedAnswer: true, deletedAt: null },\n });\n const acceptedIds = new Set(accepted.map((item) => item.discussionId));\n\n return {\n items: items.map((item) => ({\n ...serializeDiscussion(item, userId, unreadMap.get(item.id) ?? 0),\n hasAcceptedAnswer: acceptedIds.has(item.id),\n })),\n nextCursor: next?.id,\n };\n}\n\nexport async function getDiscussion(userId: string, discussionId: string) {\n const { discussion: accessDiscussion, isTeacher } = await getDiscussionForUser(discussionId, userId);\n const [discussion, replies, myReaction] = await Promise.all([\n prisma.discussion.findUniqueOrThrow({ where: { id: discussionId }, include: discussionInclude }),\n prisma.discussionReply.findMany({ where: { discussionId }, include: replyInclude, orderBy: { createdAt: \"asc\" } }),\n prisma.reaction.findUnique({ where: { userId_discussionId: { userId, discussionId } }, select: { type: true } }),\n prisma.discussionRead.upsert({\n where: { userId_discussionId: { userId, discussionId } },\n update: { lastReadAt: new Date() },\n create: { userId, discussionId },\n }),\n ]);\n const canAuthorEdit = accessDiscussion.authorId === userId && isWithinAuthorEditWindow(accessDiscussion.createdAt);\n const canReply = isTeacher || (accessDiscussion.class.studentsCanReply && !accessDiscussion.isLocked && accessDiscussion.allowReplies);\n return {\n discussion: serializeDiscussion(discussion, userId),\n replies: buildReplyTree(replies, userId),\n myReaction: myReaction?.type ?? null,\n canEdit: isTeacher || canAuthorEdit,\n canPin: isTeacher,\n canLock: isTeacher,\n canDelete: isTeacher || accessDiscussion.authorId === userId,\n canReply,\n };\n}\n\nexport async function createDiscussion(userId: string, input: {\n classId: string;\n title: string;\n body: string;\n type: DiscussionType;\n tagIds?: string[];\n attachmentIds?: string[];\n}) {\n const classData = await getDiscussionClassAccess(input.classId, userId);\n if (!classData.isTeacher && !classData.studentsCanCreateDiscussions) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Students cannot create discussions in this class\" });\n }\n if (input.type === \"ANNOUNCEMENT\" && !classData.isTeacher) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can create announcement discussions\" });\n }\n\n const discussion = await prisma.$transaction(async (tx) => {\n const created = await tx.discussion.create({\n data: {\n classId: input.classId,\n authorId: userId,\n title: input.title.trim(),\n body: input.body.trim(),\n type: input.type,\n allowReplies: input.type !== \"ANNOUNCEMENT\",\n tags: input.tagIds?.length ? { connect: input.tagIds.map((id) => ({ id })) } : undefined,\n },\n });\n await claimDiscussionAttachments(tx, userId, created.id, input.attachmentIds);\n return tx.discussion.findUniqueOrThrow({ where: { id: created.id }, include: discussionInclude });\n });\n\n triggerDiscussionEvent(input.classId, \"discussion-created\", { discussion: serializeDiscussion(discussion, userId) });\n await notifyMentionedUsers(input.classId, userId, input.body, `/class/${input.classId}/discussions/${discussion.id}`);\n return { discussion: serializeDiscussion(discussion, userId) };\n}\n\nexport async function updateDiscussion(userId: string, input: {\n discussionId: string;\n title?: string;\n body?: string;\n type?: DiscussionType;\n tagIds?: string[];\n allowReplies?: boolean;\n}) {\n const { discussion, isTeacher } = await getDiscussionForUser(input.discussionId, userId);\n if (!isTeacher && !(discussion.authorId === userId && isWithinAuthorEditWindow(discussion.createdAt))) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"You cannot edit this discussion\" });\n }\n if (input.type === \"ANNOUNCEMENT\" && !isTeacher) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can create announcement discussions\" });\n }\n const updated = await prisma.discussion.update({\n where: { id: input.discussionId },\n data: {\n ...(input.title !== undefined ? { title: input.title.trim() } : {}),\n ...(input.body !== undefined ? { body: input.body.trim() } : {}),\n ...(input.type !== undefined ? { type: input.type } : {}),\n ...(input.allowReplies !== undefined ? { allowReplies: input.allowReplies } : {}),\n ...(input.tagIds ? { tags: { set: input.tagIds.map((id) => ({ id })) } } : {}),\n },\n include: discussionInclude,\n });\n triggerDiscussionEvent(updated.classId, \"discussion-updated\", { discussion: serializeDiscussion(updated, userId) });\n return { discussion: serializeDiscussion(updated, userId) };\n}\n\nexport async function deleteDiscussion(userId: string, discussionId: string) {\n const { discussion, isTeacher } = await getDiscussionForUser(discussionId, userId);\n if (!isTeacher && discussion.authorId !== userId) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"You cannot delete this discussion\" });\n }\n await prisma.discussion.delete({ where: { id: discussionId } });\n triggerDiscussionEvent(discussion.classId, \"discussion-deleted\", { discussionId });\n return { success: true };\n}\n\nexport async function replyToDiscussion(userId: string, input: {\n discussionId: string;\n parentReplyId?: string;\n body: string;\n attachmentIds?: string[];\n}) {\n const { discussion, isTeacher } = await getDiscussionForUser(input.discussionId, userId);\n const canReply = isTeacher || (discussion.class.studentsCanReply && !discussion.isLocked && discussion.allowReplies);\n if (!canReply) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"You cannot reply to this discussion\" });\n }\n let parent: { id: string; authorId: string } | null = null;\n if (input.parentReplyId) {\n parent = await prisma.discussionReply.findFirst({\n where: { id: input.parentReplyId, discussionId: input.discussionId },\n select: { id: true, authorId: true },\n });\n if (!parent) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Parent reply not found\" });\n }\n const reply = await prisma.$transaction(async (tx) => {\n const created = await tx.discussionReply.create({\n data: {\n discussionId: input.discussionId,\n authorId: userId,\n parentId: input.parentReplyId,\n body: input.body.trim(),\n },\n });\n await claimReplyAttachments(tx, userId, created.id, input.attachmentIds);\n await tx.discussion.update({\n where: { id: input.discussionId },\n data: { lastActivityAt: new Date() },\n });\n return tx.discussionReply.findUniqueOrThrow({ where: { id: created.id }, include: replyInclude });\n });\n const link = `/class/${discussion.classId}/discussions/${discussion.id}#${reply.id}`;\n await Promise.all([\n notify(discussion.authorId, userId, \"New reply to your discussion\", link),\n notify(parent?.authorId, userId, \"New reply in a discussion thread\", link),\n notifyMentionedUsers(discussion.classId, userId, input.body, link),\n ]);\n triggerDiscussionEvent(discussion.classId, \"reply-created\", { discussionId: discussion.id, reply: serializeReply(reply, userId) });\n return { reply: serializeReply(reply, userId) };\n}\n\nexport async function updateDiscussionReply(userId: string, input: { replyId: string; body: string; attachmentIds?: string[] }) {\n const existing = await prisma.discussionReply.findUnique({ where: { id: input.replyId }, include: { discussion: true } });\n if (!existing) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Reply not found\" });\n const { isTeacher } = await getDiscussionForUser(existing.discussionId, userId);\n if (!isTeacher && !(existing.authorId === userId && isWithinAuthorEditWindow(existing.createdAt))) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"You cannot edit this reply\" });\n }\n const reply = await prisma.$transaction(async (tx) => {\n await tx.file.updateMany({ where: { discussionReplyId: input.replyId }, data: { discussionReplyId: null } });\n await claimReplyAttachments(tx, userId, input.replyId, input.attachmentIds);\n return tx.discussionReply.update({\n where: { id: input.replyId },\n data: { body: input.body.trim(), deletedAt: null },\n include: replyInclude,\n });\n });\n triggerDiscussionEvent(existing.discussion.classId, \"reply-updated\", { discussionId: existing.discussionId, reply: serializeReply(reply, userId) });\n return { reply: serializeReply(reply, userId) };\n}\n\nexport async function deleteDiscussionReply(userId: string, replyId: string) {\n const existing = await prisma.discussionReply.findUnique({ where: { id: replyId }, include: { discussion: true } });\n if (!existing) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Reply not found\" });\n const { isTeacher } = await getDiscussionForUser(existing.discussionId, userId);\n if (!isTeacher && existing.authorId !== userId) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"You cannot delete this reply\" });\n }\n const reply = await prisma.discussionReply.update({\n where: { id: replyId },\n data: { body: \"[deleted]\", deletedAt: new Date(), isAcceptedAnswer: false },\n include: replyInclude,\n });\n triggerDiscussionEvent(existing.discussion.classId, \"reply-deleted\", { discussionId: existing.discussionId, reply: serializeReply(reply, userId) });\n return { reply: serializeReply(reply, userId) };\n}\n\nexport async function pinDiscussion(userId: string, discussionId: string, isPinned: boolean) {\n const { discussion, isTeacher } = await getDiscussionForUser(discussionId, userId);\n if (!isTeacher) throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can pin discussions\" });\n const updated = await prisma.discussion.update({ where: { id: discussionId }, data: { isPinned }, include: discussionInclude });\n await notify(discussion.authorId, userId, isPinned ? \"Your discussion was pinned\" : \"Your discussion was unpinned\", `/class/${discussion.classId}/discussions/${discussionId}`);\n triggerDiscussionEvent(discussion.classId, \"discussion-updated\", { discussion: serializeDiscussion(updated, userId) });\n return { discussion: serializeDiscussion(updated, userId) };\n}\n\nexport async function lockDiscussion(userId: string, discussionId: string, isLocked: boolean) {\n const { discussion, isTeacher } = await getDiscussionForUser(discussionId, userId);\n if (!isTeacher) throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can lock discussions\" });\n const updated = await prisma.discussion.update({ where: { id: discussionId }, data: { isLocked }, include: discussionInclude });\n triggerDiscussionEvent(discussion.classId, \"discussion-updated\", { discussion: serializeDiscussion(updated, userId) });\n return { discussion: serializeDiscussion(updated, userId) };\n}\n\nexport async function markAcceptedAnswer(userId: string, replyId: string, accepted: boolean) {\n const reply = await prisma.discussionReply.findUnique({ where: { id: replyId }, include: { discussion: true } });\n if (!reply) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Reply not found\" });\n const { isTeacher } = await getDiscussionForUser(reply.discussionId, userId);\n if (reply.discussion.type !== \"QUESTION\") {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"Only question discussions can have accepted answers\" });\n }\n if (!isTeacher && reply.discussion.authorId !== userId) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only the discussion author or a teacher can mark an accepted answer\" });\n }\n const updated = await prisma.$transaction(async (tx) => {\n if (accepted) {\n await tx.discussionReply.updateMany({ where: { discussionId: reply.discussionId, isAcceptedAnswer: true }, data: { isAcceptedAnswer: false } });\n }\n return tx.discussionReply.update({ where: { id: replyId }, data: { isAcceptedAnswer: accepted }, include: replyInclude });\n });\n await notify(reply.authorId, userId, accepted ? \"Your answer was accepted\" : \"Your answer was unmarked\", `/class/${reply.discussion.classId}/discussions/${reply.discussionId}#${replyId}`);\n triggerDiscussionEvent(reply.discussion.classId, \"reply-updated\", { discussionId: reply.discussionId, reply: serializeReply(updated, userId) });\n return { reply: serializeReply(updated, userId) };\n}\n\nexport async function markDiscussionRead(userId: string, discussionId: string) {\n await getDiscussionForUser(discussionId, userId);\n return prisma.discussionRead.upsert({\n where: { userId_discussionId: { userId, discussionId } },\n update: { lastReadAt: new Date() },\n create: { userId, discussionId },\n });\n}\n\nexport async function getUnreadCounts(userId: string, classIds: string[]) {\n const allowedClasses = await prisma.class.findMany({\n where: { id: { in: classIds }, discussionsEnabled: true, ...classMemberOrSchoolAdminWhere(userId) },\n select: { id: true },\n });\n const result: Record<string, { total: number; perDiscussion: { discussionId: string; count: number }[] }> = {};\n for (const cls of allowedClasses) {\n const discussions = await prisma.discussion.findMany({\n where: { classId: cls.id },\n select: { id: true },\n });\n const countMap = await unreadCountsForDiscussions(userId, discussions.map((discussion) => discussion.id));\n const perDiscussion = Array.from(countMap.entries())\n .map(([discussionId, count]) => ({ discussionId, count }))\n .filter((item) => item.count > 0);\n result[cls.id] = {\n total: perDiscussion.reduce((sum, item) => sum + item.count, 0),\n perDiscussion,\n };\n }\n return result;\n}\n\nexport async function toggleDiscussionReaction(userId: string, input: { discussionId?: string; discussionReplyId?: string; type: ReactionType }) {\n if (!input.discussionId && !input.discussionReplyId) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"A discussion or reply is required\" });\n }\n if (input.discussionId && input.discussionReplyId) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"React to either a discussion or a reply\" });\n }\n const target = input.discussionId\n ? await getDiscussionForUser(input.discussionId, userId).then(({ discussion }) => ({ classId: discussion.classId, discussionId: discussion.id }))\n : await prisma.discussionReply.findUnique({ where: { id: input.discussionReplyId }, include: { discussion: true } }).then(async (reply) => {\n if (!reply) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Reply not found\" });\n await getDiscussionForUser(reply.discussionId, userId);\n return { classId: reply.discussion.classId, discussionId: reply.discussionId };\n });\n const where = input.discussionId\n ? { userId_discussionId: { userId, discussionId: input.discussionId } }\n : { userId_discussionReplyId: { userId, discussionReplyId: input.discussionReplyId! } };\n const existing = await prisma.reaction.findUnique({ where });\n if (existing?.type === input.type) {\n await prisma.reaction.delete({ where: { id: existing.id } });\n triggerDiscussionEvent(target.classId, \"reaction-removed\", { discussionId: target.discussionId, discussionReplyId: input.discussionReplyId, userId });\n return { reaction: null };\n }\n const reaction = input.discussionId\n ? await prisma.reaction.upsert({\n where: { userId_discussionId: { userId, discussionId: input.discussionId } },\n update: { type: input.type },\n create: { userId, discussionId: input.discussionId, type: input.type },\n })\n : await prisma.reaction.upsert({\n where: { userId_discussionReplyId: { userId, discussionReplyId: input.discussionReplyId! } },\n update: { type: input.type },\n create: { userId, discussionReplyId: input.discussionReplyId!, type: input.type },\n });\n triggerDiscussionEvent(target.classId, \"reaction-added\", { discussionId: target.discussionId, discussionReplyId: input.discussionReplyId, reaction });\n return { reaction };\n}\n\nexport async function listDiscussionTags(userId: string, classId: string) {\n await getDiscussionClassAccess(classId, userId);\n return prisma.discussionTag.findMany({ where: { classId }, orderBy: { name: \"asc\" } });\n}\n\nexport async function createDiscussionTag(userId: string, input: { classId: string; name: string; color: string }) {\n const isTeacher = await prisma.class.findFirst({ where: { id: input.classId, ...classTeacherOrSchoolAdminWhere(userId) }, select: { id: true, discussionsEnabled: true } });\n if (!isTeacher?.discussionsEnabled) throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can manage discussion tags\" });\n return prisma.discussionTag.create({ data: { classId: input.classId, name: input.name.trim(), color: input.color } });\n}\n\nexport async function updateDiscussionTag(userId: string, input: { tagId: string; name?: string; color?: string }) {\n const tag = await prisma.discussionTag.findUnique({ where: { id: input.tagId }, select: { classId: true } });\n if (!tag) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Tag not found\" });\n const isTeacher = await prisma.class.findFirst({ where: { id: tag.classId, ...classTeacherOrSchoolAdminWhere(userId) }, select: { id: true, discussionsEnabled: true } });\n if (!isTeacher?.discussionsEnabled) throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can manage discussion tags\" });\n return prisma.discussionTag.update({ where: { id: input.tagId }, data: { name: input.name?.trim(), color: input.color } });\n}\n\nexport async function deleteDiscussionTag(userId: string, tagId: string) {\n const tag = await prisma.discussionTag.findUnique({ where: { id: tagId }, select: { classId: true } });\n if (!tag) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Tag not found\" });\n const isTeacher = await prisma.class.findFirst({ where: { id: tag.classId, ...classTeacherOrSchoolAdminWhere(userId) }, select: { id: true, discussionsEnabled: true } });\n if (!isTeacher?.discussionsEnabled) throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can manage discussion tags\" });\n await prisma.discussionTag.delete({ where: { id: tagId } });\n return { success: true };\n}\n"],"names":[],"mappings":";;AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,6BAA6B,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,YAAY,GAAG;IACnB,EAAE,EAAE,IAAI;IACR,QAAQ,EAAE,IAAI;IACd,OAAO,EAAE;QACP,MAAM,EAAE;YACN,WAAW,EAAE,IAAI;YACjB,cAAc,EAAE,IAAI;YACpB,uBAAuB,EAAE,IAAI;SAC9B;KACF;CACO,CAAC;AAEX,MAAM,gBAAgB,GAAG;IACvB,EAAE,EAAE,IAAI;IACR,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,UAAU,EAAE,IAAI;IAChB,YAAY,EAAE,IAAI;IAClB,WAAW,EAAE,IAAI;IACjB,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;CACvC,CAAC;AAEX,MAAM,cAAc,GAAG;IACrB,QAAQ,EAAE,CAAC;IACX,SAAS,EAAE,CAAC;IACZ,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CAC8B,CAAC;AAEzC,MAAM,iBAAiB,GAAG;IACxB,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE;IAChC,WAAW,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE;IACzC,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;IACvD,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IACnD,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;CACvD,CAAC;AAEX,MAAM,YAAY,GAAG;IACnB,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE;IAChC,WAAW,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE;IACzC,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;CAC3C,CAAC;AAEX,MAAM,wBAAwB,GAAG;IAC/B,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,IAAI;IAClB,QAAQ,EAAE,IAAI;IACd,SAAS,EAAE,IAAI;IACf,cAAc,EAAE,IAAI;IACpB,YAAY,EAAE,IAAI;IAClB,iBAAiB,EAAE,IAAI;CACQ,CAAC;AASlC,SAAS,kBAAkB,CAAC,SAAmD,EAAE,MAAc;IAC7F,MAAM,MAAM,GAAG,EAAE,GAAG,cAAc,EAAE,CAAC;IACrC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO;QACL,MAAM;QACN,YAAY,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,EAAE,IAAI,IAAI,IAAI;QACpF,KAAK,EAAE,SAAS,CAAC,MAAM;KACxB,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAAC,UAAiC,EAAE,MAAc,EAAE,WAAW,GAAG,CAAC;IAC7F,OAAO;QACL,EAAE,EAAE,UAAU,CAAC,EAAE;QACjB,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,IAAI,EAAE,UAAU,CAAC,IAAI;QACrB,IAAI,EAAE,UAAU,CAAC,IAAI;QACrB,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,YAAY,EAAE,UAAU,CAAC,YAAY;QACrC,SAAS,EAAE,UAAU,CAAC,SAAS;QAC/B,SAAS,EAAE,UAAU,CAAC,SAAS;QAC/B,cAAc,EAAE,UAAU,CAAC,cAAc;QACzC,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,IAAI,EAAE,UAAU,CAAC,IAAI;QACrB,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC,OAAO;QACrC,iBAAiB,EAAE,KAAK;QACxB,SAAS,EAAE,kBAAkB,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3D,WAAW;KACZ,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,KAAuB,EAAE,MAAc;IAC7D,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;QAChD,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW;QACrD,SAAS,EAAE,kBAAkB,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC;KACvD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAA2B,EAAE,MAAc;IACxE,MAAM,IAAI,GAAG,IAAI,GAAG,EAA+B,CAAC;IACpD,MAAM,KAAK,GAA0B,EAAE,CAAC;IAExC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAE,CAAC;QACjC,IAAI,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/C,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAe;IAC/C,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,OAAe,EAAE,MAAc;IAC5E,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC;QAC7C,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,6BAA6B,CAAC,MAAM,CAAC,EAAE;QAChE,MAAM,EAAE;YACN,EAAE,EAAE,IAAI;YACR,IAAI,EAAE,IAAI;YACV,kBAAkB,EAAE,IAAI;YACxB,4BAA4B,EAAE,IAAI;YAClC,gBAAgB,EAAE,IAAI;YACtB,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;YACzD,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;YACzD,MAAM,EAAE;gBACN,MAAM,EAAE;oBACN,WAAW,EAAE;wBACX,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE;wBAClD,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;qBACzB;iBACF;aACF;SACF;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,kBAAkB,EAAE,CAAC;QAClC,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,yCAAyC,EAAE,CAAC,CAAC;IACjG,CAAC;IAED,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACjG,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IAEhD,OAAO,EAAE,GAAG,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAChD,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,YAAoB,EAAE,MAAc;IACtE,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC;QACpD,KAAK,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE;QAC3B,OAAO,EAAE;YACP,KAAK,EAAE;gBACL,MAAM,EAAE;oBACN,EAAE,EAAE,IAAI;oBACR,kBAAkB,EAAE,IAAI;oBACxB,gBAAgB,EAAE,IAAI;oBACtB,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;oBACzD,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;oBACzD,MAAM,EAAE;wBACN,MAAM,EAAE;4BACN,WAAW,EAAE;gCACX,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE;gCAClD,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;6BACzB;yBACF;qBACF;iBACF;aACF;SACF;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/G,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IACvD,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAC;QACzC,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,yCAAyC,EAAE,CAAC,CAAC;IACjG,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAC9C,CAAC;AAED,KAAK,UAAU,0BAA0B,CACvC,EAA4B,EAC5B,MAAc,EACd,YAAoB,EACpB,gBAA0B,EAAE;IAE5B,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;IAC9C,IAAI,CAAC,SAAS,CAAC,MAAM;QAAE,OAAO;IAC9B,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC;QACzC,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,wBAAwB,EAAE;QAChG,IAAI,EAAE,EAAE,YAAY,EAAE;KACvB,CAAC,CAAC;IACH,IAAI,KAAK,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;QAC/B,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,0DAA0D,EAAE,CAAC,CAAC;IACpH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,qBAAqB,CAClC,EAA4B,EAC5B,MAAc,EACd,OAAe,EACf,gBAA0B,EAAE;IAE5B,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;IAC9C,IAAI,CAAC,SAAS,CAAC,MAAM;QAAE,OAAO;IAC9B,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC;QACzC,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,wBAAwB,EAAE;QAChG,IAAI,EAAE,EAAE,iBAAiB,EAAE,OAAO,EAAE;KACrC,CAAC,CAAC;IACH,IAAI,KAAK,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;QAC/B,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,0DAA0D,EAAE,CAAC,CAAC;IACpH,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAe,EAAE,KAAa,EAAE,OAAgB;IAC9E,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACzE,MAAM,CAAC,KAAK,CAAC,2CAA2C,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,UAAqC,EAAE,QAAgB,EAAE,KAAa,EAAE,OAAe;IAC3G,IAAI,CAAC,UAAU,IAAI,UAAU,KAAK,QAAQ;QAAE,OAAO;IACnD,MAAM,gBAAgB,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACrE,MAAM,CAAC,KAAK,CAAC,wCAAwC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,OAAe,EAAE,QAAgB,EAAE,IAAY,EAAE,IAAY;IAC/F,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,gCAAgC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrH,IAAI,CAAC,SAAS,CAAC,MAAM;QAAE,OAAO;IAC9B,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;QACzC,KAAK,EAAE;YACL,QAAQ,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE;YAC3B,EAAE,EAAE;gBACF,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBACxC,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBACxC,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;aACtG;SACF;QACD,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE;KACrB,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,oCAAoC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AACtH,CAAC;AAED,KAAK,UAAU,0BAA0B,CAAC,MAAc,EAAE,aAAuB;IAC/E,IAAI,CAAC,aAAa,CAAC,MAAM;QAAE,OAAO,IAAI,GAAG,EAAkB,CAAC;IAC5D,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC;QACjD,KAAK,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE;QACtD,MAAM,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;KACjD,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACnF,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC;IACrF,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QACxF,YAAY;QACZ,SAAS,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE;KAC9B,CAAC,CAAC,CAAC;IACJ,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEzC,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACtD,SAAS,CAAC,MAAM;YACd,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC;gBAC7B,EAAE,EAAE,CAAC,cAAc,CAAC;gBACpB,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;gBACtF,MAAM,EAAE,IAAI;aACb,CAAC;YACJ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACvB,cAAc,CAAC,MAAM;YACnB,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC;gBAC7B,EAAE,EAAE,CAAC,cAAc,CAAC;gBACpB,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,cAAc,EAAE;gBACzE,MAAM,EAAE,IAAI;aACb,CAAC;YACJ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;KACxB,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,eAAe,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAc,EAAE,KAQrD;IACC,MAAM,wBAAwB,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACtD,MAAM,KAAK,GAAgC;QACzC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE;YACtB,CAAC,CAAC;gBACE,EAAE,EAAE;oBACF,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE;oBACjE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE;iBACjE;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;IACF,MAAM,OAAO,GACX,KAAK,CAAC,IAAI,KAAK,QAAQ;QACrB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QAC/C,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK;YACpB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;YACrF,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC;IAE3D,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;QAC7C,KAAK;QACL,OAAO,EAAE,iBAAiB;QAC1B,OAAO;QACP,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS;QACvD,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,EAAE,KAAK,CAAC,KAAK,GAAG,CAAC;KACtB,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAClE,MAAM,SAAS,GAAG,MAAM,0BAA0B,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACzF,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC;QACpD,EAAE,EAAE,CAAC,cAAc,CAAC;QACpB,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;KACvG,CAAC,CAAC;IACH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IAEvE,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC1B,GAAG,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YACjE,iBAAiB,EAAE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;SAC5C,CAAC,CAAC;QACH,UAAU,EAAE,IAAI,EAAE,EAAE;KACrB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc,EAAE,YAAoB;IACtE,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,SAAS,EAAE,GAAG,MAAM,oBAAoB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACrG,MAAM,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC1D,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;QAChG,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,CAAC;QAClH,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,mBAAmB,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;QAChH,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC;YAC3B,KAAK,EAAE,EAAE,mBAAmB,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE;YACxD,MAAM,EAAE,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,EAAE;YAClC,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE;SACjC,CAAC;KACH,CAAC,CAAC;IACH,MAAM,aAAa,GAAG,gBAAgB,CAAC,QAAQ,KAAK,MAAM,IAAI,wBAAwB,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;IACnH,MAAM,QAAQ,GAAG,SAAS,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,gBAAgB,IAAI,CAAC,gBAAgB,CAAC,QAAQ,IAAI,gBAAgB,CAAC,YAAY,CAAC,CAAC;IACvI,OAAO;QACL,UAAU,EAAE,mBAAmB,CAAC,UAAU,EAAE,MAAM,CAAC;QACnD,OAAO,EAAE,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC;QACxC,UAAU,EAAE,UAAU,EAAE,IAAI,IAAI,IAAI;QACpC,OAAO,EAAE,SAAS,IAAI,aAAa;QACnC,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,SAAS;QAClB,SAAS,EAAE,SAAS,IAAI,gBAAgB,CAAC,QAAQ,KAAK,MAAM;QAC5D,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAc,EAAE,KAOtD;IACC,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACxE,IAAI,CAAC,SAAS,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,4BAA4B,EAAE,CAAC;QACpE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,kDAAkD,EAAE,CAAC,CAAC;IAC1G,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;QAC1D,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,mDAAmD,EAAE,CAAC,CAAC;IAC3G,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACxD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;YACzC,IAAI,EAAE;gBACJ,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,QAAQ,EAAE,MAAM;gBAChB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;gBACzB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE;gBACvB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,YAAY,EAAE,KAAK,CAAC,IAAI,KAAK,cAAc;gBAC3C,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;aACzF;SACF,CAAC,CAAC;QACH,MAAM,0BAA0B,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;QAC9E,OAAO,EAAE,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;IACpG,CAAC,CAAC,CAAC;IAEH,sBAAsB,CAAC,KAAK,CAAC,OAAO,EAAE,oBAAoB,EAAE,EAAE,UAAU,EAAE,mBAAmB,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACrH,MAAM,oBAAoB,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,UAAU,KAAK,CAAC,OAAO,gBAAgB,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IACtH,OAAO,EAAE,UAAU,EAAE,mBAAmB,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAc,EAAE,KAOtD;IACC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACzF,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,KAAK,MAAM,IAAI,wBAAwB,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QACtG,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,iCAAiC,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,CAAC,SAAS,EAAE,CAAC;QAChD,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,mDAAmD,EAAE,CAAC,CAAC;IAC3G,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;QAC7C,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,YAAY,EAAE;QACjC,IAAI,EAAE;YACJ,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnE,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,GAAG,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/E;QACD,OAAO,EAAE,iBAAiB;KAC3B,CAAC,CAAC;IACH,sBAAsB,CAAC,OAAO,CAAC,OAAO,EAAE,oBAAoB,EAAE,EAAE,UAAU,EAAE,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACpH,OAAO,EAAE,UAAU,EAAE,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAc,EAAE,YAAoB;IACzE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,oBAAoB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACnF,IAAI,CAAC,SAAS,IAAI,UAAU,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACjD,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC,CAAC;IAC3F,CAAC;IACD,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;IAChE,sBAAsB,CAAC,UAAU,CAAC,OAAO,EAAE,oBAAoB,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;IACnF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAc,EAAE,KAKvD;IACC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACzF,MAAM,QAAQ,GAAG,SAAS,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,gBAAgB,IAAI,CAAC,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC;IACrH,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,qCAAqC,EAAE,CAAC,CAAC;IAC7F,CAAC;IACD,IAAI,MAAM,GAA4C,IAAI,CAAC;IAC3D,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;QACxB,MAAM,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC;YAC9C,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,aAAa,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE;YACpE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;SACrC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC,CAAC;IAC7F,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACnD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC;YAC9C,IAAI,EAAE;gBACJ,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,QAAQ,EAAE,MAAM;gBAChB,QAAQ,EAAE,KAAK,CAAC,aAAa;gBAC7B,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE;aACxB;SACF,CAAC,CAAC;QACH,MAAM,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;QACzE,MAAM,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;YACzB,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,YAAY,EAAE;YACjC,IAAI,EAAE,EAAE,cAAc,EAAE,IAAI,IAAI,EAAE,EAAE;SACrC,CAAC,CAAC;QACH,OAAO,EAAE,CAAC,eAAe,CAAC,iBAAiB,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;IACpG,CAAC,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,UAAU,UAAU,CAAC,OAAO,gBAAgB,UAAU,CAAC,EAAE,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;IACrF,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,8BAA8B,EAAE,IAAI,CAAC;QACzE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,kCAAkC,EAAE,IAAI,CAAC;QAC1E,oBAAoB,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC;KACnE,CAAC,CAAC;IACH,sBAAsB,CAAC,UAAU,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,YAAY,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACnI,OAAO,EAAE,KAAK,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,MAAc,EAAE,KAAkE;IAC5H,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC1H,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;IACtF,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,oBAAoB,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAChF,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,KAAK,MAAM,IAAI,wBAAwB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QAClG,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACnD,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,iBAAiB,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QAC7G,MAAM,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;QAC5E,OAAO,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC;YAC/B,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,OAAO,EAAE;YAC5B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;YAClD,OAAO,EAAE,YAAY;SACtB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,sBAAsB,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,YAAY,EAAE,KAAK,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACpJ,OAAO,EAAE,KAAK,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,MAAc,EAAE,OAAe;IACzE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IACpH,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;IACtF,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,oBAAoB,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAChF,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC/C,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,8BAA8B,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC;QAChD,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE;QACtB,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE;QAC3E,OAAO,EAAE,YAAY;KACtB,CAAC,CAAC;IACH,sBAAsB,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,YAAY,EAAE,KAAK,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACpJ,OAAO,EAAE,KAAK,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc,EAAE,YAAoB,EAAE,QAAiB;IACzF,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,oBAAoB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACnF,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC,CAAC;IACzG,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAChI,MAAM,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,8BAA8B,EAAE,UAAU,UAAU,CAAC,OAAO,gBAAgB,YAAY,EAAE,CAAC,CAAC;IAChL,sBAAsB,CAAC,UAAU,CAAC,OAAO,EAAE,oBAAoB,EAAE,EAAE,UAAU,EAAE,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACvH,OAAO,EAAE,UAAU,EAAE,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAc,EAAE,YAAoB,EAAE,QAAiB;IAC1F,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,oBAAoB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACnF,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,oCAAoC,EAAE,CAAC,CAAC;IAC1G,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAChI,sBAAsB,CAAC,UAAU,CAAC,OAAO,EAAE,oBAAoB,EAAE,EAAE,UAAU,EAAE,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACvH,OAAO,EAAE,UAAU,EAAE,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,OAAe,EAAE,QAAiB;IACzF,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IACjH,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;IACnF,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAC7E,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACzC,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,qDAAqD,EAAE,CAAC,CAAC;IAC/G,CAAC;IACD,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,UAAU,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACvD,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,qEAAqE,EAAE,CAAC,CAAC;IAC7H,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACrD,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,EAAE,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,gBAAgB,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QAClJ,CAAC;QACD,OAAO,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,gBAAgB,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;IAC5H,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,0BAA0B,EAAE,UAAU,KAAK,CAAC,UAAU,CAAC,OAAO,gBAAgB,KAAK,CAAC,YAAY,IAAI,OAAO,EAAE,CAAC,CAAC;IAC5L,sBAAsB,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,EAAE,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAChJ,OAAO,EAAE,KAAK,EAAE,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC;AACpD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,YAAoB;IAC3E,MAAM,oBAAoB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACjD,OAAO,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC;QAClC,KAAK,EAAE,EAAE,mBAAmB,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE;QACxD,MAAM,EAAE,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,EAAE;QAClC,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE;KACjC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAc,EAAE,QAAkB;IACtE,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;QACjD,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,6BAA6B,CAAC,MAAM,CAAC,EAAE;QACnG,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE;KACrB,CAAC,CAAC;IACH,MAAM,MAAM,GAAgG,EAAE,CAAC;IAC/G,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QACjC,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;YACnD,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,EAAE;YAC1B,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE;SACrB,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,0BAA0B,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1G,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;aACjD,GAAG,CAAC,CAAC,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;aACzD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG;YACf,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YAC/D,aAAa;SACd,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,MAAc,EAAE,KAAgF;IAC7I,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC;QACpD,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC,CAAC;IAC7F,CAAC;IACD,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAClD,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,yCAAyC,EAAE,CAAC,CAAC;IACnG,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY;QAC/B,CAAC,CAAC,MAAM,oBAAoB,CAAC,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QACjJ,CAAC,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,iBAAiB,EAAE,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACtI,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;YACnF,MAAM,oBAAoB,CAAC,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;YACvD,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC;QACjF,CAAC,CAAC,CAAC;IACP,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY;QAC9B,CAAC,CAAC,EAAE,mBAAmB,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,EAAE;QACvE,CAAC,CAAC,EAAE,wBAAwB,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,KAAK,CAAC,iBAAkB,EAAE,EAAE,CAAC;IAC1F,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7D,IAAI,QAAQ,EAAE,IAAI,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;QAClC,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC7D,sBAAsB,CAAC,MAAM,CAAC,OAAO,EAAE,kBAAkB,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,EAAE,MAAM,EAAE,CAAC,CAAC;QACtJ,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,YAAY;QACjC,CAAC,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC3B,KAAK,EAAE,EAAE,mBAAmB,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,EAAE;YAC5E,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;YAC5B,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;SACvE,CAAC;QACJ,CAAC,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC3B,KAAK,EAAE,EAAE,wBAAwB,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,KAAK,CAAC,iBAAkB,EAAE,EAAE;YAC5F,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;YAC5B,MAAM,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,KAAK,CAAC,iBAAkB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;SAClF,CAAC,CAAC;IACP,sBAAsB,CAAC,MAAM,CAAC,OAAO,EAAE,gBAAgB,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtJ,OAAO,EAAE,QAAQ,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,OAAe;IACtE,MAAM,wBAAwB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAc,EAAE,KAAuD;IAC/G,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,OAAO,EAAE,GAAG,8BAA8B,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC5K,IAAI,CAAC,SAAS,EAAE,kBAAkB;QAAE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,0CAA0C,EAAE,CAAC,CAAC;IACpI,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACxH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAc,EAAE,KAAuD;IAC/G,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC7G,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC;IAC/E,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,8BAA8B,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC1K,IAAI,CAAC,SAAS,EAAE,kBAAkB;QAAE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,0CAA0C,EAAE,CAAC,CAAC;IACpI,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC7H,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAc,EAAE,KAAa;IACrE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IACvG,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC;IAC/E,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,8BAA8B,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC1K,IAAI,CAAC,SAAS,EAAE,kBAAkB;QAAE,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,0CAA0C,EAAE,CAAC,CAAC;IACpI,MAAM,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IAC5D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC","debug_id":"b10e68f8-0106-57a7-be41-a32938701565"}
|
|
1
|
+
{"version":3,"file":"discussion.js","sources":["services/discussion.ts"],"sourceRoot":"/","sourcesContent":["import type { DiscussionType, Prisma, ReactionType } from \"@prisma/client\";\nimport type { AppTransactionClient } from \"../lib/prisma.js\";\nimport { TRPCError } from \"@trpc/server\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { discussionChannel, pusher } from \"../lib/pusher.js\";\nimport { logger } from \"../utils/logger.js\";\nimport { classMemberOrSchoolAdminWhere, classTeacherOrSchoolAdminWhere } from \"../models/access.js\";\nimport { sendNotification } from \"./notification.js\";\n\nconst authorSelect = {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n profilePictureThumbnail: true,\n },\n },\n} as const;\n\nconst attachmentSelect = {\n id: true,\n name: true,\n type: true,\n size: true,\n path: true,\n uploadedAt: true,\n uploadStatus: true,\n thumbnailId: true,\n thumbnail: { select: { id: true, path: true } },\n} as const;\n\nconst reactionCounts = {\n THUMBSUP: 0,\n CELEBRATE: 0,\n CARE: 0,\n HEART: 0,\n IDEA: 0,\n HAPPY: 0,\n} satisfies Record<ReactionType, number>;\n\nconst discussionInclude = {\n author: { select: authorSelect },\n attachments: { select: attachmentSelect },\n tags: { select: { id: true, name: true, color: true } },\n reactions: { select: { type: true, userId: true } },\n _count: { select: { replies: { where: { deletedAt: null } } } },\n} as const;\n\nconst replyInclude = {\n author: { select: authorSelect },\n attachments: { select: attachmentSelect },\n reactions: { select: { type: true, userId: true } },\n} as const;\n\nconst unclaimedAttachmentWhere = {\n assignmentId: null,\n submissionId: null,\n annotationId: null,\n classDraftId: null,\n folderId: null,\n messageId: null,\n announcementId: null,\n discussionId: null,\n discussionReplyId: null,\n} satisfies Prisma.FileWhereInput;\n\ntype DiscussionWithInclude = Prisma.DiscussionGetPayload<{ include: typeof discussionInclude }>;\ntype ReplyWithInclude = Prisma.DiscussionReplyGetPayload<{ include: typeof replyInclude }>;\n\nexport type DiscussionReplyTree = ReturnType<typeof serializeReply> & {\n children: DiscussionReplyTree[];\n};\n\nfunction summarizeReactions(reactions: { type: ReactionType; userId: string }[], userId: string) {\n const counts = { ...reactionCounts };\n for (const reaction of reactions) {\n counts[reaction.type] += 1;\n }\n return {\n counts,\n userReaction: reactions.find((reaction) => reaction.userId === userId)?.type ?? null,\n total: reactions.length,\n };\n}\n\nfunction serializeDiscussion(discussion: DiscussionWithInclude, userId: string, unreadCount = 0) {\n return {\n id: discussion.id,\n classId: discussion.classId,\n authorId: discussion.authorId,\n title: discussion.title,\n body: discussion.body,\n type: discussion.type,\n isPinned: discussion.isPinned,\n isLocked: discussion.isLocked,\n allowReplies: discussion.allowReplies,\n createdAt: discussion.createdAt,\n updatedAt: discussion.updatedAt,\n lastActivityAt: discussion.lastActivityAt,\n author: discussion.author,\n attachments: discussion.attachments,\n tags: discussion.tags,\n replyCount: discussion._count.replies,\n hasAcceptedAnswer: false,\n reactions: summarizeReactions(discussion.reactions, userId),\n unreadCount,\n };\n}\n\nfunction serializeReply(reply: ReplyWithInclude, userId: string) {\n return {\n id: reply.id,\n discussionId: reply.discussionId,\n authorId: reply.authorId,\n parentId: reply.parentId,\n body: reply.deletedAt ? \"[deleted]\" : reply.body,\n deletedAt: reply.deletedAt,\n isAcceptedAnswer: reply.isAcceptedAnswer,\n createdAt: reply.createdAt,\n modifiedAt: reply.modifiedAt,\n author: reply.author,\n attachments: reply.deletedAt ? [] : reply.attachments,\n reactions: summarizeReactions(reply.reactions, userId),\n };\n}\n\nexport function buildReplyTree(replies: ReplyWithInclude[], userId: string): DiscussionReplyTree[] {\n const byId = new Map<string, DiscussionReplyTree>();\n const roots: DiscussionReplyTree[] = [];\n\n for (const reply of replies) {\n byId.set(reply.id, { ...serializeReply(reply, userId), children: [] });\n }\n\n for (const reply of replies) {\n const node = byId.get(reply.id)!;\n if (reply.parentId && byId.has(reply.parentId)) {\n byId.get(reply.parentId)!.children.push(node);\n } else {\n roots.push(node);\n }\n }\n\n return roots;\n}\n\nfunction isWithinAuthorEditWindow(createdAt: Date) {\n return Date.now() - createdAt.getTime() <= 24 * 60 * 60 * 1000;\n}\n\nexport async function getDiscussionClassAccess(classId: string, userId: string) {\n const classData = await prisma.class.findFirst({\n where: { id: classId, ...classMemberOrSchoolAdminWhere(userId) },\n select: {\n id: true,\n name: true,\n discussionsEnabled: true,\n studentsCanCreateDiscussions: true,\n studentsCanReply: true,\n students: { where: { id: userId }, select: { id: true } },\n teachers: { where: { id: userId }, select: { id: true } },\n school: {\n select: {\n memberships: {\n where: { userId, role: \"ADMIN\", status: \"ACTIVE\" },\n select: { userId: true },\n },\n },\n },\n },\n });\n\n if (!classData) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Not a member in this class\" });\n }\n if (!classData.discussionsEnabled) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Discussions are disabled for this class\" });\n }\n\n const isTeacher = classData.teachers.length > 0 || Boolean(classData.school?.memberships.length);\n const isStudent = classData.students.length > 0;\n\n return { ...classData, isTeacher, isStudent };\n}\n\nasync function getDiscussionForUser(discussionId: string, userId: string) {\n const discussion = await prisma.discussion.findUnique({\n where: { id: discussionId },\n include: {\n class: {\n select: {\n id: true,\n discussionsEnabled: true,\n studentsCanReply: true,\n teachers: { where: { id: userId }, select: { id: true } },\n students: { where: { id: userId }, select: { id: true } },\n school: {\n select: {\n memberships: {\n where: { userId, role: \"ADMIN\", status: \"ACTIVE\" },\n select: { userId: true },\n },\n },\n },\n },\n },\n },\n });\n\n if (!discussion) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Discussion not found\" });\n }\n\n const isTeacher = discussion.class.teachers.length > 0 || Boolean(discussion.class.school?.memberships.length);\n const isStudent = discussion.class.students.length > 0;\n if (!isTeacher && !isStudent) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Not a member in this class\" });\n }\n if (!discussion.class.discussionsEnabled) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Discussions are disabled for this class\" });\n }\n\n return { discussion, isTeacher, isStudent };\n}\n\nasync function claimDiscussionAttachments(\n tx: AppTransactionClient,\n userId: string,\n discussionId: string,\n attachmentIds: string[] = []\n) {\n const uniqueIds = [...new Set(attachmentIds)];\n if (!uniqueIds.length) return;\n const { count } = await tx.file.updateMany({\n where: { id: { in: uniqueIds }, userId, uploadStatus: \"COMPLETED\", ...unclaimedAttachmentWhere },\n data: { discussionId },\n });\n if (count !== uniqueIds.length) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"Some attachments are missing, unfinished, or unavailable\" });\n }\n}\n\nasync function claimReplyAttachments(\n tx: AppTransactionClient,\n userId: string,\n replyId: string,\n attachmentIds: string[] = []\n) {\n const uniqueIds = [...new Set(attachmentIds)];\n if (!uniqueIds.length) return;\n const { count } = await tx.file.updateMany({\n where: { id: { in: uniqueIds }, userId, uploadStatus: \"COMPLETED\", ...unclaimedAttachmentWhere },\n data: { discussionReplyId: replyId },\n });\n if (count !== uniqueIds.length) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"Some attachments are missing, unfinished, or unavailable\" });\n }\n}\n\nfunction triggerDiscussionEvent(classId: string, event: string, payload: unknown) {\n pusher.trigger(discussionChannel(classId), event, payload).catch((error) => {\n logger.error(\"Failed to trigger discussion pusher event\", { event, classId, error });\n });\n}\n\nasync function notify(receiverId: string | null | undefined, senderId: string, title: string, content: string) {\n if (!receiverId || receiverId === senderId) return;\n await sendNotification({ receiverId, title, content }).catch((error) => {\n logger.error(\"Failed to send discussion notification\", { receiverId, error });\n });\n}\n\nasync function notifyMentionedUsers(classId: string, senderId: string, body: string, link: string) {\n const usernames = [...new Set(Array.from(body.matchAll(/(^|\\s)@([a-zA-Z0-9_.-]{2,32})/g)).map((match) => match[2]))];\n if (!usernames.length) return;\n const members = await prisma.user.findMany({\n where: {\n username: { in: usernames },\n OR: [\n { teacherIn: { some: { id: classId } } },\n { studentIn: { some: { id: classId } } },\n { schoolMemberships: { some: { status: \"ACTIVE\", school: { classes: { some: { id: classId } } } } } },\n ],\n },\n select: { id: true },\n });\n await Promise.all(members.map((member) => notify(member.id, senderId, \"You were mentioned in a discussion\", link)));\n}\n\nasync function unreadCountsForDiscussions(userId: string, discussionIds: string[]) {\n if (!discussionIds.length) return new Map<string, number>();\n const reads = await prisma.discussionRead.findMany({\n where: { userId, discussionId: { in: discussionIds } },\n select: { discussionId: true, lastReadAt: true },\n });\n const readMap = new Map(reads.map((read) => [read.discussionId, read.lastReadAt]));\n const neverRead = discussionIds.filter((discussionId) => !readMap.has(discussionId));\n const readPredicates = Array.from(readMap.entries()).map(([discussionId, lastReadAt]) => ({\n discussionId,\n createdAt: { gt: lastReadAt },\n }));\n const counts = new Map<string, number>();\n\n const [neverReadCounts, readCounts] = await Promise.all([\n neverRead.length\n ? prisma.discussionReply.groupBy({\n by: [\"discussionId\"],\n where: { discussionId: { in: neverRead }, deletedAt: null, authorId: { not: userId } },\n _count: true,\n })\n : Promise.resolve([]),\n readPredicates.length\n ? prisma.discussionReply.groupBy({\n by: [\"discussionId\"],\n where: { deletedAt: null, authorId: { not: userId }, OR: readPredicates },\n _count: true,\n })\n : Promise.resolve([]),\n ]);\n\n for (const item of [...neverReadCounts, ...readCounts]) {\n counts.set(item.discussionId, item._count);\n }\n return counts;\n}\n\nexport async function listDiscussions(userId: string, input: {\n classId: string;\n tagId?: string;\n type?: DiscussionType;\n search?: string;\n sort: \"recent\" | \"activity\" | \"top\";\n cursor?: string;\n limit: number;\n}) {\n await getDiscussionClassAccess(input.classId, userId);\n const where: Prisma.DiscussionWhereInput = {\n classId: input.classId,\n ...(input.tagId ? { tags: { some: { id: input.tagId } } } : {}),\n ...(input.type ? { type: input.type } : {}),\n ...(input.search?.trim()\n ? {\n OR: [\n { title: { contains: input.search.trim(), mode: \"insensitive\" } },\n { body: { contains: input.search.trim(), mode: \"insensitive\" } },\n ],\n }\n : {}),\n };\n const orderBy: Prisma.DiscussionOrderByWithRelationInput[] =\n input.sort === \"recent\"\n ? [{ isPinned: \"desc\" }, { createdAt: \"desc\" }]\n : input.sort === \"top\"\n ? [{ isPinned: \"desc\" }, { replies: { _count: \"desc\" } }, { lastActivityAt: \"desc\" }]\n : [{ isPinned: \"desc\" }, { lastActivityAt: \"desc\" }];\n\n const items = await prisma.discussion.findMany({\n where,\n include: discussionInclude,\n orderBy,\n cursor: input.cursor ? { id: input.cursor } : undefined,\n skip: input.cursor ? 1 : 0,\n take: input.limit + 1,\n });\n const next = items.length > input.limit ? items.pop() : undefined;\n const unreadMap = await unreadCountsForDiscussions(userId, items.map((item) => item.id));\n const accepted = await prisma.discussionReply.groupBy({\n by: [\"discussionId\"],\n where: { discussionId: { in: items.map((item) => item.id) }, isAcceptedAnswer: true, deletedAt: null },\n });\n const acceptedIds = new Set(accepted.map((item) => item.discussionId));\n\n return {\n items: items.map((item) => ({\n ...serializeDiscussion(item, userId, unreadMap.get(item.id) ?? 0),\n hasAcceptedAnswer: acceptedIds.has(item.id),\n })),\n nextCursor: next?.id,\n };\n}\n\nexport async function getDiscussion(userId: string, discussionId: string) {\n const { discussion: accessDiscussion, isTeacher } = await getDiscussionForUser(discussionId, userId);\n const [discussion, replies, myReaction] = await Promise.all([\n prisma.discussion.findUniqueOrThrow({ where: { id: discussionId }, include: discussionInclude }),\n prisma.discussionReply.findMany({ where: { discussionId }, include: replyInclude, orderBy: { createdAt: \"asc\" } }),\n prisma.reaction.findUnique({ where: { userId_discussionId: { userId, discussionId } }, select: { type: true } }),\n prisma.discussionRead.upsert({\n where: { userId_discussionId: { userId, discussionId } },\n update: { lastReadAt: new Date() },\n create: { userId, discussionId },\n }),\n ]);\n const canAuthorEdit = accessDiscussion.authorId === userId && isWithinAuthorEditWindow(accessDiscussion.createdAt);\n const canReply = isTeacher || (accessDiscussion.class.studentsCanReply && !accessDiscussion.isLocked && accessDiscussion.allowReplies);\n return {\n discussion: serializeDiscussion(discussion, userId),\n replies: buildReplyTree(replies, userId),\n myReaction: myReaction?.type ?? null,\n canEdit: isTeacher || canAuthorEdit,\n canPin: isTeacher,\n canLock: isTeacher,\n canDelete: isTeacher || accessDiscussion.authorId === userId,\n canReply,\n };\n}\n\nexport async function createDiscussion(userId: string, input: {\n classId: string;\n title: string;\n body: string;\n type: DiscussionType;\n tagIds?: string[];\n attachmentIds?: string[];\n}) {\n const classData = await getDiscussionClassAccess(input.classId, userId);\n if (!classData.isTeacher && !classData.studentsCanCreateDiscussions) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Students cannot create discussions in this class\" });\n }\n if (input.type === \"ANNOUNCEMENT\" && !classData.isTeacher) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can create announcement discussions\" });\n }\n\n const discussion = await prisma.$transaction(async (tx) => {\n const created = await tx.discussion.create({\n data: {\n classId: input.classId,\n authorId: userId,\n title: input.title.trim(),\n body: input.body.trim(),\n type: input.type,\n allowReplies: input.type !== \"ANNOUNCEMENT\",\n tags: input.tagIds?.length ? { connect: input.tagIds.map((id) => ({ id })) } : undefined,\n },\n });\n await claimDiscussionAttachments(tx, userId, created.id, input.attachmentIds);\n return tx.discussion.findUniqueOrThrow({ where: { id: created.id }, include: discussionInclude });\n });\n\n triggerDiscussionEvent(input.classId, \"discussion-created\", { discussion: serializeDiscussion(discussion, userId) });\n await notifyMentionedUsers(input.classId, userId, input.body, `/class/${input.classId}/discussions/${discussion.id}`);\n return { discussion: serializeDiscussion(discussion, userId) };\n}\n\nexport async function updateDiscussion(userId: string, input: {\n discussionId: string;\n title?: string;\n body?: string;\n type?: DiscussionType;\n tagIds?: string[];\n allowReplies?: boolean;\n}) {\n const { discussion, isTeacher } = await getDiscussionForUser(input.discussionId, userId);\n if (!isTeacher && !(discussion.authorId === userId && isWithinAuthorEditWindow(discussion.createdAt))) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"You cannot edit this discussion\" });\n }\n if (input.type === \"ANNOUNCEMENT\" && !isTeacher) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can create announcement discussions\" });\n }\n const updated = await prisma.discussion.update({\n where: { id: input.discussionId },\n data: {\n ...(input.title !== undefined ? { title: input.title.trim() } : {}),\n ...(input.body !== undefined ? { body: input.body.trim() } : {}),\n ...(input.type !== undefined ? { type: input.type } : {}),\n ...(input.allowReplies !== undefined ? { allowReplies: input.allowReplies } : {}),\n ...(input.tagIds ? { tags: { set: input.tagIds.map((id) => ({ id })) } } : {}),\n },\n include: discussionInclude,\n });\n triggerDiscussionEvent(updated.classId, \"discussion-updated\", { discussion: serializeDiscussion(updated, userId) });\n return { discussion: serializeDiscussion(updated, userId) };\n}\n\nexport async function deleteDiscussion(userId: string, discussionId: string) {\n const { discussion, isTeacher } = await getDiscussionForUser(discussionId, userId);\n if (!isTeacher && discussion.authorId !== userId) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"You cannot delete this discussion\" });\n }\n await prisma.discussion.delete({ where: { id: discussionId } });\n triggerDiscussionEvent(discussion.classId, \"discussion-deleted\", { discussionId });\n return { success: true };\n}\n\nexport async function replyToDiscussion(userId: string, input: {\n discussionId: string;\n parentReplyId?: string;\n body: string;\n attachmentIds?: string[];\n}) {\n const { discussion, isTeacher } = await getDiscussionForUser(input.discussionId, userId);\n const canReply = isTeacher || (discussion.class.studentsCanReply && !discussion.isLocked && discussion.allowReplies);\n if (!canReply) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"You cannot reply to this discussion\" });\n }\n let parent: { id: string; authorId: string } | null = null;\n if (input.parentReplyId) {\n parent = await prisma.discussionReply.findFirst({\n where: { id: input.parentReplyId, discussionId: input.discussionId },\n select: { id: true, authorId: true },\n });\n if (!parent) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Parent reply not found\" });\n }\n const reply = await prisma.$transaction(async (tx) => {\n const created = await tx.discussionReply.create({\n data: {\n discussionId: input.discussionId,\n authorId: userId,\n parentId: input.parentReplyId,\n body: input.body.trim(),\n },\n });\n await claimReplyAttachments(tx, userId, created.id, input.attachmentIds);\n await tx.discussion.update({\n where: { id: input.discussionId },\n data: { lastActivityAt: new Date() },\n });\n return tx.discussionReply.findUniqueOrThrow({ where: { id: created.id }, include: replyInclude });\n });\n const link = `/class/${discussion.classId}/discussions/${discussion.id}#${reply.id}`;\n await Promise.all([\n notify(discussion.authorId, userId, \"New reply to your discussion\", link),\n notify(parent?.authorId, userId, \"New reply in a discussion thread\", link),\n notifyMentionedUsers(discussion.classId, userId, input.body, link),\n ]);\n triggerDiscussionEvent(discussion.classId, \"reply-created\", { discussionId: discussion.id, reply: serializeReply(reply, userId) });\n return { reply: serializeReply(reply, userId) };\n}\n\nexport async function updateDiscussionReply(userId: string, input: { replyId: string; body: string; attachmentIds?: string[] }) {\n const existing = await prisma.discussionReply.findUnique({ where: { id: input.replyId }, include: { discussion: true } });\n if (!existing) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Reply not found\" });\n const { isTeacher } = await getDiscussionForUser(existing.discussionId, userId);\n if (!isTeacher && !(existing.authorId === userId && isWithinAuthorEditWindow(existing.createdAt))) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"You cannot edit this reply\" });\n }\n const reply = await prisma.$transaction(async (tx) => {\n await tx.file.updateMany({ where: { discussionReplyId: input.replyId }, data: { discussionReplyId: null } });\n await claimReplyAttachments(tx, userId, input.replyId, input.attachmentIds);\n return tx.discussionReply.update({\n where: { id: input.replyId },\n data: { body: input.body.trim(), deletedAt: null },\n include: replyInclude,\n });\n });\n triggerDiscussionEvent(existing.discussion.classId, \"reply-updated\", { discussionId: existing.discussionId, reply: serializeReply(reply, userId) });\n return { reply: serializeReply(reply, userId) };\n}\n\nexport async function deleteDiscussionReply(userId: string, replyId: string) {\n const existing = await prisma.discussionReply.findUnique({ where: { id: replyId }, include: { discussion: true } });\n if (!existing) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Reply not found\" });\n const { isTeacher } = await getDiscussionForUser(existing.discussionId, userId);\n if (!isTeacher && existing.authorId !== userId) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"You cannot delete this reply\" });\n }\n const reply = await prisma.discussionReply.update({\n where: { id: replyId },\n data: { body: \"[deleted]\", deletedAt: new Date(), isAcceptedAnswer: false },\n include: replyInclude,\n });\n triggerDiscussionEvent(existing.discussion.classId, \"reply-deleted\", { discussionId: existing.discussionId, reply: serializeReply(reply, userId) });\n return { reply: serializeReply(reply, userId) };\n}\n\nexport async function pinDiscussion(userId: string, discussionId: string, isPinned: boolean) {\n const { discussion, isTeacher } = await getDiscussionForUser(discussionId, userId);\n if (!isTeacher) throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can pin discussions\" });\n const updated = await prisma.discussion.update({ where: { id: discussionId }, data: { isPinned }, include: discussionInclude });\n await notify(discussion.authorId, userId, isPinned ? \"Your discussion was pinned\" : \"Your discussion was unpinned\", `/class/${discussion.classId}/discussions/${discussionId}`);\n triggerDiscussionEvent(discussion.classId, \"discussion-updated\", { discussion: serializeDiscussion(updated, userId) });\n return { discussion: serializeDiscussion(updated, userId) };\n}\n\nexport async function lockDiscussion(userId: string, discussionId: string, isLocked: boolean) {\n const { discussion, isTeacher } = await getDiscussionForUser(discussionId, userId);\n if (!isTeacher) throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can lock discussions\" });\n const updated = await prisma.discussion.update({ where: { id: discussionId }, data: { isLocked }, include: discussionInclude });\n triggerDiscussionEvent(discussion.classId, \"discussion-updated\", { discussion: serializeDiscussion(updated, userId) });\n return { discussion: serializeDiscussion(updated, userId) };\n}\n\nexport async function markAcceptedAnswer(userId: string, replyId: string, accepted: boolean) {\n const reply = await prisma.discussionReply.findUnique({ where: { id: replyId }, include: { discussion: true } });\n if (!reply) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Reply not found\" });\n const { isTeacher } = await getDiscussionForUser(reply.discussionId, userId);\n if (reply.discussion.type !== \"QUESTION\") {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"Only question discussions can have accepted answers\" });\n }\n if (!isTeacher && reply.discussion.authorId !== userId) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only the discussion author or a teacher can mark an accepted answer\" });\n }\n const updated = await prisma.$transaction(async (tx) => {\n if (accepted) {\n await tx.discussionReply.updateMany({ where: { discussionId: reply.discussionId, isAcceptedAnswer: true }, data: { isAcceptedAnswer: false } });\n }\n return tx.discussionReply.update({ where: { id: replyId }, data: { isAcceptedAnswer: accepted }, include: replyInclude });\n });\n await notify(reply.authorId, userId, accepted ? \"Your answer was accepted\" : \"Your answer was unmarked\", `/class/${reply.discussion.classId}/discussions/${reply.discussionId}#${replyId}`);\n triggerDiscussionEvent(reply.discussion.classId, \"reply-updated\", { discussionId: reply.discussionId, reply: serializeReply(updated, userId) });\n return { reply: serializeReply(updated, userId) };\n}\n\nexport async function markDiscussionRead(userId: string, discussionId: string) {\n await getDiscussionForUser(discussionId, userId);\n return prisma.discussionRead.upsert({\n where: { userId_discussionId: { userId, discussionId } },\n update: { lastReadAt: new Date() },\n create: { userId, discussionId },\n });\n}\n\nexport async function getUnreadCounts(userId: string, classIds: string[]) {\n const allowedClasses = await prisma.class.findMany({\n where: { id: { in: classIds }, discussionsEnabled: true, ...classMemberOrSchoolAdminWhere(userId) },\n select: { id: true },\n });\n const result: Record<string, { total: number; perDiscussion: { discussionId: string; count: number }[] }> = {};\n for (const cls of allowedClasses) {\n const discussions = await prisma.discussion.findMany({\n where: { classId: cls.id },\n select: { id: true },\n });\n const countMap = await unreadCountsForDiscussions(userId, discussions.map((discussion) => discussion.id));\n const perDiscussion = Array.from(countMap.entries())\n .map(([discussionId, count]) => ({ discussionId, count }))\n .filter((item) => item.count > 0);\n result[cls.id] = {\n total: perDiscussion.reduce((sum, item) => sum + item.count, 0),\n perDiscussion,\n };\n }\n return result;\n}\n\nexport async function toggleDiscussionReaction(userId: string, input: { discussionId?: string; discussionReplyId?: string; type: ReactionType }) {\n if (!input.discussionId && !input.discussionReplyId) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"A discussion or reply is required\" });\n }\n if (input.discussionId && input.discussionReplyId) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"React to either a discussion or a reply\" });\n }\n const target = input.discussionId\n ? await getDiscussionForUser(input.discussionId, userId).then(({ discussion }) => ({ classId: discussion.classId, discussionId: discussion.id }))\n : await prisma.discussionReply.findUnique({ where: { id: input.discussionReplyId }, include: { discussion: true } }).then(async (reply) => {\n if (!reply) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Reply not found\" });\n await getDiscussionForUser(reply.discussionId, userId);\n return { classId: reply.discussion.classId, discussionId: reply.discussionId };\n });\n const where = input.discussionId\n ? { userId_discussionId: { userId, discussionId: input.discussionId } }\n : { userId_discussionReplyId: { userId, discussionReplyId: input.discussionReplyId! } };\n const existing = await prisma.reaction.findUnique({ where });\n if (existing?.type === input.type) {\n await prisma.reaction.delete({ where: { id: existing.id } });\n triggerDiscussionEvent(target.classId, \"reaction-removed\", { discussionId: target.discussionId, discussionReplyId: input.discussionReplyId, userId });\n return { reaction: null };\n }\n const reaction = input.discussionId\n ? await prisma.reaction.upsert({\n where: { userId_discussionId: { userId, discussionId: input.discussionId } },\n update: { type: input.type },\n create: { userId, discussionId: input.discussionId, type: input.type },\n })\n : await prisma.reaction.upsert({\n where: { userId_discussionReplyId: { userId, discussionReplyId: input.discussionReplyId! } },\n update: { type: input.type },\n create: { userId, discussionReplyId: input.discussionReplyId!, type: input.type },\n });\n triggerDiscussionEvent(target.classId, \"reaction-added\", { discussionId: target.discussionId, discussionReplyId: input.discussionReplyId, reaction });\n return { reaction };\n}\n\nexport async function listDiscussionTags(userId: string, classId: string) {\n await getDiscussionClassAccess(classId, userId);\n return prisma.classTag.findMany({ where: { classId }, orderBy: { name: \"asc\" } });\n}\n\nexport async function createDiscussionTag(userId: string, input: { classId: string; name: string; color: string }) {\n const isTeacher = await prisma.class.findFirst({ where: { id: input.classId, ...classTeacherOrSchoolAdminWhere(userId) }, select: { id: true, discussionsEnabled: true } });\n if (!isTeacher?.discussionsEnabled) throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can manage discussion tags\" });\n return prisma.classTag.create({ data: { classId: input.classId, name: input.name.trim(), color: input.color } });\n}\n\nexport async function updateDiscussionTag(userId: string, input: { tagId: string; name?: string; color?: string }) {\n const tag = await prisma.classTag.findUnique({ where: { id: input.tagId }, select: { classId: true } });\n if (!tag) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Tag not found\" });\n const isTeacher = await prisma.class.findFirst({ where: { id: tag.classId, ...classTeacherOrSchoolAdminWhere(userId) }, select: { id: true, discussionsEnabled: true } });\n if (!isTeacher?.discussionsEnabled) throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can manage discussion tags\" });\n return prisma.classTag.update({ where: { id: input.tagId }, data: { name: input.name?.trim(), color: input.color } });\n}\n\nexport async function deleteDiscussionTag(userId: string, tagId: string) {\n const tag = await prisma.classTag.findUnique({ where: { id: tagId }, select: { classId: true } });\n if (!tag) throw new TRPCError({ code: \"NOT_FOUND\", message: \"Tag not found\" });\n const isTeacher = await prisma.class.findFirst({ where: { id: tag.classId, ...classTeacherOrSchoolAdminWhere(userId) }, select: { id: true, discussionsEnabled: true } });\n if (!isTeacher?.discussionsEnabled) throw new TRPCError({ code: \"FORBIDDEN\", message: \"Only teachers can manage discussion tags\" });\n await prisma.classTag.delete({ where: { id: tagId } });\n return { success: true };\n}\n"],"names":[],"mappings":"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","debug_id":"032ababf-51bb-5770-84c4-b3ab35e0e66b"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
declare const discussionSummarySchema: z.ZodObject<{
|
|
3
|
+
summary: z.ZodString;
|
|
4
|
+
keyQuestions: z.ZodArray<z.ZodString, "many">;
|
|
5
|
+
unresolvedIssues: z.ZodArray<z.ZodString, "many">;
|
|
6
|
+
participantCount: z.ZodNumber;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
summary: string;
|
|
9
|
+
keyQuestions: string[];
|
|
10
|
+
unresolvedIssues: string[];
|
|
11
|
+
participantCount: number;
|
|
12
|
+
}, {
|
|
13
|
+
summary: string;
|
|
14
|
+
keyQuestions: string[];
|
|
15
|
+
unresolvedIssues: string[];
|
|
16
|
+
participantCount: number;
|
|
17
|
+
}>;
|
|
18
|
+
export type DiscussionSummary = z.infer<typeof discussionSummarySchema>;
|
|
19
|
+
export declare function getDiscussionSummary(userId: string, discussionId: string): Promise<DiscussionSummary>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=discussionSummary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discussionSummary.d.ts","sourceRoot":"/","sources":["services/discussionSummary.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,uBAAuB;;;;;;;;;;;;;;;EAe3B,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAmFxE,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,iBAAiB,CAAC,CA+G5B"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-powered discussion summary service with in-memory + Redis caching.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="123ae967-1b03-513e-8fd2-867781eb48f0")}catch(e){}}();
|
|
6
|
+
import { prisma } from "../lib/prisma.js";
|
|
7
|
+
import { getRedis } from "../lib/redis.js";
|
|
8
|
+
import { inference } from "../utils/inference.js";
|
|
9
|
+
import { logger } from "../utils/logger.js";
|
|
10
|
+
import { TRPCError } from "@trpc/server";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { classMemberOrSchoolAdminWhere } from "../models/access.js";
|
|
13
|
+
const discussionSummarySchema = z.object({
|
|
14
|
+
summary: z
|
|
15
|
+
.string()
|
|
16
|
+
.describe("A concise 2-4 sentence TL;DR of the entire discussion thread."),
|
|
17
|
+
keyQuestions: z
|
|
18
|
+
.array(z.string())
|
|
19
|
+
.describe("Up to 5 important student questions raised in the thread."),
|
|
20
|
+
unresolvedIssues: z
|
|
21
|
+
.array(z.string())
|
|
22
|
+
.describe("Up to 3 questions or topics that remain unanswered or unresolved."),
|
|
23
|
+
participantCount: z
|
|
24
|
+
.number()
|
|
25
|
+
.describe("Number of unique participants in the thread."),
|
|
26
|
+
});
|
|
27
|
+
const REDIS_PREFIX = "discussionSummary:";
|
|
28
|
+
const REDIS_TTL_SECONDS = 60 * 30; // 30 min
|
|
29
|
+
const memoryCache = new Map();
|
|
30
|
+
const MEMORY_TTL_MS = 10 * 60 * 1000; // 10 min
|
|
31
|
+
function memoryCacheKey(discussionId) {
|
|
32
|
+
return discussionId;
|
|
33
|
+
}
|
|
34
|
+
function getMemoryCacheHit(discussionId, currentReplyCount) {
|
|
35
|
+
const entry = memoryCache.get(memoryCacheKey(discussionId));
|
|
36
|
+
if (!entry)
|
|
37
|
+
return undefined;
|
|
38
|
+
if (Date.now() - entry.cachedAt > MEMORY_TTL_MS) {
|
|
39
|
+
memoryCache.delete(memoryCacheKey(discussionId));
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
if (entry.replyCount !== currentReplyCount) {
|
|
43
|
+
memoryCache.delete(memoryCacheKey(discussionId));
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
return entry.value;
|
|
47
|
+
}
|
|
48
|
+
function setMemoryCache(discussionId, value, replyCount) {
|
|
49
|
+
memoryCache.set(memoryCacheKey(discussionId), {
|
|
50
|
+
value,
|
|
51
|
+
replyCount,
|
|
52
|
+
cachedAt: Date.now(),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async function getRedisCacheHit(discussionId, currentReplyCount) {
|
|
56
|
+
const redis = getRedis();
|
|
57
|
+
if (!redis)
|
|
58
|
+
return undefined;
|
|
59
|
+
try {
|
|
60
|
+
const raw = await redis.get(`${REDIS_PREFIX}${discussionId}`);
|
|
61
|
+
if (!raw)
|
|
62
|
+
return undefined;
|
|
63
|
+
const parsed = JSON.parse(raw);
|
|
64
|
+
if (parsed.replyCount !== currentReplyCount)
|
|
65
|
+
return undefined;
|
|
66
|
+
return parsed.value;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function setRedisCache(discussionId, value, replyCount) {
|
|
73
|
+
const redis = getRedis();
|
|
74
|
+
if (!redis)
|
|
75
|
+
return;
|
|
76
|
+
try {
|
|
77
|
+
await redis.set(`${REDIS_PREFIX}${discussionId}`, JSON.stringify({ value, replyCount }), "EX", REDIS_TTL_SECONDS);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
logger.error("Failed to cache discussion summary in Redis", { err });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export async function getDiscussionSummary(userId, discussionId) {
|
|
84
|
+
const discussion = await prisma.discussion.findUnique({
|
|
85
|
+
where: { id: discussionId },
|
|
86
|
+
select: {
|
|
87
|
+
id: true,
|
|
88
|
+
classId: true,
|
|
89
|
+
title: true,
|
|
90
|
+
body: true,
|
|
91
|
+
type: true,
|
|
92
|
+
replies: {
|
|
93
|
+
where: { deletedAt: null },
|
|
94
|
+
select: {
|
|
95
|
+
body: true,
|
|
96
|
+
author: {
|
|
97
|
+
select: {
|
|
98
|
+
username: true,
|
|
99
|
+
profile: { select: { displayName: true } },
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
createdAt: true,
|
|
103
|
+
},
|
|
104
|
+
orderBy: { createdAt: "asc" },
|
|
105
|
+
},
|
|
106
|
+
author: {
|
|
107
|
+
select: {
|
|
108
|
+
username: true,
|
|
109
|
+
profile: { select: { displayName: true } },
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
if (!discussion) {
|
|
115
|
+
throw new TRPCError({
|
|
116
|
+
code: "NOT_FOUND",
|
|
117
|
+
message: "Discussion not found",
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// Verify user is a member of the class
|
|
121
|
+
const classMembership = await prisma.class.findFirst({
|
|
122
|
+
where: { id: discussion.classId, ...classMemberOrSchoolAdminWhere(userId) },
|
|
123
|
+
select: { id: true },
|
|
124
|
+
});
|
|
125
|
+
if (!classMembership) {
|
|
126
|
+
throw new TRPCError({
|
|
127
|
+
code: "UNAUTHORIZED",
|
|
128
|
+
message: "You are not a member of this class",
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const replyCount = discussion.replies.length;
|
|
132
|
+
// Check memory cache
|
|
133
|
+
const memoryCached = getMemoryCacheHit(discussionId, replyCount);
|
|
134
|
+
if (memoryCached)
|
|
135
|
+
return memoryCached;
|
|
136
|
+
// Check Redis cache
|
|
137
|
+
const redisCached = await getRedisCacheHit(discussionId, replyCount);
|
|
138
|
+
if (redisCached) {
|
|
139
|
+
setMemoryCache(discussionId, redisCached, replyCount);
|
|
140
|
+
return redisCached;
|
|
141
|
+
}
|
|
142
|
+
// Build context for inference
|
|
143
|
+
const authorName = discussion.author.profile?.displayName ?? discussion.author.username;
|
|
144
|
+
const threadText = [
|
|
145
|
+
`Title: ${discussion.title}`,
|
|
146
|
+
`Type: ${discussion.type}`,
|
|
147
|
+
`Author: ${authorName}`,
|
|
148
|
+
`Original post:\n${discussion.body}`,
|
|
149
|
+
"",
|
|
150
|
+
...discussion.replies.map((reply, i) => {
|
|
151
|
+
const name = reply.author.profile?.displayName ?? reply.author.username;
|
|
152
|
+
return `Reply ${i + 1} by ${name}:\n${reply.body}`;
|
|
153
|
+
}),
|
|
154
|
+
].join("\n\n");
|
|
155
|
+
const messages = [
|
|
156
|
+
{
|
|
157
|
+
role: "system",
|
|
158
|
+
content: "You are a helpful assistant summarizing a class discussion thread for a teacher. Be concise, specific, and grounded in the actual content. Do not fabricate information.",
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
role: "user",
|
|
162
|
+
content: threadText,
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
role: "user",
|
|
166
|
+
content: "Generate a structured summary of this discussion thread. Include a TL;DR, key student questions, and any unresolved issues.",
|
|
167
|
+
},
|
|
168
|
+
];
|
|
169
|
+
const result = await inference(messages, discussionSummarySchema, {
|
|
170
|
+
reason: "discussion_summary",
|
|
171
|
+
metadata: { discussionId, classId: discussion.classId },
|
|
172
|
+
});
|
|
173
|
+
// Cache result
|
|
174
|
+
setMemoryCache(discussionId, result, replyCount);
|
|
175
|
+
await setRedisCache(discussionId, result, replyCount);
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=discussionSummary.js.map
|
|
179
|
+
//# debugId=123ae967-1b03-513e-8fd2-867781eb48f0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discussionSummary.js","sources":["services/discussionSummary.ts"],"sourceRoot":"/","sourcesContent":["/**\n * AI-powered discussion summary service with in-memory + Redis caching.\n */\nimport { prisma } from \"../lib/prisma.js\";\nimport { getRedis } from \"../lib/redis.js\";\nimport { inference } from \"../utils/inference.js\";\nimport { logger } from \"../utils/logger.js\";\nimport { TRPCError } from \"@trpc/server\";\nimport { z } from \"zod\";\nimport { classMemberOrSchoolAdminWhere } from \"../models/access.js\";\n\nconst discussionSummarySchema = z.object({\n summary: z\n .string()\n .describe(\"A concise 2-4 sentence TL;DR of the entire discussion thread.\"),\n keyQuestions: z\n .array(z.string())\n .describe(\"Up to 5 important student questions raised in the thread.\"),\n unresolvedIssues: z\n .array(z.string())\n .describe(\n \"Up to 3 questions or topics that remain unanswered or unresolved.\",\n ),\n participantCount: z\n .number()\n .describe(\"Number of unique participants in the thread.\"),\n});\n\nexport type DiscussionSummary = z.infer<typeof discussionSummarySchema>;\n\nconst REDIS_PREFIX = \"discussionSummary:\";\nconst REDIS_TTL_SECONDS = 60 * 30; // 30 min\n\nconst memoryCache = new Map<\n string,\n { value: DiscussionSummary; replyCount: number; cachedAt: number }\n>();\nconst MEMORY_TTL_MS = 10 * 60 * 1000; // 10 min\n\nfunction memoryCacheKey(discussionId: string) {\n return discussionId;\n}\n\nfunction getMemoryCacheHit(\n discussionId: string,\n currentReplyCount: number,\n): DiscussionSummary | undefined {\n const entry = memoryCache.get(memoryCacheKey(discussionId));\n if (!entry) return undefined;\n if (Date.now() - entry.cachedAt > MEMORY_TTL_MS) {\n memoryCache.delete(memoryCacheKey(discussionId));\n return undefined;\n }\n if (entry.replyCount !== currentReplyCount) {\n memoryCache.delete(memoryCacheKey(discussionId));\n return undefined;\n }\n return entry.value;\n}\n\nfunction setMemoryCache(\n discussionId: string,\n value: DiscussionSummary,\n replyCount: number,\n) {\n memoryCache.set(memoryCacheKey(discussionId), {\n value,\n replyCount,\n cachedAt: Date.now(),\n });\n}\n\nasync function getRedisCacheHit(\n discussionId: string,\n currentReplyCount: number,\n): Promise<DiscussionSummary | undefined> {\n const redis = getRedis();\n if (!redis) return undefined;\n try {\n const raw = await redis.get(`${REDIS_PREFIX}${discussionId}`);\n if (!raw) return undefined;\n const parsed = JSON.parse(raw) as {\n value: DiscussionSummary;\n replyCount: number;\n };\n if (parsed.replyCount !== currentReplyCount) return undefined;\n return parsed.value;\n } catch {\n return undefined;\n }\n}\n\nasync function setRedisCache(\n discussionId: string,\n value: DiscussionSummary,\n replyCount: number,\n) {\n const redis = getRedis();\n if (!redis) return;\n try {\n await redis.set(\n `${REDIS_PREFIX}${discussionId}`,\n JSON.stringify({ value, replyCount }),\n \"EX\",\n REDIS_TTL_SECONDS,\n );\n } catch (err) {\n logger.error(\"Failed to cache discussion summary in Redis\", { err });\n }\n}\n\nexport async function getDiscussionSummary(\n userId: string,\n discussionId: string,\n): Promise<DiscussionSummary> {\n const discussion = await prisma.discussion.findUnique({\n where: { id: discussionId },\n select: {\n id: true,\n classId: true,\n title: true,\n body: true,\n type: true,\n replies: {\n where: { deletedAt: null },\n select: {\n body: true,\n author: {\n select: {\n username: true,\n profile: { select: { displayName: true } },\n },\n },\n createdAt: true,\n },\n orderBy: { createdAt: \"asc\" },\n },\n author: {\n select: {\n username: true,\n profile: { select: { displayName: true } },\n },\n },\n },\n });\n\n if (!discussion) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Discussion not found\",\n });\n }\n\n // Verify user is a member of the class\n const classMembership = await prisma.class.findFirst({\n where: { id: discussion.classId, ...classMemberOrSchoolAdminWhere(userId) },\n select: { id: true },\n });\n if (!classMembership) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not a member of this class\",\n });\n }\n\n const replyCount = discussion.replies.length;\n\n // Check memory cache\n const memoryCached = getMemoryCacheHit(discussionId, replyCount);\n if (memoryCached) return memoryCached;\n\n // Check Redis cache\n const redisCached = await getRedisCacheHit(discussionId, replyCount);\n if (redisCached) {\n setMemoryCache(discussionId, redisCached, replyCount);\n return redisCached;\n }\n\n // Build context for inference\n const authorName =\n discussion.author.profile?.displayName ?? discussion.author.username;\n const threadText = [\n `Title: ${discussion.title}`,\n `Type: ${discussion.type}`,\n `Author: ${authorName}`,\n `Original post:\\n${discussion.body}`,\n \"\",\n ...discussion.replies.map((reply, i) => {\n const name =\n reply.author.profile?.displayName ?? reply.author.username;\n return `Reply ${i + 1} by ${name}:\\n${reply.body}`;\n }),\n ].join(\"\\n\\n\");\n\n const messages = [\n {\n role: \"system\" as const,\n content:\n \"You are a helpful assistant summarizing a class discussion thread for a teacher. Be concise, specific, and grounded in the actual content. Do not fabricate information.\",\n },\n {\n role: \"user\" as const,\n content: threadText,\n },\n {\n role: \"user\" as const,\n content:\n \"Generate a structured summary of this discussion thread. Include a TL;DR, key student questions, and any unresolved issues.\",\n },\n ];\n\n const result = await inference<DiscussionSummary>(\n messages,\n discussionSummarySchema,\n {\n reason: \"discussion_summary\",\n metadata: { discussionId, classId: discussion.classId },\n },\n );\n\n // Cache result\n setMemoryCache(discussionId, result, replyCount);\n await setRedisCache(discussionId, result, replyCount);\n\n return result;\n}\n"],"names":[],"mappings":"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","debug_id":"123ae967-1b03-513e-8fd2-867781eb48f0"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { EmbeddingSourceType } from '@prisma/client';
|
|
2
|
+
export interface EmbeddingSearchResult {
|
|
3
|
+
id: string;
|
|
4
|
+
sourceType: EmbeddingSourceType;
|
|
5
|
+
sourceId: string;
|
|
6
|
+
content: string;
|
|
7
|
+
metadata: Record<string, unknown>;
|
|
8
|
+
similarity: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Split text into overlapping chunks for embedding.
|
|
12
|
+
*/
|
|
13
|
+
export declare function chunkText(text: string, chunkSize?: number, overlap?: number): string[];
|
|
14
|
+
/**
|
|
15
|
+
* Generate embedding vector for a text string.
|
|
16
|
+
*/
|
|
17
|
+
export declare function generateEmbedding(text: string): Promise<number[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Generate embeddings for multiple texts in a single batch.
|
|
20
|
+
*/
|
|
21
|
+
export declare function generateEmbeddings(texts: string[]): Promise<number[][]>;
|
|
22
|
+
/**
|
|
23
|
+
* Store embeddings for a source document. Replaces any existing embeddings for
|
|
24
|
+
* the same sourceType + sourceId combination.
|
|
25
|
+
*/
|
|
26
|
+
export declare function indexContent(params: {
|
|
27
|
+
classId: string;
|
|
28
|
+
sourceType: EmbeddingSourceType;
|
|
29
|
+
sourceId: string;
|
|
30
|
+
text: string;
|
|
31
|
+
metadata?: Record<string, unknown>;
|
|
32
|
+
}): Promise<number>;
|
|
33
|
+
/**
|
|
34
|
+
* Semantic search over class embeddings using cosine similarity.
|
|
35
|
+
*/
|
|
36
|
+
export declare function searchEmbeddings(params: {
|
|
37
|
+
classId: string;
|
|
38
|
+
query: string;
|
|
39
|
+
limit?: number;
|
|
40
|
+
sourceTypes?: EmbeddingSourceType[];
|
|
41
|
+
}): Promise<EmbeddingSearchResult[]>;
|
|
42
|
+
/**
|
|
43
|
+
* Remove all embeddings for a given source.
|
|
44
|
+
*/
|
|
45
|
+
export declare function removeEmbeddings(params: {
|
|
46
|
+
classId: string;
|
|
47
|
+
sourceType: EmbeddingSourceType;
|
|
48
|
+
sourceId: string;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Index an assignment (title + instructions) into the vector store.
|
|
52
|
+
*/
|
|
53
|
+
export declare function indexAssignment(classId: string, assignmentId: string): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Index a worksheet (questions + answers) into the vector store.
|
|
56
|
+
*/
|
|
57
|
+
export declare function indexWorksheet(classId: string, worksheetId: string): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Index an announcement into the vector store.
|
|
60
|
+
*/
|
|
61
|
+
export declare function indexAnnouncement(classId: string, announcementId: string): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Fire-and-forget: enqueue a background job to embed content.
|
|
64
|
+
* Safe to call from service functions after a create/update.
|
|
65
|
+
*/
|
|
66
|
+
export declare function enqueueEmbedding(classId: string, sourceType: EmbeddingSourceType, sourceId: string): void;
|
|
67
|
+
//# sourceMappingURL=embedding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.d.ts","sourceRoot":"/","sources":["services/embedding.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAQ1D,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,mBAAmB,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAa,EAAE,OAAO,SAAgB,GAAG,MAAM,EAAE,CAoBjG;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAQvE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAY7E;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,mBAAmB,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,GAAG,OAAO,CAAC,MAAM,CAAC,CAmClB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACrC,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAwCnC;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,mBAAmB,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQhB;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB1F;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBxF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9F;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,mBAAmB,EAC/B,QAAQ,EAAE,MAAM,GACf,IAAI,CAKN"}
|