├── recording
├── .gitignore
├── package.json
├── run.sh
├── record.js
├── yarn.lock
└── package-lock.json
├── demo.mp4
├── .DS_Store
├── video.cn.png
├── video.us.png
├── resource
├── .DS_Store
└── h264
│ ├── libgmpopenh264.so
│ └── gmpopenh264.info
├── demo
├── public
│ ├── favicon.ico
│ ├── logo192.png
│ ├── logo512.png
│ ├── robots.txt
│ ├── manifest.json
│ └── index.html
├── src
│ ├── setupTests.js
│ ├── App.test.js
│ ├── index.css
│ ├── reportWebVitals.js
│ ├── index.js
│ ├── App.css
│ ├── App.js
│ └── logo.svg
├── .gitignore
├── package.json
└── README.md
├── demo.sh
├── Dockerfile
├── logo.svg
├── README.cn.md
├── README.md
├── pic1.svg
└── LICENSE
/recording/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/demo.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easychen/windrecorder/HEAD/demo.mp4
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easychen/windrecorder/HEAD/.DS_Store
--------------------------------------------------------------------------------
/video.cn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easychen/windrecorder/HEAD/video.cn.png
--------------------------------------------------------------------------------
/video.us.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easychen/windrecorder/HEAD/video.us.png
--------------------------------------------------------------------------------
/resource/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easychen/windrecorder/HEAD/resource/.DS_Store
--------------------------------------------------------------------------------
/demo/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easychen/windrecorder/HEAD/demo/public/favicon.ico
--------------------------------------------------------------------------------
/demo/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easychen/windrecorder/HEAD/demo/public/logo192.png
--------------------------------------------------------------------------------
/demo/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easychen/windrecorder/HEAD/demo/public/logo512.png
--------------------------------------------------------------------------------
/demo/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/resource/h264/libgmpopenh264.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easychen/windrecorder/HEAD/resource/h264/libgmpopenh264.so
--------------------------------------------------------------------------------
/resource/h264/gmpopenh264.info:
--------------------------------------------------------------------------------
1 | Name: gmpopenh264
2 | Description: GMP Plugin for OpenH264.
3 | Version: 1.8.1
4 | APIs: encode-video[h264], decode-video[h264]
5 |
--------------------------------------------------------------------------------
/demo.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | # change dd.ftqq.com to internal IP
4 |
5 | docker run --rm -p 80:80 -p 5900:5900 -v "$(pwd):/data" easychen/windrec:latest 'http://dd.ftqq.com:3000/'
--------------------------------------------------------------------------------
/recording/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "recording",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "dependencies": {
7 | "cors": "^2.8.5",
8 | "express": "^4.17.1"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/demo/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/demo/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render();
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/demo/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/demo/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/demo/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | ReactDOM.render(
8 |
9 |
10 | ,
11 | document.getElementById('root')
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/demo/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/demo/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-spin infinite 20s linear;
13 | }
14 | }
15 |
16 | .App-header {
17 | background-color: #282c34;
18 | min-height: 100vh;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 | justify-content: center;
23 | font-size: calc(10px + 2vmin);
24 | color: white;
25 | }
26 |
27 | .App-link {
28 | color: #61dafb;
29 | }
30 |
31 | @keyframes App-logo-spin {
32 | from {
33 | transform: rotate(0deg);
34 | }
35 | to {
36 | transform: rotate(360deg);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.11.4",
7 | "@testing-library/react": "^11.1.0",
8 | "@testing-library/user-event": "^12.1.10",
9 | "animejs": "^3.2.1",
10 | "axios": "^0.21.1",
11 | "react": "^17.0.2",
12 | "react-dom": "^17.0.2",
13 | "react-scripts": "4.0.3",
14 | "web-vitals": "^1.0.1"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test",
20 | "eject": "react-scripts eject"
21 | },
22 | "eslintConfig": {
23 | "extends": [
24 | "react-app",
25 | "react-app/jest"
26 | ]
27 | },
28 | "browserslist": {
29 | "production": [
30 | ">0.2%",
31 | "not dead",
32 | "not op_mini all"
33 | ],
34 | "development": [
35 | "last 1 chrome version",
36 | "last 1 firefox version",
37 | "last 1 safari version"
38 | ]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:20.04
2 |
3 | ENV DEBIAN_FRONTEND noninteractive
4 |
5 | # 安装用到的软件
6 | RUN /usr/bin/apt-get update && \
7 | /usr/bin/apt-get install -y curl && \
8 | curl -sL https://deb.nodesource.com/setup_14.x | bash - && \
9 | /usr/bin/apt-get update && \
10 | /usr/bin/apt-get upgrade -y && \
11 | /usr/bin/apt-get install -y nodejs pulseaudio xvfb firefox ffmpeg xdotool unzip x11vnc
12 |
13 | # 安装中文字体
14 | RUN set -eux && \
15 | apt-get update && \
16 | apt-get install -y locales tzdata xfonts-wqy ttf-wqy-microhei ttf-wqy-zenhei && \
17 | locale-gen zh_CN.UTF-8 && \
18 | update-locale LANG=zh_CN.UTF-8 LANGUAGE=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 && \
19 | ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
20 | dpkg-reconfigure --frontend noninteractive tzdata && \
21 | find /var/lib/apt/lists -type f -delete && \
22 | find /var/cache -type f -delete
23 |
24 | # 配置中文
25 | ENV LANG=zh_CN.UTF-8 LANGUAGE=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8
26 |
27 | # 配置firefox
28 |
29 | COPY resource/h264 /tmp/h264
30 |
31 | COPY /recording /recording
32 | WORKDIR /recording
33 | RUN chmod +x /recording/*.sh
34 | # RUN /usr/bin/npm install
35 |
36 | EXPOSE 80 5900
37 |
38 | ENTRYPOINT ["/recording/run.sh"]
--------------------------------------------------------------------------------
/logo.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/demo/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import logo from './logo.svg';
3 | import './App.css';
4 | import axios from 'axios';
5 | import anime from 'animejs/lib/anime.es.js';
6 |
7 | class App extends Component {
8 |
9 | state = {"text":"Loading"};
10 |
11 | async componentDidMount()
12 | {
13 | this.axios = axios.create();
14 | this.axios.defaults.timeout = 500;
15 | window.setTimeout( ()=>this.start(), 1000 );
16 | window.setTimeout( ()=>this.stop(), 9000 );
17 | anime({
18 | targets:'.App-link',
19 | // translateX: 270,
20 | translateY: 100,
21 | loop: true,
22 | // easing: 'easeInOutSine',
23 | autoplay: true,
24 | });
25 |
26 | }
27 |
28 | async start()
29 | {
30 | this.setState({"text":"Recording..."});
31 | await this.axios.get( "http://localhost/start" );
32 |
33 | }
34 |
35 | async stop()
36 | {
37 | this.setState({"text":"Stopped"});
38 | await this.axios.get( "http://localhost/stop" );
39 | }
40 |
41 | render()
42 | {
43 | return (
44 |
60 | );
61 | }
62 |
63 | }
64 |
65 | export default App;
66 |
--------------------------------------------------------------------------------
/demo/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/README.cn.md:
--------------------------------------------------------------------------------
1 | # Wind Recorder
2 |
3 | ## Wind Recorder 短版介绍
4 |
5 | Wind Recorder 是一个用来录制「[自播放网页](https://github.com/easychen/autoplay-web-specification)」的 docker 镜像。你可以通过快速测试先体验一下。
6 |
7 | 首先搭建一个「自播放网页」:
8 |
9 | 1. cd demo && yarn install && yarn start
10 |
11 | 运行 docker 命令:
12 |
13 | 1. 打开 demo.sh
14 | 2. 修改其中的 `dd.ftqq.com` 为电脑的局域网IP
15 | 3. 运行命令 bash demo.sh
16 |
17 | 运行完成后就可以在根目录下查看录制好的视频了。点这里可以直接查看[录制好的视频](demo.mp4)。
18 |
19 |
20 |
21 | ## 什么是 Wind Recorder
22 |
23 | 
24 |
25 |
26 | [WindMark.pro] 是一个用 [Tailwind CSS](https://tailwindcss.com/) 框架和 [Markdown](https://en.wikipedia.org/wiki/Markdown) 进行视频制作的免费在线工具。
27 |
28 | 其原理是用 Web 技术制作自动播放的网页,在通过浏览器进行访问时,将其录制为视频。
29 |
30 | 而 [Wind Recorder] 正是 [WindMark.pro] 用于录制的开源项目,它不但可以用来录制 [WindMark.pro] 生成的网页,也可以录制任何可以在浏览器中正常播放的网页。
31 |
32 | 通过 [Wind Recorder] 只需要运行一行 Docker 命令即可完成视频录制。
33 |
34 | ```docker
35 | docker run --rm -p 5900:5900 -p 80:80 -v "$(pwd):/data" easychen/windrec:latest https://video.windmark.pro
36 | ```
37 |
38 | 将以上命令中的 `https://video.windmark.pro` 替换为要录制的自动播放网页URL即可。
39 |
40 | 录制效果可以查看这个视频 → [WindMark.pro使用教学](https://www.bilibili.com/video/BV1sb4y167Mh/)
41 |
42 | 
43 |
44 |
45 | ## Wind Recorder 的工作原理
46 |
47 | 
48 |
49 | [Wind Recorder] 在容器中安装了浏览器,并启动了一个 Web 服务。当访问 `/start` 时,开始通过 ffmpeg 进行录制;当访问 `/stop` 时,停止录制。
50 |
51 | 除了在容器外通过 `http` 主动访问容器的 `/start` 和 `/stop`进行控制, 在容器内被录制的网页也可以通过 `JavaScript` 调用 `http://localhost/start` 和 `http://localhost/stop` 对录制进行控制。
52 |
53 | ## VNC
54 |
55 | 虽然有了简单的控制接口,但在录制时,容器对我们依然是黑箱。因此 [Wind Recorder] 内置了 VNC 服务。当容器启动后,可以通过 VNC Viewer 等工具连接 5900 端口查看内部浏览器的画面,这在进行兼容性调试时非常有用。
56 |
57 | ## 中文支持
58 |
59 | [Wind Recorder] 在容器环境中安装了中文字体,可以在要录制的网页中使用。
60 |
61 |
62 | 字体中文名 | 字体英文名 | Ubuntu 包名
63 | | --- | --- |--- |
64 | 文泉驿微米黑 | WenQuanYi Micro Hei | ttf-wqy-microhei
65 | 文泉驿正黑 | WenQuanYi Zen Hei | ttf-wqy-zenhei
66 | 文泉驿点阵宋体 | WenQuanYi Bitmap Song | xfonts-wqy
67 |
68 | ## FAQ
69 |
70 | ### 为什么录制的视频会卡顿?
71 |
72 | 请保持运行 docker 命令的机器网络良好,容器拥有至少 4G 的内存,页面越复杂,所需内存越多。
73 |
74 | ### 为什么音频视频不同步?
75 |
76 | 当内存不够时会出现这类问题,如果遇到请调大容器的内存。
77 |
78 | 另外因为录制时以追加方式写入mp4,如果遇到轻微的不同步,可以通过 [HandBrake](https://handbrake.fr/) 等工具对视频再次进行压缩和优化校正。
79 |
80 | ## Thanks
81 |
82 | 本项目录制部分的代码大量参考了[highattendance-aws-meeting-recording](https://github.com/banzai-io/highattendance-aws-meeting-recording),并采用 Apache2.0 协议发布。
83 |
84 | [WindMark.pro]: https://windmark.pro
85 | [Wind Recorder]: https://github.com/easychen/windrecorder
86 |
--------------------------------------------------------------------------------
/demo/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/recording/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -xeo pipefail
4 |
5 | BROWSER_URL="$1"
6 | SCREEN_WIDTH=${RECORDING_SCREEN_WIDTH:-'1920'}
7 | SCREEN_HEIGHT=${RECORDING_SCREEN_HEIGHT:-'1080'}
8 | SCREEN_RESOLUTION=${SCREEN_WIDTH}x${SCREEN_HEIGHT}
9 | COLOR_DEPTH=24
10 | X_SERVER_NUM=1
11 |
12 | # Start PulseAudio server so Firefox will have somewhere to which to send audio
13 | pulseaudio -D --exit-idle-time=-1
14 | pacmd load-module module-virtual-sink sink_name=v1 # Load a virtual sink as `v1`
15 | pacmd set-default-sink v1 # Set the `v1` as the default sink device
16 | pacmd set-default-source v1.monitor # Set the monitor of the v1 sink to be the default source
17 |
18 | # Start X11 virtual framebuffer so Firefox will have somewhere to draw
19 | Xvfb :${X_SERVER_NUM} -ac -screen 0 ${SCREEN_RESOLUTION}x${COLOR_DEPTH} > /dev/null 2>&1 &
20 | export DISPLAY=:${X_SERVER_NUM}.0
21 | sleep 0.5 # Ensure this has started before moving on
22 |
23 | # Create a new Firefox profile for capturing preferences for this
24 | firefox --no-remote --new-instance --createprofile "foo4 /tmp/foo4"
25 |
26 | # Install the OpenH264 plugin for Firefox
27 | mkdir -p /tmp/foo4/gmp-gmpopenh264/1.8.1.1/
28 |
29 | cp -rf /tmp/h264/* /tmp/foo4/gmp-gmpopenh264/1.8.1.1/
30 |
31 | # pushd /tmp/foo4/gmp-gmpopenh264/1.8.1.1 >& /dev/null
32 | # curl -s -O http://ciscobinary.openh264.org/openh264-linux64-2e1774ab6dc6c43debb0b5b628bdf122a391d521.zip
33 | # unzip openh264-linux64-2e1774ab6dc6c43debb0b5b628bdf122a391d521.zip
34 | # rm -f openh264-linux64-2e1774ab6dc6c43debb0b5b628bdf122a391d521.zip
35 | # popd >& /dev/null
36 |
37 | # Set the Firefox preferences to enable automatic media playing with no user
38 | # interaction and the use of the OpenH264 plugin.
39 | # media.setsinkid.enabled is recommended for firefox: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId
40 | cat <> /tmp/foo4/prefs.js
41 | user_pref("media.autoplay.default", 0);
42 | user_pref("media.autoplay.enabled.user-gestures-needed", false);
43 | user_pref("media.navigator.permission.disabled", true);
44 | user_pref("media.gmp-gmpopenh264.abi", "x86_64-gcc3");
45 | user_pref("media.gmp-gmpopenh264.lastUpdate", 1571534329);
46 | user_pref("media.gmp-gmpopenh264.version", "1.8.1.1");
47 | user_pref("doh-rollout.doorhanger-shown", true);
48 | user_pref("media.setsinkid.enabled", true);
49 | EOF
50 |
51 | # Start Firefox browser and point it at the URL we want to capture
52 | #
53 | # NB: The `--width` and `--height` arguments have to be very early in the
54 | # argument list or else only a white screen will result in the capture for some
55 | # reason.
56 |
57 | firefox \
58 | -P foo4 \
59 | --width ${SCREEN_WIDTH} \
60 | --height ${SCREEN_HEIGHT} \
61 | --new-instance \
62 | --first-startup \
63 | --foreground \
64 | --kiosk \
65 | --ssb ${BROWSER_URL} \
66 | &
67 | sleep 1 # Ensure this has started before moving on
68 | xdotool mousemove 1 1 click 1 # Move mouse out of the way so it doesn't trigger the "pause" overlay on the video tile
69 |
70 | x11vnc -display :1 &
71 |
72 | exec node /recording/record.js ${BROWSER_URL} ${SCREEN_WIDTH} ${SCREEN_HEIGHT}
73 |
74 | # tail -f /data/demo.txt
75 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WindRecorder
2 |
3 | [中文说明](README.cn.md)
4 |
5 | ## TLDR
6 |
7 | Wind Recorder is a docker image for recording "self-playing web pages". You can try it out with a quick test.
8 |
9 | First build a "self-playing web page":
10 |
11 | 1. cd demo && yarn install && yarn start
12 |
13 | Run the docker command:
14 |
15 | 1. open demo.sh
16 | 2. change `dd.ftqq.com` to be the LAN IP
17 | 3. Run the command bash demo.sh
18 |
19 | After running, you can view the recorded video in the root directory.Click here to view [recorded video](demo.mp4) directly.
20 |
21 | ## What is Wind Recorder
22 |
23 | 
24 |
25 |
26 | [WindMark.pro] is a free online tool for video production using the [Tailwind CSS](https://tailwindcss.com/) framework and [Markdown](https://en.wikipedia.org/wiki/Markdown).
27 |
28 | The principle is to create autoplay web pages using web technology and record them as videos when accessed through a browser.
29 |
30 | Wind Recorder] is the open source project used by [WindMark.pro] to record not only the web pages generated by [WindMark.pro], but also any web pages that can be rendered normally in a browser.
31 |
32 | With [Wind Recorder] you only need to run one line of Docker command to complete the video recording.
33 |
34 | ```docker
35 | docker run --rm -p 5900:5900 -p 80:80 -v "$(pwd):/data" easychen/windrec:latest https://video.windmark.pro
36 | ```
37 |
38 | Just replace `https://video.windmark.pro` in the above command with the URL of the autoplay page you want to record.
39 |
40 | The recording result can be seen in this video → [How to use WindMark.pro ](https://youtu.be/BpJ5O4dILUg)
41 |
42 | 
43 |
44 |
45 | ## How Wind Recorder works
46 |
47 | 
48 |
49 | The [Wind Recorder] installs a browser in the container and starts a web service. When `/start` is accessed, recording via ffmpeg starts; when `/stop` is accessed, recording stops.
50 |
51 | In addition to the `/start` and `/stop` control from outside the container via `http` active access to the container, the recorded web pages inside the container can also be controlled by `http://localhost/start` and `http://localhost/stop` calls via `JavaScript`.
52 |
53 | ## VNC
54 |
55 | Despite the simple control interface, the container remains a black box for us when it comes to recording. Therefore [Wind Recorder] has a built-in VNC service. When the container is started, you can connect to port 5900 to see the internal browser screen via tools like VNC Viewer, which is very useful when doing compatibility debugging.
56 |
57 | ## FAQ
58 |
59 | ### Why does the recorded video lag?
60 |
61 | Please keep the network of the machine running docker commands good and the container has at least 4G memory, the more complex the page, the more memory is needed.
62 |
63 | ### Why does the audio and video not sync?
64 |
65 | This kind of problem occurs when there is not enough memory, if you encounter it, please increase the memory of the container.
66 |
67 | Also, since the recording is written to mp4 as an append, if you encounter slight out of sync, you can use tools like [HandBrake](https://handbrake.fr/) to compress and optimize the video again to correct it.
68 |
69 | ## Thanks
70 |
71 | The code for the recording part of this project is heavily referenced from [highattendance-aws-meeting-recording](https://github.com/banzai-io/highattendance-aws-meeting-recording) and is distributed using the Apache2.0 protocol.
72 |
73 | [WindMark.pro]: https://windmark.pro
74 | [Wind Recorder]: https://github.com/easychen/windrecorder
75 |
--------------------------------------------------------------------------------
/demo/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React App
2 |
3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `yarn start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
13 |
14 | The page will reload if you make edits.\
15 | You will also see any lint errors in the console.
16 |
17 | ### `yarn test`
18 |
19 | Launches the test runner in the interactive watch mode.\
20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21 |
22 | ### `yarn build`
23 |
24 | Builds the app for production to the `build` folder.\
25 | It correctly bundles React in production mode and optimizes the build for the best performance.
26 |
27 | The build is minified and the filenames include the hashes.\
28 | Your app is ready to be deployed!
29 |
30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31 |
32 | ### `yarn eject`
33 |
34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
35 |
36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37 |
38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
39 |
40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
41 |
42 | ## Learn More
43 |
44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45 |
46 | To learn React, check out the [React documentation](https://reactjs.org/).
47 |
48 | ### Code Splitting
49 |
50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
51 |
52 | ### Analyzing the Bundle Size
53 |
54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
55 |
56 | ### Making a Progressive Web App
57 |
58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
59 |
60 | ### Advanced Configuration
61 |
62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
63 |
64 | ### Deployment
65 |
66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
67 |
68 | ### `yarn build` fails to minify
69 |
70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
71 |
--------------------------------------------------------------------------------
/pic1.svg:
--------------------------------------------------------------------------------
1 |
42 |
--------------------------------------------------------------------------------
/recording/record.js:
--------------------------------------------------------------------------------
1 | const { spawn } = require('child_process');
2 |
3 | const args = process.argv.slice(2);
4 | const REC_URL = args[0];
5 | console.log(`[recording process] REC_URL: ${REC_URL}`);
6 | const BROWSER_SCREEN_WIDTH = args[1];
7 | const BROWSER_SCREEN_HEIGHT = args[2];
8 | console.log(`[recording process] BROWSER_SCREEN_WIDTH: ${BROWSER_SCREEN_WIDTH}, BROWSER_SCREEN_HEIGHT: ${BROWSER_SCREEN_HEIGHT}`);
9 |
10 | const VIDEO_BITRATE = 3000;
11 | const VIDEO_FRAMERATE = 30;
12 | const VIDEO_GOP = VIDEO_FRAMERATE * 2;
13 | const AUDIO_BITRATE = '160k';
14 | const AUDIO_SAMPLERATE = 44100;
15 | const AUDIO_CHANNELS = 2
16 | const DISPLAY = process.env.DISPLAY;
17 |
18 | const timestamp = new Date();
19 | const fileTimestamp = timestamp.toISOString().substring(0,19);
20 | const year = timestamp.getFullYear();
21 | const month = timestamp.getMonth() + 1;
22 | const day = timestamp.getDate();
23 | const hour = timestamp.getUTCHours();
24 | const fileName = `${year}-${month}-${day}-${hour}-${fileTimestamp}.mp4`;
25 |
26 |
27 | // const vncOutput = spawn('ffmpeg',['x11vnc','-display',':1']);
28 |
29 | let transcodeStreamToOutput = false;
30 |
31 | // event handler for docker stop, not exit until upload completes
32 | process.on('SIGTERM', (code, signal) => {
33 | console.log(`[recording process] 1 exited with code ${code} and signal ${signal}(SIGTERM)`);
34 | if( transcodeStreamToOutput )
35 | process.kill(transcodeStreamToOutput.pid, 'SIGTERM');
36 | });
37 |
38 | // debug use - event handler for ctrl + c
39 | process.on('SIGINT', (code, signal) => {
40 | console.log(`[recording process] 2 exited with code ${code} and signal ${signal}(SIGINT)`)
41 | process.kill(process.pid,'SIGTERM');
42 | process.exit();
43 | });
44 |
45 | process.on('exit', function(code) {
46 | console.log('[recording process] exit code', code);
47 | });
48 |
49 | const express = require('express')
50 | const cors = require('cors')
51 | const app = express()
52 | app.use(cors())
53 |
54 | app.get('/stop', function (req, res) {
55 |
56 | setTimeout( ()=>
57 | {
58 | process.kill(process.pid,'SIGTERM');
59 | process.exit();
60 | }, 3000 );
61 | res.json({"code":0,"message":"done","detail":"stopping in 3 seconds"});
62 | });
63 |
64 | app.get('/start', function (req, res) {
65 | transcodeStreamToOutput = spawn('ffmpeg',[
66 | '-hide_banner',
67 | '-loglevel', 'error',
68 | // disable interaction via stdin
69 | '-nostdin',
70 | // screen image size
71 | '-s', `${BROWSER_SCREEN_WIDTH}x${BROWSER_SCREEN_HEIGHT}`,
72 | // video frame rate
73 | '-r', `${VIDEO_FRAMERATE}`,
74 | // hides the mouse cursor from the resulting video
75 | '-draw_mouse', '0',
76 | // grab the x11 display as video input
77 | '-f', 'x11grab',
78 | '-i', `${DISPLAY}`,
79 | // grab pulse as audio input
80 | '-f', 'pulse',
81 | '-ac', '2',
82 | '-i', 'default',
83 | // codec video with libx264
84 | '-c:v', 'libx264',
85 | '-pix_fmt', 'yuv420p',
86 | '-profile:v', 'main',
87 | '-preset', 'veryfast',
88 | '-x264opts', 'nal-hrd=cbr:no-scenecut',
89 | '-minrate', `${VIDEO_BITRATE}`,
90 | '-maxrate', `${VIDEO_BITRATE}`,
91 | '-g', `${VIDEO_GOP}`,
92 | // apply a fixed delay to the audio stream in order to synchronize it with the video stream
93 | '-filter_complex', 'adelay=delays=1000|1000',
94 | // codec audio with aac
95 | '-c:a', 'aac',
96 | '-b:a', `${AUDIO_BITRATE}`,
97 | '-ac', `${AUDIO_CHANNELS}`,
98 | '-ar', `${AUDIO_SAMPLERATE}`,
99 | // adjust fragmentation to prevent seeking(resolve issue: muxer does not support non seekable output)
100 | '-movflags', 'frag_keyframe+empty_moov',
101 | // set output format to mp4 and output file to stdout
102 | '-f', 'mp4', '/data/'+fileName
103 | ]
104 | );
105 |
106 | transcodeStreamToOutput.stderr.on('data', data => {
107 | console.log(`[transcodeStreamToOutput process] stderr: ${(new Date()).toISOString()} ffmpeg: ${data}`);
108 | });
109 |
110 | console.log(`[recording process] start recording`);
111 | res.json({"code":0,"message":"done"});
112 | } );
113 |
114 | app.listen(80);
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/recording/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "accepts@~1.3.7":
6 | "integrity" "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA=="
7 | "resolved" "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz"
8 | "version" "1.3.7"
9 | dependencies:
10 | "mime-types" "~2.1.24"
11 | "negotiator" "0.6.2"
12 |
13 | "array-flatten@1.1.1":
14 | "integrity" "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
15 | "resolved" "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz"
16 | "version" "1.1.1"
17 |
18 | "body-parser@1.19.0":
19 | "integrity" "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw=="
20 | "resolved" "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz"
21 | "version" "1.19.0"
22 | dependencies:
23 | "bytes" "3.1.0"
24 | "content-type" "~1.0.4"
25 | "debug" "2.6.9"
26 | "depd" "~1.1.2"
27 | "http-errors" "1.7.2"
28 | "iconv-lite" "0.4.24"
29 | "on-finished" "~2.3.0"
30 | "qs" "6.7.0"
31 | "raw-body" "2.4.0"
32 | "type-is" "~1.6.17"
33 |
34 | "bytes@3.1.0":
35 | "integrity" "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
36 | "resolved" "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz"
37 | "version" "3.1.0"
38 |
39 | "content-disposition@0.5.3":
40 | "integrity" "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g=="
41 | "resolved" "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz"
42 | "version" "0.5.3"
43 | dependencies:
44 | "safe-buffer" "5.1.2"
45 |
46 | "content-type@~1.0.4":
47 | "integrity" "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
48 | "resolved" "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz"
49 | "version" "1.0.4"
50 |
51 | "cookie-signature@1.0.6":
52 | "integrity" "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
53 | "resolved" "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
54 | "version" "1.0.6"
55 |
56 | "cookie@0.4.0":
57 | "integrity" "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
58 | "resolved" "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz"
59 | "version" "0.4.0"
60 |
61 | "cors@^2.8.5":
62 | "integrity" "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="
63 | "resolved" "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz"
64 | "version" "2.8.5"
65 | dependencies:
66 | "object-assign" "^4"
67 | "vary" "^1"
68 |
69 | "debug@2.6.9":
70 | "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
71 | "resolved" "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
72 | "version" "2.6.9"
73 | dependencies:
74 | "ms" "2.0.0"
75 |
76 | "depd@~1.1.2":
77 | "integrity" "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
78 | "resolved" "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz"
79 | "version" "1.1.2"
80 |
81 | "destroy@~1.0.4":
82 | "integrity" "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
83 | "resolved" "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz"
84 | "version" "1.0.4"
85 |
86 | "ee-first@1.1.1":
87 | "integrity" "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
88 | "resolved" "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz"
89 | "version" "1.1.1"
90 |
91 | "encodeurl@~1.0.2":
92 | "integrity" "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
93 | "resolved" "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz"
94 | "version" "1.0.2"
95 |
96 | "escape-html@~1.0.3":
97 | "integrity" "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
98 | "resolved" "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz"
99 | "version" "1.0.3"
100 |
101 | "etag@~1.8.1":
102 | "integrity" "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
103 | "resolved" "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz"
104 | "version" "1.8.1"
105 |
106 | "express@^4.17.1":
107 | "integrity" "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g=="
108 | "resolved" "https://registry.npmjs.org/express/-/express-4.17.1.tgz"
109 | "version" "4.17.1"
110 | dependencies:
111 | "accepts" "~1.3.7"
112 | "array-flatten" "1.1.1"
113 | "body-parser" "1.19.0"
114 | "content-disposition" "0.5.3"
115 | "content-type" "~1.0.4"
116 | "cookie" "0.4.0"
117 | "cookie-signature" "1.0.6"
118 | "debug" "2.6.9"
119 | "depd" "~1.1.2"
120 | "encodeurl" "~1.0.2"
121 | "escape-html" "~1.0.3"
122 | "etag" "~1.8.1"
123 | "finalhandler" "~1.1.2"
124 | "fresh" "0.5.2"
125 | "merge-descriptors" "1.0.1"
126 | "methods" "~1.1.2"
127 | "on-finished" "~2.3.0"
128 | "parseurl" "~1.3.3"
129 | "path-to-regexp" "0.1.7"
130 | "proxy-addr" "~2.0.5"
131 | "qs" "6.7.0"
132 | "range-parser" "~1.2.1"
133 | "safe-buffer" "5.1.2"
134 | "send" "0.17.1"
135 | "serve-static" "1.14.1"
136 | "setprototypeof" "1.1.1"
137 | "statuses" "~1.5.0"
138 | "type-is" "~1.6.18"
139 | "utils-merge" "1.0.1"
140 | "vary" "~1.1.2"
141 |
142 | "finalhandler@~1.1.2":
143 | "integrity" "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA=="
144 | "resolved" "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz"
145 | "version" "1.1.2"
146 | dependencies:
147 | "debug" "2.6.9"
148 | "encodeurl" "~1.0.2"
149 | "escape-html" "~1.0.3"
150 | "on-finished" "~2.3.0"
151 | "parseurl" "~1.3.3"
152 | "statuses" "~1.5.0"
153 | "unpipe" "~1.0.0"
154 |
155 | "forwarded@0.2.0":
156 | "integrity" "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
157 | "resolved" "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz"
158 | "version" "0.2.0"
159 |
160 | "fresh@0.5.2":
161 | "integrity" "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
162 | "resolved" "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz"
163 | "version" "0.5.2"
164 |
165 | "http-errors@~1.7.2":
166 | "integrity" "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw=="
167 | "resolved" "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz"
168 | "version" "1.7.3"
169 | dependencies:
170 | "depd" "~1.1.2"
171 | "inherits" "2.0.4"
172 | "setprototypeof" "1.1.1"
173 | "statuses" ">= 1.5.0 < 2"
174 | "toidentifier" "1.0.0"
175 |
176 | "http-errors@1.7.2":
177 | "integrity" "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg=="
178 | "resolved" "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz"
179 | "version" "1.7.2"
180 | dependencies:
181 | "depd" "~1.1.2"
182 | "inherits" "2.0.3"
183 | "setprototypeof" "1.1.1"
184 | "statuses" ">= 1.5.0 < 2"
185 | "toidentifier" "1.0.0"
186 |
187 | "iconv-lite@0.4.24":
188 | "integrity" "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="
189 | "resolved" "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
190 | "version" "0.4.24"
191 | dependencies:
192 | "safer-buffer" ">= 2.1.2 < 3"
193 |
194 | "inherits@2.0.3":
195 | "integrity" "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
196 | "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
197 | "version" "2.0.3"
198 |
199 | "inherits@2.0.4":
200 | "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
201 | "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
202 | "version" "2.0.4"
203 |
204 | "ipaddr.js@1.9.1":
205 | "integrity" "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
206 | "resolved" "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz"
207 | "version" "1.9.1"
208 |
209 | "media-typer@0.3.0":
210 | "integrity" "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
211 | "resolved" "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz"
212 | "version" "0.3.0"
213 |
214 | "merge-descriptors@1.0.1":
215 | "integrity" "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
216 | "resolved" "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz"
217 | "version" "1.0.1"
218 |
219 | "methods@~1.1.2":
220 | "integrity" "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
221 | "resolved" "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz"
222 | "version" "1.1.2"
223 |
224 | "mime-db@1.48.0":
225 | "integrity" "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
226 | "resolved" "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz"
227 | "version" "1.48.0"
228 |
229 | "mime-types@~2.1.24":
230 | "integrity" "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg=="
231 | "resolved" "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz"
232 | "version" "2.1.31"
233 | dependencies:
234 | "mime-db" "1.48.0"
235 |
236 | "mime@1.6.0":
237 | "integrity" "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
238 | "resolved" "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz"
239 | "version" "1.6.0"
240 |
241 | "ms@2.0.0":
242 | "integrity" "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
243 | "resolved" "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
244 | "version" "2.0.0"
245 |
246 | "ms@2.1.1":
247 | "integrity" "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
248 | "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz"
249 | "version" "2.1.1"
250 |
251 | "negotiator@0.6.2":
252 | "integrity" "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
253 | "resolved" "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz"
254 | "version" "0.6.2"
255 |
256 | "object-assign@^4":
257 | "integrity" "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
258 | "resolved" "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
259 | "version" "4.1.1"
260 |
261 | "on-finished@~2.3.0":
262 | "integrity" "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc="
263 | "resolved" "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz"
264 | "version" "2.3.0"
265 | dependencies:
266 | "ee-first" "1.1.1"
267 |
268 | "parseurl@~1.3.3":
269 | "integrity" "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
270 | "resolved" "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz"
271 | "version" "1.3.3"
272 |
273 | "path-to-regexp@0.1.7":
274 | "integrity" "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
275 | "resolved" "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz"
276 | "version" "0.1.7"
277 |
278 | "proxy-addr@~2.0.5":
279 | "integrity" "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="
280 | "resolved" "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz"
281 | "version" "2.0.7"
282 | dependencies:
283 | "forwarded" "0.2.0"
284 | "ipaddr.js" "1.9.1"
285 |
286 | "qs@6.7.0":
287 | "integrity" "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
288 | "resolved" "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz"
289 | "version" "6.7.0"
290 |
291 | "range-parser@~1.2.1":
292 | "integrity" "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
293 | "resolved" "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz"
294 | "version" "1.2.1"
295 |
296 | "raw-body@2.4.0":
297 | "integrity" "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q=="
298 | "resolved" "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz"
299 | "version" "2.4.0"
300 | dependencies:
301 | "bytes" "3.1.0"
302 | "http-errors" "1.7.2"
303 | "iconv-lite" "0.4.24"
304 | "unpipe" "1.0.0"
305 |
306 | "safe-buffer@5.1.2":
307 | "integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
308 | "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
309 | "version" "5.1.2"
310 |
311 | "safer-buffer@>= 2.1.2 < 3":
312 | "integrity" "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
313 | "resolved" "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
314 | "version" "2.1.2"
315 |
316 | "send@0.17.1":
317 | "integrity" "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg=="
318 | "resolved" "https://registry.npmjs.org/send/-/send-0.17.1.tgz"
319 | "version" "0.17.1"
320 | dependencies:
321 | "debug" "2.6.9"
322 | "depd" "~1.1.2"
323 | "destroy" "~1.0.4"
324 | "encodeurl" "~1.0.2"
325 | "escape-html" "~1.0.3"
326 | "etag" "~1.8.1"
327 | "fresh" "0.5.2"
328 | "http-errors" "~1.7.2"
329 | "mime" "1.6.0"
330 | "ms" "2.1.1"
331 | "on-finished" "~2.3.0"
332 | "range-parser" "~1.2.1"
333 | "statuses" "~1.5.0"
334 |
335 | "serve-static@1.14.1":
336 | "integrity" "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg=="
337 | "resolved" "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz"
338 | "version" "1.14.1"
339 | dependencies:
340 | "encodeurl" "~1.0.2"
341 | "escape-html" "~1.0.3"
342 | "parseurl" "~1.3.3"
343 | "send" "0.17.1"
344 |
345 | "setprototypeof@1.1.1":
346 | "integrity" "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
347 | "resolved" "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz"
348 | "version" "1.1.1"
349 |
350 | "statuses@>= 1.5.0 < 2", "statuses@~1.5.0":
351 | "integrity" "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
352 | "resolved" "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz"
353 | "version" "1.5.0"
354 |
355 | "toidentifier@1.0.0":
356 | "integrity" "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
357 | "resolved" "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz"
358 | "version" "1.0.0"
359 |
360 | "type-is@~1.6.17", "type-is@~1.6.18":
361 | "integrity" "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="
362 | "resolved" "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz"
363 | "version" "1.6.18"
364 | dependencies:
365 | "media-typer" "0.3.0"
366 | "mime-types" "~2.1.24"
367 |
368 | "unpipe@~1.0.0", "unpipe@1.0.0":
369 | "integrity" "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
370 | "resolved" "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
371 | "version" "1.0.0"
372 |
373 | "utils-merge@1.0.1":
374 | "integrity" "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
375 | "resolved" "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz"
376 | "version" "1.0.1"
377 |
378 | "vary@^1", "vary@~1.1.2":
379 | "integrity" "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
380 | "resolved" "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
381 | "version" "1.1.2"
382 |
--------------------------------------------------------------------------------
/recording/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "recording",
3 | "version": "1.0.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "version": "1.0.0",
9 | "license": "MIT",
10 | "dependencies": {
11 | "cors": "^2.8.5",
12 | "express": "^4.17.1"
13 | }
14 | },
15 | "node_modules/accepts": {
16 | "version": "1.3.7",
17 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
18 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
19 | "license": "MIT",
20 | "dependencies": {
21 | "mime-types": "~2.1.24",
22 | "negotiator": "0.6.2"
23 | },
24 | "engines": {
25 | "node": ">= 0.6"
26 | }
27 | },
28 | "node_modules/array-flatten": {
29 | "version": "1.1.1",
30 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
31 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
32 | "license": "MIT"
33 | },
34 | "node_modules/body-parser": {
35 | "version": "1.19.0",
36 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
37 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
38 | "license": "MIT",
39 | "dependencies": {
40 | "bytes": "3.1.0",
41 | "content-type": "~1.0.4",
42 | "debug": "2.6.9",
43 | "depd": "~1.1.2",
44 | "http-errors": "1.7.2",
45 | "iconv-lite": "0.4.24",
46 | "on-finished": "~2.3.0",
47 | "qs": "6.7.0",
48 | "raw-body": "2.4.0",
49 | "type-is": "~1.6.17"
50 | },
51 | "engines": {
52 | "node": ">= 0.8"
53 | }
54 | },
55 | "node_modules/bytes": {
56 | "version": "3.1.0",
57 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
58 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
59 | "license": "MIT",
60 | "engines": {
61 | "node": ">= 0.8"
62 | }
63 | },
64 | "node_modules/content-disposition": {
65 | "version": "0.5.3",
66 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
67 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
68 | "license": "MIT",
69 | "dependencies": {
70 | "safe-buffer": "5.1.2"
71 | },
72 | "engines": {
73 | "node": ">= 0.6"
74 | }
75 | },
76 | "node_modules/content-type": {
77 | "version": "1.0.4",
78 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
79 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
80 | "license": "MIT",
81 | "engines": {
82 | "node": ">= 0.6"
83 | }
84 | },
85 | "node_modules/cookie": {
86 | "version": "0.4.0",
87 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
88 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
89 | "license": "MIT",
90 | "engines": {
91 | "node": ">= 0.6"
92 | }
93 | },
94 | "node_modules/cookie-signature": {
95 | "version": "1.0.6",
96 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
97 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
98 | "license": "MIT"
99 | },
100 | "node_modules/cors": {
101 | "version": "2.8.5",
102 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
103 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
104 | "dependencies": {
105 | "object-assign": "^4",
106 | "vary": "^1"
107 | },
108 | "engines": {
109 | "node": ">= 0.10"
110 | }
111 | },
112 | "node_modules/debug": {
113 | "version": "2.6.9",
114 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
115 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
116 | "license": "MIT",
117 | "dependencies": {
118 | "ms": "2.0.0"
119 | }
120 | },
121 | "node_modules/depd": {
122 | "version": "1.1.2",
123 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
124 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
125 | "license": "MIT",
126 | "engines": {
127 | "node": ">= 0.6"
128 | }
129 | },
130 | "node_modules/destroy": {
131 | "version": "1.0.4",
132 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
133 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
134 | "license": "MIT"
135 | },
136 | "node_modules/ee-first": {
137 | "version": "1.1.1",
138 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
139 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
140 | "license": "MIT"
141 | },
142 | "node_modules/encodeurl": {
143 | "version": "1.0.2",
144 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
145 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
146 | "license": "MIT",
147 | "engines": {
148 | "node": ">= 0.8"
149 | }
150 | },
151 | "node_modules/escape-html": {
152 | "version": "1.0.3",
153 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
154 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
155 | "license": "MIT"
156 | },
157 | "node_modules/etag": {
158 | "version": "1.8.1",
159 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
160 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
161 | "license": "MIT",
162 | "engines": {
163 | "node": ">= 0.6"
164 | }
165 | },
166 | "node_modules/express": {
167 | "version": "4.17.1",
168 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
169 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
170 | "license": "MIT",
171 | "dependencies": {
172 | "accepts": "~1.3.7",
173 | "array-flatten": "1.1.1",
174 | "body-parser": "1.19.0",
175 | "content-disposition": "0.5.3",
176 | "content-type": "~1.0.4",
177 | "cookie": "0.4.0",
178 | "cookie-signature": "1.0.6",
179 | "debug": "2.6.9",
180 | "depd": "~1.1.2",
181 | "encodeurl": "~1.0.2",
182 | "escape-html": "~1.0.3",
183 | "etag": "~1.8.1",
184 | "finalhandler": "~1.1.2",
185 | "fresh": "0.5.2",
186 | "merge-descriptors": "1.0.1",
187 | "methods": "~1.1.2",
188 | "on-finished": "~2.3.0",
189 | "parseurl": "~1.3.3",
190 | "path-to-regexp": "0.1.7",
191 | "proxy-addr": "~2.0.5",
192 | "qs": "6.7.0",
193 | "range-parser": "~1.2.1",
194 | "safe-buffer": "5.1.2",
195 | "send": "0.17.1",
196 | "serve-static": "1.14.1",
197 | "setprototypeof": "1.1.1",
198 | "statuses": "~1.5.0",
199 | "type-is": "~1.6.18",
200 | "utils-merge": "1.0.1",
201 | "vary": "~1.1.2"
202 | },
203 | "engines": {
204 | "node": ">= 0.10.0"
205 | }
206 | },
207 | "node_modules/finalhandler": {
208 | "version": "1.1.2",
209 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
210 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
211 | "license": "MIT",
212 | "dependencies": {
213 | "debug": "2.6.9",
214 | "encodeurl": "~1.0.2",
215 | "escape-html": "~1.0.3",
216 | "on-finished": "~2.3.0",
217 | "parseurl": "~1.3.3",
218 | "statuses": "~1.5.0",
219 | "unpipe": "~1.0.0"
220 | },
221 | "engines": {
222 | "node": ">= 0.8"
223 | }
224 | },
225 | "node_modules/forwarded": {
226 | "version": "0.2.0",
227 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
228 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
229 | "license": "MIT",
230 | "engines": {
231 | "node": ">= 0.6"
232 | }
233 | },
234 | "node_modules/fresh": {
235 | "version": "0.5.2",
236 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
237 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
238 | "license": "MIT",
239 | "engines": {
240 | "node": ">= 0.6"
241 | }
242 | },
243 | "node_modules/http-errors": {
244 | "version": "1.7.2",
245 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
246 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
247 | "license": "MIT",
248 | "dependencies": {
249 | "depd": "~1.1.2",
250 | "inherits": "2.0.3",
251 | "setprototypeof": "1.1.1",
252 | "statuses": ">= 1.5.0 < 2",
253 | "toidentifier": "1.0.0"
254 | },
255 | "engines": {
256 | "node": ">= 0.6"
257 | }
258 | },
259 | "node_modules/iconv-lite": {
260 | "version": "0.4.24",
261 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
262 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
263 | "license": "MIT",
264 | "dependencies": {
265 | "safer-buffer": ">= 2.1.2 < 3"
266 | },
267 | "engines": {
268 | "node": ">=0.10.0"
269 | }
270 | },
271 | "node_modules/inherits": {
272 | "version": "2.0.3",
273 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
274 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
275 | "license": "ISC"
276 | },
277 | "node_modules/ipaddr.js": {
278 | "version": "1.9.1",
279 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
280 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
281 | "license": "MIT",
282 | "engines": {
283 | "node": ">= 0.10"
284 | }
285 | },
286 | "node_modules/media-typer": {
287 | "version": "0.3.0",
288 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
289 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
290 | "license": "MIT",
291 | "engines": {
292 | "node": ">= 0.6"
293 | }
294 | },
295 | "node_modules/merge-descriptors": {
296 | "version": "1.0.1",
297 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
298 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
299 | "license": "MIT"
300 | },
301 | "node_modules/methods": {
302 | "version": "1.1.2",
303 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
304 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
305 | "license": "MIT",
306 | "engines": {
307 | "node": ">= 0.6"
308 | }
309 | },
310 | "node_modules/mime": {
311 | "version": "1.6.0",
312 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
313 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
314 | "license": "MIT",
315 | "bin": {
316 | "mime": "cli.js"
317 | },
318 | "engines": {
319 | "node": ">=4"
320 | }
321 | },
322 | "node_modules/mime-db": {
323 | "version": "1.48.0",
324 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
325 | "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==",
326 | "license": "MIT",
327 | "engines": {
328 | "node": ">= 0.6"
329 | }
330 | },
331 | "node_modules/mime-types": {
332 | "version": "2.1.31",
333 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
334 | "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
335 | "license": "MIT",
336 | "dependencies": {
337 | "mime-db": "1.48.0"
338 | },
339 | "engines": {
340 | "node": ">= 0.6"
341 | }
342 | },
343 | "node_modules/ms": {
344 | "version": "2.0.0",
345 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
346 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
347 | "license": "MIT"
348 | },
349 | "node_modules/negotiator": {
350 | "version": "0.6.2",
351 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
352 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
353 | "license": "MIT",
354 | "engines": {
355 | "node": ">= 0.6"
356 | }
357 | },
358 | "node_modules/object-assign": {
359 | "version": "4.1.1",
360 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
361 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
362 | "engines": {
363 | "node": ">=0.10.0"
364 | }
365 | },
366 | "node_modules/on-finished": {
367 | "version": "2.3.0",
368 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
369 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
370 | "license": "MIT",
371 | "dependencies": {
372 | "ee-first": "1.1.1"
373 | },
374 | "engines": {
375 | "node": ">= 0.8"
376 | }
377 | },
378 | "node_modules/parseurl": {
379 | "version": "1.3.3",
380 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
381 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
382 | "license": "MIT",
383 | "engines": {
384 | "node": ">= 0.8"
385 | }
386 | },
387 | "node_modules/path-to-regexp": {
388 | "version": "0.1.7",
389 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
390 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
391 | "license": "MIT"
392 | },
393 | "node_modules/proxy-addr": {
394 | "version": "2.0.7",
395 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
396 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
397 | "license": "MIT",
398 | "dependencies": {
399 | "forwarded": "0.2.0",
400 | "ipaddr.js": "1.9.1"
401 | },
402 | "engines": {
403 | "node": ">= 0.10"
404 | }
405 | },
406 | "node_modules/qs": {
407 | "version": "6.7.0",
408 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
409 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
410 | "license": "BSD-3-Clause",
411 | "engines": {
412 | "node": ">=0.6"
413 | }
414 | },
415 | "node_modules/range-parser": {
416 | "version": "1.2.1",
417 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
418 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
419 | "license": "MIT",
420 | "engines": {
421 | "node": ">= 0.6"
422 | }
423 | },
424 | "node_modules/raw-body": {
425 | "version": "2.4.0",
426 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
427 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
428 | "license": "MIT",
429 | "dependencies": {
430 | "bytes": "3.1.0",
431 | "http-errors": "1.7.2",
432 | "iconv-lite": "0.4.24",
433 | "unpipe": "1.0.0"
434 | },
435 | "engines": {
436 | "node": ">= 0.8"
437 | }
438 | },
439 | "node_modules/safe-buffer": {
440 | "version": "5.1.2",
441 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
442 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
443 | "license": "MIT"
444 | },
445 | "node_modules/safer-buffer": {
446 | "version": "2.1.2",
447 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
448 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
449 | "license": "MIT"
450 | },
451 | "node_modules/send": {
452 | "version": "0.17.1",
453 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
454 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
455 | "license": "MIT",
456 | "dependencies": {
457 | "debug": "2.6.9",
458 | "depd": "~1.1.2",
459 | "destroy": "~1.0.4",
460 | "encodeurl": "~1.0.2",
461 | "escape-html": "~1.0.3",
462 | "etag": "~1.8.1",
463 | "fresh": "0.5.2",
464 | "http-errors": "~1.7.2",
465 | "mime": "1.6.0",
466 | "ms": "2.1.1",
467 | "on-finished": "~2.3.0",
468 | "range-parser": "~1.2.1",
469 | "statuses": "~1.5.0"
470 | },
471 | "engines": {
472 | "node": ">= 0.8.0"
473 | }
474 | },
475 | "node_modules/send/node_modules/http-errors": {
476 | "version": "1.7.3",
477 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
478 | "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
479 | "license": "MIT",
480 | "dependencies": {
481 | "depd": "~1.1.2",
482 | "inherits": "2.0.4",
483 | "setprototypeof": "1.1.1",
484 | "statuses": ">= 1.5.0 < 2",
485 | "toidentifier": "1.0.0"
486 | },
487 | "engines": {
488 | "node": ">= 0.6"
489 | }
490 | },
491 | "node_modules/send/node_modules/inherits": {
492 | "version": "2.0.4",
493 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
494 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
495 | "license": "ISC"
496 | },
497 | "node_modules/send/node_modules/ms": {
498 | "version": "2.1.1",
499 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
500 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
501 | "license": "MIT"
502 | },
503 | "node_modules/serve-static": {
504 | "version": "1.14.1",
505 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
506 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
507 | "license": "MIT",
508 | "dependencies": {
509 | "encodeurl": "~1.0.2",
510 | "escape-html": "~1.0.3",
511 | "parseurl": "~1.3.3",
512 | "send": "0.17.1"
513 | },
514 | "engines": {
515 | "node": ">= 0.8.0"
516 | }
517 | },
518 | "node_modules/setprototypeof": {
519 | "version": "1.1.1",
520 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
521 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
522 | "license": "ISC"
523 | },
524 | "node_modules/statuses": {
525 | "version": "1.5.0",
526 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
527 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
528 | "license": "MIT",
529 | "engines": {
530 | "node": ">= 0.6"
531 | }
532 | },
533 | "node_modules/toidentifier": {
534 | "version": "1.0.0",
535 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
536 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
537 | "license": "MIT",
538 | "engines": {
539 | "node": ">=0.6"
540 | }
541 | },
542 | "node_modules/type-is": {
543 | "version": "1.6.18",
544 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
545 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
546 | "license": "MIT",
547 | "dependencies": {
548 | "media-typer": "0.3.0",
549 | "mime-types": "~2.1.24"
550 | },
551 | "engines": {
552 | "node": ">= 0.6"
553 | }
554 | },
555 | "node_modules/unpipe": {
556 | "version": "1.0.0",
557 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
558 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
559 | "license": "MIT",
560 | "engines": {
561 | "node": ">= 0.8"
562 | }
563 | },
564 | "node_modules/utils-merge": {
565 | "version": "1.0.1",
566 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
567 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
568 | "license": "MIT",
569 | "engines": {
570 | "node": ">= 0.4.0"
571 | }
572 | },
573 | "node_modules/vary": {
574 | "version": "1.1.2",
575 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
576 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
577 | "license": "MIT",
578 | "engines": {
579 | "node": ">= 0.8"
580 | }
581 | }
582 | },
583 | "dependencies": {
584 | "accepts": {
585 | "version": "1.3.7",
586 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
587 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
588 | "requires": {
589 | "mime-types": "~2.1.24",
590 | "negotiator": "0.6.2"
591 | }
592 | },
593 | "array-flatten": {
594 | "version": "1.1.1",
595 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
596 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
597 | },
598 | "body-parser": {
599 | "version": "1.19.0",
600 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
601 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
602 | "requires": {
603 | "bytes": "3.1.0",
604 | "content-type": "~1.0.4",
605 | "debug": "2.6.9",
606 | "depd": "~1.1.2",
607 | "http-errors": "1.7.2",
608 | "iconv-lite": "0.4.24",
609 | "on-finished": "~2.3.0",
610 | "qs": "6.7.0",
611 | "raw-body": "2.4.0",
612 | "type-is": "~1.6.17"
613 | }
614 | },
615 | "bytes": {
616 | "version": "3.1.0",
617 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
618 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
619 | },
620 | "content-disposition": {
621 | "version": "0.5.3",
622 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
623 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
624 | "requires": {
625 | "safe-buffer": "5.1.2"
626 | }
627 | },
628 | "content-type": {
629 | "version": "1.0.4",
630 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
631 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
632 | },
633 | "cookie": {
634 | "version": "0.4.0",
635 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
636 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
637 | },
638 | "cookie-signature": {
639 | "version": "1.0.6",
640 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
641 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
642 | },
643 | "cors": {
644 | "version": "2.8.5",
645 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
646 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
647 | "requires": {
648 | "object-assign": "^4",
649 | "vary": "^1"
650 | }
651 | },
652 | "debug": {
653 | "version": "2.6.9",
654 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
655 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
656 | "requires": {
657 | "ms": "2.0.0"
658 | }
659 | },
660 | "depd": {
661 | "version": "1.1.2",
662 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
663 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
664 | },
665 | "destroy": {
666 | "version": "1.0.4",
667 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
668 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
669 | },
670 | "ee-first": {
671 | "version": "1.1.1",
672 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
673 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
674 | },
675 | "encodeurl": {
676 | "version": "1.0.2",
677 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
678 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
679 | },
680 | "escape-html": {
681 | "version": "1.0.3",
682 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
683 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
684 | },
685 | "etag": {
686 | "version": "1.8.1",
687 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
688 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
689 | },
690 | "express": {
691 | "version": "4.17.1",
692 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
693 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
694 | "requires": {
695 | "accepts": "~1.3.7",
696 | "array-flatten": "1.1.1",
697 | "body-parser": "1.19.0",
698 | "content-disposition": "0.5.3",
699 | "content-type": "~1.0.4",
700 | "cookie": "0.4.0",
701 | "cookie-signature": "1.0.6",
702 | "debug": "2.6.9",
703 | "depd": "~1.1.2",
704 | "encodeurl": "~1.0.2",
705 | "escape-html": "~1.0.3",
706 | "etag": "~1.8.1",
707 | "finalhandler": "~1.1.2",
708 | "fresh": "0.5.2",
709 | "merge-descriptors": "1.0.1",
710 | "methods": "~1.1.2",
711 | "on-finished": "~2.3.0",
712 | "parseurl": "~1.3.3",
713 | "path-to-regexp": "0.1.7",
714 | "proxy-addr": "~2.0.5",
715 | "qs": "6.7.0",
716 | "range-parser": "~1.2.1",
717 | "safe-buffer": "5.1.2",
718 | "send": "0.17.1",
719 | "serve-static": "1.14.1",
720 | "setprototypeof": "1.1.1",
721 | "statuses": "~1.5.0",
722 | "type-is": "~1.6.18",
723 | "utils-merge": "1.0.1",
724 | "vary": "~1.1.2"
725 | }
726 | },
727 | "finalhandler": {
728 | "version": "1.1.2",
729 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
730 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
731 | "requires": {
732 | "debug": "2.6.9",
733 | "encodeurl": "~1.0.2",
734 | "escape-html": "~1.0.3",
735 | "on-finished": "~2.3.0",
736 | "parseurl": "~1.3.3",
737 | "statuses": "~1.5.0",
738 | "unpipe": "~1.0.0"
739 | }
740 | },
741 | "forwarded": {
742 | "version": "0.2.0",
743 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
744 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
745 | },
746 | "fresh": {
747 | "version": "0.5.2",
748 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
749 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
750 | },
751 | "http-errors": {
752 | "version": "1.7.2",
753 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
754 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
755 | "requires": {
756 | "depd": "~1.1.2",
757 | "inherits": "2.0.3",
758 | "setprototypeof": "1.1.1",
759 | "statuses": ">= 1.5.0 < 2",
760 | "toidentifier": "1.0.0"
761 | }
762 | },
763 | "iconv-lite": {
764 | "version": "0.4.24",
765 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
766 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
767 | "requires": {
768 | "safer-buffer": ">= 2.1.2 < 3"
769 | }
770 | },
771 | "inherits": {
772 | "version": "2.0.3",
773 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
774 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
775 | },
776 | "ipaddr.js": {
777 | "version": "1.9.1",
778 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
779 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
780 | },
781 | "media-typer": {
782 | "version": "0.3.0",
783 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
784 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
785 | },
786 | "merge-descriptors": {
787 | "version": "1.0.1",
788 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
789 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
790 | },
791 | "methods": {
792 | "version": "1.1.2",
793 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
794 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
795 | },
796 | "mime": {
797 | "version": "1.6.0",
798 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
799 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
800 | },
801 | "mime-db": {
802 | "version": "1.48.0",
803 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
804 | "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
805 | },
806 | "mime-types": {
807 | "version": "2.1.31",
808 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
809 | "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
810 | "requires": {
811 | "mime-db": "1.48.0"
812 | }
813 | },
814 | "ms": {
815 | "version": "2.0.0",
816 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
817 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
818 | },
819 | "negotiator": {
820 | "version": "0.6.2",
821 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
822 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
823 | },
824 | "object-assign": {
825 | "version": "4.1.1",
826 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
827 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
828 | },
829 | "on-finished": {
830 | "version": "2.3.0",
831 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
832 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
833 | "requires": {
834 | "ee-first": "1.1.1"
835 | }
836 | },
837 | "parseurl": {
838 | "version": "1.3.3",
839 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
840 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
841 | },
842 | "path-to-regexp": {
843 | "version": "0.1.7",
844 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
845 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
846 | },
847 | "proxy-addr": {
848 | "version": "2.0.7",
849 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
850 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
851 | "requires": {
852 | "forwarded": "0.2.0",
853 | "ipaddr.js": "1.9.1"
854 | }
855 | },
856 | "qs": {
857 | "version": "6.7.0",
858 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
859 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
860 | },
861 | "range-parser": {
862 | "version": "1.2.1",
863 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
864 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
865 | },
866 | "raw-body": {
867 | "version": "2.4.0",
868 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
869 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
870 | "requires": {
871 | "bytes": "3.1.0",
872 | "http-errors": "1.7.2",
873 | "iconv-lite": "0.4.24",
874 | "unpipe": "1.0.0"
875 | }
876 | },
877 | "safe-buffer": {
878 | "version": "5.1.2",
879 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
880 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
881 | },
882 | "safer-buffer": {
883 | "version": "2.1.2",
884 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
885 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
886 | },
887 | "send": {
888 | "version": "0.17.1",
889 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
890 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
891 | "requires": {
892 | "debug": "2.6.9",
893 | "depd": "~1.1.2",
894 | "destroy": "~1.0.4",
895 | "encodeurl": "~1.0.2",
896 | "escape-html": "~1.0.3",
897 | "etag": "~1.8.1",
898 | "fresh": "0.5.2",
899 | "http-errors": "~1.7.2",
900 | "mime": "1.6.0",
901 | "ms": "2.1.1",
902 | "on-finished": "~2.3.0",
903 | "range-parser": "~1.2.1",
904 | "statuses": "~1.5.0"
905 | },
906 | "dependencies": {
907 | "http-errors": {
908 | "version": "1.7.3",
909 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
910 | "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
911 | "requires": {
912 | "depd": "~1.1.2",
913 | "inherits": "2.0.4",
914 | "setprototypeof": "1.1.1",
915 | "statuses": ">= 1.5.0 < 2",
916 | "toidentifier": "1.0.0"
917 | }
918 | },
919 | "inherits": {
920 | "version": "2.0.4",
921 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
922 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
923 | },
924 | "ms": {
925 | "version": "2.1.1",
926 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
927 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
928 | }
929 | }
930 | },
931 | "serve-static": {
932 | "version": "1.14.1",
933 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
934 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
935 | "requires": {
936 | "encodeurl": "~1.0.2",
937 | "escape-html": "~1.0.3",
938 | "parseurl": "~1.3.3",
939 | "send": "0.17.1"
940 | }
941 | },
942 | "setprototypeof": {
943 | "version": "1.1.1",
944 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
945 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
946 | },
947 | "statuses": {
948 | "version": "1.5.0",
949 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
950 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
951 | },
952 | "toidentifier": {
953 | "version": "1.0.0",
954 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
955 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
956 | },
957 | "type-is": {
958 | "version": "1.6.18",
959 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
960 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
961 | "requires": {
962 | "media-typer": "0.3.0",
963 | "mime-types": "~2.1.24"
964 | }
965 | },
966 | "unpipe": {
967 | "version": "1.0.0",
968 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
969 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
970 | },
971 | "utils-merge": {
972 | "version": "1.0.1",
973 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
974 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
975 | },
976 | "vary": {
977 | "version": "1.1.2",
978 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
979 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
980 | }
981 | }
982 | }
983 |
--------------------------------------------------------------------------------