fix: harden repository content and improve access recovery

Sandbox executable MIME aliases, enforce strict Mermaid rendering, and add security regression coverage. Upgrade vulnerable dependencies with archive compatibility checks and Node 22/24 CI. Make repository restoration atomic and provide actionable viewer errors with retry controls.
This commit is contained in:
Thomas Durieux committed 2026-11-02 05:50:34 +00:00
1 parent 772e40debd
commit a301c46a94
21 files changed
+1048 -1051

No files matched your search

+24 -2
View File
@@ -21,15 +21,37 @@ jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
node: [22, 24]
services:
mongodb:
image: mongo:7
ports:
- 27017:27017
options: >-
--health-cmd "mongosh --quiet --eval 'db.adminCommand({ping:1})'"
--health-interval 10s --health-timeout 5s --health-retries 10
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s --health-timeout 3s --health-retries 10
env:
TEST_MONGODB_URI: mongodb://127.0.0.1:27017/dependency_test
PERFORMANCE_MONGO_URI: mongodb://127.0.0.1:27017/perf_test_ci
PERFORMANCE_REDIS_PORT: 6379
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
node-version: ${{ matrix.node }}
cache: npm
- run: npm ci
- run: npm run build
- run: npm audit --omit=dev --audit-level=moderate
- run: npm audit --audit-level=low
- run: npm test
review-consent:
+17
View File
@@ -48,6 +48,23 @@ Local installation requires Node.js 22.15 or newer in the 22.x series,
24.x, or 26 or newer. Run `npm ci` and `npm run build` to install and build.
`npm run dev` uses Node's watch mode; `npm run build:ui` rebuilds browser assets.
For the November 2026 dependency update, install from the committed lockfile
with `npm ci`, rebuild with `npm run build`, and restart the API and streamer
services together. Docker installations should rebuild the application image.
This dependency update does not change MongoDB documents, Redis keys, or queue
formats, so it requires no production data migration. Existing credential
migration requirements still apply when upgrading from an older release.
The [`glob`](https://github.com/advisories/GHSA-3g3m-2fjr-6pw4) and
[`minimatch`](https://github.com/advisories/GHSA-g3hv-75wg-m249) overrides select security fixes unavailable through
the dependency ranges of archive and development tools. Keep them until those
packages accept patched versions. CI checks the full dependency audit and runs
MongoDB migration, Redis session, and archive compatibility tests on Node 22
and 24. To run the database tests locally, point `TEST_MONGODB_URI` and
`PERFORMANCE_MONGO_URI` at disposable MongoDB databases and set
`PERFORMANCE_REDIS_PORT` to a disposable Redis instance. The performance database
name must begin with `perf_test_`; these tests delete their test data.
<details>
<summary>Run your own instance with Docker</summary>
+635 -949
View File
File diff suppressed because it is too large. Load diff
+22 -18
View File
@@ -41,12 +41,12 @@
"build"
],
"dependencies": {
"@aws-sdk/client-s3": "^3.1147.0",
"@aws-sdk/lib-storage": "^3.1147.0",
"@aws-sdk/client-s3": "^3.1161.0",
"@aws-sdk/lib-storage": "^3.1161.0",
"@mongodb-js/zstd": "^1.2.2",
"@octokit/plugin-throttling": "^8.2.0",
"@octokit/rest": "^20.1.2",
"@smithy/node-http-handler": "^4.12.1",
"@smithy/node-http-handler": "^4.14.1",
"archiver": "^7.0.1",
"bullmq": "^5.81.5",
"cacheable-lookup": "^6.1.0",
@@ -54,9 +54,9 @@
"connect-redis": "^10.0.0",
"crypto-js": "^4.2.0",
"decompress-stream-to-s3": "^2.1.1",
"dotenv": "^18.0.6",
"express": "^5.2.1",
"express-rate-limit": "^8.7.1",
"dotenv": "^18.0.9",
"express": "^5.3.0",
"express-rate-limit": "^8.7.2",
"express-session": "^1.19.0",
"express-slow-down": "^3.1.1",
"got": "^11.8.6",
@@ -64,15 +64,15 @@
"isbinaryfile": "^5.0.7",
"marked": "^15.0.12",
"mime-types": "^3.0.2",
"mongoose": "^7.8.12",
"node-schedule": "^2.1.1",
"mongoose": "^7.8.13",
"node-schedule": "^2.1.2",
"parse-github-url": "^1.0.4",
"passport": "^0.7.0",
"passport-github2": "^0.1.12",
"rate-limit-redis": "^6.0.1",
"re2js": "^2.8.6",
"rate-limit-redis": "^6.0.2",
"re2js": "^2.9.1",
"redis": "^5.12.1",
"sanitize-html": "^2.18.0",
"sanitize-html": "^2.18.1",
"ts-custom-error": "^3.3.1",
"unzip-stream": "^0.3.4"
},
@@ -94,23 +94,27 @@
"c8": "^12.0.0",
"chai": "^4.5.0",
"esbuild": "^0.28.2",
"eslint": "^10.12.0",
"eslint": "^10.14.0",
"gulp-clean-css": "^4.3.0",
"gulp-concat": "^2.6.1",
"gulp-uglify": "^3.0.2",
"http-proxy-middleware": "^4.2.0",
"http-proxy-middleware": "^4.2.1",
"jsdom": "^29.1.1",
"knip": "^6.40.0",
"knip": "^6.44.1",
"mocha": "^12.0.3",
"ordered-read-streams": "^2.0.0",
"ts-node": "^10.9.2",
"typescript": "^5.9.3",
"typescript-eslint": "^8.71.1",
"vue": "^3.5.43",
"vue-router": "^4.6.4",
"vinyl-fs": "^4.0.2"
"typescript-eslint": "^8.72.1",
"vinyl-fs": "^4.0.2",
"vue": "^3.5.44",
"vue-router": "^4.6.4"
},
"engines": {
"node": "^22.15.0 || ^24.0.0 || >=26.0.0"
},
"overrides": {
"glob": "^14.0.2",
"minimatch": "^11.0.1"
}
}
+2 -2
View File
@@ -1,8 +1,8 @@
{
"core.min.js": "core.3b07189932.min.js",
"vendor.min.js": "vendor.16ae3c0693.min.js",
"vendor.min.js": "vendor.bc13fa71b6.min.js",
"mermaid.min.js": "mermaid.f848a72d16.min.js",
"all.min.css": "all.904f999bac.min.css",
"all.min.css": "all.84bf1214d6.min.css",
"markdown.min.js": "markdown.44f2e93820.min.js",
"pdf.min.js": "pdf.4d9cc6ff49.min.js",
"notebook.min.js": "notebook.c3144c18ae.min.js",
+1 -1
View File
@@ -6,4 +6,4 @@
*/:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]){color:inherit;text-decoration:none}a:not([href]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unsLine truncated
* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:solid .08em #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{-webkit-transform:scale(1,-1);transform:scale(1,-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1,-1);transform:scale(-1,-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-rotate-90{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{contentLine truncated
*/.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:solid .08em #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{-webkit-transform:scale(1,-1);transform:scale(1,-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1,-1);transform:scale(-1,-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-rotate-90{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{contentLine truncated
+12
View File
@@ -7900,3 +7900,15 @@ input[type="date"], select { color-scheme: light; }
.email-prompt p { margin-bottom: 20px; }
.email-prompt-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; margin-top: 24px; }
body.dark-mode .email-prompt { background: #242320; color: #faf9f6; }
.file-error .viewer-error {
width: 100%;
max-width: 65ch;
padding: 2rem 1rem;
overflow-wrap: anywhere;
font-size: 1rem;
font-weight: 400;
text-align: left;
}
.viewer-error .paper-empty-title { margin-bottom: 1rem; }
.viewer-error p { line-height: 1.6; }
.viewer-error .paper-error-actions { display: flex; flex-wrap: wrap; gap: .75rem; }
+13 -5
View File
@@ -1,4 +1,12 @@
{
"VIEWER_ERRORS": {
"title": "Content could not be loaded",
"access_title": "GitHub access needs attention",
"reader_help": "Reading this repository? You do not need to sign in. Try again after the owner restores access, or let them know this anonymous link is unavailable.",
"owner_help": "Own this repository? If your GitHub account was suspended or recently recovered, sign in to Anonymous GitHub again and check the GitHub connection and repository permissions in your dashboard. Then retry this page. Keep the existing anonymous URL; do not delete the repository to restore access.",
"retry": "Try again",
"dashboard": "Open owner dashboard"
},
"ERRORS": {
"cache_busy": "Downloads are busy. Please try again shortly.",
"invalid_sort": "The selected sort order is invalid.",
@@ -6,9 +14,9 @@
"repository_changed": "The repository changed while processing. Please retry.",
"repository_job_cancelled": "The repository changed or was removed while processing.",
"storage_delete_failed": "Unable to remove cached files. Please try again later.",
"unknown_error": "Unknown error, contact the admin.",
"unreachable": "Anonymous GitHub is unreachable, contact the admin.",
"request_error": "Unable to download the file, check your connection or contact the admin.",
"unknown_error": "We could not load this content. Try again. If it still fails, contact support with the anonymous URL and the time of the error.",
"unreachable": "The service could not complete this request. Wait a moment and try again.",
"request_error": "The connection was interrupted. Check your internet connection and try again.",
"not_found": "The requested resource could not be found.",
"not_connected": "You must be logged in to perform this action.",
"not_authorized": "You do not have permission to perform this action.",
@@ -17,7 +25,7 @@
"user_banned": "Your account has been banned. Contact the admin for more information.",
"repo_access_limited": "GitHub blocked access because the repository's organization restricts third-party OAuth apps. Ask an org owner to approve Anonymous GitHub under Settings → Third-party Access → OAuth app policy, or anonymize a personal fork instead.",
"repo_saml_enforcement": "The repository's organization enforces SAML single sign-on. Authorize your token for that organization (GitHub → Settings → Applications, or re-run the org's SSO sign-in), then retry. Alternatively, anonymize a personal fork.",
"repo_not_found": "The repository was not found on GitHub. Check the URL and spelling, make sure you are signed in to the account that can see it, and confirm the repo isn't hidden under an org that restricts third-party app access.",
"repo_not_found": "Anonymous GitHub cannot access the source repository on GitHub. It may be private, unavailable, or require the owner to reconnect GitHub.",
"repo_empty": "The selected branch has no commits on GitHub. Push at least one commit, or pick a different branch, then retry.",
"repo_not_accessible": "Anonymous GitHub cannot access this repository. Verify the repository exists and that Anonymous GitHub has been authorized for the owning organization.",
"repository_archived": "This repository has been archived and its files are no longer available.",
@@ -118,7 +126,7 @@
"storage_write_size_mismatch": "The downloaded file was smaller than expected. The upstream source may have returned an incomplete response — please try again.",
"storage_read_error": "An error occurred while reading the file from storage — please try again.",
"upstream_error": "A temporary error occurred while fetching from GitHub — please try again.",
"token_expired": "Your GitHub access token has expired. Please log out and log in again to refresh it.",
"token_expired": "The repository owner needs to renew their GitHub connection before this content can be loaded.",
"job_is_active": "This job is currently running — wait for it to finish or remove it first.",
"github_app_access_required": "Allow this repository on GitHub using the read-only access button, then retry. Organization access may require administrator approval.",
"github_app_reconnect_required": "Reconnect your GitHub App account to restore read-only access.",
+1 -1
View File
@@ -63,7 +63,7 @@
window._mermaidLoaded = true;
window._mermaidLoading = false;
if (typeof mermaid !== "undefined") {
mermaid.initialize({ startOnLoad: false, theme: "default", securityLevel: "loose" });
mermaid.initialize({ startOnLoad: false, theme: "default", securityLevel: "strict" });
window.mermaidInitialized = true;
var els = document.querySelectorAll(".mermaid:not([data-processed])");
if (els.length) mermaid.init(undefined, els);
+14 -9
View File
@@ -19,16 +19,21 @@
<p class="paper-error-msg">This repository will be available in <strong>{{ rateLimitCountdown }}</strong>. The page will reload automatically.</p>
</div>
</div>
<div class="file-error container d-flex h-100" v-if="type == &#x27;error&#x27;">
<div class="paper-error-card file-error-card m-auto" role="alert">
<div class="paper-error-eyebrow">Unavailable</div>
<div class="paper-error-title">This content can&rsquo;t be shown</div>
<p class="file-error-msg" v-text="fmt.translate(&quot;ERRORS.&quot; + (content))"></p>
<div class="file-error-actions">
<a href="/" class="btn btn-sm">Back to home</a>
<a href="/faq" class="btn btn-sm">Read the FAQ</a>
<div class="file-error container d-flex h-100" v-if="type == 'error'">
<section class="viewer-error paper-error-card file-error-card m-auto" role="alert" aria-labelledby="viewer-error-title">
<h1 id="viewer-error-title" class="paper-empty-title">{{ fmt.translate(isSourceAccessError() ? 'VIEWER_ERRORS.access_title' : 'VIEWER_ERRORS.title') }}</h1>
<p>{{ fmt.translate('ERRORS.' + content) }}</p>
<template v-if="isSourceAccessError()">
<p>{{ fmt.translate('VIEWER_ERRORS.reader_help') }}</p>
<p>{{ fmt.translate('VIEWER_ERRORS.owner_help') }}</p>
</template>
<div class="paper-error-actions">
<a v-if="!isSourceAccessError()" href="/" class="btn btn-sm">Back to home</a>
<a v-if="!isSourceAccessError()" href="/faq" class="btn btn-sm">Read the FAQ</a>
<button type="button" class="btn btn-primary" @click="retryContent()">{{ fmt.translate('VIEWER_ERRORS.retry') }}</button>
<a v-if="isSourceAccessError()" class="btn btn-outline-ink" href="/dashboard">{{ fmt.translate('VIEWER_ERRORS.dashboard') }}</a>
</div>
</div>
</section>
</div>
<div class="file-error container d-flex h-100" v-if="type == &#x27;loading&#x27; &amp;&amp; !error"><h1 class="paper-empty-title m-auto">Loading&hellip;</h1></div>
<div class="file-error container d-flex h-100" v-if="type == &#x27;empty&#x27;"><h1 class="paper-empty-title m-auto">Empty <em>repository</em>.</h1></div>
+19 -19
View File
@@ -1,6 +1,18 @@
import { reactive, nextTick } from "vue";
import { createTimers, createListeners } from "./state.js";
import { formDraft } from "./drafts.js";
import translations from "../i18n/locale-en.json";
function viewerErrorCode(error) {
let data = error?.data;
if (typeof data === "string") {
try { data = JSON.parse(data); } catch (_) { data = null; }
}
if (typeof data?.error === "string" && Object.prototype.hasOwnProperty.call(translations.ERRORS, data.error)) return data.error;
if (error?.status === -1 || error?.status === 0) return "request_error";
if ([502, 503, 504].includes(error?.status)) return "unreachable";
return "unknown_error";
}
// The mask comes from /api/options; mainController sets it once loaded.
let redactionMask = "XXXX";
@@ -2554,7 +2566,7 @@ export const exploreController = function (state, http, location, params, html,
}, function (err) {
if (destroyed || repoId !== state.repoId) return [];
state.type = "error";
state.content = (err && err.data && err.data.error) || "unknown_error";
state.content = viewerErrorCode(err);
state.files = [];
});
};
@@ -2624,7 +2636,7 @@ export const exploreController = function (state, http, location, params, html,
timers.timeout(function () { getOptions(callback); }, 3000);
} else {
state.type = "error";
state.content = data.error;
state.content = viewerErrorCode(err);
}
}
);
@@ -2749,23 +2761,7 @@ export const exploreController = function (state, http, location, params, html,
(err) => {
if (destroyed || generation !== contentGeneration) return;
state.type = "error";
state.content = "unknown_error";
try {
err.data = JSON.parse(err.data);
if (err.data.error) {
state.content = err.data.error;
} else {
state.content = err.data;
}
} catch (ignore) {
console.log(err);
if (err.status == -1) {
state.content = "request_error";
} else if (err.status == 502) {
// cloudflare error
state.content = "unreachable";
}
}
state.content = viewerErrorCode(err);
}
);
}
@@ -2970,6 +2966,10 @@ export const exploreController = function (state, http, location, params, html,
getContent(state.filePath, state.file);
}
state.isSourceAccessError = () => ["repo_not_found", "token_expired", "github_app_access_required",
"github_app_reconnect_required", "repo_saml_enforcement", "repo_access_limited"].includes(state.content);
state.retryContent = () => init();
function init() {
contentGeneration++;
state.files = [];
+26 -26
View File
@@ -1,63 +1,63 @@
"use strict";(()=>{var hd=Object.defineProperty;var vd=(e,t)=>{for(var n in t)hd(e,n,{get:t[n],enumerable:!0})};var he=["abap","abc","actionscript","ada","alda","apache_conf","apex","applescript","aql","asciidoc","asl","assembly_x86","autohotkey","batchfile","c9search","c_cpp","cirru","clojure","cobol","coffee","coldfusion","crystal","csharp","csound_document","csound_orchestra","csound_score","csp","css","curly","d","dart","diff","django","dockerfile","dot","drools","edifact","eiffel","ejs","elixir","elm","erlang","forth","fortran","fsharp","fsl","ftl","gcode","gherkin","gitignore","glsl","gobstones","golang","graphqlschema","groovy","haml","handlebars","haskell","haskell_cabal","haxe","hjson","html","html_elixir","html_ruby","ini","io","jack","jade","java","javascript","json","json5","jsoniq","jsp","jssm","jsx","julia","kotlin","latex","less","liquid","lisp","livescript","logiql","logtalk","lsl","lua","luapage","lucene","makefile","markdown","mask","matlab","maze","mediawiki","mel","mixal","mushcode","mysql","nginx","nim","nix","nsis","nunjucks","objectivec","ocaml","pascal","perl","perl6","pgsql","php","php_laravel_blade","pig","plain_text","powershell","praat","prisma","prolog","properties","protobuf","puppet","python","qml","r","razor","rdoc","red","redshift","rhtml","rst","ruby","rust","sass","scad","scala","scheme","scss","sh","sjs","slim","smarty","snippets","soy_template","space","sparql","sql","sqlserver","stylus","svg","swift","tcl","terraform","tex","text","textile","toml","tsx","turtle","twig","typescript","vala","vbscript","velocity","verilog","vhdl","visualforce","wollok","xml","xquery","yaml","zeek"];var ve={org:"/script/org.f61f262915.min.js",notebook:"/script/notebook.c3144c18ae.min.js",markdown:"/script/markdown.44f2e93820.min.js",pdf:"/script/pdf.4d9cc6ff49.min.js",editor:"/script/editor.4f142d3adc.min.js"};function hr(e){let t=e.location.hash.slice(1);if(e.history.replaceState(null,"","/review-link"),t.length>2048)return null;let n=new URLSearchParams(t);if([...n.keys()].length!==3||[...n.keys()].some(a=>!["clientId","intentId","token"].includes(a)))return null;let r=n.get("clientId"),s=n.get("intentId"),i=n.get("token");return!/^[a-f0-9]{32}$/.test(r||"")||!/^[a-f0-9]{32}$/.test(s||"")||!/^[a-f0-9]{64}$/.test(i||"")?null:{contract:"4open.artifacts/1",clientId:r,intentId:s,token:i}}function vr(e,t){let{http:n,promises:r,window:s}=t,i=t.takeReviewHandoff(),a=i?{clientId:i.clientId,intentId:i.intentId}:null,u,f,w,h,k,m=!0,E,y=r.defer(),g=()=>[...s.crypto.getRandomValues(new Uint8Array(16))].map(F=>F.toString(16).padStart(2,"0")).join("");Object.assign(e,{repositoryId:"",handoffEnabled:!1,busy:!1,preview:null,acceptAccess:!1,acceptRetention:!1,uncertain:!1,saved:!1,expired:!1,error:i?"":"Open a new artifact link from your submission. This link is missing or invalid."});let _=()=>m&&e.user?.username===k;function R(){m=!1,i=u=f=void 0,y.resolve(),s.clearTimeout(E)}e.on("dispose",R),e.on("routeLeave",R),e.watch(()=>e.user?.username,F=>{!k&&F?k=F:k&&F!==k&&(R(),e.preview=null,e.repositoryId="",e.busy=!1,e.saved=!1,e.handoffEnabled=!1,e.error="Your account changed. Open a new artifact link from your submission.")});let T=()=>({timeout:y.promise,headers:{"Content-Type":"application/json","X-Review-CSRF":f}}),P=F=>F?.status===404?"Artifact linking is not available on this server.":F?.status===401?"Sign in, then open a new artifact link from your submission.":F?.status===403?"This account cannot approve this repository or this link.":"The request could not be completed. You can retry from this page.";e.loadPreview=async()=>{if(!m||!i||e.busy||e.uncertain||e.saved||!e.user?.username)return;k=e.user.username;let F=e.repositoryId.trim();if(!/^[A-Za-z0-9_-]{3,128}$/.test(F)){e.error="Enter the anonymous repository ID from its URL.";return}e.busy=!0,e.error="",e.preview=null,u=void 0,e.acceptAccess=e.acceptRetention=!1,e.expired=!1,s.clearTimeout(E),h||(h=g());try{let V=(await n.get("/api/review-consent/csrf",{timeout:y.promise})).data;if(!_())return;if(f=V.csrf,e.handoffEnabled=V.handoffEnabled===!0,!/^[a-f0-9]{64}$/.test(f||""))throw new Error("invalid_csrf");let M=(await n.post("/api/review-consent/preview",{repositoryId:F,intent:{...i,requestId:h}},T())).data;if(!_())return;if(!M||typeof M.ticket!="string"||!M.ticket||M.ticket.length>8192||typeof M.repositoryName!="string"||!["restricted-review","anonymous-link"].includes(M.policy?.access)||!Number.isSafeInteger(M.policy.version)||!Number.isFinite(Date.parse(M.policy.retainUntil))||!Number.isFinite(Date.parse(M.expiresAt))||Date.parse(M.expiresAt)<=Date.now()||Date.parse(M.expiresAt)>Date.now()+6e5)throw new Error("invalid_preview");u=M.ticket,w=g(),e.preview={repositoryName:M.repositoryName,policy:{...M.policy},expiresAt:M.expiresAt},E=s.setTimeout(()=>{m&&(e.expired=!0)},Math.max(0,Date.parse(M.expiresAt)-Date.now()))}catch(V){_()&&(e.error=P(V))}finally{_()&&(e.busy=!1)}},e.confirmConsent=async()=>{if(!(!_()||e.busy||e.saved||!u||!e.acceptAccesLine truncated
`))),e[Lt]=To(s);let i=r||s.props&&s.props.type==="number";to(e,t?"change":"input",a=>{a.target.composing||e[Lt](Gs(e.value,n,i))}),(n||i)&&to(e,"change",()=>{e.value=Gs(e.value,n,i)}),t||(to(e,"compositionstart",bc),to(e,"compositionend",ea),to(e,"change",ea))},mounted(e,{value:t,modifiers:{trim:n,number:r}}){let s=t??"",i=e[Jn];delete e[Jn],i!==void 0&&(e.type==="text"||e.type==="textarea")&&e.value!==i?e[Lt](Gs(e.value,n,r)):e.value=s},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:r,trim:s,number:i}},a){if(e[Lt]=To(a),e.composing)return;let u=(i||e.type==="number")&&!/^0\d/.test(e.value)?ko(e.value):e.value,f=t??"";if(u===f)return;let w=e.getRootNode();(w instanceof Document||w instanceof ShadowRoot)&&w.activeElement===e&&e.type!=="range"&&(r&&t===n||s&&e.value.trim()===f)||(e.value=f)}},Ks={deep:!0,created(e,t,n){e[Lt]=To(n),to(e,"change",()=>{let r=e._modelValue,s=fn(e),i=e.checked,a=e[Lt];if(ye(r)){let u=kn(r,s),f=u!==-1;if(i&&!f)a(r.concat(s));else if(!i&&f){let w=[...r];w.splice(u,1),a(w)}}else if(Ct(r)){let u=new Set(r);i?u.add(s):u.delete(s),a(u)}else a(aa(e,i))})},mounted:ta,beforeUpdate(e,t,n){e[Lt]=To(n),ta(e,t,n)}};function ta(e,{value:t,oldValue:n},r){e._modelValue=t;let s;if(ye(t))s=kn(t,r.props.value)>-1;else if(Ct(t))s=t.has(r.props.value);else{if(t===n)return;s=_t(t,aa(e,!0))}e.checked!==s&&(e.checked=s)}var ia={deep:!0,created(e,{value:t,modifiers:{number:n}},r){e._modelValue=t,to(e,"change",()=>{let s=Array.prototype.filter.call(e.options,f=>f.selected).map(f=>n?ko(fn(f)):fn(f)),i=e.multiple,a=i?Ct(e._modelValue)?new Set(s):s:s[0],u=e._pendingValue=[i,i?ye(a)?s.slice():s:a];try{e[Lt](a)}finally{nt(()=>{e._pendingValue===u&&(e._pendingValue=void 0)})}}),e[Lt]=To(r)},mounted(e,{value:t}){oa(e,t)},beforeUpdate(e,{value:t},n){e._modelValue=t,e[Lt]=To(n)},updated(e,{value:t}){let n=e._pendingValue;e._pendingValue=void 0,(!n||n[0]!==e.multiple||!wc(t,n[1],n[0]))&&oa(e,t)}};function wc(e,t,n){if(!n)return _t(e,t);if(ye(e))return _t(e,t);if(Ct(e)){if(e.size!==t.length)return!1;for(let r of t)if(!e.has(r))return!1;return!0}return!1}function oa(e,t){let n=e.multiple,r=ye(t);if(!(n&&!r&&!Ct(t))){for(let s=0,i=e.options.length;s<i;s++){let a=e.options[s],u=fn(a);if(n)if(r){let f=typeof u;f==="string"||f==="number"?a.selected=t.some(w=>String(w)===String(u)):a.selected=kn(t,u)>-1}else a.selected=t.has(u);else if(_t(fn(a),t)){e.selectedIndex!==s&&(e.selectedIndex=s);return}}!n&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function fn(e){return"_value"in e?e._value:e.value}function aa(e,t){let n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}var kc=["ctrl","shift","alt","meta"],Ec={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>kc.some(n=>e[`${n}Key`]&&!t.includes(n))},de=(e,t)=>{if(!e)return e;let n=e._withMods||(e._withMods={}),r=t.join(".");return n[r]||(n[r]=((s,...i)=>{for(let a=0;a<t.length;a++){let u=Ec[t[a]];if(u&&u(s,t))return}return e(s,...i)}))},Cc={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},Ao=(e,t)=>{let n=e._withKeys||(e._withKeys={}),r=t.join(".");return n[r]||(n[r]=(s=>{if(!("key"in s))return;let i=Dt(s.key);if(t.some(a=>a===i||Cc[a]===i))return e(s)}))},_c=Ge({patchProp:vc},ec),na;function Sc(){return na||(na=Mi(_c))}var la=((...e)=>{let t=Sc().createApp(...e),{mount:n}=t;return t.mount=r=>{let s=Dc(r);if(!s)return;let i=t._component;!we(i)&&!i.render&&!i.template&&(i.template=s.innerHTML),s.nodeType===1&&(s.textContent="");let a=n(s,!1,Nc(s));return s instanceof Element&&(s.removeAttribute("v-cloak"),s.setAttribute("data-v-app","")),a},t});function Nc(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function Dc(e){return Fe(e)?document.querySelector(e):e}var mo=typeof document<"u";function ua(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function Rc(e){return e.__esModule||e[Symbol.toStringTag]==="Module"||e.default&&ua(e.default)}var Ae=Object.assign;function Xn(e,t){let n={};for(let r in t){let s=t[r];n[r]=kt(s)?s.map(e):e(s)}return n}var Io=()=>{},kt=Array.isArray;function Qs(e,t){let n={};for(let r in e)n[r]=r in t?t[r]:e[r];return n}var ca=/#/g,Tc=/&/g,Ac=/\//g,Oc=/=/g,Ic=/\?/g,pa=/\+/g,Pc=/%5B/g,Vc=/%5D/g,fa=/%5E/g,qc=/%60/g,ma=/%7B/g,Mc=/%7C/g,ha=/%7D/g,$c=/%20/g;function Xs(e){return e==null?"":encodeURI(""+e).replace(Mc,"|").replace(Pc,"[").replace(Vc,"]")}function va(e){return Xs(e).replace(ma,"{").replace(ha,"}").replace(fa,"^")}function Ys(e){return Xs(e).replace(pa,"%2B").replace($c,"+").replace(ca,"%23").replace(Tc,"%26").replace(qc,"`").replace(ma,"{").replace(ha,"}").replace(fa,"^")}function Uc(e){return Ys(e).replace(Oc,"%3D")}function Lc(e){return XLine truncated
"use strict";(()=>{var kd=Object.defineProperty;var Ed=(e,t)=>{for(var n in t)kd(e,n,{get:t[n],enumerable:!0})};var me=["abap","abc","actionscript","ada","alda","apache_conf","apex","applescript","aql","asciidoc","asl","assembly_x86","autohotkey","batchfile","c9search","c_cpp","cirru","clojure","cobol","coffee","coldfusion","crystal","csharp","csound_document","csound_orchestra","csound_score","csp","css","curly","d","dart","diff","django","dockerfile","dot","drools","edifact","eiffel","ejs","elixir","elm","erlang","forth","fortran","fsharp","fsl","ftl","gcode","gherkin","gitignore","glsl","gobstones","golang","graphqlschema","groovy","haml","handlebars","haskell","haskell_cabal","haxe","hjson","html","html_elixir","html_ruby","ini","io","jack","jade","java","javascript","json","json5","jsoniq","jsp","jssm","jsx","julia","kotlin","latex","less","liquid","lisp","livescript","logiql","logtalk","lsl","lua","luapage","lucene","makefile","markdown","mask","matlab","maze","mediawiki","mel","mixal","mushcode","mysql","nginx","nim","nix","nsis","nunjucks","objectivec","ocaml","pascal","perl","perl6","pgsql","php","php_laravel_blade","pig","plain_text","powershell","praat","prisma","prolog","properties","protobuf","puppet","python","qml","r","razor","rdoc","red","redshift","rhtml","rst","ruby","rust","sass","scad","scala","scheme","scss","sh","sjs","slim","smarty","snippets","soy_template","space","sparql","sql","sqlserver","stylus","svg","swift","tcl","terraform","tex","text","textile","toml","tsx","turtle","twig","typescript","vala","vbscript","velocity","verilog","vhdl","visualforce","wollok","xml","xquery","yaml","zeek"];var he={notebook:"/script/notebook.c3144c18ae.min.js",org:"/script/org.f61f262915.min.js",pdf:"/script/pdf.4d9cc6ff49.min.js",markdown:"/script/markdown.44f2e93820.min.js",editor:"/script/editor.4f142d3adc.min.js"};function gr(e){let t=e.location.hash.slice(1);if(e.history.replaceState(null,"","/review-link"),t.length>2048)return null;let n=new URLSearchParams(t);if([...n.keys()].length!==3||[...n.keys()].some(a=>!["clientId","intentId","token"].includes(a)))return null;let r=n.get("clientId"),s=n.get("intentId"),i=n.get("token");return!/^[a-f0-9]{32}$/.test(r||"")||!/^[a-f0-9]{32}$/.test(s||"")||!/^[a-f0-9]{64}$/.test(i||"")?null:{contract:"4open.artifacts/1",clientId:r,intentId:s,token:i}}function br(e,t){let{http:n,promises:r,window:s}=t,i=t.takeReviewHandoff(),a=i?{clientId:i.clientId,intentId:i.intentId}:null,u,f,w,h,k,m=!0,C,y=r.defer(),g=()=>[...s.crypto.getRandomValues(new Uint8Array(16))].map(L=>L.toString(16).padStart(2,"0")).join("");Object.assign(e,{repositoryId:"",handoffEnabled:!1,busy:!1,preview:null,acceptAccess:!1,acceptRetention:!1,uncertain:!1,saved:!1,expired:!1,error:i?"":"Open a new artifact link from your submission. This link is missing or invalid."});let S=()=>m&&e.user?.username===k;function R(){m=!1,i=u=f=void 0,y.resolve(),s.clearTimeout(C)}e.on("dispose",R),e.on("routeLeave",R),e.watch(()=>e.user?.username,L=>{!k&&L?k=L:k&&L!==k&&(R(),e.preview=null,e.repositoryId="",e.busy=!1,e.saved=!1,e.handoffEnabled=!1,e.error="Your account changed. Open a new artifact link from your submission.")});let T=()=>({timeout:y.promise,headers:{"Content-Type":"application/json","X-Review-CSRF":f}}),P=L=>L?.status===404?"Artifact linking is not available on this server.":L?.status===401?"Sign in, then open a new artifact link from your submission.":L?.status===403?"This account cannot approve this repository or this link.":"The request could not be completed. You can retry from this page.";e.loadPreview=async()=>{if(!m||!i||e.busy||e.uncertain||e.saved||!e.user?.username)return;k=e.user.username;let L=e.repositoryId.trim();if(!/^[A-Za-z0-9_-]{3,128}$/.test(L)){e.error="Enter the anonymous repository ID from its URL.";return}e.busy=!0,e.error="",e.preview=null,u=void 0,e.acceptAccess=e.acceptRetention=!1,e.expired=!1,s.clearTimeout(C),h||(h=g());try{let V=(await n.get("/api/review-consent/csrf",{timeout:y.promise})).data;if(!S())return;if(f=V.csrf,e.handoffEnabled=V.handoffEnabled===!0,!/^[a-f0-9]{64}$/.test(f||""))throw new Error("invalid_csrf");let M=(await n.post("/api/review-consent/preview",{repositoryId:L,intent:{...i,requestId:h}},T())).data;if(!S())return;if(!M||typeof M.ticket!="string"||!M.ticket||M.ticket.length>8192||typeof M.repositoryName!="string"||!["restricted-review","anonymous-link"].includes(M.policy?.access)||!Number.isSafeInteger(M.policy.version)||!Number.isFinite(Date.parse(M.policy.retainUntil))||!Number.isFinite(Date.parse(M.expiresAt))||Date.parse(M.expiresAt)<=Date.now()||Date.parse(M.expiresAt)>Date.now()+6e5)throw new Error("invalid_preview");u=M.ticket,w=g(),e.preview={repositoryName:M.repositoryName,policy:{...M.policy},expiresAt:M.expiresAt},C=s.setTimeout(()=>{m&&(e.expired=!0)},Math.max(0,Date.parse(M.expiresAt)-Date.now()))}catch(V){S()&&(e.error=P(V))}finally{S()&&(e.busy=!1)}},e.confirmConsent=async()=>{if(!(!S()||e.busy||e.saved||!u||!e.acceptAccesLine truncated
`))),e[Ft]=Ro(s);let i=r||s.props&&s.props.type==="number";to(e,t?"change":"input",a=>{a.target.composing||e[Ft](Ys(e.value,n,i))}),(n||i)&&to(e,"change",()=>{e.value=Ys(e.value,n,i)}),t||(to(e,"compositionstart",Sc),to(e,"compositionend",ia),to(e,"change",ia))},mounted(e,{value:t,modifiers:{trim:n,number:r}}){let s=t??"",i=e[Jn];delete e[Jn],i!==void 0&&(e.type==="text"||e.type==="textarea")&&e.value!==i?e[Ft](Ys(e.value,n,r)):e.value=s},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:r,trim:s,number:i}},a){if(e[Ft]=Ro(a),e.composing)return;let u=(i||e.type==="number")&&!/^0\d/.test(e.value)?ko(e.value):e.value,f=t??"";if(u===f)return;let w=e.getRootNode();(w instanceof Document||w instanceof ShadowRoot)&&w.activeElement===e&&e.type!=="range"&&(r&&t===n||s&&e.value.trim()===f)||(e.value=f)}},Qs={deep:!0,created(e,t,n){e[Ft]=Ro(n),to(e,"change",()=>{let r=e._modelValue,s=mn(e),i=e.checked,a=e[Ft];if(ve(r)){let u=Cn(r,s),f=u!==-1;if(i&&!f)a(r.concat(s));else if(!i&&f){let w=[...r];w.splice(u,1),a(w)}}else if(Et(r)){let u=new Set(r);i?u.add(s):u.delete(s),a(u)}else a(fa(e,i))})},mounted:aa,beforeUpdate(e,t,n){e[Ft]=Ro(n),aa(e,t,n)}};function aa(e,{value:t,oldValue:n},r){e._modelValue=t;let s;if(ve(t))s=Cn(t,r.props.value)>-1;else if(Et(t))s=t.has(r.props.value);else{if(t===n)return;s=Ct(t,fa(e,!0))}e.checked!==s&&(e.checked=s)}var pa={deep:!0,created(e,{value:t,modifiers:{number:n}},r){e._modelValue=t,to(e,"change",()=>{let s=Array.prototype.filter.call(e.options,f=>f.selected).map(f=>n?ko(mn(f)):mn(f)),i=e.multiple,a=i?Et(e._modelValue)?new Set(s):s:s[0],u=e._pendingValue=[i,i?ve(a)?s.slice():s:a];try{e[Ft](a)}finally{ot(()=>{e._pendingValue===u&&(e._pendingValue=void 0)})}}),e[Ft]=Ro(r)},mounted(e,{value:t}){la(e,t)},beforeUpdate(e,{value:t},n){e._modelValue=t,e[Ft]=Ro(n)},updated(e,{value:t}){let n=e._pendingValue;e._pendingValue=void 0,(!n||n[0]!==e.multiple||!Nc(t,n[1],n[0]))&&la(e,t)}};function Nc(e,t,n){if(!n)return Ct(e,t);if(ve(e))return Ct(e,t);if(Et(e)){if(e.size!==t.length)return!1;for(let r of t)if(!e.has(r))return!1;return!0}return!1}function la(e,t){let n=e.multiple,r=ve(t);if(!(n&&!r&&!Et(t))){for(let s=0,i=e.options.length;s<i;s++){let a=e.options[s],u=mn(a);if(n)if(r){let f=typeof u;f==="string"||f==="number"?a.selected=t.some(w=>String(w)===String(u)):a.selected=Cn(t,u)>-1}else a.selected=t.has(u);else if(Ct(mn(a),t)){e.selectedIndex!==s&&(e.selectedIndex=s);return}}!n&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function mn(e){return"_value"in e?e._value:e.value}function fa(e,t){let n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}var Dc=["ctrl","shift","alt","meta"],Rc={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>Dc.some(n=>e[`${n}Key`]&&!t.includes(n))},le=(e,t)=>{if(!e)return e;let n=e._withMods||(e._withMods={}),r=t.join(".");return n[r]||(n[r]=((s,...i)=>{for(let a=0;a<t.length;a++){let u=Rc[t[a]];if(u&&u(s,t))return}return e(s,...i)}))},Tc={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},To=(e,t)=>{let n=e._withKeys||(e._withKeys={}),r=t.join(".");return n[r]||(n[r]=(s=>{if(!("key"in s))return;let i=At(s.key);if(t.some(a=>a===i||Tc[a]===i))return e(s)}))},Ac=je({patchProp:Ec},ic),da;function Oc(){return da||(da=Hi(Ac))}var ma=((...e)=>{let t=Oc().createApp(...e),{mount:n}=t;return t.mount=r=>{let s=Pc(r);if(!s)return;let i=t._component;!be(i)&&!i.render&&!i.template&&(i.template=s.innerHTML),s.nodeType===1&&(s.textContent="");let a=n(s,!1,Ic(s));return s instanceof Element&&(s.removeAttribute("v-cloak"),s.setAttribute("data-v-app","")),a},t});function Ic(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function Pc(e){return Fe(e)?document.querySelector(e):e}var mo=typeof document<"u";function va(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function Vc(e){return e.__esModule||e[Symbol.toStringTag]==="Module"||e.default&&va(e.default)}var Te=Object.assign;function Xn(e,t){let n={};for(let r in t){let s=t[r];n[r]=wt(s)?s.map(e):e(s)}return n}var Oo=()=>{},wt=Array.isArray;function xs(e,t){let n={};for(let r in e)n[r]=r in t?t[r]:e[r];return n}var ya=/#/g,qc=/&/g,Mc=/\//g,$c=/=/g,Lc=/\?/g,ga=/\+/g,Uc=/%5B/g,Fc=/%5D/g,ba=/%5E/g,zc=/%60/g,wa=/%7B/g,Hc=/%7C/g,ka=/%7D/g,Bc=/%20/g;function er(e){return e==null?"":encodeURI(""+e).replace(Hc,"|").replace(Uc,"[").replace(Fc,"]")}function Ea(e){return er(e).replace(wa,"{").replace(ka,"}").replace(ba,"^")}function Xs(e){return er(e).replace(ga,"%2B").replace(Bc,"+").replace(ya,"%23").replace(qc,"%26").replace(zc,"`").replace(wa,"{").replace(ka,"}").replace(ba,"^")}function jc(e){return Xs(e).replace($c,"%3D")}function Gc(e){return eLine truncated
${JSON.stringify(e)}${t?`
while being at
`+JSON.stringify(t):""}`},[je.NAVIGATION_GUARD_REDIRECT]({from:e,to:t}){return`Redirected from "${e.fullPath}" to "${Yc(t)}" via a navigation guard.`},[je.NAVIGATION_ABORTED]({from:e,to:t}){return`Navigation aborted from "${e.fullPath}" to "${t.fullPath}" via a navigation guard.`},[je.NAVIGATION_CANCELLED]({from:e,to:t}){return`Navigation cancelled from "${e.fullPath}" to "${t.fullPath}" with a new navigation.`},[je.NAVIGATION_DUPLICATED]({from:e,to:t}){return`Avoided redundant navigation to current location: "${e.fullPath}".`}};function fo(e,t){return Ae(new Error,{type:e,[Sa]:!0},t)}function zt(e,t){return e instanceof Error&&Sa in e&&(t==null||!!(e.type&t))}var Kc=["params","query","hash"];function Yc(e){if(typeof e=="string")return e;if(e.path!=null)return e.path;let t={};for(let n of Kc)n in e&&(t[n]=e[n]);return JSON.stringify(t,null,2)}function Na(e){let t={};if(e===""||e==="?")return t;let n=(e[0]==="?"?e.slice(1):e).split("&");for(let r=0;r<n.length;++r){let s=n[r].replace(pa," "),i=s.indexOf("="),a=Oo(i<0?s:s.slice(0,i)),u=i<0?null:Oo(s.slice(i+1));if(a in t){let f=t[a];kt(f)||(f=t[a]=[f]),f.push(u)}else t[a]=u}return t}function or(e){let t="";for(let n in e){let r=e[n];if(n=Uc(n),r==null){r!==void 0&&(t+=(t.length?"&":"")+n);continue}(kt(r)?r.map(s=>s&&Ys(s)):[r&&Ys(r)]).forEach(s=>{s!==void 0&&(t+=(t.length?"&":"")+n,s!=null&&(t+="="+s))})}return t}function Da(e){let t={};for(let n in e){let r=e[n];r!==void 0&&(t[n]=kt(r)?r.map(s=>s==null?null:""+s):r==null?r:""+r)}return t}var Ra=Symbol(""),nr=Symbol(""),ts=Symbol(""),os=Symbol(""),ns=Symbol("");function Po(){let e=[];function t(r){return e.push(r),()=>{let s=e.indexOf(r);s>-1&&e.splice(s,1)}}function n(){e=[]}return{add:t,list:()=>e.slice(),reset:n}}function Qt(e,t,n,r,s,i=a=>a()){let a=r&&(r.enterCallbacks[s]=r.enterCallbacks[s]||[]);return()=>new Promise((u,f)=>{let w=m=>{m===!1?f(fo(je.NAVIGATION_ABORTED,{from:n,to:t})):m instanceof Error?f(m):Wc(m)?f(fo(je.NAVIGATION_GUARD_REDIRECT,{from:t,to:m})):(a&&r.enterCallbacks[s]===a&&typeof m=="function"&&a.push(m),u())},h=i(()=>e.call(r&&r.instances[s],t,n,w)),k=Promise.resolve(h);e.length<3&&(k=k.then(w)),k.catch(m=>f(m))})}function ss(e,t,n,r,s=i=>i()){let i=[];for(let a of e)for(let u in a.components){let f=a.components[u];if(!(t!=="beforeRouteEnter"&&!a.instances[u]))if(ua(f)){let w=(f.__vccOpts||f)[t];w&&i.push(Qt(w,n,r,a,u,s))}else{let w=f();i.push(()=>w.then(h=>{if(!h)throw new Error(`Couldn't resolve component "${u}" at "${a.path}"`);let k=Rc(h)?h.default:h;a.mods[u]=h,a.components[u]=k;let m=(k.__vccOpts||k)[t];return m&&Qt(m,n,r,a,u,s)()}))}}return i}function Ta(e,t){let n=[],r=[],s=[],i=Math.max(t.matched.length,e.matched.length);for(let a=0;a<i;a++){let u=t.matched[a];u&&(e.matched.find(w=>po(w,u))?r.push(u):n.push(u));let f=e.matched[a];f&&(t.matched.find(w=>po(w,f))||s.push(f))}return[n,r,s]}var Jc=()=>location.protocol+"//"+location.host;function Fa(e,t){let{pathname:n,search:r,hash:s}=t,i=e.indexOf("#");if(i>-1){let a=s.includes(e.slice(i))?e.slice(i).length:1,u=s.slice(a);return u[0]!=="/"&&(u="/"+u),Zs(u,"")}return Zs(n,e)+r+s}function Qc(e,t,n,r){let s=[],i=[],a=null,u=({state:m})=>{let E=Fa(e,location),y=n.value,g=t.value,_=0;if(m){if(n.value=E,t.value=m,a&&a===y){a=null;return}_=g?m.position-g.position:0}else r(E);s.forEach(R=>{R(n.value,y,{delta:_,type:xn.pop,direction:_?_>0?es.forward:es.back:es.unknown})})};function f(){a=n.value}function w(m){s.push(m);let E=()=>{let y=s.indexOf(m);y>-1&&s.splice(y,1)};return i.push(E),E}function h(){if(document.visibilityState==="hidden"){let{history:m}=window;if(!m.state)return;m.replaceState(Ae({},m.state,{scroll:mn()}),"")}}function k(){for(let m of i)m();i=[],window.removeEventListener("popstate",u),window.removeEventListener("pagehide",h),document.removeEventListener("visibilitychange",h)}return window.addEventListener("popstate",u),window.addEventListener("pagehide",h),document.addEventListener("visibilitychange",h),{pauseListeners:f,listen:w,destroy:k}}function Aa(e,t,n,r=!1,s=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:s?mn():null}}function Xc(e){let{history:t,location:n}=window,r={value:Fa(e,n)},s={value:t.state};s.value||i(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function i(f,w,h){let k=e.indexOf("#"),m=k>-1?(n.host&&document.querySelector("base")?e:e.slice(k))+f:Jc()+e+f;try{t[h?"replaceState":"pushState"](w,"",m),s.value=w}catch(E){console.error(E),n[h?"replace":"assign"](m)}}function a(f,w){i(f,Ae({},t.state,Aa(s.value.back,f,s.value.forward,!0),w,{position:s.value.position}),!0),r.value=f}function u(f,w){let h=Ae({},s.value,t.state,{forward:f,scroll:mn()});i(h.current,h,!0),i(f,Ae({},Aa(r.value,f,null),{position:h.position+1},w),!1),r.value=f}return{location:r,state:s,push:u,replace:a}}function za(e){e=wa(e);let t=Xc(e),n=Qc(e,t.state,t.location,t.replace);function r(i,a=!0){a||n.pauseListeners(),history.go(i)}let s=Ae({locatLine truncated
`+JSON.stringify(t):""}`},[Be.NAVIGATION_GUARD_REDIRECT]({from:e,to:t}){return`Redirected from "${e.fullPath}" to "${ep(t)}" via a navigation guard.`},[Be.NAVIGATION_ABORTED]({from:e,to:t}){return`Navigation aborted from "${e.fullPath}" to "${t.fullPath}" via a navigation guard.`},[Be.NAVIGATION_CANCELLED]({from:e,to:t}){return`Navigation cancelled from "${e.fullPath}" to "${t.fullPath}" with a new navigation.`},[Be.NAVIGATION_DUPLICATED]({from:e,to:t}){return`Avoided redundant navigation to current location: "${e.fullPath}".`}};function fo(e,t){return Te(new Error,{type:e,[Oa]:!0},t)}function Ht(e,t){return e instanceof Error&&Oa in e&&(t==null||!!(e.type&t))}var xc=["params","query","hash"];function ep(e){if(typeof e=="string")return e;if(e.path!=null)return e.path;let t={};for(let n of xc)n in e&&(t[n]=e[n]);return JSON.stringify(t,null,2)}function Ia(e){let t={};if(e===""||e==="?")return t;let n=(e[0]==="?"?e.slice(1):e).split("&");for(let r=0;r<n.length;++r){let s=n[r].replace(ga," "),i=s.indexOf("="),a=Ao(i<0?s:s.slice(0,i)),u=i<0?null:Ao(s.slice(i+1));if(a in t){let f=t[a];wt(f)||(f=t[a]=[f]),f.push(u)}else t[a]=u}return t}function rr(e){let t="";for(let n in e){let r=e[n];if(n=jc(n),r==null){r!==void 0&&(t+=(t.length?"&":"")+n);continue}(wt(r)?r.map(s=>s&&Xs(s)):[r&&Xs(r)]).forEach(s=>{s!==void 0&&(t+=(t.length?"&":"")+n,s!=null&&(t+="="+s))})}return t}function Pa(e){let t={};for(let n in e){let r=e[n];r!==void 0&&(t[n]=wt(r)?r.map(s=>s==null?null:""+s):r==null?r:""+r)}return t}var Va=Symbol(""),ir=Symbol(""),ts=Symbol(""),os=Symbol(""),ns=Symbol("");function Io(){let e=[];function t(r){return e.push(r),()=>{let s=e.indexOf(r);s>-1&&e.splice(s,1)}}function n(){e=[]}return{add:t,list:()=>e.slice(),reset:n}}function Qt(e,t,n,r,s,i=a=>a()){let a=r&&(r.enterCallbacks[s]=r.enterCallbacks[s]||[]);return()=>new Promise((u,f)=>{let w=m=>{m===!1?f(fo(Be.NAVIGATION_ABORTED,{from:n,to:t})):m instanceof Error?f(m):Zc(m)?f(fo(Be.NAVIGATION_GUARD_REDIRECT,{from:t,to:m})):(a&&r.enterCallbacks[s]===a&&typeof m=="function"&&a.push(m),u())},h=i(()=>e.call(r&&r.instances[s],t,n,w)),k=Promise.resolve(h);e.length<3&&(k=k.then(w)),k.catch(m=>f(m))})}function ss(e,t,n,r,s=i=>i()){let i=[];for(let a of e)for(let u in a.components){let f=a.components[u];if(!(t!=="beforeRouteEnter"&&!a.instances[u]))if(va(f)){let w=(f.__vccOpts||f)[t];w&&i.push(Qt(w,n,r,a,u,s))}else{let w=f();i.push(()=>w.then(h=>{if(!h)throw new Error(`Couldn't resolve component "${u}" at "${a.path}"`);let k=Vc(h)?h.default:h;a.mods[u]=h,a.components[u]=k;let m=(k.__vccOpts||k)[t];return m&&Qt(m,n,r,a,u,s)()}))}}return i}function qa(e,t){let n=[],r=[],s=[],i=Math.max(t.matched.length,e.matched.length);for(let a=0;a<i;a++){let u=t.matched[a];u&&(e.matched.find(w=>po(w,u))?r.push(u):n.push(u));let f=e.matched[a];f&&(t.matched.find(w=>po(w,f))||s.push(f))}return[n,r,s]}var tp=()=>location.protocol+"//"+location.host;function Wa(e,t){let{pathname:n,search:r,hash:s}=t,i=e.indexOf("#");if(i>-1){let a=s.includes(e.slice(i))?e.slice(i).length:1,u=s.slice(a);return u[0]!=="/"&&(u="/"+u),tr(u,"")}return tr(n,e)+r+s}function op(e,t,n,r){let s=[],i=[],a=null,u=({state:m})=>{let C=Wa(e,location),y=n.value,g=t.value,S=0;if(m){if(n.value=C,t.value=m,a&&a===y){a=null;return}S=g?m.position-g.position:0}else r(C);s.forEach(R=>{R(n.value,y,{delta:S,type:xn.pop,direction:S?S>0?es.forward:es.back:es.unknown})})};function f(){a=n.value}function w(m){s.push(m);let C=()=>{let y=s.indexOf(m);y>-1&&s.splice(y,1)};return i.push(C),C}function h(){if(document.visibilityState==="hidden"){let{history:m}=window;if(!m.state)return;m.replaceState(Te({},m.state,{scroll:hn()}),"")}}function k(){for(let m of i)m();i=[],window.removeEventListener("popstate",u),window.removeEventListener("pagehide",h),document.removeEventListener("visibilitychange",h)}return window.addEventListener("popstate",u),window.addEventListener("pagehide",h),document.addEventListener("visibilitychange",h),{pauseListeners:f,listen:w,destroy:k}}function Ma(e,t,n,r=!1,s=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:s?hn():null}}function np(e){let{history:t,location:n}=window,r={value:Wa(e,n)},s={value:t.state};s.value||i(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function i(f,w,h){let k=e.indexOf("#"),m=k>-1?(n.host&&document.querySelector("base")?e:e.slice(k))+f:tp()+e+f;try{t[h?"replaceState":"pushState"](w,"",m),s.value=w}catch(C){console.error(C),n[h?"replace":"assign"](m)}}function a(f,w){i(f,Te({},t.state,Ma(s.value.back,f,s.value.forward,!0),w,{position:s.value.position}),!0),r.value=f}function u(f,w){let h=Te({},s.value,t.state,{forward:f,scroll:hn()});i(h.current,h,!0),i(f,Te({},Ma(r.value,f,null),{position:h.position+1},w),!1),r.value=f}return{location:r,state:s,push:u,replace:a}}function Ka(e){e=Na(e);let t=np(e),n=op(e,t.state,t.location,t.replace);function r(i,a=!0){a||n.pauseListeners(),history.go(i)}let s=Te({locatLine truncated
`)),e.options=Object.assign({},e.options,h.options),a.restore()})}u();let f=null;e.saveDefault=w=>{if(w&&w.preventDefault&&w.preventDefault(),e.saving)return;let h=a.checkpoint(),k={terms:e.terms.split(`
`).map(m=>m.trim()).filter(m=>m.length>0),options:e.options};e.saving=!0,e.error=null,t.post("/api/user/default",k).then(()=>{a.accept(h),e.saving=!1,e.message=e.unsavedChanges?null:"Saved",f&&r.cancel(f),f=r(()=>{e.message=null},2500)},m=>{e.saving=!1;let E=m&&m.data&&m.data.error,y="Unable to save your defaults. Please try again.";Promise.all([n("ERRORS."+E),n("ERRORS.unknown_error")]).then(([g,_])=>{e.error=E&&g!==_?g:y},()=>{e.error=y})})},e.deleteAccount=()=>{confirm("Delete your account? All your anonymized repositories, gists, and pull requests will be removed, and your personal data will be erased. This cannot be undone.")&&(e.deletingAccount=!0,t.delete("/api/user").then(()=>{window.location.href="/"},()=>{e.deletingAccount=!1,e.deleteError="Unable to delete the account. Please try again."}))}},el=function(e,t,n){e.repoId=null,e.repoUrl=null,e.claim=()=>{t.post("/api/repo/claim",{repoId:e.repoId,repoUrl:e.repoUrl}).then(r=>{n.url("/dashboard")},r=>{e.error=r.data,e.claimForm.repoUrl.setValidity("not_found",!1),e.claimForm.repoId.setValidity("not_found",!1)})}},tl=function(e,t,n,r,s){e.user&&!e.user.status&&n.url("/dashboard"),e.watch("user.status",()=>{e.user&&!e.user.status&&n.url("/dashboard")}),e.features=[{key:"anonymize",num:"01",eyebrow:"Anonymize",title:"Double-anonymous,",accent:"your rules.",text:"Choose what reviewers may see: links, images, PDFs, notebooks, GitHub Pages. Add your own terms, with regex if you need it, and pick the expiration date.",cta:"Start an anonymization",href:"/anonymize",url:"anonymous.4open.science/anonymize",img:"/imgs/anonymize.png",alt:"The anonymize form: source repository, terms to redact, options and a live README preview"},{key:"review",num:"02",eyebrow:"Review",title:"Reviewers browse",accent:"the real thing.",text:"Highlighted source code, rendered PDFs, images, and notebooks, in a familiar file explorer. GitHub Pages is also supported.",cta:"Open the example",href:"https://anonymous.4open.science/r/840c8c57-3c32-451e-bf12-0e20be300389/",target:"_self",url:"anonymous.4open.science/r/840c8c57-\u2026",img:"/imgs/explorer.png",alt:"The repository explorer with a file tree and a rendered README"},{key:"manage",num:"03",eyebrow:"Manage",title:"One dashboard,",accent:"until the decision.",text:"Monitor views, edit configuration, remove or update your repository. Program chairs can group submissions under a conference with one shared expiry.",cta:"Open the dashboard",href:"/dashboard",needsUser:!0,url:"anonymous.4open.science/dashboard",img:"/imgs/dashboard.png",alt:"The dashboard listing anonymized repositories with status, views and expiry"}],e.feature=e.features[0].key,e.selectFeature=function(u){e.feature=u},e.featureHref=function(u){return u.needsUser&&!e.user?"/signin":u.href},e.featureTarget=function(u){return u.needsUser&&!e.user?"_self":u.target||void 0},e.featureKeydown=function(u,f){let w={ArrowDown:1,ArrowRight:1,ArrowUp:-1,ArrowLeft:-1,Home:"first",End:"last"}[u.key];if(w===void 0)return;u.preventDefault();let h=e.features.length,k=w==="first"?0:w==="last"?h-1:(f+w+h)%h;e.feature=e.features[k].key,s(()=>{let m=r.document.getElementById("feature-tab-"+e.feature);m&&m.focus()})},e.cards=[{key:"repositories",total:0,label:"repositories anonymized"},{key:"users",total:0,label:"researchers"},{key:"pageViews",total:0,label:"page views"},{key:"pullRequests",total:0,label:"pull requests"}];function i(){t.get("/api/stat/").then(u=>{e.stat=u.data,e.cards[0].total=u.data.nbRepositories,e.cards[1].total=u.data.nbUsers,e.cards[2].total=u.data.nbPageViews,e.cards[3].total=u.data.nbPullRequests})}i();function a(u){let f={series:u,bars:[],viewW:100,deltaToday:0,pctChange:0,pctAbs:0,isUp:!0};if(!u||u.length<2)return f;let w=new Array(u.length-1);for(let g=1;g<u.length;g++)w[g-1]=u[g]-u[g-1];let h=w.length,k=Math.max.apply(null,w),m=Math.min.apply(null,w),E=Math.min(0,m),y=k-E||1;f.viewW=h*2,f.bars=new Array(h);for(let g=0;g<h;g++){let _=(w[g]-E)/y,R=Math.max(1.5,_*34);f.bars[g]={x:(g*2+.25).toFixed(2),y:(36-R).toFixed(2),w:"1.5",h:R.toFixed(2)}}if(f.deltaToday=w[h-1],h>=2){let g=w[h-2];g&&(f.pctChange=(f.deltaToday-g)/g*100)}return f.pctAbs=Math.round(Math.abs(f.pctChange)),f.isUp=f.pctChange>=0,f}e.history={repositories:a([]),users:a([]),pageViews:a([]),pullRequests:a([])},t.get("/api/stat/history?days=60").then(u=>{let f=u.data||[];e.history={repositories:a(f.map(w=>w.nbRepositories||0)),users:a(f.map(w=>w.nbUsers||0)),pageViews:a(f.map(w=>w.nbPageViews||0)),pullRequests:a(f.map(w=>w.nbPullRequests||0))}})},ol=function(e,t,n,r,s,i){let a=ct();e.on("routeLeave",function(){$('[data-toggle="tooltip"]').tooltip("dispose")}),e.watch("user.status",()=>{e.user==null&&n.url("/")}),e.user==null&&n.url("/"),a.timeout(()=>{$('[data-toggle="tooltip"]').tooltip()},250),e.quotaExpanded=!1,e.closeQuota=()=>{e.quotaExpanded=!1,nt(()=>document.querySelector(".dashboard-quota > summary")?.focus())},Zt()(document,"click",S=>{e.quotaExpanded&&!S.target.closest?.(".dashboard-quota")& Line truncated
`)),e.options=Object.assign({},e.options,B.options),e.options.expirationDate=B.options&&B.options.expirationDate?new Date(B.options.expirationDate):T(),!r.repoId&&!r.pullRequestId&&!r.gistId&&!e.anonymize?.terms?.dirty&&(e.terms=e.defaultTerms),C&&C()})}function M(C,I,B){e.anonymize&&e.anonymize[C]&&e.anonymize[C].setValidity(I,B)}function se(C){try{let I=parseGithubUrl(C);if(I&&I.owner&&I.repo)return I.owner+"/"+I.repo}catch{}return null}e.accessRepairAllowed=!1,e.repairingGitHubAccess=!1,e.accessRepairMessage="",e.repairGitHubAccess=async()=>{if(!e.accessRepairAllowed||e.repairingGitHubAccess||!e.githubConnections?.appEnabled||!r.repoId||e.role!=="owner"||e.githubConnection!=="github-app"||se(e.sourceUrl)!==e._originalFullName)return;e.repairingGitHubAccess=!0,e.accessRepairMessage="";let C=m();try{let I=await t.get("/github/connections");if(e.githubConnections=I.data,!I.data.appEnabled)return;let B=await t.post("/github/connections/migrate",{type:"repository",id:r.repoId,connection:"github-app"},{headers:{"X-CSRF-Token":I.data.csrf}});if(!k(C))return;e.error=null,B.data.fullName&&(e._originalFullName=B.data.fullName,e.source.fullName=B.data.fullName,e.sourceUrl="https://github.com/"+B.data.fullName),e.accessRepairMessage="GitHub access repaired. Your anonymous URL and published commit are unchanged.",await e.urlSelected(!0)}catch{k(C)&&(e.accessRepairMessage="Unable to repair GitHub access. Check the App's repository permissions in Manage access, then retry. Your published snapshot has not been replaced.")}finally{e.repairingGitHubAccess=!1,E(C)}},e.reconnectingSource=!1,e.reconnectRepositoryId=void 0,e.reconnectSource=async()=>{if(confirm("Reconnect to the repository currently at this GitHub URL? Review its branch and commit before saving. Saving will replace the published snapshot.")){e.reconnectingSource=!0,e.reconnectRepositoryId=void 0,e.source.commit="",e.source.branch="",e.readme="",e.branches=[];try{await Y()}catch{}}};function oe(){return e.reconnectingSource||!e.isUpdate||!e._originalRepositoryID?void 0:se(e.sourceUrl)===e._originalFullName?e._originalRepositoryID:void 0}async function S(){e._preservingDraft=!0;try{await e.urlSelected(!0)}finally{e._preservingDraft=!1}}async function O(){let C;try{C=JSON.parse(sessionStorage.getItem("github-access-draft")||"null")}catch{return!1}if(!C||C.path!==s.path()||Date.now()-C.savedAt>=30*6e4)return _.restore()?(e.sourceUrl&&await S(),!0):!1;_.restore();for(let I of["sourceUrl","terms","repoId","pullRequestId","gistId","source","options","conference","githubConnection"])Object.prototype.hasOwnProperty.call(C.draft,I)&&(e[I]=C.draft[I]);return e.options.expirationDate&&(e.options.expirationDate=new Date(e.options.expirationDate)),await S(),sessionStorage.removeItem("github-access-draft"),!0}V(()=>{!r.repoId&&!r.pullRequestId&&!r.gistId&&a(O,0),r.repoId&&r.repoId!=""&&(e.isUpdate=!0,e.detectedType="repo",e.repoId=r.repoId,t.get("/api/repo/"+e.repoId).then(async C=>{e.accessRepairAllowed=!["removed","archived","preparing","queue","download","removing","expiring"].includes(C.data.status),e.githubConnection=C.data.connection||"oauth",e.sourceUrl="https://github.com/"+C.data.source.fullName,e._originalFullName=C.data.source.fullName,e.terms=C.data.options.terms.filter(I=>I).join(`
`),e.source=C.data.source,e.role=C.data.role||"owner",e.coauthors=C.data.coauthors||[],e._originalBranch=C.data.source.branch,e.options=Object.assign({},e.options,C.data.options),e.conference=C.data.conference,e._originalConference=C.data.conference,e.repositoryID=C.data.source.repositoryID,e._originalRepositoryID=C.data.source.repositoryID,C.data.options.expirationDate&&(e.options.expirationDate=new Date(C.data.options.expirationDate)),y=g(parseGithubUrl(e.sourceUrl)),!await O()&&(await Promise.all([Y(),Z()]),ce())},()=>{s.url("/404")})),r.pullRequestId&&r.pullRequestId!=""&&(e.isUpdate=!0,e.detectedType="pr",e.pullRequestId=r.pullRequestId,t.get("/api/pr/"+e.pullRequestId).then(async C=>{if(e.githubConnection=C.data.connection||"oauth",e.sourceUrl="https://github.com/"+C.data.source.repositoryFullName+"/pull/"+C.data.source.pullRequestId,e.terms=C.data.options.terms.filter(I=>I).join(`
`),e.source=C.data.source,e.options=Object.assign({},e.options,C.data.options),e.conference=C.data.conference,e._originalConference=C.data.conference,C.data.options.expirationDate&&(e.options.expirationDate=new Date(C.data.options.expirationDate)),y=g(parseGithubUrl(e.sourceUrl)),!await O())try{await fe()}catch{}},()=>{s.url("/404")})),r.gistId&&r.gistId!=""&&(e.isUpdate=!0,e.detectedType="gist",e.gistId=r.gistId,t.get("/api/gist/"+e.gistId).then(async C=>{e.sourceUrl="https://gist.github.com/"+C.data.source.gistId,e.terms=C.data.options.terms.filter(I=>I).join(`
`),e.source=C.data.source,e.options=Object.assign({},e.options,C.data.options),e.conference=C.data.conference,e._originalConference=C.data.conference,C.data.options.expirationDate&&(e.options.expirationDate=new Date(C.data.options.expirationDate)),y=g(parseGithubUrl(e.sourceUrl)),!await O()&&await Le()},()=>{s.url("/404")}))}),t.get("/github/connections").then(C=>{e.githubConnections=C.data,!r.repoId&&!r.pullRequestId&&!r.gistId&&e.githubConnection===void 0&&C.data.appEnabled&&C.data.appConnected&&(e.githubConnection="github-app",e.sourceUrl&&e.workspaceOpen&&S())}).catch(()=>{}),e.urlSelected=async(C=!1)=>{let I=++f,B;try{B=parseGithubUrl(e.sourceUrl.trim())}catch{e.sourceLoading=!1,re.cancel(),_e.cancel(),Pe.cancel(),e.previewStatus="idle",e.sourceUrlError=e.sourceUrl?"Please provide a valid GitHub URL.":"",M("sourceUrl","github",!1);return}let U=g(B),v=C||y===U;y=U,e.sourceUrlError="",M("sourceUrl","github",!0);let N=document.activeElement?.id==="sourceUrl-landing";e.workspaceOpen=!0,N&&a(()=>document.getElementById("sourceUrl")?.focus(),0),e.reconnectingSource=!1,e.reconnectRepositoryId=void 0,!v&&!e.isUpdate&&(e.repoId="",e.pullRequestId="",e.gistId=""),e.details=null,e.branches=[],v||(e.source={type:"GitHubStream",branch:"",commit:""}),re.cancel(),_e.cancel(),Pe.cancel(),le.clear(),Re.clear(),e.previewStatus="idle",e.anonymize_readme="",e.readme="",e.html_readme="",e.detectedType=null,e.gistOAuthRequired=!1,e.gistAppRequired=!1,e._preservingDraft=v;try{B.gistId&&!B.repo?(e.detectedType="gist",e.source={gistId:B.gistId},await Le()):B.pullRequestId?(e.detectedType="pr",e.source={repositoryFullName:B.owner+"/"+B.repo,pullRequestId:B.pullRequestId},await fe()):(e.detectedType="repo",await Promise.all([Y(),Z()]),ce())}catch{}finally{I===f&&(e._preservingDraft=!1)}$('[data-toggle="tooltip"]').tooltip()},$('[data-toggle="tooltip"]').tooltip(),e.watch("source.branch",async()=>{if(e.detectedType!=="repo")return;let C=e.branches.filter(B=>B.name==e.source.branch)[0];if(!C)return;!(!e.reconnectingSource&&e.isUpdate&&e._originalBranch===e.source.branch&&e.source.commit)&&!(e._preservingDraft&&e.source.commit)&&(e.source.commit=C.commit),e.readme=C.readme,await Z(),ce()}),e.getBranches=async C=>{let I=parseGithubUrl(e.sourceUrl),B=m();try{let U=await t.get(`/api/repo/${I.owner}/${I.repo}/branches`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&r.repoId&&se(e.sourceUrl)===e._originalFullName?r.repoId:void 0,connection:e.githubConnection,force:C===!0||e.reconnectingSource?"1":"0",repositoryID:oe()}});if(!k(B))return;e.branches=U.data,e.sourceUnreachable=!1,e.source.branch||(e.source.branch=e.details.defaultBranch);let v=e.branches.filter(N=>N.name==e.source.branch);v.length>0&&(!(!e.reconnectingSource&&!C&&e.isUpdate&&!e.options.update&&e._originalBranch===e.source.branch&&e.source.commit)&&!(e._preservingDraft&&e.source.commit)&&(e.source.commit=v[0].commit),e.readme=v[0].readme,await Z(C))}catch(U){if(!k(B))return;e.branches=[],e.sourceUnreachable=U&&(U.status===404||U.data&&U.data.error==="repo_not_found");let v=U&&U.data&&U.data.error||(U&&U.status===404?"repo_not_found":"unknown_error");i("ERRORS."+v).then(N=>{e.toasts=e.toasts||[],e.addToast({title:"Error",date:new Date,body:N}),e.error=N},console.error),typeof M=="function"&&M("sourceUrl","missing",!1)}finally{E(B)}};async function Y(){let C=parseGithubUrl(e.sourceUrl),I=m();try{z();let B=await t.get(`/api/repo/${C.owner}/${C.repo}/`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&r.repoId&&se(e.sourceUrl)===e._originalFullName?r.repoId:void 0,connection:e.githubConnection,repositoryID:oe(),force:"1"}});if(!k(I))return;e.details=B.data,e.reconnectingSource&&(e.reconnectRepositoryId=e.details.externalId),e.details&&e.details.id&&(e.repositoryID=e.details.id),e.repoId||(e.repoId=e.details.repo+"-"+generateRandomId(4)),await e.getBranches(e.reconnectingSource)}catch(B){if(!k(I))return;throw B.data&&(i("ERRORS."+B.data.error).then(U=>{e.addToast({title:"Error",date:new Date,body:U}),e.error=U},console.error),Q(B.data.error)),M("sourceUrl","missing",!1),B}finally{E(I)}}async function Z(C){if(e.readme&&!C)return e.readme;let I=parseGithubUrl(e.sourceUrl),B=m();try{let U=await t.get(`/api/repo/${I.owner}/${I.repo}/readme`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&r.repoId&&se(e.sourceUrl)===e._originalFullName?r.repoId:void 0,connection:e.githubConnection,force:C===!0?"1":"0",branch:e.source.branch,repositoryID:oe()}});k(B,!0)&&(e.readme=U.data)}catch{k(B,!0)&&(e.readme="")}finally{E(B)}}function te(){let C={terms:e.terms?e.terms.split(`
`):[],image:!!e.options.image,link:!!e.options.link,repoId:e.repoId};e.source&&e.source.branch&&(C.branchName=e.source.branch);try{let I=parseGithubUrl(e.sourceUrl);C.repoName=`${I.owner}/${I.repo}`}catch{}return C}function J(C,I,B){let U=null,v=0,N=()=>{if(e.detectedType!==C)return;U&&a.cancel(U);let q=++v;e.previewStatus="loading",U=a(()=>{U=null;let H=I();if(!H){e.previewStatus="idle";return}t.post("/api/anonymize-preview",H).then(j=>{q===v&&(B(j.data,H),e.previewStatus="ready")}).catch(()=>{q===v&&(e.previewStatus="error")})},200)};return N.cancel=()=>{v++,U&&a.cancel(U),U=null},e.on("dispose",N.cancel),N}e.retryPreview=()=>{e.detectedType==="repo"&&re(),e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Pe()};let re=J("repo",()=>e.readme?{content:e.readme,options:te()}:null,C=>{if(typeof C?.content!="string")throw Error("Invalid preview response");e.anonymize_readme=C.content;let I="";try{let U=parseGithubUrl(e.sourceUrl),v=e.source.branch||e.details&&e.details.defaultBranch||"main";I=`https://github.com/${U.owner}/${U.repo}/raw/${v}/`}catch{}let B=renderMD(e.anonymize_readme,I);e.html_readme=B,a(Prism.highlightAll,150)});function ce(){!e.anonymize||!e.anonymize.terms||(e.termsRegexWarning=!!e.terms&&!!e.terms.match(/[-[\]{}()*+?.,\\^$|#]/g),re())}async function fe(){let C=parseGithubUrl(e.sourceUrl),I=m();try{z();let B=await t.get(`/api/pr/${C.owner}/${C.repo}/${C.pullRequestId}`,{params:{connection:e.githubConnection}});if(!k(I))return;e.details=B.data,e.pullRequestId||(e.pullRequestId=C.repo+"-PR"+C.pullRequestId+"-"+generateRandomId(4))}catch(B){if(!k(I))return;throw B.data&&(i("ERRORS."+B.data.error).then(U=>{e.addToast({title:"Error",date:new Date,body:U}),e.error=U},console.error),Q(B.data.error)),M("sourceUrl","missing",!1),B}finally{E(I)}}let le=ze(new Map);function Oe(){let C=new Set,I=e.details&&e.details.pullRequest;if(!I)return C;typeof I.title=="string"&&C.add(I.title),typeof I.body=="string"&&C.add(I.body),typeof I.diff=="string"&&C.add(I.diff);let B=I.comments||[];for(let U of B)typeof U.author=="string"&&C.add(U.author),typeof U.body=="string"&&C.add(U.body);return C}let _e=J("pr",()=>{let C=Oe(),I=Array.from(C);return I.length===0?null:{contents:I,options:te()}},(C,I)=>{if(!Array.isArray(C?.contents)||C.contents.length!==I.contents.length||C.contents.some(v=>typeof v!="string"))throw Error("Invalid preview response");let B=I.contents,U=new Map;for(let v=0;v<B.length&&v<C.contents.length;v++)U.set(B[v],C.contents[v]);le.clear(),U.forEach((v,N)=>le.set(N,v))});e.anonymizePrContent=function(C){return C&&(le.has(C)?le.get(C):"")};async function Le(){let C=parseGithubUrl(e.sourceUrl),I=m();try{z(),e.gistOAuthRequired=!1,e.gistAppRequired=!1;let B=await t.get(`/api/gist/source/${C.gistId}`);if(!k(I))return;e.details=B.data,e.gistId||(e.gistId="gist-"+C.gistId.substring(0,6)+"-"+generateRandomId(4))}catch(B){if(!k(I))return;if(B.data?.error==="github_app_reconnect_required"){e.gistAppRequired=!0,M("sourceUrl","missing",!1);return}if(B.data?.error==="github_oauth_required"){e.gistOAuthRequired=!0,M("sourceUrl","missing",!1);return}throw B.data&&(i("ERRORS."+B.data.error).then(U=>{e.addToast({title:"Error",date:new Date,body:U}),e.error=U},console.error),Q(B.data.error)),M("sourceUrl","missing",!1),B}finally{E(I)}}let Re=ze(new Map);function Me(){let C=new Set,I=e.details&&e.details.gist;if(!I)return C;typeof I.description=="string"&&C.add(I.description),typeof I.ownerLogin=="string"&&C.add(I.ownerLogin);let B=I.files||[];for(let v of B)typeof v.filename=="string"&&C.add(v.filename),typeof v.content=="string"&&C.add(v.content);let U=I.comments||[];for(let v of U)typeof v.author=="string"&&C.add(v.author),typeof v.body=="string"&&C.add(v.body);return C}let Pe=J("gist",()=>{let C=Me(),I=Array.from(C);return I.length===0?null:{contents:I,options:te()}},(C,I)=>{if(!Array.isArray(C?.contents)||C.contents.length!==I.contents.length||C.contents.some(v=>typeof v!="string"))throw Error("Invalid preview response");let B=I.contents,U=new Map;for(let v=0;v<B.length&&v<C.contents.length;v++)U.set(B[v],C.contents[v]);Re.clear(),U.forEach((v,N)=>Re.set(N,v)),He()});e.anonymizeGistContent=function(C){return C&&(Re.has(C)?Re.get(C):"")},e.previewGistFiles=[];function He(){let C=e.details&&e.details.gist&&e.details.gist.files||[];e.previewGistFiles=C.map(I=>({filename:e.anonymizeGistContent(I.filename),content:e.anonymizeGistContent(I.content),language:I.language}))}e.watch("details.gist.files",He,!0),e.watch("terms",He);function Ee(){let C=e.conference;if(e.conference_data=null,!C)return;let I=e.isUpdate&&C===e._originalConference;t.get("/api/conferences/"+C).then(B=>{e.conference===C&&(e.conference_data=B.data,e.conference_data.startDate=new Date(e.conference_data.startDate),e.conference_data.endDate=new Date(e.conference_data.endDate),!I&&(e.options.expirationDate=new Date(e.conference_data.endDate),e.options.expirationMode="remove",e.options.update=e.conference_data.options.update,e.options.image=e.confe Line truncated
`).filter(N=>N),connection:e.githubConnection,fullName:`${B.owner}/${B.repo}`,repository:e.sourceUrl,reconnectRepositoryId:e.reconnectRepositoryId,options:e.options,source:e.source,conference:e.conference};e.details&&(U.options.pageSource=e.details.pageSource),z();let v=e.isUpdate?"/api/repo/"+e.repoId:"/api/repo/";t.post(v,U,{headers:{"Content-Type":"application/json"}}).then(()=>{_.clear(),window.location.href="/status/"+e.repoId},N=>{N.data&&(i("ERRORS."+N.data.error).then(q=>{e.error=q},console.error),Q(N.data.error))}).finally(()=>{I.disabled=!1})},e.anonymizeGist=C=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(ne())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let I=C.currentTarget||C.target.closest?.("button")||C.target;I.disabled=!0;let B=parseGithubUrl(e.sourceUrl),U={gistId:e.gistId,terms:e.terms.trim().split(`
`).filter(N=>N),source:{gistId:B.gistId},options:e.options,conference:e.conference};z();let v=e.isUpdate?"/api/gist/"+e.gistId:"/api/gist/";t.post(v,U,{headers:{"Content-Type":"application/json"}}).then(()=>{_.clear(),window.location.href="/gist/"+e.gistId},N=>{N.data&&(i("ERRORS."+N.data.error).then(q=>{e.error=q},console.error),Q(N.data.error))}).finally(()=>{I.disabled=!1})},e.anonymizePullRequest=C=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(ne())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let I=C.currentTarget||C.target.closest?.("button")||C.target;I.disabled=!0;let B=parseGithubUrl(e.sourceUrl),U={pullRequestId:e.pullRequestId,connection:e.githubConnection,terms:e.terms.trim().split(`
`).filter(N=>N),source:{repositoryFullName:`${B.owner}/${B.repo}`,pullRequestId:B.pullRequestId},options:e.options,conference:e.conference};z();let v=e.isUpdate?"/api/pr/"+e.pullRequestId:"/api/pr/";t.post(v,U,{headers:{"Content-Type":"application/json"}}).then(()=>{_.clear(),window.location.href="/pr/"+e.pullRequestId},N=>{N.data&&(i("ERRORS."+N.data.error).then(q=>{e.error=q},console.error),Q(N.data.error))}).finally(()=>{I.disabled=!1})},e.watch("conference",()=>{Ee()}),e.watch("terms",()=>{e.detectedType==="repo"&&ce(),e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Pe()}),e.watch("options.image",()=>{e.detectedType==="repo"&&ce(),e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Pe()}),e.watch("options.link",()=>{e.detectedType==="repo"&&ce(),e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Pe()}),e.watch("details",()=>{e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Pe()},!0)},ar=function(e,t,n,r,s,i){let a=ct();window.Prism?.hooks&&!window.Prism.redactionHook&&(window.Prism.hooks.add("complete",O=>Ya(O.element)),window.Prism.redactionHook=!0);let u=Zt();e.on("dark-mode",(O,Y)=>{e.aceOption&&(Y?e.aceOption.theme="nord_dark":e.aceOption.theme="chrome")});let f=0,w=!1;e.on("dispose",()=>{w=!0,f++,h&&h.resolve()}),e.files=[],e.isMac=/Mac|iPhone|iPad|iPod/.test(navigator.platform||navigator.userAgent),e.fileSearchQuery="",e.fileSearchResults=null,e.fileSearchLoading=!1,u(document,"keydown",function(O){if((O.metaKey||O.ctrlKey)&&O.key==="k"){O.preventDefault();var Y=document.querySelector(".tree-search-input");Y&&(Y.focus(),Y.select())}});var h=null;e.onFileSearchChange=function(){h&&(h.resolve(),h=null);let O=e.fileSearchQuery;if(!O||O.length<2){e.fileSearchResults=null,e.fileSearchLoading=!1;return}e.fileSearchLoading=!0;let Y=i.defer();h=Y,t.get(`/api/repo/${e.repoId}/files/search?q=${encodeURIComponent(O)}`,{timeout:Y.promise}).then(function(Z){if(!(w||h!==Y)){h=null,e.fileSearchLoading=!1;var te={};e.files.forEach(function(z){te[(z.path||"")+"/"+z.name]=!0});for(var J=[],re={},ce=0;ce<Z.data.length;ce++){var fe=Z.data[ce];if(fe.path)for(var le=fe.path.split("/"),Oe="",_e=0;_e<le.length;_e++){var Le=Oe;Oe=Oe?Oe+"/"+le[_e]:le[_e];var Re=Le+"/"+le[_e];!te[Re]&&!re[Re]&&(re[Re]=!0,J.push({name:le[_e],path:Le}))}}J.sort(function(z,ne){return(z.path||"").split("/").length-(ne.path||"").split("/").length}),J.length>0&&e.files.push.apply(e.files,J);for(var Me=[],Pe=0;Pe<Z.data.length;Pe++){var He=Z.data[Pe],Ee=(He.path||"")+"/"+He.name;!te[Ee]&&He.size!=null&&(Me.push(He),te[Ee]=!0)}Me.length>0&&e.files.push.apply(e.files,Me),e.fileSearchResults=Z.data}},function(){!w&&h===Y&&(h=null,e.fileSearchLoading=!1,e.fileSearchResults=[])})};let k={yml:"yaml",txt:"text",py:"python",js:"javascript",ts:"typescript"},m=["license","txt"],E=["png","jpg","jpeg","gif","svg","ico","bmp","tiff","tif","webp","avif","heif","heic"],y=["wav","mp3","ogg","wma","flac","aac","m4a"],g=["mp4","avi","webm","mov","mpg","mpeg","mkv","flv","wmv","3gp","3g2","m4v","f4v","f4p","f4a","f4b"];e.on("routeUpdate",function(O,Y){if(e.repoId!=r.repoId)return S();if((r.path||"")!=e.filePath){e.filePath=r.path||"",e.paths=e.filePath.split("/").filter(Z=>Z&&Z.trim().length>0),oe();for(let Z=0;Z<e.paths.length-1;Z++){let te=Z>0?e.paths.slice(0,Z).join("/"):"";e.files.some(re=>re.path===te)||e.getFiles(te)}}});function _(){if(e.paths[0]!="")return;let O=["readme.md","readme.txt","readme.org","readme.1st","readme"],Y={};for(let te of e.files)te.name.toLowerCase().indexOf("readme")>-1&&(Y[te.name.toLowerCase()]=te.name);let Z=null;for(let te of O)if(Y[te]){Z=te;break}if(!Z&&Object.keys(Y).length>0&&(Z=Object.keys(Y)[0]),Z){let te=n.url();te[te.length-1]!="/"&&(te+="/"),n.url(te+encodePathForUrl(Y[Z]))}}e.fileCounts=null,e.getFiles=function(O){let Y=e.repoId;return t.get(`/api/repo/${e.repoId}/files/?path=${encodeURIComponent(O)}&v=${e.options.lastUpdateDate}`).then(function(Z){if(w||Y!==e.repoId)return[];let te=O||"";return e.files=e.files.filter(J=>J.path!==te),e.files.push(...Z.data),Z.data},function(Z){if(w||Y!==e.repoId)return[];e.type="error",e.content=Z&&Z.data&&Z.data.error||"unknown_error",e.files=[]})};function R(){let O=e.repoId;t.get(`/api/repo/${e.repoId}/files/counts`).then(function(Y){w||O!==e.repoId||(e.fileCounts=Y.data)},function(){e.fileCounts={}})}function T(){return e.files.filter(O=>O.name==e.paths[e.paths.length-1]&&O.path==e.paths.slice(0,e.paths.length-1).join("/"))[0]}var P=null;e.on("dispose",function(){P&&a.interval.cancel(P)});function F(O){if(w)return;let Y=e.repoId;t.get(`/api/repo/${e.repoId}/options`).then(Z=>{if(!(w||Y!==e.repoId)){if(e.options=Z.data,e.options.url){window.location=e.options.url;return}O&&O(Z.data)}},Z=>{if(!(w||Y!==e.repoId)){var te=Z.data||{};if(te.error==="rate_limited"&&te.resetAt){let re=function(){var ce=Math.max(0,Math.ceil((e.rateLimitResetAt-Date.now())/1e3));if(ce<=0)e.rateLimitCountdown="",e.rateLimitResetAt=0,P&&(a.interval.cancel(P),P=null),F(O);else{var fe=Math.floor(ce/60),l Line truncated
`).map(m=>m.trim()).filter(m=>m.length>0),options:e.options};e.saving=!0,e.error=null,t.post("/api/user/default",k).then(()=>{a.accept(h),e.saving=!1,e.message=e.unsavedChanges?null:"Saved",f&&r.cancel(f),f=r(()=>{e.message=null},2500)},m=>{e.saving=!1;let C=m&&m.data&&m.data.error,y="Unable to save your defaults. Please try again.";Promise.all([n("ERRORS."+C),n("ERRORS.unknown_error")]).then(([g,S])=>{e.error=C&&g!==S?g:y},()=>{e.error=y})})},e.deleteAccount=()=>{confirm("Delete your account? All your anonymized repositories, gists, and pull requests will be removed, and your personal data will be erased. This cannot be undone.")&&(e.deletingAccount=!0,t.delete("/api/user").then(()=>{window.location.href="/"},()=>{e.deletingAccount=!1,e.deleteError="Unable to delete the account. Please try again."}))}},il=function(e,t,n){e.repoId=null,e.repoUrl=null,e.claim=()=>{t.post("/api/repo/claim",{repoId:e.repoId,repoUrl:e.repoUrl}).then(r=>{n.url("/dashboard")},r=>{e.error=r.data,e.claimForm.repoUrl.setValidity("not_found",!1),e.claimForm.repoId.setValidity("not_found",!1)})}},al=function(e,t,n,r,s){e.user&&!e.user.status&&n.url("/dashboard"),e.watch("user.status",()=>{e.user&&!e.user.status&&n.url("/dashboard")}),e.features=[{key:"anonymize",num:"01",eyebrow:"Anonymize",title:"Double-anonymous,",accent:"your rules.",text:"Choose what reviewers may see: links, images, PDFs, notebooks, GitHub Pages. Add your own terms, with regex if you need it, and pick the expiration date.",cta:"Start an anonymization",href:"/anonymize",url:"anonymous.4open.science/anonymize",img:"/imgs/anonymize.png",alt:"The anonymize form: source repository, terms to redact, options and a live README preview"},{key:"review",num:"02",eyebrow:"Review",title:"Reviewers browse",accent:"the real thing.",text:"Highlighted source code, rendered PDFs, images, and notebooks, in a familiar file explorer. GitHub Pages is also supported.",cta:"Open the example",href:"https://anonymous.4open.science/r/840c8c57-3c32-451e-bf12-0e20be300389/",target:"_self",url:"anonymous.4open.science/r/840c8c57-\u2026",img:"/imgs/explorer.png",alt:"The repository explorer with a file tree and a rendered README"},{key:"manage",num:"03",eyebrow:"Manage",title:"One dashboard,",accent:"until the decision.",text:"Monitor views, edit configuration, remove or update your repository. Program chairs can group submissions under a conference with one shared expiry.",cta:"Open the dashboard",href:"/dashboard",needsUser:!0,url:"anonymous.4open.science/dashboard",img:"/imgs/dashboard.png",alt:"The dashboard listing anonymized repositories with status, views and expiry"}],e.feature=e.features[0].key,e.selectFeature=function(u){e.feature=u},e.featureHref=function(u){return u.needsUser&&!e.user?"/signin":u.href},e.featureTarget=function(u){return u.needsUser&&!e.user?"_self":u.target||void 0},e.featureKeydown=function(u,f){let w={ArrowDown:1,ArrowRight:1,ArrowUp:-1,ArrowLeft:-1,Home:"first",End:"last"}[u.key];if(w===void 0)return;u.preventDefault();let h=e.features.length,k=w==="first"?0:w==="last"?h-1:(f+w+h)%h;e.feature=e.features[k].key,s(()=>{let m=r.document.getElementById("feature-tab-"+e.feature);m&&m.focus()})},e.cards=[{key:"repositories",total:0,label:"repositories anonymized"},{key:"users",total:0,label:"researchers"},{key:"pageViews",total:0,label:"page views"},{key:"pullRequests",total:0,label:"pull requests"}];function i(){t.get("/api/stat/").then(u=>{e.stat=u.data,e.cards[0].total=u.data.nbRepositories,e.cards[1].total=u.data.nbUsers,e.cards[2].total=u.data.nbPageViews,e.cards[3].total=u.data.nbPullRequests})}i();function a(u){let f={series:u,bars:[],viewW:100,deltaToday:0,pctChange:0,pctAbs:0,isUp:!0};if(!u||u.length<2)return f;let w=new Array(u.length-1);for(let g=1;g<u.length;g++)w[g-1]=u[g]-u[g-1];let h=w.length,k=Math.max.apply(null,w),m=Math.min.apply(null,w),C=Math.min(0,m),y=k-C||1;f.viewW=h*2,f.bars=new Array(h);for(let g=0;g<h;g++){let S=(w[g]-C)/y,R=Math.max(1.5,S*34);f.bars[g]={x:(g*2+.25).toFixed(2),y:(36-R).toFixed(2),w:"1.5",h:R.toFixed(2)}}if(f.deltaToday=w[h-1],h>=2){let g=w[h-2];g&&(f.pctChange=(f.deltaToday-g)/g*100)}return f.pctAbs=Math.round(Math.abs(f.pctChange)),f.isUp=f.pctChange>=0,f}e.history={repositories:a([]),users:a([]),pageViews:a([]),pullRequests:a([])},t.get("/api/stat/history?days=60").then(u=>{let f=u.data||[];e.history={repositories:a(f.map(w=>w.nbRepositories||0)),users:a(f.map(w=>w.nbUsers||0)),pageViews:a(f.map(w=>w.nbPageViews||0)),pullRequests:a(f.map(w=>w.nbPullRequests||0))}})},ll=function(e,t,n,r,s,i){let a=ut();e.on("routeLeave",function(){$('[data-toggle="tooltip"]').tooltip("dispose")}),e.watch("user.status",()=>{e.user==null&&n.url("/")}),e.user==null&&n.url("/"),a.timeout(()=>{$('[data-toggle="tooltip"]').tooltip()},250),e.quotaExpanded=!1,e.closeQuota=()=>{e.quotaExpanded=!1,ot(()=>document.querySelector(".dashboard-quota > summary")?.focus())},Zt()(document,"click",N=>{e.quotaExpanded&&!N.target.closest?.(".dashboard-quota")& Line truncated
`)),e.options=Object.assign({},e.options,B.options),e.options.expirationDate=B.options&&B.options.expirationDate?new Date(B.options.expirationDate):T(),!r.repoId&&!r.pullRequestId&&!r.gistId&&!e.anonymize?.terms?.dirty&&(e.terms=e.defaultTerms),_&&_()})}function M(_,q,B){e.anonymize&&e.anonymize[_]&&e.anonymize[_].setValidity(q,B)}function se(_){try{let q=parseGithubUrl(_);if(q&&q.owner&&q.repo)return q.owner+"/"+q.repo}catch{}return null}e.accessRepairAllowed=!1,e.repairingGitHubAccess=!1,e.accessRepairMessage="",e.repairGitHubAccess=async()=>{if(!e.accessRepairAllowed||e.repairingGitHubAccess||!e.githubConnections?.appEnabled||!r.repoId||e.role!=="owner"||e.githubConnection!=="github-app"||se(e.sourceUrl)!==e._originalFullName)return;e.repairingGitHubAccess=!0,e.accessRepairMessage="";let _=m();try{let q=await t.get("/github/connections");if(e.githubConnections=q.data,!q.data.appEnabled)return;let B=await t.post("/github/connections/migrate",{type:"repository",id:r.repoId,connection:"github-app"},{headers:{"X-CSRF-Token":q.data.csrf}});if(!k(_))return;e.error=null,B.data.fullName&&(e._originalFullName=B.data.fullName,e.source.fullName=B.data.fullName,e.sourceUrl="https://github.com/"+B.data.fullName),e.accessRepairMessage="GitHub access repaired. Your anonymous URL and published commit are unchanged.",await e.urlSelected(!0)}catch{k(_)&&(e.accessRepairMessage="Unable to repair GitHub access. Check the App's repository permissions in Manage access, then retry. Your published snapshot has not been replaced.")}finally{e.repairingGitHubAccess=!1,C(_)}},e.reconnectingSource=!1,e.reconnectRepositoryId=void 0,e.reconnectSource=async()=>{if(confirm("Reconnect to the repository currently at this GitHub URL? Review its branch and commit before saving. Saving will replace the published snapshot.")){e.reconnectingSource=!0,e.reconnectRepositoryId=void 0,e.source.commit="",e.source.branch="",e.readme="",e.branches=[];try{await Y()}catch{}}};function te(){return e.reconnectingSource||!e.isUpdate||!e._originalRepositoryID?void 0:se(e.sourceUrl)===e._originalFullName?e._originalRepositoryID:void 0}async function N(){e._preservingDraft=!0;try{await e.urlSelected(!0)}finally{e._preservingDraft=!1}}async function I(){let _;try{_=JSON.parse(sessionStorage.getItem("github-access-draft")||"null")}catch{return!1}if(!_||_.path!==s.path()||Date.now()-_.savedAt>=30*6e4)return S.restore()?(e.sourceUrl&&await N(),!0):!1;S.restore();for(let q of["sourceUrl","terms","repoId","pullRequestId","gistId","source","options","conference","githubConnection"])Object.prototype.hasOwnProperty.call(_.draft,q)&&(e[q]=_.draft[q]);return e.options.expirationDate&&(e.options.expirationDate=new Date(e.options.expirationDate)),await N(),sessionStorage.removeItem("github-access-draft"),!0}V(()=>{!r.repoId&&!r.pullRequestId&&!r.gistId&&a(I,0),r.repoId&&r.repoId!=""&&(e.isUpdate=!0,e.detectedType="repo",e.repoId=r.repoId,t.get("/api/repo/"+e.repoId).then(async _=>{e.accessRepairAllowed=!["removed","archived","preparing","queue","download","removing","expiring"].includes(_.data.status),e.githubConnection=_.data.connection||"oauth",e.sourceUrl="https://github.com/"+_.data.source.fullName,e._originalFullName=_.data.source.fullName,e.terms=_.data.options.terms.filter(q=>q).join(`
`),e.source=_.data.source,e.role=_.data.role||"owner",e.coauthors=_.data.coauthors||[],e._originalBranch=_.data.source.branch,e.options=Object.assign({},e.options,_.data.options),e.conference=_.data.conference,e._originalConference=_.data.conference,e.repositoryID=_.data.source.repositoryID,e._originalRepositoryID=_.data.source.repositoryID,_.data.options.expirationDate&&(e.options.expirationDate=new Date(_.data.options.expirationDate)),y=g(parseGithubUrl(e.sourceUrl)),!await I()&&(await Promise.all([Y(),Z()]),pe())},()=>{s.url("/404")})),r.pullRequestId&&r.pullRequestId!=""&&(e.isUpdate=!0,e.detectedType="pr",e.pullRequestId=r.pullRequestId,t.get("/api/pr/"+e.pullRequestId).then(async _=>{if(e.githubConnection=_.data.connection||"oauth",e.sourceUrl="https://github.com/"+_.data.source.repositoryFullName+"/pull/"+_.data.source.pullRequestId,e.terms=_.data.options.terms.filter(q=>q).join(`
`),e.source=_.data.source,e.options=Object.assign({},e.options,_.data.options),e.conference=_.data.conference,e._originalConference=_.data.conference,_.data.options.expirationDate&&(e.options.expirationDate=new Date(_.data.options.expirationDate)),y=g(parseGithubUrl(e.sourceUrl)),!await I())try{await fe()}catch{}},()=>{s.url("/404")})),r.gistId&&r.gistId!=""&&(e.isUpdate=!0,e.detectedType="gist",e.gistId=r.gistId,t.get("/api/gist/"+e.gistId).then(async _=>{e.sourceUrl="https://gist.github.com/"+_.data.source.gistId,e.terms=_.data.options.terms.filter(q=>q).join(`
`),e.source=_.data.source,e.options=Object.assign({},e.options,_.data.options),e.conference=_.data.conference,e._originalConference=_.data.conference,_.data.options.expirationDate&&(e.options.expirationDate=new Date(_.data.options.expirationDate)),y=g(parseGithubUrl(e.sourceUrl)),!await I()&&await Le()},()=>{s.url("/404")}))}),t.get("/github/connections").then(_=>{e.githubConnections=_.data,!r.repoId&&!r.pullRequestId&&!r.gistId&&e.githubConnection===void 0&&_.data.appEnabled&&_.data.appConnected&&(e.githubConnection="github-app",e.sourceUrl&&e.workspaceOpen&&N())}).catch(()=>{}),e.urlSelected=async(_=!1)=>{let q=++f,B;try{B=parseGithubUrl(e.sourceUrl.trim())}catch{e.sourceLoading=!1,ie.cancel(),Se.cancel(),Ie.cancel(),e.previewStatus="idle",e.sourceUrlError=e.sourceUrl?"Please provide a valid GitHub URL.":"",M("sourceUrl","github",!1);return}let v=g(B),E=_||y===v;y=v,e.sourceUrlError="",M("sourceUrl","github",!0);let O=document.activeElement?.id==="sourceUrl-landing";e.workspaceOpen=!0,O&&a(()=>document.getElementById("sourceUrl")?.focus(),0),e.reconnectingSource=!1,e.reconnectRepositoryId=void 0,!E&&!e.isUpdate&&(e.repoId="",e.pullRequestId="",e.gistId=""),e.details=null,e.branches=[],E||(e.source={type:"GitHubStream",branch:"",commit:""}),ie.cancel(),Se.cancel(),Ie.cancel(),ae.clear(),De.clear(),e.previewStatus="idle",e.anonymize_readme="",e.readme="",e.html_readme="",e.detectedType=null,e.gistOAuthRequired=!1,e.gistAppRequired=!1,e._preservingDraft=E;try{B.gistId&&!B.repo?(e.detectedType="gist",e.source={gistId:B.gistId},await Le()):B.pullRequestId?(e.detectedType="pr",e.source={repositoryFullName:B.owner+"/"+B.repo,pullRequestId:B.pullRequestId},await fe()):(e.detectedType="repo",await Promise.all([Y(),Z()]),pe())}catch{}finally{q===f&&(e._preservingDraft=!1)}$('[data-toggle="tooltip"]').tooltip()},$('[data-toggle="tooltip"]').tooltip(),e.watch("source.branch",async()=>{if(e.detectedType!=="repo")return;let _=e.branches.filter(B=>B.name==e.source.branch)[0];if(!_)return;!(!e.reconnectingSource&&e.isUpdate&&e._originalBranch===e.source.branch&&e.source.commit)&&!(e._preservingDraft&&e.source.commit)&&(e.source.commit=_.commit),e.readme=_.readme,await Z(),pe()}),e.getBranches=async _=>{let q=parseGithubUrl(e.sourceUrl),B=m();try{let v=await t.get(`/api/repo/${q.owner}/${q.repo}/branches`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&r.repoId&&se(e.sourceUrl)===e._originalFullName?r.repoId:void 0,connection:e.githubConnection,force:_===!0||e.reconnectingSource?"1":"0",repositoryID:te()}});if(!k(B))return;e.branches=v.data,e.sourceUnreachable=!1,e.source.branch||(e.source.branch=e.details.defaultBranch);let E=e.branches.filter(O=>O.name==e.source.branch);E.length>0&&(!(!e.reconnectingSource&&!_&&e.isUpdate&&!e.options.update&&e._originalBranch===e.source.branch&&e.source.commit)&&!(e._preservingDraft&&e.source.commit)&&(e.source.commit=E[0].commit),e.readme=E[0].readme,await Z(_))}catch(v){if(!k(B))return;e.branches=[],e.sourceUnreachable=v&&(v.status===404||v.data&&v.data.error==="repo_not_found");let E=v&&v.data&&v.data.error||(v&&v.status===404?"repo_not_found":"unknown_error");i("ERRORS."+E).then(O=>{e.toasts=e.toasts||[],e.addToast({title:"Error",date:new Date,body:O}),e.error=O},console.error),typeof M=="function"&&M("sourceUrl","missing",!1)}finally{C(B)}};async function Y(){let _=parseGithubUrl(e.sourceUrl),q=m();try{U();let B=await t.get(`/api/repo/${_.owner}/${_.repo}/`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&r.repoId&&se(e.sourceUrl)===e._originalFullName?r.repoId:void 0,connection:e.githubConnection,repositoryID:te(),force:"1"}});if(!k(q))return;e.details=B.data,e.reconnectingSource&&(e.reconnectRepositoryId=e.details.externalId),e.details&&e.details.id&&(e.repositoryID=e.details.id),e.repoId||(e.repoId=e.details.repo+"-"+generateRandomId(4)),await e.getBranches(e.reconnectingSource)}catch(B){if(!k(q))return;throw B.data&&(i("ERRORS."+B.data.error).then(v=>{e.addToast({title:"Error",date:new Date,body:v}),e.error=v},console.error),X(B.data.error)),M("sourceUrl","missing",!1),B}finally{C(q)}}async function Z(_){if(e.readme&&!_)return e.readme;let q=parseGithubUrl(e.sourceUrl),B=m();try{let v=await t.get(`/api/repo/${q.owner}/${q.repo}/readme`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&r.repoId&&se(e.sourceUrl)===e._originalFullName?r.repoId:void 0,connection:e.githubConnection,force:_===!0?"1":"0",branch:e.source.branch,repositoryID:te()}});k(B,!0)&&(e.readme=v.data)}catch{k(B,!0)&&(e.readme="")}finally{C(B)}}function ee(){let _={terms:e.terms?e.terms.split(`
`):[],image:!!e.options.image,link:!!e.options.link,repoId:e.repoId};e.source&&e.source.branch&&(_.branchName=e.source.branch);try{let q=parseGithubUrl(e.sourceUrl);_.repoName=`${q.owner}/${q.repo}`}catch{}return _}function J(_,q,B){let v=null,E=0,O=()=>{if(e.detectedType!==_)return;v&&a.cancel(v);let H=++E;e.previewStatus="loading",v=a(()=>{v=null;let F=q();if(!F){e.previewStatus="idle";return}t.post("/api/anonymize-preview",F).then(j=>{H===E&&(B(j.data,F),e.previewStatus="ready")}).catch(()=>{H===E&&(e.previewStatus="error")})},200)};return O.cancel=()=>{E++,v&&a.cancel(v),v=null},e.on("dispose",O.cancel),O}e.retryPreview=()=>{e.detectedType==="repo"&&ie(),e.detectedType==="pr"&&Se(),e.detectedType==="gist"&&Ie()};let ie=J("repo",()=>e.readme?{content:e.readme,options:ee()}:null,_=>{if(typeof _?.content!="string")throw Error("Invalid preview response");e.anonymize_readme=_.content;let q="";try{let v=parseGithubUrl(e.sourceUrl),E=e.source.branch||e.details&&e.details.defaultBranch||"main";q=`https://github.com/${v.owner}/${v.repo}/raw/${E}/`}catch{}let B=renderMD(e.anonymize_readme,q);e.html_readme=B,a(Prism.highlightAll,150)});function pe(){!e.anonymize||!e.anonymize.terms||(e.termsRegexWarning=!!e.terms&&!!e.terms.match(/[-[\]{}()*+?.,\\^$|#]/g),ie())}async function fe(){let _=parseGithubUrl(e.sourceUrl),q=m();try{U();let B=await t.get(`/api/pr/${_.owner}/${_.repo}/${_.pullRequestId}`,{params:{connection:e.githubConnection}});if(!k(q))return;e.details=B.data,e.pullRequestId||(e.pullRequestId=_.repo+"-PR"+_.pullRequestId+"-"+generateRandomId(4))}catch(B){if(!k(q))return;throw B.data&&(i("ERRORS."+B.data.error).then(v=>{e.addToast({title:"Error",date:new Date,body:v}),e.error=v},console.error),X(B.data.error)),M("sourceUrl","missing",!1),B}finally{C(q)}}let ae=ze(new Map);function Ae(){let _=new Set,q=e.details&&e.details.pullRequest;if(!q)return _;typeof q.title=="string"&&_.add(q.title),typeof q.body=="string"&&_.add(q.body),typeof q.diff=="string"&&_.add(q.diff);let B=q.comments||[];for(let v of B)typeof v.author=="string"&&_.add(v.author),typeof v.body=="string"&&_.add(v.body);return _}let Se=J("pr",()=>{let _=Ae(),q=Array.from(_);return q.length===0?null:{contents:q,options:ee()}},(_,q)=>{if(!Array.isArray(_?.contents)||_.contents.length!==q.contents.length||_.contents.some(E=>typeof E!="string"))throw Error("Invalid preview response");let B=q.contents,v=new Map;for(let E=0;E<B.length&&E<_.contents.length;E++)v.set(B[E],_.contents[E]);ae.clear(),v.forEach((E,O)=>ae.set(O,E))});e.anonymizePrContent=function(_){return _&&(ae.has(_)?ae.get(_):"")};async function Le(){let _=parseGithubUrl(e.sourceUrl),q=m();try{U(),e.gistOAuthRequired=!1,e.gistAppRequired=!1;let B=await t.get(`/api/gist/source/${_.gistId}`);if(!k(q))return;e.details=B.data,e.gistId||(e.gistId="gist-"+_.gistId.substring(0,6)+"-"+generateRandomId(4))}catch(B){if(!k(q))return;if(B.data?.error==="github_app_reconnect_required"){e.gistAppRequired=!0,M("sourceUrl","missing",!1);return}if(B.data?.error==="github_oauth_required"){e.gistOAuthRequired=!0,M("sourceUrl","missing",!1);return}throw B.data&&(i("ERRORS."+B.data.error).then(v=>{e.addToast({title:"Error",date:new Date,body:v}),e.error=v},console.error),X(B.data.error)),M("sourceUrl","missing",!1),B}finally{C(q)}}let De=ze(new Map);function qe(){let _=new Set,q=e.details&&e.details.gist;if(!q)return _;typeof q.description=="string"&&_.add(q.description),typeof q.ownerLogin=="string"&&_.add(q.ownerLogin);let B=q.files||[];for(let E of B)typeof E.filename=="string"&&_.add(E.filename),typeof E.content=="string"&&_.add(E.content);let v=q.comments||[];for(let E of v)typeof E.author=="string"&&_.add(E.author),typeof E.body=="string"&&_.add(E.body);return _}let Ie=J("gist",()=>{let _=qe(),q=Array.from(_);return q.length===0?null:{contents:q,options:ee()}},(_,q)=>{if(!Array.isArray(_?.contents)||_.contents.length!==q.contents.length||_.contents.some(E=>typeof E!="string"))throw Error("Invalid preview response");let B=q.contents,v=new Map;for(let E=0;E<B.length&&E<_.contents.length;E++)v.set(B[E],_.contents[E]);De.clear(),v.forEach((E,O)=>De.set(O,E)),Ue()});e.anonymizeGistContent=function(_){return _&&(De.has(_)?De.get(_):"")},e.previewGistFiles=[];function Ue(){let _=e.details&&e.details.gist&&e.details.gist.files||[];e.previewGistFiles=_.map(q=>({filename:e.anonymizeGistContent(q.filename),content:e.anonymizeGistContent(q.content),language:q.language}))}e.watch("details.gist.files",Ue,!0),e.watch("terms",Ue);function Ee(){let _=e.conference;if(e.conference_data=null,!_)return;let q=e.isUpdate&&_===e._originalConference;t.get("/api/conferences/"+_).then(B=>{e.conference===_&&(e.conference_data=B.data,e.conference_data.startDate=new Date(e.conference_data.startDate),e.conference_data.endDate=new Date(e.conference_data.endDate),!q&&(e.options.expirationDate=new Date(e.conference_data.endDate),e.options.expirationMode="remove",e.options.update=e.conference_data.options.update,e.options.image=e.confe Line truncated
`).filter(O=>O),connection:e.githubConnection,fullName:`${B.owner}/${B.repo}`,repository:e.sourceUrl,reconnectRepositoryId:e.reconnectRepositoryId,options:e.options,source:e.source,conference:e.conference};e.details&&(v.options.pageSource=e.details.pageSource),U();let E=e.isUpdate?"/api/repo/"+e.repoId:"/api/repo/";t.post(E,v,{headers:{"Content-Type":"application/json"}}).then(()=>{S.clear(),window.location.href="/status/"+e.repoId},O=>{O.data&&(i("ERRORS."+O.data.error).then(H=>{e.error=H},console.error),X(O.data.error))}).finally(()=>{q.disabled=!1})},e.anonymizeGist=_=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(oe())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let q=_.currentTarget||_.target.closest?.("button")||_.target;q.disabled=!0;let B=parseGithubUrl(e.sourceUrl),v={gistId:e.gistId,terms:e.terms.trim().split(`
`).filter(O=>O),source:{gistId:B.gistId},options:e.options,conference:e.conference};U();let E=e.isUpdate?"/api/gist/"+e.gistId:"/api/gist/";t.post(E,v,{headers:{"Content-Type":"application/json"}}).then(()=>{S.clear(),window.location.href="/gist/"+e.gistId},O=>{O.data&&(i("ERRORS."+O.data.error).then(H=>{e.error=H},console.error),X(O.data.error))}).finally(()=>{q.disabled=!1})},e.anonymizePullRequest=_=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(oe())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let q=_.currentTarget||_.target.closest?.("button")||_.target;q.disabled=!0;let B=parseGithubUrl(e.sourceUrl),v={pullRequestId:e.pullRequestId,connection:e.githubConnection,terms:e.terms.trim().split(`
`).filter(O=>O),source:{repositoryFullName:`${B.owner}/${B.repo}`,pullRequestId:B.pullRequestId},options:e.options,conference:e.conference};U();let E=e.isUpdate?"/api/pr/"+e.pullRequestId:"/api/pr/";t.post(E,v,{headers:{"Content-Type":"application/json"}}).then(()=>{S.clear(),window.location.href="/pr/"+e.pullRequestId},O=>{O.data&&(i("ERRORS."+O.data.error).then(H=>{e.error=H},console.error),X(O.data.error))}).finally(()=>{q.disabled=!1})},e.watch("conference",()=>{Ee()}),e.watch("terms",()=>{e.detectedType==="repo"&&pe(),e.detectedType==="pr"&&Se(),e.detectedType==="gist"&&Ie()}),e.watch("options.image",()=>{e.detectedType==="repo"&&pe(),e.detectedType==="pr"&&Se(),e.detectedType==="gist"&&Ie()}),e.watch("options.link",()=>{e.detectedType==="repo"&&pe(),e.detectedType==="pr"&&Se(),e.detectedType==="gist"&&Ie()}),e.watch("details",()=>{e.detectedType==="pr"&&Se(),e.detectedType==="gist"&&Ie()},!0)},cr=function(e,t,n,r,s,i){let a=ut();window.Prism?.hooks&&!window.Prism.redactionHook&&(window.Prism.hooks.add("complete",I=>el(I.element)),window.Prism.redactionHook=!0);let u=Zt();e.on("dark-mode",(I,Y)=>{e.aceOption&&(Y?e.aceOption.theme="nord_dark":e.aceOption.theme="chrome")});let f=0,w=!1;e.on("dispose",()=>{w=!0,f++,h&&h.resolve()}),e.files=[],e.isMac=/Mac|iPhone|iPad|iPod/.test(navigator.platform||navigator.userAgent),e.fileSearchQuery="",e.fileSearchResults=null,e.fileSearchLoading=!1,u(document,"keydown",function(I){if((I.metaKey||I.ctrlKey)&&I.key==="k"){I.preventDefault();var Y=document.querySelector(".tree-search-input");Y&&(Y.focus(),Y.select())}});var h=null;e.onFileSearchChange=function(){h&&(h.resolve(),h=null);let I=e.fileSearchQuery;if(!I||I.length<2){e.fileSearchResults=null,e.fileSearchLoading=!1;return}e.fileSearchLoading=!0;let Y=i.defer();h=Y,t.get(`/api/repo/${e.repoId}/files/search?q=${encodeURIComponent(I)}`,{timeout:Y.promise}).then(function(Z){if(!(w||h!==Y)){h=null,e.fileSearchLoading=!1;var ee={};e.files.forEach(function(U){ee[(U.path||"")+"/"+U.name]=!0});for(var J=[],ie={},pe=0;pe<Z.data.length;pe++){var fe=Z.data[pe];if(fe.path)for(var ae=fe.path.split("/"),Ae="",Se=0;Se<ae.length;Se++){var Le=Ae;Ae=Ae?Ae+"/"+ae[Se]:ae[Se];var De=Le+"/"+ae[Se];!ee[De]&&!ie[De]&&(ie[De]=!0,J.push({name:ae[Se],path:Le}))}}J.sort(function(U,oe){return(U.path||"").split("/").length-(oe.path||"").split("/").length}),J.length>0&&e.files.push.apply(e.files,J);for(var qe=[],Ie=0;Ie<Z.data.length;Ie++){var Ue=Z.data[Ie],Ee=(Ue.path||"")+"/"+Ue.name;!ee[Ee]&&Ue.size!=null&&(qe.push(Ue),ee[Ee]=!0)}qe.length>0&&e.files.push.apply(e.files,qe),e.fileSearchResults=Z.data}},function(){!w&&h===Y&&(h=null,e.fileSearchLoading=!1,e.fileSearchResults=[])})};let k={yml:"yaml",txt:"text",py:"python",js:"javascript",ts:"typescript"},m=["license","txt"],C=["png","jpg","jpeg","gif","svg","ico","bmp","tiff","tif","webp","avif","heif","heic"],y=["wav","mp3","ogg","wma","flac","aac","m4a"],g=["mp4","avi","webm","mov","mpg","mpeg","mkv","flv","wmv","3gp","3g2","m4v","f4v","f4p","f4a","f4b"];e.on("routeUpdate",function(I,Y){if(e.repoId!=r.repoId)return N();if((r.path||"")!=e.filePath){e.filePath=r.path||"",e.paths=e.filePath.split("/").filter(Z=>Z&&Z.trim().length>0),te();for(let Z=0;Z<e.paths.length-1;Z++){let ee=Z>0?e.paths.slice(0,Z).join("/"):"";e.files.some(ie=>ie.path===ee)||e.getFiles(ee)}}});function S(){if(e.paths[0]!="")return;let I=["readme.md","readme.txt","readme.org","readme.1st","readme"],Y={};for(let ee of e.files)ee.name.toLowerCase().indexOf("readme")>-1&&(Y[ee.name.toLowerCase()]=ee.name);let Z=null;for(let ee of I)if(Y[ee]){Z=ee;break}if(!Z&&Object.keys(Y).length>0&&(Z=Object.keys(Y)[0]),Z){let ee=n.url();ee[ee.length-1]!="/"&&(ee+="/"),n.url(ee+encodePathForUrl(Y[Z]))}}e.fileCounts=null,e.getFiles=function(I){let Y=e.repoId;return t.get(`/api/repo/${e.repoId}/files/?path=${encodeURIComponent(I)}&v=${e.options.lastUpdateDate}`).then(function(Z){if(w||Y!==e.repoId)return[];let ee=I||"";return e.files=e.files.filter(J=>J.path!==ee),e.files.push(...Z.data),Z.data},function(Z){if(w||Y!==e.repoId)return[];e.type="error",e.content=ur(Z),e.files=[]})};function R(){let I=e.repoId;t.get(`/api/repo/${e.repoId}/files/counts`).then(function(Y){w||I!==e.repoId||(e.fileCounts=Y.data)},function(){e.fileCounts={}})}function T(){return e.files.filter(I=>I.name==e.paths[e.paths.length-1]&&I.path==e.paths.slice(0,e.paths.length-1).join("/"))[0]}var P=null;e.on("dispose",function(){P&&a.interval.cancel(P)});function L(I){if(w)return;let Y=e.repoId;t.get(`/api/repo/${e.repoId}/options`).then(Z=>{if(!(w||Y!==e.repoId)){if(e.options=Z.data,e.options.url){window.location=e.options.url;return}I&&I(Z.data)}},Z=>{if(!(w||Y!==e.repoId)){var ee=Z.data||{};if(ee.error==="rate_limited"&&ee.resetAt){let ie=function(){var pe=Math.max(0,Math.ceil((e.rateLimitResetAt-Date.now())/1e3));if(pe<=0)e.rateLimitCountdown="",e.rateLimitResetAt=0,P&&(a.interval.cancel(P),P=null),L(I);else{var fe=Math.floor(pe/60),ae=pe%60;e.rateLimitCountdown=fe>0?f Line truncated
`+g.join(`
`)],{type:"text/csv"}),R=document.createElement("a");R.href=URL.createObjectURL(_),R.download=r.username+"-repositories.csv",R.click()},e.showStatusMessage=m=>{let E=m.statusMessage||"(no message)";window.prompt(`Status message for ${m.repoId} (${m.status}):`,E)},e.fetchGithubInfo=m=>{let E=window.open("","_blank");E&&E.document.write("<pre>Loading GitHub info for "+m.repoId+"...</pre>"),t.get("/api/admin/repos/"+m.repoId+"/github").then(y=>{E&&(E.document.open(),E.document.write('<pre style="font:13px monospace;padding:16px;white-space:pre-wrap">'+JSON.stringify(y.data,null,2).replace(/[<>]/g,g=>g==="<"?"&lt;":"&gt;")+"</pre>"),E.document.close())},y=>{let g=y&&y.data?JSON.stringify(y.data,null,2):String(y);E&&(E.document.body.innerHTML='<pre style="color:#B42318;padding:16px">'+g+"</pre>")})};function f(m){t.get("/api/admin/users/"+m+"/repos",{}).then(E=>{e.repositories=E.data},E=>{console.error(E)})}function w(m){t.get("/api/admin/users/"+m,{}).then(E=>{e.userInfo=E.data},E=>{console.error(E)})}w(r.username),f(r.username),e.banUser=()=>{confirm(`Ban user ${r.username}?`)&&t.post(`/api/admin/users/${r.username}/ban`).then(()=>w(r.username),m=>console.error(m))},e.activateUser=()=>{t.post(`/api/admin/users/${r.username}/activate`).then(()=>w(r.username),m=>console.error(m))},e.promoteUser=()=>{confirm(`Promote ${r.username} to admin?`)&&t.post(`/api/admin/users/${r.username}/promote`).then(()=>w(r.username),m=>console.error(m))},e.demoteUser=()=>{confirm(`Remove admin privileges from ${r.username}?`)&&t.post(`/api/admin/users/${r.username}/demote`).then(()=>w(r.username),m=>console.error(m))},e.tokens=[],e.tokenForm={name:"",plaintext:null};function h(){t.get("/api/admin/tokens").then(m=>{e.tokens=m.data||[]},m=>{m.status!==401&&m.status!==403&&console.error(m)})}h(),e.createToken=()=>{e.tokenForm.name&&t.post("/api/admin/tokens",{name:e.tokenForm.name}).then(m=>{e.tokenForm.plaintext=m.data.token,e.tokenForm.name="",h()},m=>console.error(m))},e.revokeToken=m=>{confirm(`Revoke token "${m.name}"?`)&&t.delete("/api/admin/tokens/"+m.id).then(()=>h(),E=>console.error(E))},e.removeCache=m=>{confirm("Remove cached files for "+m.repoId+"?")&&t.delete("/api/admin/repos/"+m.repoId).then(()=>f(r.username),E=>console.error(E))},e.removeRepository=m=>{confirm("Remove repository "+m.repoId+"?")&&t.delete("/api/repo/"+m.repoId+"/").then(()=>f(r.username),E=>console.error(E))},e.updateRepository=m=>{let E=ze({title:`Refreshing ${m.repoId}...`,date:new Date,body:`The repository ${m.repoId} is going to be refreshed.`});e.toasts.push(E),t.post(`/api/repo/${m.repoId}/refresh`).then(y=>{y.data.status=="ready"?E.title=`${m.repoId} is refreshed.`:E.title=`Refreshing of ${m.repoId}.`},y=>{E.title=`Error during the refresh of ${m.repoId}.`,E.body=y.body})},e.getGitHubRepositories=m=>{t.get(`/api/user/${e.userInfo.username}/all_repositories`,{params:{force:"1"}}).then(E=>{e.userInfo.repositories=E.data})};let k=null;e.watch("query",()=>{s.timeout.cancel(k),k=s.timeout(()=>{f(r.username)},500)},!0)},fl=function(e,t,n){let r=ct(),s=Zt();e.Math=Math,e.watch("user.status",()=>{e.user==null&&n.url("/")}),e.user==null&&n.url("/"),e.conferences=[],e.total=-1,e.totalPage=0,e.statusCounts=[];let i=y=>{if(y.key==="/"&&!["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName)){y.preventDefault();let g=document.querySelector('.admin-filter-toolbar input[type="search"]');g&&g.focus()}};s(document,"keydown",i),e.on("dispose",()=>document.removeEventListener("keydown",i)),e.clearFilter=y=>{y==="dateRange"?(e.query.dateFrom="",e.query.dateTo=""):e.query[y]="",e.query.page=1},e.chips=[];let a=()=>{let y=[];(e.query.dateFrom||e.query.dateTo)&&y.push({key:"dateRange",label:"Date",value:(e.query.dateFrom||"\u2026")+" \u2013 "+(e.query.dateTo||"\u2026")}),e.chips=y};e.statusCountFor=y=>{let g=(e.statusCounts||[]).find(_=>_._id===y);return g?g.count:0},e.toggleSortDirection=()=>{e.query.direction=e.query.direction==="asc"?"desc":"asc"},e.sortBy=y=>{e.query.sort===y?e.query.direction=e.query.direction==="asc"?"desc":"asc":(e.query.sort=y,e.query.direction="desc"),e.query.page=1},e.sortIcon=y=>e.query.sort===y?e.query.direction==="asc"?"fa-arrow-up":"fa-arrow-down":"";let u="admin.conferences.filterPrefs",f={page:1,limit:25,sort:"name",direction:"asc",search:"",dateFrom:"",dateTo:"",ready:!1,expired:!1,removed:!1,error:!0,preparing:!0},w=loadFilterPrefs(u)||{};e.query=Object.assign({},f,w,{page:1,search:""});let h=n.search();h.search&&(e.query.search=h.search);let k="admin.conferences.presets";e.presets=JSON.parse(localStorage.getItem(k)||"[]"),e.savePreset=()=>{let y=window.prompt("Preset name:");if(!y)return;let g=Object.assign({},e.query);delete g.page,e.presets=(e.presets||[]).filter(_=>_.name!==y),e.presets.push({name:y,query:g}),localStorage.setItem(k,JSON.stringify(e.presets))},e.applyPreset=y=>{Object.assign(e.query,y.query,{page:1})},e.deletePreset=y=>{e.presets=(e.presets||[]).filter(g=>g.name!==y.name),localStorage.setItem(k,JS Line truncated
`).map((ce,fe)=>fe===0?ce:re+ce).join(`
`)}else typeof S=="number"||typeof S=="boolean"?J=String(S):J=JSON.stringify(S);se.push(`${Z}${J}${te}`)}),se.push("}"),se.join(`
`)}function w(R){let T=[],P="",F=/(\w+):(>=|<=|!=|>|<|=)?([^\s]+)/g,V=0,M;for(;M=F.exec(R);)P+=R.slice(V,M.index),V=F.lastIndex,T.push({key:M[1],op:M[2]||"=",val:M[3]});return P+=R.slice(V),{filters:T,free:P.trim().toLowerCase()}}function h(R,T){for(let P of T.filters){let F=(M,se,oe)=>{let S=parseFloat(M),O=parseFloat(se);return oe==="="?String(M)===String(se):oe==="!="?String(M)!==String(se):oe===">="?S>=O:oe==="<="?S<=O:oe===">"?S>O:oe==="<"?S<O:!0},V;if(P.key==="code")V=R.displayMessage;else if(P.key==="module")V=R.module;else if(P.key==="status")V=R._status;else if(P.key==="url")V=R._url;else if(P.key==="repo")V=R._repoId;else if(P.key==="level")V=R.level;else continue;if(V==null||!F(V,P.val,P.op))return!1}return!(T.free&&((R.displayMessage||"")+" "+(R.module||"")+" "+(R._url||"")+" "+JSON.stringify(R.raw||[])).toLowerCase().indexOf(T.free)===-1)}function k(){let R=w(e.query.search||"");e.parsedFilterCount=R.filters.length;let T=e.query.bucket,P=e.entries.filter(V=>T&&V._bucket!==T?!1:h(V,R)),F=e.query.group;if(F){let V=oe=>F==="module"?oe.module:oe.displayMessage||oe.message||"_",M=new Map;for(let oe of P){let S=V(oe);if(M.has(S)){let O=M.get(S);O.count++,O._related.push(oe),new Date(oe.ts)>new Date(O.ts)&&(O.ts=oe.ts,O._url=oe._url,O._status=oe._status),new Date(oe.ts)<new Date(O._firstSeen)&&(O._firstSeen=oe.ts)}else{let O=Object.assign({},oe);O._key=`${F}:${S}`,O._related=[oe],O._firstSeen=oe.ts,O._lastHourCount=0,O.count=1,M.set(S,O)}}let se=Date.now()-3600*1e3;for(let oe of M.values())oe._lastHourCount=oe._related.filter(S=>new Date(S.ts).getTime()>=se).length;P=Array.from(M.values())}else P=P.map((V,M)=>(V._key="row:"+M+":"+V.ts,V._related=[V],V._firstSeen=V.ts,V._lastHourCount=0,V.count=1,V));e.query.sort==="count"?P.sort((V,M)=>M.count-V.count||new Date(M.ts)-new Date(V.ts)):P.sort((V,M)=>new Date(M.ts)-new Date(V.ts)),e.visible=P}function m(R){let T=R?e.entries.length:0,P=R?e.pageSize:Math.max(e.pageSize,e.entries.length||e.pageSize);t.get("/api/admin/errors",{params:{offset:T,limit:P}}).then(F=>{let V=(F.data.entries||[]).map(u);e.entries=R?e.entries.concat(V):V,e.available=!!F.data.available,e.cap=F.data.max||e.cap,e.total=F.data.total||e.entries.length,k()},F=>console.error(F))}e.loadMore=()=>m(!0),e.canLoadMore=()=>e.entries.length<e.total;function E(){t.get("/api/admin/errors/stats").then(R=>{let T=R.data||{},P=T.prev24h?Math.round((T.last24h-T.prev24h)/T.prev24h*100):0;e.stats={last24h:T.last24h||0,prev24h:T.prev24h||0,delta:P,severity:T.severity||{error:0,warn:0,info:0},unique:T.unique||{error:0,warn:0,info:0},buckets:T.buckets||[],dropped:T.dropped||0}},R=>console.error(R))}function y(){m(),E()}e.barPx=(R,T)=>{let P=e.stats.buckets||[],F=0;for(let oe of P)F=Math.max(F,(oe.error||0)+(oe.warn||0)+(oe.info||0));if(!F)return 0;let V=(R.error||0)+(R.warn||0)+(R.info||0);if(!V)return 0;let M=Math.round(V/F*60),se=R[T]||0;return Math.round(se/V*M)},e.bucketTitle=R=>`${new Date(R.hour).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})} \xB7 ${R.error||0} err \xB7 ${R.warn||0} warn \xB7 ${R.info||0} info`,e.toggle=R=>{e.expanded[R._key]=!e.expanded[R._key]},e.setBucket=R=>{e.query.bucket=R},e.refreshNow=y,e.clearAll=()=>{confirm("Clear all captured errors?")&&t.delete("/api/admin/errors").then(y,R=>console.error(R))},e.exportCsv=()=>{let R=["ts","level","module","displayMessage","_status","_url","_repoId"],T=[R.join(",")];for(let M of e.visible)T.push(R.map(se=>{let oe=M[se]==null?"":String(M[se]);return/[",\n]/.test(oe)?`"${oe.replace(/"/g,'""')}"`:oe}).join(","));let P=new Blob([T.join(`
`)],{type:"text/csv;charset=utf-8"}),F=URL.createObjectURL(P),V=document.createElement("a");V.href=F,V.download=`errors-${new Date().toISOString().slice(0,19)}.csv`,document.body.appendChild(V),V.click(),document.body.removeChild(V),URL.revokeObjectURL(F)};function g(R){e.copyHint=`${R} copied`,s.timeout(()=>{e.copyHint=""},1500)}e.copyJson=R=>{navigator.clipboard.writeText(R._detailJson).then(()=>g("JSON"))},e.copyCurl=R=>{if(!R._url)return;let P=`curl -X ${R._method||"GET"} '${window.location.origin}${R._url}'`;navigator.clipboard.writeText(P).then(()=>g("curl"))},y();let _=r(()=>{e.query.autoRefresh&&y()},15e3);e.on("dispose",()=>r.cancel(_)),e.watch("query.search",k),e.watch("query.bucket",k),e.watch("query.sort",k),e.watch("query.group",k)},vl=function(e,t,n,r){if(e.Math=Math,e.watch("user.status",()=>{e.user==null&&n.url("/")}),e.user==null){n.url("/");return}e.data=null,e.loading=!0,e.error=null,e.performance=null,e.performanceMinutes=15,e.performanceTab="routes",e.performanceError=null,e.formatMs=function(y){return y==null?"":y<1e3?y+" ms":+(y/1e3).toFixed(1)+" s"},e.latencyBound=function(y,g){return y.count?y[g]==null?"> 60 s":"\u2264 "+e.formatMs(y[g]):"No samples"},e.firstByteBound=function(y){return e.latencyBound({count:y.firstByteCount,p95UpperMs:y.firstByteP95UpperMs},"p95UpperMs")},e.sampleAge=function(y){return Math.max(0,Math.round((Date.now()-y.sampledAt)/1e3))},e.peakRss=function(y){return(e.performance.runtimeSeries||[]).filter(function(g){return g.instance===y.instance}).reduce(function(g,_){return Math.max(g,_.rss)},y.memory.rss)},e.performanceWarning=function(y){return e.sampleAge(y)>45||y.droppedBatches||y.droppedMetrics||y.sockets?.closeWait>0||y.eventLoop.p95Ms>100||y.memoryLimitBytes&&y.memory.rss>y.memoryLimitBytes*.8};var s=!1;e.loadPerformance=function(){var y=e.performanceMinutes;e.performance?.windowMinutes&&e.performance.windowMinutes!==y&&(e.performance=null),!s&&(s=!0,t.get("/api/admin/performance",{params:{minutes:y}}).then(function(g){y===e.performanceMinutes&&(e.performance=g.data,e.performanceError=g.data.available?null:"Performance monitoring is unavailable. Request history may be incomplete.")},function(){y===e.performanceMinutes&&(e.performanceError="Could not refresh performance monitoring. Displayed samples may be stale.")}).finally(function(){s=!1,y!==e.performanceMinutes&&e.loadPerformance()}))};function i(y){if(y==null)return"\u2014";for(var g=["B","KB","MB","GB","TB"],_=0,R=y;R>=1024&&_<g.length-1;)R/=1024,_++;return R.toFixed(_>0?1:0)+" "+g[_]}e.humanBytes=i;function a(y){if(!y)return"\u2014";var g=Math.floor(y/86400),_=Math.floor(y%86400/3600),R=Math.floor(y%3600/60);return g>0?g+"d "+(_<10?"0":"")+_+"h":_>0?_+"h "+(R<10?"0":"")+R+"m":R+"m"}e.humanDuration=a;function u(y){return y==null?"\u2014":y>=1e6?(y/1e6).toFixed(1)+"M":y>=1e3?(y/1e3).toFixed(1)+"K":String(y)}e.humanNum=u,e.queueTotal=function(y){return y?(y.waiting||0)+(y.active||0)+(y.delayed||0)+(y.failed||0):0},e.statusCount=function(y){if(!e.data||!e.data.repos)return 0;for(var g=e.data.repos.statusBreakdown||[],_=0;_<g.length;_++)if(g[_]._id===y)return g[_].count;return 0},e.barPct=function(y){var g=e.data&&e.data.repos?e.data.repos.total:0;if(!g)return 0;var _=[y];y==="expired"&&_.push("expiring"),y==="removed"&&_.push("removing"),y==="preparing"&&_.push("download");var R=0;return _.forEach(function(T){R+=e.statusCount(T)}),Math.max(.4,R/g*100)},e.errPct=function(y){if(!e.data||!e.data.errors)return 0;var g=Math.max(e.data.errors.severity.error,e.data.errors.severity.warn,e.data.errors.severity.info,1);return e.data.errors.severity[y]/g*100};function f(y){var g=y||[];return g.map(function(_,R){var T=g[R-1]||{},P=Object.assign({},_);return P.dailyRepositories=R?Math.max(0,(_.nbRepositories||0)-(T.nbRepositories||0)):0,P.dailyUsers=R?Math.max(0,(_.nbUsers||0)-(T.nbUsers||0)):0,P.dailyPageViews=R?Math.max(0,(_.nbPageViews||0)-(T.nbPageViews||0)):0,P})}function w(y){var g=y&&y.length?y[y.length-1]:{};return{repositories:g.dailyRepositories||0,users:g.dailyUsers||0,pageViews:g.dailyPageViews||0}}var h={},k={};e.historyBarH=function(y,g){return!y||!h[g]?0:Math.max(1,Math.round(y[g]/h[g]*140))},e.historyRangeH=function(y,g){if(!y||h[g]==null)return 0;var _=h[g]-k[g];return _?Math.round(8+(y[g]-k[g])/_*132):70},e.historyRange=function(y){return{min:k[y],max:h[y]}},e.historyLabel=function(y){if(!y||!y.date)return"";var g=new Date(y.date);return g.getUTCMonth()+1+"/"+g.getUTCDate()};function m(){e.loadPerformance(),t.get("/api/admin/overview").then(function(y){y.data.history=f(y.data.history),y.data.daily={today:w(y.data.history)},e.data=y.data,e.loading=!1,e.error=null,h={},k={},(y.data.history||[]).forEach(function(g){["dailyPageViews","dailyRepositories","dailyUsers","nbUsers"].forEach(function(_){(!h[_]||g[_]>h[_])&&(h[_]=g[_]),(k[_]==null||g[_]<k[_])&&(k[_]=g[_])})})},function(y){e.loading=!1,e.error=y.data&&y.data.error||"Failed to load overview"})}m();var E=r(m,3e4);e.on("dispose",function(){r.can Line truncated
anonymous_github`)])])])])]),p(" Limitations "),o("h4",{class:"faq-cat"},[o("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[o("use",{href:"#ui-icon-warning"})]),b("Limitations ")]),o("div",{class:"panel-group",id:"faq-limitations",role:"tablist","aria-multiselectable":"true"},[o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingLimitation"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-limitations",href:"#limitation","aria-expanded":"false","aria-controls":"limitation"}," What are the limitations of Anonymous GitHub? ")])]),o("div",{id:"limitation",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingLimitation"},[o("div",{class:"panel-body p-3"},[o("ul",null,[o("li",null," Anonymous GitHub only anonymizes text-based files. Binary files (compiled executables, archives, etc.) are served as-is without anonymization. "),o("li",null," Files larger than 8 MB are not supported. "),o("li",null," Static site generators (such as Jekyll) used with GitHub Pages are not fully supported, although Markdown files are converted to HTML. "),o("li",null," The anonymization of terms within source code may change the behavior of the program (e.g., if a replaced term appears in a string literal or identifier). ")])])])])]),p(" Privacy & Security "),o("h4",{class:"faq-cat"},[o("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[o("use",{href:"#ui-icon-shield"})]),b("Privacy & Security ")]),o("div",{class:"panel-group",id:"faq-privacy",role:"tablist","aria-multiselectable":"true"},[o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingData"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-privacy",href:"#data","aria-expanded":"false","aria-controls":"data"}," How is my data handled? ")])]),o("div",{id:"data",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingData"},[o("div",{class:"panel-body p-3"},[o("p",null," Data stored on Anonymous GitHub is never shared or used for any purpose beyond providing the anonymization service. When a repository is removed or expires, only its configuration is retained \u2014 this makes it easy to restore the repository if needed and ensures that no future repository reuses the same ID. ")])])]),o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingPermissions"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-privacy",href:"#permissions","aria-expanded":"false","aria-controls":"permissions"}," Why does GitHub say Anonymous GitHub asks for write access? ")])]),o("div",{id:"permissions",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingPermissions"},[o("div",{class:"panel-body p-3"},[o("p",null,[b("The GitHub App has read-only access to the repositories you choose. You can change repository access on your "),o("a",{href:"/connections"},"GitHub connections"),b(" page.")]),o("p",null,"Legacy GitHub OAuth includes write access to private repositories because GitHub's OAuth scopes do not offer a read-only option for them. Existing OAuth anonymizations and gists can still use this connection."),o("p",null,"Anonymous GitHub reads repository content. It never pushes, modifies, or deletes files on GitHub.")])])]),o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingViewer"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-privacy",href:"#viewer","aria-expanded":"false","aria-controls":"viewer"}," Can repository owners see who viewed their anonymized repository? ")])]),o("div",{id:"viewer",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingViewer"},[o("div",{class:"panel-body p-3"},[o("p",null," No. Only the total number of views is tracked as an incremental counter. It is not possible for the repository owner or for Anonymous GitHub to identify individual viewers. Reviewer anonymity is fully preserved. ")])])])]),p(" Self-Hosting "),o("h4",{class:"faq-cat"},[o("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[o("use",{href:"#project-icon-storage"})]),b("Self-Hosting ")]),o("div",{class:"panel-group",id:"faq-hosting",role:"tablist","aria-multiselectable":"true"},[o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingDeploy"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-hosting",href:"#deploy","aria-expanded":"false","aria-controls":"deploy"}," Can I deploy my own instance? ")])]),o("div",{id:"deploy",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingDeploy"},[o("div",{class:"panel-body p-3"},[o("p",null,[b(" Yes. Anonymous Git Line truncated
`)],{type:"text/csv"}),R=document.createElement("a");R.href=URL.createObjectURL(S),R.download=r.username+"-repositories.csv",R.click()},e.showStatusMessage=m=>{let C=m.statusMessage||"(no message)";window.prompt(`Status message for ${m.repoId} (${m.status}):`,C)},e.fetchGithubInfo=m=>{let C=window.open("","_blank");C&&C.document.write("<pre>Loading GitHub info for "+m.repoId+"...</pre>"),t.get("/api/admin/repos/"+m.repoId+"/github").then(y=>{C&&(C.document.open(),C.document.write('<pre style="font:13px monospace;padding:16px;white-space:pre-wrap">'+JSON.stringify(y.data,null,2).replace(/[<>]/g,g=>g==="<"?"&lt;":"&gt;")+"</pre>"),C.document.close())},y=>{let g=y&&y.data?JSON.stringify(y.data,null,2):String(y);C&&(C.document.body.innerHTML='<pre style="color:#B42318;padding:16px">'+g+"</pre>")})};function f(m){t.get("/api/admin/users/"+m+"/repos",{}).then(C=>{e.repositories=C.data},C=>{console.error(C)})}function w(m){t.get("/api/admin/users/"+m,{}).then(C=>{e.userInfo=C.data},C=>{console.error(C)})}w(r.username),f(r.username),e.banUser=()=>{confirm(`Ban user ${r.username}?`)&&t.post(`/api/admin/users/${r.username}/ban`).then(()=>w(r.username),m=>console.error(m))},e.activateUser=()=>{t.post(`/api/admin/users/${r.username}/activate`).then(()=>w(r.username),m=>console.error(m))},e.promoteUser=()=>{confirm(`Promote ${r.username} to admin?`)&&t.post(`/api/admin/users/${r.username}/promote`).then(()=>w(r.username),m=>console.error(m))},e.demoteUser=()=>{confirm(`Remove admin privileges from ${r.username}?`)&&t.post(`/api/admin/users/${r.username}/demote`).then(()=>w(r.username),m=>console.error(m))},e.tokens=[],e.tokenForm={name:"",plaintext:null};function h(){t.get("/api/admin/tokens").then(m=>{e.tokens=m.data||[]},m=>{m.status!==401&&m.status!==403&&console.error(m)})}h(),e.createToken=()=>{e.tokenForm.name&&t.post("/api/admin/tokens",{name:e.tokenForm.name}).then(m=>{e.tokenForm.plaintext=m.data.token,e.tokenForm.name="",h()},m=>console.error(m))},e.revokeToken=m=>{confirm(`Revoke token "${m.name}"?`)&&t.delete("/api/admin/tokens/"+m.id).then(()=>h(),C=>console.error(C))},e.removeCache=m=>{confirm("Remove cached files for "+m.repoId+"?")&&t.delete("/api/admin/repos/"+m.repoId).then(()=>f(r.username),C=>console.error(C))},e.removeRepository=m=>{confirm("Remove repository "+m.repoId+"?")&&t.delete("/api/repo/"+m.repoId+"/").then(()=>f(r.username),C=>console.error(C))},e.updateRepository=m=>{let C=ze({title:`Refreshing ${m.repoId}...`,date:new Date,body:`The repository ${m.repoId} is going to be refreshed.`});e.toasts.push(C),t.post(`/api/repo/${m.repoId}/refresh`).then(y=>{y.data.status=="ready"?C.title=`${m.repoId} is refreshed.`:C.title=`Refreshing of ${m.repoId}.`},y=>{C.title=`Error during the refresh of ${m.repoId}.`,C.body=y.body})},e.getGitHubRepositories=m=>{t.get(`/api/user/${e.userInfo.username}/all_repositories`,{params:{force:"1"}}).then(C=>{e.userInfo.repositories=C.data})};let k=null;e.watch("query",()=>{s.timeout.cancel(k),k=s.timeout(()=>{f(r.username)},500)},!0)},bl=function(e,t,n){let r=ut(),s=Zt();e.Math=Math,e.watch("user.status",()=>{e.user==null&&n.url("/")}),e.user==null&&n.url("/"),e.conferences=[],e.total=-1,e.totalPage=0,e.statusCounts=[];let i=y=>{if(y.key==="/"&&!["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName)){y.preventDefault();let g=document.querySelector('.admin-filter-toolbar input[type="search"]');g&&g.focus()}};s(document,"keydown",i),e.on("dispose",()=>document.removeEventListener("keydown",i)),e.clearFilter=y=>{y==="dateRange"?(e.query.dateFrom="",e.query.dateTo=""):e.query[y]="",e.query.page=1},e.chips=[];let a=()=>{let y=[];(e.query.dateFrom||e.query.dateTo)&&y.push({key:"dateRange",label:"Date",value:(e.query.dateFrom||"\u2026")+" \u2013 "+(e.query.dateTo||"\u2026")}),e.chips=y};e.statusCountFor=y=>{let g=(e.statusCounts||[]).find(S=>S._id===y);return g?g.count:0},e.toggleSortDirection=()=>{e.query.direction=e.query.direction==="asc"?"desc":"asc"},e.sortBy=y=>{e.query.sort===y?e.query.direction=e.query.direction==="asc"?"desc":"asc":(e.query.sort=y,e.query.direction="desc"),e.query.page=1},e.sortIcon=y=>e.query.sort===y?e.query.direction==="asc"?"fa-arrow-up":"fa-arrow-down":"";let u="admin.conferences.filterPrefs",f={page:1,limit:25,sort:"name",direction:"asc",search:"",dateFrom:"",dateTo:"",ready:!1,expired:!1,removed:!1,error:!0,preparing:!0},w=loadFilterPrefs(u)||{};e.query=Object.assign({},f,w,{page:1,search:""});let h=n.search();h.search&&(e.query.search=h.search);let k="admin.conferences.presets";e.presets=JSON.parse(localStorage.getItem(k)||"[]"),e.savePreset=()=>{let y=window.prompt("Preset name:");if(!y)return;let g=Object.assign({},e.query);delete g.page,e.presets=(e.presets||[]).filter(S=>S.name!==y),e.presets.push({name:y,query:g}),localStorage.setItem(k,JSON.stringify(e.presets))},e.applyPreset=y=>{Object.assign(e.query,y.query,{page:1})},e.deletePreset=y=>{e.presets=(e.presets||[]).filter(g=>g.name!==y.name),localStorage.setItem(k,JS Line truncated
`).map((pe,fe)=>fe===0?pe:ie+pe).join(`
`)}else typeof N=="number"||typeof N=="boolean"?J=String(N):J=JSON.stringify(N);se.push(`${Z}${J}${ee}`)}),se.push("}"),se.join(`
`)}function w(R){let T=[],P="",L=/(\w+):(>=|<=|!=|>|<|=)?([^\s]+)/g,V=0,M;for(;M=L.exec(R);)P+=R.slice(V,M.index),V=L.lastIndex,T.push({key:M[1],op:M[2]||"=",val:M[3]});return P+=R.slice(V),{filters:T,free:P.trim().toLowerCase()}}function h(R,T){for(let P of T.filters){let L=(M,se,te)=>{let N=parseFloat(M),I=parseFloat(se);return te==="="?String(M)===String(se):te==="!="?String(M)!==String(se):te===">="?N>=I:te==="<="?N<=I:te===">"?N>I:te==="<"?N<I:!0},V;if(P.key==="code")V=R.displayMessage;else if(P.key==="module")V=R.module;else if(P.key==="status")V=R._status;else if(P.key==="url")V=R._url;else if(P.key==="repo")V=R._repoId;else if(P.key==="level")V=R.level;else continue;if(V==null||!L(V,P.val,P.op))return!1}return!(T.free&&((R.displayMessage||"")+" "+(R.module||"")+" "+(R._url||"")+" "+JSON.stringify(R.raw||[])).toLowerCase().indexOf(T.free)===-1)}function k(){let R=w(e.query.search||"");e.parsedFilterCount=R.filters.length;let T=e.query.bucket,P=e.entries.filter(V=>T&&V._bucket!==T?!1:h(V,R)),L=e.query.group;if(L){let V=te=>L==="module"?te.module:te.displayMessage||te.message||"_",M=new Map;for(let te of P){let N=V(te);if(M.has(N)){let I=M.get(N);I.count++,I._related.push(te),new Date(te.ts)>new Date(I.ts)&&(I.ts=te.ts,I._url=te._url,I._status=te._status),new Date(te.ts)<new Date(I._firstSeen)&&(I._firstSeen=te.ts)}else{let I=Object.assign({},te);I._key=`${L}:${N}`,I._related=[te],I._firstSeen=te.ts,I._lastHourCount=0,I.count=1,M.set(N,I)}}let se=Date.now()-3600*1e3;for(let te of M.values())te._lastHourCount=te._related.filter(N=>new Date(N.ts).getTime()>=se).length;P=Array.from(M.values())}else P=P.map((V,M)=>(V._key="row:"+M+":"+V.ts,V._related=[V],V._firstSeen=V.ts,V._lastHourCount=0,V.count=1,V));e.query.sort==="count"?P.sort((V,M)=>M.count-V.count||new Date(M.ts)-new Date(V.ts)):P.sort((V,M)=>new Date(M.ts)-new Date(V.ts)),e.visible=P}function m(R){let T=R?e.entries.length:0,P=R?e.pageSize:Math.max(e.pageSize,e.entries.length||e.pageSize);t.get("/api/admin/errors",{params:{offset:T,limit:P}}).then(L=>{let V=(L.data.entries||[]).map(u);e.entries=R?e.entries.concat(V):V,e.available=!!L.data.available,e.cap=L.data.max||e.cap,e.total=L.data.total||e.entries.length,k()},L=>console.error(L))}e.loadMore=()=>m(!0),e.canLoadMore=()=>e.entries.length<e.total;function C(){t.get("/api/admin/errors/stats").then(R=>{let T=R.data||{},P=T.prev24h?Math.round((T.last24h-T.prev24h)/T.prev24h*100):0;e.stats={last24h:T.last24h||0,prev24h:T.prev24h||0,delta:P,severity:T.severity||{error:0,warn:0,info:0},unique:T.unique||{error:0,warn:0,info:0},buckets:T.buckets||[],dropped:T.dropped||0}},R=>console.error(R))}function y(){m(),C()}e.barPx=(R,T)=>{let P=e.stats.buckets||[],L=0;for(let te of P)L=Math.max(L,(te.error||0)+(te.warn||0)+(te.info||0));if(!L)return 0;let V=(R.error||0)+(R.warn||0)+(R.info||0);if(!V)return 0;let M=Math.round(V/L*60),se=R[T]||0;return Math.round(se/V*M)},e.bucketTitle=R=>`${new Date(R.hour).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})} \xB7 ${R.error||0} err \xB7 ${R.warn||0} warn \xB7 ${R.info||0} info`,e.toggle=R=>{e.expanded[R._key]=!e.expanded[R._key]},e.setBucket=R=>{e.query.bucket=R},e.refreshNow=y,e.clearAll=()=>{confirm("Clear all captured errors?")&&t.delete("/api/admin/errors").then(y,R=>console.error(R))},e.exportCsv=()=>{let R=["ts","level","module","displayMessage","_status","_url","_repoId"],T=[R.join(",")];for(let M of e.visible)T.push(R.map(se=>{let te=M[se]==null?"":String(M[se]);return/[",\n]/.test(te)?`"${te.replace(/"/g,'""')}"`:te}).join(","));let P=new Blob([T.join(`
`)],{type:"text/csv;charset=utf-8"}),L=URL.createObjectURL(P),V=document.createElement("a");V.href=L,V.download=`errors-${new Date().toISOString().slice(0,19)}.csv`,document.body.appendChild(V),V.click(),document.body.removeChild(V),URL.revokeObjectURL(L)};function g(R){e.copyHint=`${R} copied`,s.timeout(()=>{e.copyHint=""},1500)}e.copyJson=R=>{navigator.clipboard.writeText(R._detailJson).then(()=>g("JSON"))},e.copyCurl=R=>{if(!R._url)return;let P=`curl -X ${R._method||"GET"} '${window.location.origin}${R._url}'`;navigator.clipboard.writeText(P).then(()=>g("curl"))},y();let S=r(()=>{e.query.autoRefresh&&y()},15e3);e.on("dispose",()=>r.cancel(S)),e.watch("query.search",k),e.watch("query.bucket",k),e.watch("query.sort",k),e.watch("query.group",k)},El=function(e,t,n,r){if(e.Math=Math,e.watch("user.status",()=>{e.user==null&&n.url("/")}),e.user==null){n.url("/");return}e.data=null,e.loading=!0,e.error=null,e.performance=null,e.performanceMinutes=15,e.performanceTab="routes",e.performanceError=null,e.formatMs=function(y){return y==null?"":y<1e3?y+" ms":+(y/1e3).toFixed(1)+" s"},e.latencyBound=function(y,g){return y.count?y[g]==null?"> 60 s":"\u2264 "+e.formatMs(y[g]):"No samples"},e.firstByteBound=function(y){return e.latencyBound({count:y.firstByteCount,p95UpperMs:y.firstByteP95UpperMs},"p95UpperMs")},e.sampleAge=function(y){return Math.max(0,Math.round((Date.now()-y.sampledAt)/1e3))},e.peakRss=function(y){return(e.performance.runtimeSeries||[]).filter(function(g){return g.instance===y.instance}).reduce(function(g,S){return Math.max(g,S.rss)},y.memory.rss)},e.performanceWarning=function(y){return e.sampleAge(y)>45||y.droppedBatches||y.droppedMetrics||y.sockets?.closeWait>0||y.eventLoop.p95Ms>100||y.memoryLimitBytes&&y.memory.rss>y.memoryLimitBytes*.8};var s=!1;e.loadPerformance=function(){var y=e.performanceMinutes;e.performance?.windowMinutes&&e.performance.windowMinutes!==y&&(e.performance=null),!s&&(s=!0,t.get("/api/admin/performance",{params:{minutes:y}}).then(function(g){y===e.performanceMinutes&&(e.performance=g.data,e.performanceError=g.data.available?null:"Performance monitoring is unavailable. Request history may be incomplete.")},function(){y===e.performanceMinutes&&(e.performanceError="Could not refresh performance monitoring. Displayed samples may be stale.")}).finally(function(){s=!1,y!==e.performanceMinutes&&e.loadPerformance()}))};function i(y){if(y==null)return"\u2014";for(var g=["B","KB","MB","GB","TB"],S=0,R=y;R>=1024&&S<g.length-1;)R/=1024,S++;return R.toFixed(S>0?1:0)+" "+g[S]}e.humanBytes=i;function a(y){if(!y)return"\u2014";var g=Math.floor(y/86400),S=Math.floor(y%86400/3600),R=Math.floor(y%3600/60);return g>0?g+"d "+(S<10?"0":"")+S+"h":S>0?S+"h "+(R<10?"0":"")+R+"m":R+"m"}e.humanDuration=a;function u(y){return y==null?"\u2014":y>=1e6?(y/1e6).toFixed(1)+"M":y>=1e3?(y/1e3).toFixed(1)+"K":String(y)}e.humanNum=u,e.queueTotal=function(y){return y?(y.waiting||0)+(y.active||0)+(y.delayed||0)+(y.failed||0):0},e.statusCount=function(y){if(!e.data||!e.data.repos)return 0;for(var g=e.data.repos.statusBreakdown||[],S=0;S<g.length;S++)if(g[S]._id===y)return g[S].count;return 0},e.barPct=function(y){var g=e.data&&e.data.repos?e.data.repos.total:0;if(!g)return 0;var S=[y];y==="expired"&&S.push("expiring"),y==="removed"&&S.push("removing"),y==="preparing"&&S.push("download");var R=0;return S.forEach(function(T){R+=e.statusCount(T)}),Math.max(.4,R/g*100)},e.errPct=function(y){if(!e.data||!e.data.errors)return 0;var g=Math.max(e.data.errors.severity.error,e.data.errors.severity.warn,e.data.errors.severity.info,1);return e.data.errors.severity[y]/g*100};function f(y){var g=y||[];return g.map(function(S,R){var T=g[R-1]||{},P=Object.assign({},S);return P.dailyRepositories=R?Math.max(0,(S.nbRepositories||0)-(T.nbRepositories||0)):0,P.dailyUsers=R?Math.max(0,(S.nbUsers||0)-(T.nbUsers||0)):0,P.dailyPageViews=R?Math.max(0,(S.nbPageViews||0)-(T.nbPageViews||0)):0,P})}function w(y){var g=y&&y.length?y[y.length-1]:{};return{repositories:g.dailyRepositories||0,users:g.dailyUsers||0,pageViews:g.dailyPageViews||0}}var h={},k={};e.historyBarH=function(y,g){return!y||!h[g]?0:Math.max(1,Math.round(y[g]/h[g]*140))},e.historyRangeH=function(y,g){if(!y||h[g]==null)return 0;var S=h[g]-k[g];return S?Math.round(8+(y[g]-k[g])/S*132):70},e.historyRange=function(y){return{min:k[y],max:h[y]}},e.historyLabel=function(y){if(!y||!y.date)return"";var g=new Date(y.date);return g.getUTCMonth()+1+"/"+g.getUTCDate()};function m(){e.loadPerformance(),t.get("/api/admin/overview").then(function(y){y.data.history=f(y.data.history),y.data.daily={today:w(y.data.history)},e.data=y.data,e.loading=!1,e.error=null,h={},k={},(y.data.history||[]).forEach(function(g){["dailyPageViews","dailyRepositories","dailyUsers","nbUsers"].forEach(function(S){(!h[S]||g[S]>h[S])&&(h[S]=g[S]),(k[S]==null||g[S]<k[S])&&(k[S]=g[S])})})},function(y){e.loading=!1,e.error=y.data&&y.data.error||"Failed to load overview"})}m();var C=r(m,3e4);e.on("dispose",function(){r.can Line truncated
anonymous_github`)])])])])]),p(" Limitations "),o("h4",{class:"faq-cat"},[o("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[o("use",{href:"#ui-icon-warning"})]),b("Limitations ")]),o("div",{class:"panel-group",id:"faq-limitations",role:"tablist","aria-multiselectable":"true"},[o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingLimitation"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-limitations",href:"#limitation","aria-expanded":"false","aria-controls":"limitation"}," What are the limitations of Anonymous GitHub? ")])]),o("div",{id:"limitation",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingLimitation"},[o("div",{class:"panel-body p-3"},[o("ul",null,[o("li",null," Anonymous GitHub only anonymizes text-based files. Binary files (compiled executables, archives, etc.) are served as-is without anonymization. "),o("li",null," Files larger than 8 MB are not supported. "),o("li",null," Static site generators (such as Jekyll) used with GitHub Pages are not fully supported, although Markdown files are converted to HTML. "),o("li",null," The anonymization of terms within source code may change the behavior of the program (e.g., if a replaced term appears in a string literal or identifier). ")])])])])]),p(" Privacy & Security "),o("h4",{class:"faq-cat"},[o("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[o("use",{href:"#ui-icon-shield"})]),b("Privacy & Security ")]),o("div",{class:"panel-group",id:"faq-privacy",role:"tablist","aria-multiselectable":"true"},[o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingData"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-privacy",href:"#data","aria-expanded":"false","aria-controls":"data"}," How is my data handled? ")])]),o("div",{id:"data",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingData"},[o("div",{class:"panel-body p-3"},[o("p",null," Data stored on Anonymous GitHub is never shared or used for any purpose beyond providing the anonymization service. When a repository is removed or expires, only its configuration is retained \u2014 this makes it easy to restore the repository if needed and ensures that no future repository reuses the same ID. ")])])]),o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingPermissions"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-privacy",href:"#permissions","aria-expanded":"false","aria-controls":"permissions"}," Why does GitHub say Anonymous GitHub asks for write access? ")])]),o("div",{id:"permissions",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingPermissions"},[o("div",{class:"panel-body p-3"},[o("p",null,[b("The GitHub App has read-only access to the repositories you choose. You can change repository access on your "),o("a",{href:"/connections"},"GitHub connections"),b(" page.")]),o("p",null,"Legacy GitHub OAuth includes write access to private repositories because GitHub's OAuth scopes do not offer a read-only option for them. Existing OAuth anonymizations and gists can still use this connection."),o("p",null,"Anonymous GitHub reads repository content. It never pushes, modifies, or deletes files on GitHub.")])])]),o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingViewer"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-privacy",href:"#viewer","aria-expanded":"false","aria-controls":"viewer"}," Can repository owners see who viewed their anonymized repository? ")])]),o("div",{id:"viewer",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingViewer"},[o("div",{class:"panel-body p-3"},[o("p",null," No. Only the total number of views is tracked as an incremental counter. It is not possible for the repository owner or for Anonymous GitHub to identify individual viewers. Reviewer anonymity is fully preserved. ")])])])]),p(" Self-Hosting "),o("h4",{class:"faq-cat"},[o("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[o("use",{href:"#project-icon-storage"})]),b("Self-Hosting ")]),o("div",{class:"panel-group",id:"faq-hosting",role:"tablist","aria-multiselectable":"true"},[o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingDeploy"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-hosting",href:"#deploy","aria-expanded":"false","aria-controls":"deploy"}," Can I deploy my own instance? ")])]),o("div",{id:"deploy",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingDeploy"},[o("div",{class:"panel-body p-3"},[o("p",null,[b(" Yes. Anonymous Git Line truncated
anonymized repository often think it is about the paper, so the
label names the service and the tooltip says who to contact. `),t[17]||(t[17]=o("li",{class:"nav-item d-none d-lg-block"},[o("a",{class:"nav-link",target:"_blank",rel:"noopener",href:"https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml",title:"Report a problem with the Anonymous GitHub service. Questions about an anonymized repository or paper go to its authors.","data-offset":"30"},[o("svg",{class:"ui-icon d-lg-none mr-1","aria-hidden":"true"},[o("use",{href:"#ui-icon-bug"})]),b("Report a bug ")])],-1)),e.isDarkMode?p("v-if",!0):(l(),d("li",V3,[o("a",{class:"nav-link nav-icon",href:"#",title:"Switch to dark mode","aria-label":"Switch to dark mode",role:"button",onClick:t[0]||(t[0]=de(n=>{e.darkMode(!0)},["prevent"]))},[...t[13]||(t[13]=[o("svg",{class:"ui-icon","aria-hidden":"true"},[o("use",{href:"#ui-icon-moon"})],-1)])])])),e.isDarkMode?(l(),d("li",q3,[o("a",{class:"nav-link nav-icon",href:"#",title:"Switch to light mode","aria-label":"Switch to light mode",role:"button",onClick:t[1]||(t[1]=de(n=>{e.darkMode(!1)},["prevent"]))},[...t[14]||(t[14]=[o("svg",{class:"ui-icon","aria-hidden":"true"},[o("use",{href:"#ui-icon-sun"})],-1)])])])):p("v-if",!0),!e.user&&!e.isReviewerRoute?(l(),d("li",M3,[...t[15]||(t[15]=[o("a",{class:"nav-link btn-signin",target:"_self",href:"/signin","data-offset":"30"},[o("i",{class:"fab fa-github mr-1"}),b(" Sign in ")],-1)])])):p("v-if",!0),e.user?(l(),d("li",$3,[o("a",U3,[e.user?.photo?(l(),d("img",{key:0,width:"22",height:"22",class:"rounded-circle",src:e.safeUrl(e.user?.photo)},null,8,L3)):p("v-if",!0),o("span",F3,c(e.user?.username),1)]),o("div",z3,[o("h6",H3,"Signed in as @"+c(e.user?.username),1),t[16]||(t[16]=pe('<a class="dropdown-item" href="/profile"><svg class="ui-icon" aria-hidden="true"><use href="#project-icon-filter"></use></svg><span>Settings<small>Defaults, quotas, account</small></span></a><a class="dropdown-item" href="/connections"><i class="fab fa-github" aria-hidden="true"></i><span>GitHub connections<small>Repository access and OAuth</small></span></a><a class="dropdown-item" href="/claim"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-link"></use></svg><span>Claim an anonymization<small>Attach an existing mirror to your account</small></span></a><div class="dropdown-divider"></div><a class="dropdown-item" href="https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml" target="_blank" rel="noopener"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-bug"></use></svg><span>Report a bug<small>About this service, not a paper</small></span></a><a class="dropdown-item" href="https://github.com/tdurieux/anonymous_github/" target="_blank" rel="noopener"><i class="fab fa-github" aria-hidden="true"></i><span>Source code</span></a><a class="dropdown-item" href="https://ko-fi.com/tdurieux" target="_blank" rel="noopener"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-heart"></use></svg><span>Support the project</span></a><div class="dropdown-divider"></div><a class="dropdown-item" href="/api/user/logout" target="_self"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-logout"></use></svg><span>Sign out</span></a>',9))])])):p("v-if",!0)])])],2),e.generalMessage?(l(),d("div",{key:0,class:"navbar shadow generalMessage",innerHTML:e.sanitize(e.generalMessage)},null,8,B3)):p("v-if",!0),e.emailPromptOpen?(l(),d("dialog",{key:1,id:"email-prompt",class:"email-prompt","aria-labelledby":"email-prompt-title","aria-describedby":"email-prompt-reason",onCancel:t[6]||(t[6]=de(n=>e.respondToEmailPrompt("later"),["prevent"]))},[o("form",{onSubmit:t[5]||(t[5]=de(n=>e.respondToEmailPrompt("save"),["prevent"]))},[t[19]||(t[19]=o("h2",{id:"email-prompt-title"},"Stay informed about access problems",-1)),t[20]||(t[20]=o("p",{id:"email-prompt-reason"},"Get email alerts when your GitHub token or repository access fails.",-1)),t[21]||(t[21]=o("label",{for:"email-prompt-address"},"Email address",-1)),D(o("input",{id:"email-prompt-address",class:"form-control",type:"email",autocomplete:"email",maxlength:"254",required:"","onUpdate:modelValue":t[2]||(t[2]=n=>e.emailPromptAddress=n),disabled:e.emailPromptBusy},null,8,j3),[[Ft,e.emailPromptAddress]]),e.emailPromptError?(l(),d("p",G3,c(e.emailPromptError),1)):p("v-if",!0),o("div",W3,[o("button",{type:"button",class:"btn btn-outline-ink",disabled:e.emailPromptBusy,onClick:t[3]||(t[3]=n=>e.respondToEmailPrompt("later"))},"Remind me later",8,K3),o("button",{type:"button",class:"btn btn-outline-ink",disabled:e.emailPromptBusy,onClick:t[4]||(t[4]=n=>e.respondToEmailPrompt("never"))},"Never",8,Y3),o("button",{type:"submit",class:"btn btn-ink",disabled:e.emailPromptBusy},c(e.emailPromptBusy?"Saving\u2026":"Save"),9,J3)])],32)],32)):p("v-if",!0)],64)}var Q3={class:"paper-landing"},X3={class:"paper-hero"},Z3={class:"paper-hero-copy"},x3={class:"paper-cta-row"},eP={key:0,href:"/signin",target:"_self",class:"btn-hero"},tP={key:1,href:"/anonymize",cla Line truncated
label names the service and the tooltip says who to contact. `),t[17]||(t[17]=o("li",{class:"nav-item d-none d-lg-block"},[o("a",{class:"nav-link",target:"_blank",rel:"noopener",href:"https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml",title:"Report a problem with the Anonymous GitHub service. Questions about an anonymized repository or paper go to its authors.","data-offset":"30"},[o("svg",{class:"ui-icon d-lg-none mr-1","aria-hidden":"true"},[o("use",{href:"#ui-icon-bug"})]),b("Report a bug ")])],-1)),e.isDarkMode?p("v-if",!0):(l(),d("li",z3,[o("a",{class:"nav-link nav-icon",href:"#",title:"Switch to dark mode","aria-label":"Switch to dark mode",role:"button",onClick:t[0]||(t[0]=le(n=>{e.darkMode(!0)},["prevent"]))},[...t[13]||(t[13]=[o("svg",{class:"ui-icon","aria-hidden":"true"},[o("use",{href:"#ui-icon-moon"})],-1)])])])),e.isDarkMode?(l(),d("li",H3,[o("a",{class:"nav-link nav-icon",href:"#",title:"Switch to light mode","aria-label":"Switch to light mode",role:"button",onClick:t[1]||(t[1]=le(n=>{e.darkMode(!1)},["prevent"]))},[...t[14]||(t[14]=[o("svg",{class:"ui-icon","aria-hidden":"true"},[o("use",{href:"#ui-icon-sun"})],-1)])])])):p("v-if",!0),!e.user&&!e.isReviewerRoute?(l(),d("li",B3,[...t[15]||(t[15]=[o("a",{class:"nav-link btn-signin",target:"_self",href:"/signin","data-offset":"30"},[o("i",{class:"fab fa-github mr-1"}),b(" Sign in ")],-1)])])):p("v-if",!0),e.user?(l(),d("li",j3,[o("a",G3,[e.user?.photo?(l(),d("img",{key:0,width:"22",height:"22",class:"rounded-circle",src:e.safeUrl(e.user?.photo)},null,8,W3)):p("v-if",!0),o("span",K3,c(e.user?.username),1)]),o("div",Y3,[o("h6",J3,"Signed in as @"+c(e.user?.username),1),t[16]||(t[16]=ce('<a class="dropdown-item" href="/profile"><svg class="ui-icon" aria-hidden="true"><use href="#project-icon-filter"></use></svg><span>Settings<small>Defaults, quotas, account</small></span></a><a class="dropdown-item" href="/connections"><i class="fab fa-github" aria-hidden="true"></i><span>GitHub connections<small>Repository access and OAuth</small></span></a><a class="dropdown-item" href="/claim"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-link"></use></svg><span>Claim an anonymization<small>Attach an existing mirror to your account</small></span></a><div class="dropdown-divider"></div><a class="dropdown-item" href="https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml" target="_blank" rel="noopener"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-bug"></use></svg><span>Report a bug<small>About this service, not a paper</small></span></a><a class="dropdown-item" href="https://github.com/tdurieux/anonymous_github/" target="_blank" rel="noopener"><i class="fab fa-github" aria-hidden="true"></i><span>Source code</span></a><a class="dropdown-item" href="https://ko-fi.com/tdurieux" target="_blank" rel="noopener"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-heart"></use></svg><span>Support the project</span></a><div class="dropdown-divider"></div><a class="dropdown-item" href="/api/user/logout" target="_self"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-logout"></use></svg><span>Sign out</span></a>',9))])])):p("v-if",!0)])])],2),e.generalMessage?(l(),d("div",{key:0,class:"navbar shadow generalMessage",innerHTML:e.sanitize(e.generalMessage)},null,8,Q3)):p("v-if",!0),e.emailPromptOpen?(l(),d("dialog",{key:1,id:"email-prompt",class:"email-prompt","aria-labelledby":"email-prompt-title","aria-describedby":"email-prompt-reason",onCancel:t[6]||(t[6]=le(n=>e.respondToEmailPrompt("later"),["prevent"]))},[o("form",{onSubmit:t[5]||(t[5]=le(n=>e.respondToEmailPrompt("save"),["prevent"]))},[t[19]||(t[19]=o("h2",{id:"email-prompt-title"},"Stay informed about access problems",-1)),t[20]||(t[20]=o("p",{id:"email-prompt-reason"},"Get email alerts when your GitHub token or repository access fails.",-1)),t[21]||(t[21]=o("label",{for:"email-prompt-address"},"Email address",-1)),D(o("input",{id:"email-prompt-address",class:"form-control",type:"email",autocomplete:"email",maxlength:"254",required:"","onUpdate:modelValue":t[2]||(t[2]=n=>e.emailPromptAddress=n),disabled:e.emailPromptBusy},null,8,X3),[[zt,e.emailPromptAddress]]),e.emailPromptError?(l(),d("p",Z3,c(e.emailPromptError),1)):p("v-if",!0),o("div",x3,[o("button",{type:"button",class:"btn btn-outline-ink",disabled:e.emailPromptBusy,onClick:t[3]||(t[3]=n=>e.respondToEmailPrompt("later"))},"Remind me later",8,eP),o("button",{type:"button",class:"btn btn-outline-ink",disabled:e.emailPromptBusy,onClick:t[4]||(t[4]=n=>e.respondToEmailPrompt("never"))},"Never",8,tP),o("button",{type:"submit",class:"btn btn-ink",disabled:e.emailPromptBusy},c(e.emailPromptBusy?"Saving\u2026":"Save"),9,oP)])],32)],32)):p("v-if",!0)],64)}var nP={class:"paper-landing"},sP={class:"paper-hero"},rP={class:"paper-hero-copy"},iP={class:"paper-cta-row"},aP={key:0,href:"/signin",target:"_self",class:"btn-hero"},lP={key:1,href:"/anonymize",cla Line truncated
MIT CSAIL
jane.smith@example.org`},bq={id:"termsHelp",class:"form-text text-muted"},wq={class:"invalid-feedback"},kq={id:"settings-display",class:"paper-settings-section"},Eq={class:"form-group paper-check-list"},Cq={class:"form-check"},_q={class:"form-check-input",type:"checkbox",id:"link",name:"link"},Sq={class:"form-check"},Nq={class:"form-check-input",type:"checkbox",id:"image",name:"image"},Dq={class:"form-check"},Rq={class:"form-check-input",type:"checkbox",id:"pdf",name:"pdf"},Tq={class:"form-check"},Aq={class:"form-check-input",type:"checkbox",id:"notebook",name:"notebook"},Oq={id:"settings-features",class:"paper-settings-section"},Iq={class:"form-group paper-check-list"},Pq={class:"form-check"},Vq={class:"form-check-input",type:"checkbox",id:"page",name:"page"},qq={class:"form-check"},Mq={class:"form-check-input",type:"checkbox",id:"loc",name:"loc"},$q={class:"form-check"},Uq={class:"form-check-input",type:"checkbox",id:"update",name:"update"},Lq={class:"form-group"},Fq={class:"form-control",id:"mode",name:"mode"},zq={class:"form-text text-muted"},Hq={id:"settings-expiration",class:"paper-settings-section"},Bq={class:"form-group"},jq={class:"form-control",id:"expiration",name:"expiration"},Gq={key:0,class:"draft-status",role:"status"},Wq={key:1,class:"draft-status"},Kq={class:"paper-settings-footer"},Yq={key:0,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},Jq=["textContent"],Qq={class:"paper-settings-actions"},Xq=["disabled"],Zq={key:0,class:"ui-icon mr-1","aria-hidden":"true"},xq={id:"settings-account",class:"paper-settings-section"},eM={class:"paper-account-card"},tM=["src"],oM={class:"paper-account-identity"},nM={class:"paper-account-name"},sM=["disabled"],rM={key:0,role:"status"},iM={key:1,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},aM=["disabled"],lM={key:3,role:"status"},dM={class:"paper-danger-zone"},uM={key:0,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},cM=["textContent"],pM=["disabled"];function jl(e,t){let n=We("quota-usage"),r=be("paper-scrollspy"),s=be("field"),i=be("form");return l(),d("div",dq,[t[58]||(t[58]=pe('<div class="paper-crumbs"><a href="/dashboard">My work</a> \xA0/\xA0 <span class="here">Settings</span></div><h1 class="paper-page-title">Your <em>settings</em></h1><p class="paper-page-lede">Defaults applied to every new anonymization, your quotas, and your account.</p>',3)),o("div",uq,[D((l(),d("aside",cq,[...t[8]||(t[8]=[pe('<div class="paper-settings-toc-head">On this page</div><nav><a href="#settings-quota">Quota</a><a href="#settings-terms">Terms to redact</a><a href="#settings-display">Display</a><a href="#settings-features">Features</a><a href="#settings-expiration">Expiration</a><a href="#settings-account">Account</a></nav>',2)])])),[[r]]),o("div",pq,[p(" Account usage shares the dashboard component. "),o("section",fq,[t[10]||(t[10]=o("div",{class:"paper-section-eyebrow"},"Quota",-1)),t[11]||(t[11]=o("p",{class:"paper-section-copy"},"What you are using across all your anonymizations. Conferences can lift these limits during a review window.",-1)),e.quota?(l(),Ut(n,{key:0,quota:e.quota,fmt:e.fmt},null,8,["quota","fmt"])):p("v-if",!0),e.quota?p("v-if",!0):(l(),d("div",mq,[(l(),d(X,null,ae([1,2,3],(a,u)=>o("div",hq,[...t[9]||(t[9]=[o("div",{class:"quota-header"},[o("span",{class:"skeleton skeleton-line",style:{width:"40%"}}),o("span",{class:"skeleton skeleton-line",style:{width:"25%"}})],-1),o("div",{class:"quota-track"},null,-1)])])),64))]))]),D((l(),d("form",{class:"form needs-validation",name:"defaultsForm",novalidate:"",onSubmit:t[2]||(t[2]=de(a=>e.submitForm(a,()=>{e.saveDefault(a)}),["prevent"]))},[o("section",vq,[t[17]||(t[17]=o("div",{class:"paper-section-eyebrow"},"Terms to redact",-1)),t[18]||(t[18]=o("p",{class:"paper-section-copy"},"Pre-filled in every new anonymization. You can still edit the list per anonymization.",-1)),o("div",yq,[t[16]||(t[16]=o("label",{class:"paper-field-label",for:"terms"},"Default terms",-1)),D(o("textarea",gq,null,512),[[s,{state:e.viewState,set:a=>{e.terms=a},value:e.terms,form:"defaultsForm",options:{debounce:250}}]]),o("small",bq,[t[12]||(t[12]=b(" One term per line (regex allowed). Each match is replaced by ",-1)),o("code",null,c(e.site_options?.ANONYMIZATION_MASK||"XXX")+"-[N]",1),t[13]||(t[13]=b(", or use ",-1)),t[14]||(t[14]=o("code",null,"term=>replacement",-1)),t[15]||(t[15]=b(" to pick your own. ",-1))]),D(o("div",wq," Terms are in an invalid format ",512),[[K,e.defaultsForm?.terms?.errors?.format]])])]),o("section",kq,[t[27]||(t[27]=o("div",{class:"paper-section-eyebrow"},"Display",-1)),t[28]||(t[28]=o("p",{class:"paper-section-copy"},"What reviewers can see inside an anonymized repository.",-1)),o("div",Eq,[o("div",Cq,[D(o("input",_q,null,512),[[s,{state:e.viewState,set:a=>{e.options.link=a},value:e.options?.link,form:"defaultsForm",options:{}}]]),t[19]||(t[19]=o("label",{class:"form-check-label",for:"link"},"Keep links",-1)),t[20]||(t[20]=o("small",{class:"form-text t Line truncated
`);for(let k=0;k<h.length;k++){let m=h[k];if(m.startsWith("diff --git")){w(),f();continue}if(m.startsWith("--- ")){i&&i.lines.length&&w(),f().oldPath=m.replace(/^--- (a\/)?/,"").trim();continue}if(m.startsWith("+++ ")){f().newPath=m.replace(/^\+\+\+ (b\/)?/,"").trim();continue}if(!(m.startsWith("index ")||m.startsWith("similarity index")||m.startsWith("rename ")||m.startsWith("new file mode")||m.startsWith("deleted file mode")||m.startsWith("Binary files"))){if(m.startsWith("@@")){let E=m.match(/@@\s+-(\d+)(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/);E&&(a=parseInt(E[1],10),u=parseInt(E[2],10)),f().lines.push({kind:"hunk",oldNo:"",newNo:"",text:m});continue}i&&(m.startsWith("+")?(i.lines.push({kind:"add",oldNo:"",newNo:u,text:m.slice(1)}),u++):m.startsWith("-")?(i.lines.push({kind:"remove",oldNo:a,newNo:"",text:m.slice(1)}),a++):(i.lines.push({kind:"ctx",oldNo:a,newNo:u,text:m.startsWith(" ")?m.slice(1):m}),a++,u++))}}return n(s,i),s.join("")}})({trustAsHtml:e=>e});function T8(e,t){return e==null?"":Number(e).toLocaleString(void 0,t==null?{}:{minimumFractionDigits:t,maximumFractionDigits:t})}function A8(e){return String(e??"").toUpperCase()}function O8(e,t,n=0){return(e||[]).slice(n,n+t)}function I8(e,t){return Array.isArray(e)?typeof t=="function"?e.filter(t):e:[]}function P8(e,t){if(!t)return e||[];let n=Array.isArray(t)?t:[t];return[...e||[]].sort((r,s)=>{for(let i of n){let a=i[0]==="-"?-1:1;i=i.replace(/^[+-]/,"");let u=i.split(".").reduce((w,h)=>w?.[h],r),f=i.split(".").reduce((w,h)=>w?.[h],s);if(typeof u=="string"&&(u=u.toLowerCase()),typeof f=="string"&&(f=f.toLowerCase()),u!==f)return(u==null?-1:f==null?1:u<f?-1:1)*a}return 0})}function V8(e,t){if(!e)return"";let n=new Date(e);if(isNaN(n))return String(e);if(!t||t==="mediumDate")return n.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"});let r={yyyy:n.getFullYear(),MMM:n.toLocaleDateString(void 0,{month:"short"}),MM:String(n.getMonth()+1).padStart(2,"0"),dd:String(n.getDate()).padStart(2,"0"),d:n.getDate(),HH:String(n.getHours()).padStart(2,"0"),mm:String(n.getMinutes()).padStart(2,"0"),ss:String(n.getSeconds()).padStart(2,"0")};return t.replace(/yyyy|MMM|MM|dd|HH|mm|ss|d/g,s=>r[s])}function q8(e,t){return(t?.[e]??t?.[e===1?"one":"other"]??"").replace(/\{\}/g,e??0)}var ur={ERRORS:{cache_busy:"Downloads are busy. Please try again shortly.",invalid_sort:"The selected sort order is invalid.",invalid_cursor:"This project page is no longer valid. Reload the list.",repository_changed:"The repository changed while processing. Please retry.",repository_job_cancelled:"The repository changed or was removed while processing.",storage_delete_failed:"Unable to remove cached files. Please try again later.",unknown_error:"Unknown error, contact the admin.",unreachable:"Anonymous GitHub is unreachable, contact the admin.",request_error:"Unable to download the file, check your connection or contact the admin.",not_found:"The requested resource could not be found.",not_connected:"You must be logged in to perform this action.",not_authorized:"You do not have permission to perform this action.",unable_to_connect_user:"Unable to connect your account. Please try again later.",user_not_found:"The requested user could not be found.",user_banned:"Your account has been banned. Contact the admin for more information.",repo_access_limited:"GitHub blocked access because the repository's organization restricts third-party OAuth apps. Ask an org owner to approve Anonymous GitHub under Settings \u2192 Third-party Access \u2192 OAuth app policy, or anonymize a personal fork instead.",repo_saml_enforcement:"The repository's organization enforces SAML single sign-on. Authorize your token for that organization (GitHub \u2192 Settings \u2192 Applications, or re-run the org's SSO sign-in), then retry. Alternatively, anonymize a personal fork.",repo_not_found:"The repository was not found on GitHub. Check the URL and spelling, make sure you are signed in to the account that can see it, and confirm the repo isn't hidden under an org that restricts third-party app access.",repo_empty:"The selected branch has no commits on GitHub. Push at least one commit, or pick a different branch, then retry.",repo_not_accessible:"Anonymous GitHub cannot access this repository. Verify the repository exists and that Anonymous GitHub has been authorized for the owning organization.",repository_archived:"This repository has been archived and its files are no longer available.",repository_expired:"The repository is expired.",invalid_status:"This action cannot be performed while the resource is in its current state.",repository_not_ready:"Anonymous GitHub is still processing the repository, it can take several minutes.",repository_not_accessible:"This repository is currently not accessible.",repo_is_updating:"Anonymous GitHub is still processing the repository, it can take several minutes.",invalid_repo:"The provided repository is not valid.",invalid_source_repository:"The repository source name Line truncated
jane.smith@example.org`},Aq={id:"termsHelp",class:"form-text text-muted"},Oq={class:"invalid-feedback"},Iq={id:"settings-display",class:"paper-settings-section"},Pq={class:"form-group paper-check-list"},Vq={class:"form-check"},qq={class:"form-check-input",type:"checkbox",id:"link",name:"link"},Mq={class:"form-check"},$q={class:"form-check-input",type:"checkbox",id:"image",name:"image"},Lq={class:"form-check"},Uq={class:"form-check-input",type:"checkbox",id:"pdf",name:"pdf"},Fq={class:"form-check"},zq={class:"form-check-input",type:"checkbox",id:"notebook",name:"notebook"},Hq={id:"settings-features",class:"paper-settings-section"},Bq={class:"form-group paper-check-list"},jq={class:"form-check"},Gq={class:"form-check-input",type:"checkbox",id:"page",name:"page"},Wq={class:"form-check"},Kq={class:"form-check-input",type:"checkbox",id:"loc",name:"loc"},Yq={class:"form-check"},Jq={class:"form-check-input",type:"checkbox",id:"update",name:"update"},Qq={class:"form-group"},Xq={class:"form-control",id:"mode",name:"mode"},Zq={class:"form-text text-muted"},xq={id:"settings-expiration",class:"paper-settings-section"},eM={class:"form-group"},tM={class:"form-control",id:"expiration",name:"expiration"},oM={key:0,class:"draft-status",role:"status"},nM={key:1,class:"draft-status"},sM={class:"paper-settings-footer"},rM={key:0,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},iM=["textContent"],aM={class:"paper-settings-actions"},lM=["disabled"],dM={key:0,class:"ui-icon mr-1","aria-hidden":"true"},uM={id:"settings-account",class:"paper-settings-section"},cM={class:"paper-account-card"},pM=["src"],fM={class:"paper-account-identity"},mM={class:"paper-account-name"},hM=["disabled"],vM={key:0,role:"status"},yM={key:1,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},gM=["disabled"],bM={key:3,role:"status"},wM={class:"paper-danger-zone"},kM={key:0,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},EM=["textContent"],CM=["disabled"];function Ql(e,t){let n=Ge("quota-usage"),r=ge("paper-scrollspy"),s=ge("field"),i=ge("form");return l(),d("div",wq,[t[58]||(t[58]=ce('<div class="paper-crumbs"><a href="/dashboard">My work</a> \xA0/\xA0 <span class="here">Settings</span></div><h1 class="paper-page-title">Your <em>settings</em></h1><p class="paper-page-lede">Defaults applied to every new anonymization, your quotas, and your account.</p>',3)),o("div",kq,[D((l(),d("aside",Eq,[...t[8]||(t[8]=[ce('<div class="paper-settings-toc-head">On this page</div><nav><a href="#settings-quota">Quota</a><a href="#settings-terms">Terms to redact</a><a href="#settings-display">Display</a><a href="#settings-features">Features</a><a href="#settings-expiration">Expiration</a><a href="#settings-account">Account</a></nav>',2)])])),[[r]]),o("div",Cq,[p(" Account usage shares the dashboard component. "),o("section",_q,[t[10]||(t[10]=o("div",{class:"paper-section-eyebrow"},"Quota",-1)),t[11]||(t[11]=o("p",{class:"paper-section-copy"},"What you are using across all your anonymizations. Conferences can lift these limits during a review window.",-1)),e.quota?(l(),Ut(n,{key:0,quota:e.quota,fmt:e.fmt},null,8,["quota","fmt"])):p("v-if",!0),e.quota?p("v-if",!0):(l(),d("div",Sq,[(l(),d(Q,null,re([1,2,3],(a,u)=>o("div",Nq,[...t[9]||(t[9]=[o("div",{class:"quota-header"},[o("span",{class:"skeleton skeleton-line",style:{width:"40%"}}),o("span",{class:"skeleton skeleton-line",style:{width:"25%"}})],-1),o("div",{class:"quota-track"},null,-1)])])),64))]))]),D((l(),d("form",{class:"form needs-validation",name:"defaultsForm",novalidate:"",onSubmit:t[2]||(t[2]=le(a=>e.submitForm(a,()=>{e.saveDefault(a)}),["prevent"]))},[o("section",Dq,[t[17]||(t[17]=o("div",{class:"paper-section-eyebrow"},"Terms to redact",-1)),t[18]||(t[18]=o("p",{class:"paper-section-copy"},"Pre-filled in every new anonymization. You can still edit the list per anonymization.",-1)),o("div",Rq,[t[16]||(t[16]=o("label",{class:"paper-field-label",for:"terms"},"Default terms",-1)),D(o("textarea",Tq,null,512),[[s,{state:e.viewState,set:a=>{e.terms=a},value:e.terms,form:"defaultsForm",options:{debounce:250}}]]),o("small",Aq,[t[12]||(t[12]=b(" One term per line (regex allowed). Each match is replaced by ",-1)),o("code",null,c(e.site_options?.ANONYMIZATION_MASK||"XXX")+"-[N]",1),t[13]||(t[13]=b(", or use ",-1)),t[14]||(t[14]=o("code",null,"term=>replacement",-1)),t[15]||(t[15]=b(" to pick your own. ",-1))]),D(o("div",Oq," Terms are in an invalid format ",512),[[K,e.defaultsForm?.terms?.errors?.format]])])]),o("section",Iq,[t[27]||(t[27]=o("div",{class:"paper-section-eyebrow"},"Display",-1)),t[28]||(t[28]=o("p",{class:"paper-section-copy"},"What reviewers can see inside an anonymized repository.",-1)),o("div",Pq,[o("div",Vq,[D(o("input",qq,null,512),[[s,{state:e.viewState,set:a=>{e.options.link=a},value:e.options?.link,form:"defaultsForm",options:{}}]]),t[19]||(t[19]=o("label",{class:"form-check-label",for:"link"},"Keep links",-1)),t[20]||(t[20]=o("small",{class:"form-text t Line truncated
`);for(let k=0;k<h.length;k++){let m=h[k];if(m.startsWith("diff --git")){w(),f();continue}if(m.startsWith("--- ")){i&&i.lines.length&&w(),f().oldPath=m.replace(/^--- (a\/)?/,"").trim();continue}if(m.startsWith("+++ ")){f().newPath=m.replace(/^\+\+\+ (b\/)?/,"").trim();continue}if(!(m.startsWith("index ")||m.startsWith("similarity index")||m.startsWith("rename ")||m.startsWith("new file mode")||m.startsWith("deleted file mode")||m.startsWith("Binary files"))){if(m.startsWith("@@")){let C=m.match(/@@\s+-(\d+)(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/);C&&(a=parseInt(C[1],10),u=parseInt(C[2],10)),f().lines.push({kind:"hunk",oldNo:"",newNo:"",text:m});continue}i&&(m.startsWith("+")?(i.lines.push({kind:"add",oldNo:"",newNo:u,text:m.slice(1)}),u++):m.startsWith("-")?(i.lines.push({kind:"remove",oldNo:a,newNo:"",text:m.slice(1)}),a++):(i.lines.push({kind:"ctx",oldNo:a,newNo:u,text:m.startsWith(" ")?m.slice(1):m}),a++,u++))}}return n(s,i),s.join("")}})({trustAsHtml:e=>e});function F8(e,t){return e==null?"":Number(e).toLocaleString(void 0,t==null?{}:{minimumFractionDigits:t,maximumFractionDigits:t})}function z8(e){return String(e??"").toUpperCase()}function H8(e,t,n=0){return(e||[]).slice(n,n+t)}function B8(e,t){return Array.isArray(e)?typeof t=="function"?e.filter(t):e:[]}function j8(e,t){if(!t)return e||[];let n=Array.isArray(t)?t:[t];return[...e||[]].sort((r,s)=>{for(let i of n){let a=i[0]==="-"?-1:1;i=i.replace(/^[+-]/,"");let u=i.split(".").reduce((w,h)=>w?.[h],r),f=i.split(".").reduce((w,h)=>w?.[h],s);if(typeof u=="string"&&(u=u.toLowerCase()),typeof f=="string"&&(f=f.toLowerCase()),u!==f)return(u==null?-1:f==null?1:u<f?-1:1)*a}return 0})}function G8(e,t){if(!e)return"";let n=new Date(e);if(isNaN(n))return String(e);if(!t||t==="mediumDate")return n.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"});let r={yyyy:n.getFullYear(),MMM:n.toLocaleDateString(void 0,{month:"short"}),MM:String(n.getMonth()+1).padStart(2,"0"),dd:String(n.getDate()).padStart(2,"0"),d:n.getDate(),HH:String(n.getHours()).padStart(2,"0"),mm:String(n.getMinutes()).padStart(2,"0"),ss:String(n.getSeconds()).padStart(2,"0")};return t.replace(/yyyy|MMM|MM|dd|HH|mm|ss|d/g,s=>r[s])}function W8(e,t){return(t?.[e]??t?.[e===1?"one":"other"]??"").replace(/\{\}/g,e??0)}var sd={name:"htmlDoc",props:["content","baseUrl","allowScripts"],setup(e){let t=xe(null);return Lt(()=>{let r=[t.value][0];r.classList.add("html-doc");function s(){r.innerHTML="";let i=e.content;if(typeof i!="string")return;let a=document.createElement("iframe");a.className="html-doc-frame",a.setAttribute("title","Rendered HTML document");let u=["allow-popups","allow-popups-to-escape-sandbox"];e.allowScripts&&u.push("allow-scripts","allow-forms","allow-modals"),a.setAttribute("sandbox",u.join(" ")),a.setAttribute("referrerpolicy","no-referrer"),r.appendChild(a);let f="";e.baseUrl&&(f='<base href="'+e.baseUrl.replace(/&/g,"&amp;").replace(/"/g,"&quot;")+'">'),a.srcdoc=f+i}He(()=>e.content,s,{immediate:!0}),He(()=>e.baseUrl,s,{immediate:!0}),He(()=>e.allowScripts,s,{immediate:!0})}),()=>we("html-doc",{ref:t})}};var rd={name:"pdfviewer",props:["src"],setup(e){let t=xe(null);return Lt(()=>{let n=[t.value],r=400,s=[.5,.75,1,1.25,1.5,2,3],i=1e3,a=n[0];a.classList.add("pdf-viewer");let u=null,f=[],w=!1,h=null,k=1,m=1,C=0,y=0,g=612/792,S=0,R=null,T=new Map,P=0;function L(v){let E=T.get(v);E&&(E.cancelled=!0,E.task?.cancel?.(),T.delete(v));let O=v.querySelector("canvas");O&&(O.width=0,O.height=0),v.innerHTML="",delete v.dataset.state}let V=document.createElement("div");V.className="pdf-toolbar";let M=document.createElement("div");M.className="pdf-pages",M.tabIndex=0,M.setAttribute("aria-label","PDF pages"),a.appendChild(V),a.appendChild(M);function se(v,E,O){let H=document.createElement("button");return H.type="button",H.className="pdf-toolbar-btn",H.title=E,H.setAttribute("aria-label",E),H.innerHTML='<i class="fas '+v+'"></i>',H.addEventListener("click",O),H}let te=se("fa-chevron-up","Previous page",function(){Se(m-1)}),N=se("fa-chevron-down","Next page",function(){Se(m+1)}),I=document.createElement("input");I.type="text",I.className="pdf-toolbar-page",I.setAttribute("aria-label","Page number"),I.title="Page number \u2014 type a page and press Enter",I.addEventListener("keydown",function(v){v.key==="Enter"&&(Se(parseInt(I.value,10)),I.blur())}),I.addEventListener("blur",function(){I.value=String(m)});let Y=document.createElement("span");Y.className="pdf-toolbar-count";let Z=se("fa-search-minus","Zoom out",function(){_(s[Math.max(0,fe()-1)])}),ee=se("fa-search-plus","Zoom in",function(){_(s[Math.min(s.length-1,fe()+1)])}),J=document.createElement("button");J.type="button",J.className="pdf-toolbar-btn pdf-toolbar-zoom",J.title="Reset zoom to fit the width",J.setAttribute("aria-label","Reset zoom to fit the width"),J.addEventListener("click",function(){_(1)}),V.appendChild(te),V.appendChild(N);let ie=document.createElement("span");ie.className="pdf-toolbar-group",ie.appendChild(I),ie. Line truncated
/*! Bundled license information:
@vue/shared/dist/shared.esm-bundler.js:
(**
* @vue/shared v3.5.43
* @vue/shared v3.5.44
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**)
@vue/reactivity/dist/reactivity.esm-bundler.js:
(**
* @vue/reactivity v3.5.43
* @vue/reactivity v3.5.44
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**)
@vue/runtime-core/dist/runtime-core.esm-bundler.js:
(**
* @vue/runtime-core v3.5.43
* @vue/runtime-core v3.5.44
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**)
@vue/runtime-dom/dist/runtime-dom.esm-bundler.js:
(**
* @vue/runtime-dom v3.5.43
* @vue/runtime-dom v3.5.44
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**)
vue/dist/vue.runtime.esm-bundler.js:
(**
* vue v3.5.43
* vue v3.5.44
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**)
+9 -2
View File
@@ -21,8 +21,8 @@ function decodePathSegment(segment: string): string {
}
}
// Extensions the browser will execute script from when it renders the
// response as a document (directly, or via the "Raw" action).
// Keep explicit fallbacks for markup types not consistently mapped by MIME
// databases. MIME classification below also covers aliases such as svgz/shtml.
const SCRIPTABLE_EXTENSIONS = new Set([
"html",
"htm",
@@ -33,10 +33,16 @@ const SCRIPTABLE_EXTENSIONS = new Set([
"xsl",
"xslt",
"mhtml",
"mht",
]);
export function isScriptableDocument(anonymizedPath: string): boolean {
const name = anonymizedPath.substring(anonymizedPath.lastIndexOf("/") + 1);
const mime = lookup(name);
if (mime && (
mime === "text/html" || mime === "text/xml" || mime === "application/xml" ||
mime.endsWith("+xml") || mime === "message/rfc822" || mime === "multipart/related"
)) return true;
const dot = name.lastIndexOf(".");
if (dot < 0) return false;
return SCRIPTABLE_EXTENSIONS.has(name.substring(dot + 1).toLowerCase());
@@ -115,6 +121,7 @@ router.get(
object: f,
});
}
res.header("X-Content-Type-Options", "nosniff");
if (req.query.download) {
res.attachment(
anonymizedPath.substring(anonymizedPath.lastIndexOf("/") + 1)
+35 -14
View File
@@ -33,6 +33,24 @@ const router = express.Router();
// user needs to be connected for all user API
router.use(ensureAuthenticated);
async function enqueueSavedSnapshot(model: IAnonymizedRepositoryDocument) {
try {
await downloadQueue.add(model.repoId, { repoId: model.repoId }, {
jobId: `repo-${model.repoId}`, attempts: 3,
});
} catch (error) {
// Leave a failed enqueue retryable without overwriting a worker or a
// lifecycle change that happened after this save.
await AnonymizedRepositoryModel.updateOne({
_id: model._id, status: RepositoryStatus.PREPARING,
statusDate: model.statusDate, anonymizeDate: model.anonymizeDate,
"githubAccess.revision": model.githubAccess?.revision || { $exists: false },
}, { $set: { status: RepositoryStatus.ERROR, statusDate: new Date(),
statusMessage: "preparation_interrupted" } }).exec();
throw error;
}
}
async function previewToken(req: express.Request) {
const user = await getUser(req);
if (typeof req.query.anonymizedRepoId === "string") {
@@ -185,15 +203,18 @@ router.post(
repo.model.options.expirationDate
);
const reactivating = repo.status === RepositoryStatus.EXPIRED;
const updates: Record<string, Date> = {
const updates: Record<string, Date | string | null> = {
"options.expirationDate": newExpiration,
settingsSavedAt: new Date(),
};
repo.model.options.expirationDate = newExpiration;
repo.model.settingsSavedAt = updates.settingsSavedAt;
repo.model.settingsSavedAt = updates.settingsSavedAt as Date;
if (reactivating) {
repo.model.anonymizeDate = new Date();
updates.anonymizeDate = repo.model.anonymizeDate;
updates.status = RepositoryStatus.PREPARING;
updates.statusDate = new Date();
updates.statusMessage = null;
}
const saved = await AnonymizedRepositoryModel.updateOne(
{ _id: repo.model._id, status: repo.status, statusDate: repo.model.statusDate },
@@ -207,12 +228,10 @@ router.post(
// directly instead of asking GitHub for the latest branch head first;
// that lookup can fail after the new date has already been persisted
// and leave the repository stuck in the expired state.
await repo.updateStatus(RepositoryStatus.PREPARING);
await downloadQueue.add(
repo.repoId,
{ repoId: repo.repoId },
{ jobId: `repo-${repo.repoId}`, attempts: 3 }
);
repo.model.status = RepositoryStatus.PREPARING;
repo.model.statusDate = updates.statusDate as Date;
repo.model.statusMessage = undefined;
await enqueueSavedSnapshot(repo.model);
}
res.json({ status: repo.status, expirationDate: newExpiration });
} catch (error) {
@@ -610,6 +629,9 @@ router.post(
}
}
repo.model.conference = repoUpdate.conference;
const preparation = sourceChanged || reactivating ? {
status: RepositoryStatus.PREPARING, statusDate: new Date(), statusMessage: null,
} : undefined;
const saved = await AnonymizedRepositoryModel.updateOne(
{ _id: repo.model._id, status: repo.status, statusDate: repo.model.statusDate,
"githubAccess.revision": previousAccessRevision || { $exists: false } },
@@ -621,6 +643,7 @@ router.post(
githubAccess: repo.model.githubAccess,
conference: repo.model.conference,
anonymizeDate: repo.model.anonymizeDate,
...preparation,
},
}
).exec();
@@ -630,13 +653,11 @@ router.post(
return res.json({ status: repo.status });
}
await repo.updateStatus(RepositoryStatus.PREPARING);
repo.model.status = preparation!.status;
repo.model.statusDate = preparation!.statusDate;
repo.model.statusMessage = undefined;
await enqueueSavedSnapshot(repo.model);
res.json({ status: repo.status });
await downloadQueue.add(
repo.repoId,
{ repoId: repo.repoId },
{ jobId: `repo-${repo.repoId}` }
);
} catch (error) {
return handleError(error, res, req);
}
+43
View File
@@ -0,0 +1,43 @@
const { expect } = require("chai");
const fs = require("node:fs/promises");
const os = require("node:os");
const path = require("node:path");
const { once } = require("node:events");
const archiver = require("archiver");
const { Parse } = require("unzip-stream");
describe("archive glob dependency compatibility", function () {
it("archives nested matches and excludes ignored files with the patched matcher", async function () {
const directory = await fs.mkdtemp(path.join(os.tmpdir(), "archive-dependencies-"));
const archive = archiver("zip");
const parser = Parse();
try {
await fs.mkdir(path.join(directory, "nested"));
await Promise.all(["README.md", "nested/notes.md", "nested/private.md", "nested/code.js"]
.map(name => fs.writeFile(path.join(directory, name), name)));
// archiver-utils uses glob.sync, while archiver.glob uses readdir-glob
// and Minimatch. Exercise both callers of the major-version overrides.
expect(require("archiver-utils").file.expand({ cwd: directory }, ["**/*.md", "!**/private.md"]).sort())
.to.deep.equal(["README.md", "nested/notes.md"]);
const entries = [];
const reads = [];
parser.on("entry", entry => {
const chunks = [];
entry.on("data", chunk => chunks.push(chunk));
reads.push(once(entry, "end").then(() => entries.push({ name: entry.path, body: Buffer.concat(chunks).toString() })));
});
const finished = once(parser, "finish");
archive.pipe(parser);
archive.glob("**/*.md", { cwd: directory, ignore: ["**/private.md"] });
await archive.finalize();
await finished;
await Promise.all(reads);
expect(entries.sort((a, b) => a.name.localeCompare(b.name)))
.to.deep.equal(["nested/notes.md", "README.md"].map(name => ({ name, body: name })));
} finally {
archive.destroy();
parser.destroy();
await fs.rm(directory, { recursive: true, force: true });
}
});
});
+29
View File
@@ -43,6 +43,35 @@ describe("download headers and website revalidation", function () {
expect(response.headers["etag"]).to.match(/^"f-/); expect(response.headers["content-type"]).to.include("text/plain");
expect(transfers).to.equal(0);
});
for (const name of ["page.shtml", "drawing.svgz", "schema.xsd"]) {
it(`sandboxes ${name} on GET, HEAD, and revalidation`, async function () {
const path = `/api/repo/fixture/file/${name}`;
const first = await fetch(path);
const head = await fetch(path, "HEAD");
const cached = await fetch(path, "GET", { "If-None-Match": first.headers.etag });
expect(first.status).to.equal(200);
expect(head.status).to.equal(200);
expect(cached.status).to.equal(304);
for (const response of [first, head, cached]) {
expect(response.headers["content-security-policy"]).to.include("sandbox");
expect(response.headers["content-security-policy"]).not.to.include("allow-scripts");
expect(response.headers["content-security-policy"]).not.to.include("allow-same-origin");
expect(response.headers["x-content-type-options"]).to.equal("nosniff");
}
});
}
it("sandboxes MIME aliases even when anonymization changes their extension", async function () {
AnonymizedFile.prototype.originalPath = async () => "original.shtml";
const response = await fetch("/api/repo/fixture/file/page.txt");
expect(response.status).to.equal(200);
expect(response.headers["content-security-policy"]).to.include("sandbox");
});
it("keeps explicit downloads as attachments", async function () {
const response = await fetch("/api/repo/fixture/file/page.shtml?download=1");
expect(response.status).to.equal(200);
expect(response.headers["content-disposition"]).to.include("attachment");
expect(response.headers["x-content-type-options"]).to.equal("nosniff");
});
it("preserves content gates for HEAD", async function () {
repo.options.pdf = false;
expect((await fetch("/api/repo/fixture/file/private.pdf", "HEAD")).status).to.equal(403);
+8
View File
@@ -17,6 +17,12 @@ describe("file route scriptable-document detection", function () {
"style.xsl",
"transform.xslt",
"archive.mhtml",
"archive.mht",
"page.shtml",
"figures/plot.svgz",
"schema.xsd",
"schema.rng",
"feed.atom",
];
scriptable.forEach((path) => {
expect(isScriptableDocument(path), path).to.equal(true);
@@ -26,6 +32,8 @@ describe("file route scriptable-document detection", function () {
it("is case insensitive on the extension", function () {
expect(isScriptableDocument("README.HTML")).to.equal(true);
expect(isScriptableDocument("logo.SVG")).to.equal(true);
expect(isScriptableDocument("logo.SVGZ")).to.equal(true);
expect(isScriptableDocument("page.SHTML")).to.equal(true);
});
it("leaves everything else alone", function () {
+57
View File
@@ -0,0 +1,57 @@
const { expect } = require("chai");
const fs = require("node:fs");
const path = require("node:path");
const vm = require("node:vm");
const { JSDOM } = require("jsdom");
const read = file => fs.readFileSync(path.join(__dirname, "../public", file), "utf8");
const loader = [...read("index.html").matchAll(/<script>([\s\S]*?)<\/script>/g)]
.map(match => match[1]).find(script => script.includes("window.loadMermaid"));
describe("Mermaid untrusted diagram security", function () {
this.timeout(10000);
let dom, window;
beforeEach(function () {
dom = new JSDOM("<body></body>", { runScripts: "outside-only", url: "https://viewer.test/" });
window = dom.window;
window.SVGElement.prototype.getBBox = () => ({ x: 0, y: 0, width: 100, height: 20 });
vm.runInContext(read("script/external/mermaid.min.js"), dom.getInternalVMContext());
});
afterEach(function () { dom.window.close(); });
it("lazy-loads with strict security and rejects diagram overrides and click links", async function () {
window.eval(loader);
window.loadMermaid();
window.document.querySelector("script").onload();
expect(window.mermaidInitialized).to.equal(true);
expect(window.mermaid.mermaidAPI.getConfig().securityLevel).to.equal("strict");
const result = await window.mermaid.render("hostile-diagram", `%%{init: {"securityLevel": "loose"}}%%
flowchart TD
A[Readme] --> B[Details]
click A href "javascript:alert(document.domain)" "Open"
click B call alert() "Callback"`);
expect(result.svg).to.include("Readme");
expect(result.svg).not.to.include("javascript:");
window.document.body.innerHTML = result.svg;
let callbacks = 0;
window.alert = () => { callbacks++; };
result.bindFunctions?.(window.document.body);
expect(window.document.querySelector("a[href], a[xlink\\:href]")).to.equal(null);
window.document.querySelectorAll(".node").forEach(node => {
node.dispatchEvent(new window.MouseEvent("click", { bubbles: true }));
});
expect(callbacks).to.equal(0);
expect(window.mermaid.mermaidAPI.getConfig().securityLevel).to.equal("strict");
});
it("initializes strict security through the extension fallback too", function () {
const scheduled = [];
window.setTimeout = callback => scheduled.push(callback);
window.eval(read("script/external/marked-mermaid.js"));
const extension = window.markedMermaid().extensions[0];
extension.renderer({ text: "graph TD; A-->B" });
scheduled.forEach(callback => callback());
expect(window.mermaidInitialized).to.equal(true);
expect(window.mermaid.mermaidAPI.getConfig().securityLevel).to.equal("strict");
});
});
+39
View File
@@ -73,6 +73,45 @@ describe("repository activity dates", () => {
expect(saved.settingsSavedAt).to.be.instanceOf(Date);
expect(saved["options.expirationDate"]).to.be.instanceOf(Date);
});
for (const action of ["save", "extend"]) {
for (const outcome of ["success", "failure", "concurrent removal"]) {
it(`${action} restores atomically and handles enqueue ${outcome}`, async () => {
const repo = repository(action === "save" ? "removed" : "expired");
auth(repo);
const stored = repo.model.toObject();
let writes = 0, responded = false, queued = false;
stub(Model, "updateOne", (filter, update) => ({ exec: async () => {
if (!require("sift").default(filter)(stored)) return { matchedCount: 0 };
// Mongoose omits undefined values from $set before sending it.
for (const [key, value] of Object.entries(update.$set)) {
if (value !== undefined) stored[key] = value;
}
writes++;
return { matchedCount: 1 };
} }));
const failure = new Error("queue unavailable");
stub(queue, "downloadQueue", { add: async () => {
expect(responded).to.equal(false);
expect(writes).to.equal(1);
expect(stored.status).to.equal("preparing");
expect(stored.anonymizeDate.getTime()).to.be.greaterThan(new Date("2026-01-02").getTime());
if (outcome === "concurrent removal") stored.status = "removing";
if (outcome !== "success") throw failure;
queued = true;
} });
let caught;
try {
await handler("repository-private", action === "save" ? "/:repoId/" : "/:repoId/extend", "post")({ body: {
repoId: repo.repoId, fullName: "owner/repo", source: { commit: "abc123", branch: "main" },
terms: [], options: { expirationMode: "never" },
} }, { json: () => { expect(queued).to.equal(true); responded = true; } });
} catch (error) { caught = error; }
expect(caught).to.equal(outcome === "success" ? undefined : failure);
expect(responded).to.equal(outcome === "success");
expect(stored.status).to.equal(outcome === "success" ? "preparing" : outcome === "failure" ? "error" : "removing");
});
}
}
it("returns publication and settings dates independently of the older source commit", async () => {
const repo = repository(); auth(repo);
repo.model.settingsSavedAt = new Date("2026-03-01");
+2
View File
@@ -103,6 +103,8 @@ describe("reconnecting a recreated repository", () => {
expect(saved.update.$set.githubAccess.revision).not.to.equal("old");
expect(saved.update.$set.source.repositoryId).to.equal("new-record");
expect(saved.update.$set.source.commit).to.equal("abcdef");
expect(saved.update.$set.status).to.equal("preparing");
expect(saved.update.$set.statusDate).to.be.instanceOf(Date);
expect(saved.update.$set.source.commitDate).to.deep.equal(new Date("2026-09-29T00:00:00Z"));
expect(removals).to.deep.equal([{ accessRevision: "old" }]);
expect(jobs[0][1]).to.deep.equal({ repoId: "recreated" });
+40 -3
View File
@@ -190,6 +190,43 @@ describe("Vue 3 UI", function () {
expect(ui.window.document.querySelector("#email-prompt-address").value).to.equal("owner@example.com");
});
for (const code of ["repo_not_found", "token_expired", "github_app_reconnect_required"]) {
it(`explains ${code} without exposing the source and retries after access recovers`, async () => {
let recovered = false;
ui = await browser("/r/access-test/hello.js", {
"/api/repo/access-test/file/hello.js": () => recovered ? "recovered content" : {
__status: 404, body: { error: code, detail: "private-owner/private-source", token: "secret" },
},
});
await delay(100);
const panel = ui.window.document.querySelector(".viewer-error");
expect(panel?.textContent).to.include("GitHub access needs attention");
expect(panel.textContent).to.include("You do not need to sign in");
expect(panel.textContent).to.include("Keep the existing anonymous URL");
expect(panel.textContent).not.to.include("private-owner");
expect(panel.textContent).not.to.include("secret");
recovered = true;
panel.querySelector("button").click();
await delay(150);
expect(ui.window.document.querySelector(".viewer-error")).to.equal(null);
expect(ui.requests.filter(request => request.url.pathname.endsWith("/file/hello.js"))).to.have.length(2);
expect(ui.errors).to.deep.equal([]);
});
}
it("offers a safe retry for an unrecognized gateway response", async () => {
ui = await browser("/r/access-test/hello.js", {
"/api/repo/access-test/options": { __status: 403, body: "<html>private diagnostic</html>" },
});
await delay(100);
const panel = ui.window.document.querySelector(".viewer-error");
expect(panel?.textContent).to.include("We could not load this content");
expect(panel.textContent).not.to.include("private diagnostic");
expect(panel.textContent).not.to.include("GitHub access needs attention");
expect(panel.querySelector("button").textContent).to.equal("Try again");
expect(ui.errors).to.deep.equal([]);
});
const repositorySource = {
"/api/user": { username: "owner" },
"/api/user/default": { terms: ["Default Author"], options: {} },
@@ -1161,13 +1198,13 @@ describe("Vue 3 UI", function () {
expect(ui.errors).to.deep.equal([]);
});
for (const [code, message] of [["repo_not_found", "The repository was not found"], ["untranslated_failure", "Unknown error, contact the admin."]]) {
for (const [code, message] of [["repo_not_found", "GitHub access needs attention"], ["untranslated_failure", "We could not load this content"]]) {
it("shows the " + code + " explorer error in a card without file actions", async function () {
ui = await browser("/r/gone/", { "/api/repo/gone/options": { __status: 404, body: { error: code } } });
const card = ui.window.document.querySelector(".file-error-card");
expect(card.textContent).to.include("This content can").and.include(message);
expect(card.textContent).to.include(message);
expect(card.textContent).not.to.include("ERRORS.");
expect(card.querySelector('a[href="/"]')).to.not.equal(null);
expect(card.querySelector(code === "repo_not_found" ? 'a[href="/dashboard"]' : 'a[href="/"]')).to.not.equal(null);
expect(ui.window.document.querySelector(".status-bar").style.display).to.equal("none");
expect(ui.errors).to.deep.equal([]);
});