7 пре 2 дана
родитељ
комит
ecd28c63f2
100 измењених фајлова са 2217 додато и 9347 уклоњено
  1. 889 1366
      myapp/package-lock.json
  2. 1 0
      myapp/package.json
  3. 7 1
      myapp/src/app/app-routing.module.ts
  4. 19 0
      myapp/src/app/chat/chat.module.ts
  5. 32 0
      myapp/src/app/chat/chat.page.html
  6. 78 0
      myapp/src/app/chat/chat.page.scss
  7. 40 0
      myapp/src/app/chat/chat.page.ts
  8. 45 0
      myapp/src/app/tab1/community-activity.modal.page.ts
  9. 100 0
      myapp/src/app/tab1/services-modal.page.ts
  10. 5 0
      myapp/src/app/tab1/tab1.module.ts
  11. 44 28
      myapp/src/app/tab1/tab1.page.html
  12. 108 336
      myapp/src/app/tab1/tab1.page.scss
  13. 66 22
      myapp/src/app/tab1/tab1.page.ts
  14. 3 1
      myapp/src/app/tab1/tools-modal.page.ts
  15. 71 0
      myapp/src/app/tab2/create-request.page.html
  16. 139 0
      myapp/src/app/tab2/create-request.page.scss
  17. 130 0
      myapp/src/app/tab2/create-request.page.ts
  18. 4 0
      myapp/src/app/tab2/tab2-routing.module.ts
  19. 51 106
      myapp/src/app/tab2/tab2.page.html
  20. 20 362
      myapp/src/app/tab2/tab2.page.scss
  21. 149 1
      myapp/src/app/tab2/tab2.page.ts
  22. 36 15
      myapp/src/app/tab5/user-dashboard.page.html
  23. 121 0
      myapp/src/app/tab5/user-dashboard.page.scss
  24. 19 1
      myapp/src/app/tab5/user-dashboard.page.ts
  25. BIN
      myapp/src/assets/images/aipic.jpg
  26. BIN
      myapp/src/assets/images/banner1.jpg
  27. BIN
      myapp/src/assets/images/banner2.jpg
  28. BIN
      myapp/src/assets/images/banner3.jpg
  29. BIN
      myapp/src/assets/images/eventspic.jpg
  30. BIN
      myapp/src/assets/images/mypic.jpg
  31. BIN
      myapp/src/assets/images/toolspic.jpg
  32. 18 3
      myapp/src/global.scss
  33. 22 0
      myapp/src/lib/ncloud.ts
  34. 0 16
      node_modules/.bin/mkdirp
  35. 0 17
      node_modules/.bin/mkdirp.cmd
  36. 0 28
      node_modules/.bin/mkdirp.ps1
  37. 0 219
      node_modules/.package-lock.json
  38. 0 1
      node_modules/append-field/.npmignore
  39. 0 21
      node_modules/append-field/LICENSE
  40. 0 44
      node_modules/append-field/README.md
  41. 0 12
      node_modules/append-field/index.js
  42. 0 53
      node_modules/append-field/lib/parse-path.js
  43. 0 64
      node_modules/append-field/lib/set-value.js
  44. 0 19
      node_modules/append-field/package.json
  45. 0 19
      node_modules/append-field/test/forms.js
  46. 0 21
      node_modules/buffer-from/LICENSE
  47. 0 72
      node_modules/buffer-from/index.js
  48. 0 19
      node_modules/buffer-from/package.json
  49. 0 69
      node_modules/buffer-from/readme.md
  50. 0 5
      node_modules/busboy/.eslintrc.js
  51. 0 24
      node_modules/busboy/.github/workflows/ci.yml
  52. 0 23
      node_modules/busboy/.github/workflows/lint.yml
  53. 0 19
      node_modules/busboy/LICENSE
  54. 0 191
      node_modules/busboy/README.md
  55. 0 149
      node_modules/busboy/bench/bench-multipart-fields-100mb-big.js
  56. 0 143
      node_modules/busboy/bench/bench-multipart-fields-100mb-small.js
  57. 0 154
      node_modules/busboy/bench/bench-multipart-files-100mb-big.js
  58. 0 148
      node_modules/busboy/bench/bench-multipart-files-100mb-small.js
  59. 0 101
      node_modules/busboy/bench/bench-urlencoded-fields-100pairs-small.js
  60. 0 84
      node_modules/busboy/bench/bench-urlencoded-fields-900pairs-small-alt.js
  61. 0 57
      node_modules/busboy/lib/index.js
  62. 0 653
      node_modules/busboy/lib/types/multipart.js
  63. 0 350
      node_modules/busboy/lib/types/urlencoded.js
  64. 0 596
      node_modules/busboy/lib/utils.js
  65. 0 22
      node_modules/busboy/package.json
  66. 0 109
      node_modules/busboy/test/common.js
  67. 0 94
      node_modules/busboy/test/test-types-multipart-charsets.js
  68. 0 102
      node_modules/busboy/test/test-types-multipart-stream-pause.js
  69. 0 1053
      node_modules/busboy/test/test-types-multipart.js
  70. 0 488
      node_modules/busboy/test/test-types-urlencoded.js
  71. 0 20
      node_modules/busboy/test/test.js
  72. 0 24
      node_modules/concat-stream/LICENSE
  73. 0 144
      node_modules/concat-stream/index.js
  74. 0 55
      node_modules/concat-stream/package.json
  75. 0 102
      node_modules/concat-stream/readme.md
  76. 0 19
      node_modules/core-util-is/LICENSE
  77. 0 3
      node_modules/core-util-is/README.md
  78. 0 107
      node_modules/core-util-is/lib/util.js
  79. 0 38
      node_modules/core-util-is/package.json
  80. 0 16
      node_modules/inherits/LICENSE
  81. 0 42
      node_modules/inherits/README.md
  82. 0 9
      node_modules/inherits/inherits.js
  83. 0 27
      node_modules/inherits/inherits_browser.js
  84. 0 29
      node_modules/inherits/package.json
  85. 0 1
      node_modules/isarray/.npmignore
  86. 0 4
      node_modules/isarray/.travis.yml
  87. 0 6
      node_modules/isarray/Makefile
  88. 0 60
      node_modules/isarray/README.md
  89. 0 19
      node_modules/isarray/component.json
  90. 0 5
      node_modules/isarray/index.js
  91. 0 45
      node_modules/isarray/package.json
  92. 0 20
      node_modules/isarray/test.js
  93. 0 22
      node_modules/media-typer/HISTORY.md
  94. 0 22
      node_modules/media-typer/LICENSE
  95. 0 81
      node_modules/media-typer/README.md
  96. 0 270
      node_modules/media-typer/index.js
  97. 0 26
      node_modules/media-typer/package.json
  98. 0 507
      node_modules/mime-db/HISTORY.md
  99. 0 23
      node_modules/mime-db/LICENSE
  100. 0 100
      node_modules/mime-db/README.md

Разлика између датотеке није приказан због своје велике величине
+ 889 - 1366
myapp/package-lock.json


+ 1 - 0
myapp/package.json

@@ -31,6 +31,7 @@
     "fmode-ng": "^0.0.83",
     "ionicons": "^7.0.0",
     "rxjs": "~7.8.0",
+    "swiper": "^11.2.8",
     "tslib": "^2.3.0",
     "zone.js": "~0.15.0"
   },

+ 7 - 1
myapp/src/app/app-routing.module.ts

@@ -1,18 +1,24 @@
 import { NgModule } from '@angular/core';
 import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
 import { AiAgentPage } from './ai-agent/ai-agent.page';
+import { CreateRequestPage } from './tab2/create-request.page';
 
 const routes: Routes = [
   {
     path: '',
     loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule)
   },
+  { path: 'create-request', component: CreateRequestPage } ,
   
   {
     path: 'tab5',
     loadChildren: () => import('./tab5/tab5.module').then( m => m.Tab5PageModule)
   },
-  { path: 'ai-agent', component: AiAgentPage }
+  { path: 'ai-agent', component: AiAgentPage },
+  {
+    path: 'chat/:username',
+    loadChildren: () => import('./chat/chat.module').then(m => m.ChatPageModule)
+  }
 ];
 @NgModule({
   imports: [

+ 19 - 0
myapp/src/app/chat/chat.module.ts

@@ -0,0 +1,19 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { IonicModule } from '@ionic/angular';
+import { RouterModule } from '@angular/router';
+import { ChatPage } from './chat.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    IonicModule,
+    RouterModule.forChild([
+      {
+        path: '',
+        component: ChatPage
+      }
+    ])
+  ]
+})
+export class ChatPageModule {}

+ 32 - 0
myapp/src/app/chat/chat.page.html

@@ -0,0 +1,32 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-button (click)="goBack()">
+        <ion-icon name="arrow-back"></ion-icon>
+      </ion-button>
+    </ion-buttons>
+    <ion-title>{{username}}</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content class="chat-content">
+  <div class="message-list">
+    <!-- 消息列表将在这里动态生成 -->
+    <div *ngFor="let message of messages" class="message" [class.sent]="message.isSent">
+      <div class="message-bubble">
+        <div class="message-text">{{message.text}}</div>
+        <div class="message-time">{{message.time | date:'HH:mm'}}</div>
+      </div>
+    </div>
+  </div>
+
+  <div class="message-input-container">
+    <ion-button fill="clear" class="attachment-btn">
+      <ion-icon name="image"></ion-icon>
+    </ion-button>
+    <ion-input placeholder="输入消息..." [(ngModel)]="newMessage"></ion-input>
+    <ion-button fill="clear" (click)="sendMessage()">
+      <ion-icon name="send"></ion-icon>
+    </ion-button>
+  </div>
+</ion-content>

+ 78 - 0
myapp/src/app/chat/chat.page.scss

@@ -0,0 +1,78 @@
+.chat-content {
+  --background: #f5f5f5;
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+}
+
+.message-list {
+  flex: 1;
+  padding: 10px;
+  overflow-y: auto;
+}
+
+.message {
+  display: flex;
+  margin-bottom: 15px;
+
+  &.sent {
+    justify-content: flex-end;
+    
+    .message-bubble {
+      background-color: #95ec69;
+    }
+  }
+}
+
+.message-bubble {
+  max-width: 70%;
+  padding: 10px 15px;
+  border-radius: 18px;
+  background-color: white;
+  box-shadow: 0 1px 2px rgba(0,0,0,0.1);
+}
+
+.message-text {
+  font-size: 16px;
+  margin-bottom: 5px;
+}
+
+.message-time {
+  font-size: 12px;
+  color: #666;
+  text-align: right;
+}
+
+.message-input-container {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  display: flex;
+  align-items: center;
+  padding: 10px;
+  background-color: white;
+  border-top: 1px solid #eee;
+  
+  ion-input {
+    flex: 1;
+    margin-right: 10px;
+  }
+  
+  .attachment-btn {
+    order: 2;
+    margin-right: 5px;
+  }
+  
+  ion-button[click="sendMessage()"] {
+    order: 3;
+  }
+}
+
+.chat-content {
+  padding-bottom: 70px; /* 为底部输入框留出空间 */
+}
+
+.attachment-btn {
+  margin-right: 5px;
+}

+ 40 - 0
myapp/src/app/chat/chat.page.ts

@@ -0,0 +1,40 @@
+import { Component } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { IonicModule } from '@ionic/angular';
+import { FormsModule } from '@angular/forms';
+import { CommonModule } from '@angular/common';
+
+@Component({
+  selector: 'app-chat',
+  templateUrl: 'chat.page.html',
+  styleUrls: ['chat.page.scss'],
+  standalone: true,
+  imports: [IonicModule, FormsModule, CommonModule]
+})
+export class ChatPage {
+  username: string = '';
+  newMessage: string = '';
+  messages: any[] = [
+    { text: '你好,您家的地址在哪里呢?', isSent: false, time: new Date() }
+  ];
+
+  constructor(private route: ActivatedRoute, private router: Router) {
+    this.username = this.route.snapshot.paramMap.get('username') || '';
+  }
+
+  goBack() {
+    this.router.navigate(['/tabs/tab2']); // 修改为正确的路由路径
+  }
+
+  sendMessage() {
+    if (this.newMessage.trim()) {
+      this.messages.push({
+        text: this.newMessage,
+        isSent: true,
+        time: new Date()
+      });
+      this.newMessage = '';
+      // 这里可以添加消息发送到服务器的逻辑
+    }
+  }
+}

+ 45 - 0
myapp/src/app/tab1/community-activity.modal.page.ts

@@ -0,0 +1,45 @@
+import { Component } from '@angular/core';
+import { ModalController } from '@ionic/angular';
+import { IonicModule } from '@ionic/angular';
+import { CommonModule } from '@angular/common';
+@Component({
+  selector: 'app-community-activity-modal',
+  standalone: true,
+  imports: [CommonModule, IonicModule],
+  template: `
+    <ion-header>
+      <ion-toolbar>
+        <ion-title>社区活动</ion-title>
+        <ion-buttons slot="end">
+          <ion-button (click)="dismiss()">关闭</ion-button>
+        </ion-buttons>
+      </ion-toolbar>
+    </ion-header>
+    <ion-content>
+      <div class="dashed-box">
+        <h2>活动待公布</h2>
+      </div>
+    </ion-content>
+  `,
+  styles: [`
+    .dashed-box {
+      height: 30%;
+      border: 2px dashed #999;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      color: #999;
+    }
+    h2 {
+      font-size: 1.5rem;
+      font-weight: bold;
+    }
+  `]
+})
+export class CommunityActivityModal {
+  constructor(private modalCtrl: ModalController) {}
+
+  dismiss() {
+    this.modalCtrl.dismiss();
+  }
+}

+ 100 - 0
myapp/src/app/tab1/services-modal.page.ts

@@ -0,0 +1,100 @@
+import { Component, Input } from '@angular/core';
+import { ModalController } from '@ionic/angular';
+import { CommonModule } from '@angular/common';
+import { IonicModule } from '@ionic/angular';
+import { CloudObject, CloudQuery } from 'src/lib/ncloud';
+
+@Component({
+  selector: 'app-services-modal',
+  standalone: true,
+  imports: [CommonModule, IonicModule],
+  template: `
+    <ion-header>
+      <ion-toolbar>
+        <ion-title>我的服务</ion-title>
+        <ion-buttons slot="end">
+          <ion-button (click)="dismiss()">关闭</ion-button>
+        </ion-buttons>
+      </ion-toolbar>
+      <ion-toolbar>
+        <ion-segment value="inProgress" (ionChange)="segmentChanged($event)">
+          <ion-segment-button value="inProgress">
+            <ion-label>进行中</ion-label>
+          </ion-segment-button>
+          <ion-segment-button value="completed">
+            <ion-label>已完成</ion-label>
+          </ion-segment-button>
+        </ion-segment>
+      </ion-toolbar>
+    </ion-header>
+    <ion-content>
+      <ion-list>
+        <ion-item *ngFor="let service of services">
+          <ion-avatar slot="start">
+            <img [src]="service.userAvatar || 'https://ionicframework.com/docs/img/demos/avatar.svg'">
+          </ion-avatar>
+          <ion-label>
+            <h2>{{ service.userName }}</h2>
+            <p>{{ service.description }}</p>
+            <p>服务类型: {{ service.serviceType }}</p>
+            <p>积分: {{ service.points }} | 状态: {{ service.status === 'inProgress' ? '进行中' : '已完成' }}</p>
+            <p>创建时间: {{ service.createTime | date:'yyyy-MM-dd' }}</p>
+          </ion-label>
+        </ion-item>
+      </ion-list>
+    </ion-content>
+  `
+})
+export class ServicesModalPage {
+    @Input() services: any[] = [];
+    segmentValue: any;
+  
+
+  constructor(private modalCtrl: ModalController) {
+    this.loadServices();
+  }
+  storeList: CloudObject[]=[]
+
+  async loadServices() {
+    try {
+      let query = new CloudQuery("Progressing");
+      this.storeList = await query.find();
+      
+      // 确保所有字段都有默认值
+      this.services = this.storeList.map(item => ({
+        userName: item.get('userName') || '未知用户',
+        userAvatar: item.get('userAvatar') || 'https://ionicframework.com/docs/img/demos/avatar.svg',
+        description: item.get('description') || '无描述',
+        points: item.get('points') || 0,
+        status: item.get('status') || 'inProgress',
+        // 添加其他需要的字段
+        createTime: item.get('createTime') || new Date().toISOString(),
+        serviceType: item.get('serviceType') || '普通服务'
+      }));
+      
+      console.log('加载的服务数据:', this.services); // 调试用
+    } catch (error) {
+      console.error('加载服务数据失败:', error);
+      this.services = []; // 出错时清空列表
+    }
+  }
+
+  segmentChanged(event: any) {
+    this.segmentValue = event.detail.value;
+    if(this.segmentValue === 'inProgress') {
+        this.loadServices(); // 点击"进行中"时加载数据
+    } else {
+        this.services = []; // 点击"已完成"时清空数据
+    }
+}
+
+  
+
+  dismiss() {
+    this.modalCtrl.dismiss();
+  }
+
+  ionViewWillEnter() {
+    this.loadServices(); // 每次打开模态框时刷新数据
+  }
+}

+ 5 - 0
myapp/src/app/tab1/tab1.module.ts

@@ -7,6 +7,10 @@ import { ExploreContainerComponentModule } from '../explore-container/explore-co
 
 import { Tab1PageRoutingModule } from './tab1-routing.module';
 import { ToolsModalPage } from './tools-modal.page';
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { register } from 'swiper/element';
+
+register();
 
 @NgModule({
   imports: [
@@ -20,5 +24,6 @@ import { ToolsModalPage } from './tools-modal.page';
     Tab1Page,
     
   ],
+  schemas: [CUSTOM_ELEMENTS_SCHEMA]
 })
 export class Tab1PageModule {}

+ 44 - 28
myapp/src/app/tab1/tab1.page.html

@@ -15,26 +15,47 @@
 
 
   <!-- 服务九宫格 -->
-  <div class="services-grid">
-    <ion-grid>
-      <ion-row>
-        <ion-col *ngFor="let service of services" size="4" class="service-item">
-          <!-- 添加data-service-id属性用于样式区分 -->
-          <ion-button (click)="handleServiceClick(service.id)" fill="clear" [attr.data-service-id]="service.id">
-            <div class="icon-container">
-              <ion-icon [name]="service.icon"></ion-icon>
-            </div>
-            <ion-label>{{ service.name }}</ion-label>
-            <ion-badge *ngIf="service.badge > 0">{{ service.badge }}</ion-badge>
-          </ion-button>
-        </ion-col>
-      </ion-row>
-    </ion-grid>
-  </div>
+  <div class="ion-padding">
+    <!-- 添加轮播图 -->
+    <!-- 替换原有的ion-slides部分 -->
+    <swiper-container [config]="swiperConfig" class="banner-slides">
+      <swiper-slide>
+        <img src="assets/images/banner2.jpg" class="banner-img">
+      </swiper-slide>
+      <swiper-slide>
+        <img src="assets/images/banner1.jpg" class="banner-img">
+      </swiper-slide>
+      <swiper-slide>
+        <img src="assets/images/banner3.jpg" class="banner-img">
+      </swiper-slide>
+    </swiper-container>
+
+
+    
+  <ion-grid class="services-grid">
+    <ion-row>
+      <ion-col size="6" *ngFor="let service of services">
+        <ion-button
+          expand="block" 
+          fill="clear"  
+          class="service-button"
+          [attr.data-service-id]="service.id"
+          (click)="handleServiceClick(service.id)">
+          <div class="button-content">
+            <ion-icon *ngIf="service.id !== 'tools'" slot="start" [name]="service.icon"></ion-icon>
+            <span *ngIf="service.id !== 'tools'">{{service.name}}</span>
+            <ion-badge *ngIf="service.badge > 0" color="danger">{{service.badge}}</ion-badge>
+          </div>
+        </ion-button>
+       </ion-col>
+    </ion-row>
+   </ion-grid>
+
+  
 
   <!-- 社区动态信息流 -->
   <div class="community-feed">
-    <ion-list lines="none" style="max-height: 50vh; overflow-y: auto;">
+    <ion-list lines="none" style="height: calc(43vh - 120px); overflow-y: auto;">
       <ion-list-header>
         <ion-label>社区互助动态</ion-label>
         <ion-chip (click)="importMessage()">导入测试数据</ion-chip>
@@ -47,21 +68,16 @@
           <img [src]="'https://ionicframework.com/docs/img/demos/avatar.svg'" />
         </ion-avatar>
         <ion-label class="message-content">
-          <h2>{{ item.name }}({{ item.ages }}岁)</h2>
-          <p class="matter">{{ item.matter }}</p>
-          <ion-badge color="warning" *ngIf="item.points > 40">
-            <ion-icon name="flash"></ion-icon>
-            高积分需求
-          </ion-badge>
+          <h2>{{item.name}}</h2>
+          <p>{{item.ages}}岁 | {{item.matter}}</p>
+          <p>积分: {{item.points}}</p>
         </ion-label>
-        <div slot="end" class="meta-info">
-          <ion-text color="primary" class="points">+{{ item.points }}分</ion-text>
-          <ion-note class="time">{{ today | date:'HH:mm' }}</ion-note>
-        </div>
+        <ion-button slot="end" fill="solid" color="primary" (click)="claimService(item)">领取</ion-button>
       </ion-item>
     </ion-list>
   </div>
 
+  
 
 <!-- 悬浮助手按钮 -->
 <div class="assistant-button" (click)="openVoiceInput()">
@@ -71,4 +87,4 @@
     <div class="assistant-mouth"></div>
   </div>
 </div>
-
+  </div>

+ 108 - 336
myapp/src/app/tab1/tab1.page.scss

@@ -1,303 +1,9 @@
-/* 基础样式 */
-ion-content {
-    --background: #f5f5f5;
-    --padding-top: 0;
-    --padding-bottom: 0;
-    --padding-start: 0;
-    --padding-end: 0;
-}
-
-/* iPhone 形状容器 */
-.iphone-container {
-    position: relative;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    height: 100vh;
-    width: 100vw;
-}
-
-.iphone-screen {
-    position: relative;
-    width: 375px; /* 模拟 iPhone 宽度 */
-    height: calc(375px * 19.5 / 9); /* 根据宽高比计算高度 */
-    background: white;
-    border-radius: 54px;
-    box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
-    overflow: hidden;
-    margin: auto;
-}
-
-.iphone-notch {
-    position: absolute;
-    top: 0;
-    left: 50%;
-    transform: translateX(-50%);
-    width: 210px;
-    height: 30px;
-    background: black;
-    border-bottom-left-radius: 20px;
-    border-bottom-right-radius: 20px;
-    z-index: 1;
-}
-
-/* 将主要内容包裹在 iPhone 屏幕内 */
-.page-container {
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    max-width: 100%;
-    margin: 0 auto;
-    padding: 30px 16px; /* 为刘海留出空间 */
-    overflow-y: auto;
-}
-
-/* 紧急状态条 */
-.emergency-bar {
-    display: flex;
-    align-items: center;
-    padding: 12px 16px;  // 增加垂直padding
-    background-color: #ff5252;
-    color: white;
-    font-size: 16px;  // 增大字体
-    line-height: 1.5;
-    ion-icon {
-      margin-right: 8px;
-    }
-  }
-  
-  /* 子女消息区域 */
-  .children-messages {
-    padding: 0 8px;
-    
-    ion-card {
-      margin: 8px 0;
-      border-left: 4px solid var(--ion-color-warning);
-      
-      &.unread {
-        border-left-color: var(--ion-color-primary);
-        background: rgba(var(--ion-color-primary-rgb), 0.05);
-      }
-      
-      .unread-indicator {
-        position: absolute;
-        right: 16px;
-        top: 16px;
-        width: 8px;
-        height: 8px;
-        border-radius: 50%;
-        background: var(--ion-color-primary);
-      }
-    }
-  }
-  
-  /* 服务九宫格 */
-  /* 服务九宫格 */
-  .services-grid {
-    padding: 16px 12px;
-    
-    ion-grid {
-      gap: 12px; /* 增加格子间距 */
-    }
-  
-    .service-item {
-      ion-button {
-        --padding-top: 12px;
-        --padding-bottom: 12px;
-        border-radius: 14px; /* 更圆润的边角 */
-        background: #ffffff;
-        box-shadow: 0 3px 8px rgba(0, 0, 0, 0.08); /* 更柔和的阴影 */
-        transition: all 0.2s ease;
-        min-height: 100px; /* 统一高度 */
-        width: 100%; /* 占满列宽度 */
-  
-        &:hover {
-          transform: translateY(-2px); /* 悬停上移效果 */
-          box-shadow: 0 5px 12px rgba(0, 0, 0, 0.12);
-        }
-  
-        // 已有的紧急求助和代买药品颜色
-        &[data-service-id="emergency"] {
-          background: linear-gradient(135deg, #ff6b6b, #ff9a9a);
-          ion-icon { color: #ffffff; }
-          ion-label { 
-            color: #ffffff;
-            white-space: normal; /* 允许文字换行 */
-            line-height: 1.3; /* 调整行高让文字两行显示 */
-          }
-        }
-        &[data-service-id="medicine"] {
-          background: linear-gradient(135deg, #42a5f5, #64b5f6);
-          ion-icon { color: #ffffff; }
-          ion-label { color: #ffffff; }
-        }
-      
-        // 新增工具借用、老人陪聊、AI管家颜色
-&[data-service-id="tools"] {
-  background: linear-gradient(135deg, #458cee, #2951d2); /* 蓝色渐变 */
-  ion-icon { color: #ffffff; }
-  ion-label { 
-    color: #ffffff;
-    white-space: normal; /* 允许文字换行 */
-    line-height: 1.3;
-  }
-}
 
-&[data-service-id="ai"] {
-  background: linear-gradient(135deg, #4dd0e1, #80deea); /* 青色渐变 */
-  ion-icon { color: #ffffff; }
-  ion-label { 
-    color: #ffffff;
-    white-space: normal; 
-    line-height: 1.3;
-  }
-}
-        &[data-service-id="events"] {
-          background: linear-gradient(135deg, #66bb6a, #81c784); /* 绿色渐变 */
-          ion-icon { color: #ffffff; }
-          ion-label { color: #ffffff; }
-        }
-        
-        &[data-service-id="my"] {
-          background: linear-gradient(135deg, #90a4ae, #b0bec5); /* 灰色渐变 */
-          ion-icon { color: #ffffff; }
-          ion-label { color: #ffffff; }
-        }
-      }
-    }
-  }
-    .service-card {
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      justify-content: center;
-      height: 100%;
-      padding: 12px 0;
-      border-radius: 12px;
-      background: white;
-      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
-      transition: transform 0.2s ease;
-      
-      &:active {
-        transform: scale(0.95);
-      }
-      
-      &.emergency-service {
-        background: linear-gradient(135deg, #ff5252, #ff8a80);
-        color: white;
-        animation: pulse 1.5s infinite;
-      }
-      
-      .icon-container {
-        position: relative;
-        margin-bottom: 8px;
-        
-        // 为不同图标添加不同颜色
-        ion-icon[name="warning"] {
-          color: #ff5252;
-        }
-        ion-icon[name="medical"] {
-          color: #4caf50;
-        }
-        ion-icon[name="construct"] {
-          color: #2196f3;
-        }
-        ion-icon[name="chatbubbles"] {
-          color: #9c27b0;
-        }
-        ion-icon[name="headset"] {
-          color: #ff9800;
-        }
-        ion-icon[name="gift"] {
-          color: #e91e63;
-        }
-        ion-icon[name="calendar"] {
-          color: #673ab7;
-        }
-        ion-icon[name="people"] {
-          color: #009688;
-        }
-        ion-icon[name="list"] {
-          color: #795548;
-        }
-        
-        ion-badge {
-          position: absolute;
-          top: -8px;
-          right: -8px;
-        }
-      }
-      
-      ion-label {
-        font-size: 12px;
-        text-align: center;
-      }  // 此处为正确闭合的大括号,若第227行是额外的`}`需删除
-  }
-  
-  /* 社区动态信息流 */
-  .community-feed {
-    ion-item {
-      --padding-start: 8px;
-      --inner-padding-end: 8px;
-      margin-bottom: 8px;
-      border-radius: 12px;
-      background: white;
-      
-      &.emergency-item {
-        --background: rgba(255, 82, 82, 0.1);
-        border-left: 4px solid var(--ion-color-danger);
-      }
-      
-      &.completed-item {
-        --background: rgba(200, 200, 200, 0.2);
-        opacity: 0.8;
-      }
-      
-      ion-avatar {
-        width: 40px;
-        height: 40px;
-      }
-      
-      .emergency-tag {
-        display: inline-flex;
-        align-items: center;
-        padding: 2px 6px;
-        background: rgba(255, 82, 82, 0.2);
-        border-radius: 4px;
-        color: var(--ion-color-danger);
-        font-size: 12px;
-        
-        ion-icon {
-          margin-right: 4px;
-        }
-      }
-      
-      .item-meta {
-        display: flex;
-        flex-direction: column;
-        align-items: flex-end;
-        
-        .time {
-          font-size: 12px;
-          color: var(--ion-color-medium);
-        }
-        
-        .points {
-          font-size: 14px;
-          color: var(--ion-color-warning);
-          font-weight: bold;
-        }
-      }
-    }
-  }
-  
-  /* 悬浮助手按钮 */
+/* 悬浮助手按钮 */
   .assistant-button {
     position: fixed;
     right: 20px;
-    bottom: 20px;
+    bottom: 80px;
     width: 56px;
     height: 56px;
     border-radius: 50%;
@@ -351,6 +57,13 @@ ion-content {
     100% { transform: scale(1); opacity: 0.7; }
   }
 
+/* 增加各区块间距 */
+.children-messages,
+.services-grid,
+.community-feed {
+  margin-bottom: 0px;
+}
+  
 /* 中央布局容器 */
 .page-container {
   max-width: 100%;
@@ -358,17 +71,11 @@ ion-content {
   padding: 0 16px;
 }
 
-/* 增加各区块间距 */
-.children-messages,
-.services-grid,
-.community-feed {
-  margin-bottom: 24px;
-}
 
 /* 服务卡片间距调整 */
 .services-grid {
   ion-col {
-    padding: 8px;
+    padding: 0px;
   }
 }
 
@@ -379,45 +86,110 @@ ion-content {
   }
 }
 
-// 确保 html 和 body 元素充满屏幕
-html, body {
-  height: 100vh; // 设置高度为视口高度
-  width: 100vw; // 设置宽度为视口宽度
-  margin: 0;
-  padding: 0;
-  overflow: hidden;
+.services-grid {
+  padding: 5px;
 }
 
-ion-app {
-  height: 100vh; // 设置高度为视口高度
-  width: 100vw; // 设置宽度为视口宽度
+.service-button {
+  height: 80px;
+  margin: 8px;
+  position: relative;
+  border-radius: 18px !important;  // 添加圆角样式
+  overflow: hidden;  // 确保背景图片也遵循圆角
+  
+  &[data-service-id="tools"] {
+    background: url('/assets/images/toolspic.jpg') center/cover no-repeat;
+    height: 80px;
+    .button-content {
+      display: none;
+    }
+  }
+  &[data-service-id="ai"] {
+    background: url('/assets/images/aipic.jpg') center/cover no-repeat;
+    height: 80px;
+    .button-content {
+      display: none;
+    }
+  }
+  &[data-service-id="events"] {
+    background: url('/assets/images/eventspic.jpg') center/cover no-repeat;
+    height: 80px;
+    .button-content {
+      display: none;
+    }
+  }
+  &[data-service-id="my"] {
+    background: url('/assets/images/mypic.jpg') center/cover no-repeat;
+    height: 80px;
+    .button-content {
+      display: none;
+    }
+  }
+  .button-content {
+    position: relative;
+    z-index: 2;
+  }
 }
+  
 
-ion-content {
-  height: 100%;
-  --background: #f5f5f5;
-  --padding-top: 0;
-  --padding-bottom: 0;
-  --padding-start: 0;
-  --padding-end: 0;
+.banner-slides {
+  margin-bottom: 20px;
+  
+  .banner-img {
+    width: 100%;
+    height: 300px;
+    object-fit: cover;
+    border-radius: 8px;
+  }
 }
 
-/* 手机容器样式 */
-.phone-container {
-  position: relative;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  height: 100vh; // 设置高度为视口高度
-  width: 100vw; // 设置宽度为视口宽度
+
+/* 九宫格卡片样式 */
+.services-grid {
+  background-color: #f5f5f5;  // 外部背景灰色
+  padding: 16px;
+  border-radius: 12px;
+  margin: 16px 0;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
 }
 
-.phone-screen {
-  position: relative;
-  width: 100vw; // 设置宽度为视口宽度
-  height: 100vh; // 设置高度为视口高度
-  background: white;
-  box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
-  overflow: auto;
-  margin: auto;
+/* 社区动态卡片样式 */
+.community-feed {
+  background-color: #f5f5f5;  // 外部背景灰色
+  padding: 16px;
+  border-radius: 12px;
+  margin: 16px 0;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+  
+  ion-list {
+    background: white;  // 内部列表白色背景
+    border-radius: 8px;
+    padding: 8px;
+  }
+  
+  ion-list-header {
+    ion-label {
+      font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
+      font-size: 1.2rem;
+      font-weight: 600;
+      color: var(--ion-color-primary);
+      letter-spacing: 1px;
+      text-shadow: 0 2px 4px rgba(0,0,0,0.1);
+      position: relative;
+      padding-left: 12px;
+      
+      &:before {
+        content: '';
+        position: absolute;
+        left: 0;
+        top: 50%;
+        transform: translateY(-50%);
+        width: 4px;
+        height: 16px;
+        background: var(--ion-color-primary);
+        border-radius: 2px;
+      }
+    }
+  }
 }
+

+ 66 - 22
myapp/src/app/tab1/tab1.page.ts

@@ -4,7 +4,10 @@ import { IonicModule } from '@ionic/angular';
 import { Router } from '@angular/router'; // 新增Router导入
 import { ToolsModalPage } from './tools-modal.page';
 import { CloudObject, CloudQuery } from 'src/lib/ncloud';
-  
+import { ServicesModalPage } from './services-modal.page';
+import { ToastController } from '@ionic/angular';
+import { SwiperOptions } from 'swiper/types';
+import { CommunityActivityModal } from './community-activity.modal.page';
 // 独立的语音输入模态组件
 @Component({
   selector: 'app-voice-input-modal',
@@ -59,9 +62,18 @@ export class VoiceInputModal {
   standalone: false,
 })
 export class Tab1Page implements OnInit {
+  swiperConfig: SwiperOptions = {
+    autoplay: {
+      delay: 3000,
+    },
+    loop: true,
+    pagination: {
+      clickable: true,
+    }
+  };
   today: Date = new Date();
   // 用户数据
-  currentUser: any = { name: '王阿姨', role: 'elderly' };
+  currentUser: any = { name: 'hc', role: 'elderly' };
   isElderly: boolean = true;
 
   // 动态问候语
@@ -72,10 +84,7 @@ export class Tab1Page implements OnInit {
 
   // 服务九宫格
   services = [
-    { id: 'emergency', name: '紧急求助', icon: 'warning', badge: 1, priority: 5 },
-    { id: 'medicine', name: '代买药品', icon: 'medical', badge: 0, priority: 3 },
     { id: 'tools', name: '工具借用', icon: 'construct', badge: 2, priority: 2 },
-    // 删除 chat(老人陪聊) 和 shop(积分商城) 和 skills(技能交换)
     { id: 'ai', name: 'AI管家', icon: 'headset', badge: 0, priority: 1 },
     { id: 'events', name: '社区活动', icon: 'calendar', badge: 0, priority: 3 },
     { id: 'my', name: '我的服务', icon: 'list', badge: 0, priority: 1 }
@@ -103,19 +112,12 @@ export class Tab1Page implements OnInit {
     }
   ];
 
-  // 子女消息
-  childrenMessages = [
-    {
-      from: '儿子',
-      text: '妈,我给您约了周四体检',
-      time: new Date(),
-      played: false
-    }
-  ];
+
 
   // 是否夜间模式
-  isNightMode: boolean = false;
+  isNightMode: boolean = true;
   Message: { name: string; ages:number;matter: string; points: number}[] = [];
+  // 删除这行:toastCtrl: any;
 
   constructor(
     private modalCtrl: ModalController,
@@ -123,7 +125,8 @@ export class Tab1Page implements OnInit {
     private el: ElementRef,
     private animationCtrl: AnimationController,
     private navCtrl: NavController,
-    private router: Router // 新增Router依赖注入
+    private router: Router,
+    private toastCtrl: ToastController
   ) {
     this.loadMessage()
   }
@@ -263,13 +266,24 @@ async loadMessage(){
   }
 
   // 修改handleServiceClick函数
+  async openServicesModal() {
+    const modal = await this.modalCtrl.create({
+      component: ServicesModalPage
+    });
+    return await modal.present();
+  }
+
   handleServiceClick(serviceId: string) {
     if (serviceId === 'tools') {
       this.openToolsModal();
+    } else if (serviceId === 'my') {
+      this.openServicesModal();
+    } else if (serviceId === 'events') {
+      this.openCommunityActivityModal();
     } else {
       switch (serviceId) {
         case 'ai':
-          this.navigateToAiAgent(); // AI管家导航
+          this.navigateToAiAgent();
           break;
         // 其他服务可补充对应逻辑
       }
@@ -296,16 +310,46 @@ async loadMessage(){
             const message = new CloudObject('Message');
             message.set(Messages);
             await message.save();
-// 原代码中 MessageData 是数组,不能直接访问 name 属性,应使用当前遍历的 toolData
-// 原代码中 MessageData 是数组,应使用当前遍历的 message 对象来获取工具名称
-// 由于 Message 是普通对象,直接访问 name 属性
-console.log(`成功保存工具: ${Messages.name}`);
+            console.log(`成功保存工具: ${Messages.name}`);
         }
         console.log('所有工具数据已成功保存到数据库');
-        this.Message = [...this.Message, ...MessageData]; // 更新本地工具列表
+        this.Message = [...this.Message, ...MessageData];
     } catch (error) {
         console.error('保存数据时出错:', error);
     }
+  }
+  
+  async claimService(item: any) {
+    // 1. 从Message数组中移除该项
+    this.Message = this.Message.filter(msg => msg !== item);
+    
+    // 2. 创建新服务对象并设置状态
+    const service = new CloudObject("Progressing");
+    service.set({
+        userName: item.name,
+        userAvatar: 'https://ionicframework.com/docs/img/demos/avatar.svg',
+        description: item.matter,
+        points: item.points,
+        status: 'inProgress',
+        time: new Date()
+    });
+    
+    // 3. 保存到"我的服务"列表
+    await service.save();
+    
+    // 4. 显示领取成功提示
+    const toast = await this.toastCtrl.create({
+      message: '领取成功,请在我的服务中查看',
+      duration: 1000,
+      position: 'middle'  // 添加这行使提示出现在页面中间
+    });
+    toast.present();
+}
+async openCommunityActivityModal() {
+  const modal = await this.modalCtrl.create({
+    component: CommunityActivityModal
+  });
+  return await modal.present();
 }
 } // 此处为 Tab1Page 类的正确闭合
 

+ 3 - 1
myapp/src/app/tab1/tools-modal.page.ts

@@ -11,7 +11,9 @@ import { CloudObject, CloudQuery } from 'src/lib/ncloud';
   template: `
     <ion-header>
       <ion-toolbar>
-        <ion-title>可借用工具</ion-title> <ion-chip (click)="importTools()">导入测试数据</ion-chip>
+        <ion-title>可借用工具
+         <ion-chip (click)="importTools()">导入测试数据</ion-chip>
+         </ion-title>      
         <ion-buttons slot="end">
           <ion-button (click)="dismiss()">关闭</ion-button>
         </ion-buttons>

+ 71 - 0
myapp/src/app/tab2/create-request.page.html

@@ -0,0 +1,71 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-button (click)="dismiss()">取消</ion-button>
+    </ion-buttons>
+   
+    <ion-buttons slot="end">
+      <ion-button (click)="saveDraft()" color="medium">存草稿</ion-button>
+      <ion-button (click)="submitToPending()"  >发布</ion-button>
+      
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content class="ion-padding">
+  <ion-item>
+    <ion-input [(ngModel)]="request.title" placeholder="需求标题"></ion-input>
+  </ion-item>
+  
+  <ion-item>
+    <ion-label position="stacked">详细描述</ion-label>
+    <ion-textarea [(ngModel)]="request.description" placeholder="请详细描述您的需求"></ion-textarea>
+  </ion-item>
+  
+  <!-- 添加话题选择功能 -->
+  <ion-item>
+    <ion-button fill="clear" (click)="toggleTopics()">#添加话题</ion-button>
+    <ion-select 
+      [(ngModel)]="request.topic" 
+      interface="popover" 
+      [style.display]="showTopics ? 'block' : 'none'"
+      placeholder="选择话题"
+      (ionChange)="addTopicToDescription()">  <!-- 添加事件绑定 -->
+      <ion-select-option value="#家教">#家教</ion-select-option>
+      <ion-select-option value="#管道">#管道</ion-select-option>
+      <ion-select-option value="#水电">#水电</ion-select-option>
+      <ion-select-option value="#家政">#家政</ion-select-option>
+      <ion-select-option value="#跑腿">#跑腿</ion-select-option>
+      <ion-select-option value="#看护">#看护</ion-select-option>
+    </ion-select>
+  </ion-item>
+  
+  <!-- 添加图片上传框 -->
+  <div class="image-upload-box" (click)="selectImage()">
+    <ion-icon name="add-outline" class="plus-icon"></ion-icon>
+    <input type="file" accept="image/*" style="display: none" #fileInput (change)="onImageSelected($event)">
+  </div>
+  
+  <ion-item>
+   
+    <div class="type-points-row">
+      <div class="toggle-button-small">
+        <div class="toggle-switch" 
+             [class.urgent]="request.type === 'urgent'"
+             (click)="request.type = request.type === 'normal' ? 'urgent' : 'normal'">
+          <div class="toggle-handle"></div>
+        </div>
+        <span class="toggle-label">{{request.type === 'normal' ? '普通' : '紧急'}}</span>
+      </div>
+      
+      <div class="points-container">
+        <span class="points-label">积分奖励</span>
+        <ion-input 
+          type="number" 
+          [(ngModel)]="request.points" 
+          placeholder="输入积分"
+          class="points-input"></ion-input>
+      </div>
+    </div>
+  </ion-item>
+</ion-content>

+ 139 - 0
myapp/src/app/tab2/create-request.page.scss

@@ -0,0 +1,139 @@
+ion-content {
+  --background: #f5f5f5;
+}
+
+ion-item {
+  --background: white;
+  margin-bottom: 16px;
+  border-radius: 8px;
+}
+
+ion-textarea {
+  --padding-top: 8px;
+  --padding-bottom: 8px; 
+   min-height: 150px;  // 增加最小高度
+  font-size: 16px;   // 增大字体
+}
+
+.image-upload-box {
+  width: 25%;
+  height: 120px;
+  border: 2px dashed var(--ion-color-medium);
+  border-radius: 8px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin: 16px 0;
+  cursor: pointer;
+  
+  .plus-icon {
+    font-size: 32px;
+    color: var(--ion-color-medium);
+  }
+  
+  &:hover {
+    border-color: var(--ion-color-primary);
+    background-color: rgba(var(--ion-color-primary-rgb), 0.05);
+    
+    .plus-icon {
+      color: var(--ion-color-primary);
+    }
+  }
+}
+
+ion-button[fill="clear"] {
+  color: var(--ion-color-primary);
+  margin-top: -10px;
+}
+
+ion-select {
+  width: 100%;
+  margin-top: 8px;
+}
+
+.toggle-buttons {
+  display: flex;
+  gap: 8px;
+  
+  ion-button {
+    flex: 1;
+    margin: 0;
+  }
+}
+
+.type-points-row {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  
+  .toggle-button-small {
+    margin-right: 16px;
+  }
+  
+  .points-input {
+    width: 120px;
+    background: white;
+    border-radius: 8px;
+    --padding-start: 12px;
+    --padding-end: 12px;
+  }
+  .points-container {
+    display: flex;
+    align-items: center;
+    border: 1px solid var(--ion-color-medium);
+    border-radius: 8px;
+    padding: 0 12px;
+    
+    .points-label {
+      margin-right: 8px;
+      font-size: 14px;
+      color: var(--ion-color-medium);
+    }
+    
+    .points-input {
+      border: none;
+      --padding-start: 0;
+      --padding-end: 0;
+      --background: hsla(0, 4%, 85%, 0.155);
+      
+    }
+  }
+}
+.toggle-button-small {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  
+  .toggle-switch {
+    width: 50px;
+    height: 24px;
+    background: var(--ion-color-primary);
+    border-radius: 12px;
+    position: relative;
+    cursor: pointer;
+    
+    &.urgent {
+      background: var(--ion-color-danger);
+      
+      .toggle-handle {
+        left: 26px;
+      }
+    }
+    
+    .toggle-handle {
+      position: absolute;
+      width: 20px;
+      height: 20px;
+      background: white;
+      border-radius: 50%;
+      top: 2px;
+      left: 2px;
+      transition: left 0.2s ease;
+    }
+  }
+  
+  .toggle-label {
+    font-size: 14px;
+  }
+}

+ 130 - 0
myapp/src/app/tab2/create-request.page.ts

@@ -0,0 +1,130 @@
+import { Component, ViewChild } from '@angular/core';
+import { Router } from '@angular/router';
+import { IonicModule } from '@ionic/angular';
+import { FormsModule } from '@angular/forms';
+import { CloudObject, CloudQuery } from 'src/lib/ncloud';
+
+@Component({
+  selector: 'app-create-request',
+  templateUrl: 'create-request.page.html',
+  styleUrls: ['create-request.page.scss'],
+  standalone: true,
+  imports: [IonicModule, FormsModule]
+})
+export class CreateRequestPage {
+  request = {
+    title: '',
+    description: '',
+    type: 'normal',
+    points: 10,
+    images: [] as File[],
+    topic: '' // 新增话题字段
+  };
+  
+  showTopics = false; // 控制下拉框显示
+
+  toggleTopics() {
+    this.showTopics = !this.showTopics;
+  }
+
+  @ViewChild('fileInput') fileInput: any;
+
+  selectImage() {
+    this.fileInput.nativeElement.click();
+  }
+
+  onImageSelected(event: any) {
+    const file = event.target.files[0];
+    if (file) {
+      // 这里可以添加图片上传逻辑
+      console.log('Selected image:', file);
+      // 示例:将图片添加到请求对象
+      this.request.images.push(file);
+    }
+  }
+
+  constructor(private router: Router) {}
+
+  async submitRequest() {
+    try {
+      const obj = new CloudObject("Inprogress");
+      obj.set({
+        title: this.request.title,
+        description: this.request.description,
+        type: this.request.type,
+        points: this.request.points,
+        status: 'pending'
+      });
+      await obj.save();
+      this.router.navigate(['/tabs/tab2']); // 修改为正确的路由路径
+    } catch (error) {
+      console.error('提交需求失败:', error);
+    }
+  }
+
+  dismiss() {
+    this.router.navigate(['/tabs/tab2']); // 修改为正确的路由路径
+  }
+
+  addTopicToDescription() {
+    if (this.request.topic && this.request.description.indexOf(this.request.topic) === -1) {
+      this.request.description += (this.request.description ? '\n' : '') + this.request.topic;
+    }
+    this.showTopics = false; // 选择后隐藏下拉框
+  }
+
+  async saveDraft() {
+    try {
+      const obj = new CloudObject("Drafts");
+      obj.set({
+        title: this.request.title,
+        description: this.request.description,
+        type: this.request.type,
+        points: this.request.points,
+        images: this.request.images,
+        topic: this.request.topic
+      });
+      await obj.save();
+      this.router.navigate(['/tabs/tab2']);
+    } catch (error) {
+      console.error('保存草稿失败:', error);
+    }
+  }
+  
+  async submitToPending() {
+    try {
+      const obj = new CloudObject("PendingRequests");
+      obj.set({
+        title: this.request.title,
+        description: this.request.description,
+        type: this.request.type,
+        points: this.request.points,
+        status: 'pending',
+        topic: this.request.topic,
+        images: this.request.images,
+        time: new Date()  // 添加发布时间字段
+      });
+      await obj.save();
+      
+      // 发布成功后删除草稿
+      await this.deleteDraft();
+      this.router.navigate(['/tabs/tab2']); // 修改为正确的路由路径
+    } catch (error) {
+      console.error('发布到待领取失败:', error);
+    }
+  }
+
+  deleteDraft = async () => {
+    try {
+      const query = new CloudQuery("Drafts");
+      query.equalTo("status", "pending"); // 可以根据需要添加查询条件
+      const drafts = await query.find();
+      
+      if (drafts.length > 0) {
+        await drafts[0].destroy();
+      }
+    } catch (error) {
+      console.error('删除草稿失败:', error);
+    }
+  }
+}

+ 4 - 0
myapp/src/app/tab2/tab2-routing.module.ts

@@ -6,6 +6,10 @@ const routes: Routes = [
   {
     path: '',
     component: Tab2Page,
+  },
+  {
+    path: ':status',
+    component: Tab2Page
   }
 ];
 

+ 51 - 106
myapp/src/app/tab2/tab2.page.html

@@ -1,117 +1,62 @@
-<!-- 美化版需求发布页面 -->
 <ion-header>
-  <ion-toolbar color="primary" class="header-toolbar">
-    <ion-title>需求发布</ion-title>
+  <ion-toolbar>
+    <ion-title>我的需求</ion-title>
     <ion-buttons slot="end">
-      <ion-button class="voice-btn">
-        <ion-icon name="mic" slot="icon-only"></ion-icon>
+      <ion-button (click)="importTestData()">
+        <ion-icon slot="icon-only" name="cloud-upload"></ion-icon>
+        测
       </ion-button>
     </ion-buttons>
   </ion-toolbar>
 </ion-header>
 
-<ion-content class="ion-padding content-wrapper">
-  <!-- 步骤指示 -->
-  <div class="step-progress">
-    <div class="step active">
-      <div class="step-circle">1</div>
-      <div class="step-label">需求输入</div>
-    </div>
-    <div class="step-connector"></div>
-    <div class="step">
-      <div class="step-circle">2</div>
-      <div class="step-label">分类确认</div>
-    </div>
-    <div class="step-connector"></div>
-    <div class="step">
-      <div class="step-circle">3</div>
-      <div class="step-label">发布完成</div>
-    </div>
-  </div>
+<ion-content class="ion-padding">
+  <ion-segment value="inProgress">
+    <ion-segment-button value="inProgress" (click)="navigateTo('inProgress')">
+      <ion-label>进行中</ion-label>
+    </ion-segment-button>
+    <ion-segment-button value="completed" (click)="navigateTo('completed')">
+      <ion-label>已完成</ion-label>
+    </ion-segment-button>
+    <ion-segment-button value="pending" (click)="navigateTo('pending')">
+      <ion-label>待领取</ion-label>
+    </ion-segment-button>
+  </ion-segment>
 
-  <!-- 输入区域 -->
-  <ion-card class="camera-card">
-    <div class="camera-preview">
-      <div class="ai-focus-box">
-        <div class="scanning-line"></div>
-      </div>
-      <ion-icon name="camera" class="camera-icon"></ion-icon>
-    </div>
-    <ion-button fill="clear" class="annotate-btn">
-      <ion-icon name="pencil" slot="start"></ion-icon>
-      添加标注
-    </ion-button>
-  </ion-card>
+  <!-- 进行中任务列表 -->
+  <ion-list>
+    <ion-item *ngFor="let item of taskList">
+      <ion-avatar slot="start">
+        <img [src]="item.userAvatar"> <!-- 使用固定头像 -->
+      </ion-avatar>
+      <ion-label>
+        <h2>{{item.userName}}</h2>
+        <p>{{item.description}}</p>
+        <p *ngIf="currentStatus === 'inProgress'">开始时间: {{item.time | date:'yyyy-MM-dd HH:mm'}}</p>
+        <p *ngIf="currentStatus === 'completed'">开始时间: {{item.startTime | date:'yyyy-MM-dd HH:mm'}}</p>
+        <p *ngIf="currentStatus === 'pending'">发布时间: {{item.time | date:'yyyy-MM-dd HH:mm'}}</p>
+        <p *ngIf="item.endTime">完成时间: {{item.endTime | date:'yyyy-MM-dd HH:mm'}}</p>
+        <ion-badge [color]="item.type === 'urgent' ? 'danger' : 'primary'">
+          {{item.type === 'urgent' ? '紧急' : '普通'}}
+        </ion-badge>
+      </ion-label>
+      <ion-badge slot="end" color="primary">{{item.points}}积分</ion-badge>
+      <ion-button *ngIf="currentStatus === 'inProgress'" slot="end" fill="clear" (click)="completeTask(item)">
+        <ion-icon name="checkmark-circle" slot="icon-only"></ion-icon>
+        结束
+      </ion-button>
+      <ion-button *ngIf="currentStatus === 'inProgress'" slot="end" fill="clear" (click)="startChat(item)">
+        <ion-icon name="chatbubble" slot="icon-only"></ion-icon>
+        联系
+      </ion-button>
+    </ion-item>
+  </ion-list>
+</ion-content>
 
-  <!-- 分类卡片 -->
-  <div class="card-grid">
-    <ion-card class="emergency-card">
-      <ion-card-header>
-        <ion-card-title>紧急程度</ion-card-title>
-      </ion-card-header>
-      <div class="spectrum-bar">
-        <div class="level-indicator"></div>
-      </div>
-      <ion-note>当前选择:中等紧急</ion-note>
-    </ion-card>
+<!-- 添加在页面底部 -->
+<div class="add-button" (click)="navigateToCreate()">
+  <ion-icon name="add"></ion-icon>
+</div>
+<!-- 已清空所有内容 -->
 
-    <ion-card class="service-card">
-      <ion-card-header>
-        <ion-card-title>服务类型</ion-card-title>
-      </ion-card-header>
-      <div class="radar-placeholder">
-        <div class="radar-grid-line"></div>
-        <div class="data-point"></div>
-      </div>
-    </ion-card>
-  </div>
 
-  <!-- 资源卡片 -->
- <!-- 更新资源卡片部分 -->
-<ion-card class="resource-card">
-  <ion-card-header>
-    <ion-card-title>社区资源分布</ion-card-title>
-    <ion-badge color="primary">实时更新</ion-badge>
-  </ion-card-header>
-  
-  <div class="map-container">
-    <!-- 道路网络 -->
-    <div class="road horizontal main-road"></div>
-    <div class="road vertical main-road"></div>
-    <div class="road horizontal side-road"></div>
-    <div class="road vertical side-road"></div>
-    
-    <!-- 建筑物 -->
-    <div class="building residential" style="left:15%;top:20%">
-      <div class="windows">
-        <div class="row"></div><div class="row"></div>
-      </div>
-    </div>
-    <div class="building office" style="left:60%;top:15%">
-      <div class="logo">🏢</div>
-    </div>
-    
-    <!-- 公园 -->
-    <div class="park" style="left:30%;top:55%">
-      <div class="tree"></div>
-      <div class="tree"></div>
-    </div>
-    
-    <!-- 热力点 -->
-    <div class="heat-point tool" style="left:45%;top:35%">
-      <div class="pulse"></div>
-      <ion-icon name="construct"></ion-icon>
-    </div>
-    <div class="heat-point volunteer" style="left:70%;top:60%">
-      <div class="pulse"></div>
-      <ion-icon name="people"></ion-icon>
-    </div>
-    
-    <!-- 地图图例 -->
-    <div class="map-legend">
-      <div class="item"><span class="color residential"></span>住宅</div>
-      <div class="item"><span class="color office"></span>办公楼</div>
-      <div class="item"><span class="color park"></span>公园</div>
-    </div>
-  </div>
-</ion-card>

+ 20 - 362
myapp/src/app/tab2/tab2.page.scss

@@ -1,362 +1,20 @@
-/* 美化样式 */
-.content-wrapper {
-    --background: #f8f9fa;
-  }
-  
-  .step-progress {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    margin: 2rem 0;
-    
-    .step {
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      
-      &-circle {
-        width: 32px;
-        height: 32px;
-        border-radius: 50%;
-        background: #e9ecef;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        font-weight: 600;
-        color: #868e96;
-        transition: all 0.3s ease;
-      }
-      
-      &-label {
-        margin-top: 8px;
-        font-size: 0.8rem;
-        color: #adb5bd;
-      }
-      
-      &.active {
-        .step-circle {
-          background: var(--ion-color-primary);
-          color: white;
-          box-shadow: 0 4px 12px rgba(var(--ion-color-primary-rgb), 0.3);
-        }
-        .step-label {
-          color: var(--ion-color-primary);
-          font-weight: 500;
-        }
-      }
-    }
-    
-    .step-connector {
-      width: 60px;
-      height: 2px;
-      background: #e9ecef;
-      margin: 0 8px;
-    }
-  }
-  
-  .camera-card {
-    border-radius: 16px;
-    overflow: hidden;
-    box-shadow: 0 8px 24px rgba(0,0,0,0.08);
-    
-    .camera-preview {
-      height: 240px;
-      background: #e0e3ff;
-      position: relative;
-      
-      .ai-focus-box {
-        position: absolute;
-        width: 70%;
-        height: 60%;
-        border: 2px solid rgba(255,255,255,0.8);
-        border-radius: 12px;
-        left: 50%;
-        top: 50%;
-        transform: translate(-50%, -50%);
-        overflow: hidden;
-        
-        .scanning-line {
-          position: absolute;
-          width: 100%;
-          height: 2px;
-          background: rgba(255,255,255,0.6);
-          animation: scan 2s infinite linear;
-        }
-      }
-      
-      .camera-icon {
-        position: absolute;
-        left: 50%;
-        top: 50%;
-        transform: translate(-50%, -50%);
-        font-size: 3rem;
-        color: rgba(255,255,255,0.9);
-      }
-    }
-    
-    .annotate-btn {
-      --color: var(--ion-color-primary);
-      margin: 12px auto;
-    }
-  }
-  
-  @keyframes scan {
-    0% { top: 0 }
-    100% { top: 100% }
-  }
-  
-  .card-grid {
-    display: grid;
-    gap: 1.2rem;
-    margin: 1.5rem 0;
-  }
-  
-  .emergency-card {
-    .spectrum-bar {
-      height: 10px;
-      background: linear-gradient(90deg, 
-        #4CAF50 0%,
-        #FFEB3B 50%,
-        #F44336 100%
-      );
-      border-radius: 8px;
-      margin: 1rem 0;
-      position: relative;
-      
-      .level-indicator {
-        width: 20px;
-        height: 20px;
-        background: white;
-        border: 3px solid var(--ion-color-primary);
-        border-radius: 50%;
-        position: absolute;
-        left: 45%;
-        top: -5px;
-        box-shadow: 0 4px 12px rgba(0,0,0,0.1);
-      }
-    }
-  }
-  
-  .resource-card {
-    .resource-grid {
-      display: grid;
-      gap: 1.5rem;
-      grid-template-columns: 1fr 1fr;
-      
-      .heatmap-area {
-        background: #f1f3f5;
-        border-radius: 12px;
-        height: 160px;
-        position: relative;
-        
-        .heat-dot {
-          width: 24px;
-          height: 24px;
-          border-radius: 50%;
-          position: absolute;
-          background: rgba(var(--ion-color-primary-rgb), 0.2);
-          border: 2px solid var(--ion-color-primary);
-          
-          &.dot-1 { left: 30%; top: 20% }
-          &.dot-2 { left: 60%; top: 50% }
-          &.dot-3 { left: 45%; top: 70% }
-        }
-      }
-      
-      .tool-list {
-        background: transparent;
-        
-        ion-item {
-          --background: #f8f9fa;
-          border-radius: 8px;
-          margin-bottom: 8px;
-          
-          ion-icon {
-            color: var(--ion-color-primary);
-          }
-        }
-      }
-    }
-  }
-  
-  .publish-btn {
-    --border-radius: 12px;
-    --padding-top: 18px;
-    --padding-bottom: 18px;
-    margin: 12px;
-    font-weight: 600;
-    letter-spacing: 0.5px;
-  }
-  /* 详细地图样式 */
-.map-container {
-    height: 300px;
-    background: #f0f4f8;
-    border-radius: 12px;
-    position: relative;
-    overflow: hidden;
-    
-    /* 道路系统 */
-    .road {
-      position: absolute;
-      background: #cbd5e1;
-      
-      &.main-road {
-        width: 100%;
-        height: 8px;
-        top: 45%;
-        &::after {
-          content: '';
-          position: absolute;
-          width: 100%;
-          height: 2px;
-          background: repeating-linear-gradient(
-            90deg,
-            #fff 0,
-            #fff 10px,
-            transparent 10px,
-            transparent 20px
-          );
-        }
-      }
-      
-      &.vertical {
-        width: 8px;
-        height: 100%;
-        left: 60%;
-      }
-      
-      &.side-road {
-        background: #e2e8f0;
-        width: 4px;
-        height: 30%;
-        top: 30%;
-        left: 35%;
-      }
-    }
-  
-    /* 建筑物 */
-    .building {
-      position: absolute;
-      border-radius: 4px;
-      box-shadow: 2px 2px 8px rgba(0,0,0,0.1);
-      
-      &.residential {
-        width: 80px;
-        height: 50px;
-        background: #fff1f2;
-        .windows {
-          display: grid;
-          gap: 4px;
-          padding: 8px;
-          .row {
-            display: flex;
-            gap: 6px;
-            &::before {
-              content: '▮▮';
-              color: #94a3b8;
-              font-size: 0.8em;
-            }
-          }
-        }
-      }
-      
-      &.office {
-        width: 60px;
-        height: 80px;
-        background: #bfdbfe;
-        .logo {
-          position: absolute;
-          bottom: 4px;
-          right: 4px;
-          font-size: 1.2em;
-        }
-      }
-    }
-  
-    /* 公园 */
-    .park {
-      width: 100px;
-      height: 60px;
-      background: #dcfce7;
-      border-radius: 8px;
-      .tree {
-        width: 12px;
-        height: 12px;
-        background: #4d7c0f;
-        clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
-        position: absolute;
-        &:first-child { left: 20%; top: 30% }
-        &:last-child { left: 60%; top: 50% }
-      }
-    }
-  
-    /* 热力点 */
-    .heat-point {
-      position: absolute;
-      width: 32px;
-      height: 32px;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      border-radius: 50%;
-      
-      .pulse {
-        position: absolute;
-        width: 100%;
-        height: 100%;
-        border: 2px solid;
-        border-radius: 50%;
-        animation: pulse 1.5s infinite;
-      }
-      
-      ion-icon {
-        position: relative;
-        z-index: 1;
-        font-size: 1.2em;
-      }
-      
-      &.tool {
-        color: #3b82f6;
-        .pulse { border-color: rgba(59, 130, 246, 0.4) }
-      }
-      
-      &.volunteer {
-        color: #10b981;
-        .pulse { border-color: rgba(16, 185, 129, 0.4) }
-      }
-    }
-  
-    /* 图例 */
-    .map-legend {
-      position: absolute;
-      bottom: 10px;
-      right: 10px;
-      background: rgba(255,255,255,0.9);
-      padding: 8px;
-      border-radius: 8px;
-      
-      .item {
-        display: flex;
-        align-items: center;
-        font-size: 0.8em;
-        margin: 4px 0;
-        
-        .color {
-          width: 12px;
-          height: 12px;
-          display: inline-block;
-          margin-right: 6px;
-          border-radius: 2px;
-          
-          &.residential { background: #fff1f2 }
-          &.office { background: #bfdbfe }
-          &.park { background: #dcfce7 }
-        }
-      }
-    }
-  }
-  
-  @keyframes pulse {
-    0% { transform: scale(0.8); opacity: 1 }
-    100% { transform: scale(2); opacity: 0 }
-  }
+// ... existing code ...
+.add-button {
+  position: fixed;
+  right: 20px;
+  bottom: 80px;
+  width: 56px;
+  height: 56px;
+  border-radius: 50%;
+  background: linear-gradient(135deg, var(--ion-color-primary), var(--ion-color-secondary));
+  box-shadow: 0 4px 12px rgba(0,0,0,0.2);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 100;
+  
+  ion-icon {
+    color: white;
+    font-size: 28px;
+  }
+}

+ 149 - 1
myapp/src/app/tab2/tab2.page.ts

@@ -1,4 +1,7 @@
 import { Component } from '@angular/core';
+import { Router } from '@angular/router';
+import { IonicModule } from '@ionic/angular';
+import { CloudObject, CloudQuery, CloudUser } from 'src/lib/ncloud';
 
 @Component({
   selector: 'app-tab2',
@@ -7,7 +10,152 @@ import { Component } from '@angular/core';
   standalone: false,
 })
 export class Tab2Page {
+  taskList: any[] = [];
+  currentUser: any = {};
+  currentStatus: string = 'inProgress';
 
-  constructor() {}
+  constructor(private router: Router) {
+    this.initUser();
+    this.loadTasks('inProgress');
+  }
 
+  async initUser() {
+    const user = new CloudUser();
+    const currentUser = await user.current();
+    this.currentUser = {
+      username: currentUser?.get('username') || '邻助星',
+      avatar: currentUser?.get('avatar') || 'assets/images/1.jpg'
+    };
+  }
+
+  navigateTo(status: string) {
+    this.currentStatus = status;
+    this.loadTasks(status);
+    this.router.navigate(['/tab2', status]);
+  }
+
+  navigateToCreate() {
+    this.router.navigate(['/create-request']); // 请根据实际路由调整
+  }
+
+  async loadTasks(status: string) {
+    if (status === 'inProgress') {
+        let query = new CloudQuery("Inprogress");
+        const results = await query.find();
+        
+        this.taskList = results.map(item => ({
+            id: item.id,
+            userName: '邻助星',  // 固定用户名
+            userAvatar: this.currentUser.avatar,
+            description: item.get('description'),
+            points: item.get('points'),
+            time: item.get('time') || item.createdAt,
+            type: item.get('type')
+        }));
+    } else if (status === 'completed') {
+        let query = new CloudQuery("Completed");
+        const results = await query.find();
+        
+        this.taskList = results.map(item => ({
+            id: item.id,
+            userName: '邻助星',  // 固定用户名
+            userAvatar: this.currentUser.avatar,
+            description: item.get('description'),
+            points: item.get('points'),
+            startTime: item.get('startTime'),
+            endTime: item.get('endTime'),
+            type: item.get('type')
+        }));
+    } else if (status === 'pending') {
+        let query = new CloudQuery("PendingRequests");
+        const results = await query.find();
+        
+        this.taskList = results.map(item => ({
+            id: item.id,
+            userName: this.currentUser.username || '',
+            userAvatar: this.currentUser.avatar || '',
+            title: item.get('title') || '',
+            description: `${item.get('title') || ''}\n${item.get('topic') || ''}`,
+            points: item.get('points') || 0,
+            time: item.get('time') || item.createdAt || '',
+            type: item.get('type') || 'normal',
+            topic: item.get('topic') || '',
+            status: item.get('type') === 'urgent' ? '紧急' : '普通'
+        }));
+    } else {
+        this.taskList = [];
+    }
+}
+
+  importTestData = async () => {
+    const testData = [
+      {
+        userName: '张阿姨',
+        userAvatar: 'https://ionicframework.com/docs/img/demos/avatar.svg',
+        description: '需要帮忙修理水龙头',
+        type: 'normal',
+        time: new Date(Date.now() - Math.floor(Math.random() * 7 * 24 * 60 * 60 * 1000)),
+        points: 10,
+        status: 'pending'
+      },
+      {
+        userName: '李大爷',
+        userAvatar: 'https://ionicframework.com/docs/img/demos/avatar.svg',
+        description: '求购降压药',
+        type: 'emergency',
+        time: new Date(Date.now() - Math.floor(Math.random() * 7 * 24 * 60 * 60 * 1000)),
+        points: 20,
+        status: 'completed'
+      },
+      {
+        userName: '王阿姨',
+        userAvatar: 'https://ionicframework.com/docs/img/demos/avatar.svg',
+        description: '需要家政清洁',
+        type: 'normal',
+        time: new Date(Date.now() - Math.floor(Math.random() * 7 * 24 * 60 * 60 * 1000)),
+        points: 15,
+        status: 'inProgress'
+      }
+    ];
+    
+    for (const data of testData) {
+      const obj = new CloudObject("Inprogress");
+      obj.set(data);
+      await obj.save();
+    }
+    
+    this.loadTasks(this.currentStatus);
+  }
+
+  completeTask = async (task: any) => {
+    try {
+      const obj = new CloudObject("Inprogress");
+      obj.id = task.id;
+      await obj.destroy();
+  
+      const completedTask = new CloudObject("Completed");
+      completedTask.set({
+        userName: task.userName,
+        userAvatar: task.userAvatar,
+        description: task.description,
+        points: task.points,
+        startTime: task.time,
+        endTime: new Date(),
+        type: task.type
+      });
+      await completedTask.save();
+  
+      this.loadTasks('inProgress');
+    } catch (error) {
+      console.error('完成任务出错:', error);
+    }
+  }
+
+  startChat(item: any) {
+    this.router.navigate(['/chat', item.userName]); // 修改为直接传递用户名参数
+  }
 }
+
+  
+
+

+ 36 - 15
myapp/src/app/tab5/user-dashboard.page.html

@@ -1,28 +1,49 @@
 <ion-header>
   <ion-toolbar>
     <ion-title>用户面板</ion-title>
-    <ion-buttons slot="end">
-      <ion-button (click)="logout()">登出</ion-button>
-    </ion-buttons>
   </ion-toolbar>
 </ion-header>
 
-<ion-content class="ion-padding">
-  <ion-card>
-    <ion-card-header>
-      <ion-card-title>欢迎, {{currentUser?.data?.username}}</ion-card-title>
+<ion-content class="dashboard-content">
+  <div class="profile-card">
+    <div class="profile-buttons">
+      <ion-button fill="clear" (click)="goToAIAgent()">
+        <ion-icon name="chatbubble-ellipses" slot="icon-only"></ion-icon>
+      </ion-button>
+      <ion-button fill="clear" (click)="logout()">
+        <ion-icon name="settings" slot="icon-only"></ion-icon>
+      </ion-button>
+    </div>
+    <div class="profile-content">
       <ion-avatar class="user-avatar">
         <img [src]="currentUser?.data?.avatar || 'assets/images/1.jpg'" alt="用户头像"/>
       </ion-avatar>
-    </ion-card-header>
-    <ion-card-content>
-      <p>用户ID: {{currentUser?.id}}</p>
-      <p>注册时间: {{currentUser?.data?.createdAt | date}}</p>
-      <p>邮箱: {{currentUser?.data?.email}}</p>
-    </ion-card-content>
-  </ion-card>
+      <h2 class="username">{{currentUser?.data?.username}}</h2>
+      <p class="email">{{currentUser?.data?.email}}</p>
+      <ion-button class="profile-btn" expand="block" (click)="goToEditProfile()">个人资料</ion-button>
+    </div>
+  </div>
 
-  <ion-button expand="block" (click)="goToEditProfile()">个人资料</ion-button>
+  <!-- 添加积分卡片 -->
+  <div class="points-container">
+    <ion-card class="points-card">
+      <ion-card-content>
+        <div class="points-content">
+          <div class="points-text">
+            <h3>我的积分</h3>
+            <p class="points-value">1000</p>
+          </div>
+          <ion-icon name="coin" class="points-icon"></ion-icon>
+        </div>
+      </ion-card-content>
+    </ion-card>
+  
+    <ion-card class="withdraw-card" (click)="showWithdrawAlert()">
+      <ion-card-content>
+        <h3>积  分  提  现</h3>
+      </ion-card-content>
+    </ion-card>
+  </div>
 
   <!-- 添加我的资质框 -->
   <ion-card>

+ 121 - 0
myapp/src/app/tab5/user-dashboard.page.scss

@@ -1,3 +1,54 @@
+.dashboard-content {
+  --background: #f5f5f5;
+}
+
+.profile-card {
+  height: 35%;
+  background: linear-gradient(135deg, #4b6cb7 0%, #182848 100%);
+  position: relative;
+  overflow: hidden;
+  border-radius: 0 0 50% 50% / 0 0 20% 20%;
+  
+  .profile-content {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    width: 100%;
+    text-align: center;
+    color: white;
+    padding: 0 20px;
+  }
+}
+
+.user-avatar {
+  width: 80px;
+  height: 80px;
+  margin: 0 auto 15px;
+  border: 3px solid white;
+  box-shadow: 0 4px 8px rgba(0,0,0,0.2);
+}
+
+.username {
+  font-size: 1.2rem;
+  font-weight: bold;
+  margin-bottom: 5px;
+}
+
+.email {
+  font-size: 0.9rem;
+  opacity: 0.8;
+  margin-bottom: 15px;
+}
+
+.profile-btn {
+  --background: white;
+  --color: #4b6cb7;
+  max-width: 200px;
+  margin: 0 auto;
+  font-weight: bold;
+}
+
 .user-avatar {
   width: 80px;
   height: 80px;
@@ -8,4 +59,74 @@
     border: 2px solid var(--ion-color-primary);
     border-radius: 50%;
   }
+}
+
+.profile-buttons {
+  position: absolute;
+  top: 10px;
+  right: 10px;
+  z-index: 10;
+  
+  ion-button {
+    --color: white;
+    --background-hover: rgba(255,255,255,0.1);
+  }
+}
+
+/* 积分卡片样式 */
+.points-container {
+  display: flex;
+  justify-content: space-between;
+  padding: 16px;
+  gap: 16px;
+}
+
+.points-card, .withdraw-card {
+  flex: 1;
+  border-radius: 12px;
+  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
+}
+
+.points-card {
+  background: linear-gradient(135deg, #ff9a9e 0%, #fad0c4 100%);
+  
+  .points-content {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+  
+  .points-icon {
+    font-size: 32px;
+    color: #f31919;
+  }
+  
+  .points-value {
+    font-size: 24px;
+    font-weight: bold;
+    margin-top: 8px;
+    color: #fff;
+  }
+}
+
+.withdraw-card {
+  background: linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  
+  h3 {
+    color: #2c3e50;
+    text-align: center;
+    font-family: 'Arial', sans-serif;
+    font-weight: bold;
+    font-size: 1.2rem;
+    text-shadow: 1px 1px 2px rgba(0,0,0,0.2);
+    letter-spacing: 1px;
+    background: linear-gradient(to right, #2c3e50, #4b6cb7);
+    -webkit-background-clip: text;
+    background-clip: text;
+    color: transparent;
+    padding: 5px;
+  }
 }

+ 19 - 1
myapp/src/app/tab5/user-dashboard.page.ts

@@ -5,6 +5,7 @@ import { IonicModule } from '@ionic/angular';
 import { CommonModule } from '@angular/common';
 import { ModalController } from '@ionic/angular'; // 导入 ModalController
 import { EditProfileComponent } from './edit-profile.component'; // 假设编辑资料组件名为 EditProfileComponent
+import { AlertController } from '@ionic/angular';
 
 @Component({
   selector: 'app-user-dashboard',
@@ -24,7 +25,11 @@ export class UserDashboardPage {
   // 修改为CloudObject数组类型
   qualification: CloudObject[] = [];
 
-  constructor(private router: Router, private modalCtrl: ModalController) {
+  constructor(
+    private router: Router, 
+    private modalCtrl: ModalController,
+    private alertCtrl: AlertController
+  ) {
     this.getCurrentUser();
   }
 
@@ -126,4 +131,17 @@ export class UserDashboardPage {
     };
     input.click();
   }
+
+  goToAIAgent() {
+    this.router.navigate(['/ai-agent']);
+  }
+  
+  async showWithdrawAlert() {
+    const alert = await this.alertCtrl.create({
+      header: '提示',
+      message: '暂未开放提现通道',
+      buttons: ['确定']
+    });
+    await alert.present();
+  }
 }

BIN
myapp/src/assets/images/aipic.jpg


BIN
myapp/src/assets/images/banner1.jpg


BIN
myapp/src/assets/images/banner2.jpg


BIN
myapp/src/assets/images/banner3.jpg


BIN
myapp/src/assets/images/eventspic.jpg


BIN
myapp/src/assets/images/mypic.jpg


BIN
myapp/src/assets/images/toolspic.jpg


+ 18 - 3
myapp/src/global.scss

@@ -51,9 +51,24 @@ html, body {
 }
 
 ion-app {
-  height: 100vh; /* 改为全屏高度 */
-  width: 100vw; /* 改为全屏宽度 */
-  max-width: none; /* 移除最大宽度限制 */
+  height: 100vh;
+  width: 100vw;
+  max-width: none;
+  display: flex;
+  flex-direction: column;
+}
+
+ion-router-outlet {
+  flex: 1;
+  overflow: auto;
+  padding-bottom: 56px; /* 留出标签栏高度 */
+}
+
+ion-tab-bar {
+  position: fixed;
+  bottom: 0;
+  width: 100%;
+  z-index: 1000;
 }
 
 /* 全局放大设置 */

+ 22 - 0
myapp/src/lib/ncloud.ts

@@ -6,6 +6,15 @@ if (location.protocol == "http:") {
 }
 
 export class CloudObject {
+    static find(arg0: string, arg1: { order: { createdAt: string; }; limit: number; }) {
+        throw new Error('Method not implemented.');
+    }
+    static query(arg0: string) {
+        throw new Error('Method not implemented.');
+    }
+  delete() {
+    throw new Error('Method not implemented.');
+  }
     className: string;
     id: string | undefined = undefined;
     createdAt: any;
@@ -15,6 +24,7 @@ export class CloudObject {
      uploadTime: string | undefined; 
      certTime: string | undefined; 
      status?: string | undefined; 
+  static Batch: any;
 
     constructor(className: string) {
         this.className = className;
@@ -91,6 +101,18 @@ export class CloudObject {
 
 // CloudQuery.ts
 export class CloudQuery {
+    static query(arg0: string) {
+        throw new Error('Method not implemented.');
+    }
+    limit(arg0: number) {
+        throw new Error('Method not implemented.');
+    }
+    orderByDescending(arg0: string) {
+        throw new Error('Method not implemented.');
+    }
+  save(item: any) {
+    throw new Error('Method not implemented.');
+  }
     className: string;
     queryParams: Record<string, any> = { where: {} };
   where: any;

+ 0 - 16
node_modules/.bin/mkdirp

@@ -1,16 +0,0 @@
-#!/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/../mkdirp/bin/cmd.js" "$@"
-else 
-  exec node  "$basedir/../mkdirp/bin/cmd.js" "$@"
-fi

+ 0 - 17
node_modules/.bin/mkdirp.cmd

@@ -1,17 +0,0 @@
-@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%\..\mkdirp\bin\cmd.js" %*

+ 0 - 28
node_modules/.bin/mkdirp.ps1

@@ -1,28 +0,0 @@
-#!/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/../mkdirp/bin/cmd.js" $args
-  } else {
-    & "$basedir/node$exe"  "$basedir/../mkdirp/bin/cmd.js" $args
-  }
-  $ret=$LASTEXITCODE
-} else {
-  # Support pipeline input
-  if ($MyInvocation.ExpectingInput) {
-    $input | & "node$exe"  "$basedir/../mkdirp/bin/cmd.js" $args
-  } else {
-    & "node$exe"  "$basedir/../mkdirp/bin/cmd.js" $args
-  }
-  $ret=$LASTEXITCODE
-}
-exit $ret

+ 0 - 219
node_modules/.package-lock.json

@@ -1,219 +0,0 @@
-{
-  "name": "workspace",
-  "lockfileVersion": 3,
-  "requires": true,
-  "packages": {
-    "node_modules/append-field": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmmirror.com/append-field/-/append-field-1.0.0.tgz",
-      "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
-      "license": "MIT"
-    },
-    "node_modules/buffer-from": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz",
-      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
-      "license": "MIT"
-    },
-    "node_modules/busboy": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmmirror.com/busboy/-/busboy-1.6.0.tgz",
-      "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
-      "dependencies": {
-        "streamsearch": "^1.1.0"
-      },
-      "engines": {
-        "node": ">=10.16.0"
-      }
-    },
-    "node_modules/concat-stream": {
-      "version": "1.6.2",
-      "resolved": "https://registry.npmmirror.com/concat-stream/-/concat-stream-1.6.2.tgz",
-      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
-      "engines": [
-        "node >= 0.8"
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "buffer-from": "^1.0.0",
-        "inherits": "^2.0.3",
-        "readable-stream": "^2.2.2",
-        "typedarray": "^0.0.6"
-      }
-    },
-    "node_modules/core-util-is": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz",
-      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
-      "license": "MIT"
-    },
-    "node_modules/inherits": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-      "license": "ISC"
-    },
-    "node_modules/isarray": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz",
-      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
-      "license": "MIT"
-    },
-    "node_modules/media-typer": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz",
-      "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.6"
-      }
-    },
-    "node_modules/mime-db": {
-      "version": "1.52.0",
-      "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
-      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.6"
-      }
-    },
-    "node_modules/mime-types": {
-      "version": "2.1.35",
-      "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
-      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
-      "license": "MIT",
-      "dependencies": {
-        "mime-db": "1.52.0"
-      },
-      "engines": {
-        "node": ">= 0.6"
-      }
-    },
-    "node_modules/minimist": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz",
-      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/mkdirp": {
-      "version": "0.5.6",
-      "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz",
-      "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
-      "license": "MIT",
-      "dependencies": {
-        "minimist": "^1.2.6"
-      },
-      "bin": {
-        "mkdirp": "bin/cmd.js"
-      }
-    },
-    "node_modules/multer": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmmirror.com/multer/-/multer-2.0.0.tgz",
-      "integrity": "sha512-bS8rPZurbAuHGAnApbM9d4h1wSoYqrOqkE+6a64KLMK9yWU7gJXBDDVklKQ3TPi9DRb85cRs6yXaC0+cjxRtRg==",
-      "license": "MIT",
-      "dependencies": {
-        "append-field": "^1.0.0",
-        "busboy": "^1.0.0",
-        "concat-stream": "^1.5.2",
-        "mkdirp": "^0.5.4",
-        "object-assign": "^4.1.1",
-        "type-is": "^1.6.4",
-        "xtend": "^4.0.0"
-      },
-      "engines": {
-        "node": ">= 10.16.0"
-      }
-    },
-    "node_modules/object-assign": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/process-nextick-args": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
-      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
-      "license": "MIT"
-    },
-    "node_modules/readable-stream": {
-      "version": "2.3.8",
-      "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz",
-      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
-      "license": "MIT",
-      "dependencies": {
-        "core-util-is": "~1.0.0",
-        "inherits": "~2.0.3",
-        "isarray": "~1.0.0",
-        "process-nextick-args": "~2.0.0",
-        "safe-buffer": "~5.1.1",
-        "string_decoder": "~1.1.1",
-        "util-deprecate": "~1.0.1"
-      }
-    },
-    "node_modules/safe-buffer": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-      "license": "MIT"
-    },
-    "node_modules/streamsearch": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmmirror.com/streamsearch/-/streamsearch-1.1.0.tgz",
-      "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
-      "engines": {
-        "node": ">=10.0.0"
-      }
-    },
-    "node_modules/string_decoder": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz",
-      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-      "license": "MIT",
-      "dependencies": {
-        "safe-buffer": "~5.1.0"
-      }
-    },
-    "node_modules/type-is": {
-      "version": "1.6.18",
-      "resolved": "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz",
-      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
-      "license": "MIT",
-      "dependencies": {
-        "media-typer": "0.3.0",
-        "mime-types": "~2.1.24"
-      },
-      "engines": {
-        "node": ">= 0.6"
-      }
-    },
-    "node_modules/typedarray": {
-      "version": "0.0.6",
-      "resolved": "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz",
-      "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
-      "license": "MIT"
-    },
-    "node_modules/util-deprecate": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
-      "license": "MIT"
-    },
-    "node_modules/xtend": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz",
-      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=0.4"
-      }
-    }
-  }
-}

+ 0 - 1
node_modules/append-field/.npmignore

@@ -1 +0,0 @@
-node_modules/

+ 0 - 21
node_modules/append-field/LICENSE

@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 Linus Unnebäck
-
-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.

+ 0 - 44
node_modules/append-field/README.md

@@ -1,44 +0,0 @@
-# `append-field`
-
-A [W3C HTML JSON forms spec](http://www.w3.org/TR/html-json-forms/) compliant
-field appender (for lack of a better name). Useful for people implementing
-`application/x-www-form-urlencoded` and `multipart/form-data` parsers.
-
-It works best on objects created with `Object.create(null)`. Otherwise it might
-conflict with variables from the prototype (e.g. `hasOwnProperty`).
-
-## Installation
-
-```sh
-npm install --save append-field
-```
-
-## Usage
-
-```javascript
-var appendField = require('append-field')
-var obj = Object.create(null)
-
-appendField(obj, 'pets[0][species]', 'Dahut')
-appendField(obj, 'pets[0][name]', 'Hypatia')
-appendField(obj, 'pets[1][species]', 'Felis Stultus')
-appendField(obj, 'pets[1][name]', 'Billie')
-
-console.log(obj)
-```
-
-```text
-{ pets:
-   [ { species: 'Dahut', name: 'Hypatia' },
-     { species: 'Felis Stultus', name: 'Billie' } ] }
-```
-
-## API
-
-### `appendField(store, key, value)`
-
-Adds the field named `key` with the value `value` to the object `store`.
-
-## License
-
-MIT

+ 0 - 12
node_modules/append-field/index.js

@@ -1,12 +0,0 @@
-var parsePath = require('./lib/parse-path')
-var setValue = require('./lib/set-value')
-
-function appendField (store, key, value) {
-  var steps = parsePath(key)
-
-  steps.reduce(function (context, step) {
-    return setValue(context, step, context[step.key], value)
-  }, store)
-}
-
-module.exports = appendField

+ 0 - 53
node_modules/append-field/lib/parse-path.js

@@ -1,53 +0,0 @@
-var reFirstKey = /^[^\[]*/
-var reDigitPath = /^\[(\d+)\]/
-var reNormalPath = /^\[([^\]]+)\]/
-
-function parsePath (key) {
-  function failure () {
-    return [{ type: 'object', key: key, last: true }]
-  }
-
-  var firstKey = reFirstKey.exec(key)[0]
-  if (!firstKey) return failure()
-
-  var len = key.length
-  var pos = firstKey.length
-  var tail = { type: 'object', key: firstKey }
-  var steps = [tail]
-
-  while (pos < len) {
-    var m
-
-    if (key[pos] === '[' && key[pos + 1] === ']') {
-      pos += 2
-      tail.append = true
-      if (pos !== len) return failure()
-      continue
-    }
-
-    m = reDigitPath.exec(key.substring(pos))
-    if (m !== null) {
-      pos += m[0].length
-      tail.nextType = 'array'
-      tail = { type: 'array', key: parseInt(m[1], 10) }
-      steps.push(tail)
-      continue
-    }
-
-    m = reNormalPath.exec(key.substring(pos))
-    if (m !== null) {
-      pos += m[0].length
-      tail.nextType = 'object'
-      tail = { type: 'object', key: m[1] }
-      steps.push(tail)
-      continue
-    }
-
-    return failure()
-  }
-
-  tail.last = true
-  return steps
-}
-
-module.exports = parsePath

+ 0 - 64
node_modules/append-field/lib/set-value.js

@@ -1,64 +0,0 @@
-function valueType (value) {
-  if (value === undefined) return 'undefined'
-  if (Array.isArray(value)) return 'array'
-  if (typeof value === 'object') return 'object'
-  return 'scalar'
-}
-
-function setLastValue (context, step, currentValue, entryValue) {
-  switch (valueType(currentValue)) {
-    case 'undefined':
-      if (step.append) {
-        context[step.key] = [entryValue]
-      } else {
-        context[step.key] = entryValue
-      }
-      break
-    case 'array':
-      context[step.key].push(entryValue)
-      break
-    case 'object':
-      return setLastValue(currentValue, { type: 'object', key: '', last: true }, currentValue[''], entryValue)
-    case 'scalar':
-      context[step.key] = [context[step.key], entryValue]
-      break
-  }
-
-  return context
-}
-
-function setValue (context, step, currentValue, entryValue) {
-  if (step.last) return setLastValue(context, step, currentValue, entryValue)
-
-  var obj
-  switch (valueType(currentValue)) {
-    case 'undefined':
-      if (step.nextType === 'array') {
-        context[step.key] = []
-      } else {
-        context[step.key] = Object.create(null)
-      }
-      return context[step.key]
-    case 'object':
-      return context[step.key]
-    case 'array':
-      if (step.nextType === 'array') {
-        return currentValue
-      }
-
-      obj = Object.create(null)
-      context[step.key] = obj
-      currentValue.forEach(function (item, i) {
-        if (item !== undefined) obj['' + i] = item
-      })
-
-      return obj
-    case 'scalar':
-      obj = Object.create(null)
-      obj[''] = currentValue
-      context[step.key] = obj
-      return obj
-  }
-}
-
-module.exports = setValue

+ 0 - 19
node_modules/append-field/package.json

@@ -1,19 +0,0 @@
-{
-  "name": "append-field",
-  "version": "1.0.0",
-  "license": "MIT",
-  "author": "Linus Unnebäck <linus@folkdatorn.se>",
-  "main": "index.js",
-  "devDependencies": {
-    "mocha": "^2.2.4",
-    "standard": "^6.0.5",
-    "testdata-w3c-json-form": "^0.2.0"
-  },
-  "scripts": {
-    "test": "standard && mocha"
-  },
-  "repository": {
-    "type": "git",
-    "url": "http://github.com/LinusU/node-append-field.git"
-  }
-}

+ 0 - 19
node_modules/append-field/test/forms.js

@@ -1,19 +0,0 @@
-/* eslint-env mocha */
-
-var assert = require('assert')
-var appendField = require('../')
-var testData = require('testdata-w3c-json-form')
-
-describe('Append Field', function () {
-  for (var test of testData) {
-    it('handles ' + test.name, function () {
-      var store = Object.create(null)
-
-      for (var field of test.fields) {
-        appendField(store, field.key, field.value)
-      }
-
-      assert.deepEqual(store, test.expected)
-    })
-  }
-})

+ 0 - 21
node_modules/buffer-from/LICENSE

@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2016, 2018 Linus Unnebäck
-
-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.

+ 0 - 72
node_modules/buffer-from/index.js

@@ -1,72 +0,0 @@
-/* eslint-disable node/no-deprecated-api */
-
-var toString = Object.prototype.toString
-
-var isModern = (
-  typeof Buffer !== 'undefined' &&
-  typeof Buffer.alloc === 'function' &&
-  typeof Buffer.allocUnsafe === 'function' &&
-  typeof Buffer.from === 'function'
-)
-
-function isArrayBuffer (input) {
-  return toString.call(input).slice(8, -1) === 'ArrayBuffer'
-}
-
-function fromArrayBuffer (obj, byteOffset, length) {
-  byteOffset >>>= 0
-
-  var maxLength = obj.byteLength - byteOffset
-
-  if (maxLength < 0) {
-    throw new RangeError("'offset' is out of bounds")
-  }
-
-  if (length === undefined) {
-    length = maxLength
-  } else {
-    length >>>= 0
-
-    if (length > maxLength) {
-      throw new RangeError("'length' is out of bounds")
-    }
-  }
-
-  return isModern
-    ? Buffer.from(obj.slice(byteOffset, byteOffset + length))
-    : new Buffer(new Uint8Array(obj.slice(byteOffset, byteOffset + length)))
-}
-
-function fromString (string, encoding) {
-  if (typeof encoding !== 'string' || encoding === '') {
-    encoding = 'utf8'
-  }
-
-  if (!Buffer.isEncoding(encoding)) {
-    throw new TypeError('"encoding" must be a valid string encoding')
-  }
-
-  return isModern
-    ? Buffer.from(string, encoding)
-    : new Buffer(string, encoding)
-}
-
-function bufferFrom (value, encodingOrOffset, length) {
-  if (typeof value === 'number') {
-    throw new TypeError('"value" argument must not be a number')
-  }
-
-  if (isArrayBuffer(value)) {
-    return fromArrayBuffer(value, encodingOrOffset, length)
-  }
-
-  if (typeof value === 'string') {
-    return fromString(value, encodingOrOffset)
-  }
-
-  return isModern
-    ? Buffer.from(value)
-    : new Buffer(value)
-}
-
-module.exports = bufferFrom

+ 0 - 19
node_modules/buffer-from/package.json

@@ -1,19 +0,0 @@
-{
-  "name": "buffer-from",
-  "version": "1.1.2",
-  "license": "MIT",
-  "repository": "LinusU/buffer-from",
-  "files": [
-    "index.js"
-  ],
-  "scripts": {
-    "test": "standard && node test"
-  },
-  "devDependencies": {
-    "standard": "^12.0.1"
-  },
-  "keywords": [
-    "buffer",
-    "buffer from"
-  ]
-}

+ 0 - 69
node_modules/buffer-from/readme.md

@@ -1,69 +0,0 @@
-# Buffer From
-
-A [ponyfill](https://ponyfill.com) for `Buffer.from`, uses native implementation if available.
-
-## Installation
-
-```sh
-npm install --save buffer-from
-```
-
-## Usage
-
-```js
-const bufferFrom = require('buffer-from')
-
-console.log(bufferFrom([1, 2, 3, 4]))
-//=> <Buffer 01 02 03 04>
-
-const arr = new Uint8Array([1, 2, 3, 4])
-console.log(bufferFrom(arr.buffer, 1, 2))
-//=> <Buffer 02 03>
-
-console.log(bufferFrom('test', 'utf8'))
-//=> <Buffer 74 65 73 74>
-
-const buf = bufferFrom('test')
-console.log(bufferFrom(buf))
-//=> <Buffer 74 65 73 74>
-```
-
-## API
-
-### bufferFrom(array)
-
-- `array` &lt;Array&gt;
-
-Allocates a new `Buffer` using an `array` of octets.
-
-### bufferFrom(arrayBuffer[, byteOffset[, length]])
-
-- `arrayBuffer` &lt;ArrayBuffer&gt; The `.buffer` property of a TypedArray or ArrayBuffer
-- `byteOffset` &lt;Integer&gt; Where to start copying from `arrayBuffer`. **Default:** `0`
-- `length` &lt;Integer&gt; How many bytes to copy from `arrayBuffer`. **Default:** `arrayBuffer.length - byteOffset`
-
-When passed a reference to the `.buffer` property of a TypedArray instance, the
-newly created `Buffer` will share the same allocated memory as the TypedArray.
-
-The optional `byteOffset` and `length` arguments specify a memory range within
-the `arrayBuffer` that will be shared by the `Buffer`.
-
-### bufferFrom(buffer)
-
-- `buffer` &lt;Buffer&gt; An existing `Buffer` to copy data from
-
-Copies the passed `buffer` data onto a new `Buffer` instance.
-
-### bufferFrom(string[, encoding])
-
-- `string` &lt;String&gt; A string to encode.
-- `encoding` &lt;String&gt; The encoding of `string`. **Default:** `'utf8'`
-
-Creates a new `Buffer` containing the given JavaScript string `string`. If
-provided, the `encoding` parameter identifies the character encoding of
-`string`.
-
-## See also
-
-- [buffer-alloc](https://github.com/LinusU/buffer-alloc) A ponyfill for `Buffer.alloc`
-- [buffer-alloc-unsafe](https://github.com/LinusU/buffer-alloc-unsafe) A ponyfill for `Buffer.allocUnsafe`

+ 0 - 5
node_modules/busboy/.eslintrc.js

@@ -1,5 +0,0 @@
-'use strict';
-
-module.exports = {
-  extends: '@mscdex/eslint-config',
-};

+ 0 - 24
node_modules/busboy/.github/workflows/ci.yml

@@ -1,24 +0,0 @@
-name: CI
-
-on:
-  pull_request:
-  push:
-    branches: [ master ]
-
-jobs:
-  tests-linux:
-    runs-on: ubuntu-latest
-    strategy:
-      fail-fast: false
-      matrix:
-        node-version: [10.16.0, 10.x, 12.x, 14.x, 16.x]
-    steps:
-      - uses: actions/checkout@v2
-      - name: Use Node.js ${{ matrix.node-version }}
-        uses: actions/setup-node@v1
-        with:
-          node-version: ${{ matrix.node-version }}
-      - name: Install module
-        run: npm install
-      - name: Run tests
-        run: npm test

+ 0 - 23
node_modules/busboy/.github/workflows/lint.yml

@@ -1,23 +0,0 @@
-name: lint
-
-on:
-  pull_request:
-  push:
-    branches: [ master ]
-
-env:
-  NODE_VERSION: 16.x
-
-jobs:
-  lint-js:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-      - name: Use Node.js ${{ env.NODE_VERSION }}
-        uses: actions/setup-node@v1
-        with:
-          node-version: ${{ env.NODE_VERSION }}
-      - name: Install ESLint + ESLint configs/plugins
-        run: npm install --only=dev
-      - name: Lint files
-        run: npm run lint

+ 0 - 19
node_modules/busboy/LICENSE

@@ -1,19 +0,0 @@
-Copyright Brian White. All rights reserved.
-
-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.

+ 0 - 191
node_modules/busboy/README.md

@@ -1,191 +0,0 @@
-# Description
-
-A node.js module for parsing incoming HTML form data.
-
-Changes (breaking or otherwise) in v1.0.0 can be found [here](https://github.com/mscdex/busboy/issues/266).
-
-# Requirements
-
-* [node.js](http://nodejs.org/) -- v10.16.0 or newer
-
-
-# Install
-
-    npm install busboy
-
-
-# Examples
-
-* Parsing (multipart) with default options:
-
-```js
-const http = require('http');
-
-const busboy = require('busboy');
-
-http.createServer((req, res) => {
-  if (req.method === 'POST') {
-    console.log('POST request');
-    const bb = busboy({ headers: req.headers });
-    bb.on('file', (name, file, info) => {
-      const { filename, encoding, mimeType } = info;
-      console.log(
-        `File [${name}]: filename: %j, encoding: %j, mimeType: %j`,
-        filename,
-        encoding,
-        mimeType
-      );
-      file.on('data', (data) => {
-        console.log(`File [${name}] got ${data.length} bytes`);
-      }).on('close', () => {
-        console.log(`File [${name}] done`);
-      });
-    });
-    bb.on('field', (name, val, info) => {
-      console.log(`Field [${name}]: value: %j`, val);
-    });
-    bb.on('close', () => {
-      console.log('Done parsing form!');
-      res.writeHead(303, { Connection: 'close', Location: '/' });
-      res.end();
-    });
-    req.pipe(bb);
-  } else if (req.method === 'GET') {
-    res.writeHead(200, { Connection: 'close' });
-    res.end(`
-      <html>
-        <head></head>
-        <body>
-          <form method="POST" enctype="multipart/form-data">
-            <input type="file" name="filefield"><br />
-            <input type="text" name="textfield"><br />
-            <input type="submit">
-          </form>
-        </body>
-      </html>
-    `);
-  }
-}).listen(8000, () => {
-  console.log('Listening for requests');
-});
-
-// Example output:
-//
-// Listening for requests
-//   < ... form submitted ... >
-// POST request
-// File [filefield]: filename: "logo.jpg", encoding: "binary", mime: "image/jpeg"
-// File [filefield] got 11912 bytes
-// Field [textfield]: value: "testing! :-)"
-// File [filefield] done
-// Done parsing form!
-```
-
-* Save all incoming files to disk:
-
-```js
-const { randomFillSync } = require('crypto');
-const fs = require('fs');
-const http = require('http');
-const os = require('os');
-const path = require('path');
-
-const busboy = require('busboy');
-
-const random = (() => {
-  const buf = Buffer.alloc(16);
-  return () => randomFillSync(buf).toString('hex');
-})();
-
-http.createServer((req, res) => {
-  if (req.method === 'POST') {
-    const bb = busboy({ headers: req.headers });
-    bb.on('file', (name, file, info) => {
-      const saveTo = path.join(os.tmpdir(), `busboy-upload-${random()}`);
-      file.pipe(fs.createWriteStream(saveTo));
-    });
-    bb.on('close', () => {
-      res.writeHead(200, { 'Connection': 'close' });
-      res.end(`That's all folks!`);
-    });
-    req.pipe(bb);
-    return;
-  }
-  res.writeHead(404);
-  res.end();
-}).listen(8000, () => {
-  console.log('Listening for requests');
-});
-```
-
-
-# API
-
-## Exports
-
-`busboy` exports a single function:
-
-**( _function_ )**(< _object_ >config) - Creates and returns a new _Writable_ form parser stream.
-
-* Valid `config` properties:
-
-    * **headers** - _object_ - These are the HTTP headers of the incoming request, which are used by individual parsers.
-
-    * **highWaterMark** - _integer_ - highWaterMark to use for the parser stream. **Default:** node's _stream.Writable_ default.
-
-    * **fileHwm** - _integer_ - highWaterMark to use for individual file streams. **Default:** node's _stream.Readable_ default.
-
-    * **defCharset** - _string_ - Default character set to use when one isn't defined. **Default:** `'utf8'`.
-
-    * **defParamCharset** - _string_ - For multipart forms, the default character set to use for values of part header parameters (e.g. filename) that are not extended parameters (that contain an explicit charset). **Default:** `'latin1'`.
-
-    * **preservePath** - _boolean_ - If paths in filenames from file parts in a `'multipart/form-data'` request shall be preserved. **Default:** `false`.
-
-    * **limits** - _object_ - Various limits on incoming data. Valid properties are:
-
-        * **fieldNameSize** - _integer_ - Max field name size (in bytes). **Default:** `100`.
-
-        * **fieldSize** - _integer_ - Max field value size (in bytes). **Default:** `1048576` (1MB).
-
-        * **fields** - _integer_ - Max number of non-file fields. **Default:** `Infinity`.
-
-        * **fileSize** - _integer_ - For multipart forms, the max file size (in bytes). **Default:** `Infinity`.
-
-        * **files** - _integer_ - For multipart forms, the max number of file fields. **Default:** `Infinity`.
-
-        * **parts** - _integer_ - For multipart forms, the max number of parts (fields + files). **Default:** `Infinity`.
-
-        * **headerPairs** - _integer_ - For multipart forms, the max number of header key-value pairs to parse. **Default:** `2000` (same as node's http module).
-
-This function can throw exceptions if there is something wrong with the values in `config`. For example, if the Content-Type in `headers` is missing entirely, is not a supported type, or is missing the boundary for `'multipart/form-data'` requests.
-
-## (Special) Parser stream events
-
-* **file**(< _string_ >name, < _Readable_ >stream, < _object_ >info) - Emitted for each new file found. `name` contains the form field name. `stream` is a _Readable_ stream containing the file's data. No transformations/conversions (e.g. base64 to raw binary) are done on the file's data. `info` contains the following properties:
-
-    * `filename` - _string_ - If supplied, this contains the file's filename. **WARNING:** You should almost _never_ use this value as-is (especially if you are using `preservePath: true` in your `config`) as it could contain malicious input. You are better off generating your own (safe) filenames, or at the very least using a hash of the filename.
-
-    * `encoding` - _string_ - The file's `'Content-Transfer-Encoding'` value.
-
-    * `mimeType` - _string_ - The file's `'Content-Type'` value.
-
-    **Note:** If you listen for this event, you should always consume the `stream` whether you care about its contents or not (you can simply do `stream.resume();` if you want to discard/skip the contents), otherwise the `'finish'`/`'close'` event will never fire on the busboy parser stream.
-    However, if you aren't accepting files, you can either simply not listen for the `'file'` event at all or set `limits.files` to `0`, and any/all files will be automatically skipped (these skipped files will still count towards any configured `limits.files` and `limits.parts` limits though).
-
-    **Note:** If a configured `limits.fileSize` limit was reached for a file, `stream` will both have a boolean property `truncated` set to `true` (best checked at the end of the stream) and emit a `'limit'` event to notify you when this happens.
-
-* **field**(< _string_ >name, < _string_ >value, < _object_ >info) - Emitted for each new non-file field found. `name` contains the form field name. `value` contains the string value of the field. `info` contains the following properties:
-
-    * `nameTruncated` - _boolean_ - Whether `name` was truncated or not (due to a configured `limits.fieldNameSize` limit)
-
-    * `valueTruncated` - _boolean_ - Whether `value` was truncated or not (due to a configured `limits.fieldSize` limit)
-
-    * `encoding` - _string_ - The field's `'Content-Transfer-Encoding'` value.
-
-    * `mimeType` - _string_ - The field's `'Content-Type'` value.
-
-* **partsLimit**() - Emitted when the configured `limits.parts` limit has been reached. No more `'file'` or `'field'` events will be emitted.
-
-* **filesLimit**() - Emitted when the configured `limits.files` limit has been reached. No more `'file'` events will be emitted.
-
-* **fieldsLimit**() - Emitted when the configured `limits.fields` limit has been reached. No more `'field'` events will be emitted.

+ 0 - 149
node_modules/busboy/bench/bench-multipart-fields-100mb-big.js

@@ -1,149 +0,0 @@
-'use strict';
-
-function createMultipartBuffers(boundary, sizes) {
-  const bufs = [];
-  for (let i = 0; i < sizes.length; ++i) {
-    const mb = sizes[i] * 1024 * 1024;
-    bufs.push(Buffer.from([
-      `--${boundary}`,
-      `content-disposition: form-data; name="field${i + 1}"`,
-      '',
-      '0'.repeat(mb),
-      '',
-    ].join('\r\n')));
-  }
-  bufs.push(Buffer.from([
-    `--${boundary}--`,
-    '',
-  ].join('\r\n')));
-  return bufs;
-}
-
-const boundary = '-----------------------------168072824752491622650073';
-const buffers = createMultipartBuffers(boundary, [
-  10,
-  10,
-  10,
-  20,
-  50,
-]);
-const calls = {
-  partBegin: 0,
-  headerField: 0,
-  headerValue: 0,
-  headerEnd: 0,
-  headersEnd: 0,
-  partData: 0,
-  partEnd: 0,
-  end: 0,
-};
-
-const moduleName = process.argv[2];
-switch (moduleName) {
-  case 'busboy': {
-    const busboy = require('busboy');
-
-    const parser = busboy({
-      limits: {
-        fieldSizeLimit: Infinity,
-      },
-      headers: {
-        'content-type': `multipart/form-data; boundary=${boundary}`,
-      },
-    });
-    parser.on('field', (name, val, info) => {
-      ++calls.partBegin;
-      ++calls.partData;
-      ++calls.partEnd;
-    }).on('close', () => {
-      ++calls.end;
-      console.timeEnd(moduleName);
-    });
-
-    console.time(moduleName);
-    for (const buf of buffers)
-      parser.write(buf);
-    break;
-  }
-
-  case 'formidable': {
-    const { MultipartParser } = require('formidable');
-
-    const parser = new MultipartParser();
-    parser.initWithBoundary(boundary);
-    parser.on('data', ({ name }) => {
-      ++calls[name];
-      if (name === 'end')
-        console.timeEnd(moduleName);
-    });
-
-    console.time(moduleName);
-    for (const buf of buffers)
-      parser.write(buf);
-
-    break;
-  }
-
-  case 'multiparty': {
-    const { Readable } = require('stream');
-
-    const { Form } = require('multiparty');
-
-    const form = new Form({
-      maxFieldsSize: Infinity,
-      maxFields: Infinity,
-      maxFilesSize: Infinity,
-      autoFields: false,
-      autoFiles: false,
-    });
-
-    const req = new Readable({ read: () => {} });
-    req.headers = {
-      'content-type': `multipart/form-data; boundary=${boundary}`,
-    };
-
-    function hijack(name, fn) {
-      const oldFn = form[name];
-      form[name] = function() {
-        fn();
-        return oldFn.apply(this, arguments);
-      };
-    }
-
-    hijack('onParseHeaderField', () => {
-      ++calls.headerField;
-    });
-    hijack('onParseHeaderValue', () => {
-      ++calls.headerValue;
-    });
-    hijack('onParsePartBegin', () => {
-      ++calls.partBegin;
-    });
-    hijack('onParsePartData', () => {
-      ++calls.partData;
-    });
-    hijack('onParsePartEnd', () => {
-      ++calls.partEnd;
-    });
-
-    form.on('close', () => {
-      ++calls.end;
-      console.timeEnd(moduleName);
-    }).on('part', (p) => p.resume());
-
-    console.time(moduleName);
-    form.parse(req);
-    for (const buf of buffers)
-      req.push(buf);
-    req.push(null);
-
-    break;
-  }
-
-  default:
-    if (moduleName === undefined)
-      console.error('Missing parser module name');
-    else
-      console.error(`Invalid parser module name: ${moduleName}`);
-    process.exit(1);
-}

+ 0 - 143
node_modules/busboy/bench/bench-multipart-fields-100mb-small.js

@@ -1,143 +0,0 @@
-'use strict';
-
-function createMultipartBuffers(boundary, sizes) {
-  const bufs = [];
-  for (let i = 0; i < sizes.length; ++i) {
-    const mb = sizes[i] * 1024 * 1024;
-    bufs.push(Buffer.from([
-      `--${boundary}`,
-      `content-disposition: form-data; name="field${i + 1}"`,
-      '',
-      '0'.repeat(mb),
-      '',
-    ].join('\r\n')));
-  }
-  bufs.push(Buffer.from([
-    `--${boundary}--`,
-    '',
-  ].join('\r\n')));
-  return bufs;
-}
-
-const boundary = '-----------------------------168072824752491622650073';
-const buffers = createMultipartBuffers(boundary, (new Array(100)).fill(1));
-const calls = {
-  partBegin: 0,
-  headerField: 0,
-  headerValue: 0,
-  headerEnd: 0,
-  headersEnd: 0,
-  partData: 0,
-  partEnd: 0,
-  end: 0,
-};
-
-const moduleName = process.argv[2];
-switch (moduleName) {
-  case 'busboy': {
-    const busboy = require('busboy');
-
-    const parser = busboy({
-      limits: {
-        fieldSizeLimit: Infinity,
-      },
-      headers: {
-        'content-type': `multipart/form-data; boundary=${boundary}`,
-      },
-    });
-    parser.on('field', (name, val, info) => {
-      ++calls.partBegin;
-      ++calls.partData;
-      ++calls.partEnd;
-    }).on('close', () => {
-      ++calls.end;
-      console.timeEnd(moduleName);
-    });
-
-    console.time(moduleName);
-    for (const buf of buffers)
-      parser.write(buf);
-    break;
-  }
-
-  case 'formidable': {
-    const { MultipartParser } = require('formidable');
-
-    const parser = new MultipartParser();
-    parser.initWithBoundary(boundary);
-    parser.on('data', ({ name }) => {
-      ++calls[name];
-      if (name === 'end')
-        console.timeEnd(moduleName);
-    });
-
-    console.time(moduleName);
-    for (const buf of buffers)
-      parser.write(buf);
-
-    break;
-  }
-
-  case 'multiparty': {
-    const { Readable } = require('stream');
-
-    const { Form } = require('multiparty');
-
-    const form = new Form({
-      maxFieldsSize: Infinity,
-      maxFields: Infinity,
-      maxFilesSize: Infinity,
-      autoFields: false,
-      autoFiles: false,
-    });
-
-    const req = new Readable({ read: () => {} });
-    req.headers = {
-      'content-type': `multipart/form-data; boundary=${boundary}`,
-    };
-
-    function hijack(name, fn) {
-      const oldFn = form[name];
-      form[name] = function() {
-        fn();
-        return oldFn.apply(this, arguments);
-      };
-    }
-
-    hijack('onParseHeaderField', () => {
-      ++calls.headerField;
-    });
-    hijack('onParseHeaderValue', () => {
-      ++calls.headerValue;
-    });
-    hijack('onParsePartBegin', () => {
-      ++calls.partBegin;
-    });
-    hijack('onParsePartData', () => {
-      ++calls.partData;
-    });
-    hijack('onParsePartEnd', () => {
-      ++calls.partEnd;
-    });
-
-    form.on('close', () => {
-      ++calls.end;
-      console.timeEnd(moduleName);
-    }).on('part', (p) => p.resume());
-
-    console.time(moduleName);
-    form.parse(req);
-    for (const buf of buffers)
-      req.push(buf);
-    req.push(null);
-
-    break;
-  }
-
-  default:
-    if (moduleName === undefined)
-      console.error('Missing parser module name');
-    else
-      console.error(`Invalid parser module name: ${moduleName}`);
-    process.exit(1);
-}

+ 0 - 154
node_modules/busboy/bench/bench-multipart-files-100mb-big.js

@@ -1,154 +0,0 @@
-'use strict';
-
-function createMultipartBuffers(boundary, sizes) {
-  const bufs = [];
-  for (let i = 0; i < sizes.length; ++i) {
-    const mb = sizes[i] * 1024 * 1024;
-    bufs.push(Buffer.from([
-      `--${boundary}`,
-      `content-disposition: form-data; name="file${i + 1}"; `
-        + `filename="random${i + 1}.bin"`,
-      'content-type: application/octet-stream',
-      '',
-      '0'.repeat(mb),
-      '',
-    ].join('\r\n')));
-  }
-  bufs.push(Buffer.from([
-    `--${boundary}--`,
-    '',
-  ].join('\r\n')));
-  return bufs;
-}
-
-const boundary = '-----------------------------168072824752491622650073';
-const buffers = createMultipartBuffers(boundary, [
-  10,
-  10,
-  10,
-  20,
-  50,
-]);
-const calls = {
-  partBegin: 0,
-  headerField: 0,
-  headerValue: 0,
-  headerEnd: 0,
-  headersEnd: 0,
-  partData: 0,
-  partEnd: 0,
-  end: 0,
-};
-
-const moduleName = process.argv[2];
-switch (moduleName) {
-  case 'busboy': {
-    const busboy = require('busboy');
-
-    const parser = busboy({
-      limits: {
-        fieldSizeLimit: Infinity,
-      },
-      headers: {
-        'content-type': `multipart/form-data; boundary=${boundary}`,
-      },
-    });
-    parser.on('file', (name, stream, info) => {
-      ++calls.partBegin;
-      stream.on('data', (chunk) => {
-        ++calls.partData;
-      }).on('end', () => {
-        ++calls.partEnd;
-      });
-    }).on('close', () => {
-      ++calls.end;
-      console.timeEnd(moduleName);
-    });
-
-    console.time(moduleName);
-    for (const buf of buffers)
-      parser.write(buf);
-    break;
-  }
-
-  case 'formidable': {
-    const { MultipartParser } = require('formidable');
-
-    const parser = new MultipartParser();
-    parser.initWithBoundary(boundary);
-    parser.on('data', ({ name }) => {
-      ++calls[name];
-      if (name === 'end')
-        console.timeEnd(moduleName);
-    });
-
-    console.time(moduleName);
-    for (const buf of buffers)
-      parser.write(buf);
-
-    break;
-  }
-
-  case 'multiparty': {
-    const { Readable } = require('stream');
-
-    const { Form } = require('multiparty');
-
-    const form = new Form({
-      maxFieldsSize: Infinity,
-      maxFields: Infinity,
-      maxFilesSize: Infinity,
-      autoFields: false,
-      autoFiles: false,
-    });
-
-    const req = new Readable({ read: () => {} });
-    req.headers = {
-      'content-type': `multipart/form-data; boundary=${boundary}`,
-    };
-
-    function hijack(name, fn) {
-      const oldFn = form[name];
-      form[name] = function() {
-        fn();
-        return oldFn.apply(this, arguments);
-      };
-    }
-
-    hijack('onParseHeaderField', () => {
-      ++calls.headerField;
-    });
-    hijack('onParseHeaderValue', () => {
-      ++calls.headerValue;
-    });
-    hijack('onParsePartBegin', () => {
-      ++calls.partBegin;
-    });
-    hijack('onParsePartData', () => {
-      ++calls.partData;
-    });
-    hijack('onParsePartEnd', () => {
-      ++calls.partEnd;
-    });
-
-    form.on('close', () => {
-      ++calls.end;
-      console.timeEnd(moduleName);
-    }).on('part', (p) => p.resume());
-
-    console.time(moduleName);
-    form.parse(req);
-    for (const buf of buffers)
-      req.push(buf);
-    req.push(null);
-
-    break;
-  }
-
-  default:
-    if (moduleName === undefined)
-      console.error('Missing parser module name');
-    else
-      console.error(`Invalid parser module name: ${moduleName}`);
-    process.exit(1);
-}

+ 0 - 148
node_modules/busboy/bench/bench-multipart-files-100mb-small.js

@@ -1,148 +0,0 @@
-'use strict';
-
-function createMultipartBuffers(boundary, sizes) {
-  const bufs = [];
-  for (let i = 0; i < sizes.length; ++i) {
-    const mb = sizes[i] * 1024 * 1024;
-    bufs.push(Buffer.from([
-      `--${boundary}`,
-      `content-disposition: form-data; name="file${i + 1}"; `
-        + `filename="random${i + 1}.bin"`,
-      'content-type: application/octet-stream',
-      '',
-      '0'.repeat(mb),
-      '',
-    ].join('\r\n')));
-  }
-  bufs.push(Buffer.from([
-    `--${boundary}--`,
-    '',
-  ].join('\r\n')));
-  return bufs;
-}
-
-const boundary = '-----------------------------168072824752491622650073';
-const buffers = createMultipartBuffers(boundary, (new Array(100)).fill(1));
-const calls = {
-  partBegin: 0,
-  headerField: 0,
-  headerValue: 0,
-  headerEnd: 0,
-  headersEnd: 0,
-  partData: 0,
-  partEnd: 0,
-  end: 0,
-};
-
-const moduleName = process.argv[2];
-switch (moduleName) {
-  case 'busboy': {
-    const busboy = require('busboy');
-
-    const parser = busboy({
-      limits: {
-        fieldSizeLimit: Infinity,
-      },
-      headers: {
-        'content-type': `multipart/form-data; boundary=${boundary}`,
-      },
-    });
-    parser.on('file', (name, stream, info) => {
-      ++calls.partBegin;
-      stream.on('data', (chunk) => {
-        ++calls.partData;
-      }).on('end', () => {
-        ++calls.partEnd;
-      });
-    }).on('close', () => {
-      ++calls.end;
-      console.timeEnd(moduleName);
-    });
-
-    console.time(moduleName);
-    for (const buf of buffers)
-      parser.write(buf);
-    break;
-  }
-
-  case 'formidable': {
-    const { MultipartParser } = require('formidable');
-
-    const parser = new MultipartParser();
-    parser.initWithBoundary(boundary);
-    parser.on('data', ({ name }) => {
-      ++calls[name];
-      if (name === 'end')
-        console.timeEnd(moduleName);
-    });
-
-    console.time(moduleName);
-    for (const buf of buffers)
-      parser.write(buf);
-
-    break;
-  }
-
-  case 'multiparty': {
-    const { Readable } = require('stream');
-
-    const { Form } = require('multiparty');
-
-    const form = new Form({
-      maxFieldsSize: Infinity,
-      maxFields: Infinity,
-      maxFilesSize: Infinity,
-      autoFields: false,
-      autoFiles: false,
-    });
-
-    const req = new Readable({ read: () => {} });
-    req.headers = {
-      'content-type': `multipart/form-data; boundary=${boundary}`,
-    };
-
-    function hijack(name, fn) {
-      const oldFn = form[name];
-      form[name] = function() {
-        fn();
-        return oldFn.apply(this, arguments);
-      };
-    }
-
-    hijack('onParseHeaderField', () => {
-      ++calls.headerField;
-    });
-    hijack('onParseHeaderValue', () => {
-      ++calls.headerValue;
-    });
-    hijack('onParsePartBegin', () => {
-      ++calls.partBegin;
-    });
-    hijack('onParsePartData', () => {
-      ++calls.partData;
-    });
-    hijack('onParsePartEnd', () => {
-      ++calls.partEnd;
-    });
-
-    form.on('close', () => {
-      ++calls.end;
-      console.timeEnd(moduleName);
-    }).on('part', (p) => p.resume());
-
-    console.time(moduleName);
-    form.parse(req);
-    for (const buf of buffers)
-      req.push(buf);
-    req.push(null);
-
-    break;
-  }
-
-  default:
-    if (moduleName === undefined)
-      console.error('Missing parser module name');
-    else
-      console.error(`Invalid parser module name: ${moduleName}`);
-    process.exit(1);
-}

+ 0 - 101
node_modules/busboy/bench/bench-urlencoded-fields-100pairs-small.js

@@ -1,101 +0,0 @@
-'use strict';
-
-const buffers = [
-  Buffer.from(
-    (new Array(100)).fill('').map((_, i) => `key${i}=value${i}`).join('&')
-  ),
-];
-const calls = {
-  field: 0,
-  end: 0,
-};
-
-let n = 3e3;
-
-const moduleName = process.argv[2];
-switch (moduleName) {
-  case 'busboy': {
-    const busboy = require('busboy');
-
-    console.time(moduleName);
-    (function next() {
-      const parser = busboy({
-        limits: {
-          fieldSizeLimit: Infinity,
-        },
-        headers: {
-          'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
-        },
-      });
-      parser.on('field', (name, val, info) => {
-        ++calls.field;
-      }).on('close', () => {
-        ++calls.end;
-        if (--n === 0)
-          console.timeEnd(moduleName);
-        else
-          process.nextTick(next);
-      });
-
-      for (const buf of buffers)
-        parser.write(buf);
-      parser.end();
-    })();
-    break;
-  }
-
-  case 'formidable': {
-    const QuerystringParser =
-      require('formidable/src/parsers/Querystring.js');
-
-    console.time(moduleName);
-    (function next() {
-      const parser = new QuerystringParser();
-      parser.on('data', (obj) => {
-        ++calls.field;
-      }).on('end', () => {
-        ++calls.end;
-        if (--n === 0)
-          console.timeEnd(moduleName);
-        else
-          process.nextTick(next);
-      });
-
-      for (const buf of buffers)
-        parser.write(buf);
-      parser.end();
-    })();
-    break;
-  }
-
-  case 'formidable-streaming': {
-    const QuerystringParser =
-      require('formidable/src/parsers/StreamingQuerystring.js');
-
-    console.time(moduleName);
-    (function next() {
-      const parser = new QuerystringParser();
-      parser.on('data', (obj) => {
-        ++calls.field;
-      }).on('end', () => {
-        ++calls.end;
-        if (--n === 0)
-          console.timeEnd(moduleName);
-        else
-          process.nextTick(next);
-      });
-
-      for (const buf of buffers)
-        parser.write(buf);
-      parser.end();
-    })();
-    break;
-  }
-
-  default:
-    if (moduleName === undefined)
-      console.error('Missing parser module name');
-    else
-      console.error(`Invalid parser module name: ${moduleName}`);
-    process.exit(1);
-}

+ 0 - 84
node_modules/busboy/bench/bench-urlencoded-fields-900pairs-small-alt.js

@@ -1,84 +0,0 @@
-'use strict';
-
-const buffers = [
-  Buffer.from(
-    (new Array(900)).fill('').map((_, i) => `key${i}=value${i}`).join('&')
-  ),
-];
-const calls = {
-  field: 0,
-  end: 0,
-};
-
-const moduleName = process.argv[2];
-switch (moduleName) {
-  case 'busboy': {
-    const busboy = require('busboy');
-
-    console.time(moduleName);
-    const parser = busboy({
-      limits: {
-        fieldSizeLimit: Infinity,
-      },
-      headers: {
-        'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
-      },
-    });
-    parser.on('field', (name, val, info) => {
-      ++calls.field;
-    }).on('close', () => {
-      ++calls.end;
-      console.timeEnd(moduleName);
-    });
-
-    for (const buf of buffers)
-      parser.write(buf);
-    parser.end();
-    break;
-  }
-
-  case 'formidable': {
-    const QuerystringParser =
-      require('formidable/src/parsers/Querystring.js');
-
-    console.time(moduleName);
-    const parser = new QuerystringParser();
-    parser.on('data', (obj) => {
-      ++calls.field;
-    }).on('end', () => {
-      ++calls.end;
-      console.timeEnd(moduleName);
-    });
-
-    for (const buf of buffers)
-      parser.write(buf);
-    parser.end();
-    break;
-  }
-
-  case 'formidable-streaming': {
-    const QuerystringParser =
-      require('formidable/src/parsers/StreamingQuerystring.js');
-
-    console.time(moduleName);
-    const parser = new QuerystringParser();
-    parser.on('data', (obj) => {
-      ++calls.field;
-    }).on('end', () => {
-      ++calls.end;
-      console.timeEnd(moduleName);
-    });
-
-    for (const buf of buffers)
-      parser.write(buf);
-    parser.end();
-    break;
-  }
-
-  default:
-    if (moduleName === undefined)
-      console.error('Missing parser module name');
-    else
-      console.error(`Invalid parser module name: ${moduleName}`);
-    process.exit(1);
-}

+ 0 - 57
node_modules/busboy/lib/index.js

@@ -1,57 +0,0 @@
-'use strict';
-
-const { parseContentType } = require('./utils.js');
-
-function getInstance(cfg) {
-  const headers = cfg.headers;
-  const conType = parseContentType(headers['content-type']);
-  if (!conType)
-    throw new Error('Malformed content type');
-
-  for (const type of TYPES) {
-    const matched = type.detect(conType);
-    if (!matched)
-      continue;
-
-    const instanceCfg = {
-      limits: cfg.limits,
-      headers,
-      conType,
-      highWaterMark: undefined,
-      fileHwm: undefined,
-      defCharset: undefined,
-      defParamCharset: undefined,
-      preservePath: false,
-    };
-    if (cfg.highWaterMark)
-      instanceCfg.highWaterMark = cfg.highWaterMark;
-    if (cfg.fileHwm)
-      instanceCfg.fileHwm = cfg.fileHwm;
-    instanceCfg.defCharset = cfg.defCharset;
-    instanceCfg.defParamCharset = cfg.defParamCharset;
-    instanceCfg.preservePath = cfg.preservePath;
-    return new type(instanceCfg);
-  }
-
-  throw new Error(`Unsupported content type: ${headers['content-type']}`);
-}
-
-// Note: types are explicitly listed here for easier bundling
-// See: https://github.com/mscdex/busboy/issues/121
-const TYPES = [
-  require('./types/multipart'),
-  require('./types/urlencoded'),
-].filter(function(typemod) { return typeof typemod.detect === 'function'; });
-
-module.exports = (cfg) => {
-  if (typeof cfg !== 'object' || cfg === null)
-    cfg = {};
-
-  if (typeof cfg.headers !== 'object'
-      || cfg.headers === null
-      || typeof cfg.headers['content-type'] !== 'string') {
-    throw new Error('Missing Content-Type');
-  }
-
-  return getInstance(cfg);
-};

+ 0 - 653
node_modules/busboy/lib/types/multipart.js

@@ -1,653 +0,0 @@
-'use strict';
-
-const { Readable, Writable } = require('stream');
-
-const StreamSearch = require('streamsearch');
-
-const {
-  basename,
-  convertToUTF8,
-  getDecoder,
-  parseContentType,
-  parseDisposition,
-} = require('../utils.js');
-
-const BUF_CRLF = Buffer.from('\r\n');
-const BUF_CR = Buffer.from('\r');
-const BUF_DASH = Buffer.from('-');
-
-function noop() {}
-
-const MAX_HEADER_PAIRS = 2000; // From node
-const MAX_HEADER_SIZE = 16 * 1024; // From node (its default value)
-
-const HPARSER_NAME = 0;
-const HPARSER_PRE_OWS = 1;
-const HPARSER_VALUE = 2;
-class HeaderParser {
-  constructor(cb) {
-    this.header = Object.create(null);
-    this.pairCount = 0;
-    this.byteCount = 0;
-    this.state = HPARSER_NAME;
-    this.name = '';
-    this.value = '';
-    this.crlf = 0;
-    this.cb = cb;
-  }
-
-  reset() {
-    this.header = Object.create(null);
-    this.pairCount = 0;
-    this.byteCount = 0;
-    this.state = HPARSER_NAME;
-    this.name = '';
-    this.value = '';
-    this.crlf = 0;
-  }
-
-  push(chunk, pos, end) {
-    let start = pos;
-    while (pos < end) {
-      switch (this.state) {
-        case HPARSER_NAME: {
-          let done = false;
-          for (; pos < end; ++pos) {
-            if (this.byteCount === MAX_HEADER_SIZE)
-              return -1;
-            ++this.byteCount;
-            const code = chunk[pos];
-            if (TOKEN[code] !== 1) {
-              if (code !== 58/* ':' */)
-                return -1;
-              this.name += chunk.latin1Slice(start, pos);
-              if (this.name.length === 0)
-                return -1;
-              ++pos;
-              done = true;
-              this.state = HPARSER_PRE_OWS;
-              break;
-            }
-          }
-          if (!done) {
-            this.name += chunk.latin1Slice(start, pos);
-            break;
-          }
-          // FALLTHROUGH
-        }
-        case HPARSER_PRE_OWS: {
-          // Skip optional whitespace
-          let done = false;
-          for (; pos < end; ++pos) {
-            if (this.byteCount === MAX_HEADER_SIZE)
-              return -1;
-            ++this.byteCount;
-            const code = chunk[pos];
-            if (code !== 32/* ' ' */ && code !== 9/* '\t' */) {
-              start = pos;
-              done = true;
-              this.state = HPARSER_VALUE;
-              break;
-            }
-          }
-          if (!done)
-            break;
-          // FALLTHROUGH
-        }
-        case HPARSER_VALUE:
-          switch (this.crlf) {
-            case 0: // Nothing yet
-              for (; pos < end; ++pos) {
-                if (this.byteCount === MAX_HEADER_SIZE)
-                  return -1;
-                ++this.byteCount;
-                const code = chunk[pos];
-                if (FIELD_VCHAR[code] !== 1) {
-                  if (code !== 13/* '\r' */)
-                    return -1;
-                  ++this.crlf;
-                  break;
-                }
-              }
-              this.value += chunk.latin1Slice(start, pos++);
-              break;
-            case 1: // Received CR
-              if (this.byteCount === MAX_HEADER_SIZE)
-                return -1;
-              ++this.byteCount;
-              if (chunk[pos++] !== 10/* '\n' */)
-                return -1;
-              ++this.crlf;
-              break;
-            case 2: { // Received CR LF
-              if (this.byteCount === MAX_HEADER_SIZE)
-                return -1;
-              ++this.byteCount;
-              const code = chunk[pos];
-              if (code === 32/* ' ' */ || code === 9/* '\t' */) {
-                // Folded value
-                start = pos;
-                this.crlf = 0;
-              } else {
-                if (++this.pairCount < MAX_HEADER_PAIRS) {
-                  this.name = this.name.toLowerCase();
-                  if (this.header[this.name] === undefined)
-                    this.header[this.name] = [this.value];
-                  else
-                    this.header[this.name].push(this.value);
-                }
-                if (code === 13/* '\r' */) {
-                  ++this.crlf;
-                  ++pos;
-                } else {
-                  // Assume start of next header field name
-                  start = pos;
-                  this.crlf = 0;
-                  this.state = HPARSER_NAME;
-                  this.name = '';
-                  this.value = '';
-                }
-              }
-              break;
-            }
-            case 3: { // Received CR LF CR
-              if (this.byteCount === MAX_HEADER_SIZE)
-                return -1;
-              ++this.byteCount;
-              if (chunk[pos++] !== 10/* '\n' */)
-                return -1;
-              // End of header
-              const header = this.header;
-              this.reset();
-              this.cb(header);
-              return pos;
-            }
-          }
-          break;
-      }
-    }
-
-    return pos;
-  }
-}
-
-class FileStream extends Readable {
-  constructor(opts, owner) {
-    super(opts);
-    this.truncated = false;
-    this._readcb = null;
-    this.once('end', () => {
-      // We need to make sure that we call any outstanding _writecb() that is
-      // associated with this file so that processing of the rest of the form
-      // can continue. This may not happen if the file stream ends right after
-      // backpressure kicks in, so we force it here.
-      this._read();
-      if (--owner._fileEndsLeft === 0 && owner._finalcb) {
-        const cb = owner._finalcb;
-        owner._finalcb = null;
-        // Make sure other 'end' event handlers get a chance to be executed
-        // before busboy's 'finish' event is emitted
-        process.nextTick(cb);
-      }
-    });
-  }
-  _read(n) {
-    const cb = this._readcb;
-    if (cb) {
-      this._readcb = null;
-      cb();
-    }
-  }
-}
-
-const ignoreData = {
-  push: (chunk, pos) => {},
-  destroy: () => {},
-};
-
-function callAndUnsetCb(self, err) {
-  const cb = self._writecb;
-  self._writecb = null;
-  if (err)
-    self.destroy(err);
-  else if (cb)
-    cb();
-}
-
-function nullDecoder(val, hint) {
-  return val;
-}
-
-class Multipart extends Writable {
-  constructor(cfg) {
-    const streamOpts = {
-      autoDestroy: true,
-      emitClose: true,
-      highWaterMark: (typeof cfg.highWaterMark === 'number'
-                      ? cfg.highWaterMark
-                      : undefined),
-    };
-    super(streamOpts);
-
-    if (!cfg.conType.params || typeof cfg.conType.params.boundary !== 'string')
-      throw new Error('Multipart: Boundary not found');
-
-    const boundary = cfg.conType.params.boundary;
-    const paramDecoder = (typeof cfg.defParamCharset === 'string'
-                            && cfg.defParamCharset
-                          ? getDecoder(cfg.defParamCharset)
-                          : nullDecoder);
-    const defCharset = (cfg.defCharset || 'utf8');
-    const preservePath = cfg.preservePath;
-    const fileOpts = {
-      autoDestroy: true,
-      emitClose: true,
-      highWaterMark: (typeof cfg.fileHwm === 'number'
-                      ? cfg.fileHwm
-                      : undefined),
-    };
-
-    const limits = cfg.limits;
-    const fieldSizeLimit = (limits && typeof limits.fieldSize === 'number'
-                            ? limits.fieldSize
-                            : 1 * 1024 * 1024);
-    const fileSizeLimit = (limits && typeof limits.fileSize === 'number'
-                           ? limits.fileSize
-                           : Infinity);
-    const filesLimit = (limits && typeof limits.files === 'number'
-                        ? limits.files
-                        : Infinity);
-    const fieldsLimit = (limits && typeof limits.fields === 'number'
-                         ? limits.fields
-                         : Infinity);
-    const partsLimit = (limits && typeof limits.parts === 'number'
-                        ? limits.parts
-                        : Infinity);
-
-    let parts = -1; // Account for initial boundary
-    let fields = 0;
-    let files = 0;
-    let skipPart = false;
-
-    this._fileEndsLeft = 0;
-    this._fileStream = undefined;
-    this._complete = false;
-    let fileSize = 0;
-
-    let field;
-    let fieldSize = 0;
-    let partCharset;
-    let partEncoding;
-    let partType;
-    let partName;
-    let partTruncated = false;
-
-    let hitFilesLimit = false;
-    let hitFieldsLimit = false;
-
-    this._hparser = null;
-    const hparser = new HeaderParser((header) => {
-      this._hparser = null;
-      skipPart = false;
-
-      partType = 'text/plain';
-      partCharset = defCharset;
-      partEncoding = '7bit';
-      partName = undefined;
-      partTruncated = false;
-
-      let filename;
-      if (!header['content-disposition']) {
-        skipPart = true;
-        return;
-      }
-
-      const disp = parseDisposition(header['content-disposition'][0],
-                                    paramDecoder);
-      if (!disp || disp.type !== 'form-data') {
-        skipPart = true;
-        return;
-      }
-
-      if (disp.params) {
-        if (disp.params.name)
-          partName = disp.params.name;
-
-        if (disp.params['filename*'])
-          filename = disp.params['filename*'];
-        else if (disp.params.filename)
-          filename = disp.params.filename;
-
-        if (filename !== undefined && !preservePath)
-          filename = basename(filename);
-      }
-
-      if (header['content-type']) {
-        const conType = parseContentType(header['content-type'][0]);
-        if (conType) {
-          partType = `${conType.type}/${conType.subtype}`;
-          if (conType.params && typeof conType.params.charset === 'string')
-            partCharset = conType.params.charset.toLowerCase();
-        }
-      }
-
-      if (header['content-transfer-encoding'])
-        partEncoding = header['content-transfer-encoding'][0].toLowerCase();
-
-      if (partType === 'application/octet-stream' || filename !== undefined) {
-        // File
-
-        if (files === filesLimit) {
-          if (!hitFilesLimit) {
-            hitFilesLimit = true;
-            this.emit('filesLimit');
-          }
-          skipPart = true;
-          return;
-        }
-        ++files;
-
-        if (this.listenerCount('file') === 0) {
-          skipPart = true;
-          return;
-        }
-
-        fileSize = 0;
-        this._fileStream = new FileStream(fileOpts, this);
-        ++this._fileEndsLeft;
-        this.emit(
-          'file',
-          partName,
-          this._fileStream,
-          { filename,
-            encoding: partEncoding,
-            mimeType: partType }
-        );
-      } else {
-        // Non-file
-
-        if (fields === fieldsLimit) {
-          if (!hitFieldsLimit) {
-            hitFieldsLimit = true;
-            this.emit('fieldsLimit');
-          }
-          skipPart = true;
-          return;
-        }
-        ++fields;
-
-        if (this.listenerCount('field') === 0) {
-          skipPart = true;
-          return;
-        }
-
-        field = [];
-        fieldSize = 0;
-      }
-    });
-
-    let matchPostBoundary = 0;
-    const ssCb = (isMatch, data, start, end, isDataSafe) => {
-retrydata:
-      while (data) {
-        if (this._hparser !== null) {
-          const ret = this._hparser.push(data, start, end);
-          if (ret === -1) {
-            this._hparser = null;
-            hparser.reset();
-            this.emit('error', new Error('Malformed part header'));
-            break;
-          }
-          start = ret;
-        }
-
-        if (start === end)
-          break;
-
-        if (matchPostBoundary !== 0) {
-          if (matchPostBoundary === 1) {
-            switch (data[start]) {
-              case 45: // '-'
-                // Try matching '--' after boundary
-                matchPostBoundary = 2;
-                ++start;
-                break;
-              case 13: // '\r'
-                // Try matching CR LF before header
-                matchPostBoundary = 3;
-                ++start;
-                break;
-              default:
-                matchPostBoundary = 0;
-            }
-            if (start === end)
-              return;
-          }
-
-          if (matchPostBoundary === 2) {
-            matchPostBoundary = 0;
-            if (data[start] === 45/* '-' */) {
-              // End of multipart data
-              this._complete = true;
-              this._bparser = ignoreData;
-              return;
-            }
-            // We saw something other than '-', so put the dash we consumed
-            // "back"
-            const writecb = this._writecb;
-            this._writecb = noop;
-            ssCb(false, BUF_DASH, 0, 1, false);
-            this._writecb = writecb;
-          } else if (matchPostBoundary === 3) {
-            matchPostBoundary = 0;
-            if (data[start] === 10/* '\n' */) {
-              ++start;
-              if (parts >= partsLimit)
-                break;
-              // Prepare the header parser
-              this._hparser = hparser;
-              if (start === end)
-                break;
-              // Process the remaining data as a header
-              continue retrydata;
-            } else {
-              // We saw something other than LF, so put the CR we consumed
-              // "back"
-              const writecb = this._writecb;
-              this._writecb = noop;
-              ssCb(false, BUF_CR, 0, 1, false);
-              this._writecb = writecb;
-            }
-          }
-        }
-
-        if (!skipPart) {
-          if (this._fileStream) {
-            let chunk;
-            const actualLen = Math.min(end - start, fileSizeLimit - fileSize);
-            if (!isDataSafe) {
-              chunk = Buffer.allocUnsafe(actualLen);
-              data.copy(chunk, 0, start, start + actualLen);
-            } else {
-              chunk = data.slice(start, start + actualLen);
-            }
-
-            fileSize += chunk.length;
-            if (fileSize === fileSizeLimit) {
-              if (chunk.length > 0)
-                this._fileStream.push(chunk);
-              this._fileStream.emit('limit');
-              this._fileStream.truncated = true;
-              skipPart = true;
-            } else if (!this._fileStream.push(chunk)) {
-              if (this._writecb)
-                this._fileStream._readcb = this._writecb;
-              this._writecb = null;
-            }
-          } else if (field !== undefined) {
-            let chunk;
-            const actualLen = Math.min(
-              end - start,
-              fieldSizeLimit - fieldSize
-            );
-            if (!isDataSafe) {
-              chunk = Buffer.allocUnsafe(actualLen);
-              data.copy(chunk, 0, start, start + actualLen);
-            } else {
-              chunk = data.slice(start, start + actualLen);
-            }
-
-            fieldSize += actualLen;
-            field.push(chunk);
-            if (fieldSize === fieldSizeLimit) {
-              skipPart = true;
-              partTruncated = true;
-            }
-          }
-        }
-
-        break;
-      }
-
-      if (isMatch) {
-        matchPostBoundary = 1;
-
-        if (this._fileStream) {
-          // End the active file stream if the previous part was a file
-          this._fileStream.push(null);
-          this._fileStream = null;
-        } else if (field !== undefined) {
-          let data;
-          switch (field.length) {
-            case 0:
-              data = '';
-              break;
-            case 1:
-              data = convertToUTF8(field[0], partCharset, 0);
-              break;
-            default:
-              data = convertToUTF8(
-                Buffer.concat(field, fieldSize),
-                partCharset,
-                0
-              );
-          }
-          field = undefined;
-          fieldSize = 0;
-          this.emit(
-            'field',
-            partName,
-            data,
-            { nameTruncated: false,
-              valueTruncated: partTruncated,
-              encoding: partEncoding,
-              mimeType: partType }
-          );
-        }
-
-        if (++parts === partsLimit)
-          this.emit('partsLimit');
-      }
-    };
-    this._bparser = new StreamSearch(`\r\n--${boundary}`, ssCb);
-
-    this._writecb = null;
-    this._finalcb = null;
-
-    // Just in case there is no preamble
-    this.write(BUF_CRLF);
-  }
-
-  static detect(conType) {
-    return (conType.type === 'multipart' && conType.subtype === 'form-data');
-  }
-
-  _write(chunk, enc, cb) {
-    this._writecb = cb;
-    this._bparser.push(chunk, 0);
-    if (this._writecb)
-      callAndUnsetCb(this);
-  }
-
-  _destroy(err, cb) {
-    this._hparser = null;
-    this._bparser = ignoreData;
-    if (!err)
-      err = checkEndState(this);
-    const fileStream = this._fileStream;
-    if (fileStream) {
-      this._fileStream = null;
-      fileStream.destroy(err);
-    }
-    cb(err);
-  }
-
-  _final(cb) {
-    this._bparser.destroy();
-    if (!this._complete)
-      return cb(new Error('Unexpected end of form'));
-    if (this._fileEndsLeft)
-      this._finalcb = finalcb.bind(null, this, cb);
-    else
-      finalcb(this, cb);
-  }
-}
-
-function finalcb(self, cb, err) {
-  if (err)
-    return cb(err);
-  err = checkEndState(self);
-  cb(err);
-}
-
-function checkEndState(self) {
-  if (self._hparser)
-    return new Error('Malformed part header');
-  const fileStream = self._fileStream;
-  if (fileStream) {
-    self._fileStream = null;
-    fileStream.destroy(new Error('Unexpected end of file'));
-  }
-  if (!self._complete)
-    return new Error('Unexpected end of form');
-}
-
-const TOKEN = [
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
-  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-];
-
-const FIELD_VCHAR = [
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-];
-
-module.exports = Multipart;

+ 0 - 350
node_modules/busboy/lib/types/urlencoded.js

@@ -1,350 +0,0 @@
-'use strict';
-
-const { Writable } = require('stream');
-
-const { getDecoder } = require('../utils.js');
-
-class URLEncoded extends Writable {
-  constructor(cfg) {
-    const streamOpts = {
-      autoDestroy: true,
-      emitClose: true,
-      highWaterMark: (typeof cfg.highWaterMark === 'number'
-                      ? cfg.highWaterMark
-                      : undefined),
-    };
-    super(streamOpts);
-
-    let charset = (cfg.defCharset || 'utf8');
-    if (cfg.conType.params && typeof cfg.conType.params.charset === 'string')
-      charset = cfg.conType.params.charset;
-
-    this.charset = charset;
-
-    const limits = cfg.limits;
-    this.fieldSizeLimit = (limits && typeof limits.fieldSize === 'number'
-                           ? limits.fieldSize
-                           : 1 * 1024 * 1024);
-    this.fieldsLimit = (limits && typeof limits.fields === 'number'
-                        ? limits.fields
-                        : Infinity);
-    this.fieldNameSizeLimit = (
-      limits && typeof limits.fieldNameSize === 'number'
-      ? limits.fieldNameSize
-      : 100
-    );
-
-    this._inKey = true;
-    this._keyTrunc = false;
-    this._valTrunc = false;
-    this._bytesKey = 0;
-    this._bytesVal = 0;
-    this._fields = 0;
-    this._key = '';
-    this._val = '';
-    this._byte = -2;
-    this._lastPos = 0;
-    this._encode = 0;
-    this._decoder = getDecoder(charset);
-  }
-
-  static detect(conType) {
-    return (conType.type === 'application'
-            && conType.subtype === 'x-www-form-urlencoded');
-  }
-
-  _write(chunk, enc, cb) {
-    if (this._fields >= this.fieldsLimit)
-      return cb();
-
-    let i = 0;
-    const len = chunk.length;
-    this._lastPos = 0;
-
-    // Check if we last ended mid-percent-encoded byte
-    if (this._byte !== -2) {
-      i = readPctEnc(this, chunk, i, len);
-      if (i === -1)
-        return cb(new Error('Malformed urlencoded form'));
-      if (i >= len)
-        return cb();
-      if (this._inKey)
-        ++this._bytesKey;
-      else
-        ++this._bytesVal;
-    }
-
-main:
-    while (i < len) {
-      if (this._inKey) {
-        // Parsing key
-
-        i = skipKeyBytes(this, chunk, i, len);
-
-        while (i < len) {
-          switch (chunk[i]) {
-            case 61: // '='
-              if (this._lastPos < i)
-                this._key += chunk.latin1Slice(this._lastPos, i);
-              this._lastPos = ++i;
-              this._key = this._decoder(this._key, this._encode);
-              this._encode = 0;
-              this._inKey = false;
-              continue main;
-            case 38: // '&'
-              if (this._lastPos < i)
-                this._key += chunk.latin1Slice(this._lastPos, i);
-              this._lastPos = ++i;
-              this._key = this._decoder(this._key, this._encode);
-              this._encode = 0;
-              if (this._bytesKey > 0) {
-                this.emit(
-                  'field',
-                  this._key,
-                  '',
-                  { nameTruncated: this._keyTrunc,
-                    valueTruncated: false,
-                    encoding: this.charset,
-                    mimeType: 'text/plain' }
-                );
-              }
-              this._key = '';
-              this._val = '';
-              this._keyTrunc = false;
-              this._valTrunc = false;
-              this._bytesKey = 0;
-              this._bytesVal = 0;
-              if (++this._fields >= this.fieldsLimit) {
-                this.emit('fieldsLimit');
-                return cb();
-              }
-              continue;
-            case 43: // '+'
-              if (this._lastPos < i)
-                this._key += chunk.latin1Slice(this._lastPos, i);
-              this._key += ' ';
-              this._lastPos = i + 1;
-              break;
-            case 37: // '%'
-              if (this._encode === 0)
-                this._encode = 1;
-              if (this._lastPos < i)
-                this._key += chunk.latin1Slice(this._lastPos, i);
-              this._lastPos = i + 1;
-              this._byte = -1;
-              i = readPctEnc(this, chunk, i + 1, len);
-              if (i === -1)
-                return cb(new Error('Malformed urlencoded form'));
-              if (i >= len)
-                return cb();
-              ++this._bytesKey;
-              i = skipKeyBytes(this, chunk, i, len);
-              continue;
-          }
-          ++i;
-          ++this._bytesKey;
-          i = skipKeyBytes(this, chunk, i, len);
-        }
-        if (this._lastPos < i)
-          this._key += chunk.latin1Slice(this._lastPos, i);
-      } else {
-        // Parsing value
-
-        i = skipValBytes(this, chunk, i, len);
-
-        while (i < len) {
-          switch (chunk[i]) {
-            case 38: // '&'
-              if (this._lastPos < i)
-                this._val += chunk.latin1Slice(this._lastPos, i);
-              this._lastPos = ++i;
-              this._inKey = true;
-              this._val = this._decoder(this._val, this._encode);
-              this._encode = 0;
-              if (this._bytesKey > 0 || this._bytesVal > 0) {
-                this.emit(
-                  'field',
-                  this._key,
-                  this._val,
-                  { nameTruncated: this._keyTrunc,
-                    valueTruncated: this._valTrunc,
-                    encoding: this.charset,
-                    mimeType: 'text/plain' }
-                );
-              }
-              this._key = '';
-              this._val = '';
-              this._keyTrunc = false;
-              this._valTrunc = false;
-              this._bytesKey = 0;
-              this._bytesVal = 0;
-              if (++this._fields >= this.fieldsLimit) {
-                this.emit('fieldsLimit');
-                return cb();
-              }
-              continue main;
-            case 43: // '+'
-              if (this._lastPos < i)
-                this._val += chunk.latin1Slice(this._lastPos, i);
-              this._val += ' ';
-              this._lastPos = i + 1;
-              break;
-            case 37: // '%'
-              if (this._encode === 0)
-                this._encode = 1;
-              if (this._lastPos < i)
-                this._val += chunk.latin1Slice(this._lastPos, i);
-              this._lastPos = i + 1;
-              this._byte = -1;
-              i = readPctEnc(this, chunk, i + 1, len);
-              if (i === -1)
-                return cb(new Error('Malformed urlencoded form'));
-              if (i >= len)
-                return cb();
-              ++this._bytesVal;
-              i = skipValBytes(this, chunk, i, len);
-              continue;
-          }
-          ++i;
-          ++this._bytesVal;
-          i = skipValBytes(this, chunk, i, len);
-        }
-        if (this._lastPos < i)
-          this._val += chunk.latin1Slice(this._lastPos, i);
-      }
-    }
-
-    cb();
-  }
-
-  _final(cb) {
-    if (this._byte !== -2)
-      return cb(new Error('Malformed urlencoded form'));
-    if (!this._inKey || this._bytesKey > 0 || this._bytesVal > 0) {
-      if (this._inKey)
-        this._key = this._decoder(this._key, this._encode);
-      else
-        this._val = this._decoder(this._val, this._encode);
-      this.emit(
-        'field',
-        this._key,
-        this._val,
-        { nameTruncated: this._keyTrunc,
-          valueTruncated: this._valTrunc,
-          encoding: this.charset,
-          mimeType: 'text/plain' }
-      );
-    }
-    cb();
-  }
-}
-
-function readPctEnc(self, chunk, pos, len) {
-  if (pos >= len)
-    return len;
-
-  if (self._byte === -1) {
-    // We saw a '%' but no hex characters yet
-    const hexUpper = HEX_VALUES[chunk[pos++]];
-    if (hexUpper === -1)
-      return -1;
-
-    if (hexUpper >= 8)
-      self._encode = 2; // Indicate high bits detected
-
-    if (pos < len) {
-      // Both hex characters are in this chunk
-      const hexLower = HEX_VALUES[chunk[pos++]];
-      if (hexLower === -1)
-        return -1;
-
-      if (self._inKey)
-        self._key += String.fromCharCode((hexUpper << 4) + hexLower);
-      else
-        self._val += String.fromCharCode((hexUpper << 4) + hexLower);
-
-      self._byte = -2;
-      self._lastPos = pos;
-    } else {
-      // Only one hex character was available in this chunk
-      self._byte = hexUpper;
-    }
-  } else {
-    // We saw only one hex character so far
-    const hexLower = HEX_VALUES[chunk[pos++]];
-    if (hexLower === -1)
-      return -1;
-
-    if (self._inKey)
-      self._key += String.fromCharCode((self._byte << 4) + hexLower);
-    else
-      self._val += String.fromCharCode((self._byte << 4) + hexLower);
-
-    self._byte = -2;
-    self._lastPos = pos;
-  }
-
-  return pos;
-}
-
-function skipKeyBytes(self, chunk, pos, len) {
-  // Skip bytes if we've truncated
-  if (self._bytesKey > self.fieldNameSizeLimit) {
-    if (!self._keyTrunc) {
-      if (self._lastPos < pos)
-        self._key += chunk.latin1Slice(self._lastPos, pos - 1);
-    }
-    self._keyTrunc = true;
-    for (; pos < len; ++pos) {
-      const code = chunk[pos];
-      if (code === 61/* '=' */ || code === 38/* '&' */)
-        break;
-      ++self._bytesKey;
-    }
-    self._lastPos = pos;
-  }
-
-  return pos;
-}
-
-function skipValBytes(self, chunk, pos, len) {
-  // Skip bytes if we've truncated
-  if (self._bytesVal > self.fieldSizeLimit) {
-    if (!self._valTrunc) {
-      if (self._lastPos < pos)
-        self._val += chunk.latin1Slice(self._lastPos, pos - 1);
-    }
-    self._valTrunc = true;
-    for (; pos < len; ++pos) {
-      if (chunk[pos] === 38/* '&' */)
-        break;
-      ++self._bytesVal;
-    }
-    self._lastPos = pos;
-  }
-
-  return pos;
-}
-
-/* eslint-disable no-multi-spaces */
-const HEX_VALUES = [
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
-  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-];
-/* eslint-enable no-multi-spaces */
-
-module.exports = URLEncoded;

+ 0 - 596
node_modules/busboy/lib/utils.js

@@ -1,596 +0,0 @@
-'use strict';
-
-function parseContentType(str) {
-  if (str.length === 0)
-    return;
-
-  const params = Object.create(null);
-  let i = 0;
-
-  // Parse type
-  for (; i < str.length; ++i) {
-    const code = str.charCodeAt(i);
-    if (TOKEN[code] !== 1) {
-      if (code !== 47/* '/' */ || i === 0)
-        return;
-      break;
-    }
-  }
-  // Check for type without subtype
-  if (i === str.length)
-    return;
-
-  const type = str.slice(0, i).toLowerCase();
-
-  // Parse subtype
-  const subtypeStart = ++i;
-  for (; i < str.length; ++i) {
-    const code = str.charCodeAt(i);
-    if (TOKEN[code] !== 1) {
-      // Make sure we have a subtype
-      if (i === subtypeStart)
-        return;
-
-      if (parseContentTypeParams(str, i, params) === undefined)
-        return;
-      break;
-    }
-  }
-  // Make sure we have a subtype
-  if (i === subtypeStart)
-    return;
-
-  const subtype = str.slice(subtypeStart, i).toLowerCase();
-
-  return { type, subtype, params };
-}
-
-function parseContentTypeParams(str, i, params) {
-  while (i < str.length) {
-    // Consume whitespace
-    for (; i < str.length; ++i) {
-      const code = str.charCodeAt(i);
-      if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
-        break;
-    }
-
-    // Ended on whitespace
-    if (i === str.length)
-      break;
-
-    // Check for malformed parameter
-    if (str.charCodeAt(i++) !== 59/* ';' */)
-      return;
-
-    // Consume whitespace
-    for (; i < str.length; ++i) {
-      const code = str.charCodeAt(i);
-      if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
-        break;
-    }
-
-    // Ended on whitespace (malformed)
-    if (i === str.length)
-      return;
-
-    let name;
-    const nameStart = i;
-    // Parse parameter name
-    for (; i < str.length; ++i) {
-      const code = str.charCodeAt(i);
-      if (TOKEN[code] !== 1) {
-        if (code !== 61/* '=' */)
-          return;
-        break;
-      }
-    }
-
-    // No value (malformed)
-    if (i === str.length)
-      return;
-
-    name = str.slice(nameStart, i);
-    ++i; // Skip over '='
-
-    // No value (malformed)
-    if (i === str.length)
-      return;
-
-    let value = '';
-    let valueStart;
-    if (str.charCodeAt(i) === 34/* '"' */) {
-      valueStart = ++i;
-      let escaping = false;
-      // Parse quoted value
-      for (; i < str.length; ++i) {
-        const code = str.charCodeAt(i);
-        if (code === 92/* '\\' */) {
-          if (escaping) {
-            valueStart = i;
-            escaping = false;
-          } else {
-            value += str.slice(valueStart, i);
-            escaping = true;
-          }
-          continue;
-        }
-        if (code === 34/* '"' */) {
-          if (escaping) {
-            valueStart = i;
-            escaping = false;
-            continue;
-          }
-          value += str.slice(valueStart, i);
-          break;
-        }
-        if (escaping) {
-          valueStart = i - 1;
-          escaping = false;
-        }
-        // Invalid unescaped quoted character (malformed)
-        if (QDTEXT[code] !== 1)
-          return;
-      }
-
-      // No end quote (malformed)
-      if (i === str.length)
-        return;
-
-      ++i; // Skip over double quote
-    } else {
-      valueStart = i;
-      // Parse unquoted value
-      for (; i < str.length; ++i) {
-        const code = str.charCodeAt(i);
-        if (TOKEN[code] !== 1) {
-          // No value (malformed)
-          if (i === valueStart)
-            return;
-          break;
-        }
-      }
-      value = str.slice(valueStart, i);
-    }
-
-    name = name.toLowerCase();
-    if (params[name] === undefined)
-      params[name] = value;
-  }
-
-  return params;
-}
-
-function parseDisposition(str, defDecoder) {
-  if (str.length === 0)
-    return;
-
-  const params = Object.create(null);
-  let i = 0;
-
-  for (; i < str.length; ++i) {
-    const code = str.charCodeAt(i);
-    if (TOKEN[code] !== 1) {
-      if (parseDispositionParams(str, i, params, defDecoder) === undefined)
-        return;
-      break;
-    }
-  }
-
-  const type = str.slice(0, i).toLowerCase();
-
-  return { type, params };
-}
-
-function parseDispositionParams(str, i, params, defDecoder) {
-  while (i < str.length) {
-    // Consume whitespace
-    for (; i < str.length; ++i) {
-      const code = str.charCodeAt(i);
-      if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
-        break;
-    }
-
-    // Ended on whitespace
-    if (i === str.length)
-      break;
-
-    // Check for malformed parameter
-    if (str.charCodeAt(i++) !== 59/* ';' */)
-      return;
-
-    // Consume whitespace
-    for (; i < str.length; ++i) {
-      const code = str.charCodeAt(i);
-      if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
-        break;
-    }
-
-    // Ended on whitespace (malformed)
-    if (i === str.length)
-      return;
-
-    let name;
-    const nameStart = i;
-    // Parse parameter name
-    for (; i < str.length; ++i) {
-      const code = str.charCodeAt(i);
-      if (TOKEN[code] !== 1) {
-        if (code === 61/* '=' */)
-          break;
-        return;
-      }
-    }
-
-    // No value (malformed)
-    if (i === str.length)
-      return;
-
-    let value = '';
-    let valueStart;
-    let charset;
-    //~ let lang;
-    name = str.slice(nameStart, i);
-    if (name.charCodeAt(name.length - 1) === 42/* '*' */) {
-      // Extended value
-
-      const charsetStart = ++i;
-      // Parse charset name
-      for (; i < str.length; ++i) {
-        const code = str.charCodeAt(i);
-        if (CHARSET[code] !== 1) {
-          if (code !== 39/* '\'' */)
-            return;
-          break;
-        }
-      }
-
-      // Incomplete charset (malformed)
-      if (i === str.length)
-        return;
-
-      charset = str.slice(charsetStart, i);
-      ++i; // Skip over the '\''
-
-      //~ const langStart = ++i;
-      // Parse language name
-      for (; i < str.length; ++i) {
-        const code = str.charCodeAt(i);
-        if (code === 39/* '\'' */)
-          break;
-      }
-
-      // Incomplete language (malformed)
-      if (i === str.length)
-        return;
-
-      //~ lang = str.slice(langStart, i);
-      ++i; // Skip over the '\''
-
-      // No value (malformed)
-      if (i === str.length)
-        return;
-
-      valueStart = i;
-
-      let encode = 0;
-      // Parse value
-      for (; i < str.length; ++i) {
-        const code = str.charCodeAt(i);
-        if (EXTENDED_VALUE[code] !== 1) {
-          if (code === 37/* '%' */) {
-            let hexUpper;
-            let hexLower;
-            if (i + 2 < str.length
-                && (hexUpper = HEX_VALUES[str.charCodeAt(i + 1)]) !== -1
-                && (hexLower = HEX_VALUES[str.charCodeAt(i + 2)]) !== -1) {
-              const byteVal = (hexUpper << 4) + hexLower;
-              value += str.slice(valueStart, i);
-              value += String.fromCharCode(byteVal);
-              i += 2;
-              valueStart = i + 1;
-              if (byteVal >= 128)
-                encode = 2;
-              else if (encode === 0)
-                encode = 1;
-              continue;
-            }
-            // '%' disallowed in non-percent encoded contexts (malformed)
-            return;
-          }
-          break;
-        }
-      }
-
-      value += str.slice(valueStart, i);
-      value = convertToUTF8(value, charset, encode);
-      if (value === undefined)
-        return;
-    } else {
-      // Non-extended value
-
-      ++i; // Skip over '='
-
-      // No value (malformed)
-      if (i === str.length)
-        return;
-
-      if (str.charCodeAt(i) === 34/* '"' */) {
-        valueStart = ++i;
-        let escaping = false;
-        // Parse quoted value
-        for (; i < str.length; ++i) {
-          const code = str.charCodeAt(i);
-          if (code === 92/* '\\' */) {
-            if (escaping) {
-              valueStart = i;
-              escaping = false;
-            } else {
-              value += str.slice(valueStart, i);
-              escaping = true;
-            }
-            continue;
-          }
-          if (code === 34/* '"' */) {
-            if (escaping) {
-              valueStart = i;
-              escaping = false;
-              continue;
-            }
-            value += str.slice(valueStart, i);
-            break;
-          }
-          if (escaping) {
-            valueStart = i - 1;
-            escaping = false;
-          }
-          // Invalid unescaped quoted character (malformed)
-          if (QDTEXT[code] !== 1)
-            return;
-        }
-
-        // No end quote (malformed)
-        if (i === str.length)
-          return;
-
-        ++i; // Skip over double quote
-      } else {
-        valueStart = i;
-        // Parse unquoted value
-        for (; i < str.length; ++i) {
-          const code = str.charCodeAt(i);
-          if (TOKEN[code] !== 1) {
-            // No value (malformed)
-            if (i === valueStart)
-              return;
-            break;
-          }
-        }
-        value = str.slice(valueStart, i);
-      }
-
-      value = defDecoder(value, 2);
-      if (value === undefined)
-        return;
-    }
-
-    name = name.toLowerCase();
-    if (params[name] === undefined)
-      params[name] = value;
-  }
-
-  return params;
-}
-
-function getDecoder(charset) {
-  let lc;
-  while (true) {
-    switch (charset) {
-      case 'utf-8':
-      case 'utf8':
-        return decoders.utf8;
-      case 'latin1':
-      case 'ascii': // TODO: Make these a separate, strict decoder?
-      case 'us-ascii':
-      case 'iso-8859-1':
-      case 'iso8859-1':
-      case 'iso88591':
-      case 'iso_8859-1':
-      case 'windows-1252':
-      case 'iso_8859-1:1987':
-      case 'cp1252':
-      case 'x-cp1252':
-        return decoders.latin1;
-      case 'utf16le':
-      case 'utf-16le':
-      case 'ucs2':
-      case 'ucs-2':
-        return decoders.utf16le;
-      case 'base64':
-        return decoders.base64;
-      default:
-        if (lc === undefined) {
-          lc = true;
-          charset = charset.toLowerCase();
-          continue;
-        }
-        return decoders.other.bind(charset);
-    }
-  }
-}
-
-const decoders = {
-  utf8: (data, hint) => {
-    if (data.length === 0)
-      return '';
-    if (typeof data === 'string') {
-      // If `data` never had any percent-encoded bytes or never had any that
-      // were outside of the ASCII range, then we can safely just return the
-      // input since UTF-8 is ASCII compatible
-      if (hint < 2)
-        return data;
-
-      data = Buffer.from(data, 'latin1');
-    }
-    return data.utf8Slice(0, data.length);
-  },
-
-  latin1: (data, hint) => {
-    if (data.length === 0)
-      return '';
-    if (typeof data === 'string')
-      return data;
-    return data.latin1Slice(0, data.length);
-  },
-
-  utf16le: (data, hint) => {
-    if (data.length === 0)
-      return '';
-    if (typeof data === 'string')
-      data = Buffer.from(data, 'latin1');
-    return data.ucs2Slice(0, data.length);
-  },
-
-  base64: (data, hint) => {
-    if (data.length === 0)
-      return '';
-    if (typeof data === 'string')
-      data = Buffer.from(data, 'latin1');
-    return data.base64Slice(0, data.length);
-  },
-
-  other: (data, hint) => {
-    if (data.length === 0)
-      return '';
-    if (typeof data === 'string')
-      data = Buffer.from(data, 'latin1');
-    try {
-      const decoder = new TextDecoder(this);
-      return decoder.decode(data);
-    } catch {}
-  },
-};
-
-function convertToUTF8(data, charset, hint) {
-  const decode = getDecoder(charset);
-  if (decode)
-    return decode(data, hint);
-}
-
-function basename(path) {
-  if (typeof path !== 'string')
-    return '';
-  for (let i = path.length - 1; i >= 0; --i) {
-    switch (path.charCodeAt(i)) {
-      case 0x2F: // '/'
-      case 0x5C: // '\'
-        path = path.slice(i + 1);
-        return (path === '..' || path === '.' ? '' : path);
-    }
-  }
-  return (path === '..' || path === '.' ? '' : path);
-}
-
-const TOKEN = [
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
-  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-];
-
-const QDTEXT = [
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-];
-
-const CHARSET = [
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
-  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-];
-
-const EXTENDED_VALUE = [
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
-  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-];
-
-/* eslint-disable no-multi-spaces */
-const HEX_VALUES = [
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
-  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-];
-/* eslint-enable no-multi-spaces */
-
-module.exports = {
-  basename,
-  convertToUTF8,
-  getDecoder,
-  parseContentType,
-  parseDisposition,
-};

+ 0 - 22
node_modules/busboy/package.json

@@ -1,22 +0,0 @@
-{ "name": "busboy",
-  "version": "1.6.0",
-  "author": "Brian White <mscdex@mscdex.net>",
-  "description": "A streaming parser for HTML form data for node.js",
-  "main": "./lib/index.js",
-  "dependencies": {
-    "streamsearch": "^1.1.0"
-  },
-  "devDependencies": {
-    "@mscdex/eslint-config": "^1.1.0",
-    "eslint": "^7.32.0"
-  },
-  "scripts": {
-    "test": "node test/test.js",
-    "lint": "eslint --cache --report-unused-disable-directives --ext=.js .eslintrc.js lib test bench",
-    "lint:fix": "npm run lint -- --fix"
-  },
-  "engines": { "node": ">=10.16.0" },
-  "keywords": [ "uploads", "forms", "multipart", "form-data" ],
-  "licenses": [ { "type": "MIT", "url": "http://github.com/mscdex/busboy/raw/master/LICENSE" } ],
-  "repository": { "type": "git", "url": "http://github.com/mscdex/busboy.git" }
-}

+ 0 - 109
node_modules/busboy/test/common.js

@@ -1,109 +0,0 @@
-'use strict';
-
-const assert = require('assert');
-const { inspect } = require('util');
-
-const mustCallChecks = [];
-
-function noop() {}
-
-function runCallChecks(exitCode) {
-  if (exitCode !== 0) return;
-
-  const failed = mustCallChecks.filter((context) => {
-    if ('minimum' in context) {
-      context.messageSegment = `at least ${context.minimum}`;
-      return context.actual < context.minimum;
-    }
-    context.messageSegment = `exactly ${context.exact}`;
-    return context.actual !== context.exact;
-  });
-
-  failed.forEach((context) => {
-    console.error('Mismatched %s function calls. Expected %s, actual %d.',
-                  context.name,
-                  context.messageSegment,
-                  context.actual);
-    console.error(context.stack.split('\n').slice(2).join('\n'));
-  });
-
-  if (failed.length)
-    process.exit(1);
-}
-
-function mustCall(fn, exact) {
-  return _mustCallInner(fn, exact, 'exact');
-}
-
-function mustCallAtLeast(fn, minimum) {
-  return _mustCallInner(fn, minimum, 'minimum');
-}
-
-function _mustCallInner(fn, criteria = 1, field) {
-  if (process._exiting)
-    throw new Error('Cannot use common.mustCall*() in process exit handler');
-
-  if (typeof fn === 'number') {
-    criteria = fn;
-    fn = noop;
-  } else if (fn === undefined) {
-    fn = noop;
-  }
-
-  if (typeof criteria !== 'number')
-    throw new TypeError(`Invalid ${field} value: ${criteria}`);
-
-  const context = {
-    [field]: criteria,
-    actual: 0,
-    stack: inspect(new Error()),
-    name: fn.name || '<anonymous>'
-  };
-
-  // Add the exit listener only once to avoid listener leak warnings
-  if (mustCallChecks.length === 0)
-    process.on('exit', runCallChecks);
-
-  mustCallChecks.push(context);
-
-  function wrapped(...args) {
-    ++context.actual;
-    return fn.call(this, ...args);
-  }
-  // TODO: remove origFn?
-  wrapped.origFn = fn;
-
-  return wrapped;
-}
-
-function getCallSite(top) {
-  const originalStackFormatter = Error.prepareStackTrace;
-  Error.prepareStackTrace = (err, stack) =>
-    `${stack[0].getFileName()}:${stack[0].getLineNumber()}`;
-  const err = new Error();
-  Error.captureStackTrace(err, top);
-  // With the V8 Error API, the stack is not formatted until it is accessed
-  // eslint-disable-next-line no-unused-expressions
-  err.stack;
-  Error.prepareStackTrace = originalStackFormatter;
-  return err.stack;
-}
-
-function mustNotCall(msg) {
-  const callSite = getCallSite(mustNotCall);
-  return function mustNotCall(...args) {
-    args = args.map(inspect).join(', ');
-    const argsInfo = (args.length > 0
-                      ? `\ncalled with arguments: ${args}`
-                      : '');
-    assert.fail(
-      `${msg || 'function should not have been called'} at ${callSite}`
-        + argsInfo);
-  };
-}
-
-module.exports = {
-  mustCall,
-  mustCallAtLeast,
-  mustNotCall,
-};

+ 0 - 94
node_modules/busboy/test/test-types-multipart-charsets.js

@@ -1,94 +0,0 @@
-'use strict';
-
-const assert = require('assert');
-const { inspect } = require('util');
-
-const { mustCall } = require(`${__dirname}/common.js`);
-
-const busboy = require('..');
-
-const input = Buffer.from([
-  '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
- 'Content-Disposition: form-data; '
-   + 'name="upload_file_0"; filename="テスト.dat"',
- 'Content-Type: application/octet-stream',
- '',
- 'A'.repeat(1023),
- '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
-].join('\r\n'));
-const boundary = '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k';
-const expected = [
-  { type: 'file',
-    name: 'upload_file_0',
-    data: Buffer.from('A'.repeat(1023)),
-    info: {
-      filename: 'テスト.dat',
-      encoding: '7bit',
-      mimeType: 'application/octet-stream',
-    },
-    limited: false,
-  },
-];
-const bb = busboy({
-  defParamCharset: 'utf8',
-  headers: {
-    'content-type': `multipart/form-data; boundary=${boundary}`,
-  }
-});
-const results = [];
-
-bb.on('field', (name, val, info) => {
-  results.push({ type: 'field', name, val, info });
-});
-
-bb.on('file', (name, stream, info) => {
-  const data = [];
-  let nb = 0;
-  const file = {
-    type: 'file',
-    name,
-    data: null,
-    info,
-    limited: false,
-  };
-  results.push(file);
-  stream.on('data', (d) => {
-    data.push(d);
-    nb += d.length;
-  }).on('limit', () => {
-    file.limited = true;
-  }).on('close', () => {
-    file.data = Buffer.concat(data, nb);
-    assert.strictEqual(stream.truncated, file.limited);
-  }).once('error', (err) => {
-    file.err = err.message;
-  });
-});
-
-bb.on('error', (err) => {
-  results.push({ error: err.message });
-});
-
-bb.on('partsLimit', () => {
-  results.push('partsLimit');
-});
-
-bb.on('filesLimit', () => {
-  results.push('filesLimit');
-});
-
-bb.on('fieldsLimit', () => {
-  results.push('fieldsLimit');
-});
-
-bb.on('close', mustCall(() => {
-  assert.deepStrictEqual(
-    results,
-    expected,
-    'Results mismatch.\n'
-      + `Parsed: ${inspect(results)}\n`
-      + `Expected: ${inspect(expected)}`
-  );
-}));
-
-bb.end(input);

+ 0 - 102
node_modules/busboy/test/test-types-multipart-stream-pause.js

@@ -1,102 +0,0 @@
-'use strict';
-
-const assert = require('assert');
-const { randomFillSync } = require('crypto');
-const { inspect } = require('util');
-
-const busboy = require('..');
-
-const { mustCall } = require('./common.js');
-
-const BOUNDARY = 'u2KxIV5yF1y+xUspOQCCZopaVgeV6Jxihv35XQJmuTx8X3sh';
-
-function formDataSection(key, value) {
-  return Buffer.from(
-    `\r\n--${BOUNDARY}`
-      + `\r\nContent-Disposition: form-data; name="${key}"`
-      + `\r\n\r\n${value}`
-  );
-}
-
-function formDataFile(key, filename, contentType) {
-  const buf = Buffer.allocUnsafe(100000);
-  return Buffer.concat([
-    Buffer.from(`\r\n--${BOUNDARY}\r\n`),
-    Buffer.from(`Content-Disposition: form-data; name="${key}"`
-                  + `; filename="${filename}"\r\n`),
-    Buffer.from(`Content-Type: ${contentType}\r\n\r\n`),
-    randomFillSync(buf)
-  ]);
-}
-
-const reqChunks = [
-  Buffer.concat([
-    formDataFile('file', 'file.bin', 'application/octet-stream'),
-    formDataSection('foo', 'foo value'),
-  ]),
-  formDataSection('bar', 'bar value'),
-  Buffer.from(`\r\n--${BOUNDARY}--\r\n`)
-];
-const bb = busboy({
-  headers: {
-    'content-type': `multipart/form-data; boundary=${BOUNDARY}`
-  }
-});
-const expected = [
-  { type: 'file',
-    name: 'file',
-    info: {
-      filename: 'file.bin',
-      encoding: '7bit',
-      mimeType: 'application/octet-stream',
-    },
-  },
-  { type: 'field',
-    name: 'foo',
-    val: 'foo value',
-    info: {
-      nameTruncated: false,
-      valueTruncated: false,
-      encoding: '7bit',
-      mimeType: 'text/plain',
-    },
-  },
-  { type: 'field',
-    name: 'bar',
-    val: 'bar value',
-    info: {
-      nameTruncated: false,
-      valueTruncated: false,
-      encoding: '7bit',
-      mimeType: 'text/plain',
-    },
-  },
-];
-const results = [];
-
-bb.on('field', (name, val, info) => {
-  results.push({ type: 'field', name, val, info });
-});
-
-bb.on('file', (name, stream, info) => {
-  results.push({ type: 'file', name, info });
-  // Simulate a pipe where the destination is pausing (perhaps due to waiting
-  // for file system write to finish)
-  setTimeout(() => {
-    stream.resume();
-  }, 10);
-});
-
-bb.on('close', mustCall(() => {
-  assert.deepStrictEqual(
-    results,
-    expected,
-    'Results mismatch.\n'
-      + `Parsed: ${inspect(results)}\n`
-      + `Expected: ${inspect(expected)}`
-  );
-}));
-
-for (const chunk of reqChunks)
-  bb.write(chunk);
-bb.end();

+ 0 - 1053
node_modules/busboy/test/test-types-multipart.js

@@ -1,1053 +0,0 @@
-'use strict';
-
-const assert = require('assert');
-const { inspect } = require('util');
-
-const busboy = require('..');
-
-const active = new Map();
-
-const tests = [
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; name="file_name_0"',
-       '',
-       'super alpha file',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; name="file_name_1"',
-       '',
-       'super beta file',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_0"; filename="1k_a.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'A'.repeat(1023),
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_1"; filename="1k_b.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'B'.repeat(1023),
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    expected: [
-      { type: 'field',
-        name: 'file_name_0',
-        val: 'super alpha file',
-        info: {
-          nameTruncated: false,
-          valueTruncated: false,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-      },
-      { type: 'field',
-        name: 'file_name_1',
-        val: 'super beta file',
-        info: {
-          nameTruncated: false,
-          valueTruncated: false,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-      },
-      { type: 'file',
-        name: 'upload_file_0',
-        data: Buffer.from('A'.repeat(1023)),
-        info: {
-          filename: '1k_a.dat',
-          encoding: '7bit',
-          mimeType: 'application/octet-stream',
-        },
-        limited: false,
-      },
-      { type: 'file',
-        name: 'upload_file_1',
-        data: Buffer.from('B'.repeat(1023)),
-        info: {
-          filename: '1k_b.dat',
-          encoding: '7bit',
-          mimeType: 'application/octet-stream',
-        },
-        limited: false,
-      },
-    ],
-    what: 'Fields and files'
-  },
-  { source: [
-      ['------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
-       'Content-Disposition: form-data; name="cont"',
-       '',
-       'some random content',
-       '------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
-       'Content-Disposition: form-data; name="pass"',
-       '',
-       'some random pass',
-       '------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
-       'Content-Disposition: form-data; name=bit',
-       '',
-       '2',
-       '------WebKitFormBoundaryTB2MiQ36fnSJlrhY--'
-      ].join('\r\n')
-    ],
-    boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
-    expected: [
-      { type: 'field',
-        name: 'cont',
-        val: 'some random content',
-        info: {
-          nameTruncated: false,
-          valueTruncated: false,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-      },
-      { type: 'field',
-        name: 'pass',
-        val: 'some random pass',
-        info: {
-          nameTruncated: false,
-          valueTruncated: false,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-      },
-      { type: 'field',
-        name: 'bit',
-        val: '2',
-        info: {
-          nameTruncated: false,
-          valueTruncated: false,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-      },
-    ],
-    what: 'Fields only'
-  },
-  { source: [
-      ''
-    ],
-    boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
-    expected: [
-      { error: 'Unexpected end of form' },
-    ],
-    what: 'No fields and no files'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; name="file_name_0"',
-       '',
-       'super alpha file',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_0"; filename="1k_a.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    limits: {
-      fileSize: 13,
-      fieldSize: 5
-    },
-    expected: [
-      { type: 'field',
-        name: 'file_name_0',
-        val: 'super',
-        info: {
-          nameTruncated: false,
-          valueTruncated: true,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-      },
-      { type: 'file',
-        name: 'upload_file_0',
-        data: Buffer.from('ABCDEFGHIJKLM'),
-        info: {
-          filename: '1k_a.dat',
-          encoding: '7bit',
-          mimeType: 'application/octet-stream',
-        },
-        limited: true,
-      },
-    ],
-    what: 'Fields and files (limits)'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; name="file_name_0"',
-       '',
-       'super alpha file',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_0"; filename="1k_a.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    limits: {
-      files: 0
-    },
-    expected: [
-      { type: 'field',
-        name: 'file_name_0',
-        val: 'super alpha file',
-        info: {
-          nameTruncated: false,
-          valueTruncated: false,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-      },
-      'filesLimit',
-    ],
-    what: 'Fields and files (limits: 0 files)'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; name="file_name_0"',
-       '',
-       'super alpha file',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; name="file_name_1"',
-       '',
-       'super beta file',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_0"; filename="1k_a.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'A'.repeat(1023),
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_1"; filename="1k_b.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'B'.repeat(1023),
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    expected: [
-      { type: 'field',
-        name: 'file_name_0',
-        val: 'super alpha file',
-        info: {
-          nameTruncated: false,
-          valueTruncated: false,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-      },
-      { type: 'field',
-        name: 'file_name_1',
-        val: 'super beta file',
-        info: {
-          nameTruncated: false,
-          valueTruncated: false,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-      },
-    ],
-    events: ['field'],
-    what: 'Fields and (ignored) files'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_0"; filename="/tmp/1k_a.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_1"; filename="C:\\files\\1k_b.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_2"; filename="relative/1k_c.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    expected: [
-      { type: 'file',
-        name: 'upload_file_0',
-        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
-        info: {
-          filename: '1k_a.dat',
-          encoding: '7bit',
-          mimeType: 'application/octet-stream',
-        },
-        limited: false,
-      },
-      { type: 'file',
-        name: 'upload_file_1',
-        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
-        info: {
-          filename: '1k_b.dat',
-          encoding: '7bit',
-          mimeType: 'application/octet-stream',
-        },
-        limited: false,
-      },
-      { type: 'file',
-        name: 'upload_file_2',
-        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
-        info: {
-          filename: '1k_c.dat',
-          encoding: '7bit',
-          mimeType: 'application/octet-stream',
-        },
-        limited: false,
-      },
-    ],
-    what: 'Files with filenames containing paths'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_0"; filename="/absolute/1k_a.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_1"; filename="C:\\absolute\\1k_b.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_2"; filename="relative/1k_c.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    preservePath: true,
-    expected: [
-      { type: 'file',
-        name: 'upload_file_0',
-        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
-        info: {
-          filename: '/absolute/1k_a.dat',
-          encoding: '7bit',
-          mimeType: 'application/octet-stream',
-        },
-        limited: false,
-      },
-      { type: 'file',
-        name: 'upload_file_1',
-        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
-        info: {
-          filename: 'C:\\absolute\\1k_b.dat',
-          encoding: '7bit',
-          mimeType: 'application/octet-stream',
-        },
-        limited: false,
-      },
-      { type: 'file',
-        name: 'upload_file_2',
-        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
-        info: {
-          filename: 'relative/1k_c.dat',
-          encoding: '7bit',
-          mimeType: 'application/octet-stream',
-        },
-        limited: false,
-      },
-    ],
-    what: 'Paths to be preserved through the preservePath option'
-  },
-  { source: [
-      ['------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
-       'Content-Disposition: form-data; name="cont"',
-       'Content-Type: ',
-       '',
-       'some random content',
-       '------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
-       'Content-Disposition: ',
-       '',
-       'some random pass',
-       '------WebKitFormBoundaryTB2MiQ36fnSJlrhY--'
-      ].join('\r\n')
-    ],
-    boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
-    expected: [
-      { type: 'field',
-        name: 'cont',
-        val: 'some random content',
-        info: {
-          nameTruncated: false,
-          valueTruncated: false,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-      },
-    ],
-    what: 'Empty content-type and empty content-disposition'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="file"; filename*=utf-8\'\'n%C3%A4me.txt',
-       'Content-Type: application/octet-stream',
-       '',
-       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    expected: [
-      { type: 'file',
-        name: 'file',
-        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
-        info: {
-          filename: 'näme.txt',
-          encoding: '7bit',
-          mimeType: 'application/octet-stream',
-        },
-        limited: false,
-      },
-    ],
-    what: 'Unicode filenames'
-  },
-  { source: [
-      ['--asdasdasdasd\r\n',
-       'Content-Type: text/plain\r\n',
-       'Content-Disposition: form-data; name="foo"\r\n',
-       '\r\n',
-       'asd\r\n',
-       '--asdasdasdasd--'
-      ].join(':)')
-    ],
-    boundary: 'asdasdasdasd',
-    expected: [
-      { error: 'Malformed part header' },
-      { error: 'Unexpected end of form' },
-    ],
-    what: 'Stopped mid-header'
-  },
-  { source: [
-      ['------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
-       'Content-Disposition: form-data; name="cont"',
-       'Content-Type: application/json',
-       '',
-       '{}',
-       '------WebKitFormBoundaryTB2MiQ36fnSJlrhY--',
-      ].join('\r\n')
-    ],
-    boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
-    expected: [
-      { type: 'field',
-        name: 'cont',
-        val: '{}',
-        info: {
-          nameTruncated: false,
-          valueTruncated: false,
-          encoding: '7bit',
-          mimeType: 'application/json',
-        },
-      },
-    ],
-    what: 'content-type for fields'
-  },
-  { source: [
-      '------WebKitFormBoundaryTB2MiQ36fnSJlrhY--',
-    ],
-    boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
-    expected: [],
-    what: 'empty form'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name=upload_file_0; filename="1k_a.dat"',
-       'Content-Type: application/octet-stream',
-       'Content-Transfer-Encoding: binary',
-       '',
-       '',
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    expected: [
-      { type: 'file',
-        name: 'upload_file_0',
-        data: Buffer.alloc(0),
-        info: {
-          filename: '1k_a.dat',
-          encoding: 'binary',
-          mimeType: 'application/octet-stream',
-        },
-        limited: false,
-        err: 'Unexpected end of form',
-      },
-      { error: 'Unexpected end of form' },
-    ],
-    what: 'Stopped mid-file #1'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name=upload_file_0; filename="1k_a.dat"',
-       'Content-Type: application/octet-stream',
-       '',
-       'a',
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    expected: [
-      { type: 'file',
-        name: 'upload_file_0',
-        data: Buffer.from('a'),
-        info: {
-          filename: '1k_a.dat',
-          encoding: '7bit',
-          mimeType: 'application/octet-stream',
-        },
-        limited: false,
-        err: 'Unexpected end of form',
-      },
-      { error: 'Unexpected end of form' },
-    ],
-    what: 'Stopped mid-file #2'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_0"; filename="notes.txt"',
-       'Content-Type: text/plain; charset=utf8',
-       '',
-       'a',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    expected: [
-      { type: 'file',
-        name: 'upload_file_0',
-        data: Buffer.from('a'),
-        info: {
-          filename: 'notes.txt',
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-        limited: false,
-      },
-    ],
-    what: 'Text file with charset'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_0"; filename="notes.txt"',
-       'Content-Type: ',
-       ' text/plain; charset=utf8',
-       '',
-       'a',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    expected: [
-      { type: 'file',
-        name: 'upload_file_0',
-        data: Buffer.from('a'),
-        info: {
-          filename: 'notes.txt',
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-        limited: false,
-      },
-    ],
-    what: 'Folded header value'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Type: text/plain; charset=utf8',
-       '',
-       'a',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    expected: [],
-    what: 'No Content-Disposition'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; name="file_name_0"',
-       '',
-       'a'.repeat(64 * 1024),
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_0"; filename="notes.txt"',
-       'Content-Type: ',
-       ' text/plain; charset=utf8',
-       '',
-       'bc',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    limits: {
-      fieldSize: Infinity,
-    },
-    expected: [
-      { type: 'file',
-        name: 'upload_file_0',
-        data: Buffer.from('bc'),
-        info: {
-          filename: 'notes.txt',
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-        limited: false,
-      },
-    ],
-    events: [ 'file' ],
-    what: 'Skip field parts if no listener'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; name="file_name_0"',
-       '',
-       'a',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_0"; filename="notes.txt"',
-       'Content-Type: ',
-       ' text/plain; charset=utf8',
-       '',
-       'bc',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    limits: {
-      parts: 1,
-    },
-    expected: [
-      { type: 'field',
-        name: 'file_name_0',
-        val: 'a',
-        info: {
-          nameTruncated: false,
-          valueTruncated: false,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-      },
-      'partsLimit',
-    ],
-    what: 'Parts limit'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; name="file_name_0"',
-       '',
-       'a',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; name="file_name_1"',
-       '',
-       'b',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    limits: {
-      fields: 1,
-    },
-    expected: [
-      { type: 'field',
-        name: 'file_name_0',
-        val: 'a',
-        info: {
-          nameTruncated: false,
-          valueTruncated: false,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-      },
-      'fieldsLimit',
-    ],
-    what: 'Fields limit'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_0"; filename="notes.txt"',
-       'Content-Type: text/plain; charset=utf8',
-       '',
-       'ab',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_1"; filename="notes2.txt"',
-       'Content-Type: text/plain; charset=utf8',
-       '',
-       'cd',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    limits: {
-      files: 1,
-    },
-    expected: [
-      { type: 'file',
-        name: 'upload_file_0',
-        data: Buffer.from('ab'),
-        info: {
-          filename: 'notes.txt',
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-        limited: false,
-      },
-      'filesLimit',
-    ],
-    what: 'Files limit'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + `name="upload_file_0"; filename="${'a'.repeat(64 * 1024)}.txt"`,
-       'Content-Type: text/plain; charset=utf8',
-       '',
-       'ab',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_1"; filename="notes2.txt"',
-       'Content-Type: text/plain; charset=utf8',
-       '',
-       'cd',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    expected: [
-      { error: 'Malformed part header' },
-      { type: 'file',
-        name: 'upload_file_1',
-        data: Buffer.from('cd'),
-        info: {
-          filename: 'notes2.txt',
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-        limited: false,
-      },
-    ],
-    what: 'Oversized part header'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + 'name="upload_file_0"; filename="notes.txt"',
-       'Content-Type: text/plain; charset=utf8',
-       '',
-       'a'.repeat(31) + '\r',
-      ].join('\r\n'),
-      'b'.repeat(40),
-      '\r\n-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    fileHwm: 32,
-    expected: [
-      { type: 'file',
-        name: 'upload_file_0',
-        data: Buffer.from('a'.repeat(31) + '\r' + 'b'.repeat(40)),
-        info: {
-          filename: 'notes.txt',
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-        limited: false,
-      },
-    ],
-    what: 'Lookbehind data should not stall file streams'
-  },
-  { source: [
-      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + `name="upload_file_0"; filename="${'a'.repeat(8 * 1024)}.txt"`,
-       'Content-Type: text/plain; charset=utf8',
-       '',
-       'ab',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + `name="upload_file_1"; filename="${'b'.repeat(8 * 1024)}.txt"`,
-       'Content-Type: text/plain; charset=utf8',
-       '',
-       'cd',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-       'Content-Disposition: form-data; '
-         + `name="upload_file_2"; filename="${'c'.repeat(8 * 1024)}.txt"`,
-       'Content-Type: text/plain; charset=utf8',
-       '',
-       'ef',
-       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
-      ].join('\r\n')
-    ],
-    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
-    expected: [
-      { type: 'file',
-        name: 'upload_file_0',
-        data: Buffer.from('ab'),
-        info: {
-          filename: `${'a'.repeat(8 * 1024)}.txt`,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-        limited: false,
-      },
-      { type: 'file',
-        name: 'upload_file_1',
-        data: Buffer.from('cd'),
-        info: {
-          filename: `${'b'.repeat(8 * 1024)}.txt`,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-        limited: false,
-      },
-      { type: 'file',
-        name: 'upload_file_2',
-        data: Buffer.from('ef'),
-        info: {
-          filename: `${'c'.repeat(8 * 1024)}.txt`,
-          encoding: '7bit',
-          mimeType: 'text/plain',
-        },
-        limited: false,
-      },
-    ],
-    what: 'Header size limit should be per part'
-  },
-  { source: [
-      '\r\n--d1bf46b3-aa33-4061-b28d-6c5ced8b08ee\r\n',
-      'Content-Type: application/gzip\r\n'
-        + 'Content-Encoding: gzip\r\n'
-        + 'Content-Disposition: form-data; name=batch-1; filename=batch-1'
-        + '\r\n\r\n',
-      '\r\n--d1bf46b3-aa33-4061-b28d-6c5ced8b08ee--',
-    ],
-    boundary: 'd1bf46b3-aa33-4061-b28d-6c5ced8b08ee',
-    expected: [
-      { type: 'file',
-        name: 'batch-1',
-        data: Buffer.alloc(0),
-        info: {
-          filename: 'batch-1',
-          encoding: '7bit',
-          mimeType: 'application/gzip',
-        },
-        limited: false,
-      },
-    ],
-    what: 'Empty part'
-  },
-];
-
-for (const test of tests) {
-  active.set(test, 1);
-
-  const { what, boundary, events, limits, preservePath, fileHwm } = test;
-  const bb = busboy({
-    fileHwm,
-    limits,
-    preservePath,
-    headers: {
-      'content-type': `multipart/form-data; boundary=${boundary}`,
-    }
-  });
-  const results = [];
-
-  if (events === undefined || events.includes('field')) {
-    bb.on('field', (name, val, info) => {
-      results.push({ type: 'field', name, val, info });
-    });
-  }
-
-  if (events === undefined || events.includes('file')) {
-    bb.on('file', (name, stream, info) => {
-      const data = [];
-      let nb = 0;
-      const file = {
-        type: 'file',
-        name,
-        data: null,
-        info,
-        limited: false,
-      };
-      results.push(file);
-      stream.on('data', (d) => {
-        data.push(d);
-        nb += d.length;
-      }).on('limit', () => {
-        file.limited = true;
-      }).on('close', () => {
-        file.data = Buffer.concat(data, nb);
-        assert.strictEqual(stream.truncated, file.limited);
-      }).once('error', (err) => {
-        file.err = err.message;
-      });
-    });
-  }
-
-  bb.on('error', (err) => {
-    results.push({ error: err.message });
-  });
-
-  bb.on('partsLimit', () => {
-    results.push('partsLimit');
-  });
-
-  bb.on('filesLimit', () => {
-    results.push('filesLimit');
-  });
-
-  bb.on('fieldsLimit', () => {
-    results.push('fieldsLimit');
-  });
-
-  bb.on('close', () => {
-    active.delete(test);
-
-    assert.deepStrictEqual(
-      results,
-      test.expected,
-      `[${what}] Results mismatch.\n`
-        + `Parsed: ${inspect(results)}\n`
-        + `Expected: ${inspect(test.expected)}`
-    );
-  });
-
-  for (const src of test.source) {
-    const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
-    bb.write(buf);
-  }
-  bb.end();
-}
-
-// Byte-by-byte versions
-for (let test of tests) {
-  test = { ...test };
-  test.what += ' (byte-by-byte)';
-  active.set(test, 1);
-
-  const { what, boundary, events, limits, preservePath, fileHwm } = test;
-  const bb = busboy({
-    fileHwm,
-    limits,
-    preservePath,
-    headers: {
-      'content-type': `multipart/form-data; boundary=${boundary}`,
-    }
-  });
-  const results = [];
-
-  if (events === undefined || events.includes('field')) {
-    bb.on('field', (name, val, info) => {
-      results.push({ type: 'field', name, val, info });
-    });
-  }
-
-  if (events === undefined || events.includes('file')) {
-    bb.on('file', (name, stream, info) => {
-      const data = [];
-      let nb = 0;
-      const file = {
-        type: 'file',
-        name,
-        data: null,
-        info,
-        limited: false,
-      };
-      results.push(file);
-      stream.on('data', (d) => {
-        data.push(d);
-        nb += d.length;
-      }).on('limit', () => {
-        file.limited = true;
-      }).on('close', () => {
-        file.data = Buffer.concat(data, nb);
-        assert.strictEqual(stream.truncated, file.limited);
-      }).once('error', (err) => {
-        file.err = err.message;
-      });
-    });
-  }
-
-  bb.on('error', (err) => {
-    results.push({ error: err.message });
-  });
-
-  bb.on('partsLimit', () => {
-    results.push('partsLimit');
-  });
-
-  bb.on('filesLimit', () => {
-    results.push('filesLimit');
-  });
-
-  bb.on('fieldsLimit', () => {
-    results.push('fieldsLimit');
-  });
-
-  bb.on('close', () => {
-    active.delete(test);
-
-    assert.deepStrictEqual(
-      results,
-      test.expected,
-      `[${what}] Results mismatch.\n`
-        + `Parsed: ${inspect(results)}\n`
-        + `Expected: ${inspect(test.expected)}`
-    );
-  });
-
-  for (const src of test.source) {
-    const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
-    for (let i = 0; i < buf.length; ++i)
-      bb.write(buf.slice(i, i + 1));
-  }
-  bb.end();
-}
-
-{
-  let exception = false;
-  process.once('uncaughtException', (ex) => {
-    exception = true;
-    throw ex;
-  });
-  process.on('exit', () => {
-    if (exception || active.size === 0)
-      return;
-    process.exitCode = 1;
-    console.error('==========================');
-    console.error(`${active.size} test(s) did not finish:`);
-    console.error('==========================');
-    console.error(Array.from(active.keys()).map((v) => v.what).join('\n'));
-  });
-}

+ 0 - 488
node_modules/busboy/test/test-types-urlencoded.js

@@ -1,488 +0,0 @@
-'use strict';
-
-const assert = require('assert');
-const { transcode } = require('buffer');
-const { inspect } = require('util');
-
-const busboy = require('..');
-
-const active = new Map();
-
-const tests = [
-  { source: ['foo'],
-    expected: [
-      ['foo',
-       '',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Unassigned value'
-  },
-  { source: ['foo=bar'],
-    expected: [
-      ['foo',
-       'bar',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Assigned value'
-  },
-  { source: ['foo&bar=baz'],
-    expected: [
-      ['foo',
-       '',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-      ['bar',
-       'baz',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Unassigned and assigned value'
-  },
-  { source: ['foo=bar&baz'],
-    expected: [
-      ['foo',
-       'bar',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-      ['baz',
-       '',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Assigned and unassigned value'
-  },
-  { source: ['foo=bar&baz=bla'],
-    expected: [
-      ['foo',
-       'bar',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-      ['baz',
-       'bla',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Two assigned values'
-  },
-  { source: ['foo&bar'],
-    expected: [
-      ['foo',
-       '',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-      ['bar',
-       '',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Two unassigned values'
-  },
-  { source: ['foo&bar&'],
-    expected: [
-      ['foo',
-       '',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-      ['bar',
-       '',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Two unassigned values and ampersand'
-  },
-  { source: ['foo+1=bar+baz%2Bquux'],
-    expected: [
-      ['foo 1',
-       'bar baz+quux',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Assigned key and value with (plus) space'
-  },
-  { source: ['foo=bar%20baz%21'],
-    expected: [
-      ['foo',
-       'bar baz!',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Assigned value with encoded bytes'
-  },
-  { source: ['foo%20bar=baz%20bla%21'],
-    expected: [
-      ['foo bar',
-       'baz bla!',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Assigned value with encoded bytes #2'
-  },
-  { source: ['foo=bar%20baz%21&num=1000'],
-    expected: [
-      ['foo',
-       'bar baz!',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-      ['num',
-       '1000',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Two assigned values, one with encoded bytes'
-  },
-  { source: [
-      Array.from(transcode(Buffer.from('foo'), 'utf8', 'utf16le')).map(
-        (n) => `%${n.toString(16).padStart(2, '0')}`
-      ).join(''),
-      '=',
-      Array.from(transcode(Buffer.from('😀!'), 'utf8', 'utf16le')).map(
-        (n) => `%${n.toString(16).padStart(2, '0')}`
-      ).join(''),
-    ],
-    expected: [
-      ['foo',
-       '😀!',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'UTF-16LE',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    charset: 'UTF-16LE',
-    what: 'Encoded value with multi-byte charset'
-  },
-  { source: [
-      'foo=<',
-      Array.from(transcode(Buffer.from('©:^þ'), 'utf8', 'latin1')).map(
-        (n) => `%${n.toString(16).padStart(2, '0')}`
-      ).join(''),
-    ],
-    expected: [
-      ['foo',
-       '<©:^þ',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'ISO-8859-1',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    charset: 'ISO-8859-1',
-    what: 'Encoded value with single-byte, ASCII-compatible, non-UTF8 charset'
-  },
-  { source: ['foo=bar&baz=bla'],
-    expected: [],
-    what: 'Limits: zero fields',
-    limits: { fields: 0 }
-  },
-  { source: ['foo=bar&baz=bla'],
-    expected: [
-      ['foo',
-       'bar',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Limits: one field',
-    limits: { fields: 1 }
-  },
-  { source: ['foo=bar&baz=bla'],
-    expected: [
-      ['foo',
-       'bar',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-      ['baz',
-       'bla',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Limits: field part lengths match limits',
-    limits: { fieldNameSize: 3, fieldSize: 3 }
-  },
-  { source: ['foo=bar&baz=bla'],
-    expected: [
-      ['fo',
-       'bar',
-       { nameTruncated: true,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-      ['ba',
-       'bla',
-       { nameTruncated: true,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Limits: truncated field name',
-    limits: { fieldNameSize: 2 }
-  },
-  { source: ['foo=bar&baz=bla'],
-    expected: [
-      ['foo',
-       'ba',
-       { nameTruncated: false,
-         valueTruncated: true,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-      ['baz',
-       'bl',
-       { nameTruncated: false,
-         valueTruncated: true,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Limits: truncated field value',
-    limits: { fieldSize: 2 }
-  },
-  { source: ['foo=bar&baz=bla'],
-    expected: [
-      ['fo',
-       'ba',
-       { nameTruncated: true,
-         valueTruncated: true,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-      ['ba',
-       'bl',
-       { nameTruncated: true,
-         valueTruncated: true,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Limits: truncated field name and value',
-    limits: { fieldNameSize: 2, fieldSize: 2 }
-  },
-  { source: ['foo=bar&baz=bla'],
-    expected: [
-      ['fo',
-       '',
-       { nameTruncated: true,
-         valueTruncated: true,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-      ['ba',
-       '',
-       { nameTruncated: true,
-         valueTruncated: true,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Limits: truncated field name and zero value limit',
-    limits: { fieldNameSize: 2, fieldSize: 0 }
-  },
-  { source: ['foo=bar&baz=bla'],
-    expected: [
-      ['',
-       '',
-       { nameTruncated: true,
-         valueTruncated: true,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-      ['',
-       '',
-       { nameTruncated: true,
-         valueTruncated: true,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Limits: truncated zero field name and zero value limit',
-    limits: { fieldNameSize: 0, fieldSize: 0 }
-  },
-  { source: ['&'],
-    expected: [],
-    what: 'Ampersand'
-  },
-  { source: ['&&&&&'],
-    expected: [],
-    what: 'Many ampersands'
-  },
-  { source: ['='],
-    expected: [
-      ['',
-       '',
-       { nameTruncated: false,
-         valueTruncated: false,
-         encoding: 'utf-8',
-         mimeType: 'text/plain' },
-      ],
-    ],
-    what: 'Assigned value, empty name and value'
-  },
-  { source: [''],
-    expected: [],
-    what: 'Nothing'
-  },
-];
-
-for (const test of tests) {
-  active.set(test, 1);
-
-  const { what } = test;
-  const charset = test.charset || 'utf-8';
-  const bb = busboy({
-    limits: test.limits,
-    headers: {
-      'content-type': `application/x-www-form-urlencoded; charset=${charset}`,
-    },
-  });
-  const results = [];
-
-  bb.on('field', (key, val, info) => {
-    results.push([key, val, info]);
-  });
-
-  bb.on('file', () => {
-    throw new Error(`[${what}] Unexpected file`);
-  });
-
-  bb.on('close', () => {
-    active.delete(test);
-
-    assert.deepStrictEqual(
-      results,
-      test.expected,
-      `[${what}] Results mismatch.\n`
-        + `Parsed: ${inspect(results)}\n`
-        + `Expected: ${inspect(test.expected)}`
-    );
-  });
-
-  for (const src of test.source) {
-    const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
-    bb.write(buf);
-  }
-  bb.end();
-}
-
-// Byte-by-byte versions
-for (let test of tests) {
-  test = { ...test };
-  test.what += ' (byte-by-byte)';
-  active.set(test, 1);
-
-  const { what } = test;
-  const charset = test.charset || 'utf-8';
-  const bb = busboy({
-    limits: test.limits,
-    headers: {
-      'content-type': `application/x-www-form-urlencoded; charset="${charset}"`,
-    },
-  });
-  const results = [];
-
-  bb.on('field', (key, val, info) => {
-    results.push([key, val, info]);
-  });
-
-  bb.on('file', () => {
-    throw new Error(`[${what}] Unexpected file`);
-  });
-
-  bb.on('close', () => {
-    active.delete(test);
-
-    assert.deepStrictEqual(
-      results,
-      test.expected,
-      `[${what}] Results mismatch.\n`
-        + `Parsed: ${inspect(results)}\n`
-        + `Expected: ${inspect(test.expected)}`
-    );
-  });
-
-  for (const src of test.source) {
-    const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
-    for (let i = 0; i < buf.length; ++i)
-      bb.write(buf.slice(i, i + 1));
-  }
-  bb.end();
-}
-
-{
-  let exception = false;
-  process.once('uncaughtException', (ex) => {
-    exception = true;
-    throw ex;
-  });
-  process.on('exit', () => {
-    if (exception || active.size === 0)
-      return;
-    process.exitCode = 1;
-    console.error('==========================');
-    console.error(`${active.size} test(s) did not finish:`);
-    console.error('==========================');
-    console.error(Array.from(active.keys()).map((v) => v.what).join('\n'));
-  });
-}

+ 0 - 20
node_modules/busboy/test/test.js

@@ -1,20 +0,0 @@
-'use strict';
-
-const { spawnSync } = require('child_process');
-const { readdirSync } = require('fs');
-const { join } = require('path');
-
-const files = readdirSync(__dirname).sort();
-for (const filename of files) {
-  if (filename.startsWith('test-')) {
-    const path = join(__dirname, filename);
-    console.log(`> Running ${filename} ...`);
-    const result = spawnSync(`${process.argv0} ${path}`, {
-      shell: true,
-      stdio: 'inherit',
-      windowsHide: true
-    });
-    if (result.status !== 0)
-      process.exitCode = 1;
-  }
-}

+ 0 - 24
node_modules/concat-stream/LICENSE

@@ -1,24 +0,0 @@
-The MIT License
-
-Copyright (c) 2013 Max Ogden
-
-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.

+ 0 - 144
node_modules/concat-stream/index.js

@@ -1,144 +0,0 @@
-var Writable = require('readable-stream').Writable
-var inherits = require('inherits')
-var bufferFrom = require('buffer-from')
-
-if (typeof Uint8Array === 'undefined') {
-  var U8 = require('typedarray').Uint8Array
-} else {
-  var U8 = Uint8Array
-}
-
-function ConcatStream(opts, cb) {
-  if (!(this instanceof ConcatStream)) return new ConcatStream(opts, cb)
-
-  if (typeof opts === 'function') {
-    cb = opts
-    opts = {}
-  }
-  if (!opts) opts = {}
-
-  var encoding = opts.encoding
-  var shouldInferEncoding = false
-
-  if (!encoding) {
-    shouldInferEncoding = true
-  } else {
-    encoding =  String(encoding).toLowerCase()
-    if (encoding === 'u8' || encoding === 'uint8') {
-      encoding = 'uint8array'
-    }
-  }
-
-  Writable.call(this, { objectMode: true })
-
-  this.encoding = encoding
-  this.shouldInferEncoding = shouldInferEncoding
-
-  if (cb) this.on('finish', function () { cb(this.getBody()) })
-  this.body = []
-}
-
-module.exports = ConcatStream
-inherits(ConcatStream, Writable)
-
-ConcatStream.prototype._write = function(chunk, enc, next) {
-  this.body.push(chunk)
-  next()
-}
-
-ConcatStream.prototype.inferEncoding = function (buff) {
-  var firstBuffer = buff === undefined ? this.body[0] : buff;
-  if (Buffer.isBuffer(firstBuffer)) return 'buffer'
-  if (typeof Uint8Array !== 'undefined' && firstBuffer instanceof Uint8Array) return 'uint8array'
-  if (Array.isArray(firstBuffer)) return 'array'
-  if (typeof firstBuffer === 'string') return 'string'
-  if (Object.prototype.toString.call(firstBuffer) === "[object Object]") return 'object'
-  return 'buffer'
-}
-
-ConcatStream.prototype.getBody = function () {
-  if (!this.encoding && this.body.length === 0) return []
-  if (this.shouldInferEncoding) this.encoding = this.inferEncoding()
-  if (this.encoding === 'array') return arrayConcat(this.body)
-  if (this.encoding === 'string') return stringConcat(this.body)
-  if (this.encoding === 'buffer') return bufferConcat(this.body)
-  if (this.encoding === 'uint8array') return u8Concat(this.body)
-  return this.body
-}
-
-var isArray = Array.isArray || function (arr) {
-  return Object.prototype.toString.call(arr) == '[object Array]'
-}
-
-function isArrayish (arr) {
-  return /Array\]$/.test(Object.prototype.toString.call(arr))
-}
-
-function isBufferish (p) {
-  return typeof p === 'string' || isArrayish(p) || (p && typeof p.subarray === 'function')
-}
-
-function stringConcat (parts) {
-  var strings = []
-  var needsToString = false
-  for (var i = 0; i < parts.length; i++) {
-    var p = parts[i]
-    if (typeof p === 'string') {
-      strings.push(p)
-    } else if (Buffer.isBuffer(p)) {
-      strings.push(p)
-    } else if (isBufferish(p)) {
-      strings.push(bufferFrom(p))
-    } else {
-      strings.push(bufferFrom(String(p)))
-    }
-  }
-  if (Buffer.isBuffer(parts[0])) {
-    strings = Buffer.concat(strings)
-    strings = strings.toString('utf8')
-  } else {
-    strings = strings.join('')
-  }
-  return strings
-}
-
-function bufferConcat (parts) {
-  var bufs = []
-  for (var i = 0; i < parts.length; i++) {
-    var p = parts[i]
-    if (Buffer.isBuffer(p)) {
-      bufs.push(p)
-    } else if (isBufferish(p)) {
-      bufs.push(bufferFrom(p))
-    } else {
-      bufs.push(bufferFrom(String(p)))
-    }
-  }
-  return Buffer.concat(bufs)
-}
-
-function arrayConcat (parts) {
-  var res = []
-  for (var i = 0; i < parts.length; i++) {
-    res.push.apply(res, parts[i])
-  }
-  return res
-}
-
-function u8Concat (parts) {
-  var len = 0
-  for (var i = 0; i < parts.length; i++) {
-    if (typeof parts[i] === 'string') {
-      parts[i] = bufferFrom(parts[i])
-    }
-    len += parts[i].length
-  }
-  var u8 = new U8(len)
-  for (var i = 0, offset = 0; i < parts.length; i++) {
-    var part = parts[i]
-    for (var j = 0; j < part.length; j++) {
-      u8[offset++] = part[j]
-    }
-  }
-  return u8
-}

+ 0 - 55
node_modules/concat-stream/package.json

@@ -1,55 +0,0 @@
-{
-  "name": "concat-stream",
-  "version": "1.6.2",
-  "description": "writable stream that concatenates strings or binary data and calls a callback with the result",
-  "tags": [
-    "stream",
-    "simple",
-    "util",
-    "utility"
-  ],
-  "author": "Max Ogden <max@maxogden.com>",
-  "repository": {
-    "type": "git",
-    "url": "http://github.com/maxogden/concat-stream.git"
-  },
-  "bugs": {
-    "url": "http://github.com/maxogden/concat-stream/issues"
-  },
-  "engines": [
-    "node >= 0.8"
-  ],
-  "main": "index.js",
-  "files": [
-    "index.js"
-  ],
-  "scripts": {
-    "test": "tape test/*.js test/server/*.js"
-  },
-  "license": "MIT",
-  "dependencies": {
-    "buffer-from": "^1.0.0",
-    "inherits": "^2.0.3",
-    "readable-stream": "^2.2.2",
-    "typedarray": "^0.0.6"
-  },
-  "devDependencies": {
-    "tape": "^4.6.3"
-  },
-  "testling": {
-    "files": "test/*.js",
-    "browsers": [
-      "ie/8..latest",
-      "firefox/17..latest",
-      "firefox/nightly",
-      "chrome/22..latest",
-      "chrome/canary",
-      "opera/12..latest",
-      "opera/next",
-      "safari/5.1..latest",
-      "ipad/6.0..latest",
-      "iphone/6.0..latest",
-      "android-browser/4.2..latest"
-    ]
-  }
-}

+ 0 - 102
node_modules/concat-stream/readme.md

@@ -1,102 +0,0 @@
-# concat-stream
-
-Writable stream that concatenates all the data from a stream and calls a callback with the result. Use this when you want to collect all the data from a stream into a single buffer.
-
-[![Build Status](https://travis-ci.org/maxogden/concat-stream.svg?branch=master)](https://travis-ci.org/maxogden/concat-stream)
-
-[![NPM](https://nodei.co/npm/concat-stream.png)](https://nodei.co/npm/concat-stream/)
-
-### description
-
-Streams emit many buffers. If you want to collect all of the buffers, and when the stream ends concatenate all of the buffers together and receive a single buffer then this is the module for you.
-
-Only use this if you know you can fit all of the output of your stream into a single Buffer (e.g. in RAM).
-
-There are also `objectMode` streams that emit things other than Buffers, and you can concatenate these too. See below for details.
-
-## Related
-
-`concat-stream` is part of the [mississippi stream utility collection](https://github.com/maxogden/mississippi) which includes more useful stream modules similar to this one.
-
-### examples
-
-#### Buffers
-
-```js
-var fs = require('fs')
-var concat = require('concat-stream')
-
-var readStream = fs.createReadStream('cat.png')
-var concatStream = concat(gotPicture)
-
-readStream.on('error', handleError)
-readStream.pipe(concatStream)
-
-function gotPicture(imageBuffer) {
-  // imageBuffer is all of `cat.png` as a node.js Buffer
-}
-
-function handleError(err) {
-  // handle your error appropriately here, e.g.:
-  console.error(err) // print the error to STDERR
-  process.exit(1) // exit program with non-zero exit code
-}
-
-```
-
-#### Arrays
-
-```js
-var write = concat(function(data) {})
-write.write([1,2,3])
-write.write([4,5,6])
-write.end()
-// data will be [1,2,3,4,5,6] in the above callback
-```
-
-#### Uint8Arrays
-
-```js
-var write = concat(function(data) {})
-var a = new Uint8Array(3)
-a[0] = 97; a[1] = 98; a[2] = 99
-write.write(a)
-write.write('!')
-write.end(Buffer.from('!!1'))
-```
-
-See `test/` for more examples
-
-# methods
-
-```js
-var concat = require('concat-stream')
-```
-
-## var writable = concat(opts={}, cb)
-
-Return a `writable` stream that will fire `cb(data)` with all of the data that
-was written to the stream. Data can be written to `writable` as strings,
-Buffers, arrays of byte integers, and Uint8Arrays. 
-
-By default `concat-stream` will give you back the same data type as the type of the first buffer written to the stream. Use `opts.encoding` to set what format `data` should be returned as, e.g. if you if you don't want to rely on the built-in type checking or for some other reason.
-
-* `string` - get a string
-* `buffer` - get back a Buffer
-* `array` - get an array of byte integers
-* `uint8array`, `u8`, `uint8` - get back a Uint8Array
-* `object`, get back an array of Objects
-
-If you don't specify an encoding, and the types can't be inferred (e.g. you write things that aren't in the list above), it will try to convert concat them into a `Buffer`.
-
-If nothing is written to `writable` then `data` will be an empty array `[]`.
-
-# error handling
-
-`concat-stream` does not handle errors for you, so you must handle errors on whatever streams you pipe into `concat-stream`. This is a general rule when programming with node.js streams: always handle errors on each and every stream. Since `concat-stream` is not itself a stream it does not emit errors.
-
-We recommend using [`end-of-stream`](https://npmjs.org/end-of-stream) or [`pump`](https://npmjs.org/pump) for writing error tolerant stream code.
-
-# license
-
-MIT LICENSE

+ 0 - 19
node_modules/core-util-is/LICENSE

@@ -1,19 +0,0 @@
-Copyright Node.js contributors. All rights reserved.
-
-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.

+ 0 - 3
node_modules/core-util-is/README.md

@@ -1,3 +0,0 @@
-# core-util-is
-
-The `util.is*` functions introduced in Node v0.12.

+ 0 - 107
node_modules/core-util-is/lib/util.js

@@ -1,107 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// 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.
-
-// NOTE: These type checking functions intentionally don't use `instanceof`
-// because it is fragile and can be easily faked with `Object.create()`.
-
-function isArray(arg) {
-  if (Array.isArray) {
-    return Array.isArray(arg);
-  }
-  return objectToString(arg) === '[object Array]';
-}
-exports.isArray = isArray;
-
-function isBoolean(arg) {
-  return typeof arg === 'boolean';
-}
-exports.isBoolean = isBoolean;
-
-function isNull(arg) {
-  return arg === null;
-}
-exports.isNull = isNull;
-
-function isNullOrUndefined(arg) {
-  return arg == null;
-}
-exports.isNullOrUndefined = isNullOrUndefined;
-
-function isNumber(arg) {
-  return typeof arg === 'number';
-}
-exports.isNumber = isNumber;
-
-function isString(arg) {
-  return typeof arg === 'string';
-}
-exports.isString = isString;
-
-function isSymbol(arg) {
-  return typeof arg === 'symbol';
-}
-exports.isSymbol = isSymbol;
-
-function isUndefined(arg) {
-  return arg === void 0;
-}
-exports.isUndefined = isUndefined;
-
-function isRegExp(re) {
-  return objectToString(re) === '[object RegExp]';
-}
-exports.isRegExp = isRegExp;
-
-function isObject(arg) {
-  return typeof arg === 'object' && arg !== null;
-}
-exports.isObject = isObject;
-
-function isDate(d) {
-  return objectToString(d) === '[object Date]';
-}
-exports.isDate = isDate;
-
-function isError(e) {
-  return (objectToString(e) === '[object Error]' || e instanceof Error);
-}
-exports.isError = isError;
-
-function isFunction(arg) {
-  return typeof arg === 'function';
-}
-exports.isFunction = isFunction;
-
-function isPrimitive(arg) {
-  return arg === null ||
-         typeof arg === 'boolean' ||
-         typeof arg === 'number' ||
-         typeof arg === 'string' ||
-         typeof arg === 'symbol' ||  // ES6 symbol
-         typeof arg === 'undefined';
-}
-exports.isPrimitive = isPrimitive;
-
-exports.isBuffer = require('buffer').Buffer.isBuffer;
-
-function objectToString(o) {
-  return Object.prototype.toString.call(o);
-}

+ 0 - 38
node_modules/core-util-is/package.json

@@ -1,38 +0,0 @@
-{
-  "name": "core-util-is",
-  "version": "1.0.3",
-  "description": "The `util.is*` functions introduced in Node v0.12.",
-  "main": "lib/util.js",
-  "files": [
-    "lib"
-  ],
-  "repository": {
-    "type": "git",
-    "url": "git://github.com/isaacs/core-util-is"
-  },
-  "keywords": [
-    "util",
-    "isBuffer",
-    "isArray",
-    "isNumber",
-    "isString",
-    "isRegExp",
-    "isThis",
-    "isThat",
-    "polyfill"
-  ],
-  "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
-  "license": "MIT",
-  "bugs": {
-    "url": "https://github.com/isaacs/core-util-is/issues"
-  },
-  "scripts": {
-    "test": "tap test.js",
-    "preversion": "npm test",
-    "postversion": "npm publish",
-    "prepublishOnly": "git push origin --follow-tags"
-  },
-  "devDependencies": {
-    "tap": "^15.0.9"
-  }
-}

+ 0 - 16
node_modules/inherits/LICENSE

@@ -1,16 +0,0 @@
-The ISC License
-
-Copyright (c) Isaac Z. Schlueter
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
-

+ 0 - 42
node_modules/inherits/README.md

@@ -1,42 +0,0 @@
-Browser-friendly inheritance fully compatible with standard node.js
-[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor).
-
-This package exports standard `inherits` from node.js `util` module in
-node environment, but also provides alternative browser-friendly
-implementation through [browser
-field](https://gist.github.com/shtylman/4339901). Alternative
-implementation is a literal copy of standard one located in standalone
-module to avoid requiring of `util`. It also has a shim for old
-browsers with no `Object.create` support.
-
-While keeping you sure you are using standard `inherits`
-implementation in node.js environment, it allows bundlers such as
-[browserify](https://github.com/substack/node-browserify) to not
-include full `util` package to your client code if all you need is
-just `inherits` function. It worth, because browser shim for `util`
-package is large and `inherits` is often the single function you need
-from it.
-
-It's recommended to use this package instead of
-`require('util').inherits` for any code that has chances to be used
-not only in node.js but in browser too.
-
-## usage
-
-```js
-var inherits = require('inherits');
-// then use exactly as the standard one
-```
-
-## note on version ~1.0
-
-Version ~1.0 had completely different motivation and is not compatible
-neither with 2.0 nor with standard node.js `inherits`.
-
-If you are using version ~1.0 and planning to switch to ~2.0, be
-careful:
-
-* new version uses `super_` instead of `super` for referencing
-  superclass
-* new version overwrites current prototype while old one preserves any
-  existing fields on it

+ 0 - 9
node_modules/inherits/inherits.js

@@ -1,9 +0,0 @@
-try {
-  var util = require('util');
-  /* istanbul ignore next */
-  if (typeof util.inherits !== 'function') throw '';
-  module.exports = util.inherits;
-} catch (e) {
-  /* istanbul ignore next */
-  module.exports = require('./inherits_browser.js');
-}

+ 0 - 27
node_modules/inherits/inherits_browser.js

@@ -1,27 +0,0 @@
-if (typeof Object.create === 'function') {
-  // implementation from standard node.js 'util' module
-  module.exports = function inherits(ctor, superCtor) {
-    if (superCtor) {
-      ctor.super_ = superCtor
-      ctor.prototype = Object.create(superCtor.prototype, {
-        constructor: {
-          value: ctor,
-          enumerable: false,
-          writable: true,
-          configurable: true
-        }
-      })
-    }
-  };
-} else {
-  // old school shim for old browsers
-  module.exports = function inherits(ctor, superCtor) {
-    if (superCtor) {
-      ctor.super_ = superCtor
-      var TempCtor = function () {}
-      TempCtor.prototype = superCtor.prototype
-      ctor.prototype = new TempCtor()
-      ctor.prototype.constructor = ctor
-    }
-  }
-}

+ 0 - 29
node_modules/inherits/package.json

@@ -1,29 +0,0 @@
-{
-  "name": "inherits",
-  "description": "Browser-friendly inheritance fully compatible with standard node.js inherits()",
-  "version": "2.0.4",
-  "keywords": [
-    "inheritance",
-    "class",
-    "klass",
-    "oop",
-    "object-oriented",
-    "inherits",
-    "browser",
-    "browserify"
-  ],
-  "main": "./inherits.js",
-  "browser": "./inherits_browser.js",
-  "repository": "git://github.com/isaacs/inherits",
-  "license": "ISC",
-  "scripts": {
-    "test": "tap"
-  },
-  "devDependencies": {
-    "tap": "^14.2.4"
-  },
-  "files": [
-    "inherits.js",
-    "inherits_browser.js"
-  ]
-}

+ 0 - 1
node_modules/isarray/.npmignore

@@ -1 +0,0 @@
-node_modules

+ 0 - 4
node_modules/isarray/.travis.yml

@@ -1,4 +0,0 @@
-language: node_js
-node_js:
-  - "0.8"
-  - "0.10"

+ 0 - 6
node_modules/isarray/Makefile

@@ -1,6 +0,0 @@
-
-test:
-	@node_modules/.bin/tape test.js
-
-.PHONY: test
-

+ 0 - 60
node_modules/isarray/README.md

@@ -1,60 +0,0 @@
-
-# isarray
-
-`Array#isArray` for older browsers.
-
-[![build status](https://secure.travis-ci.org/juliangruber/isarray.svg)](http://travis-ci.org/juliangruber/isarray)
-[![downloads](https://img.shields.io/npm/dm/isarray.svg)](https://www.npmjs.org/package/isarray)
-
-[![browser support](https://ci.testling.com/juliangruber/isarray.png)
-](https://ci.testling.com/juliangruber/isarray)
-
-## Usage
-
-```js
-var isArray = require('isarray');
-
-console.log(isArray([])); // => true
-console.log(isArray({})); // => false
-```
-
-## Installation
-
-With [npm](http://npmjs.org) do
-
-```bash
-$ npm install isarray
-```
-
-Then bundle for the browser with
-[browserify](https://github.com/substack/browserify).
-
-With [component](http://component.io) do
-
-```bash
-$ component install juliangruber/isarray
-```
-
-## License
-
-(MIT)
-
-Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
-
-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.

+ 0 - 19
node_modules/isarray/component.json

@@ -1,19 +0,0 @@
-{
-  "name" : "isarray",
-  "description" : "Array#isArray for older browsers",
-  "version" : "0.0.1",
-  "repository" : "juliangruber/isarray",
-  "homepage": "https://github.com/juliangruber/isarray",
-  "main" : "index.js",
-  "scripts" : [
-    "index.js"
-  ],
-  "dependencies" : {},
-  "keywords": ["browser","isarray","array"],
-  "author": {
-    "name": "Julian Gruber",
-    "email": "mail@juliangruber.com",
-    "url": "http://juliangruber.com"
-  },
-  "license": "MIT"
-}

+ 0 - 5
node_modules/isarray/index.js

@@ -1,5 +0,0 @@
-var toString = {}.toString;
-
-module.exports = Array.isArray || function (arr) {
-  return toString.call(arr) == '[object Array]';
-};

+ 0 - 45
node_modules/isarray/package.json

@@ -1,45 +0,0 @@
-{
-  "name": "isarray",
-  "description": "Array#isArray for older browsers",
-  "version": "1.0.0",
-  "repository": {
-    "type": "git",
-    "url": "git://github.com/juliangruber/isarray.git"
-  },
-  "homepage": "https://github.com/juliangruber/isarray",
-  "main": "index.js",
-  "dependencies": {},
-  "devDependencies": {
-    "tape": "~2.13.4"
-  },
-  "keywords": [
-    "browser",
-    "isarray",
-    "array"
-  ],
-  "author": {
-    "name": "Julian Gruber",
-    "email": "mail@juliangruber.com",
-    "url": "http://juliangruber.com"
-  },
-  "license": "MIT",
-  "testling": {
-    "files": "test.js",
-    "browsers": [
-      "ie/8..latest",
-      "firefox/17..latest",
-      "firefox/nightly",
-      "chrome/22..latest",
-      "chrome/canary",
-      "opera/12..latest",
-      "opera/next",
-      "safari/5.1..latest",
-      "ipad/6.0..latest",
-      "iphone/6.0..latest",
-      "android-browser/4.2..latest"
-    ]
-  },
-  "scripts": {
-    "test": "tape test.js"
-  }
-}

+ 0 - 20
node_modules/isarray/test.js

@@ -1,20 +0,0 @@
-var isArray = require('./');
-var test = require('tape');
-
-test('is array', function(t){
-  t.ok(isArray([]));
-  t.notOk(isArray({}));
-  t.notOk(isArray(null));
-  t.notOk(isArray(false));
-
-  var obj = {};
-  obj[0] = true;
-  t.notOk(isArray(obj));
-
-  var arr = [];
-  arr.foo = 'bar';
-  t.ok(isArray(arr));
-
-  t.end();
-});
-

+ 0 - 22
node_modules/media-typer/HISTORY.md

@@ -1,22 +0,0 @@
-0.3.0 / 2014-09-07
-==================
-
-  * Support Node.js 0.6
-  * Throw error when parameter format invalid on parse
-
-0.2.0 / 2014-06-18
-==================
-
-  * Add `typer.format()` to format media types
-
-0.1.0 / 2014-06-17
-==================
-
-  * Accept `req` as argument to `parse`
-  * Accept `res` as argument to `parse`
-  * Parse media type with extra LWS between type and first parameter
-
-0.0.0 / 2014-06-13
-==================
-
-  * Initial implementation

+ 0 - 22
node_modules/media-typer/LICENSE

@@ -1,22 +0,0 @@
-(The MIT License)
-
-Copyright (c) 2014 Douglas Christopher Wilson
-
-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.

+ 0 - 81
node_modules/media-typer/README.md

@@ -1,81 +0,0 @@
-# media-typer
-
-[![NPM Version][npm-image]][npm-url]
-[![NPM Downloads][downloads-image]][downloads-url]
-[![Node.js Version][node-version-image]][node-version-url]
-[![Build Status][travis-image]][travis-url]
-[![Test Coverage][coveralls-image]][coveralls-url]
-
-Simple RFC 6838 media type parser
-
-## Installation
-
-```sh
-$ npm install media-typer
-```
-
-## API
-
-```js
-var typer = require('media-typer')
-```
-
-### typer.parse(string)
-
-```js
-var obj = typer.parse('image/svg+xml; charset=utf-8')
-```
-
-Parse a media type string. This will return an object with the following
-properties (examples are shown for the string `'image/svg+xml; charset=utf-8'`):
-
- - `type`: The type of the media type (always lower case). Example: `'image'`
-
- - `subtype`: The subtype of the media type (always lower case). Example: `'svg'`
-
- - `suffix`: The suffix of the media type (always lower case). Example: `'xml'`
-
- - `parameters`: An object of the parameters in the media type (name of parameter always lower case). Example: `{charset: 'utf-8'}`
-
-### typer.parse(req)
-
-```js
-var obj = typer.parse(req)
-```
-
-Parse the `content-type` header from the given `req`. Short-cut for
-`typer.parse(req.headers['content-type'])`.
-
-### typer.parse(res)
-
-```js
-var obj = typer.parse(res)
-```
-
-Parse the `content-type` header set on the given `res`. Short-cut for
-`typer.parse(res.getHeader('content-type'))`.
-
-### typer.format(obj)
-
-```js
-var obj = typer.format({type: 'image', subtype: 'svg', suffix: 'xml'})
-```
-
-Format an object into a media type string. This will return a string of the
-mime type for the given object. For the properties of the object, see the
-documentation for `typer.parse(string)`.
-
-## License
-
-[MIT](LICENSE)
-
-[npm-image]: https://img.shields.io/npm/v/media-typer.svg?style=flat
-[npm-url]: https://npmjs.org/package/media-typer
-[node-version-image]: https://img.shields.io/badge/node.js-%3E%3D_0.6-brightgreen.svg?style=flat
-[node-version-url]: http://nodejs.org/download/
-[travis-image]: https://img.shields.io/travis/jshttp/media-typer.svg?style=flat
-[travis-url]: https://travis-ci.org/jshttp/media-typer
-[coveralls-image]: https://img.shields.io/coveralls/jshttp/media-typer.svg?style=flat
-[coveralls-url]: https://coveralls.io/r/jshttp/media-typer
-[downloads-image]: https://img.shields.io/npm/dm/media-typer.svg?style=flat
-[downloads-url]: https://npmjs.org/package/media-typer

+ 0 - 270
node_modules/media-typer/index.js

@@ -1,270 +0,0 @@
-/*!
- * media-typer
- * Copyright(c) 2014 Douglas Christopher Wilson
- * MIT Licensed
- */
-
-/**
- * RegExp to match *( ";" parameter ) in RFC 2616 sec 3.7
- *
- * parameter     = token "=" ( token | quoted-string )
- * token         = 1*<any CHAR except CTLs or separators>
- * separators    = "(" | ")" | "<" | ">" | "@"
- *               | "," | ";" | ":" | "\" | <">
- *               | "/" | "[" | "]" | "?" | "="
- *               | "{" | "}" | SP | HT
- * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
- * qdtext        = <any TEXT except <">>
- * quoted-pair   = "\" CHAR
- * CHAR          = <any US-ASCII character (octets 0 - 127)>
- * TEXT          = <any OCTET except CTLs, but including LWS>
- * LWS           = [CRLF] 1*( SP | HT )
- * CRLF          = CR LF
- * CR            = <US-ASCII CR, carriage return (13)>
- * LF            = <US-ASCII LF, linefeed (10)>
- * SP            = <US-ASCII SP, space (32)>
- * SHT           = <US-ASCII HT, horizontal-tab (9)>
- * CTL           = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
- * OCTET         = <any 8-bit sequence of data>
- */
-var paramRegExp = /; *([!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) *= *("(?:[ !\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u0020-\u007e])*"|[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) */g;
-var textRegExp = /^[\u0020-\u007e\u0080-\u00ff]+$/
-var tokenRegExp = /^[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+$/
-
-/**
- * RegExp to match quoted-pair in RFC 2616
- *
- * quoted-pair = "\" CHAR
- * CHAR        = <any US-ASCII character (octets 0 - 127)>
- */
-var qescRegExp = /\\([\u0000-\u007f])/g;
-
-/**
- * RegExp to match chars that must be quoted-pair in RFC 2616
- */
-var quoteRegExp = /([\\"])/g;
-
-/**
- * RegExp to match type in RFC 6838
- *
- * type-name = restricted-name
- * subtype-name = restricted-name
- * restricted-name = restricted-name-first *126restricted-name-chars
- * restricted-name-first  = ALPHA / DIGIT
- * restricted-name-chars  = ALPHA / DIGIT / "!" / "#" /
- *                          "$" / "&" / "-" / "^" / "_"
- * restricted-name-chars =/ "." ; Characters before first dot always
- *                              ; specify a facet name
- * restricted-name-chars =/ "+" ; Characters after last plus always
- *                              ; specify a structured syntax suffix
- * ALPHA =  %x41-5A / %x61-7A   ; A-Z / a-z
- * DIGIT =  %x30-39             ; 0-9
- */
-var subtypeNameRegExp = /^[A-Za-z0-9][A-Za-z0-9!#$&^_.-]{0,126}$/
-var typeNameRegExp = /^[A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126}$/
-var typeRegExp = /^ *([A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126})\/([A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}) *$/;
-
-/**
- * Module exports.
- */
-
-exports.format = format
-exports.parse = parse
-
-/**
- * Format object to media type.
- *
- * @param {object} obj
- * @return {string}
- * @api public
- */
-
-function format(obj) {
-  if (!obj || typeof obj !== 'object') {
-    throw new TypeError('argument obj is required')
-  }
-
-  var parameters = obj.parameters
-  var subtype = obj.subtype
-  var suffix = obj.suffix
-  var type = obj.type
-
-  if (!type || !typeNameRegExp.test(type)) {
-    throw new TypeError('invalid type')
-  }
-
-  if (!subtype || !subtypeNameRegExp.test(subtype)) {
-    throw new TypeError('invalid subtype')
-  }
-
-  // format as type/subtype
-  var string = type + '/' + subtype
-
-  // append +suffix
-  if (suffix) {
-    if (!typeNameRegExp.test(suffix)) {
-      throw new TypeError('invalid suffix')
-    }
-
-    string += '+' + suffix
-  }
-
-  // append parameters
-  if (parameters && typeof parameters === 'object') {
-    var param
-    var params = Object.keys(parameters).sort()
-
-    for (var i = 0; i < params.length; i++) {
-      param = params[i]
-
-      if (!tokenRegExp.test(param)) {
-        throw new TypeError('invalid parameter name')
-      }
-
-      string += '; ' + param + '=' + qstring(parameters[param])
-    }
-  }
-
-  return string
-}
-
-/**
- * Parse media type to object.
- *
- * @param {string|object} string
- * @return {Object}
- * @api public
- */
-
-function parse(string) {
-  if (!string) {
-    throw new TypeError('argument string is required')
-  }
-
-  // support req/res-like objects as argument
-  if (typeof string === 'object') {
-    string = getcontenttype(string)
-  }
-
-  if (typeof string !== 'string') {
-    throw new TypeError('argument string is required to be a string')
-  }
-
-  var index = string.indexOf(';')
-  var type = index !== -1
-    ? string.substr(0, index)
-    : string
-
-  var key
-  var match
-  var obj = splitType(type)
-  var params = {}
-  var value
-
-  paramRegExp.lastIndex = index
-
-  while (match = paramRegExp.exec(string)) {
-    if (match.index !== index) {
-      throw new TypeError('invalid parameter format')
-    }
-
-    index += match[0].length
-    key = match[1].toLowerCase()
-    value = match[2]
-
-    if (value[0] === '"') {
-      // remove quotes and escapes
-      value = value
-        .substr(1, value.length - 2)
-        .replace(qescRegExp, '$1')
-    }
-
-    params[key] = value
-  }
-
-  if (index !== -1 && index !== string.length) {
-    throw new TypeError('invalid parameter format')
-  }
-
-  obj.parameters = params
-
-  return obj
-}
-
-/**
- * Get content-type from req/res objects.
- *
- * @param {object}
- * @return {Object}
- * @api private
- */
-
-function getcontenttype(obj) {
-  if (typeof obj.getHeader === 'function') {
-    // res-like
-    return obj.getHeader('content-type')
-  }
-
-  if (typeof obj.headers === 'object') {
-    // req-like
-    return obj.headers && obj.headers['content-type']
-  }
-}
-
-/**
- * Quote a string if necessary.
- *
- * @param {string} val
- * @return {string}
- * @api private
- */
-
-function qstring(val) {
-  var str = String(val)
-
-  // no need to quote tokens
-  if (tokenRegExp.test(str)) {
-    return str
-  }
-
-  if (str.length > 0 && !textRegExp.test(str)) {
-    throw new TypeError('invalid parameter value')
-  }
-
-  return '"' + str.replace(quoteRegExp, '\\$1') + '"'
-}
-
-/**
- * Simply "type/subtype+siffx" into parts.
- *
- * @param {string} string
- * @return {Object}
- * @api private
- */
-
-function splitType(string) {
-  var match = typeRegExp.exec(string.toLowerCase())
-
-  if (!match) {
-    throw new TypeError('invalid media type')
-  }
-
-  var type = match[1]
-  var subtype = match[2]
-  var suffix
-
-  // suffix after last +
-  var index = subtype.lastIndexOf('+')
-  if (index !== -1) {
-    suffix = subtype.substr(index + 1)
-    subtype = subtype.substr(0, index)
-  }
-
-  var obj = {
-    type: type,
-    subtype: subtype,
-    suffix: suffix
-  }
-
-  return obj
-}

+ 0 - 26
node_modules/media-typer/package.json

@@ -1,26 +0,0 @@
-{
-  "name": "media-typer",
-  "description": "Simple RFC 6838 media type parser and formatter",
-  "version": "0.3.0",
-  "author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
-  "license": "MIT",
-  "repository": "jshttp/media-typer",
-  "devDependencies": {
-    "istanbul": "0.3.2",
-    "mocha": "~1.21.4",
-    "should": "~4.0.4"
-  },
-  "files": [
-    "LICENSE",
-    "HISTORY.md",
-    "index.js"
-  ],
-  "engines": {
-    "node": ">= 0.6"
-  },
-  "scripts": {
-    "test": "mocha --reporter spec --check-leaks --bail test/",
-    "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
-    "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
-  }
-}

+ 0 - 507
node_modules/mime-db/HISTORY.md

@@ -1,507 +0,0 @@
-1.52.0 / 2022-02-21
-===================
-
-  * Add extensions from IANA for more `image/*` types
-  * Add extension `.asc` to `application/pgp-keys`
-  * Add extensions to various XML types
-  * Add new upstream MIME types
-
-1.51.0 / 2021-11-08
-===================
-
-  * Add new upstream MIME types
-  * Mark `image/vnd.microsoft.icon` as compressible
-  * Mark `image/vnd.ms-dds` as compressible
-
-1.50.0 / 2021-09-15
-===================
-
-  * Add deprecated iWorks mime types and extensions
-  * Add new upstream MIME types
-
-1.49.0 / 2021-07-26
-===================
-
-  * Add extension `.trig` to `application/trig`
-  * Add new upstream MIME types
-
-1.48.0 / 2021-05-30
-===================
-
-  * Add extension `.mvt` to `application/vnd.mapbox-vector-tile`
-  * Add new upstream MIME types
-  * Mark `text/yaml` as compressible
-
-1.47.0 / 2021-04-01
-===================
-
-  * Add new upstream MIME types
-  * Remove ambigious extensions from IANA for `application/*+xml` types
-  * Update primary extension to `.es` for `application/ecmascript`
-
-1.46.0 / 2021-02-13
-===================
-
-  * Add extension `.amr` to `audio/amr`
-  * Add extension `.m4s` to `video/iso.segment`
-  * Add extension `.opus` to `audio/ogg`
-  * Add new upstream MIME types
-
-1.45.0 / 2020-09-22
-===================
-
-  * Add `application/ubjson` with extension `.ubj`
-  * Add `image/avif` with extension `.avif`
-  * Add `image/ktx2` with extension `.ktx2`
-  * Add extension `.dbf` to `application/vnd.dbf`
-  * Add extension `.rar` to `application/vnd.rar`
-  * Add extension `.td` to `application/urc-targetdesc+xml`
-  * Add new upstream MIME types
-  * Fix extension of `application/vnd.apple.keynote` to be `.key`
-
-1.44.0 / 2020-04-22
-===================
-
-  * Add charsets from IANA
-  * Add extension `.cjs` to `application/node`
-  * Add new upstream MIME types
-
-1.43.0 / 2020-01-05
-===================
-
-  * Add `application/x-keepass2` with extension `.kdbx`
-  * Add extension `.mxmf` to `audio/mobile-xmf`
-  * Add extensions from IANA for `application/*+xml` types
-  * Add new upstream MIME types
-
-1.42.0 / 2019-09-25
-===================
-
-  * Add `image/vnd.ms-dds` with extension `.dds`
-  * Add new upstream MIME types
-  * Remove compressible from `multipart/mixed`
-
-1.41.0 / 2019-08-30
-===================
-
-  * Add new upstream MIME types
-  * Add `application/toml` with extension `.toml`
-  * Mark `font/ttf` as compressible
-
-1.40.0 / 2019-04-20
-===================
-
-  * Add extensions from IANA for `model/*` types
-  * Add `text/mdx` with extension `.mdx`
-
-1.39.0 / 2019-04-04
-===================
-
-  * Add extensions `.siv` and `.sieve` to `application/sieve`
-  * Add new upstream MIME types
-
-1.38.0 / 2019-02-04
-===================
-
-  * Add extension `.nq` to `application/n-quads`
-  * Add extension `.nt` to `application/n-triples`
-  * Add new upstream MIME types
-  * Mark `text/less` as compressible
-
-1.37.0 / 2018-10-19
-===================
-
-  * Add extensions to HEIC image types
-  * Add new upstream MIME types
-
-1.36.0 / 2018-08-20
-===================
-
-  * Add Apple file extensions from IANA
-  * Add extensions from IANA for `image/*` types
-  * Add new upstream MIME types
-
-1.35.0 / 2018-07-15
-===================
-
-  * Add extension `.owl` to `application/rdf+xml`
-  * Add new upstream MIME types
-    - Removes extension `.woff` from `application/font-woff`
-
-1.34.0 / 2018-06-03
-===================
-
-  * Add extension `.csl` to `application/vnd.citationstyles.style+xml`
-  * Add extension `.es` to `application/ecmascript`
-  * Add new upstream MIME types
-  * Add `UTF-8` as default charset for `text/turtle`
-  * Mark all XML-derived types as compressible
-
-1.33.0 / 2018-02-15
-===================
-
-  * Add extensions from IANA for `message/*` types
-  * Add new upstream MIME types
-  * Fix some incorrect OOXML types
-  * Remove `application/font-woff2`
-
-1.32.0 / 2017-11-29
-===================
-
-  * Add new upstream MIME types
-  * Update `text/hjson` to registered `application/hjson`
-  * Add `text/shex` with extension `.shex`
-
-1.31.0 / 2017-10-25
-===================
-
-  * Add `application/raml+yaml` with extension `.raml`
-  * Add `application/wasm` with extension `.wasm`
-  * Add new `font` type from IANA
-  * Add new upstream font extensions
-  * Add new upstream MIME types
-  * Add extensions for JPEG-2000 images
-
-1.30.0 / 2017-08-27
-===================
-
-  * Add `application/vnd.ms-outlook`
-  * Add `application/x-arj`
-  * Add extension `.mjs` to `application/javascript`
-  * Add glTF types and extensions
-  * Add new upstream MIME types
-  * Add `text/x-org`
-  * Add VirtualBox MIME types
-  * Fix `source` records for `video/*` types that are IANA
-  * Update `font/opentype` to registered `font/otf`
-
-1.29.0 / 2017-07-10
-===================
-
-  * Add `application/fido.trusted-apps+json`
-  * Add extension `.wadl` to `application/vnd.sun.wadl+xml`
-  * Add new upstream MIME types
-  * Add `UTF-8` as default charset for `text/css`
-
-1.28.0 / 2017-05-14
-===================
-
-  * Add new upstream MIME types
-  * Add extension `.gz` to `application/gzip`
-  * Update extensions `.md` and `.markdown` to be `text/markdown`
-
-1.27.0 / 2017-03-16
-===================
-
-  * Add new upstream MIME types
-  * Add `image/apng` with extension `.apng`
-
-1.26.0 / 2017-01-14
-===================
-
-  * Add new upstream MIME types
-  * Add extension `.geojson` to `application/geo+json`
-
-1.25.0 / 2016-11-11
-===================
-
-  * Add new upstream MIME types
-
-1.24.0 / 2016-09-18
-===================
-
-  * Add `audio/mp3`
-  * Add new upstream MIME types
-
-1.23.0 / 2016-05-01
-===================
-
-  * Add new upstream MIME types
-  * Add extension `.3gpp` to `audio/3gpp`
-
-1.22.0 / 2016-02-15
-===================
-
-  * Add `text/slim`
-  * Add extension `.rng` to `application/xml`
-  * Add new upstream MIME types
-  * Fix extension of `application/dash+xml` to be `.mpd`
-  * Update primary extension to `.m4a` for `audio/mp4`
-
-1.21.0 / 2016-01-06
-===================
-
-  * Add Google document types
-  * Add new upstream MIME types
-
-1.20.0 / 2015-11-10
-===================
-
-  * Add `text/x-suse-ymp`
-  * Add new upstream MIME types
-
-1.19.0 / 2015-09-17
-===================
-
-  * Add `application/vnd.apple.pkpass`
-  * Add new upstream MIME types
-
-1.18.0 / 2015-09-03
-===================
-
-  * Add new upstream MIME types
-
-1.17.0 / 2015-08-13
-===================
-
-  * Add `application/x-msdos-program`
-  * Add `audio/g711-0`
-  * Add `image/vnd.mozilla.apng`
-  * Add extension `.exe` to `application/x-msdos-program`
-
-1.16.0 / 2015-07-29
-===================
-
-  * Add `application/vnd.uri-map`
-
-1.15.0 / 2015-07-13
-===================
-
-  * Add `application/x-httpd-php`
-
-1.14.0 / 2015-06-25
-===================
-
-  * Add `application/scim+json`
-  * Add `application/vnd.3gpp.ussd+xml`
-  * Add `application/vnd.biopax.rdf+xml`
-  * Add `text/x-processing`
-
-1.13.0 / 2015-06-07
-===================
-
-  * Add nginx as a source
-  * Add `application/x-cocoa`
-  * Add `application/x-java-archive-diff`
-  * Add `application/x-makeself`
-  * Add `application/x-perl`
-  * Add `application/x-pilot`
-  * Add `application/x-redhat-package-manager`
-  * Add `application/x-sea`
-  * Add `audio/x-m4a`
-  * Add `audio/x-realaudio`
-  * Add `image/x-jng`
-  * Add `text/mathml`
-
-1.12.0 / 2015-06-05
-===================
-
-  * Add `application/bdoc`
-  * Add `application/vnd.hyperdrive+json`
-  * Add `application/x-bdoc`
-  * Add extension `.rtf` to `text/rtf`
-
-1.11.0 / 2015-05-31
-===================
-
-  * Add `audio/wav`
-  * Add `audio/wave`
-  * Add extension `.litcoffee` to `text/coffeescript`
-  * Add extension `.sfd-hdstx` to `application/vnd.hydrostatix.sof-data`
-  * Add extension `.n-gage` to `application/vnd.nokia.n-gage.symbian.install`
-
-1.10.0 / 2015-05-19
-===================
-
-  * Add `application/vnd.balsamiq.bmpr`
-  * Add `application/vnd.microsoft.portable-executable`
-  * Add `application/x-ns-proxy-autoconfig`
-
-1.9.1 / 2015-04-19
-==================
-
-  * Remove `.json` extension from `application/manifest+json`
-    - This is causing bugs downstream
-
-1.9.0 / 2015-04-19
-==================
-
-  * Add `application/manifest+json`
-  * Add `application/vnd.micro+json`
-  * Add `image/vnd.zbrush.pcx`
-  * Add `image/x-ms-bmp`
-
-1.8.0 / 2015-03-13
-==================
-
-  * Add `application/vnd.citationstyles.style+xml`
-  * Add `application/vnd.fastcopy-disk-image`
-  * Add `application/vnd.gov.sk.xmldatacontainer+xml`
-  * Add extension `.jsonld` to `application/ld+json`
-
-1.7.0 / 2015-02-08
-==================
-
-  * Add `application/vnd.gerber`
-  * Add `application/vnd.msa-disk-image`
-
-1.6.1 / 2015-02-05
-==================
-
-  * Community extensions ownership transferred from `node-mime`
-
-1.6.0 / 2015-01-29
-==================
-
-  * Add `application/jose`
-  * Add `application/jose+json`
-  * Add `application/json-seq`
-  * Add `application/jwk+json`
-  * Add `application/jwk-set+json`
-  * Add `application/jwt`
-  * Add `application/rdap+json`
-  * Add `application/vnd.gov.sk.e-form+xml`
-  * Add `application/vnd.ims.imsccv1p3`
-
-1.5.0 / 2014-12-30
-==================
-
-  * Add `application/vnd.oracle.resource+json`
-  * Fix various invalid MIME type entries
-    - `application/mbox+xml`
-    - `application/oscp-response`
-    - `application/vwg-multiplexed`
-    - `audio/g721`
-
-1.4.0 / 2014-12-21
-==================
-
-  * Add `application/vnd.ims.imsccv1p2`
-  * Fix various invalid MIME type entries
-    - `application/vnd-acucobol`
-    - `application/vnd-curl`
-    - `application/vnd-dart`
-    - `application/vnd-dxr`
-    - `application/vnd-fdf`
-    - `application/vnd-mif`
-    - `application/vnd-sema`
-    - `application/vnd-wap-wmlc`
-    - `application/vnd.adobe.flash-movie`
-    - `application/vnd.dece-zip`
-    - `application/vnd.dvb_service`
-    - `application/vnd.micrografx-igx`
-    - `application/vnd.sealed-doc`
-    - `application/vnd.sealed-eml`
-    - `application/vnd.sealed-mht`
-    - `application/vnd.sealed-ppt`
-    - `application/vnd.sealed-tiff`
-    - `application/vnd.sealed-xls`
-    - `application/vnd.sealedmedia.softseal-html`
-    - `application/vnd.sealedmedia.softseal-pdf`
-    - `application/vnd.wap-slc`
-    - `application/vnd.wap-wbxml`
-    - `audio/vnd.sealedmedia.softseal-mpeg`
-    - `image/vnd-djvu`
-    - `image/vnd-svf`
-    - `image/vnd-wap-wbmp`
-    - `image/vnd.sealed-png`
-    - `image/vnd.sealedmedia.softseal-gif`
-    - `image/vnd.sealedmedia.softseal-jpg`
-    - `model/vnd-dwf`
-    - `model/vnd.parasolid.transmit-binary`
-    - `model/vnd.parasolid.transmit-text`
-    - `text/vnd-a`
-    - `text/vnd-curl`
-    - `text/vnd.wap-wml`
-  * Remove example template MIME types
-    - `application/example`
-    - `audio/example`
-    - `image/example`
-    - `message/example`
-    - `model/example`
-    - `multipart/example`
-    - `text/example`
-    - `video/example`
-
-1.3.1 / 2014-12-16
-==================
-
-  * Fix missing extensions
-    - `application/json5`
-    - `text/hjson`
-
-1.3.0 / 2014-12-07
-==================
-
-  * Add `application/a2l`
-  * Add `application/aml`
-  * Add `application/atfx`
-  * Add `application/atxml`
-  * Add `application/cdfx+xml`
-  * Add `application/dii`
-  * Add `application/json5`
-  * Add `application/lxf`
-  * Add `application/mf4`
-  * Add `application/vnd.apache.thrift.compact`
-  * Add `application/vnd.apache.thrift.json`
-  * Add `application/vnd.coffeescript`
-  * Add `application/vnd.enphase.envoy`
-  * Add `application/vnd.ims.imsccv1p1`
-  * Add `text/csv-schema`
-  * Add `text/hjson`
-  * Add `text/markdown`
-  * Add `text/yaml`
-
-1.2.0 / 2014-11-09
-==================
-
-  * Add `application/cea`
-  * Add `application/dit`
-  * Add `application/vnd.gov.sk.e-form+zip`
-  * Add `application/vnd.tmd.mediaflex.api+xml`
-  * Type `application/epub+zip` is now IANA-registered
-
-1.1.2 / 2014-10-23
-==================
-
-  * Rebuild database for `application/x-www-form-urlencoded` change
-
-1.1.1 / 2014-10-20
-==================
-
-  * Mark `application/x-www-form-urlencoded` as compressible.
-
-1.1.0 / 2014-09-28
-==================
-
-  * Add `application/font-woff2`
-
-1.0.3 / 2014-09-25
-==================
-
-  * Fix engine requirement in package
-
-1.0.2 / 2014-09-25
-==================
-
-  * Add `application/coap-group+json`
-  * Add `application/dcd`
-  * Add `application/vnd.apache.thrift.binary`
-  * Add `image/vnd.tencent.tap`
-  * Mark all JSON-derived types as compressible
-  * Update `text/vtt` data
-
-1.0.1 / 2014-08-30
-==================
-
-  * Fix extension ordering
-
-1.0.0 / 2014-08-30
-==================
-
-  * Add `application/atf`
-  * Add `application/merge-patch+json`
-  * Add `multipart/x-mixed-replace`
-  * Add `source: 'apache'` metadata
-  * Add `source: 'iana'` metadata
-  * Remove badly-assumed charset data

+ 0 - 23
node_modules/mime-db/LICENSE

@@ -1,23 +0,0 @@
-(The MIT License)
-
-Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
-Copyright (c) 2015-2022 Douglas Christopher Wilson <doug@somethingdoug.com>
-
-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.

+ 0 - 100
node_modules/mime-db/README.md

@@ -1,100 +0,0 @@
-# mime-db
-
-[![NPM Version][npm-version-image]][npm-url]
-[![NPM Downloads][npm-downloads-image]][npm-url]
-[![Node.js Version][node-image]][node-url]
-[![Build Status][ci-image]][ci-url]
-[![Coverage Status][coveralls-image]][coveralls-url]
-
-This is a large database of mime types and information about them.
-It consists of a single, public JSON file and does not include any logic,
-allowing it to remain as un-opinionated as possible with an API.
-It aggregates data from the following sources:
-
-- http://www.iana.org/assignments/media-types/media-types.xhtml
-- http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
-- http://hg.nginx.org/nginx/raw-file/default/conf/mime.types
-
-## Installation
-
-```bash
-npm install mime-db
-```
-
-### Database Download
-
-If you're crazy enough to use this in the browser, you can just grab the
-JSON file using [jsDelivr](https://www.jsdelivr.com/). It is recommended to
-replace `master` with [a release tag](https://github.com/jshttp/mime-db/tags)
-as the JSON format may change in the future.
-
-```
-https://cdn.jsdelivr.net/gh/jshttp/mime-db@master/db.json
-```
-
-## Usage
-
-```js
-var db = require('mime-db')
-
-// grab data on .js files
-var data = db['application/javascript']
-```
-
-## Data Structure
-
-The JSON file is a map lookup for lowercased mime types.
-Each mime type has the following properties:
-
-- `.source` - where the mime type is defined.
-    If not set, it's probably a custom media type.
-    - `apache` - [Apache common media types](http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types)
-    - `iana` - [IANA-defined media types](http://www.iana.org/assignments/media-types/media-types.xhtml)
-    - `nginx` - [nginx media types](http://hg.nginx.org/nginx/raw-file/default/conf/mime.types)
-- `.extensions[]` - known extensions associated with this mime type.
-- `.compressible` - whether a file of this type can be gzipped.
-- `.charset` - the default charset associated with this type, if any.
-
-If unknown, every property could be `undefined`.
-
-## Contributing
-
-To edit the database, only make PRs against `src/custom-types.json` or
-`src/custom-suffix.json`.
-
-The `src/custom-types.json` file is a JSON object with the MIME type as the
-keys and the values being an object with the following keys:
-
-- `compressible` - leave out if you don't know, otherwise `true`/`false` to
-  indicate whether the data represented by the type is typically compressible.
-- `extensions` - include an array of file extensions that are associated with
-  the type.
-- `notes` - human-readable notes about the type, typically what the type is.
-- `sources` - include an array of URLs of where the MIME type and the associated
-  extensions are sourced from. This needs to be a [primary source](https://en.wikipedia.org/wiki/Primary_source);
-  links to type aggregating sites and Wikipedia are _not acceptable_.
-
-To update the build, run `npm run build`.
-
-### Adding Custom Media Types
-
-The best way to get new media types included in this library is to register
-them with the IANA. The community registration procedure is outlined in
-[RFC 6838 section 5](http://tools.ietf.org/html/rfc6838#section-5). Types
-registered with the IANA are automatically pulled into this library.
-
-If that is not possible / feasible, they can be added directly here as a
-"custom" type. To do this, it is required to have a primary source that
-definitively lists the media type. If an extension is going to be listed as
-associateed with this media type, the source must definitively link the
-media type and extension as well.
-
-[ci-image]: https://badgen.net/github/checks/jshttp/mime-db/master?label=ci
-[ci-url]: https://github.com/jshttp/mime-db/actions?query=workflow%3Aci
-[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/mime-db/master
-[coveralls-url]: https://coveralls.io/r/jshttp/mime-db?branch=master
-[node-image]: https://badgen.net/npm/node/mime-db
-[node-url]: https://nodejs.org/en/download
-[npm-downloads-image]: https://badgen.net/npm/dm/mime-db
-[npm-url]: https://npmjs.org/package/mime-db
-[npm-version-image]: https://badgen.net/npm/v/mime-db

Неке датотеке нису приказане због велике количине промена