Compare commits

..

1 commit

Author SHA1 Message Date
Hydrazer
7199dd266e pkg(k-1.0.0): Added k 1.0.0 2022-12-24 08:37:55 -07:00
173 changed files with 778 additions and 1661 deletions

View file

@ -13,22 +13,22 @@ jobs:
name: Build and Push Docker image to Github Packages
steps:
- name: Check out repo
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Login to GitHub registry
uses: docker/login-action@v2
uses: docker/login-action@v1
with:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: docker.pkg.github.com
- name: Login to ghcr.io
uses: docker/login-action@v2
uses: docker/login-action@v1
with:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
- name: Build and push API
uses: docker/build-push-action@v4
uses: docker/build-push-action@v2
with:
context: api
push: true

View file

@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Get list of changed files
uses: lots0logs/gh-action-get-changed-files@2.1.4
with:
@ -36,10 +36,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Login to GitHub registry
uses: docker/login-action@v2
uses: docker/login-action@v1
with:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
@ -60,7 +60,7 @@ jobs:
ls -la packages
- name: Upload package as artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: packages
path: packages/*.pkg.tar.gz
@ -70,9 +70,9 @@ jobs:
runs-on: ubuntu-latest
needs: build-pkg
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v2
with:
name: packages
@ -80,7 +80,7 @@ jobs:
run: mv *.pkg.tar.gz packages/
- name: Login to GitHub registry
uses: docker/login-action@v2
uses: docker/login-action@v1
with:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
@ -92,7 +92,7 @@ jobs:
docker run -v $(pwd)'/repo:/piston/repo' -v $(pwd)'/packages:/piston/packages' -d --name repo docker.pkg.github.com/engineer-man/piston/repo-builder --no-build
docker pull docker.pkg.github.com/engineer-man/piston/api
docker build -t piston-api api
docker run --privileged --network container:repo -v $(pwd)'/data:/piston' -e PISTON_LOG_LEVEL=DEBUG -e 'PISTON_REPO_URL=http://localhost:8000/index' -d --name api piston-api
docker run --network container:repo -v $(pwd)'/data:/piston' -e PISTON_LOG_LEVEL=DEBUG -e 'PISTON_REPO_URL=http://localhost:8000/index' -d --name api piston-api
echo Waiting for API to start..
docker run --network container:api appropriate/curl -s --retry 10 --retry-connrefused http://localhost:2000/api/v2/runtimes

View file

@ -14,10 +14,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Login to GitHub registry
uses: docker/login-action@v2
uses: docker/login-action@v1
with:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

View file

@ -13,16 +13,16 @@ jobs:
name: Build and Push Docker image to Github Packages
steps:
- name: Check out repo
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Login to GitHub registry
uses: docker/login-action@v2
uses: docker/login-action@v1
with:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: docker.pkg.github.com
- name: Build and push repo
uses: docker/build-push-action@v4
uses: docker/build-push-action@v2
with:
context: repo
pull: true

View file

@ -1,29 +1,20 @@
FROM buildpack-deps:buster AS isolate
RUN apt-get update && \
apt-get install -y --no-install-recommends git libcap-dev && \
rm -rf /var/lib/apt/lists/* && \
git clone https://github.com/envicutor/isolate.git /tmp/isolate/ && \
cd /tmp/isolate && \
git checkout af6db68042c3aa0ded80787fbb78bc0846ea2114 && \
make -j$(nproc) install && \
rm -rf /tmp/*
FROM node:15.10.0-buster-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN dpkg-reconfigure -p critical dash
RUN for i in $(seq 1001 1500); do \
groupadd -g $i runner$i && \
useradd -M runner$i -g $i -u $i ; \
done
RUN apt-get update && \
apt-get install -y libxml2 gnupg tar coreutils util-linux libc6-dev \
binutils build-essential locales libpcre3-dev libevent-dev libgmp3-dev \
libncurses6 libncurses5 libedit-dev libseccomp-dev rename procps python3 \
libreadline-dev libblas-dev liblapack-dev libpcre3-dev libarpack2-dev \
libfftw3-dev libglpk-dev libqhull-dev libqrupdate-dev libsuitesparse-dev \
libsundials-dev libpcre2-dev libcap-dev && \
libsundials-dev libpcre2-dev && \
rm -rf /var/lib/apt/lists/*
RUN useradd -M piston
COPY --from=isolate /usr/local/bin/isolate /usr/local/bin
COPY --from=isolate /usr/local/etc/isolate /usr/local/etc/isolate
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
@ -32,5 +23,7 @@ COPY ["package.json", "package-lock.json", "./"]
RUN npm install
COPY ./src ./src
CMD ["/piston_api/src/docker-entrypoint.sh"]
RUN make -C ./src/nosocket/ all && make -C ./src/nosocket/ install
CMD [ "node", "src"]
EXPOSE 2000/tcp

395
api/package-lock.json generated
View file

@ -11,7 +11,7 @@
"dependencies": {
"body-parser": "^1.19.0",
"chownr": "^2.0.0",
"express": "^4.17.3",
"express": "^4.17.1",
"express-ws": "^5.0.2",
"is-docker": "^2.1.1",
"logplease": "^1.2.15",
@ -23,12 +23,12 @@
}
},
"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==",
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
"dependencies": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
},
"engines": {
"node": ">= 0.6"
@ -40,29 +40,29 @@
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"node_modules/body-parser": {
"version": "1.19.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz",
"integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==",
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
"dependencies": {
"bytes": "3.1.2",
"bytes": "3.1.0",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.2",
"http-errors": "1.8.1",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"on-finished": "~2.3.0",
"qs": "6.9.7",
"raw-body": "2.4.3",
"type-is": "~1.6.18"
"qs": "6.7.0",
"raw-body": "2.4.0",
"type-is": "~1.6.17"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
"engines": {
"node": ">= 0.8"
}
@ -76,11 +76,11 @@
}
},
"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==",
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
"dependencies": {
"safe-buffer": "5.2.1"
"safe-buffer": "5.1.2"
},
"engines": {
"node": ">= 0.6"
@ -95,9 +95,9 @@
}
},
"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==",
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
"engines": {
"node": ">= 0.6"
}
@ -126,7 +126,7 @@
"node_modules/destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg=="
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"node_modules/ee-first": {
"version": "1.1.1",
@ -149,22 +149,22 @@
"node_modules/etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/express": {
"version": "4.17.3",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz",
"integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==",
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
"dependencies": {
"accepts": "~1.3.8",
"accepts": "~1.3.7",
"array-flatten": "1.1.1",
"body-parser": "1.19.2",
"content-disposition": "0.5.4",
"body-parser": "1.19.0",
"content-disposition": "0.5.3",
"content-type": "~1.0.4",
"cookie": "0.4.2",
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "~1.1.2",
@ -178,13 +178,13 @@
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.7",
"qs": "6.9.7",
"proxy-addr": "~2.0.5",
"qs": "6.7.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.17.2",
"serve-static": "1.14.2",
"setprototypeof": "1.2.0",
"safe-buffer": "5.1.2",
"send": "0.17.1",
"serve-static": "1.14.1",
"setprototypeof": "1.1.1",
"statuses": "~1.5.0",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
@ -226,9 +226,9 @@
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
"engines": {
"node": ">= 0.6"
}
@ -236,21 +236,21 @@
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
"dependencies": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"inherits": "2.0.3",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.1"
"toidentifier": "1.0.0"
},
"engines": {
"node": ">= 0.6"
@ -268,9 +268,9 @@
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
@ -340,19 +340,19 @@
}
},
"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==",
"version": "1.46.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz",
"integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==",
"engines": {
"node": ">= 0.6"
}
},
"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==",
"version": "2.1.29",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz",
"integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==",
"dependencies": {
"mime-db": "1.52.0"
"mime-db": "1.46.0"
},
"engines": {
"node": ">= 0.6"
@ -364,9 +364,9 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"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==",
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
"engines": {
"node": ">= 0.6"
}
@ -407,11 +407,11 @@
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"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==",
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
"integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
"dependencies": {
"forwarded": "0.2.0",
"forwarded": "~0.1.2",
"ipaddr.js": "1.9.1"
},
"engines": {
@ -419,14 +419,11 @@
}
},
"node_modules/qs": {
"version": "6.9.7",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz",
"integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/range-parser": {
@ -438,12 +435,12 @@
}
},
"node_modules/raw-body": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz",
"integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==",
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "1.8.1",
"bytes": "3.1.0",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
},
@ -452,23 +449,9 @@
}
},
"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"
}
]
"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/safer-buffer": {
"version": "2.1.2",
@ -490,9 +473,9 @@
}
},
"node_modules/send": {
"version": "0.17.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
"integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
"dependencies": {
"debug": "2.6.9",
"depd": "~1.1.2",
@ -501,9 +484,9 @@
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "1.8.1",
"http-errors": "~1.7.2",
"mime": "1.6.0",
"ms": "2.1.3",
"ms": "2.1.1",
"on-finished": "~2.3.0",
"range-parser": "~1.2.1",
"statuses": "~1.5.0"
@ -513,28 +496,28 @@
}
},
"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=="
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
},
"node_modules/serve-static": {
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz",
"integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==",
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
"dependencies": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.17.2"
"send": "0.17.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
},
"node_modules/statuses": {
"version": "1.5.0",
@ -545,9 +528,9 @@
}
},
"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==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
"engines": {
"node": ">=0.6"
}
@ -628,12 +611,12 @@
},
"dependencies": {
"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==",
"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.34",
"negotiator": "0.6.3"
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
}
},
"array-flatten": {
@ -642,26 +625,26 @@
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"body-parser": {
"version": "1.19.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz",
"integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==",
"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.2",
"bytes": "3.1.0",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.2",
"http-errors": "1.8.1",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"on-finished": "~2.3.0",
"qs": "6.9.7",
"raw-body": "2.4.3",
"type-is": "~1.6.18"
"qs": "6.7.0",
"raw-body": "2.4.0",
"type-is": "~1.6.17"
}
},
"bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
},
"chownr": {
"version": "2.0.0",
@ -669,11 +652,11 @@
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
},
"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==",
"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.2.1"
"safe-buffer": "5.1.2"
}
},
"content-type": {
@ -682,9 +665,9 @@
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"cookie": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
},
"cookie-signature": {
"version": "1.0.6",
@ -707,7 +690,7 @@
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg=="
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"ee-first": {
"version": "1.1.1",
@ -727,19 +710,19 @@
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"express": {
"version": "4.17.3",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz",
"integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==",
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
"requires": {
"accepts": "~1.3.8",
"accepts": "~1.3.7",
"array-flatten": "1.1.1",
"body-parser": "1.19.2",
"content-disposition": "0.5.4",
"body-parser": "1.19.0",
"content-disposition": "0.5.3",
"content-type": "~1.0.4",
"cookie": "0.4.2",
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "~1.1.2",
@ -753,13 +736,13 @@
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.7",
"qs": "6.9.7",
"proxy-addr": "~2.0.5",
"qs": "6.7.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.17.2",
"serve-static": "1.14.2",
"setprototypeof": "1.2.0",
"safe-buffer": "5.1.2",
"send": "0.17.1",
"serve-static": "1.14.1",
"setprototypeof": "1.1.1",
"statuses": "~1.5.0",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
@ -789,25 +772,25 @@
}
},
"forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"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.4",
"setprototypeof": "1.2.0",
"inherits": "2.0.3",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.1"
"toidentifier": "1.0.0"
}
},
"iconv-lite": {
@ -819,9 +802,9 @@
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ipaddr.js": {
"version": "1.9.1",
@ -867,16 +850,16 @@
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
"version": "1.46.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz",
"integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ=="
},
"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==",
"version": "2.1.29",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz",
"integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==",
"requires": {
"mime-db": "1.52.0"
"mime-db": "1.46.0"
}
},
"ms": {
@ -885,9 +868,9 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
},
"nocamel": {
"version": "git+ssh://git@github.com/HexF/nocamel.git#89a5bfbbd07c72c302d968b967d0f4fe54846544",
@ -917,18 +900,18 @@
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"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==",
"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.2.0",
"forwarded": "~0.1.2",
"ipaddr.js": "1.9.1"
}
},
"qs": {
"version": "6.9.7",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz",
"integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw=="
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
},
"range-parser": {
"version": "1.2.1",
@ -936,20 +919,20 @@
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
"raw-body": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz",
"integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==",
"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.2",
"http-errors": "1.8.1",
"bytes": "3.1.0",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
}
},
"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=="
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safer-buffer": {
"version": "2.1.2",
@ -965,9 +948,9 @@
}
},
"send": {
"version": "0.17.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
"integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
@ -976,36 +959,36 @@
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "1.8.1",
"http-errors": "~1.7.2",
"mime": "1.6.0",
"ms": "2.1.3",
"ms": "2.1.1",
"on-finished": "~2.3.0",
"range-parser": "~1.2.1",
"statuses": "~1.5.0"
},
"dependencies": {
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
},
"serve-static": {
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz",
"integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==",
"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": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.17.2"
"send": "0.17.1"
}
},
"setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
},
"statuses": {
"version": "1.5.0",
@ -1013,9 +996,9 @@
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
"toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
},
"type-is": {
"version": "1.6.18",

View file

@ -1,12 +1,12 @@
{
"name": "piston-api",
"version": "3.1.1",
"version": "3.1.0",
"description": "API for piston - a high performance code execution engine",
"main": "src/index.js",
"dependencies": {
"body-parser": "^1.19.0",
"chownr": "^2.0.0",
"express": "^4.17.3",
"express": "^4.17.1",
"express-ws": "^5.0.2",
"is-docker": "^2.1.1",
"logplease": "^1.2.15",

View file

@ -6,9 +6,50 @@ const events = require('events');
const runtime = require('../runtime');
const { Job } = require('../job');
const package = require('../package');
const globals = require('../globals');
const logger = require('logplease').create('api/v2');
const SIGNALS = [
'SIGABRT',
'SIGALRM',
'SIGBUS',
'SIGCHLD',
'SIGCLD',
'SIGCONT',
'SIGEMT',
'SIGFPE',
'SIGHUP',
'SIGILL',
'SIGINFO',
'SIGINT',
'SIGIO',
'SIGIOT',
'SIGKILL',
'SIGLOST',
'SIGPIPE',
'SIGPOLL',
'SIGPROF',
'SIGPWR',
'SIGQUIT',
'SIGSEGV',
'SIGSTKFLT',
'SIGSTOP',
'SIGTSTP',
'SIGSYS',
'SIGTERM',
'SIGTRAP',
'SIGTTIN',
'SIGTTOU',
'SIGUNUSED',
'SIGURG',
'SIGUSR1',
'SIGUSR2',
'SIGVTALRM',
'SIGXCPU',
'SIGXFSZ',
'SIGWINCH',
];
// ref: https://man7.org/linux/man-pages/man7/signal.7.html
function get_job(body) {
let {
language,
@ -20,8 +61,6 @@ function get_job(body) {
run_memory_limit,
run_timeout,
compile_timeout,
run_cpu_time,
compile_cpu_time,
} = body;
return new Promise((resolve, reject) => {
@ -67,7 +106,7 @@ function get_job(body) {
});
}
for (const constraint of ['memory_limit', 'timeout', 'cpu_time']) {
for (const constraint of ['memory_limit', 'timeout']) {
for (const type of ['compile', 'run']) {
const constraint_name = `${type}_${constraint}`;
const constraint_value = body[constraint_name];
@ -96,23 +135,23 @@ function get_job(body) {
}
}
compile_timeout = compile_timeout || rt.timeouts.compile;
run_timeout = run_timeout || rt.timeouts.run;
compile_memory_limit = compile_memory_limit || rt.memory_limits.compile;
run_memory_limit = run_memory_limit || rt.memory_limits.run;
resolve(
new Job({
runtime: rt,
args: args ?? [],
stdin: stdin ?? '',
args: args || [],
stdin: stdin || '',
files,
timeouts: {
run: run_timeout ?? rt.timeouts.run,
compile: compile_timeout ?? rt.timeouts.compile,
},
cpu_times: {
run: run_cpu_time ?? rt.cpu_times.run,
compile: compile_cpu_time ?? rt.cpu_times.compile,
run: run_timeout,
compile: compile_timeout,
},
memory_limits: {
run: run_memory_limit ?? rt.memory_limits.run,
compile: compile_memory_limit ?? rt.memory_limits.compile,
run: run_memory_limit,
compile: compile_memory_limit,
},
})
);
@ -124,7 +163,7 @@ router.use((req, res, next) => {
return next();
}
if (!req.headers['content-type']?.startsWith('application/json')) {
if (!req.headers['content-type'].startsWith('application/json')) {
return res.status(415).send({
message: 'requests must be of type application/json',
});
@ -135,9 +174,9 @@ router.use((req, res, next) => {
router.ws('/connect', async (ws, req) => {
let job = null;
let event_bus = new events.EventEmitter();
let eventBus = new events.EventEmitter();
event_bus.on('stdout', data =>
eventBus.on('stdout', data =>
ws.send(
JSON.stringify({
type: 'data',
@ -146,7 +185,7 @@ router.ws('/connect', async (ws, req) => {
})
)
);
event_bus.on('stderr', data =>
eventBus.on('stderr', data =>
ws.send(
JSON.stringify({
type: 'data',
@ -155,10 +194,10 @@ router.ws('/connect', async (ws, req) => {
})
)
);
event_bus.on('stage', stage =>
eventBus.on('stage', stage =>
ws.send(JSON.stringify({ type: 'stage', stage }))
);
event_bus.on('exit', (stage, status) =>
eventBus.on('exit', (stage, status) =>
ws.send(JSON.stringify({ type: 'exit', stage, ...status }))
);
@ -171,27 +210,19 @@ router.ws('/connect', async (ws, req) => {
if (job === null) {
job = await get_job(msg);
try {
const box = await job.prime();
await job.prime();
ws.send(
JSON.stringify({
type: 'runtime',
language: job.runtime.language,
version: job.runtime.version.raw,
})
);
ws.send(
JSON.stringify({
type: 'runtime',
language: job.runtime.language,
version: job.runtime.version.raw,
})
);
await job.execute(box, event_bus);
} catch (error) {
logger.error(
`Error cleaning up job: ${job.uuid}:\n${error}`
);
throw error;
} finally {
await job.cleanup();
}
ws.close(4999, 'Job Completed'); // Will not execute if an error is thrown above
await job.execute_interactive(eventBus);
ws.close(4999, 'Job Completed');
} else {
ws.close(4000, 'Already Initialized');
}
@ -199,7 +230,7 @@ router.ws('/connect', async (ws, req) => {
case 'data':
if (job !== null) {
if (msg.stream === 'stdin') {
event_bus.emit('stdin', msg.data);
eventBus.emit('stdin', msg.data);
} else {
ws.close(4004, 'Can only write to stdin');
}
@ -209,10 +240,8 @@ router.ws('/connect', async (ws, req) => {
break;
case 'signal':
if (job !== null) {
if (
Object.values(globals.SIGNALS).includes(msg.signal)
) {
event_bus.emit('signal', msg.signal);
if (SIGNALS.includes(msg.signal)) {
eventBus.emit('signal', msg.signal);
} else {
ws.close(4005, 'Invalid signal');
}
@ -228,6 +257,12 @@ router.ws('/connect', async (ws, req) => {
}
});
ws.on('close', async () => {
if (job !== null) {
await job.cleanup();
}
});
setTimeout(() => {
//Terminate the socket after 1 second, if not initialized.
if (job === null) ws.close(4001, 'Initialization Timeout');
@ -235,32 +270,18 @@ router.ws('/connect', async (ws, req) => {
});
router.post('/execute', async (req, res) => {
let job;
try {
job = await get_job(req.body);
} catch (error) {
return res.status(400).json(error);
}
try {
const box = await job.prime();
const job = await get_job(req.body);
let result = await job.execute(box);
// Backward compatibility when the run stage is not started
if (result.run === undefined) {
result.run = result.compile;
}
await job.prime();
const result = await job.execute();
await job.cleanup();
return res.status(200).send(result);
} catch (error) {
logger.error(`Error executing job: ${job.uuid}:\n${error}`);
return res.status(500).send();
} finally {
try {
await job.cleanup(); // This gets executed before the returns in try/catch
} catch (error) {
logger.error(`Error cleaning up job: ${job.uuid}:\n${error}`);
return res.status(500).send(); // On error, this replaces the return in the outer try-catch
}
return res.status(400).json(error);
}
});

View file

@ -90,18 +90,6 @@ const options = {
parser: parse_int,
validators: [(x, raw) => !is_nan(x) || `${raw} is not a number`],
},
compile_cpu_time: {
desc: 'Max CPU time allowed for compile stage in milliseconds',
default: 10000, // 10 seconds
parser: parse_int,
validators: [(x, raw) => !is_nan(x) || `${raw} is not a number`],
},
run_cpu_time: {
desc: 'Max CPU time allowed for run stage in milliseconds',
default: 3000, // 3 seconds
parser: parse_int,
validators: [(x, raw) => !is_nan(x) || `${raw} is not a number`],
},
compile_memory_limit: {
desc: 'Max memory usage for compile stage in bytes (set to -1 for no limit)',
default: -1, // no limit
@ -129,7 +117,7 @@ const options = {
limit_overrides: {
desc: 'Per-language exceptions in JSON format for each of:\
max_process_count, max_open_files, max_file_size, compile_memory_limit,\
run_memory_limit, compile_timeout, run_timeout, compile_cpu_time, run_cpu_time, output_max_size',
run_memory_limit, compile_timeout, run_timeout, output_max_size',
default: {},
parser: parse_overrides,
validators: [
@ -177,8 +165,6 @@ function parse_overrides(overrides_string) {
'run_memory_limit',
'compile_timeout',
'run_timeout',
'compile_cpu_time',
'run_cpu_time',
'output_max_size',
].includes(key)
) {

View file

@ -1,29 +0,0 @@
#!/bin/bash
CGROUP_FS="/sys/fs/cgroup"
if [ ! -e "$CGROUP_FS" ]; then
echo "Cannot find $CGROUP_FS. Please make sure your system is using cgroup v2"
exit 1
fi
if [ -e "$CGROUP_FS/unified" ]; then
echo "Combined cgroup v1+v2 mode is not supported. Please make sure your system is using pure cgroup v2"
exit 1
fi
if [ ! -e "$CGROUP_FS/cgroup.subtree_control" ]; then
echo "Cgroup v2 not found. Please make sure cgroup v2 is enabled on your system"
exit 1
fi
cd /sys/fs/cgroup && \
mkdir isolate/ && \
echo 1 > isolate/cgroup.procs && \
echo '+cpuset +cpu +io +memory +pids' > cgroup.subtree_control && \
cd isolate && \
mkdir init && \
echo 1 > init/cgroup.procs && \
echo '+cpuset +memory' > cgroup.subtree_control && \
echo "Initialized cgroup" && \
chown -R piston:piston /piston && \
exec su -- piston -c 'ulimit -n 65536 && node /piston_api/src'

View file

@ -7,78 +7,14 @@ const platform = `${is_docker() ? 'docker' : 'baremetal'}-${fs
.split('\n')
.find(x => x.startsWith('ID'))
.replace('ID=', '')}`;
const SIGNALS = {
1: 'SIGHUP',
2: 'SIGINT',
3: 'SIGQUIT',
4: 'SIGILL',
5: 'SIGTRAP',
6: 'SIGABRT',
7: 'SIGBUS',
8: 'SIGFPE',
9: 'SIGKILL',
10: 'SIGUSR1',
11: 'SIGSEGV',
12: 'SIGUSR2',
13: 'SIGPIPE',
14: 'SIGALRM',
15: 'SIGTERM',
16: 'SIGSTKFLT',
17: 'SIGCHLD',
18: 'SIGCONT',
19: 'SIGSTOP',
20: 'SIGTSTP',
21: 'SIGTTIN',
22: 'SIGTTOU',
23: 'SIGURG',
24: 'SIGXCPU',
25: 'SIGXFSZ',
26: 'SIGVTALRM',
27: 'SIGPROF',
28: 'SIGWINCH',
29: 'SIGIO',
30: 'SIGPWR',
31: 'SIGSYS',
34: 'SIGRTMIN',
35: 'SIGRTMIN+1',
36: 'SIGRTMIN+2',
37: 'SIGRTMIN+3',
38: 'SIGRTMIN+4',
39: 'SIGRTMIN+5',
40: 'SIGRTMIN+6',
41: 'SIGRTMIN+7',
42: 'SIGRTMIN+8',
43: 'SIGRTMIN+9',
44: 'SIGRTMIN+10',
45: 'SIGRTMIN+11',
46: 'SIGRTMIN+12',
47: 'SIGRTMIN+13',
48: 'SIGRTMIN+14',
49: 'SIGRTMIN+15',
50: 'SIGRTMAX-14',
51: 'SIGRTMAX-13',
52: 'SIGRTMAX-12',
53: 'SIGRTMAX-11',
54: 'SIGRTMAX-10',
55: 'SIGRTMAX-9',
56: 'SIGRTMAX-8',
57: 'SIGRTMAX-7',
58: 'SIGRTMAX-6',
59: 'SIGRTMAX-5',
60: 'SIGRTMAX-4',
61: 'SIGRTMAX-3',
62: 'SIGRTMAX-2',
63: 'SIGRTMAX-1',
64: 'SIGRTMAX',
};
module.exports = {
data_directories: {
packages: 'packages',
jobs: 'jobs',
},
version: require('../package.json').version,
platform,
pkg_installed_file: '.ppman-installed', //Used as indication for if a package was installed
clean_directories: ['/dev/shm', '/run/lock', '/tmp', '/var/tmp'],
SIGNALS,
};

View file

@ -35,6 +35,7 @@ expressWs(app);
}
}
});
fss.chmodSync(path.join(config.data_directory, globals.data_directories.jobs), 0o711)
logger.info('Loading packages');
const pkgdir = path.join(
@ -78,12 +79,6 @@ expressWs(app);
const api_v2 = require('./api/v2');
app.use('/api/v2', api_v2);
const { version } = require('../package.json');
app.get('/', (req, res, next) => {
return res.status(200).send({ message: `Piston v${version}` });
});
app.use((req, res, next) => {
return res.status(404).send({ message: 'Not Found' });
});
@ -91,12 +86,7 @@ expressWs(app);
logger.debug('Calling app.listen');
const [address, port] = config.bind_address.split(':');
const server = app.listen(port, address, () => {
app.listen(port, address, () => {
logger.info('API server started on', config.bind_address);
});
process.on('SIGTERM', () => {
server.close();
process.exit(0)
});
})();

View file

@ -1,10 +1,13 @@
const logplease = require('logplease');
const logger = logplease.create('job');
const { v4: uuidv4 } = require('uuid');
const cp = require('child_process');
const path = require('path');
const config = require('./config');
const fs = require('fs/promises');
const globals = require('./globals');
const fs = require('fs/promises');
const fss = require('fs');
const wait_pid = require('waitpid');
const job_states = {
READY: Symbol('Ready to be primed'),
@ -12,26 +15,21 @@ const job_states = {
EXECUTED: Symbol('Executed and ready for cleanup'),
};
const MAX_BOX_ID = 999;
const ISOLATE_PATH = '/usr/local/bin/isolate';
let box_id = 0;
let uid = 0;
let gid = 0;
let remaining_job_spaces = config.max_concurrent_jobs;
let job_queue = [];
let jobQueue = [];
const get_next_box_id = () => ++box_id % MAX_BOX_ID;
setInterval(() => {
// Every 10ms try resolve a new job, if there is an available slot
if (jobQueue.length > 0 && remaining_job_spaces > 0) {
jobQueue.shift()();
}
}, 10);
class Job {
#dirty_boxes;
constructor({
runtime,
files,
args,
stdin,
timeouts,
cpu_times,
memory_limits,
}) {
constructor({ runtime, files, args, stdin, timeouts, memory_limits }) {
this.uuid = uuidv4();
this.logger = logplease.create(`job/${this.uuid}`);
@ -47,282 +45,187 @@ class Job {
this.args = args;
this.stdin = stdin;
// Add a trailing newline if it doesn't exist
if (this.stdin.slice(-1) !== '\n') {
this.stdin += '\n';
}
this.timeouts = timeouts;
this.cpu_times = cpu_times;
this.memory_limits = memory_limits;
this.state = job_states.READY;
this.#dirty_boxes = [];
}
this.uid = config.runner_uid_min + uid;
this.gid = config.runner_gid_min + gid;
async #create_isolate_box() {
const box_id = get_next_box_id();
const metadata_file_path = `/tmp/${box_id}-metadata.txt`;
return new Promise((res, rej) => {
cp.exec(
`isolate --init --cg -b${box_id}`,
(error, stdout, stderr) => {
if (error) {
rej(
`Failed to run isolate --init: ${error.message}\nstdout: ${stdout}\nstderr: ${stderr}`
);
}
if (stdout === '') {
rej('Received empty stdout from isolate --init');
}
const box = {
id: box_id,
metadata_file_path,
dir: `${stdout.trim()}/box`,
};
this.#dirty_boxes.push(box);
res(box);
}
);
});
uid++;
gid++;
uid %= config.runner_uid_max - config.runner_uid_min + 1;
gid %= config.runner_gid_max - config.runner_gid_min + 1;
this.logger.debug(`Assigned uid=${this.uid} gid=${this.gid}`);
this.state = job_states.READY;
this.dir = path.join(
config.data_directory,
globals.data_directories.jobs,
this.uuid
);
}
async prime() {
if (remaining_job_spaces < 1) {
this.logger.info(`Awaiting job slot`);
await new Promise(resolve => {
job_queue.push(resolve);
jobQueue.push(resolve);
});
}
this.logger.info(`Priming job`);
remaining_job_spaces--;
this.logger.debug('Running isolate --init');
const box = await this.#create_isolate_box();
this.logger.debug('Writing files to job cache');
this.logger.debug(`Transfering ownership`);
await fs.mkdir(this.dir, { mode: 0o700 });
await fs.chown(this.dir, this.uid, this.gid);
this.logger.debug(`Creating submission files in Isolate box`);
const submission_dir = path.join(box.dir, 'submission');
await fs.mkdir(submission_dir);
for (const file of this.files) {
const file_path = path.join(submission_dir, file.name);
const rel = path.relative(submission_dir, file_path);
const file_path = path.join(this.dir, file.name);
const rel = path.relative(this.dir, file_path);
const file_content = Buffer.from(file.content, file.encoding);
if (rel.startsWith('..'))
throw Error(
`File path "${file.name}" tries to escape parent directory: ${rel}`
);
const file_content = Buffer.from(file.content, file.encoding);
await fs.mkdir(path.dirname(file_path), {
recursive: true,
mode: 0o700,
});
await fs.chown(path.dirname(file_path), this.uid, this.gid);
await fs.write_file(file_path, file_content);
await fs.chown(file_path, this.uid, this.gid);
}
this.state = job_states.PRIMED;
this.logger.debug('Primed job');
return box;
}
async safe_call(
box,
file,
args,
timeout,
cpu_time,
memory_limit,
event_bus = null
) {
let stdout = '';
let stderr = '';
let output = '';
let memory = null;
let code = null;
let signal = null;
let message = null;
let status = null;
let cpu_time_stat = null;
let wall_time_stat = null;
async safe_call(file, args, timeout, memory_limit, eventBus = null) {
return new Promise((resolve, reject) => {
const nonetwork = config.disable_networking ? ['nosocket'] : [];
const proc = cp.spawn(
ISOLATE_PATH,
[
'--run',
`-b${box.id}`,
`--meta=${box.metadata_file_path}`,
'--cg',
'-s',
'-c',
'/box/submission',
'-E',
'HOME=/tmp',
...this.runtime.env_vars.flat_map(v => ['-E', v]),
'-E',
`PISTON_LANGUAGE=${this.runtime.language}`,
`--dir=${this.runtime.pkgdir}`,
`--dir=/etc:noexec`,
`--processes=${this.runtime.max_process_count}`,
`--open-files=${this.runtime.max_open_files}`,
`--fsize=${Math.floor(this.runtime.max_file_size / 1000)}`,
`--wall-time=${timeout / 1000}`,
`--time=${cpu_time / 1000}`,
`--extra-time=0`,
...(memory_limit >= 0
? [`--cg-mem=${Math.floor(memory_limit / 1000)}`]
: []),
...(config.disable_networking ? [] : ['--share-net']),
'--',
'/bin/bash',
path.join(this.runtime.pkgdir, file),
const prlimit = [
'prlimit',
'--nproc=' + this.runtime.max_process_count,
'--nofile=' + this.runtime.max_open_files,
'--fsize=' + this.runtime.max_file_size,
];
const timeout_call = [
'timeout', '-s', '9', Math.ceil(timeout / 1000),
];
if (memory_limit >= 0) {
prlimit.push('--as=' + memory_limit);
}
const proc_call = [
'nice',
...timeout_call,
...prlimit,
...nonetwork,
'bash',
file,
...args,
],
{
];
var stdout = '';
var stderr = '';
var output = '';
const proc = cp.spawn(proc_call[0], proc_call.splice(1), {
env: {
...this.runtime.env_vars,
PISTON_LANGUAGE: this.runtime.language,
},
stdio: 'pipe',
}
);
if (event_bus === null) {
proc.stdin.write(this.stdin);
proc.stdin.end();
proc.stdin.destroy();
} else {
event_bus.on('stdin', data => {
proc.stdin.write(data);
cwd: this.dir,
uid: this.uid,
gid: this.gid,
detached: true, //give this process its own process group
});
event_bus.on('kill', signal => {
proc.kill(signal);
});
}
proc.stderr.on('data', async data => {
if (event_bus !== null) {
event_bus.emit('stderr', data);
} else if (
stderr.length + data.length >
this.runtime.output_max_size
) {
message = 'stderr length exceeded';
status = 'EL';
this.logger.info(message);
try {
process.kill(proc.pid, 'SIGABRT');
} catch (e) {
// Could already be dead and just needs to be waited on
this.logger.debug(
`Got error while SIGABRTing process ${proc}:`,
e
);
}
if (eventBus === null) {
proc.stdin.write(this.stdin);
proc.stdin.end();
proc.stdin.destroy();
} else {
stderr += data;
output += data;
}
});
proc.stdout.on('data', async data => {
if (event_bus !== null) {
event_bus.emit('stdout', data);
} else if (
stdout.length + data.length >
this.runtime.output_max_size
) {
message = 'stdout length exceeded';
status = 'OL';
this.logger.info(message);
try {
process.kill(proc.pid, 'SIGABRT');
} catch (e) {
// Could already be dead and just needs to be waited on
this.logger.debug(
`Got error while SIGABRTing process ${proc}:`,
e
);
}
} else {
stdout += data;
output += data;
}
});
const data = await new Promise((res, rej) => {
proc.on('exit', (_, signal) => {
res({
signal,
eventBus.on('stdin', data => {
proc.stdin.write(data);
});
eventBus.on('kill', signal => {
proc.kill(signal);
});
}
const kill_timeout =
(timeout >= 0 &&
set_timeout(async _ => {
this.logger.info(`Timeout exceeded timeout=${timeout}`);
process.kill(proc.pid, 'SIGKILL');
}, timeout)) ||
null;
proc.stderr.on('data', async data => {
if (eventBus !== null) {
eventBus.emit('stderr', data);
} else if (stderr.length > this.runtime.output_max_size) {
this.logger.info(`stderr length exceeded`);
process.kill(proc.pid, 'SIGKILL');
} else {
stderr += data;
output += data;
}
});
proc.stdout.on('data', async data => {
if (eventBus !== null) {
eventBus.emit('stdout', data);
} else if (stdout.length > this.runtime.output_max_size) {
this.logger.info(`stdout length exceeded`);
process.kill(proc.pid, 'SIGKILL');
} else {
stdout += data;
output += data;
}
});
const exit_cleanup = () => {
clear_timeout(kill_timeout);
proc.stderr.destroy();
proc.stdout.destroy();
this.cleanup_processes();
this.logger.debug(`Finished exit cleanup`);
};
proc.on('exit', (code, signal) => {
exit_cleanup();
resolve({ stdout, stderr, code, signal, output });
});
proc.on('error', err => {
rej({
error: err,
});
exit_cleanup();
reject({ error: err, stdout, stderr, output });
});
});
try {
const metadata_str = (
await fs.read_file(box.metadata_file_path)
).toString();
const metadata_lines = metadata_str.split('\n');
for (const line of metadata_lines) {
if (!line) continue;
const [key, value] = line.split(':');
if (key === undefined || value === undefined) {
throw new Error(
`Failed to parse metadata file, received: ${line}`
);
}
switch (key) {
case 'cg-mem':
memory = parse_int(value) * 1000;
break;
case 'exitcode':
code = parse_int(value);
break;
case 'exitsig':
signal = globals.SIGNALS[parse_int(value)] ?? null;
break;
case 'message':
message = message || value;
break;
case 'status':
status = status || value;
break;
case 'time':
cpu_time_stat = parse_float(value) * 1000;
break;
case 'time-wall':
wall_time_stat = parse_float(value) * 1000;
break;
default:
break;
}
}
} catch (e) {
throw new Error(
`Error reading metadata file: ${box.metadata_file_path}\nError: ${e.message}\nIsolate run stdout: ${stdout}\nIsolate run stderr: ${stderr}`
);
}
return {
...data,
stdout,
stderr,
code,
signal: ['TO', 'OL', 'EL'].includes(status) ? 'SIGKILL' : signal,
output,
memory,
message,
status,
cpu_time: cpu_time_stat,
wall_time: wall_time_stat,
};
}
async execute(box, event_bus = null) {
async execute() {
if (this.state !== job_states.PRIMED) {
throw new Error(
'Job must be in primed state, current state: ' +
@ -339,66 +242,24 @@ class Job {
this.logger.debug('Compiling');
let compile;
let compile_errored = false;
const { emit_event_bus_result, emit_event_bus_stage } =
event_bus === null
? {
emit_event_bus_result: () => {},
emit_event_bus_stage: () => {},
}
: {
emit_event_bus_result: (stage, result) => {
const { error, code, signal } = result;
event_bus.emit('exit', stage, {
error,
code,
signal,
});
},
emit_event_bus_stage: stage => {
event_bus.emit('stage', stage);
},
};
if (this.runtime.compiled) {
this.logger.debug('Compiling');
emit_event_bus_stage('compile');
compile = await this.safe_call(
box,
'compile',
path.join(this.runtime.pkgdir, 'compile'),
code_files.map(x => x.name),
this.timeouts.compile,
this.cpu_times.compile,
this.memory_limits.compile,
event_bus
this.memory_limits.compile
);
emit_event_bus_result('compile', compile);
compile_errored = compile.code !== 0;
if (!compile_errored) {
const old_box_dir = box.dir;
box = await this.#create_isolate_box();
await fs.rename(
path.join(old_box_dir, 'submission'),
path.join(box.dir, 'submission')
);
}
}
let run;
if (!compile_errored) {
this.logger.debug('Running');
emit_event_bus_stage('run');
run = await this.safe_call(
box,
'run',
[code_files[0].name, ...this.args],
this.timeouts.run,
this.cpu_times.run,
this.memory_limits.run,
event_bus
);
emit_event_bus_result('run', run);
}
this.logger.debug('Running');
const run = await this.safe_call(
path.join(this.runtime.pkgdir, 'run'),
[code_files[0].name, ...this.args],
this.timeouts.run,
this.memory_limits.run
);
this.state = job_states.EXECUTED;
@ -410,34 +271,179 @@ class Job {
};
}
async execute_interactive(eventBus) {
if (this.state !== job_states.PRIMED) {
throw new Error(
'Job must be in primed state, current state: ' +
this.state.toString()
);
}
this.logger.info(
`Interactively executing job runtime=${this.runtime.toString()}`
);
const code_files =
(this.runtime.language === 'file' && this.files) ||
this.files.filter(file => file.encoding == 'utf8');
if (this.runtime.compiled) {
eventBus.emit('stage', 'compile');
const { error, code, signal } = await this.safe_call(
path.join(this.runtime.pkgdir, 'compile'),
code_files.map(x => x.name),
this.timeouts.compile,
this.memory_limits.compile,
eventBus
);
eventBus.emit('exit', 'compile', { error, code, signal });
}
this.logger.debug('Running');
eventBus.emit('stage', 'run');
const { error, code, signal } = await this.safe_call(
path.join(this.runtime.pkgdir, 'run'),
[code_files[0].name, ...this.args],
this.timeouts.run,
this.memory_limits.run,
eventBus
);
eventBus.emit('exit', 'run', { error, code, signal });
this.state = job_states.EXECUTED;
}
cleanup_processes(dont_wait = []) {
let processes = [1];
const to_wait = [];
this.logger.debug(`Cleaning up processes`);
while (processes.length > 0) {
processes = [];
const proc_ids = fss.readdir_sync('/proc');
processes = proc_ids.map(proc_id => {
if (isNaN(proc_id)) return -1;
try {
const proc_status = fss.read_file_sync(
path.join('/proc', proc_id, 'status')
);
const proc_lines = proc_status.to_string().split('\n');
const state_line = proc_lines.find(line =>
line.starts_with('State:')
);
const uid_line = proc_lines.find(line =>
line.starts_with('Uid:')
);
const [_, ruid, euid, suid, fuid] = uid_line.split(/\s+/);
const [_1, state, user_friendly] = state_line.split(/\s+/);
const proc_id_int = parse_int(proc_id);
// Skip over any processes that aren't ours.
if(ruid != this.uid && euid != this.uid) return -1;
if (state == 'Z'){
// Zombie process, just needs to be waited, regardless of the user id
if(!to_wait.includes(proc_id_int))
to_wait.push(proc_id_int);
return -1;
}
// We should kill in all other state (Sleep, Stopped & Running)
return proc_id_int;
} catch {
return -1;
}
return -1;
});
processes = processes.filter(p => p > 0);
if (processes.length > 0)
this.logger.debug(`Got processes to kill: ${processes}`);
for (const proc of processes) {
// First stop the processes, but keep their resources allocated so they cant re-fork
try {
process.kill(proc, 'SIGSTOP');
} catch (e) {
// Could already be dead
this.logger.debug(
`Got error while SIGSTOPping process ${proc}:`,
e
);
}
}
for (const proc of processes) {
// Then clear them out of the process tree
try {
process.kill(proc, 'SIGKILL');
} catch(e) {
// Could already be dead and just needs to be waited on
this.logger.debug(
`Got error while SIGKILLing process ${proc}:`,
e
);
}
to_wait.push(proc);
}
}
this.logger.debug(
`Finished kill-loop, calling wait_pid to end any zombie processes`
);
for (const proc of to_wait) {
if (dont_wait.includes(proc)) continue;
wait_pid(proc);
}
this.logger.debug(`Cleaned up processes`);
}
async cleanup_filesystem() {
for (const clean_path of globals.clean_directories) {
const contents = await fs.readdir(clean_path);
for (const file of contents) {
const file_path = path.join(clean_path, file);
try {
const stat = await fs.stat(file_path);
if (stat.uid === this.uid) {
await fs.rm(file_path, {
recursive: true,
force: true,
});
}
} catch (e) {
// File was somehow deleted in the time that we read the dir to when we checked the file
this.logger.warn(`Error removing file ${file_path}: ${e}`);
}
}
}
await fs.rm(this.dir, { recursive: true, force: true });
}
async cleanup() {
this.logger.info(`Cleaning up job`);
this.cleanup_processes(); // Run process janitor, just incase there are any residual processes somehow
await this.cleanup_filesystem();
remaining_job_spaces++;
if (job_queue.length > 0) {
job_queue.shift()();
}
await Promise.all(
this.#dirty_boxes.map(async box => {
cp.exec(
`isolate --cleanup --cg -b${box.id}`,
(error, stdout, stderr) => {
if (error) {
this.logger.error(
`Failed to run isolate --cleanup: ${error.message} on box #${box.id}\nstdout: ${stdout}\nstderr: ${stderr}`
);
}
}
);
try {
await fs.rm(box.metadata_file_path);
} catch (e) {
this.logger.error(
`Failed to remove the metadata directory of box #${box.id}. Error: ${e.message}`
);
}
})
);
}
}

19
api/src/nosocket/Makefile Normal file
View file

@ -0,0 +1,19 @@
CC = gcc
CFLAGS = -O2 -Wall -lseccomp
TARGET = nosocket
BUILD_PATH = ./
INSTALL_PATH = /usr/local/bin/
SOURCE = nosocket.c
all: $(TARGET)
$(TARGET): $(SOURCE)
$(CC) $(BUILD_PATH)$(SOURCE) $(CFLAGS) -o $(TARGET)
install:
mv $(TARGET) $(INSTALL_PATH)
clean:
$(RM) $(TARGET)
$(RM) $(INSTALL_PATH)$(TARGET)

View file

@ -0,0 +1,62 @@
/*
nosocket.c
Disables access to the `socket` syscall and runs a program provided as the first
commandline argument.
*/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <seccomp.h>
int main(int argc, char *argv[])
{
// Disallow any new capabilities from being added
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
// SCMP_ACT_ALLOW lets the filter have no effect on syscalls not matching a
// configured filter rule (allow all by default)
scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
if (!ctx)
{
fprintf(stderr, "Unable to initialize seccomp filter context\n");
return 1;
}
// Add 32 bit and 64 bit architectures to seccomp filter
int rc;
uint32_t arch[] = {SCMP_ARCH_X86_64, SCMP_ARCH_X86, SCMP_ARCH_X32};
// We first remove the existing arch, otherwise our subsequent call to add
// it will fail
seccomp_arch_remove(ctx, seccomp_arch_native());
for (int i = 0; i < sizeof(arch) / sizeof(arch[0]); i++)
{
rc = seccomp_arch_add(ctx, arch[i]);
if (rc != 0)
{
fprintf(stderr, "Unable to add arch: %d\n", arch[i]);
return 1;
}
}
// Add a seccomp rule to the syscall blacklist - blacklist the socket syscall
if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(socket), 0) < 0)
{
fprintf(stderr, "Unable to add seccomp rule to context\n");
return 1;
}
#ifdef DEBUG
seccomp_export_pfc(ctx, 0);
#endif
if (argc < 2)
{
fprintf(stderr, "Usage %s: %s <program name> <arguments>\n", argv[0], argv[0]);
return 1;
}
seccomp_load(ctx);
execvp(argv[1], argv + 1);
return 1;
}

View file

@ -145,11 +145,7 @@ class Package {
await fs.write_file(path.join(this.install_path, '.env'), filtered_env);
logger.debug('Changing Ownership of package directory');
await util.promisify(chownr)(
this.install_path,
process.getuid(),
process.getgid()
);
await util.promisify(chownr)(this.install_path, 0, 0);
logger.debug('Writing installed state to disk');
await fs.write_file(

View file

@ -15,7 +15,6 @@ class Runtime {
pkgdir,
runtime,
timeouts,
cpu_times,
memory_limits,
max_process_count,
max_open_files,
@ -28,7 +27,6 @@ class Runtime {
this.pkgdir = pkgdir;
this.runtime = runtime;
this.timeouts = timeouts;
this.cpu_times = cpu_times;
this.memory_limits = memory_limits;
this.max_process_count = max_process_count;
this.max_open_files = max_open_files;
@ -64,18 +62,6 @@ class Runtime {
language_limit_overrides
),
},
cpu_times: {
compile: this.compute_single_limit(
language_name,
'compile_cpu_time',
language_limit_overrides
),
run: this.compute_single_limit(
language_name,
'run_cpu_time',
language_limit_overrides
),
},
memory_limits: {
compile: this.compute_single_limit(
language_name,
@ -178,7 +164,15 @@ class Runtime {
const env_file = path.join(this.pkgdir, '.env');
const env_content = fss.read_file_sync(env_file).toString();
this._env_vars = env_content.trim().split('\n');
this._env_vars = {};
env_content
.trim()
.split('\n')
.map(line => line.split('=', 2))
.forEach(([key, val]) => {
this._env_vars[key.trim()] = val.trim();
});
}
return this._env_vars;

View file

@ -23,20 +23,20 @@ fetch_packages(){
mkdir build
# Start a piston container
docker run \
--privileged \
-v "$PWD/build":'/piston/packages' \
--tmpfs /piston/jobs \
-dit \
-p $port:2000 \
--name builder_piston_instance \
ghcr.io/engineer-man/piston
# Ensure the CLI is installed
cd ../cli
npm i
cd -
# Evalulate the specfile
../cli/index.js -u "http://127.0.0.1:$port" ppman spec $1
../cli/index.js -u "http://127.0.0.1:$port" ppman spec $1
}
build_container(){
@ -61,4 +61,4 @@ fetch_packages $SPEC_FILE
build_container $TAG
echo "Start your custom piston container with"
echo "$ docker run --privileged -dit -p 2000:2000 $TAG"
echo "$ docker run --tmpfs /piston/jobs -dit -p 2000:2000 $TAG"

View file

@ -4,7 +4,8 @@ services:
api:
build: api
container_name: piston_api
privileged: true
cap_add:
- CAP_SYS_ADMIN
restart: always
ports:
- 2000:2000
@ -12,6 +13,8 @@ services:
- ./data/piston/packages:/piston/packages
environment:
- PISTON_REPO_URL=http://repo:8000/index
tmpfs:
- /piston/jobs:exec,uid=1000,gid=1000,mode=711
repo: # Local testing of packages
build: repo

View file

@ -5,10 +5,10 @@ services:
image: ghcr.io/engineer-man/piston
container_name: piston_api
restart: always
privileged: true
ports:
- 2000:2000
volumes:
- ./data/piston/packages:/piston/packages
tmpfs:
- /piston/jobs:exec,uid=1000,gid=1000,mode=711
- /tmp:exec

View file

@ -135,21 +135,8 @@ key:
default: 3000
```
The maximum time that is allowed to be taken by a stage in milliseconds. This is the wall-time of the stage. The time that the CPU does not spend working on the stage (e.g, due to context switches or IO) is counted.
## Compile/Run CPU-Time
```yaml
key:
- PISTON_COMPILE_CPU_TIME
default: 10000
key:
- PISTON_RUN_CPU_TIME
default: 3000
```
The maximum CPU-time that is allowed to be consumed by a stage in milliseconds. The time that the CPU does not spend working on the stage (e.g, IO and context switches) is not counted. This option is typically used in algorithm contests.
The maximum time that is allowed to be taken by a stage in milliseconds.
Use -1 for unlimited time.
## Compile/Run memory limits
@ -191,7 +178,7 @@ default: {}
```
Per-language overrides/exceptions for the each of `max_process_count`, `max_open_files`, `max_file_size`,
`compile_memory_limit`, `run_memory_limit`, `compile_timeout`, `run_timeout`, `compile_cpu_time`, `run_cpu_time`, `output_max_size`. Defined as follows:
`compile_memory_limit`, `run_memory_limit`, `compile_timeout`, `run_timeout`, `output_max_size`. Defined as follows:
```
PISTON_LIMIT_OVERRIDES={"c++":{"max_process_count":128}}

View file

@ -1,9 +0,0 @@
#!/usr/bin/env bash
# build octave as dependency
source ../../octave/6.2.0/build.sh
# curl MATL 22.7.4
curl -L "https://github.com/lmendo/MATL/archive/refs/tags/22.7.4.tar.gz" -o MATL.tar.xz
tar xf MATL.tar.xz --strip-components=1
rm MATL.tar.xz

View file

@ -1,5 +0,0 @@
#!/usr/bin/env bash
# Path to MATL binary
export PATH=$PWD/bin:$PATH
export MATL_PATH=$PWD

View file

@ -1,5 +0,0 @@
{
"language": "matl",
"version": "22.7.4",
"aliases": []
}

View file

@ -1,13 +0,0 @@
#!/usr/bin/env bash
# get file as first argument
file="$1"
# remove the file from $@
shift
# use the rest of the arguments as stdin
stdin=`printf "%s\n" "$@"`
# pass stdin into octave which will run MATL
echo "$stdin" | octave -W -p "$MATL_PATH" --eval "matl -of '$file'"

View file

@ -1 +0,0 @@
'OK'

View file

@ -1,20 +0,0 @@
#!/usr/bin/env bash
# Put instructions to build your package in here
PREFIX=$(realpath $(dirname $0))
mkdir -p build
cd build
curl "https://ftp.gnu.org/gnu/bash/bash-5.2.tar.gz" -o bash.tar.gz
tar xzf bash.tar.gz --strip-components=1
# === autoconf based ===
./configure --prefix "$PREFIX"
make -j$(nproc)
make install -j$(nproc)
cd ../
rm -rf build

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Put 'export' statements here for environment variables
export PATH=$PWD/bin:$PATH

View file

@ -1,5 +0,0 @@
{
"language": "bash",
"version": "5.2.0",
"aliases": ["sh"]
}

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Put instructions to run the runtime
bash "$@"

View file

@ -1 +0,0 @@
echo "OK"

View file

@ -2,6 +2,6 @@
PREFIX=$(realpath $(dirname $0))
curl -L "https://github.com/crystal-lang/crystal/releases/download/1.9.2/crystal-1.9.2-1-linux-x86_64.tar.gz" -o crystal.tar.gz
curl -L "https://github.com/crystal-lang/crystal/releases/download/0.36.1/crystal-0.36.1-1-linux-x86_64.tar.gz" -o crystal.tar.gz
tar xzf crystal.tar.gz --strip-components=1
rm crystal.tar.gz

View file

@ -1,5 +1,5 @@
{
"language": "crystal",
"version": "1.9.2",
"version": "0.36.1",
"aliases": ["crystal", "cr"]
}

View file

@ -1,11 +0,0 @@
#!/usr/bin/env bash
curl -L "https://storage.googleapis.com/dart-archive/channels/stable/release/2.19.6/sdk/dartsdk-linux-x64-release.zip" -o dart.zip
unzip dart.zip
rm dart.zip
cp -r dart-sdk/* .
rm -rf dart-sdk
chmod -R +rx bin

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Put 'export' statements here for environment variables
export PATH=$PWD/bin:$PATH

View file

@ -1,5 +0,0 @@
{
"language": "dart",
"version": "2.19.6",
"aliases": []
}

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Put instructions to run the runtime
dart run "$@"

View file

@ -1,3 +0,0 @@
void main() {
print('OK');
}

View file

@ -1,11 +0,0 @@
#!/usr/bin/env bash
curl -L "https://storage.googleapis.com/dart-archive/channels/stable/release/3.0.1/sdk/dartsdk-linux-x64-release.zip" -o dart.zip
unzip dart.zip
rm dart.zip
cp -r dart-sdk/* .
rm -rf dart-sdk
chmod -R +rx bin

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Put 'export' statements here for environment variables
export PATH=$PWD/bin:$PATH

View file

@ -1,5 +0,0 @@
{
"language": "dart",
"version": "3.0.1",
"aliases": []
}

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Put instructions to run the runtime
dart run "$@"

View file

@ -1,3 +0,0 @@
void main() {
print('OK');
}

View file

@ -1,3 +1,3 @@
#!/bin/bash
DENO_DIR=$PWD NO_COLOR=true deno run $@
DENO_DIR=$PWD deno run $@

View file

@ -1,5 +0,0 @@
#!/bin/bash
curl -OL https://github.com/denoland/deno/releases/download/v1.32.3/deno-x86_64-unknown-linux-gnu.zip
unzip -o deno-x86_64-unknown-linux-gnu.zip
rm deno-x86_64-unknown-linux-gnu.zip

View file

@ -1,3 +0,0 @@
#!/bin/bash
export PATH=$PWD:$PATH

View file

@ -1,20 +0,0 @@
{
"language": "deno",
"version": "1.32.3",
"dependencies": {},
"provides": [
{
"language": "typescript",
"aliases": [
"deno",
"deno-ts"
]
},
{
"language": "javascript",
"aliases": [
"deno-js"
]
}
]
}

View file

@ -1,3 +0,0 @@
#!/bin/bash
DENO_DIR=$PWD NO_COLOR=true deno run $@

View file

@ -1 +0,0 @@
console.log("OK")

View file

@ -1,2 +1,2 @@
#!/bin/bash
DENO_DIR=$PWD NO_COLOR=true deno run "$@"
DENO_DIR=$PWD deno run "$@"

View file

@ -1,5 +0,0 @@
#!/usr/bin/env bash
curl -L "https://sourceforge.net/projects/fbc/files/FreeBASIC-1.09.0/Binaries-Linux/FreeBASIC-1.09.0-linux-x86_64.tar.gz/download" -o freebasic.tar.gz
tar xf freebasic.tar.gz --strip-components=1
rm freebasic.tar.gz

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Compile bas files
fbc -lang qb -b "$@" -x out

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Path to fbc compiler
export PATH=$PWD/bin:$PATH

View file

@ -1,5 +0,0 @@
{
"language": "freebasic",
"version": "1.9.0",
"aliases": ["bas", "fbc", "basic", "qbasic", "quickbasic"]
}

View file

@ -1,5 +0,0 @@
#!/usr/bin/env bash
# Run output file from compile with arguments
shift
./out "$@"

View file

@ -1 +0,0 @@
PRINT "OK"

View file

@ -1,21 +0,0 @@
#!/usr/bin/env bash
# Install location
PREFIX=$(realpath $(dirname $0))
mkdir -p build
cd build
# Download and extract Julia source
curl -L "https://github.com/JuliaLang/julia/releases/download/v1.8.5/julia-1.8.5.tar.gz" -o julia.tar.gz
tar xzf julia.tar.gz --strip-components=1
# Build
echo "JULIA_CPU_TARGET=generic;sandybridge,-xsaveopt,clone_all;haswell,-rdrnd,base(1)
prefix=$PREFIX" > Make.user
make -j$(nproc)
make install -j$(nproc)
# Cleanup
cd ..
rm -rf build

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Add Julia binary to path
export PATH=$PWD/bin:$PATH

View file

@ -1,5 +0,0 @@
{
"language": "julia",
"version": "1.8.5",
"aliases": ["jl"]
}

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Run without startup or history file
julia --startup-file=no --history-file=no "$@"

View file

@ -1 +0,0 @@
println("OK")

View file

@ -1,5 +0,0 @@
#!/usr/bin/env bash
# k path
export PATH=$PWD/bin:$PATH
export K_PATH=$PWD/k

View file

@ -1,5 +0,0 @@
{
"language": "k",
"version": "1.0.0",
"aliases": ["ngnk"]
}

View file

@ -1 +0,0 @@
`0:`c$2/'((1 0 0 1 1 1 1);(1 0 0 1 0 1 1))

View file

@ -1,13 +0,0 @@
#!/usr/bin/env bash
# Download and extract JDK8
curl -L "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u292-b10/OpenJDK8U-jdk_x64_linux_hotspot_8u292b10.tar.gz" -o jdk.tar.gz
tar xzf jdk.tar.gz --strip-components=1
rm jdk.tar.gz
# Download and extract Kotlin
curl -L "https://github.com/JetBrains/kotlin/releases/download/v1.8.20/kotlin-compiler-1.8.20.zip" -o kotlin.zip
unzip kotlin.zip
rm kotlin.zip
cp -r kotlinc/* .
rm -rf kotlinc

View file

@ -1,6 +0,0 @@
#!/usr/bin/env bash
rename 's/$/\.kt/' "$@" # Add .kt extension
# Compile Kotlin code to a jar file
kotlinc *.kt -include-runtime -d code.jar

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Add java and kotlinc to path
export PATH=$PWD/bin:$PATH

View file

@ -1,5 +0,0 @@
{
"language": "kotlin",
"version": "1.8.20",
"aliases": ["kt"]
}

View file

@ -1,5 +0,0 @@
#!/usr/bin/env bash
# Run jar file
shift
java -jar code.jar "$@"

View file

@ -1,3 +0,0 @@
fun main() {
println("OK")
}

View file

@ -1,14 +0,0 @@
#!/usr/bin/env bash
# Put instructions to build your package in here
curl -R -O -L http://www.lua.org/ftp/lua-5.4.4.tar.gz
tar zxf lua-5.4.4.tar.gz
rm lua-5.4.4.tar.gz
cd lua-5.4.4
# Building Lua
make linux
# To check that Lua has been built correctly
make test
# Installing Lua
make linux install

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Put 'export' statements here for environment variables
export PATH="$PWD/lua-5.4.4/src:$PATH"

View file

@ -1,5 +0,0 @@
{
"language": "lua",
"version": "5.4.4",
"aliases": []
}

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Put instructions to run the runtime
lua "$@"

View file

@ -1 +0,0 @@
print("OK")

View file

@ -5,7 +5,7 @@ PREFIX=$(realpath $(dirname $0))
mkdir -p build/mono build/mono-basic
cd build
curl "https://download.mono-project.com/sources/mono/mono-6.12.0.182.tar.xz" -o mono.tar.xz
curl "https://download.mono-project.com/sources/mono/mono-6.12.0.122.tar.xz" -o mono.tar.xz
curl -L "https://github.com/mono/mono-basic/archive/refs/tags/4.7.tar.gz" -o mono-basic.tar.gz
tar xf mono.tar.xz --strip-components=1 -C mono
tar xf mono-basic.tar.gz --strip-components=1 -C mono-basic

4
packages/k/1.0.0/build.sh → packages/ngnk/1.0.0/build.sh vendored Normal file → Executable file
View file

@ -5,5 +5,5 @@ set -e
git clone "https://codeberg.org/ngn/k" k
cd k
git checkout 544d014afd8dd84b18c2011cabd3aa3d76571ca3
make CC=gcc
git checkout 040f73b56f379a8298cb1747075c9e947dfe0e42
make CC=gcc

View file

@ -1,4 +1,4 @@
#!/usr/bin/env bash
# compiler path
export PATH=$PWD/bin:$PATH
export K_PATH=$PWD/k

5
packages/ngnk/1.0.0/metadata.json vendored Normal file
View file

@ -0,0 +1,5 @@
{
"language": "ngnk",
"version": "1.0.0",
"aliases": ["k"]
}

View file

@ -1,3 +1,3 @@
#!/usr/bin/env bash
$K_PATH/k "$@"
$K_PATH/k "$@"

1
packages/ngnk/1.0.0/test.k vendored Normal file
View file

@ -0,0 +1 @@
`0:"OK"

View file

@ -1,18 +0,0 @@
#!/bin/bash
PREFIX=$(realpath $(dirname $0))
mkdir -p build
cd build
# Prebuilt binary - source *can* be built, but it requires gcc
curl -L "https://nim-lang.org/download/nim-1.6.2-linux_x64.tar.xz" -o nim.tar.xz
tar xf nim.tar.xz --strip-components=1
rm nim.tar.xz
./install.sh "$PREFIX"
cd ../
rm -rf build

View file

@ -1,5 +0,0 @@
#!/usr/bin/env bash
# Compile nim file(s)
nim --hints:off --out:out --nimcache:./ c "$@"
chmod +x out

View file

@ -1 +0,0 @@
export PATH=$PWD/nim/bin:$PATH

View file

@ -1,5 +0,0 @@
{
"language": "nim",
"version": "1.6.2",
"aliases": []
}

View file

@ -1,4 +0,0 @@
#!/bin/bash
shift # Filename is only used to compile
./out "$@"

View file

@ -1 +0,0 @@
echo("OK")

View file

@ -1,4 +0,0 @@
#!/bin/bash
curl "https://nodejs.org/dist/v18.15.0/node-v18.15.0-linux-x64.tar.xz" -o node.tar.xz
tar xf node.tar.xz --strip-components=1
rm node.tar.xz

View file

@ -1 +0,0 @@
export PATH=$PWD/bin:$PATH

View file

@ -1,10 +0,0 @@
{
"language": "node",
"version": "18.15.0",
"provides": [
{
"language": "javascript",
"aliases": ["node-javascript", "node-js", "javascript", "js"]
}
]
}

View file

@ -1,3 +0,0 @@
#!/bin/bash
node "$@"

View file

@ -1 +0,0 @@
console.log('OK');

View file

@ -1,4 +0,0 @@
#!/bin/bash
curl "https://nodejs.org/dist/v20.11.1/node-v20.11.1-linux-x64.tar.xz" -o node.tar.xz
tar xf node.tar.xz --strip-components=1
rm node.tar.xz

View file

@ -1 +0,0 @@
export PATH=$PWD/bin:$PATH

View file

@ -1,10 +0,0 @@
{
"language": "node",
"version": "20.11.1",
"provides": [
{
"language": "javascript",
"aliases": ["node-javascript", "node-js", "javascript", "js"]
}
]
}

View file

@ -1,3 +0,0 @@
#!/bin/bash
node "$@"

Some files were not shown because too many files have changed in this diff Show more