diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..612bc5a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,23 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..11fc491 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..7f41aa4 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + + # Maintain dependencies for docker + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/commit-issue.yml b/.github/workflows/commit-issue.yml new file mode 100644 index 0000000..97ec6c9 --- /dev/null +++ b/.github/workflows/commit-issue.yml @@ -0,0 +1,10 @@ +name: Commit Issue Commenter +on: push +jobs: + checkCommit: + name: Comment From Commit + runs-on: ubuntu-latest + steps: + - uses: adamzolyak/commit-issue-commenter-action@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/dependency-review.yaml b/.github/workflows/dependency-review.yaml new file mode 100644 index 0000000..a083a27 --- /dev/null +++ b/.github/workflows/dependency-review.yaml @@ -0,0 +1,12 @@ +name: 'Dependency Review' +on: [pull_request] +permissions: write-all + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v3 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v3 diff --git a/.github/workflows/docker-pr-clean-up.yaml b/.github/workflows/docker-pr-clean-up.yaml new file mode 100644 index 0000000..55804ce --- /dev/null +++ b/.github/workflows/docker-pr-clean-up.yaml @@ -0,0 +1,21 @@ +name: 'Docker PR Clean Up' +permissions: + packages: write + +on: + pull_request: + types: [closed] + +jobs: + purge-image: + name: Delete image from ghcr.io + runs-on: ubuntu-latest + steps: + - name: Prune + uses: vlaurin/action-ghcr-prune@main + with: + token: ${{ secrets.PACKAGES_TOKEN }} + container: ${{ github.event.repository.name }} + dry-run: false + tag-regex: pr-${{github.event.pull_request.number}} + untagged: true diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..588939b --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,111 @@ +name: Docker Build and Publish +permissions: + packages: write + contents: read + +on: + push: + branches: + - 'master' + tags: + - 'v*' + pull_request: + branches: + - master + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + name: Docker meta ghcr + id: meta-ghcr + uses: docker/metadata-action@v4 + with: + # list of Docker images to use as base name for tags + images: | + ghcr.io/${{ github.repository }} + # generate Docker tags based on the following events/attributes + tags: | + type=ref,event=pr + type=semver,pattern=v{{version}} + type=semver,pattern=v{{major}}.{{minor}} + type=semver,pattern=v{{major}} + type=edge,branch=master + - + name: Docker meta DockerHub + id: meta-dockerhub + uses: docker/metadata-action@v4 + with: + # list of Docker images to use as base name for tags + images: | + ${{ github.repository }} + # generate Docker tags based on the following events/attributes + tags: | + type=ref,event=pr + type=semver,pattern=v{{version}} + type=semver,pattern=v{{major}}.{{minor}} + type=semver,pattern=v{{major}} + type=edge,branch=master + - + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Login to DockerHub + uses: docker/login-action@v2 + if: github.event_name != 'pull_request' + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - + name: Build and push ghcr + uses: docker/build-push-action@v3 + with: + context: . + # Due to build time, only building the one currently needed. + # If needed, we can add more platforms when requested. + platforms: "linux/amd64" + # Do not push pull requests + #push: ${{ github.event_name != 'pull_request' }} + # Push pull requests so they can be tested + push: true + tags: ${{ steps.meta-ghcr.outputs.tags }} + labels: ${{ steps.meta-ghcr.outputs.labels }} + - + name: Build and push DockerHub + uses: docker/build-push-action@v3 + if: github.event_name != 'pull_request' + with: + context: . + # Due to build time, only building the one currently needed. + # If needed, we can add more platforms when requested. + platforms: "linux/amd64" + # Do not push pull requests + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta-dockerhub.outputs.tags }} + labels: ${{ steps.meta-dockerhub.outputs.labels }} + - + name: push README to Dockerhub + uses: christian-korneck/update-container-description-action@v1 + if: github.event_name != 'pull_request' + env: + DOCKER_USER: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKER_PASS: ${{ secrets.DOCKERHUB_TOKEN }} + with: + destination_container_repo: ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} + provider: dockerhub + short_description: 'Docker with telegraf setup for Synology. Needs external Influx and Grafana.' + readme_file: 'README.md' diff --git a/.github/workflows/release-please-branches.yml b/.github/workflows/release-please-branches.yml new file mode 100644 index 0000000..c325a6a --- /dev/null +++ b/.github/workflows/release-please-branches.yml @@ -0,0 +1,71 @@ +name: Create Releases From Branches +permissions: write-all + +on: + push: + branches: + # See https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet + - releases/v[0-9]+ +jobs: + create-release: + runs-on: ubuntu-latest + steps: + - name: Extract branch name + shell: bash + run: echo "##[set-output name=branch;]${GITHUB_REF#refs/heads/}" + id: extract_branch + + - uses: GoogleCloudPlatform/release-please-action@v3.7.1 + id: release + with: + release-type: simple + default-branch: ${{ steps.extract_branch.outputs.branch }} + token: "${{ secrets.PACKAGES_TOKEN }}" + + - uses: actions/checkout@v2 + with: + fetch-depth: '0' + + - name: Tag major and patch versions + if: ${{ steps.release.outputs.release_created }} + run: | + git config user.name github-actions[bot] + git config user.email 41898282+github-actions[bot]@users.noreply.github.com + git remote add gh-token "https://${{ secrets.PACKAGES_TOKEN}}@github.com/google-github-actions/release-please-action.git" + git tag -d v${{ steps.release.outputs.major }} || true + git tag -d v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} || true + git push origin :v${{ steps.release.outputs.major }} || true + git push origin :v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} || true + git tag -a v${{ steps.release.outputs.major }} -m "Release v${{ steps.release.outputs.major }}" + git tag -a v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} -m "Release v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}" + git push origin v${{ steps.release.outputs.major }} + git push origin v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} + + - name: Recreate latest tags for release ordering + if: ${{ steps.release.outputs.release_created }} + id: recreate-latest-tags + run: | + git fetch -avtf + LATEST="$(git tag -l|tail -1)" + LATEST_MAJOR="$(git tag -l|tail -1|awk -F"." '{print $1}')" + LATEST_MINOR="$(git tag -l|tail -1|awk -F"." '{print $1"."$2}')" + git checkout main + git tag -d "${LATEST}" + git tag -d "${LATEST_MAJOR}" + git tag -d "${LATEST_MINOR}" + git push origin :"${LATEST}" + git push origin :"${LATEST_MAJOR}" + git push origin :"${LATEST_MINOR}" + git tag -a "${LATEST}" -m "Release ${LATEST}" + git tag -a "${LATEST_MAJOR}" -m "Release ${LATEST_MAJOR}" + git tag -a "${LATEST_MINOR}" -m "Release ${LATEST_MINOR}" + git push origin "${LATEST}" + git push origin "${LATEST_MAJOR}" + git push origin "${LATEST_MINOR}" + echo "::set-output name=LATEST_RELEASE::${LATEST}" + + - name: Publish release on GitHub + if: ${{ steps.release.outputs.release_created }} + uses: test-room-7/action-publish-release-drafts@v0 + with: + tag-name: ${{ steps.recreate-latest-tags.outputs.LATEST_RELEASE }} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..aef0a1c --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,41 @@ +name: Create Releases From Default Branch +permissions: write-all + +on: + push: + branches: + - master +jobs: + create-release: + runs-on: ubuntu-latest + steps: + - uses: GoogleCloudPlatform/release-please-action@v3.7.1 + id: release + with: + token: "${{ secrets.PACKAGES_TOKEN }}" + release-type: simple + + - uses: actions/checkout@v2 + + - name: Create major branch and tag also patch tag versions + if: ${{ steps.release.outputs.release_created }} + run: | + git config user.name github-actions[bot] + git config user.email 41898282+github-actions[bot]@users.noreply.github.com + git remote add gh-token "https://${{ secrets.PACKAGES_TOKEN}}@github.com/google-github-actions/release-please-action.git" + git tag -d v${{ steps.release.outputs.major }} || true + git tag -d v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} || true + git push origin :v${{ steps.release.outputs.major }} || true + git push origin :v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} || true + git tag -a v${{ steps.release.outputs.major }} -m "Release v${{ steps.release.outputs.major }}" + git tag -a v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} -m "Release v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}" + git push origin v${{ steps.release.outputs.major }} + git push origin v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} + OLD_MAJOR="$( echo ${{ steps.release.outputs.major }} - 1 | bc )" + if ! git branch -r | grep "releases/v${OLD_MAJOR}"; then + git fetch -avt + if git tag -l | grep -x "^v${OLD_MAJOR}"; then + git branch releases/v${OLD_MAJOR} v${OLD_MAJOR} + git push origin releases/v${OLD_MAJOR} + fi + fi diff --git a/.gitignore b/.gitignore index 6e64c8e..58a19bb 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ npm-debug.log # cache .cache +.vercel diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fe180d1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +## [2.0.1](https://github.com/Gibby/talk/compare/v2.0.0...v2.0.1) (2023-11-07) + + +### Bug Fixes + +* Changes from upstream ([#12](https://github.com/Gibby/talk/issues/12)) ([3deea52](https://github.com/Gibby/talk/commit/3deea52bb1367daa496343e8713aadd531a3ccee)) diff --git a/Dockerfile b/Dockerfile index 4011613..cda703e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,12 @@ -FROM node:latest +#FROM node:latest +FROM node:lts-alpine + WORKDIR /usr/src/app -COPY package.json . -RUN npm install + COPY . . + +RUN npm install + EXPOSE 3000 + CMD [ "npm", "start" ] diff --git a/README.md b/README.md index 91225cd..7743464 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # Talk -## A free group video call app with screen sharing. +## A free, p2p, group video call app for the web. No signups. No downloads. Works in all major browsers. -It is built using WebRTC, so all your video, audio & text chat is peer-to-peer. Group video call is achieved using WebRTC mesh. So the quality of the call is inversely proportional to the number of people on the call. The sweet number is somewhere around 6 to 8 people in an average high-speed connection. +Talk is built using WebRTC, so all your video, audio & text chat is peer-to-peer. Group video call is achieved using WebRTC mesh. So the quality of the call is inversely proportional to the number of people on the call. The sweet number is somewhere around 6 to 8 people in an average high-speed connection. + +--- ### Prerequisites: @@ -13,19 +15,19 @@ It is built using WebRTC, so all your video, audio & text chat is peer-to-peer. [Fork this repo](https://github.com/vasanthv/talk/fork) and then clone it: -``` +```bash git clone https://github.com//talk.git ``` `cd talk` and then install dependencies -``` +```bash npm install ``` Run the app -``` +```bash npm start ``` diff --git a/assets/og-image.png b/assets/og-image.png new file mode 100644 index 0000000..835e1ab Binary files /dev/null and b/assets/og-image.png differ diff --git a/assets/videoOff.png b/assets/videoOff.png new file mode 100644 index 0000000..db83797 Binary files /dev/null and b/assets/videoOff.png differ diff --git a/docker-compose.yml b/docker-compose.yml index 9a07704..db42269 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,8 @@ version: "2.0" services: talk: container_name: talk + environment: + NGROK_AUTH_TOKEN: "" restart: always build: . ports: diff --git a/icons/apple-touch-icon.png b/icons/apple-touch-icon.png index 54c3668..eecd5e4 100644 Binary files a/icons/apple-touch-icon.png and b/icons/apple-touch-icon.png differ diff --git a/icons/favicon.ico b/icons/favicon.ico index 1c11130..4381828 100644 Binary files a/icons/favicon.ico and b/icons/favicon.ico differ diff --git a/icons/favicon.svg b/icons/favicon.svg index 8e341e1..a383b74 100644 --- a/icons/favicon.svg +++ b/icons/favicon.svg @@ -1,6 +1,15 @@ - - - + + + + + + + + + + + + diff --git a/icons/icon.png b/icons/icon.png index 7175b83..30ca7dd 100644 Binary files a/icons/icon.png and b/icons/icon.png differ diff --git a/icons/mask-icon.svg b/icons/mask-icon.svg index eeda0a5..4c630e9 100644 --- a/icons/mask-icon.svg +++ b/icons/mask-icon.svg @@ -5,20 +5,20 @@ width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000" preserveAspectRatio="xMidYMid meet"> -Created by potrace 1.11, written by Peter Selinger 2001-2013 +Created by potrace 1.14, written by Peter Selinger 2001-2017 - - + + diff --git a/package-lock.json b/package-lock.json index 2a588e8..d7c655d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,536 +1,1005 @@ { "name": "talk", - "version": "2.0.4", - "lockfileVersion": 1, + "version": "4.0.0", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@types/component-emitter": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz", - "integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg==" - }, - "@types/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg==" - }, - "@types/cors": { - "version": "2.8.10", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", - "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" - }, - "@types/node": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz", - "integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==" - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "array-flatten": { + "packages": { + "": { + "name": "talk", + "version": "4.0.0", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "express": "^4.18.2", + "socket.io": "^4.5.3", + "vue": "^3.2.41" + } + }, + "node_modules/@babel/parser": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.3.tgz", + "integrity": "sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==" + }, + "node_modules/@vue/compiler-core": { + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz", + "integrity": "sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/shared": "3.2.45", + "estree-walker": "^2.0.2", + "source-map": "^0.6.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz", + "integrity": "sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==", + "dependencies": { + "@vue/compiler-core": "3.2.45", + "@vue/shared": "3.2.45" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz", + "integrity": "sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.45", + "@vue/compiler-dom": "3.2.45", + "@vue/compiler-ssr": "3.2.45", + "@vue/reactivity-transform": "3.2.45", + "@vue/shared": "3.2.45", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7", + "postcss": "^8.1.10", + "source-map": "^0.6.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz", + "integrity": "sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==", + "dependencies": { + "@vue/compiler-dom": "3.2.45", + "@vue/shared": "3.2.45" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz", + "integrity": "sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==", + "dependencies": { + "@vue/shared": "3.2.45" + } + }, + "node_modules/@vue/reactivity-transform": { + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz", + "integrity": "sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.45", + "@vue/shared": "3.2.45", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz", + "integrity": "sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==", + "dependencies": { + "@vue/reactivity": "3.2.45", + "@vue/shared": "3.2.45" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz", + "integrity": "sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==", + "dependencies": { + "@vue/runtime-core": "3.2.45", + "@vue/shared": "3.2.45", + "csstype": "^2.6.8" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz", + "integrity": "sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==", + "dependencies": { + "@vue/compiler-ssr": "3.2.45", + "@vue/shared": "3.2.45" + }, + "peerDependencies": { + "vue": "3.2.45" + } + }, + "node_modules/@vue/shared": { + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz", + "integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, - "base64-arraybuffer": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", - "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" - }, - "base64id": { + "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "requires": { - "bytes": "3.1.0", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "requires": { - "safe-buffer": "5.1.2" + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" } }, - "content-type": { + "node_modules/content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } }, - "cookie-signature": { + "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, - "cors": { + "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { + "dependencies": { "object-assign": "^4", "vary": "^1" + }, + "engines": { + "node": ">= 0.10" } }, - "debug": { + "node_modules/csstype": { + "version": "2.6.21", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", + "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + }, + "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { + "dependencies": { "ms": "2.0.0" } }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, - "ee-first": { + "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, - "encodeurl": { + "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } }, - "engine.io": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-5.0.0.tgz", - "integrity": "sha512-BATIdDV3H1SrE9/u2BAotvsmjJg0t1P4+vGedImSs1lkFAtQdvk4Ev1y4LDiPF7BPWgXWEG+NDY+nLvW3UrMWw==", - "requires": { + "node_modules/engine.io": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz", + "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", "cookie": "~0.4.1", "cors": "~2.8.5", "debug": "~4.3.1", - "engine.io-parser": "~4.0.0", - "ws": "~7.4.2" + "engine.io-parser": "~5.0.3", + "ws": "~8.11.0" }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.7.tgz", + "integrity": "sha512-P+jDFbvK6lE3n1OL+q9KuzdOFWkkZ/cMV9gol/SbVfpyqfvrfrFTOFJ6fQm2VC3PZHlU3QPhVwmbsCnauHF2MQ==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { - "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "engine.io-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.2.tgz", - "integrity": "sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg==", - "requires": { - "base64-arraybuffer": "0.1.4" - } + "node_modules/engine.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "escape-html": { + "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" }, - "etag": { + "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "requires": { - "accepts": "~1.3.7", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" } }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } }, - "fresh": { + "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" } }, - "iconv-lite": { + "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { + "dependencies": { "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "ipaddr.js": { + "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } }, - "media-typer": { + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } }, - "merge-descriptors": { + "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, - "methods": { + "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } }, - "mime": { + "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } }, - "mime-db": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", - "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } }, - "mime-types": { - "version": "2.1.26", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", - "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", - "requires": { - "mime-db": "1.43.0" + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" } }, - "ms": { + "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } }, - "object-assign": { + "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" } }, - "parseurl": { + "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } }, - "path-to-regexp": { + "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, - "proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", - "requires": { - "forwarded": "~0.1.2", + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/postcss": { + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" } }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "range-parser": { + "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "safer-buffer": { + "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "requires": { + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "2.0.0", "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", + "ms": "2.1.3", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, - "dependencies": { - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } + "engines": { + "node": ">= 0.8.0" } }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "requires": { + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "socket.io": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.0.1.tgz", - "integrity": "sha512-g8eZB9lV0f4X4gndG0k7YZAywOg1VxYgCUspS4V+sDqsgI/duqd0AW84pKkbGj/wQwxrqrEq+VZrspRfTbHTAQ==", - "requires": { - "@types/cookie": "^0.4.0", - "@types/cors": "^2.8.8", - "@types/node": ">=10.0.0", + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/socket.io": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.1.tgz", + "integrity": "sha512-KMcaAi4l/8+xEjkRICl6ak8ySoxsYG+gG6/XfRCPJPQ/haCRIJBTL4wIl8YCsmtaBovcAXGLOShyVWQ/FG8GZA==", + "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", - "debug": "~4.3.1", - "engine.io": "~5.0.0", - "socket.io-adapter": "~2.2.0", - "socket.io-parser": "~4.0.3" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } + "debug": "~4.3.2", + "engine.io": "~6.4.1", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.1" + }, + "engines": { + "node": ">=10.0.0" } }, - "socket.io-adapter": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.2.0.tgz", - "integrity": "sha512-rG49L+FwaVEwuAdeBRq49M97YI3ElVabJPzvHT9S6a2CWhDKnjSFasvwAwSYPRhQzfn4NtDIbCaGYgOCOU/rlg==" + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dependencies": { + "ws": "~8.11.0" + } }, - "socket.io-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", - "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", - "requires": { - "@types/component-emitter": "^1.2.10", - "component-emitter": "~1.3.0", + "node_modules/socket.io-parser": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.3.tgz", + "integrity": "sha512-JMafRntWVO2DCJimKsRTh/wnqVvO4hrfwOqtO7f+uzwsQMuxO6VwImtYxaQ+ieoyshWOTJyV0fA21lccEXRPpQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "node_modules/socket.io-parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } }, - "type-is": { + "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { + "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" } }, - "unpipe": { + "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } }, - "utils-merge": { + "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } }, - "vary": { + "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } }, - "vue": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.12.tgz", - "integrity": "sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==" + "node_modules/vue": { + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.45.tgz", + "integrity": "sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==", + "dependencies": { + "@vue/compiler-dom": "3.2.45", + "@vue/compiler-sfc": "3.2.45", + "@vue/runtime-dom": "3.2.45", + "@vue/server-renderer": "3.2.45", + "@vue/shared": "3.2.45" + } }, - "ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index 57b5645..81d5e7c 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,12 @@ { "name": "talk", - "version": "2.0.4", - "description": "A free video call app for the web.", - "main": "server.js", + "version": "4.0.0", + "description": "A free, peer-to-peer, encrypted, open-source video calling for the web.", + "main": "start.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node start.js", + "postinstall": "node postinstall.js" }, "repository": { "type": "git", @@ -22,8 +24,8 @@ }, "homepage": "https://github.com/vasanthv/talk#readme", "dependencies": { - "express": "^4.17.1", - "socket.io": "^4.0.1", - "vue": "^2.6.12" + "express": "^4.18.2", + "socket.io": "^4.5.3", + "vue": "^3.2.41" } } diff --git a/postinstall.js b/postinstall.js new file mode 100644 index 0000000..e265b17 --- /dev/null +++ b/postinstall.js @@ -0,0 +1,21 @@ +"use strict"; + +const fs = require("fs"); +const path = require("path"); +if (process.env.NODE_ENV === "production" && process.env.ANALYTICS_SCRIPT) { + console.log("Inserting Analytics script tag"); + + const scriptTag = ``; + + const indexFileContents = fs.readFileSync(path.join(__dirname, "www/index.html")).toString(); + const newIndexFileContents = indexFileContents.replace("", scriptTag); + fs.writeFileSync(path.join(__dirname, "www/index.html"), newIndexFileContents); + + const appFileContents = fs.readFileSync(path.join(__dirname, "www/app.html")).toString(); + const newAppFileContents = appFileContents.replace("", scriptTag); + fs.writeFileSync(path.join(__dirname, "www/app.html"), newAppFileContents); + + const legalFileContents = fs.readFileSync(path.join(__dirname, "www/legal.html")).toString(); + const newLegalFileContents = legalFileContents.replace("", scriptTag); + fs.writeFileSync(path.join(__dirname, "www/legal.html"), newLegalFileContents); +} diff --git a/server.js b/server/signalling-server.js similarity index 55% rename from server.js rename to server/signalling-server.js index 9fe4b2f..10fe41f 100755 --- a/server.js +++ b/server/signalling-server.js @@ -1,28 +1,16 @@ -const express = require("express"); -const path = require("path"); -const http = require("http"); -const app = express(); -const server = http.createServer(app); -const io = require("socket.io")(server); - -// Server all the static files from www folder -app.use(express.static(path.join(__dirname, "www"))); -app.use(express.static(path.join(__dirname, "icons"))); -app.use(express.static(path.join(__dirname, "node_modules/vue/dist/"))); - -// Get PORT from env variable else assign 3000 for development -const PORT = process.env.PORT || 3000; -server.listen(PORT, null, () => console.log("Listening on port " + PORT)); - -app.get("/legal", (req, res) => res.sendFile(path.join(__dirname, "www/legal.html"))); - -// All URL patterns should served with the same file. -app.get(["/", "/:room"], (req, res) => res.sendFile(path.join(__dirname, "www/index.html"))); +/* +Note: This socket connection is used a signalling server as WebRTC does not support discovery of other peers. +User's audio, video & chat messages does not use this socket. +*/ +const util = require("util"); const channels = {}; const sockets = {}; +const peers = {}; + +const options = { depth: null, colors: true }; -io.sockets.on("connection", (socket) => { +const signallingServer = (socket) => { const socketHostName = socket.handshake.headers.host.split(":")[0]; socket.channels = {}; @@ -48,15 +36,41 @@ io.sockets.on("connection", (socket) => { channels[channel] = {}; } + if (!(channel in peers)) { + peers[channel] = {}; + } + + peers[channel][socket.id] = { + userData: config.userData, + }; + + console.log("[" + socket.id + "] join - connected peers grouped by channel", util.inspect(peers, options)); + for (const id in channels[channel]) { - channels[channel][id].emit("addPeer", { peer_id: socket.id, should_create_offer: false }); - socket.emit("addPeer", { peer_id: id, should_create_offer: true }); + channels[channel][id].emit("addPeer", { + peer_id: socket.id, + should_create_offer: false, + channel: peers[channel], + }); + socket.emit("addPeer", { peer_id: id, should_create_offer: true, channel: peers[channel] }); } channels[channel][socket.id] = socket; socket.channels[channel] = channel; }); + socket.on("updateUserData", async (config) => { + const channel = socketHostName + config.channel; + const key = config.key; + const value = config.value; + for (let id in peers[channel]) { + if (id == socket.id) { + peers[channel][id]["userData"][key] = value; + } + } + console.log("[" + socket.id + "] updateUserData", util.inspect(peers[channel][socket.id], options)); + }); + const part = (channel) => { // Socket not in channel if (!(channel in socket.channels)) return; @@ -64,6 +78,13 @@ io.sockets.on("connection", (socket) => { delete socket.channels[channel]; delete channels[channel][socket.id]; + delete peers[channel][socket.id]; + if (Object.keys(peers[channel]).length == 0) { + // last peer disconnected from the channel + delete peers[channel]; + } + console.log("[" + socket.id + "] part - connected peers grouped by channel", util.inspect(peers, options)); + for (const id in channels[channel]) { channels[channel][id].emit("removePeer", { peer_id: socket.id }); socket.emit("removePeer", { peer_id: id }); @@ -73,7 +94,6 @@ io.sockets.on("connection", (socket) => { socket.on("relayICECandidate", (config) => { let peer_id = config.peer_id; let ice_candidate = config.ice_candidate; - console.log("[" + socket.id + "] relay ICE-candidate to [" + peer_id + "] ", ice_candidate); if (peer_id in sockets) { sockets[peer_id].emit("iceCandidate", { peer_id: socket.id, ice_candidate: ice_candidate }); @@ -83,7 +103,6 @@ io.sockets.on("connection", (socket) => { socket.on("relaySessionDescription", (config) => { let peer_id = config.peer_id; let session_description = config.session_description; - console.log("[" + socket.id + "] relay SessionDescription to [" + peer_id + "] ", session_description); if (peer_id in sockets) { sockets[peer_id].emit("sessionDescription", { @@ -92,4 +111,6 @@ io.sockets.on("connection", (socket) => { }); } }); -}); +}; + +module.exports = signallingServer; diff --git a/start.js b/start.js new file mode 100755 index 0000000..3977627 --- /dev/null +++ b/start.js @@ -0,0 +1,35 @@ +const express = require("express"); +const path = require("path"); +const http = require("http"); +const app = express(); +const server = http.createServer(app); +const io = require("socket.io")(server, { + cors: { origin: process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(",") : "*" }, +}); + +const signallingServer = require("./server/signalling-server.js"); + +// Get PORT from env variable else assign 3000 for development +const PORT = process.env.PORT || 3000; + +// Server all the static files from www folder +app.use(express.static(path.join(__dirname, "www"))); +app.use(express.static(path.join(__dirname, "icons"))); +app.use(express.static(path.join(__dirname, "assets"))); +app.use(express.static(path.join(__dirname, "node_modules/vue/dist/"))); + +server.listen(PORT, null, () => { + console.log("Talk server started"); + console.log({ port: PORT, node_version: process.versions.node }); +}); + +// serve the landing page +app.get("/", (req, res) => res.sendFile(path.join(__dirname, "www/index.html"))); + +// serve the terms / legal page +app.get("/legal", (req, res) => res.sendFile(path.join(__dirname, "www/legal.html"))); + +// All other URL patterns will serve the app. +app.get("/:room", (req, res) => res.sendFile(path.join(__dirname, "www/app.html"))); + +io.sockets.on("connection", signallingServer); diff --git a/www/app.css b/www/app.css new file mode 100755 index 0000000..0fdc917 --- /dev/null +++ b/www/app.css @@ -0,0 +1,441 @@ +@import "icomoon/style.css"; + +:root { + --body-bg: #1e1f23; + --blanket-color: rgb(30, 31, 35, 0.9); + --intro-bg: #ffffff; + --intro-cl: #000000; + --chat-wrap-bg: #ffffff; + --chat-wrap-ch-bg: linear-gradient(white 30%, rgba(190, 179, 179, 0)), + linear-gradient(rgba(255, 255, 255, 0), white 70%) 0 100%, + radial-gradient(50% 0, farthest-side, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)), + radial-gradient(50% 100%, farthest-side, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)) 0 100%; + --chat-wrap-ch-bg: linear-gradient(white 30%, rgba(255, 255, 255, 0)), + linear-gradient(rgba(255, 255, 255, 0), white 70%) 0 100%, + radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)), + radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)) 0 100%; + --chat-wrap-ch-bgc: white; + --chat-wrap-ch-cl: #000000; + --chat-wrap-cb-bg: #f6f6f6; + --chat-wrap-cb-cl: #000000; + --settings-bg: #ffffff; + --settings-cl: #000000; + --settings-link-h-bg: #f6f6f6; + --settings-link-h-cl: #000000; + --actions-bg: rgba(255, 255, 255, 0.9); + --actions-btn-cl: #000000; + --actions-btn-h-bg: rgba(255, 255, 255, 1); + --actions-btn-h-cl: #000000; + --actions-btn-a-bg: #fafafa; + --vh: 1vh; +} + +* { + outline: none; +} +html, +body { + margin: 0px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", + sans-serif; + line-height: 1.6; +} +input { + display: block; + box-sizing: border-box; + border: 1px solid #efefef; + border-radius: 0.5rem; + padding: 0.6rem; + font-size: 1rem; +} +.light { + color: #878787; +} +.red { + color: #c0392b; +} +.bold { + font-weight: bold; +} +.italic { + font-style: italic; +} +#blanket { + position: absolute; + z-index: -1; + min-height: 100vh; + /* mobile viewport bug fix */ + min-height: -webkit-fill-available; +} +#videos { + display: flex; + justify-content: center; + flex-wrap: wrap; +} +#videos .video { + flex-shrink: 0; + width: 400px; + height: 300px; + overflow: hidden; + position: relative; + box-sizing: border-box; + padding: 0.5rem; +} +#videos .video video { + width: 100%; + height: 100%; + display: block; + margin: auto; + box-sizing: border-box; + object-fit: cover; + border-radius: 0.5rem; +} +#videos .video video.mirror { + transform: rotateY(180deg); + -webkit-transform: rotateY(180deg); + -moz-transform: rotateY(180deg); +} +#videos .video:fullscreen video { + background: #000; + object-fit: contain; + border: none; +} +#videos .video button { + position: absolute; + bottom: 1rem; + right: 0.5rem; + z-index: 10; + font-size: 2rem; + color: white; + background: none; + border: none; + cursor: pointer; + text-shadow: 2px 2px 5px #989898; + padding: 0.1rem 0.4rem; +} +#videos .video:fullscreen button { + display: none; +} +#videos.mt8 .video { + width: 200px; + height: 150px; +} + +.videoAvatarImg { + z-index: 1; + visibility: hidden; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.videoPeerName { + z-index: 2; + position: absolute; + padding: 0rem 0.75rem 0rem 0rem; + bottom: 1rem; + left: 3rem; + font-weight: bold; + font-size: 0.7rem; + color: #ffffff; + background-color: rgba(0, 0, 0, 0.7); + border: none; + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; + height: 2rem; + line-height: 2rem; + box-sizing: border-box; +} + +.audioEnabled.icon-mic-off, +.audioEnabled.icon-mic { + text-align: center; + z-index: 3; + position: absolute; + padding: 0rem 0.25rem; + bottom: 1rem; + left: 1rem; + font-weight: bold; + font-size: 1rem; + color: #ffffff; + background-color: rgba(0, 0, 0, 0.7); + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + border: none; + height: 2rem; + width: 2rem; + line-height: 2rem; + box-sizing: border-box; +} + +#app > #appWrap { + display: none; +} +#intro { + position: fixed; + top: 6rem; + left: 0px; + right: 0px; + z-index: 100; + width: 100%; + max-width: 32rem; + margin: auto; + padding: 1rem; + box-sizing: border-box; + border-radius: 1rem; + box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.16), 0px 1px 4px rgba(0, 0, 0, 0.16); +} +#intro h3 { + margin: 0px; +} +#intro label { + font-weight: bold; +} +#intro .footer { + display: flex; + justify-content: space-between; +} +#intro .footer button { + background: #6549d5; + color: #fff; + font-size: 1rem; + border: none; + border-radius: 0.25rem; + padding: 0.5rem 1rem; + cursor: pointer; +} + +#chatWrap { + background: var(--chat-wrap-bg); + position: fixed; + bottom: 6rem; + left: 0px; + right: 0px; + z-index: 100; + width: 20.8rem; + margin: auto; + padding: 1rem; + box-sizing: border-box; + border-radius: 1rem; + box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.16), 0px 1px 4px rgba(0, 0, 0, 0.16); +} +#chatWrap #chats { + overflow-y: auto; + overflow: auto; + max-height: 240px; + margin: auto; + color: var(--chat-wrap-ch-cl); + background: var(--chat-wrap-ch-bg); + background: var(--chat-wrap-ch-bg); + background-repeat: no-repeat; + background-color: var(--chat-wrap-ch-bgc); + background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px; + background-attachment: local, local, scroll, scroll; +} +#chatWrap .chat { + margin: 0.5rem 0rem; +} +#chatWrap .chat .name { + font-weight: bold; +} +#chatWrap .chat .message { +} +#chatWrap .chat .date { + font-size: small; +} +#chatWrap #composeBox { + position: relative; + background: var(--chat-wrap-cb-bg); + color: var(--chat-wrap-cb-cl); + border-radius: 1rem; + padding: 0.7rem 1rem; + margin-top: 0.5rem; + max-height: 4.2rem; + overflow-y: auto; +} +#chatWrap #composeBox #placeholder { + position: absolute; + z-index: 5; + opacity: 0.5; +} +#chatWrap #composeBox #compose { + position: relative; + z-index: 10; +} +#chatWrap #noChat { + padding: 1rem; + text-align: center; +} + +#settings { + background: var(--settings-bg); + color: var(--settings-cl); + box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.16), 0px 1px 4px rgba(0, 0, 0, 0.16); + position: fixed; + bottom: 5rem; + left: 0px; + right: 0px; + z-index: 100; + width: 20.8rem; + margin: auto; + box-sizing: border-box; + border-radius: 1rem; + max-height: 26rem; + overflow-y: auto; +} +#settings .label { + padding: 0.5rem 1rem; + font-weight: bold; +} +#settings .separator { + margin: 0px; + border-top: 1px solid var(--actions-btn-a-bg); +} +#settings .link { + padding: 0.5rem 1rem; + white-space: nowrap; + width: 100%; + box-sizing: border-box; + overflow: hidden; + text-overflow: ellipsis; + cursor: pointer; +} +#settings .link.indent { + padding: 0.5rem 1rem 0.5rem 2rem; +} +#settings .link.active:before { + content: "✔️"; + margin-right: 0.5rem; +} +#settings .link:hover { + background: var(--settings-link-h-bg); + color: var(--settings-link-h-cl); +} +#settings #name { + display: flex; + align-items: center; +} +#settings input { + background: none; + border: none; + flex: 1; +} +#actionsWrap { + position: fixed; + bottom: 1rem; + left: 0px; + right: 0px; + z-index: 100; + display: inline-flex; + transition: all 0.25s ease-out; + opacity: 1; + transform: translateY(0rem); +} +#actionsWrap.hidden { + opacity: 0; + transform: translateY(1rem); + z-index: -1; +} + +#actions { + z-index: 100; + background: var(--actions-bg); + box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.16), 0px 1px 4px rgba(0, 0, 0, 0.16); + margin: auto; + box-sizing: border-box; + border-radius: 1rem; + transition: opacity 250ms; +} +#actions button { + flex: 1; + background: none; + border: none; + font-size: 1.25rem; + padding: 1rem; + cursor: pointer; + margin: auto; + color: var(--actions-btn-cl); +} +#actions button:hover { + background: var(--actions-btn-h-bg); + color: var(--actions-btn-h-cl); + border-radius: 1rem; +} +#actions button.active { + background: var(--actions-btn-a-bg); + border-radius: 1rem; +} +#actions button.icon-exit, +#actions button.icon-mic-off, +#actions button.icon-video-off { + color: #e74c3c !important; +} + +#callFeedbackWrap { + position: fixed; + top: 0px; + bottom: 0px; + left: 0px; + right: 0px; + background: var(--blanket-color); + z-index: 110; +} +#callFeedback { + position: absolute; + padding: 1rem; + box-sizing: border-box; + width: 100%; + max-width: 400px; + height: 320px; + top: 0px; + bottom: 0px; + left: 0px; + right: 0px; + margin: auto; + background: var(--settings-bg); + border-radius: 1rem; +} +#feedbackWrap .thankYou { + display: none; +} +#feedbackWrap:focus-within .question { + display: none; +} +#feedbackWrap:focus-within .thankYou { + display: block; +} +#feedbackButtons { + display: flex; + justify-content: space-between; + margin: 1rem auto; +} +#feedbackButtons button { + cursor: pointer; + border: none; + background: #7f8c8d; + border: 5px solid #7f8c8d; + width: 30%; + font-size: 2rem; + padding: 0.5rem 0px; + border-radius: 1rem; +} +#feedbackButtons button[data-cabin-event="call-quality-nah"] { + background: #c0392b; + border-color: #c0392b; +} +#feedbackButtons button[data-cabin-event="call-quality-yay"] { + background: #27ae60; + border-color: #27ae60; +} +#feedbackButtons button:active, +#feedbackButtons button:focus { + border-color: #000; +} + +@media only screen and (max-width: 800px) { + #videos .video { + width: 50vw; + height: 33.3vh; + } +} diff --git a/www/app.html b/www/app.html new file mode 100755 index 0000000..b3dd194 --- /dev/null +++ b/www/app.html @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + Talk - Free video calling for the web + + + + +
+
+
+
+
+

You are about to enter a video call.

+

Talk is a free, peer-to-peer, encrypted, open-source video calling for the web.

+

+ + +

+
+ + +
+ +
+
+
Your call has been disconnected. You can now close this window.
+
+ +
+
How was the quality of call?
+
Thank you for your feedback
+
+ + + +
+
+
+
+ +
+
+
+ {{chat.name}} + · {{formatDate(chat.date)}} +
+
+
No chat messages.
+
+
+
Type message...
+
+
+ Press enter to submit +
+ +
+
+ Name: + +
+
+ +
Camera 📹
+
+
+ {{videoDevice.label}} +
+
+
+ +
Microphone 🎙️
+
+
+ {{audioDevice.label}} +
+
+
+ + +
+ +
+ +
+
+ + + + + + +
+
+
+
+ + diff --git a/www/app.js b/www/app.js index 33d0051..ec66da1 100644 --- a/www/app.js +++ b/www/app.js @@ -1,27 +1,47 @@ -/* globals attachMediaStream, Vue, peers, localMediaStream, dataChannels */ -const App = new Vue({ - el: "#app", - data: { - roomLink: "", - copyText: "", - videoDevices: [], - audioDevices: [], - audioEnabled: true, - videoEnabled: true, - screenshareEnabled: false, - showIntro: true, - showChat: false, - showSettings: false, - hideToolbar: false, - selectedAudioDeviceId: "", - selectedVideoDeviceId: "", - name: window.localStorage.name || "", - typing: "", - chats: [], +/* globals attachMediaStream, Vue, peers, localMediaStream, dataChannels, signalingSocket */ + +"use strict"; + +const App = Vue.createApp({ + data() { + return { + peerId: "", + roomId: "", + roomLink: "", + copyText: "", + userAgent: "", + isMobileDevice: false, + isTablet: false, + isIpad: false, + isDesktop: false, + videoDevices: [], + audioDevices: [], + audioEnabled: true, + videoEnabled: true, + screenShareEnabled: false, + showChat: false, + showSettings: false, + hideToolbar: true, + selectedAudioDeviceId: "", + selectedVideoDeviceId: "", + name: window.localStorage.name, + nameError: false, + typing: "", + chats: [], + callInitiated: false, + callEnded: false, + }; }, - computed: {}, methods: { - copyURL: function() { + initiateCall() { + if (this.name) { + this.callInitiated = true; + window.initiateCall(); + } else { + this.nameError = true; + } + }, + copyURL() { navigator.clipboard.writeText(this.roomLink).then( () => { this.copyText = "Copied 👍"; @@ -30,26 +50,32 @@ const App = new Vue({ (err) => console.error(err) ); }, - audioToggle: function(e) { + audioToggle(e) { e.stopPropagation(); localMediaStream.getAudioTracks()[0].enabled = !localMediaStream.getAudioTracks()[0].enabled; this.audioEnabled = !this.audioEnabled; + this.updateUserData("audioEnabled", this.audioEnabled); }, - videoToggle: function(e) { + videoToggle(e) { e.stopPropagation(); localMediaStream.getVideoTracks()[0].enabled = !localMediaStream.getVideoTracks()[0].enabled; this.videoEnabled = !this.videoEnabled; + this.updateUserData("videoEnabled", this.videoEnabled); }, - toggleSelfVideoMirror: function() { + toggleSelfVideoMirror() { document.querySelector("#videos .video #selfVideo").classList.toggle("mirror"); }, - nameToLocalStorage: function() { + updateName() { window.localStorage.name = this.name; }, - screenShareToggle: function(e) { + updateNameAndPublish() { + window.localStorage.name = this.name; + this.updateUserData("peerName", this.name); + }, + screenShareToggle(e) { e.stopPropagation(); let screenMediaPromise; - if (!App.screenshareEnabled) { + if (!App.screenShareEnabled) { if (navigator.getDisplayMedia) { screenMediaPromise = navigator.getDisplayMedia({ video: true }); } else if (navigator.mediaDevices.getDisplayMedia) { @@ -61,10 +87,14 @@ const App = new Vue({ } } else { screenMediaPromise = navigator.mediaDevices.getUserMedia({ video: true }); + document.getElementById(this.peerId + "_videoEnabled").style.visibility = "hidden"; } screenMediaPromise .then((screenStream) => { - App.screenshareEnabled = !App.screenshareEnabled; + App.screenShareEnabled = !App.screenShareEnabled; + + this.videoEnabled = true; + this.updateUserData("videoEnabled", this.videoEnabled); for (let peer_id in peers) { const sender = peers[peer_id].getSenders().find((s) => (s.track ? s.track.kind === "video" : false)); @@ -76,20 +106,47 @@ const App = new Vue({ attachMediaStream(document.getElementById("selfVideo"), newStream); this.toggleSelfVideoMirror(); - screenStream.getVideoTracks()[0].onended = function() { - if (App.screenshareEnabled) App.screenShareToggle(); + screenStream.getVideoTracks()[0].onended = function () { + if (App.screenShareEnabled) App.screenShareToggle(); }; + try { + if (cabin) { + cabin.event("screen-share-"+App.screenShareEnabled); + } + } catch (e) {} }) .catch((e) => { alert("Unable to share screen. Please use a supported browser."); console.error(e); }); }, - changeCamera: function(deviceId) { + updateUserData(key, value) { + this.sendDataMessage(key, value); + + switch (key) { + case "audioEnabled": + document.getElementById(this.peerId + "_audioEnabled").className = + "audioEnabled icon-mic" + (value ? "" : "-off"); + break; + case "videoEnabled": + document.getElementById(this.peerId + "_videoEnabled").style.visibility = value ? "hidden" : "visible"; + break; + case "peerName": + document.getElementById(this.peerId + "_videoPeerName").innerHTML = value + " (you)"; + break; + default: + break; + } + }, + changeCamera(deviceId) { navigator.mediaDevices .getUserMedia({ video: { deviceId: deviceId } }) .then((camStream) => { console.log(camStream); + + this.videoEnabled = true; + this.updateUserData("videoEnabled", this.videoEnabled); + for (let peer_id in peers) { const sender = peers[peer_id].getSenders().find((s) => (s.track ? s.track.kind === "video" : false)); sender.replaceTrack(camStream.getVideoTracks()[0]); @@ -106,10 +163,13 @@ const App = new Vue({ alert("Error while swaping camera"); }); }, - changeMicrophone: function(deviceId) { + changeMicrophone(deviceId) { navigator.mediaDevices .getUserMedia({ audio: { deviceId: deviceId } }) .then((micStream) => { + this.audioEnabled = true; + this.updateUserData("audioEnabled", this.audioEnabled); + for (let peer_id in peers) { const sender = peers[peer_id].getSenders().find((s) => (s.track ? s.track.kind === "audio" : false)); sender.replaceTrack(micStream.getAudioTracks()[0]); @@ -126,62 +186,94 @@ const App = new Vue({ alert("Error while swaping microphone"); }); }, - sanitizeString: function(str) { + sanitizeString(str) { const tagsToReplace = { "&": "&", "<": "<", ">": ">" }; const replaceTag = (tag) => tagsToReplace[tag] || tag; const safe_tags_replace = (str) => str.replace(/[&<>]/g, replaceTag); return safe_tags_replace(str); }, - linkify: function(str) { + linkify(str) { return this.sanitizeString(str).replace(/(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-?=%]+/gi, (match) => { - let displayURL = match - .trim() - .replace("https://", "") - .replace("https://", ""); + let displayURL = match.trim().replace("https://", "").replace("https://", ""); displayURL = displayURL.length > 25 ? displayURL.substr(0, 25) + "…" : displayURL; const url = !/^https?:\/\//i.test(match) ? "http://" + match : match; return `${displayURL}`; }); }, - edit: function(e) { + edit(e) { this.typing = e.srcElement.textContent; }, - paste: function(e) { + paste(e) { e.preventDefault(); const clipboardData = e.clipboardData || window.clipboardData; const pastedText = clipboardData.getData("Text"); document.execCommand("inserttext", false, pastedText.replace(/(\r\n\t|\n|\r\t)/gm, " ")); }, - sendChat: function(e) { + sendChat(e) { e.stopPropagation(); e.preventDefault(); - if (this.typing.length) { + + if (!this.typing.length) return; + + if (Object.keys(peers).length > 0) { const composeElement = document.getElementById("compose"); - const chatMessage = { - type: "chat", - name: this.name || "Unnamed", - message: this.typing, - date: new Date().toISOString(), - }; - this.chats.push(chatMessage); - Object.keys(dataChannels).map((peer_id) => dataChannels[peer_id].send(JSON.stringify(chatMessage))); + this.sendDataMessage("chat", this.typing); this.typing = ""; composeElement.textContent = ""; composeElement.blur; + } else { + alert("No peers in the room"); + } + }, + sendDataMessage(key, value) { + const dataMessage = { + type: key, + name: this.name, + id: this.peerId, + message: value, + date: new Date().toISOString(), + }; + + switch (key) { + case "chat": + this.chats.push(dataMessage); + this.$nextTick(this.scrollToBottom); + break; + default: + break; } + + Object.keys(dataChannels).map((peer_id) => dataChannels[peer_id].send(JSON.stringify(dataMessage))); }, - handleIncomingDataChannelMessage: function(chatMessage) { - switch (chatMessage.type) { + handleIncomingDataChannelMessage(dataMessage) { + switch (dataMessage.type) { case "chat": this.showChat = true; this.hideToolbar = false; - this.chats.push(chatMessage); + this.chats.push(dataMessage); + this.$nextTick(this.scrollToBottom); + break; + case "audioEnabled": + document.getElementById(dataMessage.id + "_audioEnabled").className = + "audioEnabled icon-mic" + (dataMessage.message ? "" : "-off"); + break; + case "videoEnabled": + document.getElementById(dataMessage.id + "_videoEnabled").style.visibility = dataMessage.message + ? "hidden" + : "visible"; + break; + case "peerName": + document.getElementById(dataMessage.id + "_videoPeerName").innerHTML = dataMessage.message; break; default: break; } }, - formatDate: function(dateString) { + scrollToBottom() { + const chatContainer = this.$refs.chatContainer; + chatContainer.scrollTop = chatContainer.scrollHeight; + }, + formatDate(dateString) { const date = new Date(dateString); const hours = date.getHours() > 12 ? date.getHours() - 12 : date.getHours(); return ( @@ -192,5 +284,22 @@ const App = new Vue({ (date.getHours() >= 12 ? "PM" : "AM") ); }, + setStyle(key, value) { + document.documentElement.style.setProperty(key, value); + }, + onCallFeedback(e) { + try { + if (cabin) { + cabin.event(e.target.getAttribute("data-cabin-event")); + } + } catch (e) {} + }, + exit() { + signalingSocket.close(); + for (let peer_id in peers) { + peers[peer_id].close(); + } + this.callEnded = true; + }, }, -}); +}).mount("#app"); diff --git a/www/home.css b/www/home.css new file mode 100755 index 0000000..055e3a1 --- /dev/null +++ b/www/home.css @@ -0,0 +1,89 @@ +body { + color: #212121; + margin: 0; + font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, + "Helvetica Neue", sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-size: 1.2rem; + line-height: 1.5; +} +a { + color: inherit; +} +a.button { + display: inline-block; + background: #212121; + color: #fff; + border: none; + border-radius: 0.2rem; + height: 3.2rem; + line-height: 3.2rem; + font-family: inherit; + font-size: 1.25rem; + font-weight: bold; + padding: 0px 1.5rem; + cursor: pointer; + text-decoration: none; +} +label { + font-weight: bold; +} +.wrap { + width: 100%; + max-width: 640px; + margin: auto; +} +.flex { + display: flex; +} +.row { + padding: 0px 1rem; + margin: 1.25rem auto; +} +.small { + font-size: 0.75em; +} +.title { + font-weight: bold; + font-size: 1.5rem; +} +.light { + color: #989898; +} +.spacer { + height: 5rem; +} +#logo { + width: 3rem; + margin-right: 0.5rem; +} +#roomurl { + display: flex; + align-items: center; + border: 0.2rem solid #212121; + color: #212121; + font-family: inherit; + font-size: 1.25rem; + width: 100%; + height: 3.2rem; + max-width: 320px; + padding: 0px 1rem; + border-radius: 0.2rem; + box-sizing: border-box; + line-height: 2.7rem; + margin-right: 0.5rem; +} +#roomurl > span { + color: #444; + font-weight: bold; +} +#roomurl input { + border: none; + background: none; + font: inherit; + outline: none; +} +#roomurl input::placeholder { + color: #888; +} diff --git a/www/home.js b/www/home.js new file mode 100644 index 0000000..6b3e8e4 --- /dev/null +++ b/www/home.js @@ -0,0 +1,16 @@ +/* globals Vue */ +Vue.createApp({ + data() { + return { + roomId: "", + }; + }, + methods: { + generateRandomRoomId() { + this.roomId = Math.random().toString(36).substr(2, 6); + }, + goToRoom() { + window.location = "/" + this.roomId; + }, + }, +}).mount("#app"); diff --git a/www/icomoon/Read Me.txt b/www/icomoon/Read Me.txt index e39b544..8491652 100644 --- a/www/icomoon/Read Me.txt +++ b/www/icomoon/Read Me.txt @@ -1,7 +1,7 @@ -Open *demo.html* to see a list of all the glyphs in your font along with their codes/ligatures. - -To use the generated font in desktop programs, you can install the TTF font. In order to copy the character associated with each icon, refer to the text box at the bottom right corner of each glyph in demo.html. The character inside this text box may be invisible; but it can still be copied. See this guide for more info: https://icomoon.io/#docs/local-fonts - -You won't need any of the files located under the *demo-files* directory when including the generated font in your own projects. - -You can import *selection.json* back to the IcoMoon app using the *Import Icons* button (or via Main Menu → Manage Projects) to retrieve your icon selection. +Open *demo.html* to see a list of all the glyphs in your font along with their codes/ligatures. + +To use the generated font in desktop programs, you can install the TTF font. In order to copy the character associated with each icon, refer to the text box at the bottom right corner of each glyph in demo.html. The character inside this text box may be invisible; but it can still be copied. See this guide for more info: https://icomoon.io/#docs/local-fonts + +You won't need any of the files located under the *demo-files* directory when including the generated font in your own projects. + +You can import *selection.json* back to the IcoMoon app using the *Import Icons* button (or via Main Menu → Manage Projects) to retrieve your icon selection. diff --git a/www/icomoon/demo.html b/www/icomoon/demo.html index 394f36a..5980eb2 100644 --- a/www/icomoon/demo.html +++ b/www/icomoon/demo.html @@ -9,7 +9,7 @@
-

Font Name: icomoon (Glyphs: 9)

+

Font Name: icomoon (Glyphs: 10)

Grid Size: 24

@@ -22,7 +22,7 @@

Grid Size: 24

-
+
liga:
@@ -36,7 +36,7 @@

Grid Size: 24

-
+
liga:
@@ -50,7 +50,7 @@

Grid Size: 24

-
+
liga:
@@ -64,7 +64,7 @@

Grid Size: 24

-
+
liga:
@@ -78,7 +78,7 @@

Grid Size: 24

-
+
liga:
@@ -92,7 +92,7 @@

Grid Size: 24

-
+
liga:
@@ -106,7 +106,7 @@

Grid Size: 24

-
+
liga:
@@ -120,7 +120,7 @@

Grid Size: 24

-
+
liga:
@@ -134,7 +134,21 @@

Grid Size: 24

-
+
+ liga: + +
+
+
+
+ + icon-exit +
+
+ + +
+
liga:
diff --git a/www/icomoon/fonts/icomoon.eot b/www/icomoon/fonts/icomoon.eot index fb6adb7..c37a1df 100644 Binary files a/www/icomoon/fonts/icomoon.eot and b/www/icomoon/fonts/icomoon.eot differ diff --git a/www/icomoon/fonts/icomoon.svg b/www/icomoon/fonts/icomoon.svg index 4112ad7..f01c4e4 100644 --- a/www/icomoon/fonts/icomoon.svg +++ b/www/icomoon/fonts/icomoon.svg @@ -16,4 +16,5 @@ + \ No newline at end of file diff --git a/www/icomoon/fonts/icomoon.ttf b/www/icomoon/fonts/icomoon.ttf index 38515cd..6fd50f5 100644 Binary files a/www/icomoon/fonts/icomoon.ttf and b/www/icomoon/fonts/icomoon.ttf differ diff --git a/www/icomoon/fonts/icomoon.woff b/www/icomoon/fonts/icomoon.woff index 24c9f3f..3c3210e 100644 Binary files a/www/icomoon/fonts/icomoon.woff and b/www/icomoon/fonts/icomoon.woff differ diff --git a/www/icomoon/selection.json b/www/icomoon/selection.json index ab09372..3d5ed9d 100644 --- a/www/icomoon/selection.json +++ b/www/icomoon/selection.json @@ -1 +1 @@ -{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M341.333 85.333h-128c-35.328 0-67.413 14.379-90.496 37.504s-37.504 55.168-37.504 90.496v128c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-128c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501h128c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667zM938.667 341.333v-128c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504h-128c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667h128c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165v128c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667zM682.667 938.667h128c35.328 0 67.413-14.379 90.496-37.504s37.504-55.168 37.504-90.496v-128c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v128c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501h-128c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM85.333 682.667v128c0 35.328 14.379 67.413 37.504 90.496s55.168 37.504 90.496 37.504h128c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-128c-11.776 0-22.4-4.736-30.165-12.501s-12.501-18.389-12.501-30.165v-128c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["maximize"],"grid":24},"attrs":[],"properties":{"id":150,"order":8,"prevSize":24,"code":59648,"name":"maximize"},"setIdx":0,"setId":3,"iconIdx":149},{"icon":{"paths":["M793.003 170.667l-225.835 225.835c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0l225.835-225.835v153.003c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-256c0-5.803-1.152-11.307-3.243-16.341s-5.163-9.728-9.216-13.781c-0.043-0.043-0.043-0.043-0.085-0.085-3.925-3.925-8.619-7.083-13.781-9.216-5.035-2.091-10.539-3.243-16.341-3.243h-256c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM230.997 853.333l225.835-225.835c16.683-16.683 16.683-43.691 0-60.331s-43.691-16.683-60.331 0l-225.835 225.835v-153.003c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v256c0 23.552 19.115 42.667 42.667 42.667h256c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["maximize-2"],"grid":24},"attrs":[],"properties":{"id":151,"order":9,"prevSize":24,"code":59649,"name":"maximize-2"},"setIdx":0,"setId":3,"iconIdx":150},{"icon":{"paths":["M938.667 640v-426.667c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504h-597.333c-35.328 0-67.413 14.379-90.496 37.504s-37.504 55.168-37.504 90.496v682.667c0 10.923 4.181 21.845 12.501 30.165 16.683 16.683 43.691 16.683 60.331 0l158.165-158.165h494.336c35.328 0 67.413-14.379 90.496-37.504s37.504-55.168 37.504-90.496zM853.333 640c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501h-512c-11.776 0-22.443 4.779-30.165 12.501l-97.835 97.835v-579.669c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501h597.333c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["message-square"],"grid":24},"attrs":[],"properties":{"id":155,"order":10,"prevSize":24,"code":59656,"name":"message-square"},"setIdx":0,"setId":3,"iconIdx":154},{"icon":{"paths":["M512 85.333c23.595 0 44.843 9.515 60.331 25.003s25.003 36.736 25.003 60.331v341.333c0 23.595-9.515 44.843-25.003 60.331s-36.736 25.003-60.331 25.003-44.843-9.515-60.331-25.003-25.003-36.736-25.003-60.331v-341.333c0-23.595 9.515-44.843 25.003-60.331s36.736-25.003 60.331-25.003zM512 0c-47.104 0-89.856 19.157-120.661 50.005s-50.005 73.557-50.005 120.661v341.333c0 47.104 19.157 89.856 50.005 120.661s73.557 50.005 120.661 50.005 89.856-19.157 120.661-50.005 50.005-73.557 50.005-120.661v-341.333c0-47.104-19.157-89.856-50.005-120.661s-73.557-50.005-120.661-50.005zM341.333 1024h341.333c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-128v-87.979c77.184-9.643 146.432-45.056 198.699-97.323 61.696-61.739 99.968-147.115 99.968-241.365v-85.333c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v85.333c0 70.699-28.587 134.656-74.965 181.035s-110.336 74.965-181.035 74.965-134.656-28.587-181.035-74.965-74.965-110.336-74.965-181.035v-85.333c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v85.333c0 94.251 38.272 179.627 99.968 241.365 52.267 52.267 121.472 87.68 198.699 97.323v87.979h-128c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["mic"],"grid":24},"attrs":[],"properties":{"id":156,"order":2,"prevSize":24,"code":59650,"name":"mic"},"setIdx":0,"setId":3,"iconIdx":155},{"icon":{"paths":["M534.016 594.347c-6.997 1.877-14.336 2.859-21.931 2.859-23.68-0.043-44.928-9.515-60.373-24.96-15.488-15.445-25.045-36.693-25.045-60.245v-25.003zM682.667 398.507v-227.84c0.043-47.061-19.072-89.813-49.877-120.704s-73.515-50.048-120.619-50.091c-43.264-0.043-82.901 16.085-113.024 42.752-27.136 24.021-46.592 56.619-54.357 93.739-4.821 23.083 9.984 45.653 33.067 50.475s45.653-9.984 50.475-33.067c3.925-18.773 13.739-35.2 27.349-47.275 14.933-13.227 34.389-21.205 55.808-21.291 24.363 0.128 45.483 9.643 60.885 25.045 15.488 15.531 25.003 36.779 24.96 60.416v227.84c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667zM768 426.667v85.333c0 16.043-1.493 31.573-3.968 44.587-4.352 23.168 10.88 45.483 34.048 49.835s45.483-10.88 49.835-34.048c3.499-18.517 5.419-39.339 5.419-60.373v-85.333c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667zM341.333 1024h341.333c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-128v-86.357c61.696-8.064 119.083-31.232 167.851-69.419l228.651 228.651c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-249.088-249.088c-1.92-3.371-4.309-6.528-7.211-9.344-2.688-2.645-5.632-4.821-8.747-6.613l-673.621-673.664c-16.683-16.683-43.691-16.683-60.331 0s-16.683 43.691 0 60.331l328.832 328.832v110.336c0.043 47.147 19.243 89.856 50.091 120.661s73.6 49.92 120.704 49.877c31.531-0.043 61.141-8.619 86.485-23.595l63.019 63.019c-40.917 29.568-88.661 45.568-137.045 47.915-4.011-1.237-8.235-1.877-12.587-1.877-4.395 0-8.576 0.64-12.587 1.877-60.459-2.944-119.979-27.179-166.613-72.832-49.195-48.171-74.795-111.275-76.715-175.189-0.085-4.779-0.085-9.557-0.085-9.557v-85.632c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v85.035c0 6.357 0.128 12.715 0.128 12.715 2.56 85.077 36.736 169.344 102.315 233.6 55.424 54.315 124.757 85.888 196.224 94.848v85.803h-128c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["mic-off"],"grid":24},"attrs":[],"properties":{"id":157,"order":3,"prevSize":24,"code":59651,"name":"mic-off"},"setIdx":0,"setId":3,"iconIdx":156},{"icon":{"paths":["M512 682.667h-341.333c-11.776 0-22.4-4.736-30.165-12.501s-12.501-18.389-12.501-30.165v-426.667c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501h682.667c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165v426.667c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501zM469.333 768v85.333h-128c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667h341.333c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-128v-85.333h298.667c35.328 0 67.413-14.379 90.496-37.504s37.504-55.168 37.504-90.496v-426.667c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504h-682.667c-35.328 0-67.413 14.379-90.496 37.504s-37.504 55.168-37.504 90.496v426.667c0 35.328 14.379 67.413 37.504 90.496s55.168 37.504 90.496 37.504z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["monitor"],"grid":24},"attrs":[],"properties":{"id":163,"order":7,"prevSize":24,"code":59652,"name":"monitor"},"setIdx":0,"setId":3,"iconIdx":162},{"icon":{"paths":["M597.333 512c0-23.552-9.6-44.928-25.003-60.331s-36.779-25.003-60.331-25.003-44.928 9.6-60.331 25.003-25.003 36.779-25.003 60.331 9.6 44.928 25.003 60.331 36.779 25.003 60.331 25.003 44.928-9.6 60.331-25.003 25.003-36.779 25.003-60.331zM896 512c0-23.552-9.6-44.928-25.003-60.331s-36.779-25.003-60.331-25.003-44.928 9.6-60.331 25.003-25.003 36.779-25.003 60.331 9.6 44.928 25.003 60.331 36.779 25.003 60.331 25.003 44.928-9.6 60.331-25.003 25.003-36.779 25.003-60.331zM298.667 512c0-23.552-9.6-44.928-25.003-60.331s-36.779-25.003-60.331-25.003-44.928 9.6-60.331 25.003-25.003 36.779-25.003 60.331 9.6 44.928 25.003 60.331 36.779 25.003 60.331 25.003 44.928-9.6 60.331-25.003 25.003-36.779 25.003-60.331z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["more-horizontal"],"grid":24},"attrs":[],"properties":{"id":165,"order":6,"prevSize":24,"code":59653,"name":"more-horizontal"},"setIdx":0,"setId":3,"iconIdx":164},{"icon":{"paths":["M938.667 381.568v260.864l-182.613-130.432zM128 170.667c-35.328 0-67.413 14.379-90.496 37.504s-37.504 55.168-37.504 90.496v426.667c0 35.328 14.379 67.413 37.504 90.496s55.168 37.504 90.496 37.504h469.333c35.328 0 67.413-14.379 90.496-37.504s37.504-55.168 37.504-90.496v-130.432l231.211 165.163c19.157 13.696 45.824 9.259 59.52-9.899 5.376-7.595 7.979-16.341 7.936-24.832v-426.667c0-23.552-19.115-42.667-42.667-42.667-9.301 0-17.92 2.987-24.789 7.936l-231.211 165.163v-130.432c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504zM128 256h469.333c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165v426.667c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501h-469.333c-11.776 0-22.4-4.736-30.165-12.501s-12.501-18.389-12.501-30.165v-426.667c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["video"],"grid":24},"attrs":[],"properties":{"id":263,"order":5,"prevSize":24,"code":59654,"name":"video"},"setIdx":0,"setId":3,"iconIdx":262},{"icon":{"paths":["M454.827 256h142.507c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165v142.507c0 11.776 4.779 22.443 12.501 30.165l42.667 42.667c14.976 14.976 38.315 16.512 55.168 4.395l188.331-136.192v343.125c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-426.667c0.043-8.576-2.603-17.408-8.107-25.003-13.824-19.072-40.491-23.381-59.563-9.557l-226.517 163.883-4.48-4.48v-124.843c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504h-142.507c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM195.669 256l444.331 444.331v25.003c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501h-469.333c-11.776 0-22.4-4.736-30.165-12.501s-12.501-18.389-12.501-30.165v-426.667c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501zM12.501 72.832l98.901 98.901c-28.715 3.712-54.485 16.981-73.899 36.437-23.125 23.083-37.504 55.168-37.504 90.496v426.667c0 35.328 14.379 67.413 37.504 90.496s55.168 37.504 90.496 37.504h469.333c35.328 0 67.413-14.379 90.496-37.504 11.477-11.477 20.821-25.173 27.307-40.363l236.032 236.032c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-938.667-938.667c-16.683-16.683-43.691-16.683-60.331 0s-16.683 43.691 0 60.331z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["video-off"],"grid":24},"attrs":[],"properties":{"id":264,"order":4,"prevSize":24,"code":59655,"name":"video-off"},"setIdx":0,"setId":3,"iconIdx":263}],"height":1024,"metadata":{"name":"icomoon"},"preferences":{"showGlyphs":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"icon-","metadata":{"fontFamily":"icomoon"},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"classSelector":".icon"},"historySize":50,"showCodes":true,"gridSize":16}} \ No newline at end of file +{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M341.333 85.333h-128c-35.328 0-67.413 14.379-90.496 37.504s-37.504 55.168-37.504 90.496v128c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-128c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501h128c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667zM938.667 341.333v-128c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504h-128c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667h128c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165v128c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667zM682.667 938.667h128c35.328 0 67.413-14.379 90.496-37.504s37.504-55.168 37.504-90.496v-128c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v128c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501h-128c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM85.333 682.667v128c0 35.328 14.379 67.413 37.504 90.496s55.168 37.504 90.496 37.504h128c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-128c-11.776 0-22.4-4.736-30.165-12.501s-12.501-18.389-12.501-30.165v-128c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["maximize"],"grid":24},"attrs":[],"properties":{"id":0,"order":27,"prevSize":24,"code":59648,"name":"maximize"},"setIdx":0,"setId":2,"iconIdx":0},{"icon":{"paths":["M793.003 170.667l-225.835 225.835c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0l225.835-225.835v153.003c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-256c0-5.803-1.152-11.307-3.243-16.341s-5.163-9.728-9.216-13.781c-0.043-0.043-0.043-0.043-0.085-0.085-3.925-3.925-8.619-7.083-13.781-9.216-5.035-2.091-10.539-3.243-16.341-3.243h-256c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM230.997 853.333l225.835-225.835c16.683-16.683 16.683-43.691 0-60.331s-43.691-16.683-60.331 0l-225.835 225.835v-153.003c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v256c0 23.552 19.115 42.667 42.667 42.667h256c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["maximize-2"],"grid":24},"attrs":[],"properties":{"id":1,"order":28,"prevSize":24,"code":59649,"name":"maximize-2"},"setIdx":0,"setId":2,"iconIdx":1},{"icon":{"paths":["M938.667 640v-426.667c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504h-597.333c-35.328 0-67.413 14.379-90.496 37.504s-37.504 55.168-37.504 90.496v682.667c0 10.923 4.181 21.845 12.501 30.165 16.683 16.683 43.691 16.683 60.331 0l158.165-158.165h494.336c35.328 0 67.413-14.379 90.496-37.504s37.504-55.168 37.504-90.496zM853.333 640c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501h-512c-11.776 0-22.443 4.779-30.165 12.501l-97.835 97.835v-579.669c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501h597.333c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["message-square"],"grid":24},"attrs":[],"properties":{"id":2,"order":29,"prevSize":24,"code":59656,"name":"message-square"},"setIdx":0,"setId":2,"iconIdx":2},{"icon":{"paths":["M512 85.333c23.595 0 44.843 9.515 60.331 25.003s25.003 36.736 25.003 60.331v341.333c0 23.595-9.515 44.843-25.003 60.331s-36.736 25.003-60.331 25.003-44.843-9.515-60.331-25.003-25.003-36.736-25.003-60.331v-341.333c0-23.595 9.515-44.843 25.003-60.331s36.736-25.003 60.331-25.003zM512 0c-47.104 0-89.856 19.157-120.661 50.005s-50.005 73.557-50.005 120.661v341.333c0 47.104 19.157 89.856 50.005 120.661s73.557 50.005 120.661 50.005 89.856-19.157 120.661-50.005 50.005-73.557 50.005-120.661v-341.333c0-47.104-19.157-89.856-50.005-120.661s-73.557-50.005-120.661-50.005zM341.333 1024h341.333c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-128v-87.979c77.184-9.643 146.432-45.056 198.699-97.323 61.696-61.739 99.968-147.115 99.968-241.365v-85.333c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v85.333c0 70.699-28.587 134.656-74.965 181.035s-110.336 74.965-181.035 74.965-134.656-28.587-181.035-74.965-74.965-110.336-74.965-181.035v-85.333c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v85.333c0 94.251 38.272 179.627 99.968 241.365 52.267 52.267 121.472 87.68 198.699 97.323v87.979h-128c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["mic"],"grid":24},"attrs":[],"properties":{"id":3,"order":30,"prevSize":24,"code":59650,"name":"mic"},"setIdx":0,"setId":2,"iconIdx":3},{"icon":{"paths":["M534.016 594.347c-6.997 1.877-14.336 2.859-21.931 2.859-23.68-0.043-44.928-9.515-60.373-24.96-15.488-15.445-25.045-36.693-25.045-60.245v-25.003zM682.667 398.507v-227.84c0.043-47.061-19.072-89.813-49.877-120.704s-73.515-50.048-120.619-50.091c-43.264-0.043-82.901 16.085-113.024 42.752-27.136 24.021-46.592 56.619-54.357 93.739-4.821 23.083 9.984 45.653 33.067 50.475s45.653-9.984 50.475-33.067c3.925-18.773 13.739-35.2 27.349-47.275 14.933-13.227 34.389-21.205 55.808-21.291 24.363 0.128 45.483 9.643 60.885 25.045 15.488 15.531 25.003 36.779 24.96 60.416v227.84c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667zM768 426.667v85.333c0 16.043-1.493 31.573-3.968 44.587-4.352 23.168 10.88 45.483 34.048 49.835s45.483-10.88 49.835-34.048c3.499-18.517 5.419-39.339 5.419-60.373v-85.333c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667zM341.333 1024h341.333c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-128v-86.357c61.696-8.064 119.083-31.232 167.851-69.419l228.651 228.651c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-249.088-249.088c-1.92-3.371-4.309-6.528-7.211-9.344-2.688-2.645-5.632-4.821-8.747-6.613l-673.621-673.664c-16.683-16.683-43.691-16.683-60.331 0s-16.683 43.691 0 60.331l328.832 328.832v110.336c0.043 47.147 19.243 89.856 50.091 120.661s73.6 49.92 120.704 49.877c31.531-0.043 61.141-8.619 86.485-23.595l63.019 63.019c-40.917 29.568-88.661 45.568-137.045 47.915-4.011-1.237-8.235-1.877-12.587-1.877-4.395 0-8.576 0.64-12.587 1.877-60.459-2.944-119.979-27.179-166.613-72.832-49.195-48.171-74.795-111.275-76.715-175.189-0.085-4.779-0.085-9.557-0.085-9.557v-85.632c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v85.035c0 6.357 0.128 12.715 0.128 12.715 2.56 85.077 36.736 169.344 102.315 233.6 55.424 54.315 124.757 85.888 196.224 94.848v85.803h-128c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["mic-off"],"grid":24},"attrs":[],"properties":{"id":4,"order":31,"prevSize":24,"code":59651,"name":"mic-off"},"setIdx":0,"setId":2,"iconIdx":4},{"icon":{"paths":["M512 682.667h-341.333c-11.776 0-22.4-4.736-30.165-12.501s-12.501-18.389-12.501-30.165v-426.667c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501h682.667c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165v426.667c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501zM469.333 768v85.333h-128c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667h341.333c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-128v-85.333h298.667c35.328 0 67.413-14.379 90.496-37.504s37.504-55.168 37.504-90.496v-426.667c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504h-682.667c-35.328 0-67.413 14.379-90.496 37.504s-37.504 55.168-37.504 90.496v426.667c0 35.328 14.379 67.413 37.504 90.496s55.168 37.504 90.496 37.504z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["monitor"],"grid":24},"attrs":[],"properties":{"id":5,"order":32,"prevSize":24,"code":59652,"name":"monitor"},"setIdx":0,"setId":2,"iconIdx":5},{"icon":{"paths":["M597.333 512c0-23.552-9.6-44.928-25.003-60.331s-36.779-25.003-60.331-25.003-44.928 9.6-60.331 25.003-25.003 36.779-25.003 60.331 9.6 44.928 25.003 60.331 36.779 25.003 60.331 25.003 44.928-9.6 60.331-25.003 25.003-36.779 25.003-60.331zM896 512c0-23.552-9.6-44.928-25.003-60.331s-36.779-25.003-60.331-25.003-44.928 9.6-60.331 25.003-25.003 36.779-25.003 60.331 9.6 44.928 25.003 60.331 36.779 25.003 60.331 25.003 44.928-9.6 60.331-25.003 25.003-36.779 25.003-60.331zM298.667 512c0-23.552-9.6-44.928-25.003-60.331s-36.779-25.003-60.331-25.003-44.928 9.6-60.331 25.003-25.003 36.779-25.003 60.331 9.6 44.928 25.003 60.331 36.779 25.003 60.331 25.003 44.928-9.6 60.331-25.003 25.003-36.779 25.003-60.331z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["more-horizontal"],"grid":24},"attrs":[],"properties":{"id":6,"order":33,"prevSize":24,"code":59653,"name":"more-horizontal"},"setIdx":0,"setId":2,"iconIdx":6},{"icon":{"paths":["M938.667 381.568v260.864l-182.613-130.432zM128 170.667c-35.328 0-67.413 14.379-90.496 37.504s-37.504 55.168-37.504 90.496v426.667c0 35.328 14.379 67.413 37.504 90.496s55.168 37.504 90.496 37.504h469.333c35.328 0 67.413-14.379 90.496-37.504s37.504-55.168 37.504-90.496v-130.432l231.211 165.163c19.157 13.696 45.824 9.259 59.52-9.899 5.376-7.595 7.979-16.341 7.936-24.832v-426.667c0-23.552-19.115-42.667-42.667-42.667-9.301 0-17.92 2.987-24.789 7.936l-231.211 165.163v-130.432c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504zM128 256h469.333c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165v426.667c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501h-469.333c-11.776 0-22.4-4.736-30.165-12.501s-12.501-18.389-12.501-30.165v-426.667c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["video"],"grid":24},"attrs":[],"properties":{"id":7,"order":34,"prevSize":24,"code":59654,"name":"video"},"setIdx":0,"setId":2,"iconIdx":7},{"icon":{"paths":["M454.827 256h142.507c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165v142.507c0 11.776 4.779 22.443 12.501 30.165l42.667 42.667c14.976 14.976 38.315 16.512 55.168 4.395l188.331-136.192v343.125c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-426.667c0.043-8.576-2.603-17.408-8.107-25.003-13.824-19.072-40.491-23.381-59.563-9.557l-226.517 163.883-4.48-4.48v-124.843c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504h-142.507c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM195.669 256l444.331 444.331v25.003c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501h-469.333c-11.776 0-22.4-4.736-30.165-12.501s-12.501-18.389-12.501-30.165v-426.667c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501zM12.501 72.832l98.901 98.901c-28.715 3.712-54.485 16.981-73.899 36.437-23.125 23.083-37.504 55.168-37.504 90.496v426.667c0 35.328 14.379 67.413 37.504 90.496s55.168 37.504 90.496 37.504h469.333c35.328 0 67.413-14.379 90.496-37.504 11.477-11.477 20.821-25.173 27.307-40.363l236.032 236.032c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-938.667-938.667c-16.683-16.683-43.691-16.683-60.331 0s-16.683 43.691 0 60.331z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["video-off"],"grid":24},"attrs":[],"properties":{"id":8,"order":35,"prevSize":24,"code":59655,"name":"video-off"},"setIdx":0,"setId":2,"iconIdx":8},{"icon":{"paths":["M1017.379 575.994c8.004 55.482 13.215 131.393-11.664 160.446-41.142 48.044-301.713 48.044-301.713-48.042 0-48.396 42.856-80.134 1.71-128.178-40.472-47.262-113.026-48.030-193.714-48.042-80.686 0.012-153.242 0.779-193.714 48.042-41.142 48.046 1.714 79.78 1.714 128.178 0 96.086-260.57 96.086-301.714 48.044-24.878-29.055-19.668-104.964-11.664-160.446 6.16-37.038 21.724-76.996 71.547-127.994 0-0.002 0.002-0.002 0.002-0.002 74.738-69.744 187.846-126.739 429.826-127.968v-0.030c1.344 0 2.664 0.009 4.001 0.014 1.338-0.002 2.657-0.014 4.001-0.014v0.028c241.979 1.23 355.090 58.226 429.826 127.968 0.002 0.002 0.002 0.002 0.002 0.002 49.824 50.996 65.391 90.956 71.55 127.994z"],"tags":["hang-up"],"defaultCode":59715,"grid":24,"attrs":[]},"attrs":[],"properties":{"ligatures":"","name":"exit","order":38,"id":68,"prevSize":24,"code":59657},"setIdx":1,"setId":1,"iconIdx":0}],"height":1024,"metadata":{"name":"icomoon"},"preferences":{"showGlyphs":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"icon-","metadata":{"fontFamily":"icomoon","majorVersion":1,"minorVersion":0},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false,"autoHost":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"classSelector":".icon","name":"icomoon","height":32,"columns":16,"margin":16},"historySize":50,"showCodes":true,"gridSize":16,"showLiga":true,"quickUsageToken":{"talk":"NzAxNGRjYmJjNGI2ODAyM2JjMTgwNmQ2ZmU1ZjQxNDgjMSMxNjYwNDY0NTI3IyMjN2ExZGEwMWI0Mjgz"},"showGrid":false}} \ No newline at end of file diff --git a/www/icomoon/style.css b/www/icomoon/style.css index 9a2fba4..7a370f4 100644 --- a/www/icomoon/style.css +++ b/www/icomoon/style.css @@ -1,10 +1,10 @@ @font-face { font-family: 'icomoon'; - src: url('fonts/icomoon.eot?mtf7wj'); - src: url('fonts/icomoon.eot?mtf7wj#iefix') format('embedded-opentype'), - url('fonts/icomoon.ttf?mtf7wj') format('truetype'), - url('fonts/icomoon.woff?mtf7wj') format('woff'), - url('fonts/icomoon.svg?mtf7wj#icomoon') format('svg'); + src: url('fonts/icomoon.eot?m5ngo1'); + src: url('fonts/icomoon.eot?m5ngo1#iefix') format('embedded-opentype'), + url('fonts/icomoon.ttf?m5ngo1') format('truetype'), + url('fonts/icomoon.woff?m5ngo1') format('woff'), + url('fonts/icomoon.svg?m5ngo1#icomoon') format('svg'); font-weight: normal; font-style: normal; font-display: block; @@ -52,3 +52,6 @@ .icon-video-off:before { content: "\e907"; } +.icon-exit:before { + content: "\e909"; +} diff --git a/www/index.html b/www/index.html index df9c187..cc02a20 100755 --- a/www/index.html +++ b/www/index.html @@ -6,133 +6,74 @@ name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" /> - + - - + + - - - - - - + Talk - Free group video call for the web - - + + + + -
-
-
-

- Talk is a free & open-source video conference app for the web.
Works in all major - browsers. No signups. No downloads. 100% peer-to-peer. -

-

- - Share this link to start talking.
- {{roomLink}} - {{copyText || "Copy"}} -
-

- -
- -
-
-
- {{chat.name}} - · {{formatDate(chat.date)}} -
+
+
+

Talk

+

A free, peer-to-peer, open-source video calling for the web.

+

No sign ups. No downloads.
Works in all major browsers.

+
+
+ tlk.li/
-
No chat messages.
-
-
-
Type message...
-
+ Start
- Press enter to submit -
-
-
Camera 📹
-
-
- {{videoDevice.label}} -
-
- -
Microphone 🎙️
-
-
- {{audioDevice.label}} -
-
- -
Name 📛
- - - - +

Generate a random room

+
+
+
+
-
-
- - - - - -
+
+ © tlk.li · Legal · + Contact
+ +

diff --git a/www/legal.html b/www/legal.html index a924383..9e74701 100755 --- a/www/legal.html +++ b/www/legal.html @@ -13,39 +13,33 @@ /> - + Talk - A free video call app for the web - - - +

Legal

@@ -71,12 +65,10 @@

Privacy policy

stored on your browser and used to identify the chat messages you send.

- Talk is purely peer-to-peer, which means the user's video & audio is not sent to our server at all. We use - Google Analytics to track aggregated usage statistics to improve our service. -

-

- The makers of Talk have no intention of using personally or selling any of the above-mentioned data. + Talk is purely peer-to-peer, which means the user\'s video & audio is not sent to our server at all. We also use + Cabin Analytics to track aggregated usage statistics in order to improve our service.

+

The makers of Talk have no intention of using personally or selling any of the above-mentioned data.

diff --git a/www/style.css b/www/style.css deleted file mode 100755 index dd8b087..0000000 --- a/www/style.css +++ /dev/null @@ -1,308 +0,0 @@ -@import "icomoon/style.css"; - -* { - outline: none; -} -html, -body { - margin: 0px; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", - sans-serif; - line-height: 1.6; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - background: #fff; -} -input { - display: block; - box-sizing: border-box; - border: 1px solid #efefef; - border-radius: 0.5rem; - padding: 0.6rem; - font-size: 1rem; -} -.light { - color: #878787; -} -.video { - float: left; - width: 25vw; - height: 50vh; - overflow: hidden; - position: relative; -} -.video.one { - width: 100vw; - height: 100vh; -} -.video.two { - width: 50vw; - height: 100vh; -} -.video.three { - width: 33.33vw; - height: 100vh; -} -.video.four { - width: 50vw; - height: 50vh; -} -.video.five, -.video.six { - width: 33.33vw; - height: 50vh; -} -.video video { - width: 100%; - height: 100%; - display: block; - margin: auto; - box-sizing: border-box; - object-fit: cover; -} -.video video.mirror { - transform: rotateY(180deg); - -webkit-transform: rotateY(180deg); - -moz-transform: rotateY(180deg); -} -.video:fullscreen video { - background: #acadd3; - object-fit: contain; - border: none; -} -.video button { - position: absolute; - top: 0.1rem; - right: 0px; - z-index: 10; - font-size: 2rem; - color: white; - background: none; - border: none; - cursor: pointer; - text-shadow: 2px 2px 5px #989898; - padding: 0.1rem 0.4rem; -} -.video:fullscreen button { - display: none; -} - -#app { - display: none; -} -#intro { - background: #fff; - position: fixed; - bottom: 6rem; - left: 0px; - right: 0px; - z-index: 100; - width: 18rem; - margin: auto; - padding: 1rem; - box-sizing: border-box; - border-radius: 1rem; - box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.16), 0px 1px 4px rgba(0, 0, 0, 0.16); -} -#intro .roomLink { - text-decoration: underline; - text-decoration-style: dashed; - text-underline-offset: 0.2rem; - word-wrap: break-word; - word-break: break-word; -} -#intro .copyURL { - color: inherit; - text-decoration: none; - font-weight: bold; - -webkit-user-select: none; - user-select: none; -} -#intro .footer { - display: flex; - justify-content: space-between; -} -#intro .footer .terms { - position: relative; - top: -0.25rem; -} - -#chatWrap { - background: #fff; - position: fixed; - bottom: 6rem; - left: 0px; - right: 0px; - z-index: 100; - width: 18rem; - margin: auto; - padding: 1rem; - box-sizing: border-box; - border-radius: 1rem; - box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.16), 0px 1px 4px rgba(0, 0, 0, 0.16); -} -#chatWrap #chats { - overflow-y: auto; - overflow: auto; - max-height: 240px; - margin: auto; - background: /* Shadow covers */ linear-gradient(white 30%, rgba(255, 255, 255, 0)), - linear-gradient(rgba(255, 255, 255, 0), white 70%) 0 100%, - /* Shadows */ radial-gradient(50% 0, farthest-side, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)), - radial-gradient(50% 100%, farthest-side, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)) 0 100%; - background: /* Shadow covers */ linear-gradient(white 30%, rgba(255, 255, 255, 0)), - linear-gradient(rgba(255, 255, 255, 0), white 70%) 0 100%, - /* Shadows */ radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)), - radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)) 0 100%; - background-repeat: no-repeat; - background-color: white; - background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px; - - background-attachment: local, local, scroll, scroll; -} -#chatWrap .chat { - margin: 0.5rem 0rem; -} -#chatWrap .chat .name { - font-weight: bold; -} -#chatWrap .chat .message { -} -#chatWrap .chat .date { - font-size: small; -} -#chatWrap #composeBox { - position: relative; - background: #f6f6f6; - border-radius: 1rem; - padding: 0.7rem 1rem; - margin-top: 0.5rem; - max-height: 4.2rem; - overflow-y: auto; -} -#chatWrap #composeBox #placeholder { - position: absolute; - z-index: 5; - opacity: 0.5; -} -#chatWrap #composeBox #compose { - position: relative; - z-index: 10; -} -#chatWrap #noChat { - padding: 1rem; - text-align: center; -} - -#settings { - background: rgba(255, 255, 255, 0.9); - box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.16), 0px 1px 4px rgba(0, 0, 0, 0.16); - position: fixed; - bottom: 5rem; - left: 0px; - right: 0px; - z-index: 100; - width: 17rem; - margin: auto; - box-sizing: border-box; - border-radius: 1rem; - max-height: 26rem; - overflow-y: auto; -} -#settings .label { - padding: 1rem 1rem 0.25rem; - font-weight: bold; -} -#settings .link { - padding: 0.25rem 1rem; - white-space: nowrap; - width: 100%; - box-sizing: border-box; - overflow: hidden; - text-overflow: ellipsis; - cursor: pointer; - border-radius: 1rem; -} -#settings .link.active:before { - content: "✔️"; - margin-right: 0.5rem; -} -#settings .link:hover { - background: #fff; -} -#settings .link.copy { - margin-bottom: 0.5rem; -} -#settings input { - margin: 0rem 1rem 1rem; - width: calc(100% - 2rem); -} - -#actionsWrap { - position: fixed; - bottom: 1rem; - left: 0px; - right: 0px; - z-index: 100; - display: inline-flex; - transition: all 0.25s ease-out; - opacity: 1; - transform: translateY(0rem); -} -#actionsWrap.hidden { - opacity: 0; - transform: translateY(1rem); - z-index: -1; -} - -#actions { - background: rgba(255, 255, 255, 0.5); - box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.16), 0px 1px 4px rgba(0, 0, 0, 0.16); - margin: auto; - box-sizing: border-box; - border-radius: 1rem; - transition: opacity 250ms; -} -#actions button { - flex: 1; - background: none; - border: none; - font-size: 1.25rem; - padding: 1rem; - cursor: pointer; - margin: auto; -} -#actions button:hover { - background: rgba(255, 255, 255, 0.8); - border-radius: 1rem; -} -#actions button.active { - background: #fafafa; - border-radius: 1rem; -} -#actions button.icon-mic-off, -#actions button.icon-video-off { - color: #e74c3c !important; -} - -@media only screen and (max-width: 960px) { - .video { - float: left; - width: 50vw; - height: 25vh; - overflow: hidden; - } - .video.two { - width: 100vw; - height: 50vh; - } - .video.three { - width: 100vw; - height: 33.33vh; - } - .video.five, - .video.six { - width: 50vw; - height: 33.33vh; - } -} diff --git a/www/script.js b/www/webrtc.js similarity index 50% rename from www/script.js rename to www/webrtc.js index 64cecef..5a832f1 100755 --- a/www/script.js +++ b/www/webrtc.js @@ -1,21 +1,10 @@ -/* globals App, io, cabin*/ +/* globals App, io */ + +"use strict"; + const ICE_SERVERS = [ { urls: "stun:stun.l.google.com:19302" }, - { urls: "stun:stun.stunprotocol.org:3478" }, - { urls: "stun:stun.sipnet.net:3478" }, - { urls: "stun:stun.ideasip.com:3478" }, - { urls: "stun:stun.iptel.org:3478" }, - { urls: "turn:numb.viagenie.ca", username: "imvasanthv@gmail.com", credential: "d0ntuseme" }, - { - urls: [ - "turn:173.194.72.127:19305?transport=udp", - "turn:[2404:6800:4008:C01::7F]:19305?transport=udp", - "turn:173.194.72.127:443?transport=tcp", - "turn:[2404:6800:4008:C01::7F]:443?transport=tcp", - ], - username: "CKjCuLwFEgahxNRjuTAYzc/s6OMT", - credential: "u1SQDR/SQsPQIxXNWQT7czc/G4c=", - }, + { urls: "turn:openrelay.metered.ca:443", username: "openrelayproject", credential: "openrelayproject" }, ]; const APP_URL = (() => { @@ -26,9 +15,7 @@ const APP_URL = (() => { const ROOM_ID = (() => { let roomName = location.pathname.substring(1); if (!roomName) { - roomName = Math.random() - .toString(36) - .substr(2, 6); + roomName = Math.random().toString(36).substr(2, 6); window.history.pushState({ url: `${APP_URL}/${roomName}` }, roomName, `${APP_URL}/${roomName}`); } return roomName; @@ -40,26 +27,53 @@ const USE_VIDEO = true; let signalingSocket = null; /* our socket.io connection to our webserver */ let localMediaStream = null; /* our own microphone / webcam */ let peers = {}; /* keep track of our peer connections, indexed by peer_id (aka socket.io id) */ +let channel = {}; /* keep track of the peers Info in the channel, indexed by peer_id (aka socket.io id) */ let peerMediaElements = {}; /* keep track of our