mirror of
https://github.com/OutlineFoundation/outline-server.git
synced 2026-05-13 05:52:04 +00:00
chore(devtools): non-build updates from client (#1103)
* okay put this up see where we're at * update builds here * check browserslist * add badge * Update build_and_test_debug.yml * scopes & electron version
This commit is contained in:
parent
c69c7167c0
commit
2d3481574f
14 changed files with 2739 additions and 7889 deletions
4
.browserslistrc
Normal file
4
.browserslistrc
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# We use Electron v18.
|
||||
# This is the version of Chrome it requires:
|
||||
# https://github.com/electron/releases#releases
|
||||
chrome >= 100
|
||||
|
|
@ -10,8 +10,9 @@
|
|||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"plugins": ["@typescript-eslint", "compat"],
|
||||
"rules": {
|
||||
"compat/compat": "error",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
|
|
|
|||
30
.github/workflows/build_and_test_debug.yml
vendored
30
.github/workflows/build_and_test_debug.yml
vendored
|
|
@ -9,6 +9,9 @@ on:
|
|||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
|
|
@ -119,14 +122,7 @@ jobs:
|
|||
run: npm ci
|
||||
|
||||
- name: Build Linux Manager
|
||||
run: npm run action server_manager/electron_app/build --platform linux
|
||||
|
||||
- name: Upload Linux Client
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: manager_linux_debug
|
||||
path: build/server_manager/electron_app/static/dist/Outline-Manager.AppImage
|
||||
if-no-files-found: error
|
||||
run: npm run action server_manager/electron_app/build linux
|
||||
|
||||
manager-windows-debug-build:
|
||||
name: Manager Windows Debug Build
|
||||
|
|
@ -148,14 +144,7 @@ jobs:
|
|||
run: npm ci
|
||||
|
||||
- name: Build Windows Manager
|
||||
run: npm run action server_manager/electron_app/build --platform windows
|
||||
|
||||
- name: Upload Windows Manager
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: manager_windows_debug
|
||||
path: build/server_manager/electron_app/static/dist/Outline-Manager.exe
|
||||
if-no-files-found: error
|
||||
run: npm run action server_manager/electron_app/build windows
|
||||
|
||||
manager-mac-debug-build:
|
||||
name: Manager MacOS Debug Build
|
||||
|
|
@ -180,11 +169,4 @@ jobs:
|
|||
run: sudo xcode-select -switch /Applications/Xcode_13.2.app
|
||||
|
||||
- name: Build MacOS Manager
|
||||
run: npm run action server_manager/electron_app/build --platform mac
|
||||
|
||||
- name: Upload MacOS Manager
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: manager_macos_debug
|
||||
path: build/server_manager/electron_app/static/dist/Outline-Manager.dmg
|
||||
if-no-files-found: error
|
||||
run: npm run action server_manager/electron_app/build macos
|
||||
|
|
|
|||
16
.github/workflows/build_release_candidates.yml
vendored
16
.github/workflows/build_release_candidates.yml
vendored
|
|
@ -1,16 +0,0 @@
|
|||
name: Build Release Candidates
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
uses: ./.github/workflows/manager_linux_build_release_candidate.yml
|
||||
secrets:
|
||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
name: Build Linux Release Candidate
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
secrets:
|
||||
SENTRY_DSN:
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
manager-linux-release-build:
|
||||
name: Manager Linux Release Build
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||
BUILD_ENV: production
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2.3.4
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v2.2.0
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Install NPM Dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build Linux Release Candidate
|
||||
run: npm run action server_manager/electron_app/build linux -- --buildMode=release
|
||||
|
||||
- name: Upload Linux Release Candidate
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: manager_linux_release_${{ github.sha }}
|
||||
path: build/server_manager/electron_app/static/dist
|
||||
if-no-files-found: error
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
name: Publish Manager Linux Release Candidate
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
commit_sha:
|
||||
description: "SHA of commit to publish (example: 2ac8bd4a915a7c8a3e3a63081d72da33baa9ea7e)"
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
publish-release:
|
||||
name: Publish Client Linux Release Candidate
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
environment: Releases Repository
|
||||
env:
|
||||
RELEASES_REPOSITORY: ${{ secrets.RELEASES_REPOSITORY }}
|
||||
RELEASES_DEPLOY_KEY: ${{ secrets.RELEASES_DEPLOY_KEY }}
|
||||
RELEASE_COMMIT_SHA: ${{ github.event.inputs.commit_sha }}
|
||||
# STORE_LOGIN: ${{ secrets.SNAP_STORE_LOGIN }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2.3.4
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v2.2.0
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Install NPM Dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Download Release Candidate
|
||||
uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e
|
||||
with:
|
||||
workflow: build_release_candidates.yml
|
||||
commit: ${{ env.RELEASE_COMMIT_SHA }}
|
||||
name: manager_linux_release_${{ env.RELEASE_COMMIT_SHA }}
|
||||
path: manager_linux_release
|
||||
|
||||
- name: Checkout Releases Repository
|
||||
uses: actions/checkout@v2.3.4
|
||||
with:
|
||||
repository: ${{ env.RELEASES_REPOSITORY }}
|
||||
ssh-key: ${{ env.RELEASES_DEPLOY_KEY }}
|
||||
path: outline-releases
|
||||
|
||||
- name: Push Tags and Release Commits
|
||||
run: |
|
||||
git config --global user.name "OutlineBot"
|
||||
git config --global user.email "outlinebot@users.noreply.github.com"
|
||||
|
||||
RELEASE_VERSION="$(node scripts/get_version.mjs linux)"
|
||||
RELEASE_TAG="linux-${RELEASE_VERSION}"
|
||||
|
||||
[ "$(git tag -l "$RELEASE_TAG")" != "" ] && exit 1
|
||||
|
||||
cp manager_linux_release/Outline-Manager.AppImage outline-releases/manager/stable/Outline-Manager.AppImage
|
||||
cp manager_linux_release/latest-linux.yml outline-releases/manager/stable/latest-linux.yml
|
||||
|
||||
cd outline-releases
|
||||
git checkout master
|
||||
git add manager/stable/Outline-Manager.AppImage manager/stable/latest-linux.yml
|
||||
git commit -m "Release linux manager v${RELEASE_VERSION}"
|
||||
git push origin master
|
||||
git tag "$RELEASE_TAG"
|
||||
git push origin "$RELEASE_TAG"
|
||||
|
||||
cd ..
|
||||
git tag "$RELEASE_TAG"
|
||||
git push origin "$RELEASE_TAG"
|
||||
# TODO(daniellacosse): S3 bucket?
|
||||
# TODO(daniellacosse): snap store
|
||||
# - name: Publish to Snap store
|
||||
# uses: snapcore/action-publish@v1
|
||||
# with:
|
||||
# store_login: ${{ secrets.STORE_LOGIN }}
|
||||
# snap: build/dist/Outline-Manager.AppImage
|
||||
# release: edge
|
||||
68
.github/workflows/pull_request_checks.yml
vendored
Normal file
68
.github/workflows/pull_request_checks.yml
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
name: Pull Request Checks
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
|
||||
# This `edited` flag is why we need a separate workflow -
|
||||
# specifying edited here causes this job to be re-run whenever someone edits the PR title/description.
|
||||
|
||||
# If we had the debug builds in this file, they would run unnecessarily, costing resources.
|
||||
- edited
|
||||
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
name_check:
|
||||
name: Pull Request Name Check
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v2.2.0
|
||||
with:
|
||||
node-version: 16
|
||||
cache: npm
|
||||
|
||||
- name: Install NPM Dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Ensure Commitizen Format
|
||||
uses: JulienKode/pull-request-name-linter-action@98794a8b815ec05560813c42e55fd8d32d3fd248
|
||||
|
||||
size_label:
|
||||
name: Change Size Label
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- name: Apply Size Label
|
||||
uses: pascalgn/size-label-action@a4655c448bb838e8d73b81e97fd0831bb4cbda1e
|
||||
env:
|
||||
IGNORED: |
|
||||
LICENSE
|
||||
package-lock.json
|
||||
resources
|
||||
src/server_manager/messages
|
||||
src/server_manager/images
|
||||
third_party
|
||||
with:
|
||||
sizes: >
|
||||
{
|
||||
"0": "XS",
|
||||
"64": "S",
|
||||
"128": "M",
|
||||
"256": "L",
|
||||
"512": "XL",
|
||||
"1024": "XXL"
|
||||
}
|
||||
103
.travis.yml
103
.travis.yml
|
|
@ -1,103 +0,0 @@
|
|||
# -- DEPRECATED: FOR REFERENCE ONLY --
|
||||
# Due to security issues with travis, we are in the process
|
||||
# of migrating to github actions: https://github.com/features/actions.
|
||||
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "12"
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cache/electron
|
||||
- $HOME/.cache/electron-builder
|
||||
|
||||
before_install:
|
||||
# Install latest Docker for BuildKit support if running on linux. See https://docs.travis-ci.com/user/docker/
|
||||
- |
|
||||
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
||||
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
|
||||
sudo apt-get update
|
||||
sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
fi;
|
||||
|
||||
stages:
|
||||
- name: "Server Daily Release"
|
||||
if: type = cron
|
||||
- name: "Deploy Server"
|
||||
if: tag =~ ^server-
|
||||
- name: "Manager Release"
|
||||
if: tag =~ ^v[0-9]
|
||||
|
||||
# Stages with the same name define multiple jobs which run in parallel.
|
||||
jobs:
|
||||
include:
|
||||
- stage: "Server Daily Release"
|
||||
script:
|
||||
- CREATE_RELEASE_URL=https://api.github.com/repos/Jigsaw-Code/outline-server/releases?access_token=$CI_USER_TOKEN
|
||||
- SERVER_RELEASE_NAME=server-$(date -I)
|
||||
- curl --data '{"tag_name":"'$SERVER_RELEASE_NAME'","name":"'$SERVER_RELEASE_NAME'","prerelease":true}' $CREATE_RELEASE_URL
|
||||
- MANAGER_RELEASE_NAME=v$(date -I)
|
||||
- curl --data '{"tag_name":"'$MANAGER_RELEASE_NAME'","name":"'$MANAGER_RELEASE_NAME'","prerelease":true}' $CREATE_RELEASE_URL
|
||||
- stage: "Deploy Server"
|
||||
name: Server Testing
|
||||
sudo: required
|
||||
services: docker
|
||||
script:
|
||||
# https://docs.travis-ci.com/user/docker/
|
||||
- |
|
||||
sudo rm -f /usr/local/bin/docker-compose
|
||||
curl -L https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m) > docker-compose
|
||||
chmod +x docker-compose
|
||||
sudo mv docker-compose /usr/local/bin
|
||||
- npm run action shadowbox/test
|
||||
- npm run action shadowbox/docker/build && cd src/shadowbox/integration_test && ./test.sh
|
||||
|
||||
- stage: "Deploy Server"
|
||||
name: Server Docker Image
|
||||
sudo: required
|
||||
services: docker
|
||||
script:
|
||||
- npm run action shadowbox/docker/build
|
||||
- docker login quay.io -u="$QUAY_IO_USERNAME" -p="$QUAY_IO_PASSWORD"
|
||||
- docker tag outline/shadowbox quay.io/outline/shadowbox:$TRAVIS_TAG
|
||||
- docker push quay.io/outline/shadowbox:$TRAVIS_TAG
|
||||
- docker tag outline/shadowbox quay.io/outline/shadowbox:daily
|
||||
- docker push quay.io/outline/shadowbox:daily
|
||||
|
||||
# Note that because we cannot currently sign Windows binaries on Travis,
|
||||
# these must be manually built and uploaded to the releases page.
|
||||
- stage: "Manager Release"
|
||||
name: Manager Linux
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- rpm
|
||||
script: npm run action server_manager/electron_app/release_linux
|
||||
|
||||
- stage: "Manager Release"
|
||||
os: osx
|
||||
# electron-builder requires macOS >=10.13.6 for signing to work.
|
||||
osx_image: xcode10.1
|
||||
name: Manager macOS
|
||||
script:
|
||||
- openssl aes-256-cbc -K $encrypted_61a49da75942_key -iv $encrypted_61a49da75942_iv -in macos-signing-certificate.p12.enc -out macos-signing-certificate.p12 -d
|
||||
- export CSC_LINK=$(pwd)/macos-signing-certificate.p12
|
||||
# Must run npm again due to the OS change, required for signing to work.
|
||||
- npm install && npm run action server_manager/electron_app/release_macos
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: "0uQ8HgYBpzeXG+m/q6FUrcvQe+30YkbuGej/nT4mAj9VhX7Ft/5PdsB6lFiUjc/OnNLbaMdIHJj2MO5SDy55A4d5gC/LN4hcvwWKY+sRephyMnu3f0Nepy1bZbA1rud4MToSv7K3aD24f7AWNNiwz8f/CdvENt6fDu53GuPZLPUDR6TzMy1JBZ3jyLDpy7Cjue24B9XUaXWzBpwFD1TpeKJ37O5V655+VWWPuYWUY2or0N6Iohunhrp1IhQAM7Cw4zln94prXmdX9bux8OP6U73gnyvTf7eGG4SjzypqqCL7VzqzUmDqYm072t2jvTwtjWjUt0vTE4UfOituDBK8VXqIpa4GGk3HBbx40GEQxVXJNCJl48cZsmEPZB+w4mPgxO9EWA/SpBNloqJuvfbspczYgvrM1/p5169PcXScVF+6iV+EWUeMKrymXOmJ4LpjttCDCTg/3AfwHCbAD+4JuLLMETfWeeZQ/4w3HBwxRRUFyvryLHmshuCahJxICWeJMtxftkA3O8e9Kc6P6x/G0JKDrSLeNJcY4vyKwpe4R9uJWk0A5lAnklFKgSXNT394/TNXpuTXuarZD6VaJcx9ieBQNkzpmi9RoLTjdnigmYeTWdPFrhOP/0fJu05U3nyH0NpKscG0e3+kG0XTJOHhYSwp/UknZb4rfR+BmqSTGik="
|
||||
file_glob: true
|
||||
file: "build/server_manager/electron_app/static/dist/*.*"
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
|
||||
env:
|
||||
global:
|
||||
- ELECTRON_CACHE=$HOME/.cache/electron
|
||||
- ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# Outline Server
|
||||
|
||||
[](https://travis-ci.org/Jigsaw-Code/outline-server)
|
||||

|
||||
|
||||
This repository has all the code needed to create and manage Outline servers on
|
||||
DigitalOcean. An Outline server runs instances of Shadowsocks proxies and
|
||||
|
|
|
|||
20
commitlint.config.js
Normal file
20
commitlint.config.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
module.exports = {
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
rules: {
|
||||
'scope-enum': [
|
||||
2,
|
||||
'always',
|
||||
[
|
||||
'devtools',
|
||||
'devtools/build',
|
||||
'docs',
|
||||
'manager',
|
||||
'manager/electron',
|
||||
'manager/web',
|
||||
'metrics_server',
|
||||
'sentry_webhook',
|
||||
'server',
|
||||
],
|
||||
],
|
||||
},
|
||||
};
|
||||
10222
package-lock.json
generated
10222
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -2,11 +2,14 @@
|
|||
"name": "outline-server",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@commitlint/config-conventional": "^17.0.0",
|
||||
"@types/jasmine": "^3.5.10",
|
||||
"@typescript-eslint/eslint-plugin": "^5.14.0",
|
||||
"@typescript-eslint/parser": "^5.14.0",
|
||||
"browserslist": "^4.20.3",
|
||||
"@webpack-cli/serve": "^1.6.1",
|
||||
"eslint": "^8.10.0",
|
||||
"eslint-plugin-compat": "^4.0.2",
|
||||
"generate-license-file": "^1.2.0",
|
||||
"husky": "^1.3.1",
|
||||
"jasmine": "^3.5.0",
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ To build the app binary:
|
|||
npm run action server_manager/electron_app/build ${PLATFORM} -- --buildMode=[debug,release]
|
||||
```
|
||||
|
||||
Where `${PLATFORM}` is one of `linux`, `mac`, `windows`.
|
||||
Where `${PLATFORM}` is one of `linux`, `macos`, `windows`.
|
||||
|
||||
The per-platform standalone apps will be at `build/electron_app/static/dist`.
|
||||
|
||||
|
|
|
|||
|
|
@ -11,41 +11,46 @@
|
|||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
import minimist from "minimist";
|
||||
import url from "url";
|
||||
import minimist from 'minimist';
|
||||
import url from 'url';
|
||||
|
||||
export async function getElectronBuildFlags(platform, buildMode) {
|
||||
let buildFlags = [
|
||||
"--projectDir=build/server_manager/electron_app/static",
|
||||
"--config.asarUnpack=server_manager/web_app/images",
|
||||
"--publish=never",
|
||||
'--projectDir=build/server_manager/electron_app/static',
|
||||
'--config.asarUnpack=server_manager/web_app/images',
|
||||
'--publish=never',
|
||||
'--config.artifactName="Outline-Manager.${ext}"',
|
||||
];
|
||||
|
||||
switch (platform) {
|
||||
case "linux":
|
||||
buildFlags = ["--linux", "--config.linux.icon=icons/png", "--config.linux.category=Network", ...buildFlags];
|
||||
case 'linux':
|
||||
buildFlags = [
|
||||
'--linux',
|
||||
'--config.linux.icon=icons/png',
|
||||
'--config.linux.category=Network',
|
||||
...buildFlags,
|
||||
];
|
||||
break;
|
||||
case "windows":
|
||||
buildFlags = ["--win", "--ia32", "--config.win.icon=icons/win/icon.ico", ...buildFlags];
|
||||
case 'windows':
|
||||
buildFlags = ['--win', '--ia32', '--config.win.icon=icons/win/icon.ico', ...buildFlags];
|
||||
break;
|
||||
case "mac":
|
||||
buildFlags = ["--mac", "--config.mac.icon=icons/mac/icon.icns", ...buildFlags];
|
||||
case 'macos':
|
||||
buildFlags = ['--mac', '--config.mac.icon=icons/mac/icon.icns', ...buildFlags];
|
||||
}
|
||||
|
||||
if (buildMode === "release") {
|
||||
if (buildMode === 'release') {
|
||||
// Publishing is disabled, updates are pulled from AWS. We use the generic provider instead of the S3
|
||||
// provider since the S3 provider uses "virtual-hosted style" URLs (my-bucket.s3.amazonaws.com)
|
||||
// which can be blocked by DNS or SNI without taking down other buckets.
|
||||
buildFlags = [
|
||||
...buildFlags,
|
||||
"--config.generateUpdatesFilesForAllChannels=true",
|
||||
"--config.publish.provider=generic",
|
||||
'--config.generateUpdatesFilesForAllChannels=true',
|
||||
'--config.publish.provider=generic',
|
||||
`--config.publish.url=${process.env.RELEASES_REPOSITORY}`,
|
||||
];
|
||||
}
|
||||
|
||||
if (buildMode === "release" && platform === "windows") {
|
||||
if (buildMode === 'release' && platform === 'windows') {
|
||||
buildFlags.push("--config.win.certificateSubjectName='Jigsaw Operations LLC'");
|
||||
}
|
||||
|
||||
|
|
@ -57,11 +62,11 @@ async function main() {
|
|||
|
||||
const platform = _[2];
|
||||
|
||||
console.log((await getElectronBuildFlags(platform, buildMode)).join(" "));
|
||||
console.log((await getElectronBuildFlags(platform, buildMode)).join(' '));
|
||||
}
|
||||
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
(async function() {
|
||||
(async function () {
|
||||
return main();
|
||||
})();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue