Spaces:
Sleeping
Sleeping
File size: 33,191 Bytes
8581e8a 8c17a4a 8581e8a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Chat2API โ HuggingFace Space ็๏ผๅๆไปถ้จ็ฝฒ็๏ผ
# ๅบไบ Node.js๏ผ้ๆ Chat2API ้กน็ฎ + code-server ๆ้ๅฏๅ IDE
# ๆไน
ๅๅญๅจ๏ผHuggingFace Dataset๏ผๆฏๅฐๆถ่ชๅจๅคไปฝ๏ผ้ๅฏ่ชๅจๆขๅค๏ผ
#
# ไฟฎๅค่ฏดๆ๏ผ
# ๅ็ Dockerfile ็จ RUN cat <<'EOF'> ๅ่ๆฌ๏ผๅ
้จๅตๅฅ heredoc ๆถ
# BuildKit ไผๆๅๆชๆญ๏ผๅฏผ่ด่ๆฌไธบ็ฉบๆไปถ๏ผ่ฟ่กๆถๆฅ exit 127ใ
# ๆฌ็ๆน็จ RUN python3 -c "import base64; open(...).write(base64.b64decode(...))"
# ๅฐๆๆ่ๆฌไปฅ base64 ๅฝขๅผๅ
ๅต๏ผๅฝปๅบ็ปๅผ heredoc ๅตๅฅ้ฎ้ขใ
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
FROM node:24-slim
# โโ 1. ๅบ็ก็ณป็ปไพ่ต + Electron/Chromium ่ฟ่กๅบ + Xvfb โโโโโโโโโโโโโโโโโโโโโโโโโ
RUN apt-get update && apt-get install -y --no-install-recommends \
git openssh-client build-essential python3 python3-pip \
g++ make ca-certificates curl wget nginx \
xvfb \
libgbm1 libglib2.0-0 libnss3 libatk1.0-0 libatk-bridge2.0-0 \
libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 \
libxfixes3 libxrandr2 libpangocairo-1.0-0 libcairo2 \
libasound2 libxtst6 libx11-xcb1 libxcb-dri3-0 \
fonts-liberation libappindicator3-1 xdg-utils \
&& rm -rf /var/lib/apt/lists/*
# โโ 1.1. ๅฎ่ฃ
code-server โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
RUN curl -fsSL https://code-server.dev/install.sh | sh
# โโ 2. ๅฎ่ฃ
GitHub CLI โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
RUN mkdir -p -m 755 /etc/apt/keyrings \
&& out=$(mktemp) && wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg \
&& cat $out | tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
&& chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& mkdir -p -m 755 /etc/apt/sources.list.d \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
| tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& apt-get update \
&& apt-get install -y --no-install-recommends gh \
&& rm -rf /var/lib/apt/lists/* \
&& gh --version
# โโ 3. ๅฎ่ฃ
HuggingFace Hub โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
RUN pip3 install --no-cache-dir huggingface_hub --break-system-packages
# โโ 4. ็ฏๅขไธ Git ้
็ฝฎ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
RUN update-ca-certificates && \
git config --global http.sslVerify false && \
git config --global url."https://github.com/".insteadOf ssh://git@github.com/
# โโ 5. ๅ
้ๅนถๆๅปบ Chat2API ้กน็ฎ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
WORKDIR /app/chat2api
RUN git clone --depth=1 https://github.com/xiaoY233/Chat2API.git . && \
npm install && \
npm run build:linux 2>/dev/null || true
# โโ 6. ็ฏๅขๅ้้ป่ฎคๅผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ENV PORT=7860 \
HOME=/root \
PYTHONUNBUFFERED=1 \
DISPLAY=:99
# โโ 7. ๅ
ๅตๆๆ่ๆฌ๏ผbase64 ็ผ็ ๏ผๅฝปๅบ่ง้ฟ BuildKit heredoc ๅตๅฅๆชๆญ้ฎ้ข๏ผโโโโโโ
# ๆฏไธช RUN ๆไปค็จ python3 ไธ่กๅฎๆ๏ผdecode โ ๅๆไปถ โ ่ฎพๆ้
# ๅ็๏ผbase64 ๅญ็ฌฆไธฒไธญไธๅซไปปไฝ shell ็นๆฎๅญ็ฌฆ๏ผไธๅ heredoc ๅฝฑๅใ
RUN python3 -c "import base64,os; d=base64.b64decode('aW1wb3J0IG9zLCBzeXMsIHRhcmZpbGUsIHNodXRpbApmcm9tIGh1Z2dpbmdmYWNlX2h1YiBpbXBvcnQgSGZBcGksIGhmX2h1Yl9kb3dubG9hZApmcm9tIGRhdGV0aW1lIGltcG9ydCBkYXRldGltZSwgdGltZWRlbHRhCgphcGkgPSBIZkFwaSgpCnJlcG9faWQgPSBvcy5nZXRlbnYoIkhGX0RBVEFTRVQiKQp0b2tlbiAgID0gb3MuZ2V0ZW52KCJIRl9UT0tFTiIpCgpEQVRBX0RJUiA9ICIvcm9vdC8uY2hhdDJhcGkiCgojIOKUgOKUgCDlt6Xlhbflh73mlbAg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpkZWYgX3BhcnNlX3NraXBfbGlzdChlbnZfdmFyKToKICAgIHJhdyA9IG9zLmdldGVudihlbnZfdmFyLCAiIikuc3RyaXAoKQogICAgaWYgbm90IHJhdzoKICAgICAgICByZXR1cm4gc2V0KCkKICAgIHJldHVybiB7cy5zdHJpcCgpLnN0cmlwKCIvIikgZm9yIHMgaW4gcmF3LnNwbGl0KCIsIikgaWYgcy5zdHJpcCgpfQoKZGVmIF9pc19za2lwcGVkKHJlbF9wYXRoLCBza2lwX3NldCk6CiAgICByZWwgPSByZWxfcGF0aC5zdHJpcCgiLyIpCiAgICBmb3Igc2tpcCBpbiBza2lwX3NldDoKICAgICAgICBpZiByZWwgPT0gc2tpcCBvciByZWwuc3RhcnRzd2l0aChza2lwICsgIi8iKToKICAgICAgICAgICAgcmV0dXJuIFRydWUKICAgIHJldHVybiBGYWxzZQoKZGVmIF93YWxrX2xvY2FsKGJhc2VfZGlyLCBza2lwX3NldD1Ob25lKToKICAgIHJlc3VsdHMgPSBbXQogICAgaWYgbm90IG9zLnBhdGguaXNkaXIoYmFzZV9kaXIpOgogICAgICAgIHJldHVybiByZXN1bHRzCiAgICBmb3IgZGlycGF0aCwgZGlybmFtZXMsIGZpbGVuYW1lcyBpbiBvcy53YWxrKGJhc2VfZGlyKToKICAgICAgICBmb3IgZm5hbWUgaW4gZmlsZW5hbWVzOgogICAgICAgICAgICBhYnNfcGF0aCA9IG9zLnBhdGguam9pbihkaXJwYXRoLCBmbmFtZSkKICAgICAgICAgICAgcmVsX3RvX2Jhc2UgPSBvcy5wYXRoLnJlbHBhdGgoYWJzX3BhdGgsIGJhc2VfZGlyKQogICAgICAgICAgICBpZiBza2lwX3NldCBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgIHJlbF90b19kYXRhID0gb3MucGF0aC5yZWxwYXRoKGFic19wYXRoLCBEQVRBX0RJUikKICAgICAgICAgICAgICAgIGlmIF9pc19za2lwcGVkKHJlbF90b19kYXRhLCBza2lwX3NldCk6CiAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgcmVzdWx0cy5hcHBlbmQoKGFic19wYXRoLCByZWxfdG9fYmFzZSkpCiAgICByZXR1cm4gcmVzdWx0cwoKIyDilIDilIAgcmVzdG9yZSgpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKZGVmIHJlc3RvcmUoKToKICAgIGlmIG5vdCByZXBvX2lkIG9yIG5vdCB0b2tlbjoKICAgICAgICBwcmludCgiU2tpcCBSZXN0b3JlOiBIRl9EQVRBU0VUIG9yIEhGX1RPS0VOIG5vdCBzZXQiKQogICAgICAgIHJldHVybgoKICAgIHJlc3RvcmVfc2tpcF9yYXcgPSBvcy5nZXRlbnYoIlJFU1RPUkVfU0tJUCIsICIiKS5zdHJpcCgpCiAgICBpZiByZXN0b3JlX3NraXBfcmF3ID09ICJhbGwiOgogICAgICAgIHByaW50KCJSZXN0b3JlIHNraXA6IFJFU1RPUkVfU0tJUD1hbGwsIHNraXBwaW5nIGFsbCByZXN0b3JlLiIpCiAgICAgICAgcmV0dXJuCgogICAgSU5JVF9GTEFHID0gImluaXRpYWxpemVkLmZsYWciCiAgICBmb3JjZV9yZXN0b3JlID0gb3MuZ2V0ZW52KCJGT1JDRV9SRVNUT1JFIiwgIiIpLnN0cmlwKCkubG93ZXIoKSBpbiAoInRydWUiLCAiMSIsICJ5ZXMiKQoKICAgIHRyeToKICAgICAgICBhbGxfZmlsZXMgPSBsaXN0KGFwaS5saXN0X3JlcG9fZmlsZXMocmVwb19pZD1yZXBvX2lkLCByZXBvX3R5cGU9ImRhdGFzZXQiLCB0b2tlbj10b2tlbikpCiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgcHJpbnQoZiJSZXN0b3JlIEVycm9yIChsaXN0X3JlcG9fZmlsZXMpOiB7ZX0iKQogICAgICAgIHJldHVybgoKICAgIGZsYWdfZXhpc3RzID0gSU5JVF9GTEFHIGluIGFsbF9maWxlcwoKICAgIGlmIG5vdCBmbGFnX2V4aXN0cyBhbmQgbm90IGZvcmNlX3Jlc3RvcmU6CiAgICAgICAgcHJpbnQoIlJlc3RvcmUgc2tpcDogaW5pdGlhbGl6ZWQuZmxhZyBub3QgZm91bmQsIGZpcnN0IGRlcGxveS4iKQogICAgICAgIGltcG9ydCBpbwogICAgICAgIGFwaS51cGxvYWRfZmlsZSgKICAgICAgICAgICAgcGF0aF9vcl9maWxlb2JqPWlvLkJ5dGVzSU8oYiJpbml0aWFsaXplZFxuIiksCiAgICAgICAgICAgIHBhdGhfaW5fcmVwbz1JTklUX0ZMQUcsCiAgICAgICAgICAgIHJlcG9faWQ9cmVwb19pZCwKICAgICAgICAgICAgcmVwb190eXBlPSJkYXRhc2V0IiwKICAgICAgICAgICAgdG9rZW49dG9rZW4sCiAgICAgICAgICAgIGNvbW1pdF9tZXNzYWdlPSJDcmVhdGUgaW5pdGlhbGl6ZWQuZmxhZyBvbiBmaXJzdCBkZXBsb3kiLAogICAgICAgICkKICAgICAgICBwcmludCgiaW5pdGlhbGl6ZWQuZmxhZyBjcmVhdGVkIGluIERhdGFzZXQuIikKICAgICAgICByZXR1cm4KCiAgICBpZiBmb3JjZV9yZXN0b3JlOgogICAgICAgIHByaW50KCJSZXN0b3JlOiBGT1JDRV9SRVNUT1JFPXRydWUsIGlnbm9yaW5nIGluaXRpYWxpemVkLmZsYWcuIikKICAgIGVsc2U6CiAgICAgICAgcHJpbnQoIlJlc3RvcmU6IGluaXRpYWxpemVkLmZsYWcgZm91bmQsIG5vcm1hbCByZXN0YXJ0LiIpCgogICAgc2tpcF9zZXQgPSBfcGFyc2Vfc2tpcF9saXN0KCJSRVNUT1JFX1NLSVAiKQoKICAgIHRyeToKICAgICAgICBub3cgPSBkYXRldGltZS5ub3coKQogICAgICAgIGZvciBpIGluIHJhbmdlKDUpOgogICAgICAgICAgICBkYXkgID0gKG5vdyAtIHRpbWVkZWx0YShkYXlzPWkpKS5zdHJmdGltZSgiJVktJW0tJWQiKQogICAgICAgICAgICBuYW1lID0gZiJiYWNrdXBfe2RheX0udGFyLmd6IgogICAgICAgICAgICBpZiBuYW1lIGluIGFsbF9maWxlczoKICAgICAgICAgICAgICAgIHByaW50KGYiRG93bmxvYWRpbmcge25hbWV9Li4uIikKICAgICAgICAgICAgICAgIHBhdGggPSBoZl9odWJfZG93bmxvYWQocmVwb19pZD1yZXBvX2lkLCBmaWxlbmFtZT1uYW1lLCByZXBvX3R5cGU9ImRhdGFzZXQiLCB0b2tlbj10b2tlbikKICAgICAgICAgICAgICAgIG9zLm1ha2VkaXJzKERBVEFfRElSLCBleGlzdF9vaz1UcnVlKQogICAgICAgICAgICAgICAgd2l0aCB0YXJmaWxlLm9wZW4ocGF0aCwgInI6Z3oiKSBhcyB0YXI6CiAgICAgICAgICAgICAgICAgICAgZm9yIG1lbWJlciBpbiB0YXIuZ2V0bWVtYmVycygpOgogICAgICAgICAgICAgICAgICAgICAgICBpZiBfaXNfc2tpcHBlZChtZW1iZXIubmFtZSwgc2tpcF9zZXQpOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpbnQoZiJSZXN0b3JlIHNraXA6IHttZW1iZXIubmFtZX0iKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgICAgICAgICAgdGFyLmV4dHJhY3QobWVtYmVyLCBwYXRoPURBVEFfRElSKQogICAgICAgICAgICAgICAgcHJpbnQoZiJSZXN0b3JlZCBmcm9tIHtuYW1lfSIpCiAgICAgICAgICAgICAgICBicmVhawoKICAgICAgICBpbXBvcnQgaW8KICAgICAgICBhcGkudXBsb2FkX2ZpbGUoCiAgICAgICAgICAgIHBhdGhfb3JfZmlsZW9iaj1pby5CeXRlc0lPKGIiaW5pdGlhbGl6ZWQgYXQgY29udGFpbmVyIHN0YXJ0dXBcbiIpLAogICAgICAgICAgICBwYXRoX2luX3JlcG89SU5JVF9GTEFHLAogICAgICAgICAgICByZXBvX2lkPXJlcG9faWQsCiAgICAgICAgICAgIHJlcG9fdHlwZT0iZGF0YXNldCIsCiAgICAgICAgICAgIHRva2VuPXRva2VuLAogICAgICAgICAgICBjb21taXRfbWVzc2FnZT0iU2V0IGluaXRpYWxpemVkLmZsYWciLAogICAgICAgICkKICAgICAgICBwcmludCgiaW5pdGlhbGl6ZWQuZmxhZyB1cGRhdGVkLiIpCiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgcHJpbnQoZiJSZXN0b3JlIEVycm9yOiB7ZX0iKQoKCiMg4pSA4pSAIGJhY2t1cCgpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKZGVmIGJhY2t1cCgpOgogICAgaWYgbm90IHJlcG9faWQgb3Igbm90IHRva2VuOgogICAgICAgIHByaW50KCJTa2lwIEJhY2t1cDogSEZfREFUQVNFVCBvciBIRl9UT0tFTiBub3Qgc2V0IikKICAgICAgICByZXR1cm4KCiAgICBiYWNrdXBfdGFyX3NraXBfcmF3ID0gb3MuZ2V0ZW52KCJCQUNLVVBfVEFSX1NLSVAiLCAiIikuc3RyaXAoKQogICAgaWYgYmFja3VwX3Rhcl9za2lwX3JhdyA9PSAiYWxsIjoKICAgICAgICBwcmludCgiQmFja3VwIHNraXA6IEJBQ0tVUF9UQVJfU0tJUD1hbGwiKQogICAgICAgIHJldHVybgogICAgdHJ5OgogICAgICAgIHRhcl9za2lwX3NldCA9IF9wYXJzZV9za2lwX2xpc3QoIkJBQ0tVUF9UQVJfU0tJUCIpCiAgICAgICAgZGF5ICA9IGRhdGV0aW1lLm5vdygpLnN0cmZ0aW1lKCIlWS0lbS0lZCIpCiAgICAgICAgbmFtZSA9IGYiYmFja3VwX3tkYXl9LnRhci5neiIKICAgICAgICB3aXRoIHRhcmZpbGUub3BlbihuYW1lLCAidzpneiIpIGFzIHRhcjoKICAgICAgICAgICAgZm9yIGFic19wYXRoLCByZWxfdG9fYmFzZSBpbiBfd2Fsa19sb2NhbChEQVRBX0RJUiwgc2tpcF9zZXQ9dGFyX3NraXBfc2V0KToKICAgICAgICAgICAgICAgIHRhci5hZGQoYWJzX3BhdGgsIGFyY25hbWU9cmVsX3RvX2Jhc2UpCiAgICAgICAgYXBpLnVwbG9hZF9maWxlKHBhdGhfb3JfZmlsZW9iaj1uYW1lLCBwYXRoX2luX3JlcG89bmFtZSwgcmVwb19pZD1yZXBvX2lkLCByZXBvX3R5cGU9ImRhdGFzZXQiLCB0b2tlbj10b2tlbikKICAgICAgICBwcmludChmIkJhY2t1cCB7bmFtZX0gZG9uZS4iKQogICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOgogICAgICAgIHByaW50KGYiQmFja3VwIEVycm9yOiB7ZX0iKQoKCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICBpZiBsZW4oc3lzLmFyZ3YpID4gMSBhbmQgc3lzLmFyZ3ZbMV0gPT0gImJhY2t1cCI6CiAgICAgICAgYmFja3VwKCkKICAgIGVsc2U6CiAgICAgICAgcmVzdG9yZSgpCg=='); open('/usr/local/bin/sync.py','wb').write(d)"
RUN python3 -c "import base64,os,stat; d=base64.b64decode('IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoiIiIKY3MtbWFuYWdlcjogY29kZS1zZXJ2ZXIg5oyJ6ZyA5ZCv5YGc5a6I5oqk6L+b56iLCgrnm5HlkKwgVW5peCBzb2NrZXTvvIzmj5DkvpvkuKTkuKogSFRUUCDnq6/ngrnvvJoKICBHRVQgL3dha2V1cCAgICAtIOinpuWPkeWQr+WKqCBjb2RlLXNlcnZlcu+8iOiLpeacqui/kOihjO+8ie+8jOi/lOWbniLlkK/liqjkuK0i562J5b6F6aG1CiAgR0VUIC9oZWFydGJlYXQgLSDmm7TmlrDmnIDlkI7mtLvot4Pml7bpl7TvvIhuZ2lueCDmr4/mrKHmiJDlip/ku6PnkIYgL2lkZS8g5ZCO6LCD55So77yJCgrlkI7lj7Dlrprml7bku7vliqHvvJoKICDmr48gNjAg56eS5qOA5p+l5LiA5qyh77yM6Iul6LaF6L+HIElERV9JRExFX01JTlVURVMg5YiG6ZKf5pegIGhlYXJ0YmVhdO+8jGtpbGwgY29kZS1zZXJ2ZXIKIiIiCgppbXBvcnQgb3MsIHN5cywgdGltZSwgc2lnbmFsLCBzdWJwcm9jZXNzLCB0aHJlYWRpbmcsIHNvY2tldCwgcmUKZnJvbSBodHRwLnNlcnZlciBpbXBvcnQgSFRUUFNlcnZlciwgQmFzZUhUVFBSZXF1ZXN0SGFuZGxlcgoKIyDilIDilIAg6YWN572uIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApTT0NLX1BBVEggICAgICAgID0gIi90bXAvY3MtbWFuYWdlci5zb2NrIgpDU19QT1JUICAgICAgICAgID0gaW50KG9zLmVudmlyb24uZ2V0KCJDT0RFX1NFUlZFUl9QT1JUIiwgIjEzMzM3IikpCkNTX1BBU1NXT1JEICAgICAgPSBvcy5lbnZpcm9uLmdldCgiQ09ERV9TRVJWRVJfUEFTU1dPUkQiLCAiY2hhbmdlbWUxMjMhIikKSURMRV9NSU5VVEVTICAgICA9IGludChvcy5lbnZpcm9uLmdldCgiSURFX0lETEVfTUlOVVRFUyIsICIzMCIpKQpDSEVDS19JTlRFUlZBTCAgID0gNjAgICAjIOenkgoKIyDilIDilIAg5YWo5bGA54q25oCBIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApjc19wcm9jICAgICAgICAgID0gTm9uZQpsYXN0X2hlYXJ0YmVhdCAgID0gMC4wCmxvY2sgICAgICAgICAgICAgPSB0aHJlYWRpbmcuTG9jaygpCgojIOKUgOKUgCBjb2RlLXNlcnZlciDlkK/lgZwg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpkZWYgc3RhcnRfY3MoKToKICAgIGdsb2JhbCBjc19wcm9jLCBsYXN0X2hlYXJ0YmVhdAogICAgd2l0aCBsb2NrOgogICAgICAgIGlmIGNzX3Byb2MgaXMgbm90IE5vbmUgYW5kIGNzX3Byb2MucG9sbCgpIGlzIE5vbmU6CiAgICAgICAgICAgIHJldHVybiAgIyBhbHJlYWR5IHJ1bm5pbmcKICAgICAgICBwcmludChmIltjcy1tYW5hZ2VyXSBTdGFydGluZyBjb2RlLXNlcnZlciBvbiBwb3J0IHtDU19QT1JUfSIsIGZsdXNoPVRydWUpCiAgICAgICAgZW52ID0gb3MuZW52aXJvbi5jb3B5KCkKICAgICAgICBlbnZbIlBBU1NXT1JEIl0gPSBDU19QQVNTV09SRAogICAgICAgIGNzX3Byb2MgPSBzdWJwcm9jZXNzLlBvcGVuKAogICAgICAgICAgICBbImNvZGUtc2VydmVyIiwKICAgICAgICAgICAgICItLWJpbmQtYWRkciIsIGYiMTI3LjAuMC4xOntDU19QT1JUfSIsCiAgICAgICAgICAgICAiLS1hdXRoIiwgInBhc3N3b3JkIiwKICAgICAgICAgICAgICItLWRpc2FibGUtdGVsZW1ldHJ5IiwKICAgICAgICAgICAgICIvYXBwL2NoYXQyYXBpIl0sCiAgICAgICAgICAgIGVudj1lbnYsCiAgICAgICAgICAgIHN0ZG91dD1zdWJwcm9jZXNzLkRFVk5VTEwsCiAgICAgICAgICAgIHN0ZGVycj1zdWJwcm9jZXNzLkRFVk5VTEwsCiAgICAgICAgKQogICAgICAgIGxhc3RfaGVhcnRiZWF0ID0gdGltZS50aW1lKCkKICAgICAgICBwcmludChmIltjcy1tYW5hZ2VyXSBjb2RlLXNlcnZlciBwaWQ9e2NzX3Byb2MucGlkfSIsIGZsdXNoPVRydWUpCgpkZWYgc3RvcF9jcygpOgogICAgZ2xvYmFsIGNzX3Byb2MKICAgIHdpdGggbG9jazoKICAgICAgICBpZiBjc19wcm9jIGlzIE5vbmUgb3IgY3NfcHJvYy5wb2xsKCkgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHJldHVybgogICAgICAgIHByaW50KCJbY3MtbWFuYWdlcl0gU3RvcHBpbmcgaWRsZSBjb2RlLXNlcnZlciIsIGZsdXNoPVRydWUpCiAgICAgICAgY3NfcHJvYy50ZXJtaW5hdGUoKQogICAgICAgIHRyeToKICAgICAgICAgICAgY3NfcHJvYy53YWl0KHRpbWVvdXQ9MTApCiAgICAgICAgZXhjZXB0IHN1YnByb2Nlc3MuVGltZW91dEV4cGlyZWQ6CiAgICAgICAgICAgIGNzX3Byb2Mua2lsbCgpCiAgICAgICAgY3NfcHJvYyA9IE5vbmUKCmRlZiBpc19jc19ydW5uaW5nKCk6CiAgICB3aXRoIGxvY2s6CiAgICAgICAgcmV0dXJuIGNzX3Byb2MgaXMgbm90IE5vbmUgYW5kIGNzX3Byb2MucG9sbCgpIGlzIE5vbmUKCiMg4pSA4pSAIEhUVFAgaGFuZGxlciDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCldBS0VVUF9IVE1MID0gIiIiXAo8IURPQ1RZUEUgaHRtbD48aHRtbD48aGVhZD4KPG1ldGEgY2hhcnNldD0idXRmLTgiPgo8bWV0YSBodHRwLWVxdWl2PSJyZWZyZXNoIiBjb250ZW50PSIzIj4KPHRpdGxlPklERSDlkK/liqjkuK3igKY8L3RpdGxlPgo8c3R5bGU+CmJvZHl7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjtkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2p1c3RpZnktY29udGVudDpjZW50ZXI7CiAgICAgaGVpZ2h0OjEwMHZoO21hcmdpbjowO2JhY2tncm91bmQ6IzFlMWUyZTtjb2xvcjojY2RkNmY0fQouYm94e3RleHQtYWxpZ246Y2VudGVyfS5zcGlubmVye3dpZHRoOjQ4cHg7aGVpZ2h0OjQ4cHg7Ym9yZGVyOjVweCBzb2xpZCAjMzEzMjQ0OwogICAgIGJvcmRlci10b3AtY29sb3I6Izg5YjRmYTtib3JkZXItcmFkaXVzOjUwJTthbmltYXRpb246c3BpbiAxcyBsaW5lYXIgaW5maW5pdGU7CiAgICAgbWFyZ2luOjAgYXV0byAyMHB4fQpAa2V5ZnJhbWVzIHNwaW57dG97dHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpfX0KPC9zdHlsZT48L2hlYWQ+PGJvZHk+CjxkaXYgY2xhc3M9ImJveCI+CiAgPGRpdiBjbGFzcz0ic3Bpbm5lciI+PC9kaXY+CiAgPGgyPlZTIENvZGUgSURFIOWQr+WKqOS4reKApjwvaDI+CiAgPHA+6aG16Z2i5bCG5ZyoIDMg56eS5ZCO6Ieq5Yqo5Yi35pawPC9wPgo8L2Rpdj48L2JvZHk+PC9odG1sPgoiIiIKCmNsYXNzIEhhbmRsZXIoQmFzZUhUVFBSZXF1ZXN0SGFuZGxlcik6CiAgICBkZWYgbG9nX21lc3NhZ2Uoc2VsZiwgZm10LCAqYXJncyk6CiAgICAgICAgcGFzcyAgIyDpnZnpu5jorr/pl67ml6Xlv5cKCiAgICBkZWYgZG9fR0VUKHNlbGYpOgogICAgICAgIGdsb2JhbCBsYXN0X2hlYXJ0YmVhdAogICAgICAgIHBhdGggPSBzZWxmLnBhdGguc3BsaXQoIj8iKVswXQoKICAgICAgICBpZiBwYXRoID09ICIvaGVhcnRiZWF0IjoKICAgICAgICAgICAgbGFzdF9oZWFydGJlYXQgPSB0aW1lLnRpbWUoKQogICAgICAgICAgICBzZWxmLl9yZXNwb25kKDIwMCwgInRleHQvcGxhaW4iLCBiIm9rIikKCiAgICAgICAgZWxpZiBwYXRoID09ICIvd2FrZXVwIjoKICAgICAgICAgICAgaWYgbm90IGlzX2NzX3J1bm5pbmcoKToKICAgICAgICAgICAgICAgIHN0YXJ0X2NzKCkKICAgICAgICAgICAgICAgICMg562J5b6FIGNvZGUtc2VydmVyIOWwsee7qu+8iOacgOWkmiAzMCDnp5LvvIkKICAgICAgICAgICAgICAgIGZvciBfIGluIHJhbmdlKDMwKToKICAgICAgICAgICAgICAgICAgICB0aW1lLnNsZWVwKDEpCiAgICAgICAgICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgICAgICAgICBpbXBvcnQgdXJsbGliLnJlcXVlc3QKICAgICAgICAgICAgICAgICAgICAgICAgdXJsbGliLnJlcXVlc3QudXJsb3BlbihmImh0dHA6Ly8xMjcuMC4wLjE6e0NTX1BPUlR9LyIsIHRpbWVvdXQ9MSkKICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uOgogICAgICAgICAgICAgICAgICAgICAgICBwYXNzCiAgICAgICAgICAgIHNlbGYuX3Jlc3BvbmQoMjAwLCAidGV4dC9odG1sIiwgV0FLRVVQX0hUTUwuZW5jb2RlKCkpCgogICAgICAgIGVsc2U6CiAgICAgICAgICAgIHNlbGYuX3Jlc3BvbmQoNDA0LCAidGV4dC9wbGFpbiIsIGIibm90IGZvdW5kIikKCiAgICBkZWYgX3Jlc3BvbmQoc2VsZiwgY29kZSwgY3R5cGUsIGJvZHkpOgogICAgICAgIHNlbGYuc2VuZF9yZXNwb25zZShjb2RlKQogICAgICAgIHNlbGYuc2VuZF9oZWFkZXIoIkNvbnRlbnQtVHlwZSIsIGN0eXBlKQogICAgICAgIHNlbGYuc2VuZF9oZWFkZXIoIkNvbnRlbnQtTGVuZ3RoIiwgc3RyKGxlbihib2R5KSkpCiAgICAgICAgc2VsZi5lbmRfaGVhZGVycygpCiAgICAgICAgc2VsZi53ZmlsZS53cml0ZShib2R5KQoKIyDilIDilIAgVW5peCBzb2NrZXQgc2VydmVyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKY2xhc3MgVW5peEhUVFBTZXJ2ZXIoSFRUUFNlcnZlcik6CiAgICBhZGRyZXNzX2ZhbWlseSA9IHNvY2tldC5BRl9VTklYCgogICAgZGVmIHNlcnZlcl9iaW5kKHNlbGYpOgogICAgICAgIGlmIG9zLnBhdGguZXhpc3RzKFNPQ0tfUEFUSCk6CiAgICAgICAgICAgIG9zLnJlbW92ZShTT0NLX1BBVEgpCiAgICAgICAgc3VwZXIoKS5zZXJ2ZXJfYmluZCgpCiAgICAgICAgb3MuY2htb2QoU09DS19QQVRILCAwbzY2NikKCiMg4pSA4pSAIOepuumXsuajgOafpeW+queOryDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCmRlZiBpZGxlX3dhdGNoZXIoKToKICAgIHdoaWxlIFRydWU6CiAgICAgICAgdGltZS5zbGVlcChDSEVDS19JTlRFUlZBTCkKICAgICAgICBpZiBpc19jc19ydW5uaW5nKCk6CiAgICAgICAgICAgIGlkbGVfc2VjcyA9IHRpbWUudGltZSgpIC0gbGFzdF9oZWFydGJlYXQKICAgICAgICAgICAgaWYgaWRsZV9zZWNzID4gSURMRV9NSU5VVEVTICogNjA6CiAgICAgICAgICAgICAgICBwcmludChmIltjcy1tYW5hZ2VyXSBJZGxlIHtpZGxlX3NlY3MvNjA6LjFmfSBtaW4gPiB7SURMRV9NSU5VVEVTfSBtaW4sIHN0b3BwaW5nLiIsIGZsdXNoPVRydWUpCiAgICAgICAgICAgICAgICBzdG9wX2NzKCkKCiMg4pSA4pSAIOS4u+WFpeWPoyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICB3YXRjaGVyID0gdGhyZWFkaW5nLlRocmVhZCh0YXJnZXQ9aWRsZV93YXRjaGVyLCBkYWVtb249VHJ1ZSkKICAgIHdhdGNoZXIuc3RhcnQoKQoKICAgIHNlcnZlciA9IFVuaXhIVFRQU2VydmVyKFNPQ0tfUEFUSCwgSGFuZGxlcikKICAgIHByaW50KGYiW2NzLW1hbmFnZXJdIExpc3RlbmluZyBvbiB7U09DS19QQVRIfSIsIGZsdXNoPVRydWUpCiAgICB0cnk6CiAgICAgICAgc2VydmVyLnNlcnZlX2ZvcmV2ZXIoKQogICAgZXhjZXB0IEtleWJvYXJkSW50ZXJydXB0OgogICAgICAgIHBhc3MK'); p='/usr/local/bin/cs-manager'; open(p,'wb').write(d); os.chmod(p, os.stat(p).st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)"
RUN python3 -c "import base64,os,stat; d=base64.b64decode('IyEvYmluL2Jhc2gKc2V0IC1lCgojIOKUgOKUgCDnjq/looPlj5jph48g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACkxJU1RFTl9QT1JUPSIke1BPUlQ6LTc4NjB9IgpDSEFUMkFQSV9QT1JUPTc4NjIKQ09ERV9TRVJWRVJfUE9SVD0iJHtDT0RFX1NFUlZFUl9QT1JUOi0xMzMzN30iCklERV9JRExFX01JTlVURVM9IiR7SURFX0lETEVfTUlOVVRFUzotMzB9IgoKZXhwb3J0IENPREVfU0VSVkVSX1BPUlQgSURFX0lETEVfTUlOVVRFUwpleHBvcnQgQ09ERV9TRVJWRVJfUEFTU1dPUkQ9IiR7Q09ERV9TRVJWRVJfUEFTU1dPUkQ6LWNoYW5nZW1lMTIzIX0iCmV4cG9ydCBDSEFUMkFQSV9EQVRBX0RJUj0iL3Jvb3QvLmNoYXQyYXBpIgoKZWNobyAiPT09IENoYXQyQVBJIEh1Z2dpbmdGYWNlIFNwYWNlIOWQr+WKqCA9PT0iCmVjaG8gIuWklumDqOebkeWQrOerr+WPoyAgICA6ICR7TElTVEVOX1BPUlR9IgplY2hvICJDaGF0MkFQSeWGhemDqOerr+WPozogJHtDSEFUMkFQSV9QT1JUfSIKZWNobyAiSURF5YaF6YOo56uv5Y+jICAgICA6ICR7Q09ERV9TRVJWRVJfUE9SVH0iCmVjaG8gIklERemXsue9ruiHquWKqOWFs+mXrSA6ICR7SURFX0lETEVfTUlOVVRFU30gbWluIgoKIyDilIDilIAg5q2l6aqkIDHvvJrku44gSEYgRGF0YXNldCDmgaLlpI3mjIHkuYXljJbmlbDmja4g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmVjaG8gIi0tLSDmgaLlpI3mjIHkuYXljJbphY3nva7mlbDmja4gLS0tIgpweXRob24zIC91c3IvbG9jYWwvYmluL3N5bmMucHkgcmVzdG9yZSB8fCB0cnVlCgojIOKUgOKUgCDmraXpqqQgMu+8muWHhuWkhyBDaGF0MkFQSSDmlbDmja7nm67lvZUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACm1rZGlyIC1wICIke0NIQVQyQVBJX0RBVEFfRElSfS9sb2dzIiAiJHtDSEFUMkFQSV9EQVRBX0RJUn0vc2Vzc2lvbnMiCgojIOiLpeaVsOaNruebruW9leS4jeWtmOWcqOmFjee9ru+8jOS7jiBIRiBTcGFjZSDlj5jph4/nlJ/miJDliJ3lp4vphY3nva4KQ09ORklHX0ZJTEU9IiR7Q0hBVDJBUElfREFUQV9ESVJ9L2NvbmZpZy5qc29uIgppZiBbICEgLWYgIiRDT05GSUdfRklMRSIgXTsgdGhlbgogICAgZWNobyAi55Sf5oiQ5Yid5aeLIGNvbmZpZy5qc29uLi4uIgogICAgcHl0aG9uMyAvdXNyL2xvY2FsL2Jpbi9pbml0LWNvbmZpZy5weQpmaQoKIyDoi6XmlbDmja7nm67lvZXkuI3lrZjlnKjotKbmiLfliJfooajvvIzku44gSEYgU3BhY2Ug5Y+Y6YeP5rOo5YWl5Yid5aeL6LSm5oi3CkFDQ09VTlRTX0ZJTEU9IiR7Q0hBVDJBUElfREFUQV9ESVJ9L2FjY291bnRzLmpzb24iCmlmIFsgISAtZiAiJEFDQ09VTlRTX0ZJTEUiIF07IHRoZW4KICAgIGVjaG8gIueUn+aIkOWIneWniyBhY2NvdW50cy5qc29uLi4uIgogICAgcHl0aG9uMyAvdXNyL2xvY2FsL2Jpbi9pbml0LWFjY291bnRzLnB5CmZpCgojIOKUgOKUgCDmraXpqqQgM++8muWQr+WKqOiZmuaLn+aYvuekuu+8iEVsZWN0cm9uIOmcgOimgSBYIGRpc3BsYXnvvInilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKZWNobyAiLS0tIOWQr+WKqCBYdmZiIOiZmuaLn+aYvuekuiAtLS0iClh2ZmIgOjk5IC1zY3JlZW4gMCAxMjgweDgwMHgyNCAtYWMgK2V4dGVuc2lvbiBHTFggK3JlbmRlciAtbm9yZXNldCAmClhWRkJfUElEPSQhCmV4cG9ydCBESVNQTEFZPTo5OQplY2hvICLnrYnlvoUgWHZmYiDlsLHnu6ouLi4iCnNsZWVwIDIKCiMg4pSA4pSAIOatpemqpCA077ya5ZCv5YqoIENoYXQyQVBJ77yIRWxlY3Ryb24gQXBwSW1hZ2XvvIzlkI7lj7Dov5DooYzvvInilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKZWNobyAiLS0tIOWQr+WKqCBDaGF0MkFQSSDmnI3liqEgKOWGhemDqOerr+WPoyAke0NIQVQyQVBJX1BPUlR9KSAtLS0iCmNkIC9hcHAvY2hhdDJhcGkKCiMg5p+l5om+5p6E5bu65Lqn54mp77ya5LyY5YWI55SoIEFwcEltYWdl77yM5YW25qyh55SoIHVucGFja2VkIOebruW9leWGheeahCBlbGVjdHJvbiDlj6/miafooYzmlofku7YKQVBQSU1BR0U9JChmaW5kIGRpc3QgLW5hbWUgIiouQXBwSW1hZ2UiIC1tYXhkZXB0aCAxIDI+L2Rldi9udWxsIHwgaGVhZCAtMSkKCmlmIFsgLW4gIiRBUFBJTUFHRSIgXTsgdGhlbgogICAgZWNobyAi5L2/55SoIEFwcEltYWdlOiAkQVBQSU1BR0UiCiAgICBDSEFUMkFQSV9QT1JUPSIke0NIQVQyQVBJX1BPUlR9IiBcCiAgICBDSEFUMkFQSV9EQVRBPSIke0NIQVQyQVBJX0RBVEFfRElSfSIgXAogICAgIiRBUFBJTUFHRSIgLS1uby1zYW5kYm94IC0tZGlzYWJsZS1ncHUgMj4mMSBcCiAgICAgICAgfCB0ZWUgIiR7Q0hBVDJBUElfREFUQV9ESVJ9L2xvZ3MvY2hhdDJhcGkubG9nIiAmCmVsc2UKICAgICMg5Zue6YCA77ya5L2/55SoIGVsZWN0cm9uLXZpdGUgZGV2IOaooeW8j++8iOS7jemcgCBESVNQTEFZ77yJCiAgICBlY2hvICJBcHBJbWFnZSDmnKrmib7liLDvvIzlm57pgIDliLAgZWxlY3Ryb24tdml0ZSBkZXYg5qih5byPIgogICAgQ0hBVDJBUElfUE9SVD0iJHtDSEFUMkFQSV9QT1JUfSIgXAogICAgQ0hBVDJBUElfREFUQT0iJHtDSEFUMkFQSV9EQVRBX0RJUn0iIFwKICAgIG5weCBlbGVjdHJvbiAuIC0tbm8tc2FuZGJveCAtLWRpc2FibGUtZ3B1IDI+JjEgXAogICAgICAgIHwgdGVlICIke0NIQVQyQVBJX0RBVEFfRElSfS9sb2dzL2NoYXQyYXBpLmxvZyIgJgpmaQplY2hvICJDaGF0MkFQSSDlt7LlnKjlkI7lj7DlkK/liqgiCgojIOKUgOKUgCDmraXpqqQgNe+8muWQr+WKqCBjcy1tYW5hZ2VyIOWuiOaKpOi/m+eoi++8iOWQjuWPsO+8ieKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAplY2hvICItLS0g5ZCv5YqoIElERSDmjInpnIDnrqHnkIblmaggLS0tIgpweXRob24zIC91c3IvbG9jYWwvYmluL2NzLW1hbmFnZXIgMj4mMSB8IHRlZSAiJHtDSEFUMkFQSV9EQVRBX0RJUn0vbG9ncy9jcy1tYW5hZ2VyLmxvZyIgJgoKIyDnrYnlvoUgY3MtbWFuYWdlciBzb2NrZXQg5bCx57uq77yI5pyA5aSaIDEwIOenku+8iQpmb3IgaSBpbiAkKHNlcSAxIDIwKTsgZG8KICBpZiBbIC1TIC90bXAvY3MtbWFuYWdlci5zb2NrIF07IHRoZW4KICAgIGVjaG8gImNzLW1hbmFnZXIgc29ja2V0IOWwsee7qiIKICAgIGJyZWFrCiAgZmkKICBzbGVlcCAwLjUKZG9uZQoKIyDilIDilIAg5q2l6aqkIDbvvJrnrYnlvoUgQ2hhdDJBUEkg5pyN5Yqh5bCx57uq77yI5pyA5aSaIDEyMCDnp5LvvInilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKZWNobyAi562J5b6FIENoYXQyQVBJIOacjeWKoeWQr+WKqC4uLiIKZm9yIGkgaW4gJChzZXEgMSA2MCk7IGRvCiAgaWYgY3VybCAtZnNTICJodHRwOi8vMTI3LjAuMC4xOiR7Q0hBVDJBUElfUE9SVH0vIiA+L2Rldi9udWxsIDI+JjE7IHRoZW4KICAgIGVjaG8gIkNoYXQyQVBJIOacjeWKoeW3suWwsee7qu+8iCR7aX0qMnPvvIkiCiAgICBicmVhawogIGZpCiAgc2xlZXAgMgpkb25lCgojIOKUgOKUgCDmraXpqqQgN++8muWQr+WKqOWumuaXtuWkh+S7veW+queOr++8iOavjyA2MCDliIbpkp/vvInilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKKHdoaWxlIHRydWU7IGRvIHNsZWVwIDM2MDA7IHB5dGhvbjMgL3Vzci9sb2NhbC9iaW4vc3luYy5weSBiYWNrdXAgfHwgdHJ1ZTsgZG9uZSkgJgplY2hvICLmjIHkuYXljJblpIfku73lvqrnjq/lt7LlkK/liqjvvIjmr4/lsI/ml7blpIfku73kuIDmrKHvvIkiCgojIOKUgOKUgCDmraXpqqQgOO+8mueUn+aIkCBuZ2lueCDphY3nva7lubblkK/liqgg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnJtIC1mIC9ldGMvbmdpbngvc2l0ZXMtZW5hYmxlZC9kZWZhdWx0IC9ldGMvbmdpbngvY29uZi5kL2RlZmF1bHQuY29uZgoKTkdJTlhfQ09ORj0iL2V0Yy9uZ2lueC9jb25mLmQvY2hhdDJhcGkuY29uZiIKCnB5dGhvbjMgLSA8PFBZRU9GCmltcG9ydCBvcwpsaXN0ZW4gICA9IG9zLmVudmlyb24uZ2V0KCJQT1JUIiwgIjc4NjAiKQpjc19wb3J0ICA9IG9zLmVudmlyb24uZ2V0KCJDT0RFX1NFUlZFUl9QT1JUIiwgIjEzMzM3IikKYXBpX3BvcnQgPSAiNzg2MiIKCmNvbmYgPSBmIiIiCnVwc3RyZWFtIGNzX21hbmFnZXIge3sKICAgIHNlcnZlciB1bml4Oi90bXAvY3MtbWFuYWdlci5zb2NrOwp9fQoKc2VydmVyIHt7CiAgICBsaXN0ZW4ge2xpc3Rlbn07CiAgICBzZXJ2ZXJfbmFtZSBfOwogICAgY2xpZW50X21heF9ib2R5X3NpemUgMTAwTTsKCiAgICBhY2Nlc3NfbG9nIC9kZXYvc3Rkb3V0OwogICAgZXJyb3JfbG9nICAvZGV2L3N0ZGVyciB3YXJuOwoKICAgIGFic29sdXRlX3JlZGlyZWN0IG9mZjsKICAgIHBvcnRfaW5fcmVkaXJlY3Qgb2ZmOwoKICAgIGxvY2F0aW9uIC9pZGUvIHt7CiAgICAgICAgcHJveHlfcGFzcyBodHRwOi8vMTI3LjAuMC4xOntjc19wb3J0fS87CiAgICAgICAgcHJveHlfaHR0cF92ZXJzaW9uIDEuMTsKICAgICAgICBwcm94eV9zZXRfaGVhZGVyIEhvc3QgXCRob3N0OwogICAgICAgIHByb3h5X3NldF9oZWFkZXIgVXBncmFkZSBcJGh0dHBfdXBncmFkZTsKICAgICAgICBwcm94eV9zZXRfaGVhZGVyIENvbm5lY3Rpb24gInVwZ3JhZGUiOwogICAgICAgIHByb3h5X3NldF9oZWFkZXIgWC1Gb3J3YXJkZWQtRm9yIFwkcHJveHlfYWRkX3hfZm9yd2FyZGVkX2ZvcjsKICAgICAgICBwcm94eV9zZXRfaGVhZGVyIFgtRm9yd2FyZGVkLVByb3RvIFwkc2NoZW1lOwogICAgICAgIHByb3h5X3JlZGlyZWN0IC8gL2lkZS87CiAgICAgICAgcHJveHlfcmVhZF90aW1lb3V0IDg2NDAwOwogICAgICAgIHByb3h5X2Nvbm5lY3RfdGltZW91dCAyczsKICAgICAgICBlcnJvcl9wYWdlIDUwMiA1MDQgQGlkZV93YWtldXA7CiAgICAgICAgcG9zdF9hY3Rpb24gL2lkZS1oZWFydGJlYXQvOwogICAgfX0KCiAgICBsb2NhdGlvbiAvaWRlLWhlYXJ0YmVhdC8ge3sKICAgICAgICBpbnRlcm5hbDsKICAgICAgICByZXdyaXRlIF4gL2hlYXJ0YmVhdCBicmVhazsKICAgICAgICBwcm94eV9wYXNzIGh0dHA6Ly9jc19tYW5hZ2VyOwogICAgICAgIHByb3h5X2Nvbm5lY3RfdGltZW91dCAxczsKICAgICAgICBwcm94eV9yZWFkX3RpbWVvdXQgMnM7CiAgICB9fQoKICAgIGxvY2F0aW9uIEBpZGVfd2FrZXVwIHt7CiAgICAgICAgcmV3cml0ZSBeIC93YWtldXAgYnJlYWs7CiAgICAgICAgcHJveHlfcGFzcyBodHRwOi8vY3NfbWFuYWdlcjsKICAgICAgICBwcm94eV9odHRwX3ZlcnNpb24gMS4xOwogICAgICAgIHByb3h5X3NldF9oZWFkZXIgSG9zdCBcJGhvc3Q7CiAgICAgICAgcHJveHlfY29ubmVjdF90aW1lb3V0IDVzOwogICAgICAgIHByb3h5X3JlYWRfdGltZW91dCAzMHM7CiAgICB9fQoKICAgIGxvY2F0aW9uIC8ge3sKICAgICAgICBwcm94eV9wYXNzIGh0dHA6Ly8xMjcuMC4wLjE6e2FwaV9wb3J0fS87CiAgICAgICAgcHJveHlfaHR0cF92ZXJzaW9uIDEuMTsKICAgICAgICBwcm94eV9zZXRfaGVhZGVyIEhvc3QgXCRob3N0OwogICAgICAgIHByb3h5X3NldF9oZWFkZXIgVXBncmFkZSBcJGh0dHBfdXBncmFkZTsKICAgICAgICBwcm94eV9zZXRfaGVhZGVyIENvbm5lY3Rpb24gInVwZ3JhZGUiOwogICAgICAgIHByb3h5X3NldF9oZWFkZXIgWC1Gb3J3YXJkZWQtRm9yIFwkcHJveHlfYWRkX3hfZm9yd2FyZGVkX2ZvcjsKICAgICAgICBwcm94eV9zZXRfaGVhZGVyIFgtRm9yd2FyZGVkLVByb3RvIFwkc2NoZW1lOwogICAgICAgIHByb3h5X3JlYWRfdGltZW91dCA4NjQwMDsKICAgIH19Cn19CiIiIgoKd2l0aCBvcGVuKCIvZXRjL25naW54L2NvbmYuZC9jaGF0MmFwaS5jb25mIiwgInciKSBhcyBmOgogICAgZi53cml0ZShjb25mKQpwcmludCgibmdpbnggY29uZmlnIHdyaXR0ZW4uIikKUFlFT0YKCmVjaG8gIm5naW54IOmFjee9ruW3sueUn+aIkCIKbmdpbnggLXQKZWNobyAi5ZCv5YqoIG5naW5477yI5YmN5Y+w6L+Q6KGM77yM5L+d5oyB5a655Zmo5a2Y5rS777yJLi4uIgpleGVjIG5naW54IC1nICdkYWVtb24gb2ZmOyBlcnJvcl9sb2cgL2Rldi9zdGRlcnIgd2FybjsnCg=='); p='/usr/local/bin/start-chat2api'; open(p,'wb').write(d); os.chmod(p, os.stat(p).st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)"
RUN python3 -c "import base64,os; d=base64.b64decode('aW1wb3J0IG9zLCBqc29uCgpjb25maWcgPSB7CiAgICAicG9ydCI6IGludChvcy5nZXRlbnYoIkNIQVQyQVBJX1BPUlQiLCAiNzg2MiIpKSwKICAgICJhcGlLZXkiOiBvcy5nZXRlbnYoIkNIQVQyQVBJX0FQSV9LRVkiLCAiIiksCiAgICAibG9hZEJhbGFuY2UiOiB7CiAgICAgICAgInN0cmF0ZWd5Ijogb3MuZ2V0ZW52KCJMQl9TVFJBVEVHWSIsICJyb3VuZC1yb2JpbiIpCiAgICB9Cn0KZGF0YV9kaXIgPSBvcy5nZXRlbnYoIkNIQVQyQVBJX0RBVEFfRElSIiwgIi9yb290Ly5jaGF0MmFwaSIpCm9zLm1ha2VkaXJzKGRhdGFfZGlyLCBleGlzdF9vaz1UcnVlKQp3aXRoIG9wZW4ob3MucGF0aC5qb2luKGRhdGFfZGlyLCAiY29uZmlnLmpzb24iKSwgInciKSBhcyBmOgogICAganNvbi5kdW1wKGNvbmZpZywgZiwgaW5kZW50PTIpCnByaW50KCJjb25maWcuanNvbiBpbml0aWFsaXplZC4iKQo='); open('/usr/local/bin/init-config.py','wb').write(d)"
RUN python3 -c "import base64,os; d=base64.b64decode('aW1wb3J0IG9zLCBqc29uCgphY2NvdW50cyA9IFtdCmZvciBpIGluIHJhbmdlKDEsIDExKToKICAgIHB0eXBlID0gb3MuZ2V0ZW52KGYiUFJPVklERVJfe2l9X1RZUEUiLCAiIikuc3RyaXAoKQogICAgdG9rZW4gPSBvcy5nZXRlbnYoZiJQUk9WSURFUl97aX1fVE9LRU4iLCAiIikuc3RyaXAoKQogICAgaWYgcHR5cGUgYW5kIHRva2VuOgogICAgICAgIGFjY291bnRzLmFwcGVuZCh7InByb3ZpZGVyIjogcHR5cGUsICJ0b2tlbiI6IHRva2VuLCAiZW5hYmxlZCI6IFRydWV9KQoKZGF0YV9kaXIgPSBvcy5nZXRlbnYoIkNIQVQyQVBJX0RBVEFfRElSIiwgIi9yb290Ly5jaGF0MmFwaSIpCm9zLm1ha2VkaXJzKGRhdGFfZGlyLCBleGlzdF9vaz1UcnVlKQp3aXRoIG9wZW4ob3MucGF0aC5qb2luKGRhdGFfZGlyLCAiYWNjb3VudHMuanNvbiIpLCAidyIpIGFzIGY6CiAgICBqc29uLmR1bXAoYWNjb3VudHMsIGYsIGluZGVudD0yKQpwcmludChmImFjY291bnRzLmpzb24gaW5pdGlhbGl6ZWQgd2l0aCB7bGVuKGFjY291bnRzKX0gYWNjb3VudChzKS4iKQo='); open('/usr/local/bin/init-accounts.py','wb').write(d)"
# โโ 8. ้ช่ฏ่ๆฌๅๅ
ฅๅฎๆด๏ผๆๅปบๆถๆ ก้ช๏ผๆ้ฎ้ข็ซๅณๆฅ้๏ผโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
RUN for f in /usr/local/bin/sync.py /usr/local/bin/cs-manager /usr/local/bin/start-chat2api /usr/local/bin/init-config.py /usr/local/bin/init-accounts.py; do [ -s "$f" ] || (echo "MISSING or EMPTY: $f" && exit 1); echo "OK $(wc -c < $f)B $f"; done && [ -x /usr/local/bin/cs-manager ] && [ -x /usr/local/bin/start-chat2api ] && echo "All scripts verified."
# โโ 9. ๆด้ฒ็ซฏๅฃ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
EXPOSE 7860
# โโ ่ฎฟ้ฎ่ฏดๆ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Space ๅฏๅจๅ่ฎฟ้ฎๆนๅผ๏ผ
# ไธป็้ข (Chat2API ็ฎก็้ขๆฟ) : https://<your-space>.hf.space/
# API ๆฅๅ
ฅ็ซฏ็น : https://<your-space>.hf.space/v1/
# VS Code IDE : https://<your-space>.hf.space/ide/
#
# ๅฟ
ๅกซ HF Space Secrets๏ผ
# HF_TOKEN โโ HuggingFace ่ฎฟ้ฎไปค็๏ผwrite ๆ้๏ผ
# HF_DATASET โโ Dataset repo ID๏ผๆ ผๅผ๏ผusername/dataset-name
#
# ๅฏ้ Secrets๏ผ
# CHAT2API_API_KEY โโ Chat2API ่ฎฟ้ฎๅฏ้ฅ๏ผ็็ฉบๅๆ ้่ฎค่ฏ๏ผ
# CODE_SERVER_PASSWORD โโ VS Code IDE ็ปๅฝๅฏ็ ๏ผ้ป่ฎค๏ผchangeme123!๏ผ
# IDE_IDLE_MINUTES โโ IDE ้ฒ็ฝฎ่ชๅจๅ
ณ้ญๅ้ๆฐ๏ผ้ป่ฎค๏ผ30๏ผ
# PROVIDER_1_TYPE / PROVIDER_1_TOKEN โโ ้ขๆณจๅ
ฅๆๅกๅ๏ผๆๅค 10 ไธช๏ผ
# LB_STRATEGY โโ ่ด่ฝฝๅ่กก็ญ็ฅ๏ผround-robin / fill-first / failover
# FORCE_RESTORE โโ ่ฎพไธบ true ๅผบๅถไป Dataset ่ฆ็ๆขๅค
CMD ["/usr/local/bin/start-chat2api"]
|