- {safeResults.improvementSuggestions.actionPlan.map((action, index) => (
+ {safeResults.improvementSuggestions.actionPlan.map((action: any, index: number) => (
{index + 1}
@@ -608,6 +664,14 @@ export default function ResultsPage() {
+
+ {/* Share Modal */}
+
setIsShareModalOpen(false)}
+ evaluationId={searchParams.get('id') || undefined}
+ projectTitle={safeResults.projectTitle}
+ />
)
}
diff --git a/components/share-modal.tsx b/components/share-modal.tsx
new file mode 100644
index 0000000..d77bccf
--- /dev/null
+++ b/components/share-modal.tsx
@@ -0,0 +1,296 @@
+"use client"
+
+import { useState, useEffect } from "react"
+import { Copy, Check, Share2, QrCode, Mail } from "lucide-react"
+import { Button } from "@/components/ui/button"
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { useToast } from "@/hooks/use-toast"
+import { generateShareUrl, getCurrentUrl } from "@/lib/config"
+import QRCode from "qrcode"
+
+interface ShareModalProps {
+ isOpen: boolean
+ onClose: () => void
+ evaluationId?: string
+ projectTitle?: string
+}
+
+export function ShareModal({ isOpen, onClose, evaluationId, projectTitle }: ShareModalProps) {
+ const [qrCodeUrl, setQrCodeUrl] = useState
("")
+ const [isGeneratingQR, setIsGeneratingQR] = useState(false)
+ const [copiedLink, setCopiedLink] = useState(false)
+ const [copiedQR, setCopiedQR] = useState(false)
+ const { toast } = useToast()
+
+ // 生成分享連結
+ const shareUrl = evaluationId
+ ? generateShareUrl(evaluationId)
+ : getCurrentUrl()
+
+ // 生成 QR Code
+ useEffect(() => {
+ if (isOpen && shareUrl) {
+ setIsGeneratingQR(true)
+ QRCode.toDataURL(shareUrl, {
+ width: 160,
+ margin: 2,
+ color: {
+ dark: '#000000',
+ light: '#FFFFFF'
+ }
+ })
+ .then(url => {
+ setQrCodeUrl(url)
+ setIsGeneratingQR(false)
+ })
+ .catch(err => {
+ console.error('生成 QR Code 失敗:', err)
+ setIsGeneratingQR(false)
+ toast({
+ title: "錯誤",
+ description: "生成 QR Code 失敗,請稍後再試",
+ variant: "destructive",
+ })
+ })
+ }
+ }, [isOpen, shareUrl, toast])
+
+ // 複製連結
+ const copyLink = async () => {
+ try {
+ await navigator.clipboard.writeText(shareUrl)
+ setCopiedLink(true)
+ toast({
+ title: "成功",
+ description: "連結已複製到剪貼板",
+ })
+ setTimeout(() => setCopiedLink(false), 2000)
+ } catch (err) {
+ console.error('複製失敗:', err)
+ toast({
+ title: "錯誤",
+ description: "複製失敗,請手動複製連結",
+ variant: "destructive",
+ })
+ }
+ }
+
+ // 複製 QR Code
+ const copyQRCode = async () => {
+ if (!qrCodeUrl) return
+
+ try {
+ // 將 base64 轉換為 blob
+ const response = await fetch(qrCodeUrl)
+ const blob = await response.blob()
+
+ // 複製到剪貼板
+ await navigator.clipboard.write([
+ new ClipboardItem({
+ [blob.type]: blob
+ })
+ ])
+
+ setCopiedQR(true)
+ toast({
+ title: "成功",
+ description: "QR Code 已複製到剪貼板",
+ })
+ setTimeout(() => setCopiedQR(false), 2000)
+ } catch (err) {
+ console.error('複製 QR Code 失敗:', err)
+ toast({
+ title: "錯誤",
+ description: "複製 QR Code 失敗,請截圖保存",
+ variant: "destructive",
+ })
+ }
+ }
+
+ // 分享到社群媒體
+ const shareToSocial = (platform: string) => {
+ const encodedUrl = encodeURIComponent(shareUrl)
+ const encodedTitle = encodeURIComponent(`評審結果 - ${projectTitle || 'AI 智能評審系統'}`)
+
+ let shareUrl_template = ""
+
+ switch (platform) {
+ case 'line':
+ shareUrl_template = `https://social-plugins.line.me/lineit/share?url=${encodedUrl}&text=${encodedTitle}`
+ break
+ case 'facebook':
+ shareUrl_template = `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`
+ break
+ case 'email':
+ const emailBody = encodeURIComponent(`您好,\n\n我想與您分享這個評審結果:\n\n${projectTitle || 'AI 智能評審系統'}\n\n請點擊以下連結查看詳細報告:\n${shareUrl}\n\n感謝!`)
+ shareUrl_template = `mailto:?subject=${encodedTitle}&body=${emailBody}`
+ break
+ default:
+ return
+ }
+
+ if (platform === 'email') {
+ window.location.href = shareUrl_template
+ } else {
+ window.open(shareUrl_template, '_blank', 'width=600,height=400')
+ }
+ }
+
+ return (
+
+ )
+}
diff --git a/components/ui/alert-dialog.tsx b/components/ui/alert-dialog.tsx
new file mode 100644
index 0000000..25e7b47
--- /dev/null
+++ b/components/ui/alert-dialog.tsx
@@ -0,0 +1,141 @@
+"use client"
+
+import * as React from "react"
+import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
+
+import { cn } from "@/lib/utils"
+import { buttonVariants } from "@/components/ui/button"
+
+const AlertDialog = AlertDialogPrimitive.Root
+
+const AlertDialogTrigger = AlertDialogPrimitive.Trigger
+
+const AlertDialogPortal = AlertDialogPrimitive.Portal
+
+const AlertDialogOverlay = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
+
+const AlertDialogContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+
+))
+AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
+
+const AlertDialogHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+AlertDialogHeader.displayName = "AlertDialogHeader"
+
+const AlertDialogFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+AlertDialogFooter.displayName = "AlertDialogFooter"
+
+const AlertDialogTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
+
+const AlertDialogDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogDescription.displayName =
+ AlertDialogPrimitive.Description.displayName
+
+const AlertDialogAction = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
+
+const AlertDialogCancel = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
+
+export {
+ AlertDialog,
+ AlertDialogPortal,
+ AlertDialogOverlay,
+ AlertDialogTrigger,
+ AlertDialogContent,
+ AlertDialogHeader,
+ AlertDialogFooter,
+ AlertDialogTitle,
+ AlertDialogDescription,
+ AlertDialogAction,
+ AlertDialogCancel,
+}
diff --git a/components/ui/dialog.tsx b/components/ui/dialog.tsx
new file mode 100644
index 0000000..89c8ac7
--- /dev/null
+++ b/components/ui/dialog.tsx
@@ -0,0 +1,122 @@
+"use client"
+
+import * as React from "react"
+import * as DialogPrimitive from "@radix-ui/react-dialog"
+import { X } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+const Dialog = DialogPrimitive.Root
+
+const DialogTrigger = DialogPrimitive.Trigger
+
+const DialogPortal = DialogPrimitive.Portal
+
+const DialogClose = DialogPrimitive.Close
+
+const DialogOverlay = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
+
+const DialogContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+
+ {children}
+
+
+ 關閉
+
+
+
+))
+DialogContent.displayName = DialogPrimitive.Content.displayName
+
+const DialogHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+DialogHeader.displayName = "DialogHeader"
+
+const DialogFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+DialogFooter.displayName = "DialogFooter"
+
+const DialogTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+DialogTitle.displayName = DialogPrimitive.Title.displayName
+
+const DialogDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+DialogDescription.displayName = DialogPrimitive.Description.displayName
+
+export {
+ Dialog,
+ DialogPortal,
+ DialogOverlay,
+ DialogClose,
+ DialogTrigger,
+ DialogContent,
+ DialogHeader,
+ DialogFooter,
+ DialogTitle,
+ DialogDescription,
+}
diff --git a/components/ui/toaster.tsx b/components/ui/toaster.tsx
new file mode 100644
index 0000000..f6adb95
--- /dev/null
+++ b/components/ui/toaster.tsx
@@ -0,0 +1,35 @@
+"use client"
+
+import {
+ Toast,
+ ToastClose,
+ ToastDescription,
+ ToastProvider,
+ ToastTitle,
+ ToastViewport,
+} from "@/components/ui/toast"
+import { useToast } from "@/hooks/use-toast"
+
+export function Toaster() {
+ const { toasts } = useToast()
+
+ return (
+
+ {toasts.map(function ({ id, title, description, action, ...props }) {
+ return (
+
+
+ {title && {title}}
+ {description && (
+ {description}
+ )}
+
+ {action}
+
+
+ )
+ })}
+
+
+ )
+}
diff --git a/env.example b/env.example
new file mode 100644
index 0000000..047ce7f
--- /dev/null
+++ b/env.example
@@ -0,0 +1,15 @@
+# 應用配置
+NEXT_PUBLIC_APP_URL=http://localhost:12024
+NEXT_PUBLIC_APP_NAME=AI 智能評審系統
+
+# 資料庫配置
+DB_HOST=mysql.theaken.com
+DB_PORT=33306
+DB_NAME=db_AI_scoring
+DB_USER=root
+DB_PASSWORD=zh6161168
+
+# AI 配置
+GEMINI_API_KEY=AIzaSyAN3pEJr_Vn2xkCidGZAq9eQqsMVvpj8g4
+GEMINI_MODEL=gemini-1.5-pro
+GEMINI_MAX_TOKENS=8192
diff --git a/lib/config.ts b/lib/config.ts
new file mode 100644
index 0000000..c1d6c22
--- /dev/null
+++ b/lib/config.ts
@@ -0,0 +1,89 @@
+/**
+ * 應用配置工具類
+ * 用於管理環境變量和應用設置
+ */
+
+// 資料庫配置
+export const dbConfig = {
+ host: process.env.DB_HOST || 'mysql.theaken.com',
+ port: parseInt(process.env.DB_PORT || '33306'),
+ user: process.env.DB_USER || 'root',
+ password: process.env.DB_PASSWORD || 'zh6161168',
+ database: process.env.DB_NAME || 'db_AI_scoring',
+ charset: 'utf8mb4',
+ timezone: '+08:00',
+ acquireTimeout: 60000,
+ timeout: 60000,
+ reconnect: true,
+ multipleStatements: true,
+} as const
+
+// AI 配置
+export const aiConfig = {
+ geminiApiKey: process.env.GEMINI_API_KEY || 'AIzaSyAN3pEJr_Vn2xkCidGZAq9eQqsMVvpj8g4',
+ modelName: process.env.GEMINI_MODEL || 'gemini-1.5-pro',
+ maxTokens: parseInt(process.env.GEMINI_MAX_TOKENS || '8192'),
+} as const
+
+// 獲取應用基礎 URL
+export function getAppUrl(): string {
+ // 在客戶端使用 window.location.origin
+ if (typeof window !== 'undefined') {
+ return window.location.origin
+ }
+
+ // 在服務端使用環境變量,如果沒有設置則使用 localhost:12024
+ return process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:12024'
+}
+
+// 獲取應用名稱
+export function getAppName(): string {
+ return process.env.NEXT_PUBLIC_APP_NAME || 'AI 智能評審系統'
+}
+
+// 生成分享連結
+export function generateShareUrl(evaluationId: string): string {
+ const baseUrl = getAppUrl()
+ return `${baseUrl}/results?id=${evaluationId}`
+}
+
+// 生成當前頁面連結
+export function getCurrentUrl(): string {
+ if (typeof window !== 'undefined') {
+ return window.location.href
+ }
+ return getAppUrl()
+}
+
+// 環境變量配置
+export const config = {
+ appUrl: getAppUrl(),
+ appName: getAppName(),
+ isDevelopment: process.env.NODE_ENV === 'development',
+ isProduction: process.env.NODE_ENV === 'production',
+ database: dbConfig,
+ ai: aiConfig,
+} as const
+
+// 配置驗證
+export function validateConfig(): { isValid: boolean; errors: string[] } {
+ const errors: string[] = []
+
+ // 檢查必要的環境變量
+ if (!process.env.GEMINI_API_KEY) {
+ errors.push('GEMINI_API_KEY 環境變量未設置')
+ }
+
+ if (!process.env.DB_HOST) {
+ errors.push('DB_HOST 環境變量未設置')
+ }
+
+ if (!process.env.DB_NAME) {
+ errors.push('DB_NAME 環境變量未設置')
+ }
+
+ return {
+ isValid: errors.length === 0,
+ errors
+ }
+}
diff --git a/lib/database.ts b/lib/database.ts
index 8c0df39..f036ff4 100644
--- a/lib/database.ts
+++ b/lib/database.ts
@@ -1,19 +1,5 @@
import mysql from 'mysql2/promise';
-
-// 資料庫配置
-const dbConfig = {
- host: process.env.DB_HOST || 'mysql.theaken.com',
- port: parseInt(process.env.DB_PORT || '33306'),
- user: process.env.DB_USER || 'root',
- password: process.env.DB_PASSWORD || 'zh6161168',
- database: process.env.DB_NAME || 'db_AI_scoring',
- charset: 'utf8mb4',
- timezone: '+08:00',
- acquireTimeout: 60000,
- timeout: 60000,
- reconnect: true,
- multipleStatements: true,
-};
+import { dbConfig } from './config';
// 建立連接池
const pool = mysql.createPool({
diff --git a/lib/services/gemini.ts b/lib/services/gemini.ts
index d12d240..587a371 100644
--- a/lib/services/gemini.ts
+++ b/lib/services/gemini.ts
@@ -1,7 +1,7 @@
import { GoogleGenerativeAI } from '@google/generative-ai';
+import { aiConfig } from '../config';
-const API_KEY = 'AIzaSyAN3pEJr_Vn2xkCidGZAq9eQqsMVvpj8g4';
-const genAI = new GoogleGenerativeAI(API_KEY);
+const genAI = new GoogleGenerativeAI(aiConfig.geminiApiKey);
export interface CriteriaItem {
id: string;
diff --git a/lib/utils/html-pdf-generator.ts b/lib/utils/html-pdf-generator.ts
new file mode 100644
index 0000000..6c291ec
--- /dev/null
+++ b/lib/utils/html-pdf-generator.ts
@@ -0,0 +1,504 @@
+import puppeteer from 'puppeteer';
+
+export interface PDFReportData {
+ projectTitle: string;
+ overallScore: number;
+ totalPossible: number;
+ grade: string;
+ analysisDate: string;
+ criteria: Array<{
+ name: string;
+ score: number;
+ maxScore: number;
+ weight: number;
+ weightedScore: number;
+ percentage: number;
+ feedback: string;
+ strengths: string[];
+ improvements: string[];
+ }>;
+ overview: {
+ excellentItems: number;
+ improvementItems: number;
+ overallPerformance: number;
+ };
+ improvementSuggestions: {
+ overallSuggestions: string;
+ maintainStrengths: Array<{
+ title: string;
+ description: string;
+ }>;
+ keyImprovements: Array<{
+ title: string;
+ subtitle?: string;
+ description?: string;
+ suggestions: string[];
+ }>;
+ actionPlan: Array<{
+ phase: string;
+ description: string;
+ }>;
+ };
+}
+
+export class HTMLPDFGenerator {
+ private generateHTML(data: PDFReportData): string {
+ return `
+
+
+
+
+
+ AI 智能評審報告
+
+
+
+
+
+
+
總評結果
+
+
${data.overallScore}/${data.totalPossible}
+
${data.grade}
+
+
+
+
+
統計概覽
+
+
+
${data.overview.excellentItems}
+
優秀項目
+
+
+
${data.overview.improvementItems}
+
待改進項目
+
+
+
${data.overview.overallPerformance}%
+
整體表現
+
+
+
+
+
+
評分明細
+
+
+
+ 評分項目 |
+ 得分 |
+ 權重 |
+ 加權分 |
+
+
+
+ ${data.criteria.map(item => `
+
+ ${item.name} |
+ ${item.score}/${item.maxScore} |
+ ${item.weight}% |
+ ${item.weightedScore.toFixed(1)} |
+
+ `).join('')}
+
+
+
+
+
+
詳細分析
+ ${data.criteria.map(item => `
+
+
${item.name}
+
得分:${item.score}/${item.maxScore} (${item.percentage.toFixed(1)}%)
+
+ AI 評語:${item.feedback}
+
+ ${item.strengths.length > 0 ? `
+
+
優點:
+
+ ${item.strengths.map(strength => `- ${strength}
`).join('')}
+
+
+ ` : ''}
+ ${item.improvements.length > 0 ? `
+
+
改進建議:
+
+ ${item.improvements.map(improvement => `- ${improvement}
`).join('')}
+
+
+ ` : ''}
+
+ `).join('')}
+
+
+
+
整體改進建議
+
+
${data.improvementSuggestions.overallSuggestions}
+
+
+
+ ${data.improvementSuggestions.maintainStrengths.length > 0 ? `
+
+
繼續保持的優勢
+
+ ${data.improvementSuggestions.maintainStrengths.map(strength => `
+
+
${strength.title}
+
${strength.description}
+
+ `).join('')}
+
+
+ ` : ''}
+
+ ${data.improvementSuggestions.keyImprovements.length > 0 ? `
+
+
重點改進方向
+
+ ${data.improvementSuggestions.keyImprovements.map(improvement => `
+
+
${improvement.title}
+ ${improvement.description ? `
${improvement.description}
` : ''}
+ ${improvement.suggestions.length > 0 ? `
+
+
+ ${improvement.suggestions.map(suggestion => `- ${suggestion}
`).join('')}
+
+
+ ` : ''}
+
+ `).join('')}
+
+
+ ` : ''}
+
+ ${data.improvementSuggestions.actionPlan.length > 0 ? `
+
+
下一步行動計劃
+
+ ${data.improvementSuggestions.actionPlan.map((action, index) => `
+
+
${index + 1}
+
+
${action.phase}
+
${action.description}
+
+
+ `).join('')}
+
+
+ ` : ''}
+
+
+
+
+ `;
+ }
+
+ public async generateReport(data: PDFReportData): Promise {
+ const browser = await puppeteer.launch({
+ headless: true,
+ args: [
+ '--no-sandbox',
+ '--disable-setuid-sandbox',
+ '--disable-dev-shm-usage',
+ '--disable-accelerated-2d-canvas',
+ '--no-first-run',
+ '--no-zygote',
+ '--disable-gpu'
+ ],
+ timeout: 30000
+ });
+
+ try {
+ const page = await browser.newPage();
+
+ // 設置頁面內容
+ const html = this.generateHTML(data);
+ await page.setContent(html, { waitUntil: 'networkidle0' });
+
+ // 生成 PDF
+ const pdfBuffer = await page.pdf({
+ format: 'A4',
+ printBackground: true,
+ margin: {
+ top: '20mm',
+ right: '20mm',
+ bottom: '20mm',
+ left: '20mm'
+ }
+ });
+
+ return new Blob([pdfBuffer], { type: 'application/pdf' });
+ } finally {
+ await browser.close();
+ }
+ }
+}
+
+// 便捷函數
+export async function generateHTMLPDFReport(data: PDFReportData): Promise {
+ const generator = new HTMLPDFGenerator();
+ return generator.generateReport(data);
+}
diff --git a/lib/utils/pdf-generator-chinese.ts b/lib/utils/pdf-generator-chinese.ts
new file mode 100644
index 0000000..cfa79c7
--- /dev/null
+++ b/lib/utils/pdf-generator-chinese.ts
@@ -0,0 +1,319 @@
+import jsPDF from 'jspdf';
+import 'jspdf-autotable';
+
+export interface PDFReportData {
+ projectTitle: string;
+ overallScore: number;
+ totalPossible: number;
+ grade: string;
+ analysisDate: string;
+ criteria: Array<{
+ name: string;
+ score: number;
+ maxScore: number;
+ weight: number;
+ weightedScore: number;
+ percentage: number;
+ feedback: string;
+ strengths: string[];
+ improvements: string[];
+ }>;
+ overview: {
+ excellentItems: number;
+ improvementItems: number;
+ overallPerformance: number;
+ };
+ improvementSuggestions: {
+ overallSuggestions: string;
+ maintainStrengths: Array<{
+ title: string;
+ description: string;
+ }>;
+ keyImprovements: Array<{
+ title: string;
+ subtitle?: string;
+ description?: string;
+ suggestions: string[];
+ }>;
+ actionPlan: Array<{
+ phase: string;
+ description: string;
+ }>;
+ };
+}
+
+export class ChinesePDFReportGenerator {
+ private doc: jsPDF;
+ private currentY: number = 20;
+ private pageHeight: number = 280;
+ private margin: number = 20;
+
+ constructor() {
+ this.doc = new jsPDF('p', 'mm', 'a4');
+ }
+
+ private addNewPageIfNeeded(requiredSpace: number = 20): void {
+ if (this.currentY + requiredSpace > this.pageHeight) {
+ this.doc.addPage();
+ this.currentY = 20;
+ }
+ }
+
+ private addTitle(text: string, fontSize: number = 16, isBold: boolean = true): void {
+ this.addNewPageIfNeeded(10);
+ this.doc.setFontSize(fontSize);
+ this.doc.setFont('helvetica', isBold ? 'bold' : 'normal');
+
+ // 將中文轉換為可顯示的格式
+ const displayText = this.convertChineseText(text);
+ this.doc.text(displayText, this.margin, this.currentY);
+ this.currentY += fontSize + 5;
+ }
+
+ private addSubtitle(text: string, fontSize: number = 12): void {
+ this.addNewPageIfNeeded(8);
+ this.doc.setFontSize(fontSize);
+ this.doc.setFont('helvetica', 'bold');
+
+ const displayText = this.convertChineseText(text);
+ this.doc.text(displayText, this.margin, this.currentY);
+ this.currentY += fontSize + 3;
+ }
+
+ private addText(text: string, fontSize: number = 10, isBold: boolean = false): void {
+ this.addNewPageIfNeeded(6);
+ this.doc.setFontSize(fontSize);
+ this.doc.setFont('helvetica', isBold ? 'bold' : 'normal');
+
+ const displayText = this.convertChineseText(text);
+
+ // 處理長文本換行
+ const maxWidth = 170;
+ const lines = this.doc.splitTextToSize(displayText, maxWidth);
+
+ for (const line of lines) {
+ this.addNewPageIfNeeded(6);
+ this.doc.text(line, this.margin, this.currentY);
+ this.currentY += 6;
+ }
+ }
+
+ private addBulletList(items: string[], fontSize: number = 10): void {
+ for (const item of items) {
+ this.addNewPageIfNeeded(6);
+ this.doc.setFontSize(fontSize);
+ this.doc.setFont('helvetica', 'normal');
+
+ const displayText = this.convertChineseText(item);
+ this.doc.text(`• ${displayText}`, this.margin + 5, this.currentY);
+ this.currentY += 6;
+ }
+ }
+
+ private addScoreBox(score: number, total: number, grade: string): void {
+ this.addNewPageIfNeeded(25);
+
+ // 繪製分數框
+ this.doc.setFillColor(240, 240, 240);
+ this.doc.rect(this.margin, this.currentY, 50, 20, 'F');
+
+ // 分數文字
+ this.doc.setFontSize(18);
+ this.doc.setFont('helvetica', 'bold');
+ this.doc.text(`${score}/${total}`, this.margin + 5, this.currentY + 12);
+
+ // 等級
+ this.doc.setFontSize(12);
+ this.doc.text(grade, this.margin + 5, this.currentY + 18);
+
+ this.currentY += 25;
+ }
+
+ private addCriteriaTable(criteria: PDFReportData['criteria']): void {
+ this.addNewPageIfNeeded(30);
+
+ // 準備表格數據
+ const tableData = criteria.map(item => [
+ this.convertChineseText(item.name),
+ `${item.score}/${item.maxScore}`,
+ `${item.weight}%`,
+ item.weightedScore.toFixed(1)
+ ]);
+
+ // 使用 autoTable 插件創建表格
+ (this.doc as any).autoTable({
+ head: [['評分項目', '得分', '權重', '加權分']],
+ body: tableData,
+ startY: this.currentY,
+ margin: { left: this.margin, right: this.margin },
+ styles: { fontSize: 10 },
+ headStyles: { fillColor: [66, 139, 202] },
+ alternateRowStyles: { fillColor: [245, 245, 245] }
+ });
+
+ // 更新當前 Y 位置
+ this.currentY = (this.doc as any).lastAutoTable.finalY + 10;
+ }
+
+ // 將中文字符轉換為可顯示的格式
+ private convertChineseText(text: string): string {
+ // 簡單的字符替換,將常見的中文字符替換為英文描述
+ const chineseMap: { [key: string]: string } = {
+ '評審結果': 'Evaluation Results',
+ 'AI 智能評審報告': 'AI Intelligent Evaluation Report',
+ '專案名稱': 'Project Name',
+ '分析日期': 'Analysis Date',
+ '總評結果': 'Overall Results',
+ '統計概覽': 'Statistical Overview',
+ '優秀項目': 'Excellent Items',
+ '待改進項目': 'Items to Improve',
+ '整體表現': 'Overall Performance',
+ '評分明細': 'Score Details',
+ '評分項目': 'Evaluation Items',
+ '得分': 'Score',
+ '權重': 'Weight',
+ '加權分': 'Weighted Score',
+ '詳細分析': 'Detailed Analysis',
+ 'AI 評語': 'AI Comments',
+ '優點': 'Strengths',
+ '改進建議': 'Improvement Suggestions',
+ '整體改進建議': 'Overall Improvement Suggestions',
+ '繼續保持的優勢': 'Maintain Strengths',
+ '重點改進方向': 'Key Improvement Areas',
+ '下一步行動計劃': 'Next Action Plan',
+ '本報告由 AI 智能評審系統生成': 'Generated by AI Intelligent Evaluation System',
+ '生成時間': 'Generated Time',
+ '內容品質': 'Content Quality',
+ '視覺設計': 'Visual Design',
+ '邏輯結構': 'Logical Structure',
+ '創新性': 'Innovation',
+ '實用性': 'Practicality'
+ };
+
+ let result = text;
+
+ // 替換已知的中文詞彙
+ for (const [chinese, english] of Object.entries(chineseMap)) {
+ result = result.replace(new RegExp(chinese, 'g'), english);
+ }
+
+ // 對於其他中文字符,使用 Unicode 轉換
+ result = result.replace(/[\u4e00-\u9fff]/g, (char) => {
+ const code = char.charCodeAt(0);
+ return `[U+${code.toString(16).toUpperCase()}]`;
+ });
+
+ return result;
+ }
+
+ public generateReport(data: PDFReportData): Promise {
+ return new Promise((resolve, reject) => {
+ try {
+ // 標題頁
+ this.addTitle('AI Intelligent Evaluation Report', 20);
+ this.addText(`Project Name: ${data.projectTitle}`, 12, true);
+ this.addText(`Analysis Date: ${data.analysisDate}`, 12);
+ this.currentY += 10;
+
+ // 總分顯示
+ this.addSubtitle('Overall Results');
+ this.addScoreBox(data.overallScore, data.totalPossible, data.grade);
+
+ // 統計概覽
+ this.addSubtitle('Statistical Overview');
+ this.addText(`Excellent Items: ${data.overview.excellentItems} items`);
+ this.addText(`Items to Improve: ${data.overview.improvementItems} items`);
+ this.addText(`Overall Performance: ${data.overview.overallPerformance}%`);
+ this.currentY += 10;
+
+ // 評分明細
+ this.addSubtitle('Score Details');
+ this.addCriteriaTable(data.criteria);
+
+ // 詳細分析
+ this.addSubtitle('Detailed Analysis');
+ for (const item of data.criteria) {
+ this.addNewPageIfNeeded(20);
+ this.doc.setFontSize(11);
+ this.doc.setFont('helvetica', 'bold');
+ this.doc.text(this.convertChineseText(item.name), this.margin, this.currentY);
+ this.currentY += 8;
+
+ this.addText(`Score: ${item.score}/${item.maxScore} (${item.percentage.toFixed(1)}%)`, 10);
+ this.addText(`AI Comments: ${item.feedback}`, 10);
+
+ if (item.strengths.length > 0) {
+ this.addText('Strengths:', 10, true);
+ this.addBulletList(item.strengths, 9);
+ }
+
+ if (item.improvements.length > 0) {
+ this.addText('Improvement Suggestions:', 10, true);
+ this.addBulletList(item.improvements, 9);
+ }
+
+ this.currentY += 10;
+ }
+
+ // 改進建議
+ this.addSubtitle('Overall Improvement Suggestions');
+ this.addText(data.improvementSuggestions.overallSuggestions, 10);
+ this.currentY += 10;
+
+ // 保持的優勢
+ if (data.improvementSuggestions.maintainStrengths.length > 0) {
+ this.addSubtitle('Maintain Strengths');
+ for (const strength of data.improvementSuggestions.maintainStrengths) {
+ this.addText(strength.title, 10, true);
+ this.addText(strength.description, 9);
+ this.currentY += 5;
+ }
+ }
+
+ // 重點改進方向
+ if (data.improvementSuggestions.keyImprovements.length > 0) {
+ this.addSubtitle('Key Improvement Areas');
+ for (const improvement of data.improvementSuggestions.keyImprovements) {
+ this.addText(improvement.title, 10, true);
+ if (improvement.description) {
+ this.addText(improvement.description, 9);
+ }
+ if (improvement.suggestions.length > 0) {
+ this.addBulletList(improvement.suggestions, 9);
+ }
+ this.currentY += 5;
+ }
+ }
+
+ // 行動計劃
+ if (data.improvementSuggestions.actionPlan.length > 0) {
+ this.addSubtitle('Next Action Plan');
+ for (let i = 0; i < data.improvementSuggestions.actionPlan.length; i++) {
+ const action = data.improvementSuggestions.actionPlan[i];
+ this.addText(`${i + 1}. ${action.phase}`, 10, true);
+ this.addText(action.description, 9);
+ this.currentY += 5;
+ }
+ }
+
+ // 頁腳
+ this.doc.setFontSize(8);
+ this.doc.setFont('helvetica', 'normal');
+ this.doc.text('Generated by AI Intelligent Evaluation System', this.margin, this.pageHeight - 10);
+ this.doc.text(`Generated Time: ${new Date().toLocaleString('en-US')}`, this.margin + 100, this.pageHeight - 10);
+
+ // 生成 PDF Blob
+ const pdfBlob = this.doc.output('blob');
+ resolve(pdfBlob);
+ } catch (error) {
+ reject(error);
+ }
+ });
+ }
+}
+
+// 便捷函數
+export async function generateChinesePDFReport(data: PDFReportData): Promise {
+ const generator = new ChinesePDFReportGenerator();
+ return generator.generateReport(data);
+}
diff --git a/lib/utils/pdf-generator.ts b/lib/utils/pdf-generator.ts
new file mode 100644
index 0000000..8edf738
--- /dev/null
+++ b/lib/utils/pdf-generator.ts
@@ -0,0 +1,269 @@
+import jsPDF from 'jspdf';
+import 'jspdf-autotable';
+import html2canvas from 'html2canvas';
+
+export interface PDFReportData {
+ projectTitle: string;
+ overallScore: number;
+ totalPossible: number;
+ grade: string;
+ analysisDate: string;
+ criteria: Array<{
+ name: string;
+ score: number;
+ maxScore: number;
+ weight: number;
+ weightedScore: number;
+ percentage: number;
+ feedback: string;
+ strengths: string[];
+ improvements: string[];
+ }>;
+ overview: {
+ excellentItems: number;
+ improvementItems: number;
+ overallPerformance: number;
+ };
+ improvementSuggestions: {
+ overallSuggestions: string;
+ maintainStrengths: Array<{
+ title: string;
+ description: string;
+ }>;
+ keyImprovements: Array<{
+ title: string;
+ subtitle?: string;
+ description?: string;
+ suggestions: string[];
+ }>;
+ actionPlan: Array<{
+ phase: string;
+ description: string;
+ }>;
+ };
+}
+
+export class PDFReportGenerator {
+ private doc: jsPDF;
+ private currentY: number = 20;
+ private pageHeight: number = 280;
+ private margin: number = 20;
+
+ constructor() {
+ this.doc = new jsPDF('p', 'mm', 'a4');
+ // 設置支援中文的默認字體
+ this.doc.setFont('helvetica');
+ }
+
+ private addNewPageIfNeeded(requiredSpace: number = 20): void {
+ if (this.currentY + requiredSpace > this.pageHeight) {
+ this.doc.addPage();
+ this.currentY = 20;
+ }
+ }
+
+ private addTitle(text: string, fontSize: number = 16, isBold: boolean = true): void {
+ this.addNewPageIfNeeded(10);
+ this.doc.setFontSize(fontSize);
+ this.doc.setFont('helvetica', isBold ? 'bold' : 'normal');
+ this.doc.text(text, this.margin, this.currentY);
+ this.currentY += fontSize + 5;
+ }
+
+ private addSubtitle(text: string, fontSize: number = 12): void {
+ this.addNewPageIfNeeded(8);
+ this.doc.setFontSize(fontSize);
+ this.doc.setFont('helvetica', 'bold');
+ this.doc.text(text, this.margin, this.currentY);
+ this.currentY += fontSize + 3;
+ }
+
+ private addText(text: string, fontSize: number = 10, isBold: boolean = false): void {
+ this.addNewPageIfNeeded(6);
+ this.doc.setFontSize(fontSize);
+ this.doc.setFont('helvetica', isBold ? 'bold' : 'normal');
+
+ // 處理長文本換行
+ const maxWidth = 170; // A4 寬度減去邊距
+ const lines = this.doc.splitTextToSize(text, maxWidth);
+
+ for (const line of lines) {
+ this.addNewPageIfNeeded(6);
+ this.doc.text(line, this.margin, this.currentY);
+ this.currentY += 6;
+ }
+ }
+
+ private addBulletList(items: string[], fontSize: number = 10): void {
+ for (const item of items) {
+ this.addNewPageIfNeeded(6);
+ this.doc.setFontSize(fontSize);
+ this.doc.setFont('helvetica', 'normal');
+ this.doc.text(`• ${item}`, this.margin + 5, this.currentY);
+ this.currentY += 6;
+ }
+ }
+
+ private addScoreBox(score: number, total: number, grade: string): void {
+ this.addNewPageIfNeeded(25);
+
+ // 繪製分數框
+ this.doc.setFillColor(240, 240, 240);
+ this.doc.rect(this.margin, this.currentY, 50, 20, 'F');
+
+ // 分數文字
+ this.doc.setFontSize(18);
+ this.doc.setFont('helvetica', 'bold');
+ this.doc.text(`${score}/${total}`, this.margin + 5, this.currentY + 12);
+
+ // 等級
+ this.doc.setFontSize(12);
+ this.doc.text(grade, this.margin + 5, this.currentY + 18);
+
+ this.currentY += 25;
+ }
+
+ private addCriteriaTable(criteria: PDFReportData['criteria']): void {
+ this.addNewPageIfNeeded(30);
+
+ // 表頭
+ this.doc.setFontSize(10);
+ this.doc.setFont('helvetica', 'bold');
+ this.doc.text('評分項目', this.margin, this.currentY);
+ this.doc.text('得分', this.margin + 100, this.currentY);
+ this.doc.text('權重', this.margin + 130, this.currentY);
+ this.doc.text('加權分', this.margin + 150, this.currentY);
+
+ this.currentY += 8;
+
+ // 分隔線
+ this.doc.line(this.margin, this.currentY, this.margin + 170, this.currentY);
+ this.currentY += 5;
+
+ // 數據行
+ for (const item of criteria) {
+ this.addNewPageIfNeeded(15);
+
+ this.doc.setFont('helvetica', 'normal');
+ this.doc.text(item.name, this.margin, this.currentY);
+ this.doc.text(`${item.score}/${item.maxScore}`, this.margin + 100, this.currentY);
+ this.doc.text(`${item.weight}%`, this.margin + 130, this.currentY);
+ this.doc.text(item.weightedScore.toFixed(1), this.margin + 150, this.currentY);
+
+ this.currentY += 6;
+ }
+
+ this.currentY += 10;
+ }
+
+ public generateReport(data: PDFReportData): Promise {
+ return new Promise((resolve, reject) => {
+ try {
+ // 標題頁
+ this.addTitle('AI 智能評審報告', 20);
+ this.addText(`專案名稱:${data.projectTitle}`, 12, true);
+ this.addText(`分析日期:${data.analysisDate}`, 12);
+ this.currentY += 10;
+
+ // 總分顯示
+ this.addSubtitle('總評結果');
+ this.addScoreBox(data.overallScore, data.totalPossible, data.grade);
+
+ // 統計概覽
+ this.addSubtitle('統計概覽');
+ this.addText(`優秀項目:${data.overview.excellentItems} 項`);
+ this.addText(`待改進項目:${data.overview.improvementItems} 項`);
+ this.addText(`整體表現:${data.overview.overallPerformance}%`);
+ this.currentY += 10;
+
+ // 評分明細
+ this.addSubtitle('評分明細');
+ this.addCriteriaTable(data.criteria);
+
+ // 詳細分析
+ this.addSubtitle('詳細分析');
+ for (const item of data.criteria) {
+ this.addNewPageIfNeeded(20);
+ this.doc.setFontSize(11);
+ this.doc.setFont('helvetica', 'bold');
+ this.doc.text(item.name, this.margin, this.currentY);
+ this.currentY += 8;
+
+ this.addText(`得分:${item.score}/${item.maxScore} (${item.percentage.toFixed(1)}%)`, 10);
+ this.addText(`AI 評語:${item.feedback}`, 10);
+
+ if (item.strengths.length > 0) {
+ this.addText('優點:', 10, true);
+ this.addBulletList(item.strengths, 9);
+ }
+
+ if (item.improvements.length > 0) {
+ this.addText('改進建議:', 10, true);
+ this.addBulletList(item.improvements, 9);
+ }
+
+ this.currentY += 10;
+ }
+
+ // 改進建議
+ this.addSubtitle('整體改進建議');
+ this.addText(data.improvementSuggestions.overallSuggestions, 10);
+ this.currentY += 10;
+
+ // 保持的優勢
+ if (data.improvementSuggestions.maintainStrengths.length > 0) {
+ this.addSubtitle('繼續保持的優勢');
+ for (const strength of data.improvementSuggestions.maintainStrengths) {
+ this.addText(strength.title, 10, true);
+ this.addText(strength.description, 9);
+ this.currentY += 5;
+ }
+ }
+
+ // 重點改進方向
+ if (data.improvementSuggestions.keyImprovements.length > 0) {
+ this.addSubtitle('重點改進方向');
+ for (const improvement of data.improvementSuggestions.keyImprovements) {
+ this.addText(improvement.title, 10, true);
+ if (improvement.description) {
+ this.addText(improvement.description, 9);
+ }
+ if (improvement.suggestions.length > 0) {
+ this.addBulletList(improvement.suggestions, 9);
+ }
+ this.currentY += 5;
+ }
+ }
+
+ // 行動計劃
+ if (data.improvementSuggestions.actionPlan.length > 0) {
+ this.addSubtitle('下一步行動計劃');
+ for (let i = 0; i < data.improvementSuggestions.actionPlan.length; i++) {
+ const action = data.improvementSuggestions.actionPlan[i];
+ this.addText(`${i + 1}. ${action.phase}`, 10, true);
+ this.addText(action.description, 9);
+ this.currentY += 5;
+ }
+ }
+
+ // 頁腳
+ this.doc.setFontSize(8);
+ this.doc.setFont('helvetica', 'normal');
+ this.doc.text('本報告由 AI 智能評審系統生成', this.margin, this.pageHeight - 10);
+ this.doc.text(`生成時間:${new Date().toLocaleString('zh-TW')}`, this.margin + 100, this.pageHeight - 10);
+
+ // 生成 PDF Blob
+ const pdfBlob = this.doc.output('blob');
+ resolve(pdfBlob);
+ } catch (error) {
+ reject(error);
+ }
+ });
+ }
+}
+
+// 便捷函數
+export async function generatePDFReport(data: PDFReportData): Promise {
+ const generator = new PDFReportGenerator();
+ return generator.generateReport(data);
+}
diff --git a/package.json b/package.json
index 8a48314..a46e921 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,8 @@
"lint": "next lint",
"start": "next start -p 12024",
"db:init": "node scripts/init-database-simple.js",
- "db:test": "node scripts/test-database.js"
+ "db:test": "node scripts/test-database.js",
+ "config:check": "node scripts/check-config.js"
},
"dependencies": {
"@google/generative-ai": "^0.24.1",
@@ -40,6 +41,7 @@
"@radix-ui/react-toggle": "1.1.1",
"@radix-ui/react-toggle-group": "1.1.1",
"@radix-ui/react-tooltip": "1.1.6",
+ "@types/qrcode": "^1.5.5",
"@vercel/analytics": "latest",
"adm-zip": "^0.5.16",
"autoprefixer": "^10.4.20",
@@ -49,7 +51,10 @@
"date-fns": "4.1.0",
"embla-carousel-react": "8.5.1",
"geist": "latest",
+ "html2canvas": "^1.4.1",
"input-otp": "1.4.1",
+ "jspdf": "^3.0.3",
+ "jspdf-autotable": "^5.0.2",
"lucide-react": "^0.454.0",
"mammoth": "^1.11.0",
"mysql2": "^3.15.0",
@@ -57,6 +62,8 @@
"next-themes": "^0.4.6",
"node-fetch": "^3.3.2",
"node-pptx": "^1.0.0",
+ "puppeteer": "^24.22.1",
+ "qrcode": "^1.5.4",
"react": "^18",
"react-day-picker": "9.8.0",
"react-dom": "^18",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a4dbb15..9b48347 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -95,6 +95,9 @@ importers:
'@radix-ui/react-tooltip':
specifier: 1.1.6
version: 1.1.6(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0(react@18.0.0))(react@18.0.0)
+ '@types/qrcode':
+ specifier: ^1.5.5
+ version: 1.5.5
'@vercel/analytics':
specifier: latest
version: 1.5.0(next@14.2.16(react-dom@18.0.0(react@18.0.0))(react@18.0.0))(react@18.0.0)
@@ -122,9 +125,18 @@ importers:
geist:
specifier: latest
version: 1.5.1(next@14.2.16(react-dom@18.0.0(react@18.0.0))(react@18.0.0))
+ html2canvas:
+ specifier: ^1.4.1
+ version: 1.4.1
input-otp:
specifier: 1.4.1
version: 1.4.1(react-dom@18.0.0(react@18.0.0))(react@18.0.0)
+ jspdf:
+ specifier: ^3.0.3
+ version: 3.0.3
+ jspdf-autotable:
+ specifier: ^5.0.2
+ version: 5.0.2(jspdf@3.0.3)
lucide-react:
specifier: ^0.454.0
version: 0.454.0(react@18.0.0)
@@ -146,6 +158,12 @@ importers:
node-pptx:
specifier: ^1.0.0
version: 1.0.0
+ puppeteer:
+ specifier: ^24.22.1
+ version: 24.22.1(typescript@5.0.2)
+ qrcode:
+ specifier: ^1.5.4
+ version: 1.5.4
react:
specifier: ^18
version: 18.0.0
@@ -218,6 +236,18 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
+ '@babel/code-frame@7.27.1':
+ resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.27.1':
+ resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/runtime@7.28.4':
+ resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
+ engines: {node: '>=6.9.0'}
+
'@date-fns/tz@1.2.0':
resolution: {integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==}
@@ -319,6 +349,11 @@ packages:
cpu: [x64]
os: [win32]
+ '@puppeteer/browsers@2.10.10':
+ resolution: {integrity: sha512-3ZG500+ZeLql8rE0hjfhkycJjDj0pI/btEh3L9IkWUYcOrgP0xCNRq3HbtbqOPbvDhFaAWD88pDFtlLv8ns8gA==}
+ engines: {node: '>=18'}
+ hasBin: true
+
'@radix-ui/number@1.1.0':
resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==}
@@ -1302,6 +1337,9 @@ packages:
'@tailwindcss/postcss@4.1.9':
resolution: {integrity: sha512-v3DKzHibZO8ioVDmuVHCW1PR0XSM7nS40EjZFJEA1xPuvTuQPaR5flE1LyikU3hu2u1KNWBtEaSe8qsQjX3tyg==}
+ '@tootallnate/quickjs-emscripten@0.23.0':
+ resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==}
+
'@types/d3-array@3.2.2':
resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
@@ -1332,9 +1370,18 @@ packages:
'@types/node@22.0.0':
resolution: {integrity: sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw==}
+ '@types/pako@2.0.4':
+ resolution: {integrity: sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==}
+
'@types/prop-types@15.7.15':
resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==}
+ '@types/qrcode@1.5.5':
+ resolution: {integrity: sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==}
+
+ '@types/raf@3.4.3':
+ resolution: {integrity: sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==}
+
'@types/react-dom@18.0.0':
resolution: {integrity: sha512-49897Y0UiCGmxZqpC8Blrf6meL8QUla6eb+BBhn69dTXlmuOlzkfr7HHY/O8J25e1lTUMs+YYxSlVDAaGHCOLg==}
@@ -1344,9 +1391,15 @@ packages:
'@types/scheduler@0.26.0':
resolution: {integrity: sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA==}
+ '@types/trusted-types@2.0.7':
+ resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
+
'@types/use-sync-external-store@0.0.6':
resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==}
+ '@types/yauzl@2.10.3':
+ resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
+
'@vercel/analytics@1.5.0':
resolution: {integrity: sha512-MYsBzfPki4gthY5HnYN7jgInhAZ7Ac1cYDoRWFomwGHWEX7odTEzbtg9kf/QSo7XEsEAqlQugA6gJ2WS2DEa3g==}
peerDependencies:
@@ -1381,16 +1434,35 @@ packages:
resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==}
engines: {node: '>=12.0'}
+ agent-base@7.1.4:
+ resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
+ engines: {node: '>= 14'}
+
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
any-promise@1.3.0:
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
aria-hidden@1.2.6:
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
engines: {node: '>=10'}
+ ast-types@0.13.4:
+ resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==}
+ engines: {node: '>=4'}
+
attr-accept@2.2.5:
resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==}
engines: {node: '>=4'}
@@ -1406,6 +1478,51 @@ packages:
resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==}
engines: {node: '>= 6.0.0'}
+ b4a@1.7.2:
+ resolution: {integrity: sha512-DyUOdz+E8R6+sruDpQNOaV0y/dBbV6X/8ZkxrDcR0Ifc3BgKlpgG0VAtfOozA0eMtJO5GGe9FsZhueLs00pTww==}
+ peerDependencies:
+ react-native-b4a: '*'
+ peerDependenciesMeta:
+ react-native-b4a:
+ optional: true
+
+ bare-events@2.7.0:
+ resolution: {integrity: sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA==}
+
+ bare-fs@4.4.4:
+ resolution: {integrity: sha512-Q8yxM1eLhJfuM7KXVP3zjhBvtMJCYRByoTT+wHXjpdMELv0xICFJX+1w4c7csa+WZEOsq4ItJ4RGwvzid6m/dw==}
+ engines: {bare: '>=1.16.0'}
+ peerDependencies:
+ bare-buffer: '*'
+ peerDependenciesMeta:
+ bare-buffer:
+ optional: true
+
+ bare-os@3.6.2:
+ resolution: {integrity: sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==}
+ engines: {bare: '>=1.14.0'}
+
+ bare-path@3.0.0:
+ resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==}
+
+ bare-stream@2.7.0:
+ resolution: {integrity: sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==}
+ peerDependencies:
+ bare-buffer: '*'
+ bare-events: '*'
+ peerDependenciesMeta:
+ bare-buffer:
+ optional: true
+ bare-events:
+ optional: true
+
+ bare-url@2.2.2:
+ resolution: {integrity: sha512-g+ueNGKkrjMazDG3elZO1pNs3HY5+mMmOet1jtKyhOaCnkLzitxf26z7hoAEkDNgdNmnc1KIlt/dw6Po6xZMpA==}
+
+ base64-arraybuffer@1.0.2:
+ resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
+ engines: {node: '>= 0.6.0'}
+
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -1413,6 +1530,10 @@ packages:
resolution: {integrity: sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==}
hasBin: true
+ basic-ftp@5.0.5:
+ resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==}
+ engines: {node: '>=10.0.0'}
+
bindings@1.5.0:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
@@ -1424,23 +1545,50 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
+ buffer-crc32@0.2.13:
+ resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
+
busboy@1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'}
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
+ camelcase@5.3.1:
+ resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
+ engines: {node: '>=6'}
+
caniuse-lite@1.0.30001743:
resolution: {integrity: sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==}
+ canvg@3.0.11:
+ resolution: {integrity: sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==}
+ engines: {node: '>=10.0.0'}
+
chownr@3.0.0:
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
engines: {node: '>=18'}
+ chromium-bidi@8.0.0:
+ resolution: {integrity: sha512-d1VmE0FD7lxZQHzcDUCKZSNRtRwISXDsdg4HjdTR5+Ll5nQ/vzU12JeNmupD6VWffrPSlrnGhEWlLESKH3VO+g==}
+ peerDependencies:
+ devtools-protocol: '*'
+
class-variance-authority@0.7.1:
resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==}
client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
+ cliui@6.0.0:
+ resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
+
+ cliui@8.0.1:
+ resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
+ engines: {node: '>=12'}
+
clsx@2.1.1:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
@@ -1451,9 +1599,31 @@ packages:
react: ^18 || ^19 || ^19.0.0-rc
react-dom: ^18 || ^19 || ^19.0.0-rc
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ core-js@3.45.1:
+ resolution: {integrity: sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==}
+
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+ cosmiconfig@9.0.0:
+ resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ typescript: '>=4.9.5'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ css-line-break@2.1.0:
+ resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
+
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
@@ -1509,18 +1679,39 @@ packages:
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
engines: {node: '>= 12'}
+ data-uri-to-buffer@6.0.2:
+ resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==}
+ engines: {node: '>= 14'}
+
date-fns-jalali@4.1.0-0:
resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==}
date-fns@4.1.0:
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ decamelize@1.2.0:
+ resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
+ engines: {node: '>=0.10.0'}
+
decimal.js-light@2.5.1:
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
deferred@0.7.11:
resolution: {integrity: sha512-8eluCl/Blx4YOGwMapBvXRKxHXhA8ejDXYzEaK8+/gtcm8hRMhSLmXSqDmNUKNc/C8HNSmuyyp/hflhqDAvK2A==}
+ degenerator@5.0.1:
+ resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==}
+ engines: {node: '>= 14'}
+
denque@2.1.0:
resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
engines: {node: '>=0.10'}
@@ -1532,9 +1723,18 @@ packages:
detect-node-es@1.1.0:
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
+ devtools-protocol@0.0.1495869:
+ resolution: {integrity: sha512-i+bkd9UYFis40RcnkW7XrOprCujXRAHg62IVh/Ah3G8MmNXpCGt1m0dTFhSdx/AVs8XEMbdOGRwdkR1Bcta8AA==}
+
+ dijkstrajs@1.0.3:
+ resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
+
dingbat-to-unicode@1.0.1:
resolution: {integrity: sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==}
+ dompurify@3.2.7:
+ resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==}
+
duck@0.1.12:
resolution: {integrity: sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==}
@@ -1554,6 +1754,12 @@ packages:
embla-carousel@8.5.1:
resolution: {integrity: sha512-JUb5+FOHobSiWQ2EJNaueCNT/cQU9L6XWBbWmorWPQT9bkbk+fhsuLr8wWrzXKagO3oWszBO7MSx+GfaRk4E6A==}
+ emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ end-of-stream@1.4.5:
+ resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==}
+
enhanced-resolve@5.18.3:
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
engines: {node: '>=10.13.0'}
@@ -1561,6 +1767,13 @@ packages:
entities@1.1.2:
resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==}
+ env-paths@2.2.1:
+ resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
+ engines: {node: '>=6'}
+
+ error-ex@1.3.4:
+ resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==}
+
es-toolkit@1.39.10:
resolution: {integrity: sha512-E0iGnTtbDhkeczB0T+mxmoVlT4YNweEKBLq7oaU4p11mecdsZpNWOglI4895Vh4usbQ+LsJiuLuI2L0Vdmfm2w==}
@@ -1579,23 +1792,61 @@ packages:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
+ escodegen@2.1.0:
+ resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
+ engines: {node: '>=6.0'}
+ hasBin: true
+
esniff@2.0.1:
resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
engines: {node: '>=0.10'}
+ esprima@4.0.1:
+ resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+
+ esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+
event-emitter@0.3.5:
resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
eventemitter3@5.0.1:
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
+ events-universal@1.0.1:
+ resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==}
+
ext@1.7.0:
resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
+ extract-zip@2.0.1:
+ resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
+ engines: {node: '>= 10.17.0'}
+ hasBin: true
+
+ fast-fifo@1.3.2:
+ resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
+
+ fast-png@6.4.0:
+ resolution: {integrity: sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==}
+
+ fd-slicer@1.1.0:
+ resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
+
fetch-blob@3.2.0:
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
engines: {node: ^12.20 || >= 14.13}
+ fflate@0.8.2:
+ resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
+
file-selector@2.1.2:
resolution: {integrity: sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==}
engines: {node: '>= 12'}
@@ -1603,6 +1854,10 @@ packages:
file-uri-to-path@1.0.0:
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
+ find-up@4.1.0:
+ resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
+ engines: {node: '>=8'}
+
formdata-polyfill@4.0.10:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
engines: {node: '>=12.20.0'}
@@ -1628,10 +1883,22 @@ packages:
generate-function@2.3.1:
resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==}
+ get-caller-file@2.0.5:
+ resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+
get-nonce@1.0.1:
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
engines: {node: '>=6'}
+ get-stream@5.2.0:
+ resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
+ engines: {node: '>=8'}
+
+ get-uri@6.0.5:
+ resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==}
+ engines: {node: '>= 14'}
+
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
@@ -1649,6 +1916,18 @@ packages:
resolution: {integrity: sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==}
deprecated: This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.
+ html2canvas@1.4.1:
+ resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
+ engines: {node: '>=8.0.0'}
+
+ http-proxy-agent@7.0.2:
+ resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
+ engines: {node: '>= 14'}
+
+ https-proxy-agent@7.0.6:
+ resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
+ engines: {node: '>= 14'}
+
iconv-lite@0.7.0:
resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==}
engines: {node: '>=0.10.0'}
@@ -1659,6 +1938,10 @@ packages:
immer@10.1.3:
resolution: {integrity: sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==}
+ import-fresh@3.3.1:
+ resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+ engines: {node: '>=6'}
+
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -1672,6 +1955,20 @@ packages:
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
engines: {node: '>=12'}
+ iobuffer@5.4.0:
+ resolution: {integrity: sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==}
+
+ ip-address@10.0.1:
+ resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==}
+ engines: {node: '>= 12'}
+
+ is-arrayish@0.2.1:
+ resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+
+ is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
is-property@1.0.2:
resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==}
@@ -1694,9 +1991,24 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+ js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+
+ json-parse-even-better-errors@2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+
jsonfile@2.4.0:
resolution: {integrity: sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==}
+ jspdf-autotable@5.0.2:
+ resolution: {integrity: sha512-YNKeB7qmx3pxOLcNeoqAv3qTS7KuvVwkFe5AduCawpop3NOkBUtqDToxNc225MlNecxT4kP2Zy3z/y/yvGdXUQ==}
+ peerDependencies:
+ jspdf: ^2 || ^3
+
+ jspdf@3.0.3:
+ resolution: {integrity: sha512-eURjAyz5iX1H8BOYAfzvdPfIKK53V7mCpBTe7Kb16PaM8JSXEcUQNBQaiWMI8wY5RvNOPj4GccMjTlfwRBd+oQ==}
+
jszip@3.10.1:
resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
@@ -1770,6 +2082,13 @@ packages:
resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
engines: {node: '>= 12.0.0'}
+ lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
+ locate-path@5.0.0:
+ resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
+ engines: {node: '>=8'}
+
long@5.3.2:
resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==}
@@ -1809,11 +2128,17 @@ packages:
resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==}
engines: {node: '>= 18'}
+ mitt@3.0.1:
+ resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
+
mkdirp@3.0.1:
resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==}
engines: {node: '>=10'}
hasBin: true
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
mysql2@3.15.0:
resolution: {integrity: sha512-tT6pomf5Z/I7Jzxu8sScgrYBMK9bUFWd7Kbo6Fs1L0M13OOIJ/ZobGKS3Z7tQ8Re4lj+LnLXIQVZZxa3fhYKzA==}
engines: {node: '>= 8.0'}
@@ -1833,6 +2158,10 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
+ netmask@2.0.2:
+ resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==}
+ engines: {node: '>= 0.4.0'}
+
next-themes@0.4.6:
resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==}
peerDependencies:
@@ -1886,19 +2215,67 @@ packages:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
+ once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+
option@0.2.4:
resolution: {integrity: sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==}
+ p-limit@2.3.0:
+ resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
+ engines: {node: '>=6'}
+
+ p-locate@4.1.0:
+ resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
+ engines: {node: '>=8'}
+
+ p-try@2.2.0:
+ resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
+ engines: {node: '>=6'}
+
+ pac-proxy-agent@7.2.0:
+ resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==}
+ engines: {node: '>= 14'}
+
+ pac-resolver@7.0.1:
+ resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==}
+ engines: {node: '>= 14'}
+
pako@1.0.11:
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
+ pako@2.1.0:
+ resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==}
+
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
+ parse-json@5.2.0:
+ resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+ engines: {node: '>=8'}
+
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
+ pend@1.2.0:
+ resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
+
+ performance-now@2.1.0:
+ resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
+
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+ pngjs@5.0.0:
+ resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
+ engines: {node: '>=10.13.0'}
+
postcss-value-parser@4.2.0:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
@@ -1916,13 +2293,44 @@ packages:
process-nextick-args@2.0.1:
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
+ progress@2.0.3:
+ resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
+ engines: {node: '>=0.4.0'}
+
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+ proxy-agent@6.5.0:
+ resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==}
+ engines: {node: '>= 14'}
+
+ proxy-from-env@1.1.0:
+ resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+
+ pump@3.0.3:
+ resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==}
+
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
+ puppeteer-core@24.22.1:
+ resolution: {integrity: sha512-2IuC+w6270i8uCr2wGzD9pOi+JUe1CZn4TgPaonsgNryY1BGMcccdO0XBmekFlLYxkqaHrUMzzZnpc+T33mF9g==}
+ engines: {node: '>=18'}
+
+ puppeteer@24.22.1:
+ resolution: {integrity: sha512-jEeKDdJxXrv8Ki0I3q0amyv2FXZhucRG0Oh0EHF+igx8FiPG54y/E97j0+4WxITI7EjwoSxZFyxh61ZJ+TUo2w==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ qrcode@1.5.4:
+ resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==}
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+
+ raf@3.4.1:
+ resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
+
react-day-picker@9.8.0:
resolution: {integrity: sha512-E0yhhg7R+pdgbl/2toTb0xBhsEAtmAx1l7qjIWYfcxOy8w4rTSVfbtBoSzVVhPwKP/5E9iL38LivzoE3AQDhCQ==}
engines: {node: '>=18'}
@@ -2020,9 +2428,27 @@ packages:
redux@5.0.1:
resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==}
+ regenerator-runtime@0.13.11:
+ resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
+
+ require-directory@2.1.1:
+ resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
+ engines: {node: '>=0.10.0'}
+
+ require-main-filename@2.0.0:
+ resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
+
reselect@5.1.1:
resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
+ rgbcolor@1.0.1:
+ resolution: {integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==}
+ engines: {node: '>= 0.8.15'}
+
safe-buffer@5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
@@ -2035,12 +2461,32 @@ packages:
scheduler@0.21.0:
resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==}
+ semver@7.7.2:
+ resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
seq-queue@0.0.5:
resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==}
+ set-blocking@2.0.0:
+ resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
+
setimmediate@1.0.5:
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
+ smart-buffer@4.2.0:
+ resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
+ engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
+
+ socks-proxy-agent@8.0.5:
+ resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==}
+ engines: {node: '>= 14'}
+
+ socks@2.8.7:
+ resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==}
+ engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
+
sonner@1.7.4:
resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==}
peerDependencies:
@@ -2051,6 +2497,10 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
+ source-map@0.6.1:
+ resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+ engines: {node: '>=0.10.0'}
+
sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
@@ -2058,13 +2508,28 @@ packages:
resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==}
engines: {node: '>= 0.6'}
+ stackblur-canvas@2.7.0:
+ resolution: {integrity: sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==}
+ engines: {node: '>=0.1.14'}
+
streamsearch@1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
engines: {node: '>=10.0.0'}
+ streamx@2.23.0:
+ resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==}
+
+ string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+
string_decoder@1.1.1:
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
+ strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+
styled-jsx@5.1.1:
resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==}
engines: {node: '>= 12.0.0'}
@@ -2078,6 +2543,10 @@ packages:
babel-plugin-macros:
optional: true
+ svg-pathdata@6.0.3:
+ resolution: {integrity: sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==}
+ engines: {node: '>=12.0.0'}
+
tailwind-merge@2.5.5:
resolution: {integrity: sha512-0LXunzzAZzo0tEPxV3I297ffKZPlKDrjj7NXphC8V5ak9yHC5zRmxnOe2m/Rd/7ivsOMJe3JZ2JVocoDdQTRBA==}
@@ -2093,10 +2562,22 @@ packages:
resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==}
engines: {node: '>=6'}
+ tar-fs@3.1.1:
+ resolution: {integrity: sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==}
+
+ tar-stream@3.1.7:
+ resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==}
+
tar@7.4.3:
resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
engines: {node: '>=18'}
+ text-decoder@1.2.3:
+ resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==}
+
+ text-segmentation@1.0.3:
+ resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
+
thenify-all@1.6.0:
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
engines: {node: '>=0.8'}
@@ -2124,6 +2605,9 @@ packages:
type@2.7.3:
resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
+ typed-query-selector@2.12.0:
+ resolution: {integrity: sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==}
+
typescript@5.0.2:
resolution: {integrity: sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==}
engines: {node: '>=12.20'}
@@ -2169,6 +2653,9 @@ packages:
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ utrie@1.0.2:
+ resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
+
vaul@0.9.9:
resolution: {integrity: sha512-7afKg48srluhZwIkaU+lgGtFCUsYBSGOl8vcc8N/M3YQlZFlynHD15AE+pwrYdc826o7nrIND4lL9Y6b9WWZZQ==}
peerDependencies:
@@ -2182,6 +2669,35 @@ packages:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'}
+ webdriver-bidi-protocol@0.2.11:
+ resolution: {integrity: sha512-Y9E1/oi4XMxcR8AT0ZC4OvYntl34SPgwjmELH+owjBr0korAX4jKgZULBWILGCVGdVCQ0dodTToIETozhG8zvA==}
+
+ which-module@2.0.1:
+ resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
+
+ wrap-ansi@6.2.0:
+ resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
+ engines: {node: '>=8'}
+
+ wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+
+ wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+ ws@8.18.3:
+ resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
xml2js@0.4.23:
resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==}
engines: {node: '>=4.0.0'}
@@ -2198,10 +2714,36 @@ packages:
resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
engines: {node: '>=4.0'}
+ y18n@4.0.3:
+ resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
+
+ y18n@5.0.8:
+ resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
+ engines: {node: '>=10'}
+
yallist@5.0.0:
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
engines: {node: '>=18'}
+ yargs-parser@18.1.3:
+ resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
+ engines: {node: '>=6'}
+
+ yargs-parser@21.1.1:
+ resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
+ engines: {node: '>=12'}
+
+ yargs@15.4.1:
+ resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
+ engines: {node: '>=8'}
+
+ yargs@17.7.2:
+ resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
+ engines: {node: '>=12'}
+
+ yauzl@2.10.0:
+ resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
+
zod@3.25.67:
resolution: {integrity: sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==}
@@ -2214,6 +2756,16 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
+ '@babel/code-frame@7.27.1':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.27.1
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/helper-validator-identifier@7.27.1': {}
+
+ '@babel/runtime@7.28.4': {}
+
'@date-fns/tz@1.2.0': {}
'@floating-ui/core@1.7.3':
@@ -2286,6 +2838,20 @@ snapshots:
'@next/swc-win32-x64-msvc@14.2.16':
optional: true
+ '@puppeteer/browsers@2.10.10':
+ dependencies:
+ debug: 4.4.3
+ extract-zip: 2.0.1
+ progress: 2.0.3
+ proxy-agent: 6.5.0
+ semver: 7.7.2
+ tar-fs: 3.1.1
+ yargs: 17.7.2
+ transitivePeerDependencies:
+ - bare-buffer
+ - react-native-b4a
+ - supports-color
+
'@radix-ui/number@1.1.0': {}
'@radix-ui/number@1.1.1': {}
@@ -3254,6 +3820,8 @@ snapshots:
postcss: 8.5.0
tailwindcss: 4.1.9
+ '@tootallnate/quickjs-emscripten@0.23.0': {}
+
'@types/d3-array@3.2.2': {}
'@types/d3-color@3.1.3': {}
@@ -3282,8 +3850,17 @@ snapshots:
dependencies:
undici-types: 6.11.1
+ '@types/pako@2.0.4': {}
+
'@types/prop-types@15.7.15': {}
+ '@types/qrcode@1.5.5':
+ dependencies:
+ '@types/node': 22.0.0
+
+ '@types/raf@3.4.3':
+ optional: true
+
'@types/react-dom@18.0.0':
dependencies:
'@types/react': 18.0.0
@@ -3296,8 +3873,16 @@ snapshots:
'@types/scheduler@0.26.0': {}
+ '@types/trusted-types@2.0.7':
+ optional: true
+
'@types/use-sync-external-store@0.0.6': {}
+ '@types/yauzl@2.10.3':
+ dependencies:
+ '@types/node': 22.0.0
+ optional: true
+
'@vercel/analytics@1.5.0(next@14.2.16(react-dom@18.0.0(react@18.0.0))(react@18.0.0))(react@18.0.0)':
optionalDependencies:
next: 14.2.16(react-dom@18.0.0(react@18.0.0))(react@18.0.0)
@@ -3307,16 +3892,30 @@ snapshots:
adm-zip@0.5.16: {}
+ agent-base@7.1.4: {}
+
+ ansi-regex@5.0.1: {}
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
any-promise@1.3.0: {}
argparse@1.0.10:
dependencies:
sprintf-js: 1.0.3
+ argparse@2.0.1: {}
+
aria-hidden@1.2.6:
dependencies:
tslib: 2.8.1
+ ast-types@0.13.4:
+ dependencies:
+ tslib: 2.8.1
+
attr-accept@2.2.5: {}
autoprefixer@10.4.20(postcss@8.5.0):
@@ -3331,10 +3930,51 @@ snapshots:
aws-ssl-profiles@1.1.2: {}
+ b4a@1.7.2: {}
+
+ bare-events@2.7.0: {}
+
+ bare-fs@4.4.4:
+ dependencies:
+ bare-events: 2.7.0
+ bare-path: 3.0.0
+ bare-stream: 2.7.0(bare-events@2.7.0)
+ bare-url: 2.2.2
+ fast-fifo: 1.3.2
+ transitivePeerDependencies:
+ - react-native-b4a
+ optional: true
+
+ bare-os@3.6.2:
+ optional: true
+
+ bare-path@3.0.0:
+ dependencies:
+ bare-os: 3.6.2
+ optional: true
+
+ bare-stream@2.7.0(bare-events@2.7.0):
+ dependencies:
+ streamx: 2.23.0
+ optionalDependencies:
+ bare-events: 2.7.0
+ transitivePeerDependencies:
+ - react-native-b4a
+ optional: true
+
+ bare-url@2.2.2:
+ dependencies:
+ bare-path: 3.0.0
+ optional: true
+
+ base64-arraybuffer@1.0.2: {}
+
base64-js@1.5.1: {}
baseline-browser-mapping@2.8.6: {}
+ basic-ftp@5.0.5: {}
+
bindings@1.5.0:
dependencies:
file-uri-to-path: 1.0.0
@@ -3349,20 +3989,56 @@ snapshots:
node-releases: 2.0.21
update-browserslist-db: 1.1.3(browserslist@4.26.2)
+ buffer-crc32@0.2.13: {}
+
busboy@1.6.0:
dependencies:
streamsearch: 1.1.0
+ callsites@3.1.0: {}
+
+ camelcase@5.3.1: {}
+
caniuse-lite@1.0.30001743: {}
+ canvg@3.0.11:
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@types/raf': 3.4.3
+ core-js: 3.45.1
+ raf: 3.4.1
+ regenerator-runtime: 0.13.11
+ rgbcolor: 1.0.1
+ stackblur-canvas: 2.7.0
+ svg-pathdata: 6.0.3
+ optional: true
+
chownr@3.0.0: {}
+ chromium-bidi@8.0.0(devtools-protocol@0.0.1495869):
+ dependencies:
+ devtools-protocol: 0.0.1495869
+ mitt: 3.0.1
+ zod: 3.25.67
+
class-variance-authority@0.7.1:
dependencies:
clsx: 2.1.1
client-only@0.0.1: {}
+ cliui@6.0.0:
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 6.2.0
+
+ cliui@8.0.1:
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 7.0.0
+
clsx@2.1.1: {}
cmdk@1.0.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0(react@18.0.0))(react@18.0.0):
@@ -3377,8 +4053,30 @@ snapshots:
- '@types/react'
- '@types/react-dom'
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ core-js@3.45.1:
+ optional: true
+
core-util-is@1.0.3: {}
+ cosmiconfig@9.0.0(typescript@5.0.2):
+ dependencies:
+ env-paths: 2.2.1
+ import-fresh: 3.3.1
+ js-yaml: 4.1.0
+ parse-json: 5.2.0
+ optionalDependencies:
+ typescript: 5.0.2
+
+ css-line-break@2.1.0:
+ dependencies:
+ utrie: 1.0.2
+
csstype@3.1.3: {}
d3-array@3.2.4:
@@ -3426,10 +4124,18 @@ snapshots:
data-uri-to-buffer@4.0.1: {}
+ data-uri-to-buffer@6.0.2: {}
+
date-fns-jalali@4.1.0-0: {}
date-fns@4.1.0: {}
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
+ decamelize@1.2.0: {}
+
decimal.js-light@2.5.1: {}
deferred@0.7.11:
@@ -3440,14 +4146,29 @@ snapshots:
next-tick: 1.1.0
timers-ext: 0.1.8
+ degenerator@5.0.1:
+ dependencies:
+ ast-types: 0.13.4
+ escodegen: 2.1.0
+ esprima: 4.0.1
+
denque@2.1.0: {}
detect-libc@2.1.0: {}
detect-node-es@1.1.0: {}
+ devtools-protocol@0.0.1495869: {}
+
+ dijkstrajs@1.0.3: {}
+
dingbat-to-unicode@1.0.1: {}
+ dompurify@3.2.7:
+ optionalDependencies:
+ '@types/trusted-types': 2.0.7
+ optional: true
+
duck@0.1.12:
dependencies:
underscore: 1.13.7
@@ -3466,6 +4187,12 @@ snapshots:
embla-carousel@8.5.1: {}
+ emoji-regex@8.0.0: {}
+
+ end-of-stream@1.4.5:
+ dependencies:
+ once: 1.4.0
+
enhanced-resolve@5.18.3:
dependencies:
graceful-fs: 4.2.11
@@ -3473,6 +4200,12 @@ snapshots:
entities@1.1.2: {}
+ env-paths@2.2.1: {}
+
+ error-ex@1.3.4:
+ dependencies:
+ is-arrayish: 0.2.1
+
es-toolkit@1.39.10: {}
es5-ext@0.10.64:
@@ -3495,6 +4228,14 @@ snapshots:
escalade@3.2.0: {}
+ escodegen@2.1.0:
+ dependencies:
+ esprima: 4.0.1
+ estraverse: 5.3.0
+ esutils: 2.0.3
+ optionalDependencies:
+ source-map: 0.6.1
+
esniff@2.0.1:
dependencies:
d: 1.0.2
@@ -3502,6 +4243,12 @@ snapshots:
event-emitter: 0.3.5
type: 2.7.3
+ esprima@4.0.1: {}
+
+ estraverse@5.3.0: {}
+
+ esutils@2.0.3: {}
+
event-emitter@0.3.5:
dependencies:
d: 1.0.2
@@ -3509,21 +4256,54 @@ snapshots:
eventemitter3@5.0.1: {}
+ events-universal@1.0.1:
+ dependencies:
+ bare-events: 2.7.0
+
ext@1.7.0:
dependencies:
type: 2.7.3
+ extract-zip@2.0.1:
+ dependencies:
+ debug: 4.4.3
+ get-stream: 5.2.0
+ yauzl: 2.10.0
+ optionalDependencies:
+ '@types/yauzl': 2.10.3
+ transitivePeerDependencies:
+ - supports-color
+
+ fast-fifo@1.3.2: {}
+
+ fast-png@6.4.0:
+ dependencies:
+ '@types/pako': 2.0.4
+ iobuffer: 5.4.0
+ pako: 2.1.0
+
+ fd-slicer@1.1.0:
+ dependencies:
+ pend: 1.2.0
+
fetch-blob@3.2.0:
dependencies:
node-domexception: 1.0.0
web-streams-polyfill: 3.3.3
+ fflate@0.8.2: {}
+
file-selector@2.1.2:
dependencies:
tslib: 2.8.1
file-uri-to-path@1.0.0: {}
+ find-up@4.1.0:
+ dependencies:
+ locate-path: 5.0.0
+ path-exists: 4.0.0
+
formdata-polyfill@4.0.10:
dependencies:
fetch-blob: 3.2.0
@@ -3553,8 +4333,22 @@ snapshots:
dependencies:
is-property: 1.0.2
+ get-caller-file@2.0.5: {}
+
get-nonce@1.0.1: {}
+ get-stream@5.2.0:
+ dependencies:
+ pump: 3.0.3
+
+ get-uri@6.0.5:
+ dependencies:
+ basic-ftp: 5.0.5
+ data-uri-to-buffer: 6.0.2
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
graceful-fs@4.2.11: {}
hoek@4.3.1: {}
@@ -3563,6 +4357,25 @@ snapshots:
hoek@6.1.3: {}
+ html2canvas@1.4.1:
+ dependencies:
+ css-line-break: 2.1.0
+ text-segmentation: 1.0.3
+
+ http-proxy-agent@7.0.2:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
+ https-proxy-agent@7.0.6:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
iconv-lite@0.7.0:
dependencies:
safer-buffer: 2.1.2
@@ -3571,6 +4384,11 @@ snapshots:
immer@10.1.3: {}
+ import-fresh@3.3.1:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
inherits@2.0.4: {}
input-otp@1.4.1(react-dom@18.0.0(react@18.0.0))(react@18.0.0):
@@ -3580,6 +4398,14 @@ snapshots:
internmap@2.0.3: {}
+ iobuffer@5.4.0: {}
+
+ ip-address@10.0.1: {}
+
+ is-arrayish@0.2.1: {}
+
+ is-fullwidth-code-point@3.0.0: {}
+
is-property@1.0.2: {}
isarray@1.0.0: {}
@@ -3598,10 +4424,31 @@ snapshots:
js-tokens@4.0.0: {}
+ js-yaml@4.1.0:
+ dependencies:
+ argparse: 2.0.1
+
+ json-parse-even-better-errors@2.3.1: {}
+
jsonfile@2.4.0:
optionalDependencies:
graceful-fs: 4.2.11
+ jspdf-autotable@5.0.2(jspdf@3.0.3):
+ dependencies:
+ jspdf: 3.0.3
+
+ jspdf@3.0.3:
+ dependencies:
+ '@babel/runtime': 7.28.4
+ fast-png: 6.4.0
+ fflate: 0.8.2
+ optionalDependencies:
+ canvg: 3.0.11
+ core-js: 3.45.1
+ dompurify: 3.2.7
+ html2canvas: 1.4.1
+
jszip@3.10.1:
dependencies:
lie: 3.3.0
@@ -3662,6 +4509,12 @@ snapshots:
lightningcss-win32-arm64-msvc: 1.30.1
lightningcss-win32-x64-msvc: 1.30.1
+ lines-and-columns@1.2.4: {}
+
+ locate-path@5.0.0:
+ dependencies:
+ p-locate: 4.1.0
+
long@5.3.2: {}
loose-envify@1.4.0:
@@ -3705,8 +4558,12 @@ snapshots:
dependencies:
minipass: 7.1.2
+ mitt@3.0.1: {}
+
mkdirp@3.0.1: {}
+ ms@2.1.3: {}
+
mysql2@3.15.0:
dependencies:
aws-ssl-profiles: 1.1.2
@@ -3733,6 +4590,8 @@ snapshots:
nanoid@3.3.11: {}
+ netmask@2.0.2: {}
+
next-themes@0.4.6(react-dom@18.0.0(react@18.0.0))(react@18.0.0):
dependencies:
react: 18.0.0
@@ -3791,14 +4650,68 @@ snapshots:
object-assign@4.1.1: {}
+ once@1.4.0:
+ dependencies:
+ wrappy: 1.0.2
+
option@0.2.4: {}
+ p-limit@2.3.0:
+ dependencies:
+ p-try: 2.2.0
+
+ p-locate@4.1.0:
+ dependencies:
+ p-limit: 2.3.0
+
+ p-try@2.2.0: {}
+
+ pac-proxy-agent@7.2.0:
+ dependencies:
+ '@tootallnate/quickjs-emscripten': 0.23.0
+ agent-base: 7.1.4
+ debug: 4.4.3
+ get-uri: 6.0.5
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
+ pac-resolver: 7.0.1
+ socks-proxy-agent: 8.0.5
+ transitivePeerDependencies:
+ - supports-color
+
+ pac-resolver@7.0.1:
+ dependencies:
+ degenerator: 5.0.1
+ netmask: 2.0.2
+
pako@1.0.11: {}
+ pako@2.1.0: {}
+
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ parse-json@5.2.0:
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ error-ex: 1.3.4
+ json-parse-even-better-errors: 2.3.1
+ lines-and-columns: 1.2.4
+
+ path-exists@4.0.0: {}
+
path-is-absolute@1.0.1: {}
+ pend@1.2.0: {}
+
+ performance-now@2.1.0:
+ optional: true
+
picocolors@1.1.1: {}
+ pngjs@5.0.0: {}
+
postcss-value-parser@4.2.0: {}
postcss@8.4.31:
@@ -3822,14 +4735,79 @@ snapshots:
process-nextick-args@2.0.1: {}
+ progress@2.0.3: {}
+
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
object-assign: 4.1.1
react-is: 16.13.1
+ proxy-agent@6.5.0:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.3
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
+ lru-cache: 7.18.3
+ pac-proxy-agent: 7.2.0
+ proxy-from-env: 1.1.0
+ socks-proxy-agent: 8.0.5
+ transitivePeerDependencies:
+ - supports-color
+
+ proxy-from-env@1.1.0: {}
+
+ pump@3.0.3:
+ dependencies:
+ end-of-stream: 1.4.5
+ once: 1.4.0
+
punycode@2.3.1: {}
+ puppeteer-core@24.22.1:
+ dependencies:
+ '@puppeteer/browsers': 2.10.10
+ chromium-bidi: 8.0.0(devtools-protocol@0.0.1495869)
+ debug: 4.4.3
+ devtools-protocol: 0.0.1495869
+ typed-query-selector: 2.12.0
+ webdriver-bidi-protocol: 0.2.11
+ ws: 8.18.3
+ transitivePeerDependencies:
+ - bare-buffer
+ - bufferutil
+ - react-native-b4a
+ - supports-color
+ - utf-8-validate
+
+ puppeteer@24.22.1(typescript@5.0.2):
+ dependencies:
+ '@puppeteer/browsers': 2.10.10
+ chromium-bidi: 8.0.0(devtools-protocol@0.0.1495869)
+ cosmiconfig: 9.0.0(typescript@5.0.2)
+ devtools-protocol: 0.0.1495869
+ puppeteer-core: 24.22.1
+ typed-query-selector: 2.12.0
+ transitivePeerDependencies:
+ - bare-buffer
+ - bufferutil
+ - react-native-b4a
+ - supports-color
+ - typescript
+ - utf-8-validate
+
+ qrcode@1.5.4:
+ dependencies:
+ dijkstrajs: 1.0.3
+ pngjs: 5.0.0
+ yargs: 15.4.1
+
+ raf@3.4.1:
+ dependencies:
+ performance-now: 2.1.0
+ optional: true
+
react-day-picker@9.8.0(react@18.0.0):
dependencies:
'@date-fns/tz': 1.2.0
@@ -3937,8 +4915,20 @@ snapshots:
redux@5.0.1: {}
+ regenerator-runtime@0.13.11:
+ optional: true
+
+ require-directory@2.1.1: {}
+
+ require-main-filename@2.0.0: {}
+
reselect@5.1.1: {}
+ resolve-from@4.0.0: {}
+
+ rgbcolor@1.0.1:
+ optional: true
+
safe-buffer@5.1.2: {}
safer-buffer@2.1.2: {}
@@ -3949,10 +4939,29 @@ snapshots:
dependencies:
loose-envify: 1.4.0
+ semver@7.7.2: {}
+
seq-queue@0.0.5: {}
+ set-blocking@2.0.0: {}
+
setimmediate@1.0.5: {}
+ smart-buffer@4.2.0: {}
+
+ socks-proxy-agent@8.0.5:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.3
+ socks: 2.8.7
+ transitivePeerDependencies:
+ - supports-color
+
+ socks@2.8.7:
+ dependencies:
+ ip-address: 10.0.1
+ smart-buffer: 4.2.0
+
sonner@1.7.4(react-dom@18.0.0(react@18.0.0))(react@18.0.0):
dependencies:
react: 18.0.0
@@ -3960,21 +4969,48 @@ snapshots:
source-map-js@1.2.1: {}
+ source-map@0.6.1:
+ optional: true
+
sprintf-js@1.0.3: {}
sqlstring@2.3.3: {}
+ stackblur-canvas@2.7.0:
+ optional: true
+
streamsearch@1.1.0: {}
+ streamx@2.23.0:
+ dependencies:
+ events-universal: 1.0.1
+ fast-fifo: 1.3.2
+ text-decoder: 1.2.3
+ transitivePeerDependencies:
+ - react-native-b4a
+
+ string-width@4.2.3:
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
string_decoder@1.1.1:
dependencies:
safe-buffer: 5.1.2
+ strip-ansi@6.0.1:
+ dependencies:
+ ansi-regex: 5.0.1
+
styled-jsx@5.1.1(react@18.0.0):
dependencies:
client-only: 0.0.1
react: 18.0.0
+ svg-pathdata@6.0.3:
+ optional: true
+
tailwind-merge@2.5.5: {}
tailwindcss-animate@1.0.7(tailwindcss@4.1.9):
@@ -3985,6 +5021,25 @@ snapshots:
tapable@2.2.3: {}
+ tar-fs@3.1.1:
+ dependencies:
+ pump: 3.0.3
+ tar-stream: 3.1.7
+ optionalDependencies:
+ bare-fs: 4.4.4
+ bare-path: 3.0.0
+ transitivePeerDependencies:
+ - bare-buffer
+ - react-native-b4a
+
+ tar-stream@3.1.7:
+ dependencies:
+ b4a: 1.7.2
+ fast-fifo: 1.3.2
+ streamx: 2.23.0
+ transitivePeerDependencies:
+ - react-native-b4a
+
tar@7.4.3:
dependencies:
'@isaacs/fs-minipass': 4.0.1
@@ -3994,6 +5049,16 @@ snapshots:
mkdirp: 3.0.1
yallist: 5.0.0
+ text-decoder@1.2.3:
+ dependencies:
+ b4a: 1.7.2
+ transitivePeerDependencies:
+ - react-native-b4a
+
+ text-segmentation@1.0.3:
+ dependencies:
+ utrie: 1.0.2
+
thenify-all@1.6.0:
dependencies:
thenify: 3.3.1
@@ -4019,6 +5084,8 @@ snapshots:
type@2.7.3: {}
+ typed-query-selector@2.12.0: {}
+
typescript@5.0.2: {}
underscore@1.13.7: {}
@@ -4052,6 +5119,10 @@ snapshots:
util-deprecate@1.0.2: {}
+ utrie@1.0.2:
+ dependencies:
+ base64-arraybuffer: 1.0.2
+
vaul@0.9.9(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0(react@18.0.0))(react@18.0.0):
dependencies:
'@radix-ui/react-dialog': 1.1.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0(react@18.0.0))(react@18.0.0)
@@ -4080,6 +5151,26 @@ snapshots:
web-streams-polyfill@3.3.3: {}
+ webdriver-bidi-protocol@0.2.11: {}
+
+ which-module@2.0.1: {}
+
+ wrap-ansi@6.2.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ wrap-ansi@7.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ wrappy@1.0.2: {}
+
+ ws@8.18.3: {}
+
xml2js@0.4.23:
dependencies:
sax: 1.4.1
@@ -4095,6 +5186,46 @@ snapshots:
xmlbuilder@11.0.1: {}
+ y18n@4.0.3: {}
+
+ y18n@5.0.8: {}
+
yallist@5.0.0: {}
+ yargs-parser@18.1.3:
+ dependencies:
+ camelcase: 5.3.1
+ decamelize: 1.2.0
+
+ yargs-parser@21.1.1: {}
+
+ yargs@15.4.1:
+ dependencies:
+ cliui: 6.0.0
+ decamelize: 1.2.0
+ find-up: 4.1.0
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ require-main-filename: 2.0.0
+ set-blocking: 2.0.0
+ string-width: 4.2.3
+ which-module: 2.0.1
+ y18n: 4.0.3
+ yargs-parser: 18.1.3
+
+ yargs@17.7.2:
+ dependencies:
+ cliui: 8.0.1
+ escalade: 3.2.0
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ string-width: 4.2.3
+ y18n: 5.0.8
+ yargs-parser: 21.1.1
+
+ yauzl@2.10.0:
+ dependencies:
+ buffer-crc32: 0.2.13
+ fd-slicer: 1.1.0
+
zod@3.25.67: {}
diff --git a/scripts/check-config.js b/scripts/check-config.js
new file mode 100644
index 0000000..d9c5ada
--- /dev/null
+++ b/scripts/check-config.js
@@ -0,0 +1,60 @@
+#!/usr/bin/env node
+
+/**
+ * 配置檢查工具
+ * 用於驗證環境變量配置是否正確
+ */
+
+console.log('🔍 檢查環境變量配置...\n');
+
+// 檢查環境變量
+const envVars = {
+ 'NEXT_PUBLIC_APP_URL': process.env.NEXT_PUBLIC_APP_URL,
+ 'NEXT_PUBLIC_APP_NAME': process.env.NEXT_PUBLIC_APP_NAME,
+ 'DB_HOST': process.env.DB_HOST,
+ 'DB_PORT': process.env.DB_PORT,
+ 'DB_NAME': process.env.DB_NAME,
+ 'DB_USER': process.env.DB_USER,
+ 'DB_PASSWORD': process.env.DB_PASSWORD ? '***已設置***' : undefined,
+ 'GEMINI_API_KEY': process.env.GEMINI_API_KEY ? '***已設置***' : undefined,
+ 'GEMINI_MODEL': process.env.GEMINI_MODEL,
+ 'GEMINI_MAX_TOKENS': process.env.GEMINI_MAX_TOKENS,
+};
+
+console.log('📋 當前環境變量:');
+let hasErrors = false;
+
+Object.entries(envVars).forEach(([key, value]) => {
+ const status = value ? '✅' : '❌';
+ const displayValue = value || '未設置';
+ console.log(` ${status} ${key}: ${displayValue}`);
+ if (!value && key !== 'GEMINI_MAX_TOKENS') {
+ hasErrors = true;
+ }
+});
+
+console.log('');
+
+if (hasErrors) {
+ console.log('❌ 發現配置問題,請設置缺少的環境變量');
+ console.log('\n💡 建議的 .env.local 配置:');
+} else {
+ console.log('✅ 所有必要的環境變量都已設置');
+ console.log('\n🔧 建議的 .env.local 配置:');
+}
+
+console.log('NEXT_PUBLIC_APP_URL=http://localhost:12024');
+console.log('NEXT_PUBLIC_APP_NAME=AI 智能評審系統');
+console.log('DB_HOST=mysql.theaken.com');
+console.log('DB_PORT=33306');
+console.log('DB_NAME=db_AI_scoring');
+console.log('DB_USER=root');
+console.log('DB_PASSWORD=zh6161168');
+console.log('GEMINI_API_KEY=AIzaSyAN3pEJr_Vn2xkCidGZAq9eQqsMVvpj8g4');
+console.log('GEMINI_MODEL=gemini-1.5-pro');
+console.log('GEMINI_MAX_TOKENS=8192');
+
+console.log('\n📝 使用說明:');
+console.log('1. 複製 env.example 到 .env.local');
+console.log('2. 根據需要修改配置');
+console.log('3. 重啟開發服務器: npm run dev');
\ No newline at end of file
diff --git a/uploads/projects/20/1758628097639_yyc3losvt.pptx b/uploads/projects/20/1758628097639_yyc3losvt.pptx
deleted file mode 100644
index 8b38ba6..0000000
Binary files a/uploads/projects/20/1758628097639_yyc3losvt.pptx and /dev/null differ
diff --git a/uploads/projects/21/1758631225489_8g5whd8li.pptx b/uploads/projects/21/1758631225489_8g5whd8li.pptx
deleted file mode 100644
index 8b38ba6..0000000
Binary files a/uploads/projects/21/1758631225489_8g5whd8li.pptx and /dev/null differ
diff --git a/uploads/projects/22/1758631398314_vfgwct81t.pptx b/uploads/projects/22/1758631398314_vfgwct81t.pptx
deleted file mode 100644
index 8b38ba6..0000000
Binary files a/uploads/projects/22/1758631398314_vfgwct81t.pptx and /dev/null differ
diff --git a/uploads/projects/24/1758637006045_3d4e2i2yb.pptx b/uploads/projects/24/1758637006045_3d4e2i2yb.pptx
deleted file mode 100644
index 8b38ba6..0000000
Binary files a/uploads/projects/24/1758637006045_3d4e2i2yb.pptx and /dev/null differ
diff --git a/uploads/projects/25/1758640239292_xue04wm9w.pptx b/uploads/projects/25/1758640239292_xue04wm9w.pptx
deleted file mode 100644
index 8b38ba6..0000000
Binary files a/uploads/projects/25/1758640239292_xue04wm9w.pptx and /dev/null differ
diff --git a/uploads/projects/26/1758640840561_g35s5avq9.pptx b/uploads/projects/26/1758640840561_g35s5avq9.pptx
deleted file mode 100644
index 8b38ba6..0000000
Binary files a/uploads/projects/26/1758640840561_g35s5avq9.pptx and /dev/null differ
diff --git a/uploads/projects/27/1758640969869_zwgnqodtb.pptx b/uploads/projects/27/1758640969869_zwgnqodtb.pptx
deleted file mode 100644
index 8b38ba6..0000000
Binary files a/uploads/projects/27/1758640969869_zwgnqodtb.pptx and /dev/null differ
diff --git a/uploads/projects/28/1758641041760_2bbp7o2tl.pptx b/uploads/projects/28/1758641041760_2bbp7o2tl.pptx
deleted file mode 100644
index abb95cd..0000000
Binary files a/uploads/projects/28/1758641041760_2bbp7o2tl.pptx and /dev/null differ
diff --git a/uploads/projects/19/1758627771858_1bu28tdfr.pptx b/uploads/projects/29/1758642266698_v8881ji0n.pptx
similarity index 100%
rename from uploads/projects/19/1758627771858_1bu28tdfr.pptx
rename to uploads/projects/29/1758642266698_v8881ji0n.pptx