15207938132 2 months ago
parent
commit
4da39ec9d9
64 changed files with 4490 additions and 35 deletions
  1. 1 0
      agent-app
  2. 42 0
      fashion-app/docs-prod/newschema.md
  3. 1 1
      fashion-app/docs-prod/schema.md
  4. 2 1
      fashion-app/src/app/page-ai-chat/page-ai-chat.component.html
  5. 8 15
      fashion-app/src/app/page-ai-chat/page-ai-chat.component.scss
  6. 56 8
      fashion-app/src/app/page-ai-chat/page-ai-chat.component.ts
  7. 58 0
      fashion-app/src/app/page-bmi/page-bmi.component.html
  8. 99 0
      fashion-app/src/app/page-bmi/page-bmi.component.scss
  9. 22 0
      fashion-app/src/app/page-bmi/page-bmi.component.spec.ts
  10. 61 0
      fashion-app/src/app/page-bmi/page-bmi.component.ts
  11. 1 1
      fashion-app/src/app/page-evaluate/page-evaluate.component.html
  12. 3 0
      fashion-app/src/app/page-recommend/page-recommend.component.html
  13. 0 0
      fashion-app/src/app/page-recommend/page-recommend.component.scss
  14. 22 0
      fashion-app/src/app/page-recommend/page-recommend.component.spec.ts
  15. 15 0
      fashion-app/src/app/page-recommend/page-recommend.component.ts
  16. 5 0
      fashion-app/src/app/tab2/tab2.page.html
  17. 22 2
      fashion-app/src/app/tab2/tab2.page.ts
  18. 7 3
      fashion-app/src/app/tab3/tab3.page.html
  19. 17 0
      fashion-app/src/app/tab3/tab3.page.ts
  20. 2 1
      fashion-app/src/app/tab4/tab4.page.html
  21. 2 2
      fashion-app/src/app/tab4/tab4.page.ts
  22. 5 0
      fashion-app/src/app/tabs/tabs.routes.ts
  23. 214 0
      fashion-app/src/lib/ncloud.ts
  24. 98 0
      fashion-app/src/lib/recommend.js
  25. 112 0
      fashion-app/src/lib/recommend.ts
  26. 1 1
      fashion-app/src/main.ts
  27. 183 0
      fashion-server/lib/ncloud.js
  28. 27 0
      fashion-server/lib/test.js
  29. 190 0
      fashion-server/migration/data.js
  30. 77 0
      fashion-server/migration/import-data.js
  31. 86 0
      fashion-server/migration/import-dataMethod.js
  32. 1 0
      fashion-server/migration/js/20241212ajax.txt
  33. 34 0
      fashion-server/migration/js/a.js
  34. 35 0
      fashion-server/migration/js/default.html
  35. 58 0
      fashion-server/migration/js/index.html
  36. 22 0
      fashion-server/migration/js/node.js
  37. 16 0
      fashion-server/migration/js/node_modules/.bin/mime
  38. 17 0
      fashion-server/migration/js/node_modules/.bin/mime.cmd
  39. 28 0
      fashion-server/migration/js/node_modules/.bin/mime.ps1
  40. 22 0
      fashion-server/migration/js/node_modules/.package-lock.json
  41. 21 0
      fashion-server/migration/js/node_modules/mime/LICENSE
  42. 143 0
      fashion-server/migration/js/node_modules/mime/README.md
  43. 6 0
      fashion-server/migration/js/node_modules/mime/bin/cli.js
  44. 17 0
      fashion-server/migration/js/node_modules/mime/dist/src/Mime.d.ts
  45. 84 0
      fashion-server/migration/js/node_modules/mime/dist/src/Mime.js
  46. 4 0
      fashion-server/migration/js/node_modules/mime/dist/src/index.d.ts
  47. 5 0
      fashion-server/migration/js/node_modules/mime/dist/src/index.js
  48. 4 0
      fashion-server/migration/js/node_modules/mime/dist/src/index_lite.d.ts
  49. 4 0
      fashion-server/migration/js/node_modules/mime/dist/src/index_lite.js
  50. 2 0
      fashion-server/migration/js/node_modules/mime/dist/src/mime_cli.d.ts
  51. 66 0
      fashion-server/migration/js/node_modules/mime/dist/src/mime_cli.js
  52. 4 0
      fashion-server/migration/js/node_modules/mime/dist/types/other.d.ts
  53. 701 0
      fashion-server/migration/js/node_modules/mime/dist/types/other.js
  54. 4 0
      fashion-server/migration/js/node_modules/mime/dist/types/standard.d.ts
  55. 354 0
      fashion-server/migration/js/node_modules/mime/dist/types/standard.js
  56. 76 0
      fashion-server/migration/js/node_modules/mime/package.json
  57. 137 0
      fashion-server/migration/js/node_modules/mime/src/Mime.ts
  58. 7 0
      fashion-server/migration/js/node_modules/mime/src/index.ts
  59. 6 0
      fashion-server/migration/js/node_modules/mime/src/index_lite.ts
  60. 85 0
      fashion-server/migration/js/node_modules/mime/src/mime_cli.ts
  61. 701 0
      fashion-server/migration/js/node_modules/mime/types/other.ts
  62. 354 0
      fashion-server/migration/js/node_modules/mime/types/standard.ts
  63. 27 0
      fashion-server/migration/js/package-lock.json
  64. 6 0
      fashion-server/migration/js/package.json

+ 1 - 0
agent-app

@@ -0,0 +1 @@
+Subproject commit ced2f9f061e1ff6b18d2b04776889213a647e8ee

+ 42 - 0
fashion-app/docs-prod/newschema.md

@@ -0,0 +1,42 @@
+## 个性化推荐模块
+- 模块描述 用户可以输入身高,体重,年龄,选择性别和输入补充信息(包括职业:非必填,喜好:非必填,天气:非必填,温度:非必填,其他需求:显高显瘦?儒雅甜美?等),AI会提供量身定制的服装和配饰建议并且保存AI生成的推荐结果以及用户信息和用户输入的信息。
+```plantuml
+@startuml
+class UserProfile {
+    +objectId: String
+    +createdAt: Date
+    +name: String
+    +password: String
+    +height: Float
+    +weight: Float
+    +age: Int
+    +gender: String
+    +occupation: String
+}
+
+class UserInput {
+    +objectId: String
+    +createdAt: Date
+    +user: Pointer
+    +selectHeight: Float
+    +selectWeight: Float
+    +selectAge: Int
+    +selectGender: String
+    +selectOccupation: String
+    +preferences: String
+    +weather: String
+    +temperature: Float
+    +additionalNeeds: String
+}
+
+class AIRecommendation {
+    +objectId: String
+    +createdAt: Date
+    +userInput: Pointer
+    +recommendations: String
+}
+
+UserProfile "1" -- "0..*" UserInput : has >
+UserInput "1" -- "1" AIRecommendation  >
+@enduml
+```

+ 1 - 1
fashion-app/docs-prod/schema.md

@@ -1,6 +1,6 @@
 # 一、Schema范式设计
 ## 个性化推荐模块
-- 模块描述 用户可以输入身高,体重,年龄,选择性别和输入补充信息(包括职业:非必填,喜好:非必填,天气:非必填,温度:非必填,其他需求:显高显瘦?儒雅甜美?等),AI会提供量身定制的服装和配饰建议
+- 模块描述 用户可以输入身高,体重,年龄,选择性别和输入补充信息(包括职业:非必填,喜好:非必填,天气:非必填,温度:非必填,其他需求:显高显瘦?儒雅甜美?等),AI会提供量身定制的服装和配饰建议并且保存AI生成的推荐结果以及用户信息和用户输入的信息。
 ### 1.表结构设计
 #### UserProfile(用户表)
 - objectId:唯一标识符

+ 2 - 1
fashion-app/src/app/page-ai-chat/page-ai-chat.component.html

@@ -1,6 +1,7 @@
 <div class="button-container">
-  <ion-button fill="clear" (click)="openChat()" class="chat-button">开始新聊天</ion-button>
+  <ion-button fill="clear" (click)="openFashionChat()" class="chat-button">开始新聊天</ion-button>
   <ion-button fill="clear" (click)="restoreChat(chatId)" class="chat-button">继续上次聊天</ion-button>
+
 </div>
 
 

+ 8 - 15
fashion-app/src/app/page-ai-chat/page-ai-chat.component.scss

@@ -6,19 +6,12 @@
 }
 
 .chat-button {
-  background-color: white; // 背景色为白色
-  border-radius: 12px; // 圆角矩形
-  border: 1px solid #ccc; // 添加边框
-  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); // 添加阴影效果
-  padding: 12px 24px; // 内边距
-  font-size: 16px; // 字体大小
-  width: 200px; // 设置固定宽度以确保整齐
-  margin: 10px 0; // 上下按钮之间的间距
-  transition: background-color 0.3s, transform 0.3s; // 添加过渡效果
-  
-  // 悬停效果
-  &:hover {
-    background-color: #f0f0f0; // 悬停时背景颜色变化
-    transform: translateY(-2px); // 悬停时轻微上移
-  }
+  --background: linear-gradient(to right, #ffcccb, #add8e6); /* 渐变背景色 */
+  color: white; /* 文字颜色为白色 */
+  border-radius: 8px; /* 圆角矩形 */
+  margin-top: 16px; /* 与上方区域的距离 */
+  width: 100%; /* 按钮宽度100% */
+  padding: 12px; /* 内边距 */
+  text-align: center; /* 文本居中 */
+  font-size: 17px;
 }

+ 56 - 8
fashion-app/src/app/page-ai-chat/page-ai-chat.component.ts

@@ -1,27 +1,40 @@
 import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
-import { IonButton, IonContent, IonFooter, IonHeader, IonInput, IonTitle, IonToolbar, ModalController } from '@ionic/angular/standalone';
+import { IonButton, IonContent, IonFooter, IonHeader, IonInput, IonItem, IonTitle, IonToolbar, ModalController } from '@ionic/angular/standalone';
 import { ChatPanelOptions, FmodeChat, FmodeChatCompletion,FmodeChatMessage,MarkdownPreviewModule, openChatPanelModal  } from 'fmode-ng';
 import { CommonModule } from '@angular/common';
 import { FormsModule,} from '@angular/forms'; // 导入 FormsModule
 import { Router } from '@angular/router';
+// 引用设计的对象类和查询类
+import { CloudObject, CloudQuery } from 'src/lib/ncloud';
+
 
 @Component({
   selector: 'app-page-ai-chat',
   templateUrl: './page-ai-chat.component.html',
   styleUrls: ['./page-ai-chat.component.scss'],
   standalone: true,
-  imports:[IonButton,IonHeader,IonToolbar,IonTitle,IonContent,IonFooter,IonInput,CommonModule,FormsModule,MarkdownPreviewModule ]
+  imports:[IonButton,IonHeader,IonToolbar,IonTitle,IonContent,IonFooter,IonInput,CommonModule,FormsModule,MarkdownPreviewModule,IonItem ]
 })
 export class PageAiChatComponent  implements OnInit {
   
   constructor(private modalCtrl:ModalController,
     private router:Router, private cdRef:ChangeDetectorRef) { }
 
-  ngOnInit() {}
+    ngOnInit() {
+      // 生命周期:页面加载后,运行用户列表加载函数
+      this.loadUserProfileList()
+    }
   chatId:any= null;
   //AI聊天
-openChat(){
+openFashionChat(){
   localStorage.setItem("company","E4KpGvTEto")
+  let consult = new CloudObject("AIChat")
+    let now = new Date();
+    let chatStr = `${now.getFullYear()}-${now.getMonth()+1}-${now.getDate()}`
+    consult.set({
+      title:`穿搭咨询记录${chatStr}}`,
+      
+    })
   let options:ChatPanelOptions = {
     roleId:"2DXJkRsjXK",
     onChatInit:(chat:FmodeChat)=>{
@@ -44,17 +57,26 @@ openChat(){
 “如果有一个场合,你希望我帮你推荐搭配,比如约会、工作或休闲,你会选择哪个呢?”
 “你觉得在穿搭上,最让你困扰的是什么?是搭配技巧还是风格选择呢?”
 “有没有什么服装是你一直想尝试但还没有机会的?我们可以一起聊聊!”
-2引导收尾
+2根据用户的描述给出穿搭方案
+- 完成穿搭方案时,请在消息结尾附带: [穿搭方案完成]
+3引导收尾
 “今天聊得很开心呢!如果你还有其他问题或者想法,随时可以告诉我哦。”
 “如果你觉得今天的聊天已经足够了,我也很乐意下次再和你聊更多时尚的话题!”
-“希望你能找到自己喜欢的穿搭风格,期待下次再见!”`);
+“希望你能找到自己喜欢的穿搭风格,期待下次再见!”
+# 开始话语
+当您准备好了,可以以一个时尚顾问的身份,向来访的用户打招呼。`);
     },
     onMessage:(chat:FmodeChat,message:FmodeChatMessage)=>{
       console.log("onMessage",message)
       let content:any = message?.content
       if(typeof content == "string"){
-        if(content?.indexOf("[完成]")>-1){
-          console.log("聊天已完成")
+
+        if(content?.indexOf("[穿搭方案完成]")>-1){
+          console.log("穿搭方案已完成")
+          consult.set({
+            content:content // 穿搭方案内容
+          })
+          consult.save();
         }
       }
     },
@@ -67,7 +89,24 @@ openChat(){
   openChatPanelModal(this.modalCtrl,options)
 }
 
+ /**
+   * 开始聊天
+   */
+ openChat(){
+  let options:ChatPanelOptions = {
+    roleId:"2DXJkRsjXK",
+    onChatSaved:(chat:FmodeChat)=>{
+      // chat?.chatSession?.id 本次会话的 chatId
+      console.log("onChatSaved",chat,chat?.chatSession,chat?.chatSession?.id)
+    },
+  }
+  openChatPanelModal(this.modalCtrl,options)
+}
 
+  /**
+   * 恢复聊天
+   * @chatId 从onChatSaved生命周期中,获取chat?.chatSession?.id
+   */
 restoreChat(chatId:string){
   let options:ChatPanelOptions = {
     roleId:"2DXJkRsjXK",
@@ -75,4 +114,13 @@ restoreChat(chatId:string){
   }
   openChatPanelModal(this.modalCtrl,options)
 }
+
+// 创建用于数据列表存储的属性
+UserProfileList:Array<CloudObject> = []
+// 查询并加载用户列表的函数
+async loadUserProfileList(){
+  let query = new CloudQuery("UserProfile");
+  this.UserProfileList = await query.find();
+  console.log("UserProfileList",this.UserProfileList)
+}
 }

+ 58 - 0
fashion-app/src/app/page-bmi/page-bmi.component.html

@@ -0,0 +1,58 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-button (click)="goBack()" fill="clear">
+        <ion-icon aria-hidden="true" name="chevron-back-outline" style="color: black; font-size: 24px;"></ion-icon>
+      </ion-button>
+    </ion-buttons>
+    <ion-title>BMI 测试</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <div class="info-section">
+    <div class="input-row1">
+      <div class="input-group">
+        <label class="font1">身高:</label>
+        <input type="number" [(ngModel)]="height" placeholder="" class="input-box" />
+        <span class="unit">CM</span>
+      </div>
+
+    </div>
+    
+    <div class="input-row2">
+      <div class="input-group">
+        <label class="font1">体重:</label>
+        <input type="number" [(ngModel)]="weight" placeholder="" class="input-box" />
+        <span class="unit">KG</span>
+      </div>
+
+    </div>
+  </div>
+
+  <div class="info-section">
+    
+    <div class="input-row3">
+      <div class="input-group">
+        <label class="font1">BMI:</label>
+        <div class="output-box">{{ bmi | number: '1.1-1' }}</div>
+        <span class="unit">KG/M<sup>2</sup></span>
+      </div>
+
+    </div>
+  </div>
+
+  <div class="center">
+  <ion-button fill="clear"
+  class="analysis-button" 
+  (click)="calculateBMI()" >
+BMI计算
+</ion-button>
+  
+<ion-button fill="clear"
+class="analysis-button" 
+(click)="resetForm()" >
+清空
+</ion-button>
+</div>
+</ion-content>

+ 99 - 0
fashion-app/src/app/page-bmi/page-bmi.component.scss

@@ -0,0 +1,99 @@
+ion-toolbar{
+width: 100%;
+height: 60px;
+
+display: flex; /* 使用 flexbox 布局 */
+align-items: center;
+justify-content: center;//使内容在水平方向上居中。
+}
+
+
+.info-section {
+    background-color: white; /* 背景色为白色 */
+    padding: 16px;
+    border-radius: 8px; /* 圆角 */
+    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); /* 添加阴影 */
+    margin-top: 16px; /* 与导航栏的间距 */
+  }
+  
+  .input-row1 {
+    display: flex; /* 使用 flexbox 布局 */
+    justify-content: space-between; /* 在行内均匀分布 */
+    align-items: center;
+    margin-bottom: 25px; /* 每一行的间距 */
+    margin-left: 70px;
+  }
+
+  .input-row2{
+    display: flex; /* 使用 flexbox 布局 */
+    justify-content: space-between; /* 在行内均匀分布 */
+    align-items: center;
+    margin-left: 70px;
+  }
+  
+  .input-row3{
+    display: flex; /* 使用 flexbox 布局 */
+    justify-content: space-between; /* 在行内均匀分布 */
+    align-items: center;
+    margin-left: 70px;
+  }
+  .input-group {
+    display: flex;
+    align-items: center;
+  }
+  
+  .input-group label {
+    flex: 1; /* 标签占据剩余空间 */
+  }
+  
+  .input-box {
+    border-radius: 15px; /* 圆角矩形 */
+    border: none; /* 去掉边框 */
+    padding: 8px 12px; /* 内边距 */
+    margin-left: 15px; /* 标签与输入框之间的间距 */
+    background: linear-gradient(to right, #ffcccb, #add8e6); /* 渐变背景色 */
+    width: 90px;
+    height: 45px;
+    font-size: 32px;
+  }
+
+  .output-box {
+    border-radius: 15px; /* 圆角矩形 */
+    border: none; /* 去掉边框 */
+    padding: 8px 12px; /* 内边距 */
+    margin-left: 19px; /* 标签与输入框之间的间距 */
+    background: linear-gradient(to right, #ffcccb, #add8e6); /* 渐变背景色 */
+    width: 90px;
+    height: 45px;
+    font-size: 32px;
+  }
+
+  .unit {
+    margin-left: 10px; /* 输入框与单位之间的间距 */
+    font-size: 27px;
+  }
+  
+
+  .font1{
+    font-size: 27px;
+    font-weight: bold;
+
+  }
+
+  .analysis-button {
+    --background: linear-gradient(to right, #ffcccb, #add8e6); /* 渐变背景色 */
+    color: white; /* 文字颜色为白色 */
+    border-radius: 8px; /* 圆角矩形 */
+    margin-top: 16px; /* 与上方区域的距离 */
+    width: 40%; /* 按钮宽度100% */
+    padding: 10px; /* 内边距 */
+    text-align: center; /* 文本居中 */
+    font-size: 20px;
+    font-weight: bold;
+  }
+
+  .center{
+    display: flex; /* 使用 flexbox 布局 */
+    justify-content: space-between; /* 在行内均匀分布 */
+    align-items: center;
+  }

+ 22 - 0
fashion-app/src/app/page-bmi/page-bmi.component.spec.ts

@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+
+import { PageBmiComponent } from './page-bmi.component';
+
+describe('PageBmiComponent', () => {
+  let component: PageBmiComponent;
+  let fixture: ComponentFixture<PageBmiComponent>;
+
+  beforeEach(waitForAsync(() => {
+    TestBed.configureTestingModule({
+      imports: [PageBmiComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(PageBmiComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  }));
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 61 - 0
fashion-app/src/app/page-bmi/page-bmi.component.ts

@@ -0,0 +1,61 @@
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { AlertController, IonButton, IonButtons, IonContent, IonHeader, IonIcon, IonInput, IonItem, IonLabel, IonTitle, IonToolbar } from '@ionic/angular/standalone';
+import { FormsModule } from '@angular/forms'; // 导入 FormsModule
+import { CommonModule } from '@angular/common'; // 导入 CommonModule
+import { chevronBackOutline } from 'ionicons/icons';
+import { addIcons } from 'ionicons';
+addIcons({chevronBackOutline});
+@Component({
+  selector: 'app-page-bmi',
+  templateUrl: './page-bmi.component.html',
+  styleUrls: ['./page-bmi.component.scss'],
+  standalone: true,
+  imports:[IonHeader,IonToolbar,IonTitle,IonButton,IonButtons,IonContent,IonItem,IonLabel,IonInput,FormsModule,CommonModule,IonIcon]
+})
+export class PageBmiComponent  implements OnInit {
+
+  ngOnInit() {this.resetForm();} // 页面加载时清空数据
+  height: number|null =null; // 身高
+  weight: number|null =null; // 体重
+  bmi: number|null=null; // BMI 值
+
+  constructor(private router: Router,private alertController: AlertController) {this.resetForm();}
+
+  // 计算 BMI
+  async calculateBMI() {
+    if (this.height !=null && this.weight !=null) {
+      if(this.height >0 && this.weight >0) {
+      const heightInMeters = this.height / 100; // 将身高转换为米
+      this.bmi = this.weight / (heightInMeters * heightInMeters); // 计算 BMI
+      } else {
+        const alert = await this.alertController.create({
+          header: '身高体重不能为0!',
+          buttons: ['确定']
+        });
+        await alert.present(); // 显示弹出框
+      }
+    } else {
+      const alert = await this.alertController.create({
+        header: '身高体重不能为空!',
+        buttons: ['确定']
+      });
+      await alert.present(); // 显示弹出框
+      
+    }
+  }
+
+  //清空数据
+    // 清空输入数据
+    resetForm() {
+      this.height = null;
+      this.weight = null;
+      this.bmi = null;
+    }
+
+  // 返回上一个页面
+  goBack() {
+    this.router.navigate(['/tabs/tab3'], { replaceUrl: true }); // 使用 replaceUrl 强制重载页面
+  }
+}
+

+ 1 - 1
fashion-app/src/app/page-evaluate/page-evaluate.component.html

@@ -2,7 +2,7 @@
   <ion-toolbar>
     <ion-buttons slot="start">
       <ion-button (click)="goBack()" fill="clear">
-        <ion-icon aria-hidden="true" name="chevron-back" style="color: black; font-size: 24px;"></ion-icon>
+        <ion-icon aria-hidden="true" name="chevron-back" style="color: black; font-size: 24px; argin:left"></ion-icon>
       </ion-button>
     </ion-buttons>
     <ion-title>评价</ion-title>

+ 3 - 0
fashion-app/src/app/page-recommend/page-recommend.component.html

@@ -0,0 +1,3 @@
+<p>
+  page-recommend works!
+</p>

+ 0 - 0
fashion-app/src/app/page-recommend/page-recommend.component.scss


+ 22 - 0
fashion-app/src/app/page-recommend/page-recommend.component.spec.ts

@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+
+import { PageRecommendComponent } from './page-recommend.component';
+
+describe('PageRecommendComponent', () => {
+  let component: PageRecommendComponent;
+  let fixture: ComponentFixture<PageRecommendComponent>;
+
+  beforeEach(waitForAsync(() => {
+    TestBed.configureTestingModule({
+      imports: [PageRecommendComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(PageRecommendComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  }));
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 15 - 0
fashion-app/src/app/page-recommend/page-recommend.component.ts

@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-page-recommend',
+  templateUrl: './page-recommend.component.html',
+  styleUrls: ['./page-recommend.component.scss'],
+  standalone: true,
+})
+export class PageRecommendComponent  implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {}
+
+}

+ 5 - 0
fashion-app/src/app/tab2/tab2.page.html

@@ -26,4 +26,9 @@
     }
   }
 
+
+  <ion-item *ngFor="let perfer of perferList" lines="none">
+    <h3>{{perfer}}</h3>
+  </ion-item>
+
 </ion-content>

+ 22 - 2
fashion-app/src/app/tab2/tab2.page.ts

@@ -1,7 +1,11 @@
+import { CommonModule } from '@angular/common';
 import { ChangeDetectorRef, Component } from '@angular/core';
-import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonItem } from '@ionic/angular/standalone';
 import { IonTextarea, IonButton } from "@ionic/angular/standalone";
 import { DalleOptions, ImagineWork } from 'fmode-ng';
+// 引用设计的对象类和查询类
+import { CloudObject, CloudQuery } from 'src/lib/ncloud';
+import { RecommendationService } from 'src/lib/recommend';
 
 @Component({
   selector: 'app-tab2', 
@@ -11,11 +15,27 @@ import { DalleOptions, ImagineWork } from 'fmode-ng';
   imports: [
     IonHeader, IonToolbar, IonTitle, IonContent, 
     IonButton,
-    IonTextarea
+    IonTextarea,IonItem,CommonModule
   ],
 })
 export class Tab2Page {
   userPrompt:string = "飞码产品LOGO,独角兽头部形象,极简风格,棱角分明,线条勾勒,蓝色紫色搭配。"
+  ngOnInit() {
+    // 生命周期:页面加载后,运行医生列表加载函数
+    this.loadPerferList()
+  }
+// 创建用于数据列表存储的属性
+perferList:Array<any> = []
+// 查询并加载偏好物品列表的函数
+async loadPerferList(){
+  let recommendationService=new RecommendationService();
+  let result=recommendationService.getItemRecommendations('266024222614683648', 2);
+  this.perferList = await result;
+}
+
+
+
+
   promptInput(ev:any){
     this.userPrompt = ev.detail.value;
   }

+ 7 - 3
fashion-app/src/app/tab3/tab3.page.html

@@ -103,6 +103,8 @@
 
   获取穿搭分析
 </ion-button>
+
+
   
  <!-- AI生成内容区域 -->
  <div class="bigbox1" *ngIf="responseMsg">
@@ -119,13 +121,16 @@
  
 
   </div>
-  
+
+  <!--AI聊天-->
   <div *ngIf="selectedSegment === 'ai-chat'">
 <app-page-ai-chat></app-page-ai-chat>
   </div>
   
+  <!--测试-->
   <div *ngIf="selectedSegment === 'test'">
-    <h2>这是测试页面</h2>
+    <ion-button  (click)="goBmipage()">BMI</ion-button>
+
   </div>
 
   <div *ngIf="selectedSegment === 'evaluate'">
@@ -157,5 +162,4 @@ class="analysis-button"
 
 
   </div>
-
 </ion-content>

+ 17 - 0
fashion-app/src/app/tab3/tab3.page.ts

@@ -11,6 +11,8 @@ import { PageAiChatComponent } from '../page-ai-chat/page-ai-chat.component';
 import { PageEvaluateComponent } from '../page-evaluate/page-evaluate.component';
 import { EditRatingStarComponent } from '../edit-rating-star/edit-rating-star.component';
 
+
+
 @Component({
   selector: 'app-tab3',
   templateUrl: 'tab3.page.html',
@@ -25,6 +27,8 @@ export class Tab3Page {
   selectedSegment: string = 'ai-outfit'; // 默认选中的导航项
   selectedGender: string = ''; // 默认性别
 
+ 
+
   // 新增变量
   height: number | null = null; // 身高
   weight: number | null = null; // 体重
@@ -145,6 +149,13 @@ stopTimer() {
 }
 
 
+
+//测试
+goBmipage() {
+  this.router.navigate(['/tabs/bmi']); // 跳转到测试BMI页面
+}
+
+
 //AI评价
 async submitEvaluation() {
   // 处理评价提交逻辑
@@ -184,4 +195,10 @@ switch (score) {
 }
 }
 alertButtons = ['退出'];
+
+
+
+
+
+
 }

+ 2 - 1
fashion-app/src/app/tab4/tab4.page.html

@@ -5,7 +5,8 @@
         <img src="../../assets/images/touxiang.jpg" alt="" class="avatar-container"/>
       </div>
       <div class="user-info">
-        <h2 class="username">Squirrel</h2>
+        <h2 class="username">Squirrel <ion-icon name="male-outline" style="color: #048dbb; font-size: 30px; " ></ion-icon></h2>
+        
         <div class="stats">
           <span class="marginRight">0<span class="grey">粉丝</span></span>
           <span class="marginRight">0<span class="grey">关注</span></span>

+ 2 - 2
fashion-app/src/app/tab4/tab4.page.ts

@@ -2,8 +2,8 @@ import { Component } from '@angular/core';
 import { IonHeader, IonToolbar, IonTitle, IonContent, IonIcon, IonButton } from '@ionic/angular/standalone';
 import { ExploreContainerComponent } from '../explore-container/explore-container.component';
 import { addIcons } from 'ionicons';
-import { basketOutline,chatbubbleEllipsesOutline,chevronForwardOutline,fileTrayFullOutline,folderOutline,heartOutline,helpCircleOutline,imageOutline, peopleOutline, readerOutline, settingsOutline, starOutline } from 'ionicons/icons';
-addIcons({basketOutline,starOutline,imageOutline,heartOutline,folderOutline,chatbubbleEllipsesOutline,chevronForwardOutline,fileTrayFullOutline,readerOutline,helpCircleOutline,peopleOutline,settingsOutline});
+import { basketOutline,chatbubbleEllipsesOutline,chevronForwardOutline,fileTrayFullOutline,folderOutline,heartOutline,helpCircleOutline,imageOutline, maleOutline, peopleOutline, readerOutline, settingsOutline, starOutline } from 'ionicons/icons';
+addIcons({basketOutline,starOutline,imageOutline,heartOutline,folderOutline,chatbubbleEllipsesOutline,chevronForwardOutline,fileTrayFullOutline,readerOutline,helpCircleOutline,peopleOutline,settingsOutline,maleOutline});
 @Component({
   selector: 'app-tab4',
   templateUrl: 'tab4.page.html',

+ 5 - 0
fashion-app/src/app/tabs/tabs.routes.ts

@@ -41,6 +41,11 @@ export const routes: Routes = [
         loadComponent: () =>
           import('../page-ai-chat/page-ai-chat.component').then((m) => m.PageAiChatComponent),
       },
+      {
+        path: 'bmi',
+        loadComponent: () =>
+          import('../page-bmi/page-bmi.component').then((m) => m.PageBmiComponent),
+      },
       {
         path: '',
         redirectTo: '/tabs/tab1',

+ 214 - 0
fashion-app/src/lib/ncloud.ts

@@ -0,0 +1,214 @@
+// CloudObject.ts
+export class CloudObject {
+    id: string | null = null;
+    className: string;
+    createdAt:any;
+    updatedAt:any;
+    data: Record<string, any> = {};
+
+    constructor(className: string) {
+        this.className = className;
+    }
+
+    toPointer() {
+        return { "__type": "Pointer", "className": this.className, "objectId": this.id };
+    }
+
+    set(json: Record<string, any>) {
+        Object.keys(json).forEach(key => {
+            if (["objectId", "id", "createdAt", "updatedAt", "ACL"].includes(key)) {
+                return;
+            }
+            this.data[key] = json[key];
+        });
+    }
+
+    get(key: string) {
+        return this.data[key] || null;
+    }
+
+    async save(): Promise<this> {
+        let method = "POST";
+        let url = `http://1.94.237.145:1339/parse/classes/${this.className}`;
+        
+        // 更新
+        if (this.id) {
+            url += `/${this.id}`;
+            method = "PUT";
+        }
+        
+        const body = JSON.stringify(this.data);
+        const response = await fetch(url, {
+            headers: {
+                "accept": "*/*",
+                "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+                "content-type": "text/plain;charset=UTF-8",
+                "x-parse-application-id": "ylj",
+                "Referer": "http://127.0.0.1:4040/",
+                "Referrer-Policy": "strict-origin-when-cross-origin"
+            },
+            body: body,
+            method: method,
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result.error);
+        }
+        if (result?.objectId) {
+            this.id = result.objectId;
+        }
+        return this;
+    }
+
+    async destroy(): Promise<boolean> {
+        if (!this.id) return false;
+        
+        const response = await fetch(`http://1.94.237.145:1339/parse/classes/${this.className}/${this.id}`, {
+            headers: {
+                "accept": "*/*",
+                "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+                "x-parse-application-id": "ylj",
+                "Referer": "http://127.0.0.1:4040/",
+                "Referrer-Policy": "strict-origin-when-cross-origin"
+            },
+            body: null,
+            method: "DELETE",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result) {
+            this.id = null;
+        }
+        return true;
+    }
+}
+
+// CloudQuery.ts
+export class CloudQuery {
+    className: string;
+    whereOptions: Record<string, any> = {};
+
+    constructor(className: string) {
+        this.className = className;
+    }
+
+    greaterThan(key: string, value: any) {
+        if (!this.whereOptions[key]) this.whereOptions[key] = {};
+        this.whereOptions[key]["$gt"] = value;
+    }
+
+    greaterThanAndEqualTo(key: string, value: any) {
+        if (!this.whereOptions[key]) this.whereOptions[key] = {};
+        this.whereOptions[key]["$gte"] = value;
+    }
+
+    lessThan(key: string, value: any) {
+        if (!this.whereOptions[key]) this.whereOptions[key] = {};
+        this.whereOptions[key]["$lt"] = value;
+    }
+
+    lessThanAndEqualTo(key: string, value: any) {
+        if (!this.whereOptions[key]) this.whereOptions[key] = {};
+        this.whereOptions[key]["$lte"] = value;
+    }
+
+    equalTo(key: string, value: any) {
+        this.whereOptions[key] = value;
+    }
+
+    async get(id: string): Promise<Record<string, any>> {
+        const url = `http://1.94.237.145.1339/parse/classes/${this.className}/${id}?`;
+        const response = await fetch(url, {
+            headers: {
+                "accept": "*/*",
+                "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+                "if-none-match": "W/\"127-p6+dUp7xlGAxzyvVsfuvVhMxjPo\"",
+                "x-parse-application-id": "ylj",
+                "Referer": "http://127.0.0.1:4040/",
+                "Referrer-Policy": "strict-origin-when-cross-origin"
+            },
+            body: null,
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+        const json = await response?.json();
+        return json || {};
+    }
+
+    async find(): Promise<CloudObject[]> {
+        let url = `http://1.94.237.145:1339/parse/classes/${this.className}?`;
+
+        if (Object.keys(this.whereOptions).length) {
+            const whereStr = JSON.stringify(this.whereOptions);
+            url += `where=${whereStr}`;
+        }
+
+        const response = await fetch(url, {
+            headers: {
+                "accept": "*/*",
+                "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+                "if-none-match": "W/\"127-p6+dUp7xlGAxzyvVsfuvVhMxjPo\"",
+                "x-parse-application-id": "ylj",
+                "Referer": "http://127.0.0.1:4040/",
+                "Referrer-Policy": "strict-origin-when-cross-origin"
+            },
+            body: null,
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+        
+        const json = await response?.json();
+        let list=json?.results || [];
+        let objList=list.map((item:any)=>this.dataToObj(item));
+        return objList || [];
+    }
+
+    async first(): Promise<CloudObject | null> {
+        let url = `http://1.94.237.145:1339/parse/classes/${this.className}?`;
+
+        if (Object.keys(this.whereOptions).length) {
+            const whereStr = JSON.stringify(this.whereOptions);
+            url += `where=${whereStr}`;
+        }
+
+        const response = await fetch(url, {
+            headers: {
+                "accept": "*/*",
+                "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+                "if-none-match": "W/\"127-p6+dUp7xlGAxzyvVsfuvVhMxjPo\"",
+                "x-parse-application-id": "ylj",
+                "Referer": "http://127.0.0.1:4040/",
+                "Referrer-Policy": "strict-origin-when-cross-origin"
+            },
+            body: null,
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const json = await response?.json();
+        const exists = json?.results?.[0] || null;
+        if (exists) {
+            let existsObject = this.dataToObj(exists);
+            return existsObject;
+        }
+        return null;
+    }
+
+    dataToObj(exists:any):CloudObject{
+        let existsObject = new CloudObject(this.className);
+            existsObject.set(exists);
+            existsObject.id = exists.objectId;
+            existsObject.createdAt = exists.createdAt;
+            existsObject.updatedAt = exists.updatedAt;
+            return existsObject;
+        }
+    }
+

+ 98 - 0
fashion-app/src/lib/recommend.js

@@ -0,0 +1,98 @@
+import { CloudObject, CloudQuery } from "../../../fashion-server/lib/ncloud.js";
+
+export class RecommendationService {
+    constructor() {
+        this.perferQuery = new CloudQuery('Perfer'); // 偏好数据存储在 perfer 类中
+    }
+
+    /**
+     * 获取用户的物品推荐
+     * @param userId 用户ID
+     * @param howMany 推荐数量
+     * @returns 推荐的物品ID列表
+     */
+    async getItemRecommendations(userId, howMany) {
+        // 获取用户的偏好数据
+        const userPreferences = await this.getUserPreferences(userId);
+        if (!userPreferences || userPreferences.length === 0) {
+            return [];
+        }
+
+        // 计算物品相似度
+        const similarItems = await this.calculateItemSimilarity(userPreferences);
+        // 获取推荐物品
+        return this.getTopRecommendations(similarItems, howMany);
+    }
+
+    /**
+     * 获取用户的偏好数据
+     * @param userId 用户ID
+     * @returns 用户偏好物品的列表
+     */
+    async getUserPreferences(userId) {
+        this.perferQuery.equalTo('user_id', userId); // 查询条件
+        const preferences = await this.perferQuery.find(); // 获取用户的偏好数据
+        return preferences; // 返回用户偏好物品列表
+    }
+
+    /**
+     * 计算物品相似度
+     * @param userPreferences 用户偏好物品
+     * @returns 物品相似度的映射
+     */
+    async calculateItemSimilarity(userPreferences) {
+        const itemSimilarity = new Map();
+
+        // 遍历用户偏好物品,计算与其他物品的相似度
+        for (const pref of userPreferences) {
+            const itemId = pref.item_id; // 直接访问属性
+            const preferenceValue = pref.preference; // 直接访问属性
+
+            // 获取所有物品的偏好数据
+            const allPreferences = await this.perferQuery.find();
+            for (const otherPref of allPreferences) {
+                const otherItemId = otherPref.item_id; // 直接访问属性
+                const otherPreferenceValue = otherPref.preference; // 直接访问属性
+
+                if (itemId !== otherItemId) { // 排除自身
+                    const similarityScore = this.computeSimilarity(preferenceValue, otherPreferenceValue);
+                    itemSimilarity.set(otherItemId, (itemSimilarity.get(otherItemId) || 0) + similarityScore);
+                }
+            }
+        }
+
+        return itemSimilarity;
+    }
+
+    /**
+     * 计算两个物品之间的相似度
+     * @param preference1 第一个物品的偏好值
+     * @param preference2 第二个物品的偏好值
+     * @returns 相似度分数
+     */
+    computeSimilarity(preference1, preference2) {
+        // 示例:使用简单的相似度计算(如绝对值差)
+        return Math.abs(preference1 - preference2); // 这里是一个简单的示例
+    }
+
+    /**
+     * 获取前 N 个推荐物品
+     * @param similarItems 物品相似度映射
+     * @param howMany 推荐数量
+     * @returns 推荐物品ID列表
+     */
+    getTopRecommendations(similarItems, howMany) {
+        // 将相似度映射转换为数组并排序
+        const sortedItems = Array.from(similarItems.entries()).sort((a, b) => b[1] - a[1]);
+        // 获取前 N 个物品ID
+        return sortedItems.slice(0, howMany).map(item => item[0]);
+    }
+}
+
+// 使用示例
+let recommendationService = new RecommendationService();
+recommendationService.getItemRecommendations('266024222614683648', 2).then(result => {
+    console.log(result);
+}).catch(error => {
+    console.error("Error fetching recommendations:", error);
+});

+ 112 - 0
fashion-app/src/lib/recommend.ts

@@ -0,0 +1,112 @@
+import { CloudObject, CloudQuery } from "./ncloud";
+
+export class RecommendationService {
+    private perferQuery: CloudQuery; // 偏好查询对象
+
+    constructor() {
+        this.perferQuery = new CloudQuery('Perfer'); // 偏好数据存储在 perfer 类中
+    }
+
+    /**
+     * 获取用户的物品推荐
+     * @param userId 用户ID
+     * @param howMany 推荐数量
+     * @returns 推荐的物品ID列表
+     */
+    public async getItemRecommendations(userId: string, howMany: number): Promise<string[]> {
+        // 获取用户的偏好数据
+        const userPreferences = await this.getUserPreferences(userId);
+        
+        if (!userPreferences || userPreferences.length === 0) {
+            return [];
+        }
+
+        // 计算物品相似度
+        //console.log(userPreferences);
+        const similarItems = await this.calculateItemSimilarity(userPreferences);
+        // 获取推荐物品
+        return this.getTopRecommendations(similarItems, howMany);
+    }
+
+    /**
+     * 获取用户的偏好数据
+     * @param userId 用户ID
+     * @returns 用户偏好物品的列表
+     */
+    private async getUserPreferences(userId: string): Promise<CloudObject[]> {
+        this.perferQuery.equalTo('user_id', userId); // 查询条件
+        const preferences = await this.perferQuery.find(); // 获取用户的偏好数据
+        console.log(preferences);
+        return preferences; // 返回用户偏好物品列表
+    }
+
+    /**
+     * 计算物品相似度
+     * @param userPreferences 用户偏好物品
+     * @returns 物品相似度的映射
+     */
+    private async calculateItemSimilarity(userPreferences: CloudObject[]): Promise<Map<string, number>> {
+        const itemSimilarity: Map<string, number> = new Map();
+        // 遍历用户偏好物品,计算与其他物品的相似度
+        for (const pref of userPreferences) {
+            
+            const itemId = pref.get('item_id');
+            const preferenceValue = pref.get('perference');
+            //console.log(`${itemId} : ${preferenceValue}`);
+
+            // 获取所有物品的偏好数据
+            const allPreferences = await this.perferQuery.find();
+            for (const otherPref of allPreferences) {
+                const otherItemId = otherPref.get('item_id');
+                const otherPreferenceValue = otherPref.get('perference');
+                //console.log(`${otherItemId} : ${otherPreferenceValue}`);
+
+                if (itemId !== otherItemId) { // 排除自身
+                    console.log(`${itemId} : ${preferenceValue}`)
+                    console.log(`${otherItemId} : ${otherPreferenceValue}`);
+                    const similarityScore = this.computeSimilarity(preferenceValue, otherPreferenceValue);
+                    console.log(`${itemId} : ${similarityScore}`);
+                    itemSimilarity.set(otherItemId, (itemSimilarity.get(otherItemId) || 0) + similarityScore);
+                }
+            }
+        }
+
+        return itemSimilarity;
+    }
+
+    /**
+     * 计算两个物品之间的余弦相似度
+     * @param preference1 第一个物品的偏好值
+     * @param preference2 第二个物品的偏好值
+     * @returns 相似度分数
+     */
+    private computeSimilarity(preference1: number, preference2: number): number {
+        // 计算点积
+        const dotProduct = preference1 * preference2;
+
+        // 计算模
+        const magnitude1 = Math.sqrt(preference1 ** 2);
+        const magnitude2 = Math.sqrt(preference2 ** 2);
+
+        // 计算余弦相似度
+        if (magnitude1 === 0 || magnitude2 === 0) {
+            return 0; // 避免除以零的情况
+        }
+
+        return dotProduct / (magnitude1 * magnitude2);
+    }
+
+    /**
+     * 获取前 N 个推荐物品
+     * @param similarItems 物品相似度映射
+     * @param howMany 推荐数量
+     * @returns 推荐物品ID列表
+     */
+    private getTopRecommendations(similarItems: Map<string, number>, howMany: number): string[] {
+        // 将相似度映射转换为数组并排序
+        const sortedItems = Array.from(similarItems.entries()).sort((a, b) => b[1] - a[1]);
+        // 获取前 N 个物品ID
+        return sortedItems.slice(0, howMany).map(item => item[0]);
+    }
+}
+

+ 1 - 1
fashion-app/src/main.ts

@@ -15,7 +15,7 @@ Parse.serverURL = "https://server.fmode.cn/parse";
 localStorage.setItem("NOVA_APIG_SERVER", 'aHR0cHMlM0ElMkYlMkZzZXJ2ZXIuZm1vZGUuY24lMkZhcGklMkZhcGlnJTJG')
 
 // 注意:替换Token 根据Token设置Parse服务帐套权限
-Parse.User.become("r:5abb1b0d289b97a2dedb8c6c3e96b986")
+Parse.User.become('r:bb67bfcefc53bdb8fd2e93095aced8b8')
 bootstrapApplication(AppComponent, {
   providers: [
     { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },

+ 183 - 0
fashion-server/lib/ncloud.js

@@ -0,0 +1,183 @@
+class CloudObject{
+    id
+    className
+    data = {}
+    constructor(className){
+        this.className = className
+    }
+    toPointer(){
+        return {"__type":"Pointer","className":this.className,"objectId":this.id}
+    }
+    set(json){
+        Object.keys(json).forEach(key=>{
+            if(["objectId","id","createdAt","updatedAt","ACL"].indexOf(key)>-1){
+                return
+            }
+            this.data[key] = json[key]
+        })
+    }
+    get(key){
+        return this.data[key] || null
+    }
+    async save(){
+        let method = "POST"
+        let url = "http://1.94.237.145:1339/parse/classes/" + this.className
+        // 更新
+        if(this.id){
+            url += "/"+this.id
+            method = "PUT"
+        } 
+        let body = JSON.stringify(this.data)
+        let response = await fetch(url, {
+           "headers": {
+          "accept": "*/*",
+          "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+          "content-type": "text/plain;charset=UTF-8",
+          "x-parse-application-id": "ylj",
+          "Referer": "http://127.0.0.1:4040/",
+          "Referrer-Policy": "strict-origin-when-cross-origin"
+        },
+            "body": body,
+            "method": method,
+            "mode": "cors",
+            "credentials": "omit"
+          });
+          let result = await response?.json();
+          if(result?.error){
+            console.error(result?.error)
+          }
+          if(result?.objectId){this.id = result?.objectId}
+          return this
+    }
+    async destory(){
+        if(!this.id) return
+        let response = await fetch("http://1.94.237.145:1339/parse/classes/test/"+this.id, {
+            "headers": {
+              "accept": "*/*",
+              "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+              "x-parse-application-id": "ylj",
+              "Referer": "http://127.0.0.1:4040/",
+              "Referrer-Policy": "strict-origin-when-cross-origin"
+            },
+            "body": null,
+            "method": "DELETE",
+            "mode": "cors",
+            "credentials": "omit"
+          });
+          let result = await response?.json();
+          if(result){
+            this.id = null
+        }
+        return true
+    }
+}
+
+class CloudQuery{
+    className
+    constructor(className){
+        this.className = className
+    }
+
+    whereOptions = {}
+    greaterThan(key,value){
+        if(!this.whereOptions[key]) this.whereOptions[key] = {}
+        this.whereOptions[key]["$gt"] = value
+    }
+    greaterThanAndEqualTo(key,value){
+        if(!this.whereOptions[key]) this.whereOptions[key] = {}
+        this.whereOptions[key]["$gte"] = value
+    }
+    lessThan(key,value){
+        if(!this.whereOptions[key]) this.whereOptions[key] = {}
+        this.whereOptions[key]["$lt"] = value
+    }
+    lessThanAndEqualTo(key,value){
+        if(!this.whereOptions[key]) this.whereOptions[key] = {}
+        this.whereOptions[key]["$lte"] = value
+    }
+    equalTo(key,value){
+        this.whereOptions[key] = value
+    }
+
+    async get(id){
+        let url = "http://1.94.237.145:1339/parse/classes/"+this.className+"/"+id+"?"
+
+        let response = await fetch(url, {
+            "headers": {
+                "accept": "*/*",
+                "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+                "if-none-match": "W/\"127-p6+dUp7xlGAxzyvVsfuvVhMxjPo\"",
+                "x-parse-application-id": "ylj",
+                "Referer": "http://127.0.0.1:4040/",
+                "Referrer-Policy": "strict-origin-when-cross-origin"
+              },
+            "body": null,
+            "method": "GET",
+            "mode": "cors",
+            "credentials": "omit"
+        });
+        let json = await response?.json();
+        return json || {}
+    }
+    async find(){
+        let url = "http://1.94.237.145:1339/parse/classes/"+this.className+"?"
+        
+        if(Object.keys(this.whereOptions)?.length){
+            let whereStr = JSON.stringify(this.whereOptions)
+            url += `where=${whereStr}`
+        }
+
+        let response = await fetch(url, {
+            "headers": {
+                "accept": "*/*",
+                "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+                "if-none-match": "W/\"127-p6+dUp7xlGAxzyvVsfuvVhMxjPo\"",
+                "x-parse-application-id": "ylj",
+                "Referer": "http://127.0.0.1:4040/",
+                "Referrer-Policy": "strict-origin-when-cross-origin"
+              },
+            "body": null,
+            "method": "GET",
+            "mode": "cors",
+            "credentials": "omit"
+        });
+        let json = await response?.json();
+        return json?.results || []
+    }
+    async first(){
+        let url = "http://1.94.237.145:1339/parse/classes/"+this.className+"?"
+        
+        if(Object.keys(this.whereOptions)?.length){
+            let whereStr = JSON.stringify(this.whereOptions)
+            url += `where=${whereStr}`
+        }
+
+        let response = await fetch(url, {
+            "headers": {
+                "accept": "*/*",
+                "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+                "if-none-match": "W/\"127-p6+dUp7xlGAxzyvVsfuvVhMxjPo\"",
+                "x-parse-application-id": "ylj",
+                "Referer": "http://127.0.0.1:4040/",
+                "Referrer-Policy": "strict-origin-when-cross-origin"
+              },
+            "body": null,
+            "method": "GET",
+            "mode": "cors",
+            "credentials": "omit"
+        });
+        let json = await response?.json();
+        let exists = json?.results?.[0] || null
+        if(exists){
+            let existsObject = new CloudObject(this.className)
+            existsObject.set(exists)
+            existsObject.id = exists.objectId
+            existsObject.createdAt = exists.createdAt
+            existsObject.updatedAt = exists.updatedAt
+            return existsObject
+        }
+    }
+}
+
+module.exports.CloudObject = CloudObject
+module.exports.CloudQuery = CloudQuery

+ 27 - 0
fashion-server/lib/test.js

@@ -0,0 +1,27 @@
+const { CloudQuery, CloudObject } = require("../lib/ncloud");
+// testCRUD()
+testQuery()
+async function testQuery(){
+    let query = new CloudQuery("test")
+    query.equalTo("gender","男")
+     query.greaterThanAndEqualTo("age",20)
+    query.lessThan("age",25)
+     let list = await query.find();
+     console.log(list)
+}
+
+async function testCRUD(){
+    // 基本的增删查改测试
+    let query = new CloudQuery("Doctor")
+    let doctorList = await query.find();
+    console.log("doctorList count",doctorList?.length)
+
+    let newDoctor = new CloudObject("Doctor")
+    newDoctor.set({"name":"123"})
+    
+    newDoctor = await newDoctor.save(newDoctor)
+    console.log("newDoctor",newDoctor)
+
+    await newDoctor.destory()
+    console.log("newDoctor 已删除",newDoctor)
+}

+ 190 - 0
fashion-server/migration/data.js

@@ -0,0 +1,190 @@
+module.exports.UserProfileList=[{
+    "objectId": "1",
+    "createdAt": "2024-12-17T22:00:00Z",
+    "name": "张三",
+    "password": "hashed_password_1",
+    "height": 175.0,
+    "weight": 70.0,
+    "age": 30,
+    "gender": "男",
+    "occupation": "工程师"
+},
+{
+    "objectId": "2",
+    "createdAt": "2024-12-17T22:05:00Z",
+    "name": "李四",
+    "password": "hashed_password_2",
+    "height": 160.0,
+    "weight": 55.0,
+    "age": 25,
+    "gender": "女",
+    "occupation": "设计师"
+},
+{
+    "objectId": "3",
+    "createdAt": "2024-12-17T22:10:00Z",
+    "name": "王五",
+    "password": "hashed_password_3",
+    "height": 180.0,
+    "weight": 80.0,
+    "age": 28,
+    "gender": "男",
+    "occupation": "程序员"
+},
+{
+    "objectId": "4",
+    "createdAt": "2024-12-17T22:15:00Z",
+    "name": "赵六",
+    "password": "hashed_password_4",
+    "height": 165.0,
+    "weight": 50.0,
+    "age": 22,
+    "gender": "女",
+    "occupation": "学生"
+},
+{
+    "objectId": "5",
+    "createdAt": "2024-12-17T22:20:00Z",
+    "name": "钱七",
+    "password": "hashed_password_5",
+    "height": 170.0,
+    "weight": 65.0,
+    "age": 35,
+    "gender": "男",
+    "occupation": "教师"
+}]
+
+module.exports.UserInputList=[
+    {
+        "objectId": "1",
+        "createdAt": "2024-12-17T22:25:00Z",
+        "user": {"__type": "Pointer", "className": "UserProfile", "objectId": "1"},
+        "selectHeight": 175.0,
+        "selectWeight": 70.0,
+        "selectAge": 30,
+        "selectGender": "男",
+        "selectOccupation": "工程师",
+        "preferences": "时尚, 舒适",
+        "weather": "晴天",
+        "temperature": 25.0,
+        "additionalNeeds": "显高"
+    },
+    {
+        "objectId": "2",
+        "createdAt": "2024-12-17T22:30:00Z",
+        "user": {"__type": "Pointer", "className": "UserProfile", "objectId": "2"},
+        "selectHeight": 160.0,
+        "selectWeight": 55.0,
+        "selectAge": 25,
+        "selectGender": "女",
+        "selectOccupation": "设计师",
+        "preferences": "优雅, 简约",
+        "weather": "阴天",
+        "temperature": 20.0,
+        "additionalNeeds": "甜美"
+    },
+    {
+        "objectId": "3",
+        "createdAt": "2024-12-17T22:35:00Z",
+        "user": {"__type": "Pointer", "className": "UserProfile", "objectId": "3"},
+        "selectHeight": 180.0,
+        "selectWeight": 80.0,
+        "selectAge": 28,
+        "selectGender": "男",
+        "selectOccupation": "程序员",
+        "preferences": "休闲, 运动",
+        "weather": "多云",
+        "temperature": 22.0,
+        "additionalNeeds": "显瘦"
+    },
+    {
+        "objectId": "4",
+        "createdAt": "2024-12-17T22:40:00Z",
+        "user": {"__type": "Pointer", "className": "UserProfile", "objectId": "4"},
+        "selectHeight": 165.0,
+        "selectWeight": 50.0,
+        "selectAge": 22,
+        "selectGender": "女",
+        "selectOccupation": "学生",
+        "preferences": "可爱, 活泼",
+        "weather": "阴天",
+        "temperature": 18.0,
+        "additionalNeeds": "时尚"
+    },
+    {
+        "objectId": "5",
+        "createdAt": "2024-12-17T22:45:00Z",
+        "user": {"__type": "Pointer", "className": "UserProfile", "objectId": "5"},
+        "selectHeight": 170.0,
+        "selectWeight": 65.0,
+        "selectAge": 35,
+        "selectGender": "男",
+        "selectOccupation": "教师",
+        "preferences": "正式, 经典",
+        "weather": "晴天",
+        "temperature": 24.0,
+        "additionalNeeds": "儒雅"
+    }
+]
+
+module.exports.AIRecommendationList=[
+    {
+        "objectId": "1",
+        "createdAt": "2024-12-17T22:50:00Z",
+        "userInput": {"__type": "Pointer", "className": "UserInput", "objectId": "1"},
+        "recommendations": "推荐一套休闲西装,搭配白色衬衫和运动鞋。"
+    },
+    {
+        "objectId": "2",
+        "createdAt": "2024-12-17T22:55:00Z",
+        "userInput": {"__type": "Pointer", "className": "UserInput", "objectId": "2"},
+        "recommendations": "推荐一条优雅的连衣裙,搭配简约的高跟鞋。"
+    },
+    {
+        "objectId": "3",
+        "createdAt": "2024-12-17T23:00:00Z",
+        "userInput": {"__type": "Pointer", "className": "UserInput", "objectId": "3"},
+        "recommendations": "推荐一套运动服,搭配舒适的运动鞋。"
+    },
+    {
+        "objectId": "4",
+        "createdAt": "2024-12-17T23:05:00Z",
+        "userInput": {"__type": "Pointer", "className": "UserInput", "objectId": "4"},
+        "recommendations": "推荐一套活泼的休闲服,搭配帆布鞋。"
+    },
+    {
+        "objectId": "5",
+        "createdAt": "2024-12-17T23:10:00Z",
+        "userInput": {"__type": "Pointer", "className": "UserInput", "objectId": "5"},
+        "recommendations": "推荐一套经典的西装,搭配皮鞋。"
+    }
+]
+
+
+
+module.exports.PerferList=[
+    {"objectId": "1", "createdAt": "2024-06-21T12:37:59Z", "user_id": "1", "item_id": "443185468969865216", "perference": 2.5},
+    {"objectId": "2", "createdAt": "2024-06-21T12:38:12Z", "user_id": "1", "item_id": "444976198524620800", "perference": 3},
+    {"objectId": "3", "createdAt": "2024-06-21T13:03:00Z", "user_id": "1", "item_id": "510202168684335104", "perference": 5},
+    {"objectId": "4", "createdAt": "2024-08-12T13:52:11Z", "user_id": "1", "item_id": "573258351636647936", "preference": 0.1},
+    {"objectId": "5", "createdAt": "2024-08-09T11:25:49Z", "user_id": "266024222614683648", "item_id": "317079152804872192", "perference": 0.3},
+    {"objectId": "6", "createdAt": "2024-08-09T11:53:06Z", "user_id": "266024222614683648", "item_id": "418845332949979136", "perference": 0.3},
+    {"objectId": "7", "createdAt": "2024-06-21T12:40:04Z", "user_id": "266024222614683648", "item_id": "432979672986308608", "perference": 2},
+    {"objectId": "8", "createdAt": "2024-06-21T12:43:59Z", "user_id": "266024222614683648", "item_id": "443185468969865216", "perference": 5},
+    {"objectId": "9", "createdAt": "2024-06-21T12:39:18Z", "user_id": "266024222614683648", "item_id": "444976198524620800", "perference": 2.5},
+    {"objectId": "10", "createdAt": "2024-06-21T12:39:07Z", "user_id": "266024222614683648", "item_id": "510202168684335104", "perference": 2},
+    {"objectId": "11", "createdAt": "2024-06-21T12:49:14Z", "user_id": "324354387522158592", "item_id": "410554581992296448", "perference": 5},
+    {"objectId": "12", "createdAt": "2024-06-21T12:47:14Z", "user_id": "324354387522158592", "item_id": "432979672986308608", "perference": 4},
+    {"objectId": "13", "createdAt": "2024-06-21T12:46:40Z", "user_id": "324354387522158592", "item_id": "510202168684335104", "perference": 2.5},
+    {"objectId": "14", "createdAt": "2024-06-21T12:47:32Z", "user_id": "324354387522158592", "item_id": "534795602552180736", "perference": 4.5},
+    {"objectId": "15", "createdAt": "2024-06-21T12:57:21Z", "user_id": "405145387760418819", "item_id": "411287434115960832", "perference": 4},
+    {"objectId": "16", "createdAt": "2024-06-21T12:55:59Z", "user_id": "405145387760418819", "item_id": "432979672986308608", "perference": 4},
+    {"objectId": "17", "createdAt": "2024-06-21T12:55:37Z", "user_id": "405145387760418819", "item_id": "443185468969865216", "perference": 2},
+    {"objectId": "18", "createdAt": "2024-06-21T12:55:07Z", "user_id": "405145387760418819", "item_id": "444976198524620800", "perference": 3},
+    {"objectId": "19", "createdAt": "2024-06-21T12:54:33Z", "user_id": "405145387760418819", "item_id": "510202168684335104", "perference": 4},
+    {"objectId": "20", "createdAt": "2024-06-21T12:56:30Z", "user_id": "405145387760418819", "item_id": "534795602552180736", "perference": 3.5},
+    {"objectId": "21", "createdAt": "2024-06-21T12:51:21Z", "user_id": "405145389433946114", "item_id": "411287434115960832", "perference": 4},
+    {"objectId": "22", "createdAt": "2024-06-21T12:50:53Z", "user_id": "405145389433946114", "item_id": "432979672986308608", "perference": 3},
+    {"objectId": "23", "createdAt": "2024-06-21T12:50:33Z", "user_id": "405145389433946114", "item_id": "443185468969865216", "perference": 4.5},
+    {"objectId": "24", "createdAt": "2024-06-21T12:50:33Z", "user_id": "405145389433946114", "item_id": "510202168684335104", "perference": 5}
+]

+ 77 - 0
fashion-server/migration/import-data.js

@@ -0,0 +1,77 @@
+const { CloudQuery, CloudObject } = require("../lib/ncloud");
+const { UserProfileList, UserInputList,AIRecommendationList, PerferList } = require("./data");
+importData()
+
+DataMap = {
+    UserProfile:{},
+    UserInput:{},
+    AIRecommendation:{},
+    PerferList:{}
+}
+
+async function importData(){
+    // 导入用户数据
+     //let userProfileList = UserProfileList
+     //for (let index = 0; index < userProfileList.length; index++) {
+         //let userProfile = userProfileList[index];
+        // userProfile = await importObject("UserProfile",userProfile)
+     //}
+     //导入用户输入数据
+    //  let userInputList = UserInputList
+    //  for (let index = 0; index < userInputList.length; index++) {
+    //      let userInput = userInputList[index];
+    //      userInput = await importObject("UserInput",userInput)
+    //  }
+     //导入AI生成数据
+    //  let aiRecommendationList = AIRecommendationList
+    //  for (let index = 0; index < aiRecommendationList.length; index++) {
+    //      let aiRecommendation = aiRecommendationList[index];
+    //      aiRecommendation = await importObject("AIRecommendation",aiRecommendation)
+    //  }
+    //导入偏好数据
+      let perferList = PerferList
+     for (let index = 0; index < perferList.length; index++) {
+          let perfer = perferList[index];
+          perfer = await importObject("Perfer",perfer)
+      }
+
+
+     console.log(DataMap)
+}
+
+async function importObject(className,data){
+
+    // 查重 srcId 数据源列表中的objectId并非数据库生成的唯一ID,因此需要有一个srcId字段进行记录,并查重
+    let query = new CloudQuery(className)
+    let srcId = data.objectId
+    query.equalTo("srcId",srcId)
+    let importObj = await query.first()
+    
+
+    // 导入
+    // 导入前批量处理Pointer类型数据,进行重定向
+    Object.keys(data)?.forEach(key=>{
+        let field = data[key]
+        let srcId = field?.objectId
+        if(srcId){ // 是数组字段
+            if(key=="user"){
+                data[key] = DataMap?.["UserProfile"]?.[srcId]?.toPointer();
+            }
+            if(key=="userInput"){
+                data[key] = DataMap?.["UserInput"]?.[srcId]?.toPointer();
+            }
+        }
+    })
+
+    // 若未添加,则创建新对象并保存
+    if(!importObj?.id){
+        importObj = new CloudObject(className)
+    }
+
+    // 保存或更新数据
+    data.srcId = srcId;
+    importObj.set(data);
+    importObj = await importObj.save();
+
+    //DataMap[className][srcId] = importObj
+}

+ 86 - 0
fashion-server/migration/import-dataMethod.js

@@ -0,0 +1,86 @@
+async function main(){
+
+     let newUser = {"name":"xiaoming","gender":"男","age":26}
+     let newSavedId = await createUser(newUser)
+     console.log("newSavedId",newSavedId)
+     console.log(await getUser())
+     let newUser1 = {"name":"zhansan","gender":"男","age":29}
+    console.log(await updateUser(newSavedId,newUser1))
+    console.log(await getUser())
+    console.log(await deleteUser(newSavedId))
+}
+main()
+
+async function deleteUser(id){
+    let response = await fetch("http://1.94.237.145:1339/parse/classes/test/"+id, {
+        "headers": {
+          "accept": "*/*",
+          "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+          "x-parse-application-id": "ylj",
+          "Referer": "http://127.0.0.1:4040/",
+          "Referrer-Policy": "strict-origin-when-cross-origin"
+        },
+        "body": null,
+        "method": "DELETE"
+      });
+      return response?.json();
+
+}
+
+async function updateUser(id,userInfo){
+    let body = JSON.stringify(userInfo)
+    let response = await fetch("http://1.94.237.145:1339/parse/classes/test/"+id, {
+        "headers": {
+          "accept": "*/*",
+          "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+          "content-type": "text/plain;charset=UTF-8",
+          "x-parse-application-id": "ylj",
+          "Referer": "http://127.0.0.1:4040/",
+          "Referrer-Policy": "strict-origin-when-cross-origin"
+        },
+        "body": body,
+        "method": "PUT"
+      });
+      return await response?.json()
+}
+
+async function createUser(userInfo){
+    let body = JSON.stringify(userInfo)
+    let response = await fetch("http://1.94.237.145:1339/parse/classes/test", {
+        "headers": {
+          "accept": "*/*",
+          "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+          "content-type": "text/plain;charset=UTF-8",
+          "x-parse-application-id": "ylj",
+          "Referer": "http://127.0.0.1:4040/",
+          "Referrer-Policy": "strict-origin-when-cross-origin"
+        },
+        "body": body,
+        "method": "POST"
+      });
+      let result = await response?.json();
+      return result?.objectId
+
+
+}
+
+
+async function getUser(){
+
+    let response = await fetch("http://1.94.237.145:1339/parse/classes/test?", {
+        "headers": {
+          "accept": "*/*",
+          "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+          "if-none-match": "W/\"127-p6+dUp7xlGAxzyvVsfuvVhMxjPo\"",
+          "x-parse-application-id": "ylj",
+          "Referer": "http://127.0.0.1:4040/",
+          "Referrer-Policy": "strict-origin-when-cross-origin"
+        },
+        "body": null,
+        "method": "GET"
+      });
+    let json = await response?.json();
+    return json?.results || []
+
+    
+}

+ 1 - 0
fashion-server/migration/js/20241212ajax.txt

@@ -0,0 +1 @@
+Hello,ajax!Good luck.

+ 34 - 0
fashion-server/migration/js/a.js

@@ -0,0 +1,34 @@
+import http from 'http';
+import url from 'url';
+import path from 'path';
+import fs from 'fs';
+import os from 'os';
+import mime from 'mime';
+import { fileURLToPath } from 'url';
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+
+const app = http.createServer((req, res) => {
+let rootpath = __dirname;
+if (os.platform() === 'darwin' || os.platform() === 'linux')
+ rootpath = path.join(process.env.HOME, './');
+
+
+let pathname = url.parse(req.url).pathname;
+pathname = pathname == '/' ? '/default.html' : pathname;
+let realPath = path.join(__dirname, 'public' + pathname);
+let type = mime.getType(realPath);
+fs.readFile(realPath, (error, result) => {
+if (error != null) {
+res.writeHead(404, { 'content-type': 'text/html;charset=utf8' });
+res.end('文件读取失败');
+} else {
+res.writeHead(200, {
+'content-type': type
+});
+res.end(result);
+};
+});
+});
+// 监听 3000 端口
+app.listen(3000);
+console.log('服务器已启动,监听 3000 端口,请访问 localhost:3000');

+ 35 - 0
fashion-server/migration/js/default.html

@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Document</title>
+</head>
+<body>
+    <div id="myajax">Hello world!</div>
+    <button type="button" onclick="fetchLoadTxt('20241212ajax.txt')">通过 AJAX 改变内容</button>
+    
+    <script type="text/javascript">
+        function fetchLoadTxt(url) {// 定义 fetchLoadTxt 函数,用于加载指定 URL 的文本文件
+            (async (url) => {// 使用立即调用的异步函数表达式 (IIFE)
+                try {
+                    // 使用 fetch API 请求指定的 URL
+                    let response = await fetch(url);
+                    // 检查响应状态是否为 200(成功)
+                    if (!response.ok) {
+                        throw new Error(`HTTP error! status: ${response.status}`); // 抛出错误
+                    }
+                    // 读取响应文本
+                    let res = await response.text();
+                    console.log(res); // 在控制台输出响应文本
+                    // 更新页面内容
+                    document.getElementById("myajax").innerHTML = res; // 将响应文本更新到 div 中
+                } catch (e) {
+                    // 捕获并处理错误
+                    console.log('Error:', e.message); // 在控制台输出错误信息
+                }
+            })(url); // 立即调用函数并传入 URL
+        }
+    </script>
+</body>
+</html>

+ 58 - 0
fashion-server/migration/js/index.html

@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>异步交互数据传递</title> 
+    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <!-- 引入jQuery库 -->
+</head>
+<body>
+    <h1>用户信息提交</h1> <!-- 页面主标题 -->
+    <form action="#" method="get" style="width: 245px;"> <!-- 表单,宽度设置为245px -->
+        <label for="username">用户名:</label> <!-- 用户名标签 -->
+        <input type="text" id="username" style="float: right;" /> <!-- 用户名输入框 -->
+        <br/><br/> 
+        <label for="age">年龄:</label> <!-- 年龄标签 -->
+        <input type="text" id="age" style="float: right;" /> <!-- 年龄输入框 -->
+        <br/><br/> 
+        <input type="button" value="提交" id="btn" /> <!-- 提交按钮 -->
+        <br/><br/> 
+        <div id="show"></div> <!-- 用于显示文本文件内容的div -->
+    </form>
+    <script type="text/javascript">
+        $(function() {
+            // 读取并显示文本文件的内容
+            $.ajax({
+                url: "20241212ajax.txt",  // 请求的文本文件路径
+                success: function(result) { // 请求成功的回调函数
+                    $("#show").html(result);  // 将文本文件内容显示在id为show的div中
+                },
+                error: function() { // 请求失败的回调函数
+                    alert("无法加载文本文件!"); // 弹出提示框
+                }
+            });
+            $("#btn").click(function() {// 点击提交按钮时,收集表单数据并发送给后端
+                let username = $("#username").val();  // 获取用户名输入框的值
+                let age = $("#age").val();            // 获取年龄输入框的值
+                // 判断用户名和年龄是否为空
+                if (!username || !age) { // 如果任一输入为空
+                    alert("用户名和年龄不能为空!"); // 弹出提示框
+                    return; // 终止函数执行
+                }
+                let params = { // 构建发送给后端的数据
+                    username: username, // 将用户名存入params对象
+                    age: age            // 将年龄存入params对象
+                };
+                $.ajax({// 使用 jQuery 的 AJAX 方法来发送请求
+                    url: "http://localhost:3000/get",  // 后端接收请求的URL
+                    type: "GET",                       // 请求类型为GET
+                    data: params,                      // 发送的数据
+                    success: function(data, status) { // 请求成功的回调函数
+                        alert("数据: " + data + "\n状态: " + status); // 弹出返回的数据和状态
+                    },
+                    error: function(xhr, status, error) { // 请求失败的回调函数
+                        alert("请求失败: " + error); // 弹出错误信息
+                    } });  });    });
+    </script>
+</body>
+</html>

+ 22 - 0
fashion-server/migration/js/node.js

@@ -0,0 +1,22 @@
+import http from 'http';
+import url from 'url';
+import querystring from 'querystring';
+// 创建 HTTP 服务器
+http.createServer((req, res) => {
+    res.setHeader('Access-Control-Allow-Origin', '*');  // 允许跨域访问
+
+    if (req.method.toLowerCase() === 'get') {
+        const mGet = url.parse(req.url, true);
+        const username = mGet.query.username;
+        const age = mGet.query.age;
+        // 打印用户数据
+        console.log(`用户名: ${username}, 年龄: ${age}`);
+        // 返回响应
+        res.writeHead(200, { 'Content-Type': 'text/plain' });
+        res.end(`数据接收成功:用户名 = ${username}, 年龄 = ${age}`);
+    } else {
+        res.writeHead(404, { 'Content-Type': 'text/plain' });
+        res.end('Not Found');
+    }
+}).listen(3000, () => {
+    console.log('Server running at http://localhost:3000/');});

+ 16 - 0
fashion-server/migration/js/node_modules/.bin/mime

@@ -0,0 +1,16 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+    *CYGWIN*|*MINGW*|*MSYS*)
+        if command -v cygpath > /dev/null 2>&1; then
+            basedir=`cygpath -w "$basedir"`
+        fi
+    ;;
+esac
+
+if [ -x "$basedir/node" ]; then
+  exec "$basedir/node"  "$basedir/../mime/bin/cli.js" "$@"
+else 
+  exec node  "$basedir/../mime/bin/cli.js" "$@"
+fi

+ 17 - 0
fashion-server/migration/js/node_modules/.bin/mime.cmd

@@ -0,0 +1,17 @@
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+  SET "_prog=%dp0%\node.exe"
+) ELSE (
+  SET "_prog=node"
+  SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%"  "%dp0%\..\mime\bin\cli.js" %*

+ 28 - 0
fashion-server/migration/js/node_modules/.bin/mime.ps1

@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+  # Fix case when both the Windows and Linux builds of Node
+  # are installed in the same directory
+  $exe=".exe"
+}
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+  # Support pipeline input
+  if ($MyInvocation.ExpectingInput) {
+    $input | & "$basedir/node$exe"  "$basedir/../mime/bin/cli.js" $args
+  } else {
+    & "$basedir/node$exe"  "$basedir/../mime/bin/cli.js" $args
+  }
+  $ret=$LASTEXITCODE
+} else {
+  # Support pipeline input
+  if ($MyInvocation.ExpectingInput) {
+    $input | & "node$exe"  "$basedir/../mime/bin/cli.js" $args
+  } else {
+    & "node$exe"  "$basedir/../mime/bin/cli.js" $args
+  }
+  $ret=$LASTEXITCODE
+}
+exit $ret

+ 22 - 0
fashion-server/migration/js/node_modules/.package-lock.json

@@ -0,0 +1,22 @@
+{
+  "name": "js",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "node_modules/mime": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmmirror.com/mime/-/mime-4.0.6.tgz",
+      "integrity": "sha512-4rGt7rvQHBbaSOF9POGkk1ocRP16Md1x36Xma8sz8h8/vfCUI2OtEIeCqe4Ofes853x4xDoPiFLIT47J5fI/7A==",
+      "funding": [
+        "https://github.com/sponsors/broofa"
+      ],
+      "license": "MIT",
+      "bin": {
+        "mime": "bin/cli.js"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    }
+  }
+}

+ 21 - 0
fashion-server/migration/js/node_modules/mime/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Robert Kieffer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 143 - 0
fashion-server/migration/js/node_modules/mime/README.md

@@ -0,0 +1,143 @@
+<!--
+  -- This file is auto-generated from src/README_js.md. Changes should be made there.
+  -->
+# Mime
+
+[![NPM downloads](https://img.shields.io/npm/dm/mime)](https://www.npmjs.com/package/mime)
+[![Mime CI](https://github.com/broofa/mime/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/broofa/mime/actions/workflows/ci.yml?query=branch%3Amain)
+
+An API for MIME type information.
+
+- All `mime-db` types
+- Compact and dependency-free [![mime's badge](https://deno.bundlejs.com/?q=mime&badge)](https://bundlejs.com/?q=mime)
+- Full TS support
+
+
+> [!Note]
+> `mime@4` is now `latest`.  If you're upgrading from `mime@3`, note the following:
+> * `mime@4` is API-compatible with `mime@3`, with ~~one~~ two exceptions:
+>   * Direct imports of `mime` properties [no longer supported](https://github.com/broofa/mime/issues/295)
+>   * `mime.define()` cannot be called on the default `mime` object
+> * ESM module support is required.   [ESM Module FAQ](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).
+> * Requires an [ES2020](https://caniuse.com/?search=es2020) or newer runtime
+> * Built-in Typescript types (`@types/mime` no longer needed)
+
+## Installation
+
+```bash
+npm install mime
+```
+
+## Quick Start
+
+For the full version (800+ MIME types, 1,000+ extensions):
+
+```javascript
+import mime from 'mime';
+
+mime.getType('txt');                    // ⇨ 'text/plain'
+mime.getExtension('text/plain');        // ⇨ 'txt'
+```
+
+### Lite Version [![mime/lite's badge](https://deno.bundlejs.com/?q=mime/lite&badge)](https://bundlejs.com/?q=mime/lite)
+
+`mime/lite` is a drop-in `mime` replacement, stripped of unofficial ("`prs.*`", "`x-*`", "`vnd.*`") types:
+
+```javascript
+import mime from 'mime/lite';
+```
+
+## API
+
+### `mime.getType(pathOrExtension)`
+
+Get mime type for the given file path or extension. E.g.
+
+```javascript
+mime.getType('js');             // ⇨ 'text/javascript'
+mime.getType('json');           // ⇨ 'application/json'
+
+mime.getType('txt');            // ⇨ 'text/plain'
+mime.getType('dir/text.txt');   // ⇨ 'text/plain'
+mime.getType('dir\\text.txt');  // ⇨ 'text/plain'
+mime.getType('.text.txt');      // ⇨ 'text/plain'
+mime.getType('.txt');           // ⇨ 'text/plain'
+```
+
+`null` is returned in cases where an extension is not detected or recognized
+
+```javascript
+mime.getType('foo/txt');        // ⇨ null
+mime.getType('bogus_type');     // ⇨ null
+```
+
+### `mime.getExtension(type)`
+
+Get file extension for the given mime type. Charset options (often included in Content-Type headers) are ignored.
+
+```javascript
+mime.getExtension('text/plain');               // ⇨ 'txt'
+mime.getExtension('application/json');         // ⇨ 'json'
+mime.getExtension('text/html; charset=utf8');  // ⇨ 'html'
+```
+
+### `mime.getAllExtensions(type)`
+
+> [!Note]
+> New in `mime@4`
+
+Get all file extensions for the given mime type.
+
+```javascript --run default
+mime.getAllExtensions('image/jpeg'); // ⇨ Set(3) { 'jpeg', 'jpg', 'jpe' }
+```
+
+## Custom `Mime` instances
+
+The default `mime` objects are immutable.  Custom, mutable versions can be created as follows...
+### new Mime(type map [, type map, ...])
+
+Create a new, custom mime instance.  For example, to create a mutable version of the default `mime` instance:
+
+```javascript
+import { Mime } from 'mime/lite';
+
+import standardTypes from 'mime/types/standard.js';
+import otherTypes from 'mime/types/other.js';
+
+const mime = new Mime(standardTypes, otherTypes);
+```
+
+Each argument is passed to the `define()` method, below. For example `new Mime(standardTypes, otherTypes)` is synonomous with `new Mime().define(standardTypes).define(otherTypes)`
+
+### `mime.define(type map [, force = false])`
+
+> [!Note]
+> Only available on custom `Mime` instances
+
+Define MIME type -> extensions.
+
+Attempting to map a type to an already-defined extension will `throw` unless the `force` argument is set to `true`.
+
+```javascript
+mime.define({'text/x-abc': ['abc', 'abcd']});
+
+mime.getType('abcd');            // ⇨ 'text/x-abc'
+mime.getExtension('text/x-abc')  // ⇨ 'abc'
+```
+
+## Command Line
+
+### Extension -> type
+
+```bash
+$ mime scripts/jquery.js
+text/javascript
+```
+
+### Type -> extension
+
+```bash
+$ mime -r image/jpeg
+jpeg
+```

+ 6 - 0
fashion-server/migration/js/node_modules/mime/bin/cli.js

@@ -0,0 +1,6 @@
+#!/usr/bin/env node
+
+// Thin wrapper around mime
+import mime_cli from '../dist/src/mime_cli.js';
+
+await mime_cli();

+ 17 - 0
fashion-server/migration/js/node_modules/mime/dist/src/Mime.d.ts

@@ -0,0 +1,17 @@
+type TypeMap = {
+    [key: string]: string[];
+};
+export default class Mime {
+    #private;
+    constructor(...args: TypeMap[]);
+    define(typeMap: TypeMap, force?: boolean): this;
+    getType(path: string): string | null;
+    getExtension(type: string): string | null;
+    getAllExtensions(type: string): Set<string> | null;
+    _freeze(): this;
+    _getTestState(): {
+        types: Map<string, string>;
+        extensions: Map<string, string>;
+    };
+}
+export {};

+ 84 - 0
fashion-server/migration/js/node_modules/mime/dist/src/Mime.js

@@ -0,0 +1,84 @@
+var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _Mime_extensionToType, _Mime_typeToExtension, _Mime_typeToExtensions;
+class Mime {
+    constructor(...args) {
+        _Mime_extensionToType.set(this, new Map());
+        _Mime_typeToExtension.set(this, new Map());
+        _Mime_typeToExtensions.set(this, new Map());
+        for (const arg of args) {
+            this.define(arg);
+        }
+    }
+    define(typeMap, force = false) {
+        for (let [type, extensions] of Object.entries(typeMap)) {
+            type = type.toLowerCase();
+            extensions = extensions.map((ext) => ext.toLowerCase());
+            if (!__classPrivateFieldGet(this, _Mime_typeToExtensions, "f").has(type)) {
+                __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").set(type, new Set());
+            }
+            const allExtensions = __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type);
+            let first = true;
+            for (let extension of extensions) {
+                const starred = extension.startsWith('*');
+                extension = starred ? extension.slice(1) : extension;
+                allExtensions?.add(extension);
+                if (first) {
+                    __classPrivateFieldGet(this, _Mime_typeToExtension, "f").set(type, extension);
+                }
+                first = false;
+                if (starred)
+                    continue;
+                const currentType = __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(extension);
+                if (currentType && currentType != type && !force) {
+                    throw new Error(`"${type} -> ${extension}" conflicts with "${currentType} -> ${extension}". Pass \`force=true\` to override this definition.`);
+                }
+                __classPrivateFieldGet(this, _Mime_extensionToType, "f").set(extension, type);
+            }
+        }
+        return this;
+    }
+    getType(path) {
+        if (typeof path !== 'string')
+            return null;
+        const last = path.replace(/^.*[/\\]/, '').toLowerCase();
+        const ext = last.replace(/^.*\./, '').toLowerCase();
+        const hasPath = last.length < path.length;
+        const hasDot = ext.length < last.length - 1;
+        if (!hasDot && hasPath)
+            return null;
+        return __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(ext) ?? null;
+    }
+    getExtension(type) {
+        if (typeof type !== 'string')
+            return null;
+        type = type?.split?.(';')[0];
+        return ((type && __classPrivateFieldGet(this, _Mime_typeToExtension, "f").get(type.trim().toLowerCase())) ?? null);
+    }
+    getAllExtensions(type) {
+        if (typeof type !== 'string')
+            return null;
+        return __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type.toLowerCase()) ?? null;
+    }
+    _freeze() {
+        this.define = () => {
+            throw new Error('define() not allowed for built-in Mime objects. See https://github.com/broofa/mime/blob/main/README.md#custom-mime-instances');
+        };
+        Object.freeze(this);
+        for (const extensions of __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").values()) {
+            Object.freeze(extensions);
+        }
+        return this;
+    }
+    _getTestState() {
+        return {
+            types: __classPrivateFieldGet(this, _Mime_extensionToType, "f"),
+            extensions: __classPrivateFieldGet(this, _Mime_typeToExtension, "f"),
+        };
+    }
+}
+_Mime_extensionToType = new WeakMap(), _Mime_typeToExtension = new WeakMap(), _Mime_typeToExtensions = new WeakMap();
+export default Mime;

+ 4 - 0
fashion-server/migration/js/node_modules/mime/dist/src/index.d.ts

@@ -0,0 +1,4 @@
+import Mime from './Mime.js';
+export { default as Mime } from './Mime.js';
+declare const _default: Mime;
+export default _default;

+ 5 - 0
fashion-server/migration/js/node_modules/mime/dist/src/index.js

@@ -0,0 +1,5 @@
+import otherTypes from '../types/other.js';
+import standardTypes from '../types/standard.js';
+import Mime from './Mime.js';
+export { default as Mime } from './Mime.js';
+export default new Mime(standardTypes, otherTypes)._freeze();

+ 4 - 0
fashion-server/migration/js/node_modules/mime/dist/src/index_lite.d.ts

@@ -0,0 +1,4 @@
+import Mime from './Mime.js';
+export { default as Mime } from './Mime.js';
+declare const _default: Mime;
+export default _default;

+ 4 - 0
fashion-server/migration/js/node_modules/mime/dist/src/index_lite.js

@@ -0,0 +1,4 @@
+import standardTypes from '../types/standard.js';
+import Mime from './Mime.js';
+export { default as Mime } from './Mime.js';
+export default new Mime(standardTypes)._freeze();

+ 2 - 0
fashion-server/migration/js/node_modules/mime/dist/src/mime_cli.d.ts

@@ -0,0 +1,2 @@
+#!/usr/bin/env node
+export default function (): Promise<void>;

+ 66 - 0
fashion-server/migration/js/node_modules/mime/dist/src/mime_cli.js

@@ -0,0 +1,66 @@
+#!/usr/bin/env node
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import mime from './index.js';
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+export default async function () {
+    process.title = 'mime';
+    const json = await fs.readFile(path.join(__dirname, '../../package.json'), 'utf-8');
+    const pkg = JSON.parse(json);
+    const args = process.argv.splice(2);
+    if (args.includes('--version') ||
+        args.includes('-v') ||
+        args.includes('--v')) {
+        console.log(pkg.version);
+        process.exit(0);
+    }
+    else if (args.includes('--name') ||
+        args.includes('-n') ||
+        args.includes('--n')) {
+        console.log(pkg.name);
+        process.exit(0);
+    }
+    else if (args.includes('--help') ||
+        args.includes('-h') ||
+        args.includes('--h')) {
+        console.log(pkg.name + ' - ' + pkg.description + '\n');
+        console.log(`Usage:
+
+  mime [flags] [path_or_extension]
+
+  Flags:
+    --help, -h                     Show this message
+    --version, -v                  Display the version
+    --name, -n                     Print the name of the program
+    --reverse, -r                  Print the extension of the mime type
+
+  Note: the command will exit after it executes if a command is specified
+  The path_or_extension is the path to the file or the extension of the file.
+
+  Examples:
+    mime --help
+    mime --version
+    mime --name
+    mime -v
+    mime --reverse application/text
+    mime src/log.js
+    mime new.py
+    mime foo.sh
+  `);
+        process.exit(0);
+    }
+    else if (args.includes('--reverse') || args.includes('-r')) {
+        const mimeType = args[args.length - 1];
+        const extension = mime.getExtension(mimeType);
+        if (!extension)
+            process.exit(1);
+        process.stdout.write(extension + '\n');
+        process.exit(0);
+    }
+    const file = args[0];
+    const type = mime.getType(file);
+    if (!type)
+        process.exit(1);
+    process.stdout.write(type + '\n');
+}

+ 4 - 0
fashion-server/migration/js/node_modules/mime/dist/types/other.d.ts

@@ -0,0 +1,4 @@
+declare const types: {
+    [key: string]: string[];
+};
+export default types;

+ 701 - 0
fashion-server/migration/js/node_modules/mime/dist/types/other.js

@@ -0,0 +1,701 @@
+const types = {
+    'application/prs.cww': ['cww'],
+    'application/prs.xsf+xml': ['xsf'],
+    'application/vnd.1000minds.decision-model+xml': ['1km'],
+    'application/vnd.3gpp.pic-bw-large': ['plb'],
+    'application/vnd.3gpp.pic-bw-small': ['psb'],
+    'application/vnd.3gpp.pic-bw-var': ['pvb'],
+    'application/vnd.3gpp2.tcap': ['tcap'],
+    'application/vnd.3m.post-it-notes': ['pwn'],
+    'application/vnd.accpac.simply.aso': ['aso'],
+    'application/vnd.accpac.simply.imp': ['imp'],
+    'application/vnd.acucobol': ['acu'],
+    'application/vnd.acucorp': ['atc', 'acutc'],
+    'application/vnd.adobe.air-application-installer-package+zip': ['air'],
+    'application/vnd.adobe.formscentral.fcdt': ['fcdt'],
+    'application/vnd.adobe.fxp': ['fxp', 'fxpl'],
+    'application/vnd.adobe.xdp+xml': ['xdp'],
+    'application/vnd.adobe.xfdf': ['*xfdf'],
+    'application/vnd.age': ['age'],
+    'application/vnd.ahead.space': ['ahead'],
+    'application/vnd.airzip.filesecure.azf': ['azf'],
+    'application/vnd.airzip.filesecure.azs': ['azs'],
+    'application/vnd.amazon.ebook': ['azw'],
+    'application/vnd.americandynamics.acc': ['acc'],
+    'application/vnd.amiga.ami': ['ami'],
+    'application/vnd.android.package-archive': ['apk'],
+    'application/vnd.anser-web-certificate-issue-initiation': ['cii'],
+    'application/vnd.anser-web-funds-transfer-initiation': ['fti'],
+    'application/vnd.antix.game-component': ['atx'],
+    'application/vnd.apple.installer+xml': ['mpkg'],
+    'application/vnd.apple.keynote': ['key'],
+    'application/vnd.apple.mpegurl': ['m3u8'],
+    'application/vnd.apple.numbers': ['numbers'],
+    'application/vnd.apple.pages': ['pages'],
+    'application/vnd.apple.pkpass': ['pkpass'],
+    'application/vnd.aristanetworks.swi': ['swi'],
+    'application/vnd.astraea-software.iota': ['iota'],
+    'application/vnd.audiograph': ['aep'],
+    'application/vnd.balsamiq.bmml+xml': ['bmml'],
+    'application/vnd.blueice.multipass': ['mpm'],
+    'application/vnd.bmi': ['bmi'],
+    'application/vnd.businessobjects': ['rep'],
+    'application/vnd.chemdraw+xml': ['cdxml'],
+    'application/vnd.chipnuts.karaoke-mmd': ['mmd'],
+    'application/vnd.cinderella': ['cdy'],
+    'application/vnd.citationstyles.style+xml': ['csl'],
+    'application/vnd.claymore': ['cla'],
+    'application/vnd.cloanto.rp9': ['rp9'],
+    'application/vnd.clonk.c4group': ['c4g', 'c4d', 'c4f', 'c4p', 'c4u'],
+    'application/vnd.cluetrust.cartomobile-config': ['c11amc'],
+    'application/vnd.cluetrust.cartomobile-config-pkg': ['c11amz'],
+    'application/vnd.commonspace': ['csp'],
+    'application/vnd.contact.cmsg': ['cdbcmsg'],
+    'application/vnd.cosmocaller': ['cmc'],
+    'application/vnd.crick.clicker': ['clkx'],
+    'application/vnd.crick.clicker.keyboard': ['clkk'],
+    'application/vnd.crick.clicker.palette': ['clkp'],
+    'application/vnd.crick.clicker.template': ['clkt'],
+    'application/vnd.crick.clicker.wordbank': ['clkw'],
+    'application/vnd.criticaltools.wbs+xml': ['wbs'],
+    'application/vnd.ctc-posml': ['pml'],
+    'application/vnd.cups-ppd': ['ppd'],
+    'application/vnd.curl.car': ['car'],
+    'application/vnd.curl.pcurl': ['pcurl'],
+    'application/vnd.dart': ['dart'],
+    'application/vnd.data-vision.rdz': ['rdz'],
+    'application/vnd.dbf': ['dbf'],
+    'application/vnd.dece.data': ['uvf', 'uvvf', 'uvd', 'uvvd'],
+    'application/vnd.dece.ttml+xml': ['uvt', 'uvvt'],
+    'application/vnd.dece.unspecified': ['uvx', 'uvvx'],
+    'application/vnd.dece.zip': ['uvz', 'uvvz'],
+    'application/vnd.denovo.fcselayout-link': ['fe_launch'],
+    'application/vnd.dna': ['dna'],
+    'application/vnd.dolby.mlp': ['mlp'],
+    'application/vnd.dpgraph': ['dpg'],
+    'application/vnd.dreamfactory': ['dfac'],
+    'application/vnd.ds-keypoint': ['kpxx'],
+    'application/vnd.dvb.ait': ['ait'],
+    'application/vnd.dvb.service': ['svc'],
+    'application/vnd.dynageo': ['geo'],
+    'application/vnd.ecowin.chart': ['mag'],
+    'application/vnd.enliven': ['nml'],
+    'application/vnd.epson.esf': ['esf'],
+    'application/vnd.epson.msf': ['msf'],
+    'application/vnd.epson.quickanime': ['qam'],
+    'application/vnd.epson.salt': ['slt'],
+    'application/vnd.epson.ssf': ['ssf'],
+    'application/vnd.eszigno3+xml': ['es3', 'et3'],
+    'application/vnd.ezpix-album': ['ez2'],
+    'application/vnd.ezpix-package': ['ez3'],
+    'application/vnd.fdf': ['*fdf'],
+    'application/vnd.fdsn.mseed': ['mseed'],
+    'application/vnd.fdsn.seed': ['seed', 'dataless'],
+    'application/vnd.flographit': ['gph'],
+    'application/vnd.fluxtime.clip': ['ftc'],
+    'application/vnd.framemaker': ['fm', 'frame', 'maker', 'book'],
+    'application/vnd.frogans.fnc': ['fnc'],
+    'application/vnd.frogans.ltf': ['ltf'],
+    'application/vnd.fsc.weblaunch': ['fsc'],
+    'application/vnd.fujitsu.oasys': ['oas'],
+    'application/vnd.fujitsu.oasys2': ['oa2'],
+    'application/vnd.fujitsu.oasys3': ['oa3'],
+    'application/vnd.fujitsu.oasysgp': ['fg5'],
+    'application/vnd.fujitsu.oasysprs': ['bh2'],
+    'application/vnd.fujixerox.ddd': ['ddd'],
+    'application/vnd.fujixerox.docuworks': ['xdw'],
+    'application/vnd.fujixerox.docuworks.binder': ['xbd'],
+    'application/vnd.fuzzysheet': ['fzs'],
+    'application/vnd.genomatix.tuxedo': ['txd'],
+    'application/vnd.geogebra.file': ['ggb'],
+    'application/vnd.geogebra.slides': ['ggs'],
+    'application/vnd.geogebra.tool': ['ggt'],
+    'application/vnd.geometry-explorer': ['gex', 'gre'],
+    'application/vnd.geonext': ['gxt'],
+    'application/vnd.geoplan': ['g2w'],
+    'application/vnd.geospace': ['g3w'],
+    'application/vnd.gmx': ['gmx'],
+    'application/vnd.google-apps.document': ['gdoc'],
+    'application/vnd.google-apps.presentation': ['gslides'],
+    'application/vnd.google-apps.spreadsheet': ['gsheet'],
+    'application/vnd.google-earth.kml+xml': ['kml'],
+    'application/vnd.google-earth.kmz': ['kmz'],
+    'application/vnd.gov.sk.xmldatacontainer+xml': ['xdcf'],
+    'application/vnd.grafeq': ['gqf', 'gqs'],
+    'application/vnd.groove-account': ['gac'],
+    'application/vnd.groove-help': ['ghf'],
+    'application/vnd.groove-identity-message': ['gim'],
+    'application/vnd.groove-injector': ['grv'],
+    'application/vnd.groove-tool-message': ['gtm'],
+    'application/vnd.groove-tool-template': ['tpl'],
+    'application/vnd.groove-vcard': ['vcg'],
+    'application/vnd.hal+xml': ['hal'],
+    'application/vnd.handheld-entertainment+xml': ['zmm'],
+    'application/vnd.hbci': ['hbci'],
+    'application/vnd.hhe.lesson-player': ['les'],
+    'application/vnd.hp-hpgl': ['hpgl'],
+    'application/vnd.hp-hpid': ['hpid'],
+    'application/vnd.hp-hps': ['hps'],
+    'application/vnd.hp-jlyt': ['jlt'],
+    'application/vnd.hp-pcl': ['pcl'],
+    'application/vnd.hp-pclxl': ['pclxl'],
+    'application/vnd.hydrostatix.sof-data': ['sfd-hdstx'],
+    'application/vnd.ibm.minipay': ['mpy'],
+    'application/vnd.ibm.modcap': ['afp', 'listafp', 'list3820'],
+    'application/vnd.ibm.rights-management': ['irm'],
+    'application/vnd.ibm.secure-container': ['sc'],
+    'application/vnd.iccprofile': ['icc', 'icm'],
+    'application/vnd.igloader': ['igl'],
+    'application/vnd.immervision-ivp': ['ivp'],
+    'application/vnd.immervision-ivu': ['ivu'],
+    'application/vnd.insors.igm': ['igm'],
+    'application/vnd.intercon.formnet': ['xpw', 'xpx'],
+    'application/vnd.intergeo': ['i2g'],
+    'application/vnd.intu.qbo': ['qbo'],
+    'application/vnd.intu.qfx': ['qfx'],
+    'application/vnd.ipunplugged.rcprofile': ['rcprofile'],
+    'application/vnd.irepository.package+xml': ['irp'],
+    'application/vnd.is-xpr': ['xpr'],
+    'application/vnd.isac.fcs': ['fcs'],
+    'application/vnd.jam': ['jam'],
+    'application/vnd.jcp.javame.midlet-rms': ['rms'],
+    'application/vnd.jisp': ['jisp'],
+    'application/vnd.joost.joda-archive': ['joda'],
+    'application/vnd.kahootz': ['ktz', 'ktr'],
+    'application/vnd.kde.karbon': ['karbon'],
+    'application/vnd.kde.kchart': ['chrt'],
+    'application/vnd.kde.kformula': ['kfo'],
+    'application/vnd.kde.kivio': ['flw'],
+    'application/vnd.kde.kontour': ['kon'],
+    'application/vnd.kde.kpresenter': ['kpr', 'kpt'],
+    'application/vnd.kde.kspread': ['ksp'],
+    'application/vnd.kde.kword': ['kwd', 'kwt'],
+    'application/vnd.kenameaapp': ['htke'],
+    'application/vnd.kidspiration': ['kia'],
+    'application/vnd.kinar': ['kne', 'knp'],
+    'application/vnd.koan': ['skp', 'skd', 'skt', 'skm'],
+    'application/vnd.kodak-descriptor': ['sse'],
+    'application/vnd.las.las+xml': ['lasxml'],
+    'application/vnd.llamagraphics.life-balance.desktop': ['lbd'],
+    'application/vnd.llamagraphics.life-balance.exchange+xml': ['lbe'],
+    'application/vnd.lotus-1-2-3': ['123'],
+    'application/vnd.lotus-approach': ['apr'],
+    'application/vnd.lotus-freelance': ['pre'],
+    'application/vnd.lotus-notes': ['nsf'],
+    'application/vnd.lotus-organizer': ['org'],
+    'application/vnd.lotus-screencam': ['scm'],
+    'application/vnd.lotus-wordpro': ['lwp'],
+    'application/vnd.macports.portpkg': ['portpkg'],
+    'application/vnd.mapbox-vector-tile': ['mvt'],
+    'application/vnd.mcd': ['mcd'],
+    'application/vnd.medcalcdata': ['mc1'],
+    'application/vnd.mediastation.cdkey': ['cdkey'],
+    'application/vnd.mfer': ['mwf'],
+    'application/vnd.mfmp': ['mfm'],
+    'application/vnd.micrografx.flo': ['flo'],
+    'application/vnd.micrografx.igx': ['igx'],
+    'application/vnd.mif': ['mif'],
+    'application/vnd.mobius.daf': ['daf'],
+    'application/vnd.mobius.dis': ['dis'],
+    'application/vnd.mobius.mbk': ['mbk'],
+    'application/vnd.mobius.mqy': ['mqy'],
+    'application/vnd.mobius.msl': ['msl'],
+    'application/vnd.mobius.plc': ['plc'],
+    'application/vnd.mobius.txf': ['txf'],
+    'application/vnd.mophun.application': ['mpn'],
+    'application/vnd.mophun.certificate': ['mpc'],
+    'application/vnd.mozilla.xul+xml': ['xul'],
+    'application/vnd.ms-artgalry': ['cil'],
+    'application/vnd.ms-cab-compressed': ['cab'],
+    'application/vnd.ms-excel': ['xls', 'xlm', 'xla', 'xlc', 'xlt', 'xlw'],
+    'application/vnd.ms-excel.addin.macroenabled.12': ['xlam'],
+    'application/vnd.ms-excel.sheet.binary.macroenabled.12': ['xlsb'],
+    'application/vnd.ms-excel.sheet.macroenabled.12': ['xlsm'],
+    'application/vnd.ms-excel.template.macroenabled.12': ['xltm'],
+    'application/vnd.ms-fontobject': ['eot'],
+    'application/vnd.ms-htmlhelp': ['chm'],
+    'application/vnd.ms-ims': ['ims'],
+    'application/vnd.ms-lrm': ['lrm'],
+    'application/vnd.ms-officetheme': ['thmx'],
+    'application/vnd.ms-outlook': ['msg'],
+    'application/vnd.ms-pki.seccat': ['cat'],
+    'application/vnd.ms-pki.stl': ['*stl'],
+    'application/vnd.ms-powerpoint': ['ppt', 'pps', 'pot'],
+    'application/vnd.ms-powerpoint.addin.macroenabled.12': ['ppam'],
+    'application/vnd.ms-powerpoint.presentation.macroenabled.12': ['pptm'],
+    'application/vnd.ms-powerpoint.slide.macroenabled.12': ['sldm'],
+    'application/vnd.ms-powerpoint.slideshow.macroenabled.12': ['ppsm'],
+    'application/vnd.ms-powerpoint.template.macroenabled.12': ['potm'],
+    'application/vnd.ms-project': ['*mpp', 'mpt'],
+    'application/vnd.ms-word.document.macroenabled.12': ['docm'],
+    'application/vnd.ms-word.template.macroenabled.12': ['dotm'],
+    'application/vnd.ms-works': ['wps', 'wks', 'wcm', 'wdb'],
+    'application/vnd.ms-wpl': ['wpl'],
+    'application/vnd.ms-xpsdocument': ['xps'],
+    'application/vnd.mseq': ['mseq'],
+    'application/vnd.musician': ['mus'],
+    'application/vnd.muvee.style': ['msty'],
+    'application/vnd.mynfc': ['taglet'],
+    'application/vnd.nato.bindingdataobject+xml': ['bdo'],
+    'application/vnd.neurolanguage.nlu': ['nlu'],
+    'application/vnd.nitf': ['ntf', 'nitf'],
+    'application/vnd.noblenet-directory': ['nnd'],
+    'application/vnd.noblenet-sealer': ['nns'],
+    'application/vnd.noblenet-web': ['nnw'],
+    'application/vnd.nokia.n-gage.ac+xml': ['*ac'],
+    'application/vnd.nokia.n-gage.data': ['ngdat'],
+    'application/vnd.nokia.n-gage.symbian.install': ['n-gage'],
+    'application/vnd.nokia.radio-preset': ['rpst'],
+    'application/vnd.nokia.radio-presets': ['rpss'],
+    'application/vnd.novadigm.edm': ['edm'],
+    'application/vnd.novadigm.edx': ['edx'],
+    'application/vnd.novadigm.ext': ['ext'],
+    'application/vnd.oasis.opendocument.chart': ['odc'],
+    'application/vnd.oasis.opendocument.chart-template': ['otc'],
+    'application/vnd.oasis.opendocument.database': ['odb'],
+    'application/vnd.oasis.opendocument.formula': ['odf'],
+    'application/vnd.oasis.opendocument.formula-template': ['odft'],
+    'application/vnd.oasis.opendocument.graphics': ['odg'],
+    'application/vnd.oasis.opendocument.graphics-template': ['otg'],
+    'application/vnd.oasis.opendocument.image': ['odi'],
+    'application/vnd.oasis.opendocument.image-template': ['oti'],
+    'application/vnd.oasis.opendocument.presentation': ['odp'],
+    'application/vnd.oasis.opendocument.presentation-template': ['otp'],
+    'application/vnd.oasis.opendocument.spreadsheet': ['ods'],
+    'application/vnd.oasis.opendocument.spreadsheet-template': ['ots'],
+    'application/vnd.oasis.opendocument.text': ['odt'],
+    'application/vnd.oasis.opendocument.text-master': ['odm'],
+    'application/vnd.oasis.opendocument.text-template': ['ott'],
+    'application/vnd.oasis.opendocument.text-web': ['oth'],
+    'application/vnd.olpc-sugar': ['xo'],
+    'application/vnd.oma.dd2+xml': ['dd2'],
+    'application/vnd.openblox.game+xml': ['obgx'],
+    'application/vnd.openofficeorg.extension': ['oxt'],
+    'application/vnd.openstreetmap.data+xml': ['osm'],
+    'application/vnd.openxmlformats-officedocument.presentationml.presentation': [
+        'pptx',
+    ],
+    'application/vnd.openxmlformats-officedocument.presentationml.slide': [
+        'sldx',
+    ],
+    'application/vnd.openxmlformats-officedocument.presentationml.slideshow': [
+        'ppsx',
+    ],
+    'application/vnd.openxmlformats-officedocument.presentationml.template': [
+        'potx',
+    ],
+    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['xlsx'],
+    'application/vnd.openxmlformats-officedocument.spreadsheetml.template': [
+        'xltx',
+    ],
+    'application/vnd.openxmlformats-officedocument.wordprocessingml.document': [
+        'docx',
+    ],
+    'application/vnd.openxmlformats-officedocument.wordprocessingml.template': [
+        'dotx',
+    ],
+    'application/vnd.osgeo.mapguide.package': ['mgp'],
+    'application/vnd.osgi.dp': ['dp'],
+    'application/vnd.osgi.subsystem': ['esa'],
+    'application/vnd.palm': ['pdb', 'pqa', 'oprc'],
+    'application/vnd.pawaafile': ['paw'],
+    'application/vnd.pg.format': ['str'],
+    'application/vnd.pg.osasli': ['ei6'],
+    'application/vnd.picsel': ['efif'],
+    'application/vnd.pmi.widget': ['wg'],
+    'application/vnd.pocketlearn': ['plf'],
+    'application/vnd.powerbuilder6': ['pbd'],
+    'application/vnd.previewsystems.box': ['box'],
+    'application/vnd.proteus.magazine': ['mgz'],
+    'application/vnd.publishare-delta-tree': ['qps'],
+    'application/vnd.pvi.ptid1': ['ptid'],
+    'application/vnd.pwg-xhtml-print+xml': ['xhtm'],
+    'application/vnd.quark.quarkxpress': [
+        'qxd',
+        'qxt',
+        'qwd',
+        'qwt',
+        'qxl',
+        'qxb',
+    ],
+    'application/vnd.rar': ['rar'],
+    'application/vnd.realvnc.bed': ['bed'],
+    'application/vnd.recordare.musicxml': ['mxl'],
+    'application/vnd.recordare.musicxml+xml': ['musicxml'],
+    'application/vnd.rig.cryptonote': ['cryptonote'],
+    'application/vnd.rim.cod': ['cod'],
+    'application/vnd.rn-realmedia': ['rm'],
+    'application/vnd.rn-realmedia-vbr': ['rmvb'],
+    'application/vnd.route66.link66+xml': ['link66'],
+    'application/vnd.sailingtracker.track': ['st'],
+    'application/vnd.seemail': ['see'],
+    'application/vnd.sema': ['sema'],
+    'application/vnd.semd': ['semd'],
+    'application/vnd.semf': ['semf'],
+    'application/vnd.shana.informed.formdata': ['ifm'],
+    'application/vnd.shana.informed.formtemplate': ['itp'],
+    'application/vnd.shana.informed.interchange': ['iif'],
+    'application/vnd.shana.informed.package': ['ipk'],
+    'application/vnd.simtech-mindmapper': ['twd', 'twds'],
+    'application/vnd.smaf': ['mmf'],
+    'application/vnd.smart.teacher': ['teacher'],
+    'application/vnd.software602.filler.form+xml': ['fo'],
+    'application/vnd.solent.sdkm+xml': ['sdkm', 'sdkd'],
+    'application/vnd.spotfire.dxp': ['dxp'],
+    'application/vnd.spotfire.sfs': ['sfs'],
+    'application/vnd.stardivision.calc': ['sdc'],
+    'application/vnd.stardivision.draw': ['sda'],
+    'application/vnd.stardivision.impress': ['sdd'],
+    'application/vnd.stardivision.math': ['smf'],
+    'application/vnd.stardivision.writer': ['sdw', 'vor'],
+    'application/vnd.stardivision.writer-global': ['sgl'],
+    'application/vnd.stepmania.package': ['smzip'],
+    'application/vnd.stepmania.stepchart': ['sm'],
+    'application/vnd.sun.wadl+xml': ['wadl'],
+    'application/vnd.sun.xml.calc': ['sxc'],
+    'application/vnd.sun.xml.calc.template': ['stc'],
+    'application/vnd.sun.xml.draw': ['sxd'],
+    'application/vnd.sun.xml.draw.template': ['std'],
+    'application/vnd.sun.xml.impress': ['sxi'],
+    'application/vnd.sun.xml.impress.template': ['sti'],
+    'application/vnd.sun.xml.math': ['sxm'],
+    'application/vnd.sun.xml.writer': ['sxw'],
+    'application/vnd.sun.xml.writer.global': ['sxg'],
+    'application/vnd.sun.xml.writer.template': ['stw'],
+    'application/vnd.sus-calendar': ['sus', 'susp'],
+    'application/vnd.svd': ['svd'],
+    'application/vnd.symbian.install': ['sis', 'sisx'],
+    'application/vnd.syncml+xml': ['xsm'],
+    'application/vnd.syncml.dm+wbxml': ['bdm'],
+    'application/vnd.syncml.dm+xml': ['xdm'],
+    'application/vnd.syncml.dmddf+xml': ['ddf'],
+    'application/vnd.tao.intent-module-archive': ['tao'],
+    'application/vnd.tcpdump.pcap': ['pcap', 'cap', 'dmp'],
+    'application/vnd.tmobile-livetv': ['tmo'],
+    'application/vnd.trid.tpt': ['tpt'],
+    'application/vnd.triscape.mxs': ['mxs'],
+    'application/vnd.trueapp': ['tra'],
+    'application/vnd.ufdl': ['ufd', 'ufdl'],
+    'application/vnd.uiq.theme': ['utz'],
+    'application/vnd.umajin': ['umj'],
+    'application/vnd.unity': ['unityweb'],
+    'application/vnd.uoml+xml': ['uoml', 'uo'],
+    'application/vnd.vcx': ['vcx'],
+    'application/vnd.visio': ['vsd', 'vst', 'vss', 'vsw'],
+    'application/vnd.visionary': ['vis'],
+    'application/vnd.vsf': ['vsf'],
+    'application/vnd.wap.wbxml': ['wbxml'],
+    'application/vnd.wap.wmlc': ['wmlc'],
+    'application/vnd.wap.wmlscriptc': ['wmlsc'],
+    'application/vnd.webturbo': ['wtb'],
+    'application/vnd.wolfram.player': ['nbp'],
+    'application/vnd.wordperfect': ['wpd'],
+    'application/vnd.wqd': ['wqd'],
+    'application/vnd.wt.stf': ['stf'],
+    'application/vnd.xara': ['xar'],
+    'application/vnd.xfdl': ['xfdl'],
+    'application/vnd.yamaha.hv-dic': ['hvd'],
+    'application/vnd.yamaha.hv-script': ['hvs'],
+    'application/vnd.yamaha.hv-voice': ['hvp'],
+    'application/vnd.yamaha.openscoreformat': ['osf'],
+    'application/vnd.yamaha.openscoreformat.osfpvg+xml': ['osfpvg'],
+    'application/vnd.yamaha.smaf-audio': ['saf'],
+    'application/vnd.yamaha.smaf-phrase': ['spf'],
+    'application/vnd.yellowriver-custom-menu': ['cmp'],
+    'application/vnd.zul': ['zir', 'zirz'],
+    'application/vnd.zzazz.deck+xml': ['zaz'],
+    'application/x-7z-compressed': ['7z'],
+    'application/x-abiword': ['abw'],
+    'application/x-ace-compressed': ['ace'],
+    'application/x-apple-diskimage': ['*dmg'],
+    'application/x-arj': ['arj'],
+    'application/x-authorware-bin': ['aab', 'x32', 'u32', 'vox'],
+    'application/x-authorware-map': ['aam'],
+    'application/x-authorware-seg': ['aas'],
+    'application/x-bcpio': ['bcpio'],
+    'application/x-bdoc': ['*bdoc'],
+    'application/x-bittorrent': ['torrent'],
+    'application/x-blorb': ['blb', 'blorb'],
+    'application/x-bzip': ['bz'],
+    'application/x-bzip2': ['bz2', 'boz'],
+    'application/x-cbr': ['cbr', 'cba', 'cbt', 'cbz', 'cb7'],
+    'application/x-cdlink': ['vcd'],
+    'application/x-cfs-compressed': ['cfs'],
+    'application/x-chat': ['chat'],
+    'application/x-chess-pgn': ['pgn'],
+    'application/x-chrome-extension': ['crx'],
+    'application/x-cocoa': ['cco'],
+    'application/x-conference': ['nsc'],
+    'application/x-cpio': ['cpio'],
+    'application/x-csh': ['csh'],
+    'application/x-debian-package': ['*deb', 'udeb'],
+    'application/x-dgc-compressed': ['dgc'],
+    'application/x-director': [
+        'dir',
+        'dcr',
+        'dxr',
+        'cst',
+        'cct',
+        'cxt',
+        'w3d',
+        'fgd',
+        'swa',
+    ],
+    'application/x-doom': ['wad'],
+    'application/x-dtbncx+xml': ['ncx'],
+    'application/x-dtbook+xml': ['dtb'],
+    'application/x-dtbresource+xml': ['res'],
+    'application/x-dvi': ['dvi'],
+    'application/x-envoy': ['evy'],
+    'application/x-eva': ['eva'],
+    'application/x-font-bdf': ['bdf'],
+    'application/x-font-ghostscript': ['gsf'],
+    'application/x-font-linux-psf': ['psf'],
+    'application/x-font-pcf': ['pcf'],
+    'application/x-font-snf': ['snf'],
+    'application/x-font-type1': ['pfa', 'pfb', 'pfm', 'afm'],
+    'application/x-freearc': ['arc'],
+    'application/x-futuresplash': ['spl'],
+    'application/x-gca-compressed': ['gca'],
+    'application/x-glulx': ['ulx'],
+    'application/x-gnumeric': ['gnumeric'],
+    'application/x-gramps-xml': ['gramps'],
+    'application/x-gtar': ['gtar'],
+    'application/x-hdf': ['hdf'],
+    'application/x-httpd-php': ['php'],
+    'application/x-install-instructions': ['install'],
+    'application/x-iso9660-image': ['*iso'],
+    'application/x-iwork-keynote-sffkey': ['*key'],
+    'application/x-iwork-numbers-sffnumbers': ['*numbers'],
+    'application/x-iwork-pages-sffpages': ['*pages'],
+    'application/x-java-archive-diff': ['jardiff'],
+    'application/x-java-jnlp-file': ['jnlp'],
+    'application/x-keepass2': ['kdbx'],
+    'application/x-latex': ['latex'],
+    'application/x-lua-bytecode': ['luac'],
+    'application/x-lzh-compressed': ['lzh', 'lha'],
+    'application/x-makeself': ['run'],
+    'application/x-mie': ['mie'],
+    'application/x-mobipocket-ebook': ['*prc', 'mobi'],
+    'application/x-ms-application': ['application'],
+    'application/x-ms-shortcut': ['lnk'],
+    'application/x-ms-wmd': ['wmd'],
+    'application/x-ms-wmz': ['wmz'],
+    'application/x-ms-xbap': ['xbap'],
+    'application/x-msaccess': ['mdb'],
+    'application/x-msbinder': ['obd'],
+    'application/x-mscardfile': ['crd'],
+    'application/x-msclip': ['clp'],
+    'application/x-msdos-program': ['*exe'],
+    'application/x-msdownload': ['*exe', '*dll', 'com', 'bat', '*msi'],
+    'application/x-msmediaview': ['mvb', 'm13', 'm14'],
+    'application/x-msmetafile': ['*wmf', '*wmz', '*emf', 'emz'],
+    'application/x-msmoney': ['mny'],
+    'application/x-mspublisher': ['pub'],
+    'application/x-msschedule': ['scd'],
+    'application/x-msterminal': ['trm'],
+    'application/x-mswrite': ['wri'],
+    'application/x-netcdf': ['nc', 'cdf'],
+    'application/x-ns-proxy-autoconfig': ['pac'],
+    'application/x-nzb': ['nzb'],
+    'application/x-perl': ['pl', 'pm'],
+    'application/x-pilot': ['*prc', '*pdb'],
+    'application/x-pkcs12': ['p12', 'pfx'],
+    'application/x-pkcs7-certificates': ['p7b', 'spc'],
+    'application/x-pkcs7-certreqresp': ['p7r'],
+    'application/x-rar-compressed': ['*rar'],
+    'application/x-redhat-package-manager': ['rpm'],
+    'application/x-research-info-systems': ['ris'],
+    'application/x-sea': ['sea'],
+    'application/x-sh': ['sh'],
+    'application/x-shar': ['shar'],
+    'application/x-shockwave-flash': ['swf'],
+    'application/x-silverlight-app': ['xap'],
+    'application/x-sql': ['*sql'],
+    'application/x-stuffit': ['sit'],
+    'application/x-stuffitx': ['sitx'],
+    'application/x-subrip': ['srt'],
+    'application/x-sv4cpio': ['sv4cpio'],
+    'application/x-sv4crc': ['sv4crc'],
+    'application/x-t3vm-image': ['t3'],
+    'application/x-tads': ['gam'],
+    'application/x-tar': ['tar'],
+    'application/x-tcl': ['tcl', 'tk'],
+    'application/x-tex': ['tex'],
+    'application/x-tex-tfm': ['tfm'],
+    'application/x-texinfo': ['texinfo', 'texi'],
+    'application/x-tgif': ['*obj'],
+    'application/x-ustar': ['ustar'],
+    'application/x-virtualbox-hdd': ['hdd'],
+    'application/x-virtualbox-ova': ['ova'],
+    'application/x-virtualbox-ovf': ['ovf'],
+    'application/x-virtualbox-vbox': ['vbox'],
+    'application/x-virtualbox-vbox-extpack': ['vbox-extpack'],
+    'application/x-virtualbox-vdi': ['vdi'],
+    'application/x-virtualbox-vhd': ['vhd'],
+    'application/x-virtualbox-vmdk': ['vmdk'],
+    'application/x-wais-source': ['src'],
+    'application/x-web-app-manifest+json': ['webapp'],
+    'application/x-x509-ca-cert': ['der', 'crt', 'pem'],
+    'application/x-xfig': ['fig'],
+    'application/x-xliff+xml': ['*xlf'],
+    'application/x-xpinstall': ['xpi'],
+    'application/x-xz': ['xz'],
+    'application/x-zmachine': ['z1', 'z2', 'z3', 'z4', 'z5', 'z6', 'z7', 'z8'],
+    'audio/vnd.dece.audio': ['uva', 'uvva'],
+    'audio/vnd.digital-winds': ['eol'],
+    'audio/vnd.dra': ['dra'],
+    'audio/vnd.dts': ['dts'],
+    'audio/vnd.dts.hd': ['dtshd'],
+    'audio/vnd.lucent.voice': ['lvp'],
+    'audio/vnd.ms-playready.media.pya': ['pya'],
+    'audio/vnd.nuera.ecelp4800': ['ecelp4800'],
+    'audio/vnd.nuera.ecelp7470': ['ecelp7470'],
+    'audio/vnd.nuera.ecelp9600': ['ecelp9600'],
+    'audio/vnd.rip': ['rip'],
+    'audio/x-aac': ['*aac'],
+    'audio/x-aiff': ['aif', 'aiff', 'aifc'],
+    'audio/x-caf': ['caf'],
+    'audio/x-flac': ['flac'],
+    'audio/x-m4a': ['*m4a'],
+    'audio/x-matroska': ['mka'],
+    'audio/x-mpegurl': ['m3u'],
+    'audio/x-ms-wax': ['wax'],
+    'audio/x-ms-wma': ['wma'],
+    'audio/x-pn-realaudio': ['ram', 'ra'],
+    'audio/x-pn-realaudio-plugin': ['rmp'],
+    'audio/x-realaudio': ['*ra'],
+    'audio/x-wav': ['*wav'],
+    'chemical/x-cdx': ['cdx'],
+    'chemical/x-cif': ['cif'],
+    'chemical/x-cmdf': ['cmdf'],
+    'chemical/x-cml': ['cml'],
+    'chemical/x-csml': ['csml'],
+    'chemical/x-xyz': ['xyz'],
+    'image/prs.btif': ['btif', 'btf'],
+    'image/prs.pti': ['pti'],
+    'image/vnd.adobe.photoshop': ['psd'],
+    'image/vnd.airzip.accelerator.azv': ['azv'],
+    'image/vnd.dece.graphic': ['uvi', 'uvvi', 'uvg', 'uvvg'],
+    'image/vnd.djvu': ['djvu', 'djv'],
+    'image/vnd.dvb.subtitle': ['*sub'],
+    'image/vnd.dwg': ['dwg'],
+    'image/vnd.dxf': ['dxf'],
+    'image/vnd.fastbidsheet': ['fbs'],
+    'image/vnd.fpx': ['fpx'],
+    'image/vnd.fst': ['fst'],
+    'image/vnd.fujixerox.edmics-mmr': ['mmr'],
+    'image/vnd.fujixerox.edmics-rlc': ['rlc'],
+    'image/vnd.microsoft.icon': ['ico'],
+    'image/vnd.ms-dds': ['dds'],
+    'image/vnd.ms-modi': ['mdi'],
+    'image/vnd.ms-photo': ['wdp'],
+    'image/vnd.net-fpx': ['npx'],
+    'image/vnd.pco.b16': ['b16'],
+    'image/vnd.tencent.tap': ['tap'],
+    'image/vnd.valve.source.texture': ['vtf'],
+    'image/vnd.wap.wbmp': ['wbmp'],
+    'image/vnd.xiff': ['xif'],
+    'image/vnd.zbrush.pcx': ['pcx'],
+    'image/x-3ds': ['3ds'],
+    'image/x-cmu-raster': ['ras'],
+    'image/x-cmx': ['cmx'],
+    'image/x-freehand': ['fh', 'fhc', 'fh4', 'fh5', 'fh7'],
+    'image/x-icon': ['*ico'],
+    'image/x-jng': ['jng'],
+    'image/x-mrsid-image': ['sid'],
+    'image/x-ms-bmp': ['*bmp'],
+    'image/x-pcx': ['*pcx'],
+    'image/x-pict': ['pic', 'pct'],
+    'image/x-portable-anymap': ['pnm'],
+    'image/x-portable-bitmap': ['pbm'],
+    'image/x-portable-graymap': ['pgm'],
+    'image/x-portable-pixmap': ['ppm'],
+    'image/x-rgb': ['rgb'],
+    'image/x-tga': ['tga'],
+    'image/x-xbitmap': ['xbm'],
+    'image/x-xpixmap': ['xpm'],
+    'image/x-xwindowdump': ['xwd'],
+    'message/vnd.wfa.wsc': ['wsc'],
+    'model/vnd.bary': ['bary'],
+    'model/vnd.cld': ['cld'],
+    'model/vnd.collada+xml': ['dae'],
+    'model/vnd.dwf': ['dwf'],
+    'model/vnd.gdl': ['gdl'],
+    'model/vnd.gtw': ['gtw'],
+    'model/vnd.mts': ['*mts'],
+    'model/vnd.opengex': ['ogex'],
+    'model/vnd.parasolid.transmit.binary': ['x_b'],
+    'model/vnd.parasolid.transmit.text': ['x_t'],
+    'model/vnd.pytha.pyox': ['pyo', 'pyox'],
+    'model/vnd.sap.vds': ['vds'],
+    'model/vnd.usda': ['usda'],
+    'model/vnd.usdz+zip': ['usdz'],
+    'model/vnd.valve.source.compiled-map': ['bsp'],
+    'model/vnd.vtu': ['vtu'],
+    'text/prs.lines.tag': ['dsc'],
+    'text/vnd.curl': ['curl'],
+    'text/vnd.curl.dcurl': ['dcurl'],
+    'text/vnd.curl.mcurl': ['mcurl'],
+    'text/vnd.curl.scurl': ['scurl'],
+    'text/vnd.dvb.subtitle': ['sub'],
+    'text/vnd.familysearch.gedcom': ['ged'],
+    'text/vnd.fly': ['fly'],
+    'text/vnd.fmi.flexstor': ['flx'],
+    'text/vnd.graphviz': ['gv'],
+    'text/vnd.in3d.3dml': ['3dml'],
+    'text/vnd.in3d.spot': ['spot'],
+    'text/vnd.sun.j2me.app-descriptor': ['jad'],
+    'text/vnd.wap.wml': ['wml'],
+    'text/vnd.wap.wmlscript': ['wmls'],
+    'text/x-asm': ['s', 'asm'],
+    'text/x-c': ['c', 'cc', 'cxx', 'cpp', 'h', 'hh', 'dic'],
+    'text/x-component': ['htc'],
+    'text/x-fortran': ['f', 'for', 'f77', 'f90'],
+    'text/x-handlebars-template': ['hbs'],
+    'text/x-java-source': ['java'],
+    'text/x-lua': ['lua'],
+    'text/x-markdown': ['mkd'],
+    'text/x-nfo': ['nfo'],
+    'text/x-opml': ['opml'],
+    'text/x-org': ['*org'],
+    'text/x-pascal': ['p', 'pas'],
+    'text/x-processing': ['pde'],
+    'text/x-sass': ['sass'],
+    'text/x-scss': ['scss'],
+    'text/x-setext': ['etx'],
+    'text/x-sfv': ['sfv'],
+    'text/x-suse-ymp': ['ymp'],
+    'text/x-uuencode': ['uu'],
+    'text/x-vcalendar': ['vcs'],
+    'text/x-vcard': ['vcf'],
+    'video/vnd.dece.hd': ['uvh', 'uvvh'],
+    'video/vnd.dece.mobile': ['uvm', 'uvvm'],
+    'video/vnd.dece.pd': ['uvp', 'uvvp'],
+    'video/vnd.dece.sd': ['uvs', 'uvvs'],
+    'video/vnd.dece.video': ['uvv', 'uvvv'],
+    'video/vnd.dvb.file': ['dvb'],
+    'video/vnd.fvt': ['fvt'],
+    'video/vnd.mpegurl': ['mxu', 'm4u'],
+    'video/vnd.ms-playready.media.pyv': ['pyv'],
+    'video/vnd.uvvu.mp4': ['uvu', 'uvvu'],
+    'video/vnd.vivo': ['viv'],
+    'video/x-f4v': ['f4v'],
+    'video/x-fli': ['fli'],
+    'video/x-flv': ['flv'],
+    'video/x-m4v': ['m4v'],
+    'video/x-matroska': ['mkv', 'mk3d', 'mks'],
+    'video/x-mng': ['mng'],
+    'video/x-ms-asf': ['asf', 'asx'],
+    'video/x-ms-vob': ['vob'],
+    'video/x-ms-wm': ['wm'],
+    'video/x-ms-wmv': ['wmv'],
+    'video/x-ms-wmx': ['wmx'],
+    'video/x-ms-wvx': ['wvx'],
+    'video/x-msvideo': ['avi'],
+    'video/x-sgi-movie': ['movie'],
+    'video/x-smv': ['smv'],
+    'x-conference/x-cooltalk': ['ice'],
+};
+Object.freeze(types);
+export default types;

+ 4 - 0
fashion-server/migration/js/node_modules/mime/dist/types/standard.d.ts

@@ -0,0 +1,4 @@
+declare const types: {
+    [key: string]: string[];
+};
+export default types;

+ 354 - 0
fashion-server/migration/js/node_modules/mime/dist/types/standard.js

@@ -0,0 +1,354 @@
+const types = {
+    'application/andrew-inset': ['ez'],
+    'application/appinstaller': ['appinstaller'],
+    'application/applixware': ['aw'],
+    'application/appx': ['appx'],
+    'application/appxbundle': ['appxbundle'],
+    'application/atom+xml': ['atom'],
+    'application/atomcat+xml': ['atomcat'],
+    'application/atomdeleted+xml': ['atomdeleted'],
+    'application/atomsvc+xml': ['atomsvc'],
+    'application/atsc-dwd+xml': ['dwd'],
+    'application/atsc-held+xml': ['held'],
+    'application/atsc-rsat+xml': ['rsat'],
+    'application/automationml-aml+xml': ['aml'],
+    'application/automationml-amlx+zip': ['amlx'],
+    'application/bdoc': ['bdoc'],
+    'application/calendar+xml': ['xcs'],
+    'application/ccxml+xml': ['ccxml'],
+    'application/cdfx+xml': ['cdfx'],
+    'application/cdmi-capability': ['cdmia'],
+    'application/cdmi-container': ['cdmic'],
+    'application/cdmi-domain': ['cdmid'],
+    'application/cdmi-object': ['cdmio'],
+    'application/cdmi-queue': ['cdmiq'],
+    'application/cpl+xml': ['cpl'],
+    'application/cu-seeme': ['cu'],
+    'application/cwl': ['cwl'],
+    'application/dash+xml': ['mpd'],
+    'application/dash-patch+xml': ['mpp'],
+    'application/davmount+xml': ['davmount'],
+    'application/docbook+xml': ['dbk'],
+    'application/dssc+der': ['dssc'],
+    'application/dssc+xml': ['xdssc'],
+    'application/ecmascript': ['ecma'],
+    'application/emma+xml': ['emma'],
+    'application/emotionml+xml': ['emotionml'],
+    'application/epub+zip': ['epub'],
+    'application/exi': ['exi'],
+    'application/express': ['exp'],
+    'application/fdf': ['fdf'],
+    'application/fdt+xml': ['fdt'],
+    'application/font-tdpfr': ['pfr'],
+    'application/geo+json': ['geojson'],
+    'application/gml+xml': ['gml'],
+    'application/gpx+xml': ['gpx'],
+    'application/gxf': ['gxf'],
+    'application/gzip': ['gz'],
+    'application/hjson': ['hjson'],
+    'application/hyperstudio': ['stk'],
+    'application/inkml+xml': ['ink', 'inkml'],
+    'application/ipfix': ['ipfix'],
+    'application/its+xml': ['its'],
+    'application/java-archive': ['jar', 'war', 'ear'],
+    'application/java-serialized-object': ['ser'],
+    'application/java-vm': ['class'],
+    'application/javascript': ['*js'],
+    'application/json': ['json', 'map'],
+    'application/json5': ['json5'],
+    'application/jsonml+json': ['jsonml'],
+    'application/ld+json': ['jsonld'],
+    'application/lgr+xml': ['lgr'],
+    'application/lost+xml': ['lostxml'],
+    'application/mac-binhex40': ['hqx'],
+    'application/mac-compactpro': ['cpt'],
+    'application/mads+xml': ['mads'],
+    'application/manifest+json': ['webmanifest'],
+    'application/marc': ['mrc'],
+    'application/marcxml+xml': ['mrcx'],
+    'application/mathematica': ['ma', 'nb', 'mb'],
+    'application/mathml+xml': ['mathml'],
+    'application/mbox': ['mbox'],
+    'application/media-policy-dataset+xml': ['mpf'],
+    'application/mediaservercontrol+xml': ['mscml'],
+    'application/metalink+xml': ['metalink'],
+    'application/metalink4+xml': ['meta4'],
+    'application/mets+xml': ['mets'],
+    'application/mmt-aei+xml': ['maei'],
+    'application/mmt-usd+xml': ['musd'],
+    'application/mods+xml': ['mods'],
+    'application/mp21': ['m21', 'mp21'],
+    'application/mp4': ['*mp4', '*mpg4', 'mp4s', 'm4p'],
+    'application/msix': ['msix'],
+    'application/msixbundle': ['msixbundle'],
+    'application/msword': ['doc', 'dot'],
+    'application/mxf': ['mxf'],
+    'application/n-quads': ['nq'],
+    'application/n-triples': ['nt'],
+    'application/node': ['cjs'],
+    'application/octet-stream': [
+        'bin',
+        'dms',
+        'lrf',
+        'mar',
+        'so',
+        'dist',
+        'distz',
+        'pkg',
+        'bpk',
+        'dump',
+        'elc',
+        'deploy',
+        'exe',
+        'dll',
+        'deb',
+        'dmg',
+        'iso',
+        'img',
+        'msi',
+        'msp',
+        'msm',
+        'buffer',
+    ],
+    'application/oda': ['oda'],
+    'application/oebps-package+xml': ['opf'],
+    'application/ogg': ['ogx'],
+    'application/omdoc+xml': ['omdoc'],
+    'application/onenote': ['onetoc', 'onetoc2', 'onetmp', 'onepkg'],
+    'application/oxps': ['oxps'],
+    'application/p2p-overlay+xml': ['relo'],
+    'application/patch-ops-error+xml': ['xer'],
+    'application/pdf': ['pdf'],
+    'application/pgp-encrypted': ['pgp'],
+    'application/pgp-keys': ['asc'],
+    'application/pgp-signature': ['sig', '*asc'],
+    'application/pics-rules': ['prf'],
+    'application/pkcs10': ['p10'],
+    'application/pkcs7-mime': ['p7m', 'p7c'],
+    'application/pkcs7-signature': ['p7s'],
+    'application/pkcs8': ['p8'],
+    'application/pkix-attr-cert': ['ac'],
+    'application/pkix-cert': ['cer'],
+    'application/pkix-crl': ['crl'],
+    'application/pkix-pkipath': ['pkipath'],
+    'application/pkixcmp': ['pki'],
+    'application/pls+xml': ['pls'],
+    'application/postscript': ['ai', 'eps', 'ps'],
+    'application/provenance+xml': ['provx'],
+    'application/pskc+xml': ['pskcxml'],
+    'application/raml+yaml': ['raml'],
+    'application/rdf+xml': ['rdf', 'owl'],
+    'application/reginfo+xml': ['rif'],
+    'application/relax-ng-compact-syntax': ['rnc'],
+    'application/resource-lists+xml': ['rl'],
+    'application/resource-lists-diff+xml': ['rld'],
+    'application/rls-services+xml': ['rs'],
+    'application/route-apd+xml': ['rapd'],
+    'application/route-s-tsid+xml': ['sls'],
+    'application/route-usd+xml': ['rusd'],
+    'application/rpki-ghostbusters': ['gbr'],
+    'application/rpki-manifest': ['mft'],
+    'application/rpki-roa': ['roa'],
+    'application/rsd+xml': ['rsd'],
+    'application/rss+xml': ['rss'],
+    'application/rtf': ['rtf'],
+    'application/sbml+xml': ['sbml'],
+    'application/scvp-cv-request': ['scq'],
+    'application/scvp-cv-response': ['scs'],
+    'application/scvp-vp-request': ['spq'],
+    'application/scvp-vp-response': ['spp'],
+    'application/sdp': ['sdp'],
+    'application/senml+xml': ['senmlx'],
+    'application/sensml+xml': ['sensmlx'],
+    'application/set-payment-initiation': ['setpay'],
+    'application/set-registration-initiation': ['setreg'],
+    'application/shf+xml': ['shf'],
+    'application/sieve': ['siv', 'sieve'],
+    'application/smil+xml': ['smi', 'smil'],
+    'application/sparql-query': ['rq'],
+    'application/sparql-results+xml': ['srx'],
+    'application/sql': ['sql'],
+    'application/srgs': ['gram'],
+    'application/srgs+xml': ['grxml'],
+    'application/sru+xml': ['sru'],
+    'application/ssdl+xml': ['ssdl'],
+    'application/ssml+xml': ['ssml'],
+    'application/swid+xml': ['swidtag'],
+    'application/tei+xml': ['tei', 'teicorpus'],
+    'application/thraud+xml': ['tfi'],
+    'application/timestamped-data': ['tsd'],
+    'application/toml': ['toml'],
+    'application/trig': ['trig'],
+    'application/ttml+xml': ['ttml'],
+    'application/ubjson': ['ubj'],
+    'application/urc-ressheet+xml': ['rsheet'],
+    'application/urc-targetdesc+xml': ['td'],
+    'application/voicexml+xml': ['vxml'],
+    'application/wasm': ['wasm'],
+    'application/watcherinfo+xml': ['wif'],
+    'application/widget': ['wgt'],
+    'application/winhlp': ['hlp'],
+    'application/wsdl+xml': ['wsdl'],
+    'application/wspolicy+xml': ['wspolicy'],
+    'application/xaml+xml': ['xaml'],
+    'application/xcap-att+xml': ['xav'],
+    'application/xcap-caps+xml': ['xca'],
+    'application/xcap-diff+xml': ['xdf'],
+    'application/xcap-el+xml': ['xel'],
+    'application/xcap-ns+xml': ['xns'],
+    'application/xenc+xml': ['xenc'],
+    'application/xfdf': ['xfdf'],
+    'application/xhtml+xml': ['xhtml', 'xht'],
+    'application/xliff+xml': ['xlf'],
+    'application/xml': ['xml', 'xsl', 'xsd', 'rng'],
+    'application/xml-dtd': ['dtd'],
+    'application/xop+xml': ['xop'],
+    'application/xproc+xml': ['xpl'],
+    'application/xslt+xml': ['*xsl', 'xslt'],
+    'application/xspf+xml': ['xspf'],
+    'application/xv+xml': ['mxml', 'xhvml', 'xvml', 'xvm'],
+    'application/yang': ['yang'],
+    'application/yin+xml': ['yin'],
+    'application/zip': ['zip'],
+    'audio/3gpp': ['*3gpp'],
+    'audio/aac': ['adts', 'aac'],
+    'audio/adpcm': ['adp'],
+    'audio/amr': ['amr'],
+    'audio/basic': ['au', 'snd'],
+    'audio/midi': ['mid', 'midi', 'kar', 'rmi'],
+    'audio/mobile-xmf': ['mxmf'],
+    'audio/mp3': ['*mp3'],
+    'audio/mp4': ['m4a', 'mp4a'],
+    'audio/mpeg': ['mpga', 'mp2', 'mp2a', 'mp3', 'm2a', 'm3a'],
+    'audio/ogg': ['oga', 'ogg', 'spx', 'opus'],
+    'audio/s3m': ['s3m'],
+    'audio/silk': ['sil'],
+    'audio/wav': ['wav'],
+    'audio/wave': ['*wav'],
+    'audio/webm': ['weba'],
+    'audio/xm': ['xm'],
+    'font/collection': ['ttc'],
+    'font/otf': ['otf'],
+    'font/ttf': ['ttf'],
+    'font/woff': ['woff'],
+    'font/woff2': ['woff2'],
+    'image/aces': ['exr'],
+    'image/apng': ['apng'],
+    'image/avci': ['avci'],
+    'image/avcs': ['avcs'],
+    'image/avif': ['avif'],
+    'image/bmp': ['bmp', 'dib'],
+    'image/cgm': ['cgm'],
+    'image/dicom-rle': ['drle'],
+    'image/dpx': ['dpx'],
+    'image/emf': ['emf'],
+    'image/fits': ['fits'],
+    'image/g3fax': ['g3'],
+    'image/gif': ['gif'],
+    'image/heic': ['heic'],
+    'image/heic-sequence': ['heics'],
+    'image/heif': ['heif'],
+    'image/heif-sequence': ['heifs'],
+    'image/hej2k': ['hej2'],
+    'image/hsj2': ['hsj2'],
+    'image/ief': ['ief'],
+    'image/jls': ['jls'],
+    'image/jp2': ['jp2', 'jpg2'],
+    'image/jpeg': ['jpeg', 'jpg', 'jpe'],
+    'image/jph': ['jph'],
+    'image/jphc': ['jhc'],
+    'image/jpm': ['jpm', 'jpgm'],
+    'image/jpx': ['jpx', 'jpf'],
+    'image/jxl': ['jxl'],
+    'image/jxr': ['jxr'],
+    'image/jxra': ['jxra'],
+    'image/jxrs': ['jxrs'],
+    'image/jxs': ['jxs'],
+    'image/jxsc': ['jxsc'],
+    'image/jxsi': ['jxsi'],
+    'image/jxss': ['jxss'],
+    'image/ktx': ['ktx'],
+    'image/ktx2': ['ktx2'],
+    'image/png': ['png'],
+    'image/sgi': ['sgi'],
+    'image/svg+xml': ['svg', 'svgz'],
+    'image/t38': ['t38'],
+    'image/tiff': ['tif', 'tiff'],
+    'image/tiff-fx': ['tfx'],
+    'image/webp': ['webp'],
+    'image/wmf': ['wmf'],
+    'message/disposition-notification': ['disposition-notification'],
+    'message/global': ['u8msg'],
+    'message/global-delivery-status': ['u8dsn'],
+    'message/global-disposition-notification': ['u8mdn'],
+    'message/global-headers': ['u8hdr'],
+    'message/rfc822': ['eml', 'mime'],
+    'model/3mf': ['3mf'],
+    'model/gltf+json': ['gltf'],
+    'model/gltf-binary': ['glb'],
+    'model/iges': ['igs', 'iges'],
+    'model/jt': ['jt'],
+    'model/mesh': ['msh', 'mesh', 'silo'],
+    'model/mtl': ['mtl'],
+    'model/obj': ['obj'],
+    'model/prc': ['prc'],
+    'model/step+xml': ['stpx'],
+    'model/step+zip': ['stpz'],
+    'model/step-xml+zip': ['stpxz'],
+    'model/stl': ['stl'],
+    'model/u3d': ['u3d'],
+    'model/vrml': ['wrl', 'vrml'],
+    'model/x3d+binary': ['*x3db', 'x3dbz'],
+    'model/x3d+fastinfoset': ['x3db'],
+    'model/x3d+vrml': ['*x3dv', 'x3dvz'],
+    'model/x3d+xml': ['x3d', 'x3dz'],
+    'model/x3d-vrml': ['x3dv'],
+    'text/cache-manifest': ['appcache', 'manifest'],
+    'text/calendar': ['ics', 'ifb'],
+    'text/coffeescript': ['coffee', 'litcoffee'],
+    'text/css': ['css'],
+    'text/csv': ['csv'],
+    'text/html': ['html', 'htm', 'shtml'],
+    'text/jade': ['jade'],
+    'text/javascript': ['js', 'mjs'],
+    'text/jsx': ['jsx'],
+    'text/less': ['less'],
+    'text/markdown': ['md', 'markdown'],
+    'text/mathml': ['mml'],
+    'text/mdx': ['mdx'],
+    'text/n3': ['n3'],
+    'text/plain': ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini'],
+    'text/richtext': ['rtx'],
+    'text/rtf': ['*rtf'],
+    'text/sgml': ['sgml', 'sgm'],
+    'text/shex': ['shex'],
+    'text/slim': ['slim', 'slm'],
+    'text/spdx': ['spdx'],
+    'text/stylus': ['stylus', 'styl'],
+    'text/tab-separated-values': ['tsv'],
+    'text/troff': ['t', 'tr', 'roff', 'man', 'me', 'ms'],
+    'text/turtle': ['ttl'],
+    'text/uri-list': ['uri', 'uris', 'urls'],
+    'text/vcard': ['vcard'],
+    'text/vtt': ['vtt'],
+    'text/wgsl': ['wgsl'],
+    'text/xml': ['*xml'],
+    'text/yaml': ['yaml', 'yml'],
+    'video/3gpp': ['3gp', '3gpp'],
+    'video/3gpp2': ['3g2'],
+    'video/h261': ['h261'],
+    'video/h263': ['h263'],
+    'video/h264': ['h264'],
+    'video/iso.segment': ['m4s'],
+    'video/jpeg': ['jpgv'],
+    'video/jpm': ['*jpm', '*jpgm'],
+    'video/mj2': ['mj2', 'mjp2'],
+    'video/mp2t': ['ts', 'm2t', 'm2ts', 'mts'],
+    'video/mp4': ['mp4', 'mp4v', 'mpg4'],
+    'video/mpeg': ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v'],
+    'video/ogg': ['ogv'],
+    'video/quicktime': ['qt', 'mov'],
+    'video/webm': ['webm'],
+};
+Object.freeze(types);
+export default types;

+ 76 - 0
fashion-server/migration/js/node_modules/mime/package.json

@@ -0,0 +1,76 @@
+{
+  "author": {
+    "name": "Robert Kieffer",
+    "url": "http://github.com/broofa",
+    "email": "robert@broofa.com"
+  },
+  "type": "module",
+  "engines": {
+    "node": ">=16"
+  },
+  "main": "./dist/src/index.js",
+  "exports": {
+    ".": "./dist/src/index.js",
+    "./lite": "./dist/src/index_lite.js",
+    "./types/standard.js": "./dist/types/standard.js",
+    "./types/other.js": "./dist/types/other.js",
+    "./package.json": "./package.json"
+  },
+  "files": [
+    "bin",
+    "dist/src",
+    "dist/types",
+    "src",
+    "types"
+  ],
+  "bin": {
+    "mime": "bin/cli.js"
+  },
+  "contributors": [],
+  "description": "A comprehensive library for mime-type mapping",
+  "license": "MIT",
+  "devDependencies": {
+    "@types/mime-db": "1.*",
+    "@types/mime-types": "2.1.4",
+    "@types/node": "22.10.2",
+    "@typescript-eslint/eslint-plugin": "8.18.1",
+    "@typescript-eslint/parser": "8.18.1",
+    "chalk": "5.3.0",
+    "mime-score": "2.0.4",
+    "mime-types": "2.1.35",
+    "prettier": "3.4.2",
+    "release-please": "16.15.0",
+    "runmd": "1.3.9",
+    "typescript": "5.7.2"
+  },
+  "scripts": {
+    "build": "rm -fr dist && tsc",
+    "build:types": "node dist/scripts/build.js",
+    "build:watch": "npm run build -- --watch",
+    "lint": "prettier -c .",
+    "lint:fix": "prettier -w .",
+    "prepack": "npm run build",
+    "pretest": "npm run build",
+    "prepublishOnly": "npm test",
+    "test": "node --test && ./test/exports_test.sh",
+    "test:watch": "clear && node --enable-source-maps --test --watch test"
+  },
+  "keywords": [
+    "extension",
+    "file",
+    "mime",
+    "mime-db",
+    "mimetypes",
+    "util"
+  ],
+  "name": "mime",
+  "repository": {
+    "url": "https://github.com/broofa/mime",
+    "type": "git"
+  },
+  "version": "4.0.6",
+  "funding": [
+    "https://github.com/sponsors/broofa"
+  ],
+  "packageManager": "npm@11.0.0"
+}

+ 137 - 0
fashion-server/migration/js/node_modules/mime/src/Mime.ts

@@ -0,0 +1,137 @@
+type TypeMap = { [key: string]: string[] };
+
+export default class Mime {
+  #extensionToType = new Map<string, string>();
+  #typeToExtension = new Map<string, string>();
+  #typeToExtensions = new Map<string, Set<string>>();
+
+  constructor(...args: TypeMap[]) {
+    for (const arg of args) {
+      this.define(arg);
+    }
+  }
+
+  /**
+   * Define mimetype -> extension mappings.  Each key is a mime-type that maps
+   * to an array of extensions associated with the type.  The first extension is
+   * used as the default extension for the type.
+   *
+   * e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']});
+   *
+   * If a mapping for an extension has already been defined an error will be
+   * thrown unless the `force` argument is set to `true`.
+   *
+   * e.g. mime.define({'audio/wav', ['wav']}, {'audio/x-wav', ['*wav']});
+   */
+  define(typeMap: TypeMap, force = false) {
+    for (let [type, extensions] of Object.entries(typeMap)) {
+      // Lowercase thingz
+      type = type.toLowerCase();
+      extensions = extensions.map((ext) => ext.toLowerCase());
+
+      if (!this.#typeToExtensions.has(type)) {
+        this.#typeToExtensions.set(type, new Set<string>());
+      }
+      const allExtensions = this.#typeToExtensions.get(type);
+
+      let first = true;
+      for (let extension of extensions) {
+        const starred = extension.startsWith('*');
+
+        extension = starred ? extension.slice(1) : extension;
+
+        // Add to list of extensions for the type
+        allExtensions?.add(extension);
+
+        if (first) {
+          // Map type to default extension (first in list)
+          this.#typeToExtension.set(type, extension);
+        }
+        first = false;
+
+        // Starred types are not eligible to be the default extension
+        if (starred) continue;
+
+        // Map extension to type
+        const currentType = this.#extensionToType.get(extension);
+        if (currentType && currentType != type && !force) {
+          throw new Error(
+            `"${type} -> ${extension}" conflicts with "${currentType} -> ${extension}". Pass \`force=true\` to override this definition.`,
+          );
+        }
+        this.#extensionToType.set(extension, type);
+      }
+    }
+
+    return this;
+  }
+
+  /**
+   * Get mime type associated with an extension
+   */
+  getType(path: string) {
+    if (typeof path !== 'string') return null;
+
+    // Remove chars preceeding `/` or `\`
+    const last = path.replace(/^.*[/\\]/, '').toLowerCase();
+
+    // Remove chars preceeding '.'
+    const ext = last.replace(/^.*\./, '').toLowerCase();
+
+    const hasPath = last.length < path.length;
+    const hasDot = ext.length < last.length - 1;
+
+    // Extension-less file?
+    if (!hasDot && hasPath) return null;
+
+    return this.#extensionToType.get(ext) ?? null;
+  }
+
+  /**
+   * Get default file extension associated with a mime type
+   */
+  getExtension(type: string) {
+    if (typeof type !== 'string') return null;
+
+    // Remove http header parameter(s) (specifically, charset)
+    type = type?.split?.(';')[0];
+
+    return (
+      (type && this.#typeToExtension.get(type.trim().toLowerCase())) ?? null
+    );
+  }
+
+  /**
+   * Get all file extensions associated with a mime type
+   */
+  getAllExtensions(type: string) {
+    if (typeof type !== 'string') return null;
+
+    return this.#typeToExtensions.get(type.toLowerCase()) ?? null;
+  }
+
+  //
+  // Private API, for internal use only.  These APIs may change at any time
+  //
+
+  _freeze() {
+    this.define = () => {
+      throw new Error('define() not allowed for built-in Mime objects. See https://github.com/broofa/mime/blob/main/README.md#custom-mime-instances');
+    };
+
+    Object.freeze(this);
+
+    for (const extensions of this.#typeToExtensions.values()) {
+      Object.freeze(extensions);
+    }
+
+    return this;
+  }
+
+  _getTestState() {
+    return {
+      types: this.#extensionToType,
+      extensions: this.#typeToExtension,
+    };
+  }
+}

+ 7 - 0
fashion-server/migration/js/node_modules/mime/src/index.ts

@@ -0,0 +1,7 @@
+import otherTypes from '../types/other.js';
+import standardTypes from '../types/standard.js';
+import Mime from './Mime.js';
+
+export { default as Mime } from './Mime.js';
+
+export default new Mime(standardTypes, otherTypes)._freeze();

+ 6 - 0
fashion-server/migration/js/node_modules/mime/src/index_lite.ts

@@ -0,0 +1,6 @@
+import standardTypes from '../types/standard.js';
+import Mime from './Mime.js';
+
+export { default as Mime } from './Mime.js';
+
+export default new Mime(standardTypes)._freeze();

+ 85 - 0
fashion-server/migration/js/node_modules/mime/src/mime_cli.ts

@@ -0,0 +1,85 @@
+#!/usr/bin/env node
+
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import mime from './index.js';
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+
+export default async function () {
+  process.title = 'mime';
+
+  // TODO: Use json imports to access package.json once "import attributes" are
+  // a real, stable thing.
+  //
+  // See https://github.com/tc39/proposal-import-attributes
+  const json = await fs.readFile(
+    path.join(__dirname, '../../package.json'),
+    'utf-8',
+  );
+  const pkg = JSON.parse(json);
+
+  const args = process.argv.splice(2);
+
+  if (
+    args.includes('--version') ||
+    args.includes('-v') ||
+    args.includes('--v')
+  ) {
+    console.log(pkg.version);
+    process.exit(0);
+  } else if (
+    args.includes('--name') ||
+    args.includes('-n') ||
+    args.includes('--n')
+  ) {
+    console.log(pkg.name);
+    process.exit(0);
+  } else if (
+    args.includes('--help') ||
+    args.includes('-h') ||
+    args.includes('--h')
+  ) {
+    console.log(pkg.name + ' - ' + pkg.description + '\n');
+    console.log(`Usage:
+
+  mime [flags] [path_or_extension]
+
+  Flags:
+    --help, -h                     Show this message
+    --version, -v                  Display the version
+    --name, -n                     Print the name of the program
+    --reverse, -r                  Print the extension of the mime type
+
+  Note: the command will exit after it executes if a command is specified
+  The path_or_extension is the path to the file or the extension of the file.
+
+  Examples:
+    mime --help
+    mime --version
+    mime --name
+    mime -v
+    mime --reverse application/text
+    mime src/log.js
+    mime new.py
+    mime foo.sh
+  `);
+    process.exit(0);
+  } else if (args.includes('--reverse') || args.includes('-r')) {
+    const mimeType = args[args.length - 1];
+    const extension = mime.getExtension(mimeType);
+
+    if (!extension) process.exit(1);
+
+    process.stdout.write(extension + '\n');
+    process.exit(0);
+  }
+
+  const file = args[0];
+  const type = mime.getType(file);
+
+  if (!type) process.exit(1);
+
+  process.stdout.write(type + '\n');
+}

+ 701 - 0
fashion-server/migration/js/node_modules/mime/types/other.ts

@@ -0,0 +1,701 @@
+const types: { [key: string]: string[] } = {
+  'application/prs.cww': ['cww'],
+  'application/prs.xsf+xml': ['xsf'],
+  'application/vnd.1000minds.decision-model+xml': ['1km'],
+  'application/vnd.3gpp.pic-bw-large': ['plb'],
+  'application/vnd.3gpp.pic-bw-small': ['psb'],
+  'application/vnd.3gpp.pic-bw-var': ['pvb'],
+  'application/vnd.3gpp2.tcap': ['tcap'],
+  'application/vnd.3m.post-it-notes': ['pwn'],
+  'application/vnd.accpac.simply.aso': ['aso'],
+  'application/vnd.accpac.simply.imp': ['imp'],
+  'application/vnd.acucobol': ['acu'],
+  'application/vnd.acucorp': ['atc', 'acutc'],
+  'application/vnd.adobe.air-application-installer-package+zip': ['air'],
+  'application/vnd.adobe.formscentral.fcdt': ['fcdt'],
+  'application/vnd.adobe.fxp': ['fxp', 'fxpl'],
+  'application/vnd.adobe.xdp+xml': ['xdp'],
+  'application/vnd.adobe.xfdf': ['*xfdf'],
+  'application/vnd.age': ['age'],
+  'application/vnd.ahead.space': ['ahead'],
+  'application/vnd.airzip.filesecure.azf': ['azf'],
+  'application/vnd.airzip.filesecure.azs': ['azs'],
+  'application/vnd.amazon.ebook': ['azw'],
+  'application/vnd.americandynamics.acc': ['acc'],
+  'application/vnd.amiga.ami': ['ami'],
+  'application/vnd.android.package-archive': ['apk'],
+  'application/vnd.anser-web-certificate-issue-initiation': ['cii'],
+  'application/vnd.anser-web-funds-transfer-initiation': ['fti'],
+  'application/vnd.antix.game-component': ['atx'],
+  'application/vnd.apple.installer+xml': ['mpkg'],
+  'application/vnd.apple.keynote': ['key'],
+  'application/vnd.apple.mpegurl': ['m3u8'],
+  'application/vnd.apple.numbers': ['numbers'],
+  'application/vnd.apple.pages': ['pages'],
+  'application/vnd.apple.pkpass': ['pkpass'],
+  'application/vnd.aristanetworks.swi': ['swi'],
+  'application/vnd.astraea-software.iota': ['iota'],
+  'application/vnd.audiograph': ['aep'],
+  'application/vnd.balsamiq.bmml+xml': ['bmml'],
+  'application/vnd.blueice.multipass': ['mpm'],
+  'application/vnd.bmi': ['bmi'],
+  'application/vnd.businessobjects': ['rep'],
+  'application/vnd.chemdraw+xml': ['cdxml'],
+  'application/vnd.chipnuts.karaoke-mmd': ['mmd'],
+  'application/vnd.cinderella': ['cdy'],
+  'application/vnd.citationstyles.style+xml': ['csl'],
+  'application/vnd.claymore': ['cla'],
+  'application/vnd.cloanto.rp9': ['rp9'],
+  'application/vnd.clonk.c4group': ['c4g', 'c4d', 'c4f', 'c4p', 'c4u'],
+  'application/vnd.cluetrust.cartomobile-config': ['c11amc'],
+  'application/vnd.cluetrust.cartomobile-config-pkg': ['c11amz'],
+  'application/vnd.commonspace': ['csp'],
+  'application/vnd.contact.cmsg': ['cdbcmsg'],
+  'application/vnd.cosmocaller': ['cmc'],
+  'application/vnd.crick.clicker': ['clkx'],
+  'application/vnd.crick.clicker.keyboard': ['clkk'],
+  'application/vnd.crick.clicker.palette': ['clkp'],
+  'application/vnd.crick.clicker.template': ['clkt'],
+  'application/vnd.crick.clicker.wordbank': ['clkw'],
+  'application/vnd.criticaltools.wbs+xml': ['wbs'],
+  'application/vnd.ctc-posml': ['pml'],
+  'application/vnd.cups-ppd': ['ppd'],
+  'application/vnd.curl.car': ['car'],
+  'application/vnd.curl.pcurl': ['pcurl'],
+  'application/vnd.dart': ['dart'],
+  'application/vnd.data-vision.rdz': ['rdz'],
+  'application/vnd.dbf': ['dbf'],
+  'application/vnd.dece.data': ['uvf', 'uvvf', 'uvd', 'uvvd'],
+  'application/vnd.dece.ttml+xml': ['uvt', 'uvvt'],
+  'application/vnd.dece.unspecified': ['uvx', 'uvvx'],
+  'application/vnd.dece.zip': ['uvz', 'uvvz'],
+  'application/vnd.denovo.fcselayout-link': ['fe_launch'],
+  'application/vnd.dna': ['dna'],
+  'application/vnd.dolby.mlp': ['mlp'],
+  'application/vnd.dpgraph': ['dpg'],
+  'application/vnd.dreamfactory': ['dfac'],
+  'application/vnd.ds-keypoint': ['kpxx'],
+  'application/vnd.dvb.ait': ['ait'],
+  'application/vnd.dvb.service': ['svc'],
+  'application/vnd.dynageo': ['geo'],
+  'application/vnd.ecowin.chart': ['mag'],
+  'application/vnd.enliven': ['nml'],
+  'application/vnd.epson.esf': ['esf'],
+  'application/vnd.epson.msf': ['msf'],
+  'application/vnd.epson.quickanime': ['qam'],
+  'application/vnd.epson.salt': ['slt'],
+  'application/vnd.epson.ssf': ['ssf'],
+  'application/vnd.eszigno3+xml': ['es3', 'et3'],
+  'application/vnd.ezpix-album': ['ez2'],
+  'application/vnd.ezpix-package': ['ez3'],
+  'application/vnd.fdf': ['*fdf'],
+  'application/vnd.fdsn.mseed': ['mseed'],
+  'application/vnd.fdsn.seed': ['seed', 'dataless'],
+  'application/vnd.flographit': ['gph'],
+  'application/vnd.fluxtime.clip': ['ftc'],
+  'application/vnd.framemaker': ['fm', 'frame', 'maker', 'book'],
+  'application/vnd.frogans.fnc': ['fnc'],
+  'application/vnd.frogans.ltf': ['ltf'],
+  'application/vnd.fsc.weblaunch': ['fsc'],
+  'application/vnd.fujitsu.oasys': ['oas'],
+  'application/vnd.fujitsu.oasys2': ['oa2'],
+  'application/vnd.fujitsu.oasys3': ['oa3'],
+  'application/vnd.fujitsu.oasysgp': ['fg5'],
+  'application/vnd.fujitsu.oasysprs': ['bh2'],
+  'application/vnd.fujixerox.ddd': ['ddd'],
+  'application/vnd.fujixerox.docuworks': ['xdw'],
+  'application/vnd.fujixerox.docuworks.binder': ['xbd'],
+  'application/vnd.fuzzysheet': ['fzs'],
+  'application/vnd.genomatix.tuxedo': ['txd'],
+  'application/vnd.geogebra.file': ['ggb'],
+  'application/vnd.geogebra.slides': ['ggs'],
+  'application/vnd.geogebra.tool': ['ggt'],
+  'application/vnd.geometry-explorer': ['gex', 'gre'],
+  'application/vnd.geonext': ['gxt'],
+  'application/vnd.geoplan': ['g2w'],
+  'application/vnd.geospace': ['g3w'],
+  'application/vnd.gmx': ['gmx'],
+  'application/vnd.google-apps.document': ['gdoc'],
+  'application/vnd.google-apps.presentation': ['gslides'],
+  'application/vnd.google-apps.spreadsheet': ['gsheet'],
+  'application/vnd.google-earth.kml+xml': ['kml'],
+  'application/vnd.google-earth.kmz': ['kmz'],
+  'application/vnd.gov.sk.xmldatacontainer+xml': ['xdcf'],
+  'application/vnd.grafeq': ['gqf', 'gqs'],
+  'application/vnd.groove-account': ['gac'],
+  'application/vnd.groove-help': ['ghf'],
+  'application/vnd.groove-identity-message': ['gim'],
+  'application/vnd.groove-injector': ['grv'],
+  'application/vnd.groove-tool-message': ['gtm'],
+  'application/vnd.groove-tool-template': ['tpl'],
+  'application/vnd.groove-vcard': ['vcg'],
+  'application/vnd.hal+xml': ['hal'],
+  'application/vnd.handheld-entertainment+xml': ['zmm'],
+  'application/vnd.hbci': ['hbci'],
+  'application/vnd.hhe.lesson-player': ['les'],
+  'application/vnd.hp-hpgl': ['hpgl'],
+  'application/vnd.hp-hpid': ['hpid'],
+  'application/vnd.hp-hps': ['hps'],
+  'application/vnd.hp-jlyt': ['jlt'],
+  'application/vnd.hp-pcl': ['pcl'],
+  'application/vnd.hp-pclxl': ['pclxl'],
+  'application/vnd.hydrostatix.sof-data': ['sfd-hdstx'],
+  'application/vnd.ibm.minipay': ['mpy'],
+  'application/vnd.ibm.modcap': ['afp', 'listafp', 'list3820'],
+  'application/vnd.ibm.rights-management': ['irm'],
+  'application/vnd.ibm.secure-container': ['sc'],
+  'application/vnd.iccprofile': ['icc', 'icm'],
+  'application/vnd.igloader': ['igl'],
+  'application/vnd.immervision-ivp': ['ivp'],
+  'application/vnd.immervision-ivu': ['ivu'],
+  'application/vnd.insors.igm': ['igm'],
+  'application/vnd.intercon.formnet': ['xpw', 'xpx'],
+  'application/vnd.intergeo': ['i2g'],
+  'application/vnd.intu.qbo': ['qbo'],
+  'application/vnd.intu.qfx': ['qfx'],
+  'application/vnd.ipunplugged.rcprofile': ['rcprofile'],
+  'application/vnd.irepository.package+xml': ['irp'],
+  'application/vnd.is-xpr': ['xpr'],
+  'application/vnd.isac.fcs': ['fcs'],
+  'application/vnd.jam': ['jam'],
+  'application/vnd.jcp.javame.midlet-rms': ['rms'],
+  'application/vnd.jisp': ['jisp'],
+  'application/vnd.joost.joda-archive': ['joda'],
+  'application/vnd.kahootz': ['ktz', 'ktr'],
+  'application/vnd.kde.karbon': ['karbon'],
+  'application/vnd.kde.kchart': ['chrt'],
+  'application/vnd.kde.kformula': ['kfo'],
+  'application/vnd.kde.kivio': ['flw'],
+  'application/vnd.kde.kontour': ['kon'],
+  'application/vnd.kde.kpresenter': ['kpr', 'kpt'],
+  'application/vnd.kde.kspread': ['ksp'],
+  'application/vnd.kde.kword': ['kwd', 'kwt'],
+  'application/vnd.kenameaapp': ['htke'],
+  'application/vnd.kidspiration': ['kia'],
+  'application/vnd.kinar': ['kne', 'knp'],
+  'application/vnd.koan': ['skp', 'skd', 'skt', 'skm'],
+  'application/vnd.kodak-descriptor': ['sse'],
+  'application/vnd.las.las+xml': ['lasxml'],
+  'application/vnd.llamagraphics.life-balance.desktop': ['lbd'],
+  'application/vnd.llamagraphics.life-balance.exchange+xml': ['lbe'],
+  'application/vnd.lotus-1-2-3': ['123'],
+  'application/vnd.lotus-approach': ['apr'],
+  'application/vnd.lotus-freelance': ['pre'],
+  'application/vnd.lotus-notes': ['nsf'],
+  'application/vnd.lotus-organizer': ['org'],
+  'application/vnd.lotus-screencam': ['scm'],
+  'application/vnd.lotus-wordpro': ['lwp'],
+  'application/vnd.macports.portpkg': ['portpkg'],
+  'application/vnd.mapbox-vector-tile': ['mvt'],
+  'application/vnd.mcd': ['mcd'],
+  'application/vnd.medcalcdata': ['mc1'],
+  'application/vnd.mediastation.cdkey': ['cdkey'],
+  'application/vnd.mfer': ['mwf'],
+  'application/vnd.mfmp': ['mfm'],
+  'application/vnd.micrografx.flo': ['flo'],
+  'application/vnd.micrografx.igx': ['igx'],
+  'application/vnd.mif': ['mif'],
+  'application/vnd.mobius.daf': ['daf'],
+  'application/vnd.mobius.dis': ['dis'],
+  'application/vnd.mobius.mbk': ['mbk'],
+  'application/vnd.mobius.mqy': ['mqy'],
+  'application/vnd.mobius.msl': ['msl'],
+  'application/vnd.mobius.plc': ['plc'],
+  'application/vnd.mobius.txf': ['txf'],
+  'application/vnd.mophun.application': ['mpn'],
+  'application/vnd.mophun.certificate': ['mpc'],
+  'application/vnd.mozilla.xul+xml': ['xul'],
+  'application/vnd.ms-artgalry': ['cil'],
+  'application/vnd.ms-cab-compressed': ['cab'],
+  'application/vnd.ms-excel': ['xls', 'xlm', 'xla', 'xlc', 'xlt', 'xlw'],
+  'application/vnd.ms-excel.addin.macroenabled.12': ['xlam'],
+  'application/vnd.ms-excel.sheet.binary.macroenabled.12': ['xlsb'],
+  'application/vnd.ms-excel.sheet.macroenabled.12': ['xlsm'],
+  'application/vnd.ms-excel.template.macroenabled.12': ['xltm'],
+  'application/vnd.ms-fontobject': ['eot'],
+  'application/vnd.ms-htmlhelp': ['chm'],
+  'application/vnd.ms-ims': ['ims'],
+  'application/vnd.ms-lrm': ['lrm'],
+  'application/vnd.ms-officetheme': ['thmx'],
+  'application/vnd.ms-outlook': ['msg'],
+  'application/vnd.ms-pki.seccat': ['cat'],
+  'application/vnd.ms-pki.stl': ['*stl'],
+  'application/vnd.ms-powerpoint': ['ppt', 'pps', 'pot'],
+  'application/vnd.ms-powerpoint.addin.macroenabled.12': ['ppam'],
+  'application/vnd.ms-powerpoint.presentation.macroenabled.12': ['pptm'],
+  'application/vnd.ms-powerpoint.slide.macroenabled.12': ['sldm'],
+  'application/vnd.ms-powerpoint.slideshow.macroenabled.12': ['ppsm'],
+  'application/vnd.ms-powerpoint.template.macroenabled.12': ['potm'],
+  'application/vnd.ms-project': ['*mpp', 'mpt'],
+  'application/vnd.ms-word.document.macroenabled.12': ['docm'],
+  'application/vnd.ms-word.template.macroenabled.12': ['dotm'],
+  'application/vnd.ms-works': ['wps', 'wks', 'wcm', 'wdb'],
+  'application/vnd.ms-wpl': ['wpl'],
+  'application/vnd.ms-xpsdocument': ['xps'],
+  'application/vnd.mseq': ['mseq'],
+  'application/vnd.musician': ['mus'],
+  'application/vnd.muvee.style': ['msty'],
+  'application/vnd.mynfc': ['taglet'],
+  'application/vnd.nato.bindingdataobject+xml': ['bdo'],
+  'application/vnd.neurolanguage.nlu': ['nlu'],
+  'application/vnd.nitf': ['ntf', 'nitf'],
+  'application/vnd.noblenet-directory': ['nnd'],
+  'application/vnd.noblenet-sealer': ['nns'],
+  'application/vnd.noblenet-web': ['nnw'],
+  'application/vnd.nokia.n-gage.ac+xml': ['*ac'],
+  'application/vnd.nokia.n-gage.data': ['ngdat'],
+  'application/vnd.nokia.n-gage.symbian.install': ['n-gage'],
+  'application/vnd.nokia.radio-preset': ['rpst'],
+  'application/vnd.nokia.radio-presets': ['rpss'],
+  'application/vnd.novadigm.edm': ['edm'],
+  'application/vnd.novadigm.edx': ['edx'],
+  'application/vnd.novadigm.ext': ['ext'],
+  'application/vnd.oasis.opendocument.chart': ['odc'],
+  'application/vnd.oasis.opendocument.chart-template': ['otc'],
+  'application/vnd.oasis.opendocument.database': ['odb'],
+  'application/vnd.oasis.opendocument.formula': ['odf'],
+  'application/vnd.oasis.opendocument.formula-template': ['odft'],
+  'application/vnd.oasis.opendocument.graphics': ['odg'],
+  'application/vnd.oasis.opendocument.graphics-template': ['otg'],
+  'application/vnd.oasis.opendocument.image': ['odi'],
+  'application/vnd.oasis.opendocument.image-template': ['oti'],
+  'application/vnd.oasis.opendocument.presentation': ['odp'],
+  'application/vnd.oasis.opendocument.presentation-template': ['otp'],
+  'application/vnd.oasis.opendocument.spreadsheet': ['ods'],
+  'application/vnd.oasis.opendocument.spreadsheet-template': ['ots'],
+  'application/vnd.oasis.opendocument.text': ['odt'],
+  'application/vnd.oasis.opendocument.text-master': ['odm'],
+  'application/vnd.oasis.opendocument.text-template': ['ott'],
+  'application/vnd.oasis.opendocument.text-web': ['oth'],
+  'application/vnd.olpc-sugar': ['xo'],
+  'application/vnd.oma.dd2+xml': ['dd2'],
+  'application/vnd.openblox.game+xml': ['obgx'],
+  'application/vnd.openofficeorg.extension': ['oxt'],
+  'application/vnd.openstreetmap.data+xml': ['osm'],
+  'application/vnd.openxmlformats-officedocument.presentationml.presentation': [
+    'pptx',
+  ],
+  'application/vnd.openxmlformats-officedocument.presentationml.slide': [
+    'sldx',
+  ],
+  'application/vnd.openxmlformats-officedocument.presentationml.slideshow': [
+    'ppsx',
+  ],
+  'application/vnd.openxmlformats-officedocument.presentationml.template': [
+    'potx',
+  ],
+  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['xlsx'],
+  'application/vnd.openxmlformats-officedocument.spreadsheetml.template': [
+    'xltx',
+  ],
+  'application/vnd.openxmlformats-officedocument.wordprocessingml.document': [
+    'docx',
+  ],
+  'application/vnd.openxmlformats-officedocument.wordprocessingml.template': [
+    'dotx',
+  ],
+  'application/vnd.osgeo.mapguide.package': ['mgp'],
+  'application/vnd.osgi.dp': ['dp'],
+  'application/vnd.osgi.subsystem': ['esa'],
+  'application/vnd.palm': ['pdb', 'pqa', 'oprc'],
+  'application/vnd.pawaafile': ['paw'],
+  'application/vnd.pg.format': ['str'],
+  'application/vnd.pg.osasli': ['ei6'],
+  'application/vnd.picsel': ['efif'],
+  'application/vnd.pmi.widget': ['wg'],
+  'application/vnd.pocketlearn': ['plf'],
+  'application/vnd.powerbuilder6': ['pbd'],
+  'application/vnd.previewsystems.box': ['box'],
+  'application/vnd.proteus.magazine': ['mgz'],
+  'application/vnd.publishare-delta-tree': ['qps'],
+  'application/vnd.pvi.ptid1': ['ptid'],
+  'application/vnd.pwg-xhtml-print+xml': ['xhtm'],
+  'application/vnd.quark.quarkxpress': [
+    'qxd',
+    'qxt',
+    'qwd',
+    'qwt',
+    'qxl',
+    'qxb',
+  ],
+  'application/vnd.rar': ['rar'],
+  'application/vnd.realvnc.bed': ['bed'],
+  'application/vnd.recordare.musicxml': ['mxl'],
+  'application/vnd.recordare.musicxml+xml': ['musicxml'],
+  'application/vnd.rig.cryptonote': ['cryptonote'],
+  'application/vnd.rim.cod': ['cod'],
+  'application/vnd.rn-realmedia': ['rm'],
+  'application/vnd.rn-realmedia-vbr': ['rmvb'],
+  'application/vnd.route66.link66+xml': ['link66'],
+  'application/vnd.sailingtracker.track': ['st'],
+  'application/vnd.seemail': ['see'],
+  'application/vnd.sema': ['sema'],
+  'application/vnd.semd': ['semd'],
+  'application/vnd.semf': ['semf'],
+  'application/vnd.shana.informed.formdata': ['ifm'],
+  'application/vnd.shana.informed.formtemplate': ['itp'],
+  'application/vnd.shana.informed.interchange': ['iif'],
+  'application/vnd.shana.informed.package': ['ipk'],
+  'application/vnd.simtech-mindmapper': ['twd', 'twds'],
+  'application/vnd.smaf': ['mmf'],
+  'application/vnd.smart.teacher': ['teacher'],
+  'application/vnd.software602.filler.form+xml': ['fo'],
+  'application/vnd.solent.sdkm+xml': ['sdkm', 'sdkd'],
+  'application/vnd.spotfire.dxp': ['dxp'],
+  'application/vnd.spotfire.sfs': ['sfs'],
+  'application/vnd.stardivision.calc': ['sdc'],
+  'application/vnd.stardivision.draw': ['sda'],
+  'application/vnd.stardivision.impress': ['sdd'],
+  'application/vnd.stardivision.math': ['smf'],
+  'application/vnd.stardivision.writer': ['sdw', 'vor'],
+  'application/vnd.stardivision.writer-global': ['sgl'],
+  'application/vnd.stepmania.package': ['smzip'],
+  'application/vnd.stepmania.stepchart': ['sm'],
+  'application/vnd.sun.wadl+xml': ['wadl'],
+  'application/vnd.sun.xml.calc': ['sxc'],
+  'application/vnd.sun.xml.calc.template': ['stc'],
+  'application/vnd.sun.xml.draw': ['sxd'],
+  'application/vnd.sun.xml.draw.template': ['std'],
+  'application/vnd.sun.xml.impress': ['sxi'],
+  'application/vnd.sun.xml.impress.template': ['sti'],
+  'application/vnd.sun.xml.math': ['sxm'],
+  'application/vnd.sun.xml.writer': ['sxw'],
+  'application/vnd.sun.xml.writer.global': ['sxg'],
+  'application/vnd.sun.xml.writer.template': ['stw'],
+  'application/vnd.sus-calendar': ['sus', 'susp'],
+  'application/vnd.svd': ['svd'],
+  'application/vnd.symbian.install': ['sis', 'sisx'],
+  'application/vnd.syncml+xml': ['xsm'],
+  'application/vnd.syncml.dm+wbxml': ['bdm'],
+  'application/vnd.syncml.dm+xml': ['xdm'],
+  'application/vnd.syncml.dmddf+xml': ['ddf'],
+  'application/vnd.tao.intent-module-archive': ['tao'],
+  'application/vnd.tcpdump.pcap': ['pcap', 'cap', 'dmp'],
+  'application/vnd.tmobile-livetv': ['tmo'],
+  'application/vnd.trid.tpt': ['tpt'],
+  'application/vnd.triscape.mxs': ['mxs'],
+  'application/vnd.trueapp': ['tra'],
+  'application/vnd.ufdl': ['ufd', 'ufdl'],
+  'application/vnd.uiq.theme': ['utz'],
+  'application/vnd.umajin': ['umj'],
+  'application/vnd.unity': ['unityweb'],
+  'application/vnd.uoml+xml': ['uoml', 'uo'],
+  'application/vnd.vcx': ['vcx'],
+  'application/vnd.visio': ['vsd', 'vst', 'vss', 'vsw'],
+  'application/vnd.visionary': ['vis'],
+  'application/vnd.vsf': ['vsf'],
+  'application/vnd.wap.wbxml': ['wbxml'],
+  'application/vnd.wap.wmlc': ['wmlc'],
+  'application/vnd.wap.wmlscriptc': ['wmlsc'],
+  'application/vnd.webturbo': ['wtb'],
+  'application/vnd.wolfram.player': ['nbp'],
+  'application/vnd.wordperfect': ['wpd'],
+  'application/vnd.wqd': ['wqd'],
+  'application/vnd.wt.stf': ['stf'],
+  'application/vnd.xara': ['xar'],
+  'application/vnd.xfdl': ['xfdl'],
+  'application/vnd.yamaha.hv-dic': ['hvd'],
+  'application/vnd.yamaha.hv-script': ['hvs'],
+  'application/vnd.yamaha.hv-voice': ['hvp'],
+  'application/vnd.yamaha.openscoreformat': ['osf'],
+  'application/vnd.yamaha.openscoreformat.osfpvg+xml': ['osfpvg'],
+  'application/vnd.yamaha.smaf-audio': ['saf'],
+  'application/vnd.yamaha.smaf-phrase': ['spf'],
+  'application/vnd.yellowriver-custom-menu': ['cmp'],
+  'application/vnd.zul': ['zir', 'zirz'],
+  'application/vnd.zzazz.deck+xml': ['zaz'],
+  'application/x-7z-compressed': ['7z'],
+  'application/x-abiword': ['abw'],
+  'application/x-ace-compressed': ['ace'],
+  'application/x-apple-diskimage': ['*dmg'],
+  'application/x-arj': ['arj'],
+  'application/x-authorware-bin': ['aab', 'x32', 'u32', 'vox'],
+  'application/x-authorware-map': ['aam'],
+  'application/x-authorware-seg': ['aas'],
+  'application/x-bcpio': ['bcpio'],
+  'application/x-bdoc': ['*bdoc'],
+  'application/x-bittorrent': ['torrent'],
+  'application/x-blorb': ['blb', 'blorb'],
+  'application/x-bzip': ['bz'],
+  'application/x-bzip2': ['bz2', 'boz'],
+  'application/x-cbr': ['cbr', 'cba', 'cbt', 'cbz', 'cb7'],
+  'application/x-cdlink': ['vcd'],
+  'application/x-cfs-compressed': ['cfs'],
+  'application/x-chat': ['chat'],
+  'application/x-chess-pgn': ['pgn'],
+  'application/x-chrome-extension': ['crx'],
+  'application/x-cocoa': ['cco'],
+  'application/x-conference': ['nsc'],
+  'application/x-cpio': ['cpio'],
+  'application/x-csh': ['csh'],
+  'application/x-debian-package': ['*deb', 'udeb'],
+  'application/x-dgc-compressed': ['dgc'],
+  'application/x-director': [
+    'dir',
+    'dcr',
+    'dxr',
+    'cst',
+    'cct',
+    'cxt',
+    'w3d',
+    'fgd',
+    'swa',
+  ],
+  'application/x-doom': ['wad'],
+  'application/x-dtbncx+xml': ['ncx'],
+  'application/x-dtbook+xml': ['dtb'],
+  'application/x-dtbresource+xml': ['res'],
+  'application/x-dvi': ['dvi'],
+  'application/x-envoy': ['evy'],
+  'application/x-eva': ['eva'],
+  'application/x-font-bdf': ['bdf'],
+  'application/x-font-ghostscript': ['gsf'],
+  'application/x-font-linux-psf': ['psf'],
+  'application/x-font-pcf': ['pcf'],
+  'application/x-font-snf': ['snf'],
+  'application/x-font-type1': ['pfa', 'pfb', 'pfm', 'afm'],
+  'application/x-freearc': ['arc'],
+  'application/x-futuresplash': ['spl'],
+  'application/x-gca-compressed': ['gca'],
+  'application/x-glulx': ['ulx'],
+  'application/x-gnumeric': ['gnumeric'],
+  'application/x-gramps-xml': ['gramps'],
+  'application/x-gtar': ['gtar'],
+  'application/x-hdf': ['hdf'],
+  'application/x-httpd-php': ['php'],
+  'application/x-install-instructions': ['install'],
+  'application/x-iso9660-image': ['*iso'],
+  'application/x-iwork-keynote-sffkey': ['*key'],
+  'application/x-iwork-numbers-sffnumbers': ['*numbers'],
+  'application/x-iwork-pages-sffpages': ['*pages'],
+  'application/x-java-archive-diff': ['jardiff'],
+  'application/x-java-jnlp-file': ['jnlp'],
+  'application/x-keepass2': ['kdbx'],
+  'application/x-latex': ['latex'],
+  'application/x-lua-bytecode': ['luac'],
+  'application/x-lzh-compressed': ['lzh', 'lha'],
+  'application/x-makeself': ['run'],
+  'application/x-mie': ['mie'],
+  'application/x-mobipocket-ebook': ['*prc', 'mobi'],
+  'application/x-ms-application': ['application'],
+  'application/x-ms-shortcut': ['lnk'],
+  'application/x-ms-wmd': ['wmd'],
+  'application/x-ms-wmz': ['wmz'],
+  'application/x-ms-xbap': ['xbap'],
+  'application/x-msaccess': ['mdb'],
+  'application/x-msbinder': ['obd'],
+  'application/x-mscardfile': ['crd'],
+  'application/x-msclip': ['clp'],
+  'application/x-msdos-program': ['*exe'],
+  'application/x-msdownload': ['*exe', '*dll', 'com', 'bat', '*msi'],
+  'application/x-msmediaview': ['mvb', 'm13', 'm14'],
+  'application/x-msmetafile': ['*wmf', '*wmz', '*emf', 'emz'],
+  'application/x-msmoney': ['mny'],
+  'application/x-mspublisher': ['pub'],
+  'application/x-msschedule': ['scd'],
+  'application/x-msterminal': ['trm'],
+  'application/x-mswrite': ['wri'],
+  'application/x-netcdf': ['nc', 'cdf'],
+  'application/x-ns-proxy-autoconfig': ['pac'],
+  'application/x-nzb': ['nzb'],
+  'application/x-perl': ['pl', 'pm'],
+  'application/x-pilot': ['*prc', '*pdb'],
+  'application/x-pkcs12': ['p12', 'pfx'],
+  'application/x-pkcs7-certificates': ['p7b', 'spc'],
+  'application/x-pkcs7-certreqresp': ['p7r'],
+  'application/x-rar-compressed': ['*rar'],
+  'application/x-redhat-package-manager': ['rpm'],
+  'application/x-research-info-systems': ['ris'],
+  'application/x-sea': ['sea'],
+  'application/x-sh': ['sh'],
+  'application/x-shar': ['shar'],
+  'application/x-shockwave-flash': ['swf'],
+  'application/x-silverlight-app': ['xap'],
+  'application/x-sql': ['*sql'],
+  'application/x-stuffit': ['sit'],
+  'application/x-stuffitx': ['sitx'],
+  'application/x-subrip': ['srt'],
+  'application/x-sv4cpio': ['sv4cpio'],
+  'application/x-sv4crc': ['sv4crc'],
+  'application/x-t3vm-image': ['t3'],
+  'application/x-tads': ['gam'],
+  'application/x-tar': ['tar'],
+  'application/x-tcl': ['tcl', 'tk'],
+  'application/x-tex': ['tex'],
+  'application/x-tex-tfm': ['tfm'],
+  'application/x-texinfo': ['texinfo', 'texi'],
+  'application/x-tgif': ['*obj'],
+  'application/x-ustar': ['ustar'],
+  'application/x-virtualbox-hdd': ['hdd'],
+  'application/x-virtualbox-ova': ['ova'],
+  'application/x-virtualbox-ovf': ['ovf'],
+  'application/x-virtualbox-vbox': ['vbox'],
+  'application/x-virtualbox-vbox-extpack': ['vbox-extpack'],
+  'application/x-virtualbox-vdi': ['vdi'],
+  'application/x-virtualbox-vhd': ['vhd'],
+  'application/x-virtualbox-vmdk': ['vmdk'],
+  'application/x-wais-source': ['src'],
+  'application/x-web-app-manifest+json': ['webapp'],
+  'application/x-x509-ca-cert': ['der', 'crt', 'pem'],
+  'application/x-xfig': ['fig'],
+  'application/x-xliff+xml': ['*xlf'],
+  'application/x-xpinstall': ['xpi'],
+  'application/x-xz': ['xz'],
+  'application/x-zmachine': ['z1', 'z2', 'z3', 'z4', 'z5', 'z6', 'z7', 'z8'],
+  'audio/vnd.dece.audio': ['uva', 'uvva'],
+  'audio/vnd.digital-winds': ['eol'],
+  'audio/vnd.dra': ['dra'],
+  'audio/vnd.dts': ['dts'],
+  'audio/vnd.dts.hd': ['dtshd'],
+  'audio/vnd.lucent.voice': ['lvp'],
+  'audio/vnd.ms-playready.media.pya': ['pya'],
+  'audio/vnd.nuera.ecelp4800': ['ecelp4800'],
+  'audio/vnd.nuera.ecelp7470': ['ecelp7470'],
+  'audio/vnd.nuera.ecelp9600': ['ecelp9600'],
+  'audio/vnd.rip': ['rip'],
+  'audio/x-aac': ['*aac'],
+  'audio/x-aiff': ['aif', 'aiff', 'aifc'],
+  'audio/x-caf': ['caf'],
+  'audio/x-flac': ['flac'],
+  'audio/x-m4a': ['*m4a'],
+  'audio/x-matroska': ['mka'],
+  'audio/x-mpegurl': ['m3u'],
+  'audio/x-ms-wax': ['wax'],
+  'audio/x-ms-wma': ['wma'],
+  'audio/x-pn-realaudio': ['ram', 'ra'],
+  'audio/x-pn-realaudio-plugin': ['rmp'],
+  'audio/x-realaudio': ['*ra'],
+  'audio/x-wav': ['*wav'],
+  'chemical/x-cdx': ['cdx'],
+  'chemical/x-cif': ['cif'],
+  'chemical/x-cmdf': ['cmdf'],
+  'chemical/x-cml': ['cml'],
+  'chemical/x-csml': ['csml'],
+  'chemical/x-xyz': ['xyz'],
+  'image/prs.btif': ['btif', 'btf'],
+  'image/prs.pti': ['pti'],
+  'image/vnd.adobe.photoshop': ['psd'],
+  'image/vnd.airzip.accelerator.azv': ['azv'],
+  'image/vnd.dece.graphic': ['uvi', 'uvvi', 'uvg', 'uvvg'],
+  'image/vnd.djvu': ['djvu', 'djv'],
+  'image/vnd.dvb.subtitle': ['*sub'],
+  'image/vnd.dwg': ['dwg'],
+  'image/vnd.dxf': ['dxf'],
+  'image/vnd.fastbidsheet': ['fbs'],
+  'image/vnd.fpx': ['fpx'],
+  'image/vnd.fst': ['fst'],
+  'image/vnd.fujixerox.edmics-mmr': ['mmr'],
+  'image/vnd.fujixerox.edmics-rlc': ['rlc'],
+  'image/vnd.microsoft.icon': ['ico'],
+  'image/vnd.ms-dds': ['dds'],
+  'image/vnd.ms-modi': ['mdi'],
+  'image/vnd.ms-photo': ['wdp'],
+  'image/vnd.net-fpx': ['npx'],
+  'image/vnd.pco.b16': ['b16'],
+  'image/vnd.tencent.tap': ['tap'],
+  'image/vnd.valve.source.texture': ['vtf'],
+  'image/vnd.wap.wbmp': ['wbmp'],
+  'image/vnd.xiff': ['xif'],
+  'image/vnd.zbrush.pcx': ['pcx'],
+  'image/x-3ds': ['3ds'],
+  'image/x-cmu-raster': ['ras'],
+  'image/x-cmx': ['cmx'],
+  'image/x-freehand': ['fh', 'fhc', 'fh4', 'fh5', 'fh7'],
+  'image/x-icon': ['*ico'],
+  'image/x-jng': ['jng'],
+  'image/x-mrsid-image': ['sid'],
+  'image/x-ms-bmp': ['*bmp'],
+  'image/x-pcx': ['*pcx'],
+  'image/x-pict': ['pic', 'pct'],
+  'image/x-portable-anymap': ['pnm'],
+  'image/x-portable-bitmap': ['pbm'],
+  'image/x-portable-graymap': ['pgm'],
+  'image/x-portable-pixmap': ['ppm'],
+  'image/x-rgb': ['rgb'],
+  'image/x-tga': ['tga'],
+  'image/x-xbitmap': ['xbm'],
+  'image/x-xpixmap': ['xpm'],
+  'image/x-xwindowdump': ['xwd'],
+  'message/vnd.wfa.wsc': ['wsc'],
+  'model/vnd.bary': ['bary'],
+  'model/vnd.cld': ['cld'],
+  'model/vnd.collada+xml': ['dae'],
+  'model/vnd.dwf': ['dwf'],
+  'model/vnd.gdl': ['gdl'],
+  'model/vnd.gtw': ['gtw'],
+  'model/vnd.mts': ['*mts'],
+  'model/vnd.opengex': ['ogex'],
+  'model/vnd.parasolid.transmit.binary': ['x_b'],
+  'model/vnd.parasolid.transmit.text': ['x_t'],
+  'model/vnd.pytha.pyox': ['pyo', 'pyox'],
+  'model/vnd.sap.vds': ['vds'],
+  'model/vnd.usda': ['usda'],
+  'model/vnd.usdz+zip': ['usdz'],
+  'model/vnd.valve.source.compiled-map': ['bsp'],
+  'model/vnd.vtu': ['vtu'],
+  'text/prs.lines.tag': ['dsc'],
+  'text/vnd.curl': ['curl'],
+  'text/vnd.curl.dcurl': ['dcurl'],
+  'text/vnd.curl.mcurl': ['mcurl'],
+  'text/vnd.curl.scurl': ['scurl'],
+  'text/vnd.dvb.subtitle': ['sub'],
+  'text/vnd.familysearch.gedcom': ['ged'],
+  'text/vnd.fly': ['fly'],
+  'text/vnd.fmi.flexstor': ['flx'],
+  'text/vnd.graphviz': ['gv'],
+  'text/vnd.in3d.3dml': ['3dml'],
+  'text/vnd.in3d.spot': ['spot'],
+  'text/vnd.sun.j2me.app-descriptor': ['jad'],
+  'text/vnd.wap.wml': ['wml'],
+  'text/vnd.wap.wmlscript': ['wmls'],
+  'text/x-asm': ['s', 'asm'],
+  'text/x-c': ['c', 'cc', 'cxx', 'cpp', 'h', 'hh', 'dic'],
+  'text/x-component': ['htc'],
+  'text/x-fortran': ['f', 'for', 'f77', 'f90'],
+  'text/x-handlebars-template': ['hbs'],
+  'text/x-java-source': ['java'],
+  'text/x-lua': ['lua'],
+  'text/x-markdown': ['mkd'],
+  'text/x-nfo': ['nfo'],
+  'text/x-opml': ['opml'],
+  'text/x-org': ['*org'],
+  'text/x-pascal': ['p', 'pas'],
+  'text/x-processing': ['pde'],
+  'text/x-sass': ['sass'],
+  'text/x-scss': ['scss'],
+  'text/x-setext': ['etx'],
+  'text/x-sfv': ['sfv'],
+  'text/x-suse-ymp': ['ymp'],
+  'text/x-uuencode': ['uu'],
+  'text/x-vcalendar': ['vcs'],
+  'text/x-vcard': ['vcf'],
+  'video/vnd.dece.hd': ['uvh', 'uvvh'],
+  'video/vnd.dece.mobile': ['uvm', 'uvvm'],
+  'video/vnd.dece.pd': ['uvp', 'uvvp'],
+  'video/vnd.dece.sd': ['uvs', 'uvvs'],
+  'video/vnd.dece.video': ['uvv', 'uvvv'],
+  'video/vnd.dvb.file': ['dvb'],
+  'video/vnd.fvt': ['fvt'],
+  'video/vnd.mpegurl': ['mxu', 'm4u'],
+  'video/vnd.ms-playready.media.pyv': ['pyv'],
+  'video/vnd.uvvu.mp4': ['uvu', 'uvvu'],
+  'video/vnd.vivo': ['viv'],
+  'video/x-f4v': ['f4v'],
+  'video/x-fli': ['fli'],
+  'video/x-flv': ['flv'],
+  'video/x-m4v': ['m4v'],
+  'video/x-matroska': ['mkv', 'mk3d', 'mks'],
+  'video/x-mng': ['mng'],
+  'video/x-ms-asf': ['asf', 'asx'],
+  'video/x-ms-vob': ['vob'],
+  'video/x-ms-wm': ['wm'],
+  'video/x-ms-wmv': ['wmv'],
+  'video/x-ms-wmx': ['wmx'],
+  'video/x-ms-wvx': ['wvx'],
+  'video/x-msvideo': ['avi'],
+  'video/x-sgi-movie': ['movie'],
+  'video/x-smv': ['smv'],
+  'x-conference/x-cooltalk': ['ice'],
+};
+Object.freeze(types);
+export default types;

+ 354 - 0
fashion-server/migration/js/node_modules/mime/types/standard.ts

@@ -0,0 +1,354 @@
+const types: { [key: string]: string[] } = {
+  'application/andrew-inset': ['ez'],
+  'application/appinstaller': ['appinstaller'],
+  'application/applixware': ['aw'],
+  'application/appx': ['appx'],
+  'application/appxbundle': ['appxbundle'],
+  'application/atom+xml': ['atom'],
+  'application/atomcat+xml': ['atomcat'],
+  'application/atomdeleted+xml': ['atomdeleted'],
+  'application/atomsvc+xml': ['atomsvc'],
+  'application/atsc-dwd+xml': ['dwd'],
+  'application/atsc-held+xml': ['held'],
+  'application/atsc-rsat+xml': ['rsat'],
+  'application/automationml-aml+xml': ['aml'],
+  'application/automationml-amlx+zip': ['amlx'],
+  'application/bdoc': ['bdoc'],
+  'application/calendar+xml': ['xcs'],
+  'application/ccxml+xml': ['ccxml'],
+  'application/cdfx+xml': ['cdfx'],
+  'application/cdmi-capability': ['cdmia'],
+  'application/cdmi-container': ['cdmic'],
+  'application/cdmi-domain': ['cdmid'],
+  'application/cdmi-object': ['cdmio'],
+  'application/cdmi-queue': ['cdmiq'],
+  'application/cpl+xml': ['cpl'],
+  'application/cu-seeme': ['cu'],
+  'application/cwl': ['cwl'],
+  'application/dash+xml': ['mpd'],
+  'application/dash-patch+xml': ['mpp'],
+  'application/davmount+xml': ['davmount'],
+  'application/docbook+xml': ['dbk'],
+  'application/dssc+der': ['dssc'],
+  'application/dssc+xml': ['xdssc'],
+  'application/ecmascript': ['ecma'],
+  'application/emma+xml': ['emma'],
+  'application/emotionml+xml': ['emotionml'],
+  'application/epub+zip': ['epub'],
+  'application/exi': ['exi'],
+  'application/express': ['exp'],
+  'application/fdf': ['fdf'],
+  'application/fdt+xml': ['fdt'],
+  'application/font-tdpfr': ['pfr'],
+  'application/geo+json': ['geojson'],
+  'application/gml+xml': ['gml'],
+  'application/gpx+xml': ['gpx'],
+  'application/gxf': ['gxf'],
+  'application/gzip': ['gz'],
+  'application/hjson': ['hjson'],
+  'application/hyperstudio': ['stk'],
+  'application/inkml+xml': ['ink', 'inkml'],
+  'application/ipfix': ['ipfix'],
+  'application/its+xml': ['its'],
+  'application/java-archive': ['jar', 'war', 'ear'],
+  'application/java-serialized-object': ['ser'],
+  'application/java-vm': ['class'],
+  'application/javascript': ['*js'],
+  'application/json': ['json', 'map'],
+  'application/json5': ['json5'],
+  'application/jsonml+json': ['jsonml'],
+  'application/ld+json': ['jsonld'],
+  'application/lgr+xml': ['lgr'],
+  'application/lost+xml': ['lostxml'],
+  'application/mac-binhex40': ['hqx'],
+  'application/mac-compactpro': ['cpt'],
+  'application/mads+xml': ['mads'],
+  'application/manifest+json': ['webmanifest'],
+  'application/marc': ['mrc'],
+  'application/marcxml+xml': ['mrcx'],
+  'application/mathematica': ['ma', 'nb', 'mb'],
+  'application/mathml+xml': ['mathml'],
+  'application/mbox': ['mbox'],
+  'application/media-policy-dataset+xml': ['mpf'],
+  'application/mediaservercontrol+xml': ['mscml'],
+  'application/metalink+xml': ['metalink'],
+  'application/metalink4+xml': ['meta4'],
+  'application/mets+xml': ['mets'],
+  'application/mmt-aei+xml': ['maei'],
+  'application/mmt-usd+xml': ['musd'],
+  'application/mods+xml': ['mods'],
+  'application/mp21': ['m21', 'mp21'],
+  'application/mp4': ['*mp4', '*mpg4', 'mp4s', 'm4p'],
+  'application/msix': ['msix'],
+  'application/msixbundle': ['msixbundle'],
+  'application/msword': ['doc', 'dot'],
+  'application/mxf': ['mxf'],
+  'application/n-quads': ['nq'],
+  'application/n-triples': ['nt'],
+  'application/node': ['cjs'],
+  'application/octet-stream': [
+    'bin',
+    'dms',
+    'lrf',
+    'mar',
+    'so',
+    'dist',
+    'distz',
+    'pkg',
+    'bpk',
+    'dump',
+    'elc',
+    'deploy',
+    'exe',
+    'dll',
+    'deb',
+    'dmg',
+    'iso',
+    'img',
+    'msi',
+    'msp',
+    'msm',
+    'buffer',
+  ],
+  'application/oda': ['oda'],
+  'application/oebps-package+xml': ['opf'],
+  'application/ogg': ['ogx'],
+  'application/omdoc+xml': ['omdoc'],
+  'application/onenote': ['onetoc', 'onetoc2', 'onetmp', 'onepkg'],
+  'application/oxps': ['oxps'],
+  'application/p2p-overlay+xml': ['relo'],
+  'application/patch-ops-error+xml': ['xer'],
+  'application/pdf': ['pdf'],
+  'application/pgp-encrypted': ['pgp'],
+  'application/pgp-keys': ['asc'],
+  'application/pgp-signature': ['sig', '*asc'],
+  'application/pics-rules': ['prf'],
+  'application/pkcs10': ['p10'],
+  'application/pkcs7-mime': ['p7m', 'p7c'],
+  'application/pkcs7-signature': ['p7s'],
+  'application/pkcs8': ['p8'],
+  'application/pkix-attr-cert': ['ac'],
+  'application/pkix-cert': ['cer'],
+  'application/pkix-crl': ['crl'],
+  'application/pkix-pkipath': ['pkipath'],
+  'application/pkixcmp': ['pki'],
+  'application/pls+xml': ['pls'],
+  'application/postscript': ['ai', 'eps', 'ps'],
+  'application/provenance+xml': ['provx'],
+  'application/pskc+xml': ['pskcxml'],
+  'application/raml+yaml': ['raml'],
+  'application/rdf+xml': ['rdf', 'owl'],
+  'application/reginfo+xml': ['rif'],
+  'application/relax-ng-compact-syntax': ['rnc'],
+  'application/resource-lists+xml': ['rl'],
+  'application/resource-lists-diff+xml': ['rld'],
+  'application/rls-services+xml': ['rs'],
+  'application/route-apd+xml': ['rapd'],
+  'application/route-s-tsid+xml': ['sls'],
+  'application/route-usd+xml': ['rusd'],
+  'application/rpki-ghostbusters': ['gbr'],
+  'application/rpki-manifest': ['mft'],
+  'application/rpki-roa': ['roa'],
+  'application/rsd+xml': ['rsd'],
+  'application/rss+xml': ['rss'],
+  'application/rtf': ['rtf'],
+  'application/sbml+xml': ['sbml'],
+  'application/scvp-cv-request': ['scq'],
+  'application/scvp-cv-response': ['scs'],
+  'application/scvp-vp-request': ['spq'],
+  'application/scvp-vp-response': ['spp'],
+  'application/sdp': ['sdp'],
+  'application/senml+xml': ['senmlx'],
+  'application/sensml+xml': ['sensmlx'],
+  'application/set-payment-initiation': ['setpay'],
+  'application/set-registration-initiation': ['setreg'],
+  'application/shf+xml': ['shf'],
+  'application/sieve': ['siv', 'sieve'],
+  'application/smil+xml': ['smi', 'smil'],
+  'application/sparql-query': ['rq'],
+  'application/sparql-results+xml': ['srx'],
+  'application/sql': ['sql'],
+  'application/srgs': ['gram'],
+  'application/srgs+xml': ['grxml'],
+  'application/sru+xml': ['sru'],
+  'application/ssdl+xml': ['ssdl'],
+  'application/ssml+xml': ['ssml'],
+  'application/swid+xml': ['swidtag'],
+  'application/tei+xml': ['tei', 'teicorpus'],
+  'application/thraud+xml': ['tfi'],
+  'application/timestamped-data': ['tsd'],
+  'application/toml': ['toml'],
+  'application/trig': ['trig'],
+  'application/ttml+xml': ['ttml'],
+  'application/ubjson': ['ubj'],
+  'application/urc-ressheet+xml': ['rsheet'],
+  'application/urc-targetdesc+xml': ['td'],
+  'application/voicexml+xml': ['vxml'],
+  'application/wasm': ['wasm'],
+  'application/watcherinfo+xml': ['wif'],
+  'application/widget': ['wgt'],
+  'application/winhlp': ['hlp'],
+  'application/wsdl+xml': ['wsdl'],
+  'application/wspolicy+xml': ['wspolicy'],
+  'application/xaml+xml': ['xaml'],
+  'application/xcap-att+xml': ['xav'],
+  'application/xcap-caps+xml': ['xca'],
+  'application/xcap-diff+xml': ['xdf'],
+  'application/xcap-el+xml': ['xel'],
+  'application/xcap-ns+xml': ['xns'],
+  'application/xenc+xml': ['xenc'],
+  'application/xfdf': ['xfdf'],
+  'application/xhtml+xml': ['xhtml', 'xht'],
+  'application/xliff+xml': ['xlf'],
+  'application/xml': ['xml', 'xsl', 'xsd', 'rng'],
+  'application/xml-dtd': ['dtd'],
+  'application/xop+xml': ['xop'],
+  'application/xproc+xml': ['xpl'],
+  'application/xslt+xml': ['*xsl', 'xslt'],
+  'application/xspf+xml': ['xspf'],
+  'application/xv+xml': ['mxml', 'xhvml', 'xvml', 'xvm'],
+  'application/yang': ['yang'],
+  'application/yin+xml': ['yin'],
+  'application/zip': ['zip'],
+  'audio/3gpp': ['*3gpp'],
+  'audio/aac': ['adts', 'aac'],
+  'audio/adpcm': ['adp'],
+  'audio/amr': ['amr'],
+  'audio/basic': ['au', 'snd'],
+  'audio/midi': ['mid', 'midi', 'kar', 'rmi'],
+  'audio/mobile-xmf': ['mxmf'],
+  'audio/mp3': ['*mp3'],
+  'audio/mp4': ['m4a', 'mp4a'],
+  'audio/mpeg': ['mpga', 'mp2', 'mp2a', 'mp3', 'm2a', 'm3a'],
+  'audio/ogg': ['oga', 'ogg', 'spx', 'opus'],
+  'audio/s3m': ['s3m'],
+  'audio/silk': ['sil'],
+  'audio/wav': ['wav'],
+  'audio/wave': ['*wav'],
+  'audio/webm': ['weba'],
+  'audio/xm': ['xm'],
+  'font/collection': ['ttc'],
+  'font/otf': ['otf'],
+  'font/ttf': ['ttf'],
+  'font/woff': ['woff'],
+  'font/woff2': ['woff2'],
+  'image/aces': ['exr'],
+  'image/apng': ['apng'],
+  'image/avci': ['avci'],
+  'image/avcs': ['avcs'],
+  'image/avif': ['avif'],
+  'image/bmp': ['bmp', 'dib'],
+  'image/cgm': ['cgm'],
+  'image/dicom-rle': ['drle'],
+  'image/dpx': ['dpx'],
+  'image/emf': ['emf'],
+  'image/fits': ['fits'],
+  'image/g3fax': ['g3'],
+  'image/gif': ['gif'],
+  'image/heic': ['heic'],
+  'image/heic-sequence': ['heics'],
+  'image/heif': ['heif'],
+  'image/heif-sequence': ['heifs'],
+  'image/hej2k': ['hej2'],
+  'image/hsj2': ['hsj2'],
+  'image/ief': ['ief'],
+  'image/jls': ['jls'],
+  'image/jp2': ['jp2', 'jpg2'],
+  'image/jpeg': ['jpeg', 'jpg', 'jpe'],
+  'image/jph': ['jph'],
+  'image/jphc': ['jhc'],
+  'image/jpm': ['jpm', 'jpgm'],
+  'image/jpx': ['jpx', 'jpf'],
+  'image/jxl': ['jxl'],
+  'image/jxr': ['jxr'],
+  'image/jxra': ['jxra'],
+  'image/jxrs': ['jxrs'],
+  'image/jxs': ['jxs'],
+  'image/jxsc': ['jxsc'],
+  'image/jxsi': ['jxsi'],
+  'image/jxss': ['jxss'],
+  'image/ktx': ['ktx'],
+  'image/ktx2': ['ktx2'],
+  'image/png': ['png'],
+  'image/sgi': ['sgi'],
+  'image/svg+xml': ['svg', 'svgz'],
+  'image/t38': ['t38'],
+  'image/tiff': ['tif', 'tiff'],
+  'image/tiff-fx': ['tfx'],
+  'image/webp': ['webp'],
+  'image/wmf': ['wmf'],
+  'message/disposition-notification': ['disposition-notification'],
+  'message/global': ['u8msg'],
+  'message/global-delivery-status': ['u8dsn'],
+  'message/global-disposition-notification': ['u8mdn'],
+  'message/global-headers': ['u8hdr'],
+  'message/rfc822': ['eml', 'mime'],
+  'model/3mf': ['3mf'],
+  'model/gltf+json': ['gltf'],
+  'model/gltf-binary': ['glb'],
+  'model/iges': ['igs', 'iges'],
+  'model/jt': ['jt'],
+  'model/mesh': ['msh', 'mesh', 'silo'],
+  'model/mtl': ['mtl'],
+  'model/obj': ['obj'],
+  'model/prc': ['prc'],
+  'model/step+xml': ['stpx'],
+  'model/step+zip': ['stpz'],
+  'model/step-xml+zip': ['stpxz'],
+  'model/stl': ['stl'],
+  'model/u3d': ['u3d'],
+  'model/vrml': ['wrl', 'vrml'],
+  'model/x3d+binary': ['*x3db', 'x3dbz'],
+  'model/x3d+fastinfoset': ['x3db'],
+  'model/x3d+vrml': ['*x3dv', 'x3dvz'],
+  'model/x3d+xml': ['x3d', 'x3dz'],
+  'model/x3d-vrml': ['x3dv'],
+  'text/cache-manifest': ['appcache', 'manifest'],
+  'text/calendar': ['ics', 'ifb'],
+  'text/coffeescript': ['coffee', 'litcoffee'],
+  'text/css': ['css'],
+  'text/csv': ['csv'],
+  'text/html': ['html', 'htm', 'shtml'],
+  'text/jade': ['jade'],
+  'text/javascript': ['js', 'mjs'],
+  'text/jsx': ['jsx'],
+  'text/less': ['less'],
+  'text/markdown': ['md', 'markdown'],
+  'text/mathml': ['mml'],
+  'text/mdx': ['mdx'],
+  'text/n3': ['n3'],
+  'text/plain': ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini'],
+  'text/richtext': ['rtx'],
+  'text/rtf': ['*rtf'],
+  'text/sgml': ['sgml', 'sgm'],
+  'text/shex': ['shex'],
+  'text/slim': ['slim', 'slm'],
+  'text/spdx': ['spdx'],
+  'text/stylus': ['stylus', 'styl'],
+  'text/tab-separated-values': ['tsv'],
+  'text/troff': ['t', 'tr', 'roff', 'man', 'me', 'ms'],
+  'text/turtle': ['ttl'],
+  'text/uri-list': ['uri', 'uris', 'urls'],
+  'text/vcard': ['vcard'],
+  'text/vtt': ['vtt'],
+  'text/wgsl': ['wgsl'],
+  'text/xml': ['*xml'],
+  'text/yaml': ['yaml', 'yml'],
+  'video/3gpp': ['3gp', '3gpp'],
+  'video/3gpp2': ['3g2'],
+  'video/h261': ['h261'],
+  'video/h263': ['h263'],
+  'video/h264': ['h264'],
+  'video/iso.segment': ['m4s'],
+  'video/jpeg': ['jpgv'],
+  'video/jpm': ['*jpm', '*jpgm'],
+  'video/mj2': ['mj2', 'mjp2'],
+  'video/mp2t': ['ts', 'm2t', 'm2ts', 'mts'],
+  'video/mp4': ['mp4', 'mp4v', 'mpg4'],
+  'video/mpeg': ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v'],
+  'video/ogg': ['ogv'],
+  'video/quicktime': ['qt', 'mov'],
+  'video/webm': ['webm'],
+};
+Object.freeze(types);
+export default types;

+ 27 - 0
fashion-server/migration/js/package-lock.json

@@ -0,0 +1,27 @@
+{
+  "name": "js",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "dependencies": {
+        "mime": "^4.0.6"
+      }
+    },
+    "node_modules/mime": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmmirror.com/mime/-/mime-4.0.6.tgz",
+      "integrity": "sha512-4rGt7rvQHBbaSOF9POGkk1ocRP16Md1x36Xma8sz8h8/vfCUI2OtEIeCqe4Ofes853x4xDoPiFLIT47J5fI/7A==",
+      "funding": [
+        "https://github.com/sponsors/broofa"
+      ],
+      "license": "MIT",
+      "bin": {
+        "mime": "bin/cli.js"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    }
+  }
+}

+ 6 - 0
fashion-server/migration/js/package.json

@@ -0,0 +1,6 @@
+{
+"type":"module",
+"dependencies": {
+  "mime": "^4.0.6"
+}
+}