feat: let authors leave their bibliography unredacted (#941) (#943)

* feat: let owners leave chosen files unredacted (#941)

Redacting self-citations in a bibliography reveals which papers are the
authors' own. Owners can now pick files whose content is served as
written; file names are still redacted. Patterns follow .gitignore rules.

The form gets a file picker fed by GitHub's tree API, and the terms box
grows with its content and only warns about regex symbols that can stop a
term from matching.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: honour !patterns, keep picked braces literal, preview unredacted README

- Patterns now apply in order and the last match wins, as in .gitignore,
  so "*.bib" then "!private.bib" excludes private.bib instead of
  preserving every other file.
- Picked paths escape glob characters, braces included, with a
  backslash; "[{]" did not survive brace expansion.
- The README preview drops terms when the README is an unredacted file,
  and refreshes when the list changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: keep rule order when deduplicating unredacted-file patterns

Rules apply in order and the last match wins, so dedupe keeps the last
copy of a repeated pattern instead of the first. The picker also keeps a
plain path in its place when it follows another rule, rather than moving
it to the front as a pick.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: apply unredacted-file rules to folders, as in .gitignore

A rule that matches a folder now covers every file inside it, so "*.bib"
then "!private" keeps private/refs.bib redacted. A trailing "/" limits a
rule to folders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: folder unchecks win over broad rules; accept short commit hashes

- Unchecking a folder that a broader rule such as "*.bib" still covers
  appends a "!/folder/" exclusion, so its files really go back to being
  redacted.
- The tree endpoint accepts the 6+ character hashes the commit field
  allows and resolves them to a full SHA before reading the tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: picker counts folder rules exactly as the server does

Rules ending in "/" stay patterns instead of being read as picked files,
and the checkboxes now run the saved rule list (picks, then patterns)
through the server's matcher, so the dialog cannot show files as
redacted that the server leaves unredacted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: insert escaped terms literally in "Match as written"

String.replace expanded "$&", "$'" and "$1" in the term, so the fix
could corrupt the line. Splice by index instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Thomas DurieuxandClaude Opus 5.5 authored and GitHub committed 2026-11-11 14:10:54 +01:00
1 parent accfdeef50
commit 643f4b87e9
27 files changed
+916 -49

No files matched your search

+1 -1
View File
@@ -25,7 +25,7 @@ A free public instance is available at **[anonymous.4open.science](https://anony
- The GitHub **owner, organization, and repository name**
- **File and directory names**
- **File contents** of every extension (Markdown, text, source code, …), replacing a configurable list of terms
- **File contents** of every extension (Markdown, text, source code, …), replacing a configurable list of terms. Files you choose under "Unredacted files" (e.g. `paper/refs.bib`, or a pattern such as `*.bib`) keep their content as written, so redacted self-citations do not single out the authors; their names are still redacted
## Usage
+1
View File
@@ -41,6 +41,7 @@
"marked-katex-extension": "^5.1.13",
"mermaid": "^12.2.0",
"mime-types": "^3.0.2",
"minimatch": "^11.0.1",
"mongoose": "^7.8.13",
"node-schedule": "^2.1.2",
"parse-github-url": "^1.0.4",
+1
View File
@@ -74,6 +74,7 @@
"marked-katex-extension": "^5.1.13",
"mermaid": "^12.2.0",
"mime-types": "^3.0.2",
"minimatch": "^11.0.1",
"mongoose": "^7.8.13",
"node-schedule": "^2.1.2",
"parse-github-url": "^1.0.4",
+2 -2
View File
@@ -1,8 +1,8 @@
{
"core.min.js": "core.d23af1c652.min.js",
"vendor.min.js": "vendor.fc4289fc49.min.js",
"vendor.min.js": "vendor.3f99749002.min.js",
"mermaid.min.js": "mermaid.a7356d5ed1.min.js",
"all.min.css": "all.e352c264c6.min.css",
"all.min.css": "all.c690a01ace.min.css",
"markdown.min.js": "markdown.6c8dfb7b1d.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
+31
View File
@@ -8829,6 +8829,35 @@ body:not(.dark-mode) .anonymize-page { --paper-card: #fff; --canvas-bg-color: #f
}
.anonymize-page .redaction-syntax { font-size: 12px; margin-top: 8px; }
.redaction-syntax summary { cursor: pointer; color: var(--link-color); min-height: 28px; }
.anonymize-page .term-hint { display: flex; gap: 10px; align-items: center; justify-content: space-between; margin-top: 8px; padding: 8px 10px; border-radius: 6px; background: #fbf1df; color: #5c3a07; font-size: 12px; }
.anonymize-page .term-hint code { background: none; padding: 0; color: inherit; font-weight: 600; }
.anonymize-page .term-hint .btn { flex: none; }
.anonymize-page .term-hint-more { margin-top: 6px; font-size: 12px; color: var(--ink-muted); }
body.dark-mode .anonymize-page .term-hint { background: #3a2f1c; color: #f3dcb4; }
.anonymize-page .preserve-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 4px 0 16px; padding-top: 14px; border-top: 1px solid var(--paper-border, #e5e1d9); }
.anonymize-page .preserve-row-text { display: flex; flex-direction: column; min-width: 0; }
.anonymize-page .preserve-row .paper-field-label { margin-bottom: 2px; }
.anonymize-page .preserve-row-value { font-size: 12px; color: var(--ink-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.anonymize-page .preserve-row .btn { flex: none; }
.preserve-dialog { width: min(620px, calc(100vw - 32px)); padding: 24px; border: 1px solid var(--paper-border, #e5e1d9); border-radius: 12px; background: var(--paper-bg, #faf9f6); color: inherit; box-shadow: 0 16px 64px #0003; }
.preserve-dialog::backdrop { background: #0006; }
.preserve-dialog h2 { margin: 0 0 6px; font-size: 20px; }
.preserve-dialog .preserve-intro { font-size: 13px; color: var(--ink-muted); margin-bottom: 14px; }
.preserve-dialog .preserve-tree { margin-top: 10px; height: 300px; overflow: auto; border: 1px solid var(--paper-border, #e5e1d9); border-radius: 8px; background: var(--paper-card); padding: 4px 0; }
.preserve-dialog .preserve-item { display: flex; align-items: center; gap: 6px; min-height: 30px; padding-right: 10px; font-size: 13px; }
.preserve-dialog .preserve-item:hover { background: var(--paper-bg-alt); }
.preserve-dialog .preserve-caret, .preserve-dialog .preserve-caret-space { flex: none; width: 18px; height: 22px; border: 0; padding: 0; background: none; color: var(--ink-muted); font-size: 12px; cursor: pointer; }
.preserve-dialog .preserve-item input { flex: none; margin: 0; }
.preserve-dialog .preserve-name { flex: 1; min-width: 0; margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: ui-monospace, SFMono-Regular, monospace; font-size: 12.5px; cursor: pointer; }
.preserve-dialog .preserve-note { flex: none; font-size: 11px; color: var(--ink-muted); }
.preserve-dialog .preserve-status { margin: 10px 12px; font-size: 13px; color: var(--ink-muted); }
.preserve-dialog .preserve-patterns { margin-top: 12px; font-size: 13px; }
.preserve-dialog .preserve-patterns summary { cursor: pointer; color: var(--link-color); min-height: 28px; }
.preserve-dialog .preserve-patterns textarea { margin-top: 6px; font-family: ui-monospace, SFMono-Regular, monospace; font-size: 12.5px; }
.preserve-dialog .preserve-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin-top: 16px; }
.preserve-dialog .preserve-count { font-size: 13px; color: var(--ink-muted); }
.preserve-dialog .preserve-actions { display: flex; gap: 8px; margin-left: auto; }
body.dark-mode .preserve-dialog { background: #242320; color: #faf9f6; }
.anonymize-page .anonymize-preview-body h2 { border: 0; padding: 0; font-weight: 700; }
.anonymize-page .anonymize-preview-body h1 { font-weight: 700; }
.anonymize-page .anonymize-preview-body pre { background: var(--paper-bg-alt); line-height: 1.7; }
@@ -11566,6 +11595,8 @@ mark.md-find.is-current, .ace_editor .ace_marker-layer .ace_selection { backgrou
.anonymize-page input[type="checkbox"]::before { content: ""; width: 9px; height: 9px; transform: scale(0); background: #fff; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5l3.2 3L13 4.5'/%3E%3C/svg%3E") center/contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5l3.2 3L13 4.5'/%3E%3C/svg%3E") center/contain no-repeat; }
.anonymize-page input[type="checkbox"]:checked { background: var(--accent); border-color: var(--accent); }
.anonymize-page input[type="checkbox"]:checked::before { transform: scale(1); }
.anonymize-page input[type="checkbox"]:indeterminate { background: var(--accent); border-color: var(--accent); }
.anonymize-page input[type="checkbox"]:indeterminate::before { width: 8px; height: 2px; border-radius: 1px; -webkit-mask: none; mask: none; transform: scale(1); }
.anonymize-page input[type="checkbox"]:disabled { opacity: .45; cursor: not-allowed; }
.anonymize-page input[type="checkbox"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.dark-mode .anonymize-page input[type="checkbox"] { border-color: #6E6860; background: transparent; }
+1
View File
@@ -62,6 +62,7 @@
"options_not_provided": "Anonymization options are mandatory.",
"terms_not_specified": "Anonymization terms must be specified.",
"invalid_terms_format": "Terms are in an invalid format.",
"invalid_preserve_files_format": "Unredacted files must be repository paths or patterns, at most 200 of them.",
"missing_content": "No content was provided to the anonymization preview.",
"unable_to_anonymize": "An error happened during the anonymization process. Please try later or report the issue.",
"non_supported_mode": "The selected anonymization mode is invalid, only download and stream are supported.",
+4 -1
View File
@@ -30,7 +30,10 @@ an admin token or browser cookie. Maintenance tokens cannot log into the UI.
2. PATCH the same URL with only the settings to change, for example:
{"terms":["Alice Smith","Example University"],"image":false,"update":false}
Omitted settings stay unchanged. terms replaces the whole term list;
[] clears it. Supported boolean fields: update, image, pdf, notebook, link.
[] clears it. preserveFiles is a list of .gitignore-style patterns
(*.bib, /refs.bib, paper/**, !private.bib) whose file content is served without term
redaction; file names are still redacted. Supported boolean fields: update, image, pdf,
notebook, link.
update controls automatic snapshot updates. Settings edits work in ready
or error state, and cannot change the upstream source or connection.
3. POST /api/repo/{repoId}/refresh with {} requests the latest snapshot of the
+18
View File
@@ -85,6 +85,15 @@
"maxLength": 1000
}
},
"preserveFiles": {
"type": "array",
"maxItems": 200,
"description": "Glob patterns of files whose content is not redacted. Same rules as .gitignore: a pattern without / matches the file name in any folder; one containing / (including a leading /) matches from the repository root; !pattern excludes again and the last match wins. Replaces the whole list.",
"items": {
"type": "string",
"maxLength": 512
}
},
"update": {
"type": "boolean"
},
@@ -258,6 +267,15 @@
"maxLength": 1000
}
},
"preserveFiles": {
"type": "array",
"maxItems": 200,
"description": "Glob patterns of files whose content is not redacted. Same rules as .gitignore: a pattern without / matches the file name in any folder; one containing / (including a leading /) matches from the repository root; !pattern excludes again and the last match wins. Replaces the whole list.",
"items": {
"type": "string",
"maxLength": 512
}
},
"update": {
"type": "boolean"
},
+48 -3
View File
@@ -208,11 +208,56 @@
<div class="form-group">
<label class="paper-field-label" for="terms">Terms to redact</label>
<textarea class="form-control" id="terms" name="terms" rows="4" placeholder="Jane Smith&#10;MIT CSAIL&#10;jane.smith@example.org" v-field="{ state: viewState, set: value =&gt; { terms = value }, value: terms, form: &quot;anonymize&quot;, options: { debounce: 250 } }" :class="{&#x27;is-invalid&#x27;: anonymize?.terms?.invalid}"></textarea>
<textarea class="form-control terms-input" id="terms" name="terms" :rows="Math.min(14, Math.max(4, String(terms || &quot;&quot;).split(&quot;\n&quot;).length + 1))" placeholder="Jane Smith&#10;MIT CSAIL&#10;jane.smith@example.org" v-field="{ state: viewState, set: value =&gt; { terms = value }, value: terms, form: &quot;anonymize&quot;, options: { debounce: 250 } }" :class="{&#x27;is-invalid&#x27;: anonymize?.terms?.invalid}"></textarea>
<small class="form-text text-muted">One term per line.</small><details class="redaction-syntax"><summary>Regex &amp; replacement syntax</summary> <small class="form-text text-muted">Regex is supported. Replaced by <code>{{ site_options?.ANONYMIZATION_MASK }}-[N]</code>, or use <code>term=&gt;replacement</code> to pick your own (e.g. <code>Anonymous=&gt;ABC</code>).</small></details>
<div class="warning-feedback" v-show="termsRegexWarning">Regex characters detected. Escape them if unintentional.</div>
<div class="term-hint" v-for="hint in (termHints || []).slice(0, 3)" :key="hint.line">
<span>In <code>{{ hint.term }}</code>, <code>{{ hint.symbols.join(" ") }}</code> {{ hint.symbols.length > 1 ? "are regex symbols" : "is a regex symbol" }}, so it may not match the text as written.</span>
<button type="button" class="btn btn-outline-ink btn-sm" @click="matchTermAsWritten(hint.line)">Match as written</button>
</div>
<div class="term-hint-more" v-if="(termHints || []).length > 3">{{ termHints.length - 3 }} more {{ termHints.length - 3 === 1 ? "term uses" : "terms use" }} regex symbols.</div>
<div class="invalid-feedback" v-show="anonymize?.terms?.errors?.format">Terms are in an invalid format.</div>
</div>
<div class="preserve-row" v-show="detectedType === &#x27;repo&#x27;">
<div class="preserve-row-text">
<span class="paper-field-label" id="preserve-files-label">Unredacted files</span>
<span class="preserve-row-value">{{ preserveSummary() }}</span>
</div>
<button type="button" class="btn btn-outline-ink btn-sm" aria-describedby="preserve-files-label" :disabled="!source?.commit" @click="openPreserveFiles()">{{ (options?.preserveFiles || []).length ? "Edit" : "Choose files" }}</button>
</div>
<dialog id="preserve-files-dialog" class="preserve-dialog" v-if="preserve?.open" aria-labelledby="preserve-files-title" @cancel.prevent="closePreserveFiles()">
<form @submit.prevent="savePreserveFiles()">
<h2 id="preserve-files-title">Leave files unredacted</h2>
<p class="preserve-intro">Checked files are shown exactly as written, for example a bibliography where redacted self-citations would reveal you. File names are still redacted.</p>
<input type="search" id="preserve-files-search" class="form-control" placeholder="Search files" aria-label="Search files" autocomplete="off" v-model="preserve.search">
<div class="preserve-tree">
<p class="preserve-status" v-if="preserve.loading">Loading files from GitHub…</p>
<p class="paper-inline-alert paper-inline-alert-error" role="alert" v-else-if="preserve.error">{{ preserve.error }}</p>
<template v-else>
<div class="preserve-item" v-for="(row, i) in preserveRows()" :key="row.kind + ':' + row.path" :style="{ paddingLeft: (row.depth * 18 + 6) + &quot;px&quot; }">
<button type="button" class="preserve-caret" v-if="row.kind === &#x27;dir&#x27;" :aria-expanded="row.open ? &quot;true&quot; : &quot;false&quot;" :aria-label="(row.open ? &quot;Collapse &quot; : &quot;Expand &quot;) + row.label" @click="togglePreserveDir(row.path)">{{ row.open ? "▾" : "▸" }}</button>
<span class="preserve-caret-space" v-else></span>
<input type="checkbox" :id="&quot;pf-&quot; + i" :aria-label="row.kind === &#x27;dir&#x27; ? &quot;Leave folder &quot; + row.path + &quot; unredacted&quot; : null" :checked="row.state === &#x27;all&#x27;" :indeterminate.prop="row.state === &#x27;some&#x27;" :disabled="row.locked" @change="row.kind === &#x27;dir&#x27; ? togglePreserveFolder(row.path) : togglePreserveFile(row.path)">
<label :for="row.kind === &#x27;file&#x27; ? &quot;pf-&quot; + i : null" class="preserve-name" @click="row.kind === &#x27;dir&#x27; &amp;&amp; togglePreserveDir(row.path)">{{ row.label }}</label>
<span class="preserve-note" v-if="row.note">{{ row.note }}</span>
</div>
<p class="preserve-status" v-if="!preserve.loading &amp;&amp; !preserveRows().length">{{ preserve.search ? "No file matches your search." : "No text files in this commit." }}</p>
</template>
</div>
<p class="preserve-status" v-if="preserve.truncated">This repository has too many files to list them all. Use a pattern for files you cannot find.</p>
<details class="preserve-patterns" :open="preserve.patternsOpen">
<summary>Patterns</summary>
<textarea class="form-control" rows="3" aria-label="Patterns" placeholder="*.bib&#10;paper/appendix/**" v-model="preserve.patterns"></textarea>
<small class="form-text text-muted">One per line, as in .gitignore: <code>*.bib</code> matches in any folder; <code>/refs.bib</code> and <code>paper/refs.bib</code> match from the repository root; a folder name such as <code>drafts/</code> covers everything inside it; <code>!private.bib</code> excludes again.</small>
</details>
<div class="preserve-foot">
<span class="preserve-count" aria-live="polite">{{ preserve.loading || preserve.error ? "" : preserveCount() + (preserveCount() === 1 ? " file" : " files") + " will be shown as written" }}</span>
<span class="preserve-actions">
<button type="button" class="btn btn-outline-ink" @click="closePreserveFiles()">Cancel</button>
<button type="submit" class="btn btn-ink">Save</button>
</span>
</div>
</form>
</dialog>
</section>
<section class="paper-settings-section" v-show="detectedType">
@@ -432,7 +477,7 @@
<div id="workspace-preview" :role="mobileWorkspace ? 'tabpanel' : null" :aria-labelledby="mobileWorkspace ? 'workspace-preview-tab' : null" class="anonymize-preview-col" v-if="detectedType === &#x27;repo&#x27;">
<div class="anonymize-preview-head">
<span class="paper-eyebrow">Live preview</span>
<span class="anonymize-preview-sub">{{ previewStatus !== 'ready' ? 'README preview' : (String(terms || '').trim() ? 'README with redactions applied' : 'No terms yet. Add some to see them redacted here.') }}</span>
<span class="anonymize-preview-sub">{{ previewStatus !== 'ready' ? 'README preview' : (readmePreserved() ? 'README left unredacted (Unredacted files)' : (String(terms || '').trim() ? 'README with redactions applied' : 'No terms yet. Add some to see them redacted here.')) }}</span>
<button type="button" class="task-text-button preview-expand" @click="previewExpanded = !previewExpanded">{{ previewExpanded ? 'Restore split view' : 'Expand preview' }}</button>
</div>
<div class="anonymize-preview-status" role="status" v-if="sourceLoading &amp;&amp; previewStatus === 'idle'">Loading source…</div>
+1 -1
View File
@@ -6,7 +6,7 @@
<div v-show="settingsTab === 'defaults'">
<p class="settings-scope">For new anonymizations only. Existing repositories keep their settings.</p>
<form class="form needs-validation" name="defaultsForm" novalidate v-form="viewState" @submit.prevent="submitForm($event, () => { saveDefault($event) })">
<section class="settings-row"><div><label class="settings-label" for="terms">Terms to redact</label><p class="settings-help">One term per line.</p></div><div><textarea class="form-control" id="terms" name="terms" rows="3" placeholder="Jane Smith
<section class="settings-row"><div><label class="settings-label" for="terms">Terms to redact</label><p class="settings-help">One term per line.</p></div><div><textarea class="form-control" id="terms" name="terms" :rows="Math.min(14, Math.max(3, String(terms || &quot;&quot;).split(&quot;\n&quot;).length + 1))" placeholder="Jane Smith
MIT CSAIL
jane.smith@example.org" v-field="{ state: viewState, set: value =&gt; { terms = value }, value: terms, form: &quot;defaultsForm&quot;, options: { debounce: 250 } }"></textarea>
<details class="settings-syntax"><summary>Regex &amp; replacement syntax</summary><p>Matches become <code>{{ site_options?.ANONYMIZATION_MASK || 'XXX' }}-[N]</code>. Use <code>term=&gt;replacement</code> for a custom replacement. Regex is supported.</p></details>
+191 -4
View File
@@ -3,6 +3,9 @@ import { reactive, nextTick, markRaw } from "vue";
import { loadEditor } from "./lazy-assets.js";
import { createTimers, createListeners } from "./state.js";
import { formDraft } from "./drafts.js";
import { escape as globEscape, unescape as globUnescape } from "minimatch";
import { compilePreserveMatcher, dedupePreservePatterns } from "../../src/core/preserve-files";
import { termHints, escapeTermLine } from "../../src/core/term-hints";
import translations from "../i18n/locale-en.json";
// A README image that fails to load becomes a quiet placeholder, not a broken-image glyph.
@@ -2058,9 +2061,187 @@ export const anonymizeController = function (state, http, html, params, location
// debounced and the in-flight request is dropped on the next change so
// typing in the form stays responsive.
// ---- "Leave files unredacted" picker (#941) ----
// Picked files are saved first, as root-anchored paths with glob characters
// (braces included) escaped by a backslash; folders and anything typed by
// hand follow as patterns. Patterns apply in order, so a later "!pattern"
// can exclude a picked file, exactly as on the server.
const globOpts = { magicalBraces: true };
// A picked file: a root-anchored path with no glob characters. Folder rules
// ("/paper/") stay patterns.
const isPickedPattern = (p) => p.startsWith("/") && !p.endsWith("/") && globEscape(globUnescape(p.slice(1), globOpts), globOpts) === p.slice(1);
const pickedRules = () => Object.keys(state.preserve.picked).filter((f) => state.preserve.picked[f]).sort()
.map((f) => "/" + globEscape(f, globOpts));
const folderPattern = (dir) => "/" + globEscape(dir, globOpts) + "/**";
const folderExclusion = (dir) => "!/" + globEscape(dir, globOpts) + "/";
const patternLines = () => String(state.preserve.patterns || "").split("\n").map((l) => l.trim()).filter(Boolean);
let preserveIndex = null;
// The checkboxes use the exact rule list that will be saved (picks first,
// then patterns) through the server's matcher, so they cannot disagree.
let pickVersion = 0;
let matcherKey = null;
let matcherFn = () => false;
function preserveMatcher() {
const key = pickVersion + "\u0000" + state.preserve.patterns;
if (key !== matcherKey) {
matcherKey = key;
try { matcherFn = compilePreserveMatcher(dedupePreservePatterns([...pickedRules(), ...patternLines()])); } catch { matcherFn = () => false; }
}
return matcherFn;
}
function buildPreserveIndex(files) {
const dirs = new Map([["", { dirs: [], files: [] }]]);
for (const file of files) {
const parts = file.split("/");
let parent = "";
for (let i = 0; i < parts.length - 1; i++) {
const dir = parts.slice(0, i + 1).join("/");
if (!dirs.has(dir)) { dirs.set(dir, { dirs: [], files: [] }); dirs.get(parent).dirs.push(dir); }
parent = dir;
}
dirs.get(parent).files.push(file);
}
for (const entry of dirs.values()) entry.dirs.sort();
return { files, dirs, descendants: new Map() };
}
function descendants(dir) {
if (!preserveIndex.descendants.has(dir)) {
preserveIndex.descendants.set(dir, preserveIndex.files.filter((f) => f.startsWith(dir + "/")));
}
return preserveIndex.descendants.get(dir);
}
const fileChecked = (file) => preserveMatcher()(file);
function dirState(dir) {
const files = descendants(dir);
let checked = 0;
for (const f of files) if (fileChecked(f)) checked++;
return checked === 0 ? "none" : checked === files.length ? "all" : "some";
}
state.preserve = { open: false, loading: false, error: "", truncated: false, commit: "", search: "", expanded: {}, picked: {}, patterns: "", patternsOpen: false };
state.preserveSummary = () => {
const list = (state.options?.preserveFiles || []).map((p) => String(p).trim()).filter(Boolean)
.map((p) => isPickedPattern(p) ? globUnescape(p.slice(1), globOpts) : p);
if (!list.length) return "None. Every file is redacted.";
return list.slice(0, 2).join(", ") + (list.length > 2 ? ` and ${list.length - 2} more` : "");
};
async function loadPreserveTree() {
const commit = state.source?.commit;
if (preserveIndex && state.preserve.commit === commit) return;
state.preserve.loading = true;
state.preserve.error = "";
preserveIndex = null;
try {
const o = parseGithubUrl(state.sourceUrl);
const res = await http.get(`/api/repo/${o.owner}/${o.repo}/tree`, {
params: { commit, connection: state.githubConnection, anonymizedRepoId: state.isUpdate && params.repoId && parseRepoFullName(state.sourceUrl) === state._originalFullName ? params.repoId : undefined, repositoryID: sourceRepositoryID() },
});
if (state.source?.commit !== commit) return;
preserveIndex = markRaw(buildPreserveIndex(res.data.files || []));
state.preserve.commit = commit;
state.preserve.truncated = !!res.data.truncated;
} catch (error) {
state.preserve.error = "The file list could not be loaded from GitHub. You can still use patterns.";
state.preserve.patternsOpen = true;
} finally {
state.preserve.loading = false;
}
}
state.openPreserveFiles = () => {
// Picks are saved first, so only the leading run of plain paths can be
// shown as picks; a plain path after another rule stays a pattern to
// keep its place in the order.
const picked = {};
const patterns = [];
for (const raw of state.options?.preserveFiles || []) {
const p = String(raw).trim();
if (!p) continue;
if (!patterns.length && isPickedPattern(p)) picked[globUnescape(p.slice(1), globOpts)] = true;
else patterns.push(p);
}
const expanded = {};
for (const file of Object.keys(picked)) {
const parts = file.split("/");
for (let i = 1; i < parts.length; i++) expanded[parts.slice(0, i).join("/")] = true;
}
Object.assign(state.preserve, { open: true, search: "", picked, expanded, patterns: patterns.join("\n"), patternsOpen: patterns.length > 0 });
pickVersion++;
timeout(() => {
const dialog = document.getElementById("preserve-files-dialog");
if (dialog?.showModal && !dialog.open) dialog.showModal();
document.getElementById("preserve-files-search")?.focus();
}, 0);
loadPreserveTree();
};
state.closePreserveFiles = () => {
document.getElementById("preserve-files-dialog")?.close?.();
state.preserve.open = false;
};
state.savePreserveFiles = () => {
state.options.preserveFiles = dedupePreservePatterns([...pickedRules(), ...patternLines()]);
state.closePreserveFiles();
};
state.preserveRows = () => {
if (!preserveIndex) return [];
const matcher = preserveMatcher();
const fileRow = (file, depth, label) => {
const picked = !!state.preserve.picked[file];
const checked = matcher(file);
const note = !picked && checked ? "matched by a pattern" : picked && !checked ? "excluded by a pattern" : "";
return { kind: "file", path: file, label, depth, state: checked ? "all" : "none", locked: !picked && checked, note };
};
const search = String(state.preserve.search || "").trim().toLowerCase();
if (search) {
return preserveIndex.files.filter((f) => f.toLowerCase().includes(search)).slice(0, 300).map((f) => fileRow(f, 0, f));
}
const rows = [];
const walk = (dir, depth) => {
const entry = preserveIndex.dirs.get(dir);
for (const sub of entry.dirs) {
const open = !!state.preserve.expanded[sub];
const ownPattern = patternLines().includes(folderPattern(sub));
rows.push({ kind: "dir", path: sub, label: sub.slice(dir ? dir.length + 1 : 0) + "/", depth, open, state: dirState(sub), locked: false, note: ownPattern ? "whole folder" : "" });
if (open) walk(sub, depth + 1);
}
for (const file of entry.files) rows.push(fileRow(file, depth, file.slice(dir ? dir.length + 1 : 0)));
};
walk("", 0);
return rows;
};
state.preserveCount = () => preserveIndex ? preserveIndex.files.filter(fileChecked).length : 0;
state.togglePreserveDir = (dir) => { state.preserve.expanded[dir] = !state.preserve.expanded[dir]; };
state.togglePreserveFile = (file) => { state.preserve.picked[file] = !state.preserve.picked[file]; pickVersion++; };
// Unchecking a folder must win over broader rules such as "*.bib", so a
// folder exclusion is appended when files inside would stay checked.
state.togglePreserveFolder = (dir) => {
const own = folderPattern(dir);
const exclusion = folderExclusion(dir);
const lines = patternLines().filter((l) => l !== own && l !== exclusion);
const wasChecked = dirState(dir) === "all" || patternLines().includes(own);
for (const f of descendants(dir)) state.preserve.picked[f] = false;
pickVersion++;
state.preserve.patterns = (wasChecked ? lines : [...lines, own]).join("\n");
if (wasChecked && descendants(dir).some(fileChecked)) {
state.preserve.patterns = [...lines, exclusion].join("\n");
}
};
// GitHub's README lookup order. The exact path is not known here, so the
// preview treats the README as unredacted if any candidate is selected:
// when unsure, it shows the author more exposure, not less.
const README_CANDIDATES = [".github", "", "docs"].flatMap((dir) =>
["README.md", "README", "README.markdown", "README.rst", "README.txt", "readme.md"].map((name) => (dir ? dir + "/" : "") + name));
state.readmePreserved = () => {
if (state.detectedType !== "repo") return false;
const patterns = (state.options?.preserveFiles || []).map((p) => String(p).trim()).filter(Boolean);
if (!patterns.length) return false;
try {
const matcher = compilePreserveMatcher(patterns);
return README_CANDIDATES.some((path) => matcher(path));
} catch { return false; }
};
function previewOptions() {
const opts = {
terms: state.terms ? state.terms.split("\n") : [],
terms: state.terms && !state.readmePreserved() ? state.terms.split("\n") : [],
image: !!state.options.image,
link: !!state.options.link,
repoId: state.repoId,
@@ -2144,8 +2325,6 @@ export const anonymizeController = function (state, http, html, params, location
if (!state.anonymize || !state.anonymize.terms) return;
// The "regex characters detected" hint is informational, not a blocker
// — IP addresses, escaped chars, etc. are all legitimate terms (#430).
state.termsRegexWarning =
!!state.terms && !!state.terms.match(/[-[\]{}()*+?.,\\^$|#]/g);
scheduleReadmePreview();
}
@@ -2371,7 +2550,7 @@ export const anonymizeController = function (state, http, html, params, location
setValidity("commit", "exists", true);
setValidity("conference", "activated", true);
setValidity("terms", "format", true);
state.termsRegexWarning = false;
state.termHints = [];
}
// Guards against submitting a missing or out-of-range expiration date.
@@ -2587,7 +2766,15 @@ export const anonymizeController = function (state, http, html, params, location
};
state.watch("conference", () => { getConference(); });
state.termHints = [];
state.matchTermAsWritten = (line) => {
state.terms = escapeTermLine(state.terms, line);
};
state.watch("options.preserveFiles", () => {
if (state.detectedType === "repo") scheduleReadmePreview();
});
state.watch("terms", () => {
state.termHints = termHints(state.terms);
if (state.detectedType === "repo") anonymizeReadme();
if (state.detectedType === "pr") refreshPrPreview();
if (state.detectedType === "gist") refreshGistPreview();
+43 -32
View File
@@ -1,34 +1,44 @@
"use strict";(()=>{var Rd=Object.defineProperty;var Dd=(e,t)=>{for(var o in t)Rd(e,o,{get:t[o],enumerable:!0})};var pe=["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 fe={markdown:"/script/markdown.6c8dfb7b1d.min.js",notebook:"/script/notebook.c3144c18ae.min.js",org:"/script/org.f61f262915.min.js",pdf:"/script/pdf.4d9cc6ff49.min.js",editor:"/script/editor.4f142d3adc.min.js"};function Si(e){let t=e.location.hash.slice(1);if(e.history.replaceState(null,"","/review-link"),t.length>2048)return null;let o=new URLSearchParams(t);if([...o.keys()].length!==3||[...o.keys()].some(a=>!["clientId","intentId","token"].includes(a)))return null;let i=o.get("clientId"),s=o.get("intentId"),r=o.get("token");return!/^[a-f0-9]{32}$/.test(i||"")||!/^[a-f0-9]{32}$/.test(s||"")||!/^[a-f0-9]{64}$/.test(r||"")?null:{contract:"4open.artifacts/1",clientId:i,intentId:s,token:r}}function Ni(e,t){let{http:o,promises:i,window:s}=t,r=t.takeReviewHandoff(),a=r?{clientId:r.clientId,intentId:r.intentId}:null,p,f,g,y,b,m=!0,E,P=i.defer(),k=()=>[...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:r?"":"Open a new artifact link from your submission. This link is missing or invalid."});let v=()=>m&&e.user?.username===b;function S(){m=!1,r=p=f=void 0,P.resolve(),s.clearTimeout(E)}e.on("dispose",S),e.on("routeLeave",S),e.watch(()=>e.user?.username,L=>{!b&&L?b=L:b&&L!==b&&(S(),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 _=()=>({timeout:P.promise,headers:{"Content-Type":"application/json","X-Review-CSRF":f}}),M=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||!r||e.busy||e.uncertain||e.saved||!e.user?.username)return;b=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,p=void 0,e.acceptAccess=e.acceptRetention=!1,e.expired=!1,s.clearTimeout(E),y||(y=k());try{let q=(await o.get("/api/review-consent/csrf",{timeout:P.promise})).data;if(!v())return;if(f=q.csrf,e.handoffEnabled=q.handoffEnabled===!0,!/^[a-f0-9]{64}$/.test(f||""))throw new Error("invalid_csrf");let G=(await o.post("/api/review-consent/preview",{repositoryId:L,intent:{...r,requestId:y}},_())).data;if(!v())return;if(!G||typeof G.ticket!="string"||!G.ticket||G.ticket.length>8192||typeof G.repositoryName!="string"||!["restricted-review","anonymous-link"].includes(G.policy?.access)||!Number.isSafeInteger(G.policy.version)||!Number.isFinite(Date.parse(G.policy.retainUntil))||!Number.isFinite(Date.parse(G.expiresAt))||Date.parse(G.expiresAt)<=Date.now()||Date.parse(G.expiresAt)>Date.now()+6e5)throw new Error("invalid_preview");p=G.ticket,g=k(),e.preview={repositoryName:G.repositoryName,policy:{...G.policy},expiresAt:G.expiresAt},E=s.setTimeout(()=>{m&&(e.expired=!0)},Math.max(0,Date.parse(G.expiresAt)-Date.now()))}catch(q){v()&&(e.error=M(q))}finally{v()&&(e.busy=!1)}},e.confirmConsent=async()=>{if(!(!v()||e.busy||e.saved||!p||!e.acceptAccesLine truncated
`))),e[zt]=An(s);let r=i||s.props&&s.props.type==="number";nn(e,t?"change":"input",a=>{a.target.composing||e[zt](xs(e.value,o,r))}),(o||r)&&nn(e,"change",()=>{e.value=xs(e.value,o,r)}),t||(nn(e,"compositionstart",Ac),nn(e,"compositionend",ca),nn(e,"change",ca))},mounted(e,{value:t,modifiers:{trim:o,number:i}}){let s=t??"",r=e[xo];delete e[xo],r!==void 0&&(e.type==="text"||e.type==="textarea")&&e.value!==r?e[zt](xs(e.value,o,i)):e.value=s},beforeUpdate(e,{value:t,oldValue:o,modifiers:{lazy:i,trim:s,number:r}},a){if(e[zt]=An(a),e.composing)return;let p=(r||e.type==="number")&&!/^0\d/.test(e.value)?En(e.value):e.value,f=t??"";if(p===f)return;let g=e.getRootNode();(g instanceof Document||g instanceof ShadowRoot)&&g.activeElement===e&&e.type!=="range"&&(i&&t===o||s&&e.value.trim()===f)||(e.value=f)}},ti={deep:!0,created(e,t,o){e[zt]=An(o),nn(e,"change",()=>{let i=e._modelValue,s=vo(e),r=e.checked,a=e[zt];if(ge(i)){let p=Do(i,s),f=p!==-1;if(r&&!f)a(i.concat(s));else if(!r&&f){let g=[...i];g.splice(p,1),a(g)}}else if(St(i)){let p=new Set(i);r?p.add(s):p.delete(s),a(p)}else a(ga(e,r))})},mounted:pa,beforeUpdate(e,t,o){e[zt]=An(o),pa(e,t,o)}};function pa(e,{value:t,oldValue:o},i){e._modelValue=t;let s;if(ge(t))s=Do(t,i.props.value)>-1;else if(St(t))s=t.has(i.props.value);else{if(t===o)return;s=Nt(t,ga(e,!0))}e.checked!==s&&(e.checked=s)}var fn={deep:!0,created(e,{value:t,modifiers:{number:o}},i){e._modelValue=t,nn(e,"change",()=>{let s=Array.prototype.filter.call(e.options,f=>f.selected).map(f=>o?En(vo(f)):vo(f)),r=e.multiple,a=r?St(e._modelValue)?new Set(s):s:s[0],p=e._pendingValue=[r,r?ge(a)?s.slice():s:a];try{e[zt](a)}finally{Ge(()=>{e._pendingValue===p&&(e._pendingValue=void 0)})}}),e[zt]=An(i)},mounted(e,{value:t}){fa(e,t)},beforeUpdate(e,{value:t},o){e._modelValue=t,e[zt]=An(o)},updated(e,{value:t}){let o=e._pendingValue;e._pendingValue=void 0,(!o||o[0]!==e.multiple||!Oc(t,o[1],o[0]))&&fa(e,t)}};function Oc(e,t,o){if(!o)return Nt(e,t);if(ge(e))return Nt(e,t);if(St(e)){if(e.size!==t.length)return!1;for(let i of t)if(!e.has(i))return!1;return!0}return!1}function fa(e,t){let o=e.multiple,i=ge(t);if(!(o&&!i&&!St(t))){for(let s=0,r=e.options.length;s<r;s++){let a=e.options[s],p=vo(a);if(o)if(i){let f=typeof p;f==="string"||f==="number"?a.selected=t.some(g=>String(g)===String(p)):a.selected=Do(t,p)>-1}else a.selected=t.has(p);else if(Nt(vo(a),t)){e.selectedIndex!==s&&(e.selectedIndex=s);return}}!o&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function vo(e){return"_value"in e?e._value:e.value}function ga(e,t){let o=t?"_trueValue":"_falseValue";return o in e?e[o]:t}var Pc=["ctrl","shift","alt","meta"],Ic={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)=>Pc.some(o=>e[`${o}Key`]&&!t.includes(o))},ae=(e,t)=>{if(!e)return e;let o=e._withMods||(e._withMods={}),i=t.join(".");return o[i]||(o[i]=((s,...r)=>{for(let a=0;a<t.length;a++){let p=Ic[t[a]];if(p&&p(s,t))return}return e(s,...r)}))},Mc={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},ct=(e,t)=>{let o=e._withKeys||(e._withKeys={}),i=t.join(".");return o[i]||(o[i]=(s=>{if(!("key"in s))return;let r=Pt(s.key);if(t.some(a=>a===r||Mc[a]===r))return e(s)}))},Vc=je({patchProp:Dc},cc),ma;function qc(){return ma||(ma=Kr(Vc))}var ya=((...e)=>{let t=qc().createApp(...e),{mount:o}=t;return t.mount=i=>{let s=$c(i);if(!s)return;let r=t._component;!ke(r)&&!r.render&&!r.template&&(r.template=s.innerHTML),s.nodeType===1&&(s.textContent="");let a=o(s,!1,Lc(s));return s instanceof Element&&(s.removeAttribute("v-cloak"),s.setAttribute("data-v-app","")),a},t});function Lc(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function $c(e){return $e(e)?document.querySelector(e):e}var vn=typeof document<"u";function wa(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function Uc(e){return e.__esModule||e[Symbol.toStringTag]==="Module"||e.default&&wa(e.default)}var Oe=Object.assign;function ts(e,t){let o={};for(let i in t){let s=t[i];o[i]=Ct(s)?s.map(e):e(s)}return o}var Pn=()=>{},Ct=Array.isArray;function si(e,t){let o={};for(let i in e)o[i]=i in t?t[i]:e[i];return o}var ka=/#/g,Fc=/&/g,Bc=/\//g,zc=/=/g,Hc=/\?/g,Ca=/\+/g,jc=/%5B/g,Gc=/%5D/g,Ea=/%5E/g,Wc=/%60/g,Sa=/%7B/g,Kc=/%7C/g,Na=/%7D/g,Yc=/%20/g;function ii(e){return e==null?"":encodeURI(""+e).replace(Kc,"|").replace(jc,"[").replace(Gc,"]")}function Ra(e){return ii(e).replace(Sa,"{").replace(Na,"}").replace(Ea,"^")}function ni(e){return ii(e).replace(Ca,"%2B").replace(Yc,"+").replace(ka,"%23").replace(Fc,"%26").replace(Wc,"`").replace(Sa,"{").replace(Na,"}").replace(Ea,"^")}function Jc(e){return ni(e).replace(zc,"%3D")}function Qc(e){return iLine truncated
"use strict";(()=>{var va=Object.defineProperty;var ya=e=>{throw TypeError(e)};var ip=(e,t,s)=>t in e?va(e,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):e[t]=s;var rp=(e,t)=>{for(var s in t)va(e,s,{get:t[s],enumerable:!0})};var We=(e,t,s)=>ip(e,typeof t!="symbol"?t+"":t,s),$i=(e,t,s)=>t.has(e)||ya("Cannot "+s);var oe=(e,t,s)=>($i(e,t,"read from private field"),s?s.call(e):t.get(e)),Ie=(e,t,s)=>t.has(e)?ya("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,s),qe=(e,t,s,i)=>($i(e,t,"write to private field"),i?i.call(e,s):t.set(e,s),s),Me=(e,t,s)=>($i(e,t,"access private method"),s);var ba=(e,t,s,i)=>({set _(o){qe(e,t,o,s)},get _(){return oe(e,t,i)}});var ge=["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={markdown:"/script/markdown.6c8dfb7b1d.min.js",org:"/script/org.f61f262915.min.js",notebook:"/script/notebook.c3144c18ae.min.js",editor:"/script/editor.4f142d3adc.min.js",pdf:"/script/pdf.4d9cc6ff49.min.js"};function wa(e){let t=e.location.hash.slice(1);if(e.history.replaceState(null,"","/review-link"),t.length>2048)return null;let s=new URLSearchParams(t);if([...s.keys()].length!==3||[...s.keys()].some(a=>!["clientId","intentId","token"].includes(a)))return null;let i=s.get("clientId"),o=s.get("intentId"),r=s.get("token");return!/^[a-f0-9]{32}$/.test(i||"")||!/^[a-f0-9]{32}$/.test(o||"")||!/^[a-f0-9]{64}$/.test(r||"")?null:{contract:"4open.artifacts/1",clientId:i,intentId:o,token:r}}function ka(e,t){let{http:s,promises:i,window:o}=t,r=t.takeReviewHandoff(),a=r?{clientId:r.clientId,intentId:r.intentId}:null,u,c,m,g,v,h=!0,k,A=i.defer(),w=()=>[...o.crypto.getRandomValues(new Uint8Array(16))].map(q=>q.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:r?"":"Open a new artifact link from your submission. This link is missing or invalid."});let b=()=>h&&e.user?.username===v;function E(){h=!1,r=u=c=void 0,A.resolve(),o.clearTimeout(k)}e.on("dispose",E),e.on("routeLeave",E),e.watch(()=>e.user?.username,q=>{!v&&q?v=q:v&&q!==v&&(E(),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 N=()=>({timeout:A.promise,headers:{"Content-Type":"application/json","X-Review-CSRF":c}}),O=q=>q?.status===404?"Artifact linking is not available on this server.":q?.status===401?"Sign in, then open a new artifact link from your submission.":q?.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(!h||!r||e.busy||e.uncertain||e.saved||!e.user?.username)return;v=e.user.username;let q=e.repositoryId.trim();if(!/^[A-Za-z0-9_-]{3,128}$/.test(q)){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,o.clearTimeout(k),g||(g=w());try{let I=(await s.get("/api/review-consent/csrf",{timeout:A.promise})).data;if(!b())return;if(c=I.csrf,e.handoffEnabled=I.handoffEnabled===!0,!/^[a-f0-9]{64}$/.test(c||""))throw new Error("invalid_csrf");let j=(await s.post("/api/review-consent/preview",{repositoryId:q,intent:{...r,requestId:g}},N())).data;if(!b())return;if(!j||typeof j.ticket!="string"||!j.ticket||j.ticket.length>8192||typeof j.repositoryName!="string"||!["restricted-review","anonymous-link"].iLine truncated
`))),e[on]=bs(o);let r=i||o.props&&o.props.type==="number";Sn(e,t?"change":"input",a=>{a.target.composing||e[on](Er(e.value,s,r))}),(s||r)&&Sn(e,"change",()=>{e.value=Er(e.value,s,r)}),t||(Sn(e,"compositionstart",uh),Sn(e,"compositionend",ad),Sn(e,"change",ad))},mounted(e,{value:t,modifiers:{trim:s,number:i}}){let o=t??"",r=e[pi];delete e[pi],r!==void 0&&(e.type==="text"||e.type==="textarea")&&e.value!==r?e[on](Er(e.value,s,i)):e.value=o},beforeUpdate(e,{value:t,oldValue:s,modifiers:{lazy:i,trim:o,number:r}},a){if(e[on]=bs(a),e.composing)return;let u=(r||e.type==="number")&&!/^0\d/.test(e.value)?cs(e.value):e.value,c=t??"";if(u===c)return;let m=e.getRootNode();(m instanceof Document||m instanceof ShadowRoot)&&m.activeElement===e&&e.type!=="range"&&(i&&t===s||o&&e.value.trim()===c)||(e.value=c)}},Nr={deep:!0,created(e,t,s){e[on]=bs(s),Sn(e,"change",()=>{let i=e._modelValue,o=ho(e),r=e.checked,a=e[on];if(Se(i)){let u=Fo(i,o),c=u!==-1;if(r&&!c)a(i.concat(o));else if(!r&&c){let m=[...i];m.splice(u,1),a(m)}}else if(Ut(i)){let u=new Set(i);r?u.add(o):u.delete(o),a(u)}else a(fd(e,r))})},mounted:ld,beforeUpdate(e,t,s){e[on]=bs(s),ld(e,t,s)}};function ld(e,{value:t,oldValue:s},i){e._modelValue=t;let o;if(Se(t))o=Fo(t,i.props.value)>-1;else if(Ut(t))o=t.has(i.props.value);else{if(t===s)return;o=Ft(t,fd(e,!0))}e.checked!==o&&(e.checked=o)}var Wn={deep:!0,created(e,{value:t,modifiers:{number:s}},i){e._modelValue=t,Sn(e,"change",()=>{let o=Array.prototype.filter.call(e.options,c=>c.selected).map(c=>s?cs(ho(c)):ho(c)),r=e.multiple,a=r?Ut(e._modelValue)?new Set(o):o:o[0],u=e._pendingValue=[r,r?Se(a)?o.slice():o:a];try{e[on](a)}finally{it(()=>{e._pendingValue===u&&(e._pendingValue=void 0)})}}),e[on]=bs(i)},mounted(e,{value:t}){dd(e,t)},beforeUpdate(e,{value:t},s){e._modelValue=t,e[on]=bs(s)},updated(e,{value:t}){let s=e._pendingValue;e._pendingValue=void 0,(!s||s[0]!==e.multiple||!ch(t,s[1],s[0]))&&dd(e,t)}};function ch(e,t,s){if(!s)return Ft(e,t);if(Se(e))return Ft(e,t);if(Ut(e)){if(e.size!==t.length)return!1;for(let i of t)if(!e.has(i))return!1;return!0}return!1}function dd(e,t){let s=e.multiple,i=Se(t);if(!(s&&!i&&!Ut(t))){for(let o=0,r=e.options.length;o<r;o++){let a=e.options[o],u=ho(a);if(s)if(i){let c=typeof u;c==="string"||c==="number"?a.selected=t.some(m=>String(m)===String(u)):a.selected=Fo(t,u)>-1}else a.selected=t.has(u);else if(Ft(ho(a),t)){e.selectedIndex!==o&&(e.selectedIndex=o);return}}!s&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function ho(e){return"_value"in e?e._value:e.value}function fd(e,t){let s=t?"_trueValue":"_falseValue";return s in e?e[s]:t}var ph=["ctrl","shift","alt","meta"],fh={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)=>ph.some(s=>e[`${s}Key`]&&!t.includes(s))},ce=(e,t)=>{if(!e)return e;let s=e._withMods||(e._withMods={}),i=t.join(".");return s[i]||(s[i]=((o,...r)=>{for(let a=0;a<t.length;a++){let u=fh[t[a]];if(u&&u(o,t))return}return e(o,...r)}))},hh={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},Tt=(e,t)=>{let s=e._withKeys||(e._withKeys={}),i=t.join(".");return s[i]||(s[i]=(o=>{if(!("key"in o))return;let r=Yt(o.key);if(t.some(a=>a===r||hh[a]===r))return e(o)}))},mh=ot({patchProp:ah},Gf),ud;function gh(){return ud||(ud=Hl(mh))}var hd=((...e)=>{let t=gh().createApp(...e),{mount:s}=t;return t.mount=i=>{let o=yh(i);if(!o)return;let r=t._component;!Ae(r)&&!r.render&&!r.template&&(r.template=o.innerHTML),o.nodeType===1&&(o.textContent="");let a=s(o,!1,vh(o));return o instanceof Element&&(o.removeAttribute("v-cloak"),o.setAttribute("data-v-app","")),a},t});function vh(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function yh(e){return xe(e)?document.querySelector(e):e}var Xn=typeof document<"u";function gd(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function bh(e){return e.__esModule||e[Symbol.toStringTag]==="Module"||e.default&&gd(e.default)}var je=Object.assign;function hi(e,t){let s={};for(let i in t){let o=t[i];s[i]=Lt(o)?o.map(e):e(o)}return s}var ks=()=>{},Lt=Array.isArray;function Tr(e,t){let s={};for(let i in e)s[i]=i in t?t[i]:e[i];return s}var vd=/#/g,wh=/&/g,kh=/\//g,Ch=/=/g,Eh=/\?/g,yd=/\+/g,Sh=/%5B/g,Nh=/%5D/g,bd=/%5E/g,Rh=/%60/g,wd=/%7B/g,Dh=/%7C/g,kd=/%7D/g,Th=/%20/g;function Ar(e){return e==null?"":encodeURI(""+e).replace(Dh,"|").replace(Sh,"[").replace(Nh,"]")}function Cd(e){return Ar(e).replace(wd,"{").replace(kd,"}").replace(bd,"^")}function Rr(e){return Ar(e).replace(yd,"%2B").replace(Th,"+").replace(vd,"%23").replace(wh,"%26").replace(Rh,"`").replace(wd,"{").replace(kd,"}").replace(bd,"^")}function Ah(e){return Rr(e).replace(Ch,"%3D")}function _h(e){return ALine truncated
${JSON.stringify(e)}${t?`
while being at
`+JSON.stringify(t):""}`},[Be.NAVIGATION_GUARD_REDIRECT]({from:e,to:t}){return`Redirected from "${e.fullPath}" to "${ip(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 hn(e,t){return Oe(new Error,{type:e,[Va]:!0},t)}function Ht(e,t){return e instanceof Error&&Va in e&&(t==null||!!(e.type&t))}var sp=["params","query","hash"];function ip(e){if(typeof e=="string")return e;if(e.path!=null)return e.path;let t={};for(let o of sp)o in e&&(t[o]=e[o]);return JSON.stringify(t,null,2)}function qa(e){let t={};if(e===""||e==="?")return t;let o=(e[0]==="?"?e.slice(1):e).split("&");for(let i=0;i<o.length;++i){let s=o[i].replace(Ca," "),r=s.indexOf("="),a=On(r<0?s:s.slice(0,r)),p=r<0?null:On(s.slice(r+1));if(a in t){let f=t[a];Ct(f)||(f=t[a]=[f]),f.push(p)}else t[a]=p}return t}function ui(e){let t="";for(let o in e){let i=e[o];if(o=Jc(o),i==null){i!==void 0&&(t+=(t.length?"&":"")+o);continue}(Ct(i)?i.map(s=>s&&ni(s)):[i&&ni(i)]).forEach(s=>{s!==void 0&&(t+=(t.length?"&":"")+o,s!=null&&(t+="="+s))})}return t}function La(e){let t={};for(let o in e){let i=e[o];i!==void 0&&(t[o]=Ct(i)?i.map(s=>s==null?null:""+s):i==null?i:""+i)}return t}var $a=Symbol(""),ci=Symbol(""),is=Symbol(""),rs=Symbol(""),as=Symbol("");function In(){let e=[];function t(i){return e.push(i),()=>{let s=e.indexOf(i);s>-1&&e.splice(s,1)}}function o(){e=[]}return{add:t,list:()=>e.slice(),reset:o}}function Xt(e,t,o,i,s,r=a=>a()){let a=i&&(i.enterCallbacks[s]=i.enterCallbacks[s]||[]);return()=>new Promise((p,f)=>{let g=m=>{m===!1?f(hn(Be.NAVIGATION_ABORTED,{from:o,to:t})):m instanceof Error?f(m):op(m)?f(hn(Be.NAVIGATION_GUARD_REDIRECT,{from:t,to:m})):(a&&i.enterCallbacks[s]===a&&typeof m=="function"&&a.push(m),p())},y=r(()=>e.call(i&&i.instances[s],t,o,g)),b=Promise.resolve(y);e.length<3&&(b=b.then(g)),b.catch(m=>f(m))})}function ls(e,t,o,i,s=r=>r()){let r=[];for(let a of e)for(let p in a.components){let f=a.components[p];if(!(t!=="beforeRouteEnter"&&!a.instances[p]))if(wa(f)){let g=(f.__vccOpts||f)[t];g&&r.push(Xt(g,o,i,a,p,s))}else{let g=f();r.push(()=>g.then(y=>{if(!y)throw new Error(`Couldn't resolve component "${p}" at "${a.path}"`);let b=Uc(y)?y.default:y;a.mods[p]=y,a.components[p]=b;let m=(b.__vccOpts||b)[t];return m&&Xt(m,o,i,a,p,s)()}))}}return r}function Ua(e,t){let o=[],i=[],s=[],r=Math.max(t.matched.length,e.matched.length);for(let a=0;a<r;a++){let p=t.matched[a];p&&(e.matched.find(g=>mn(g,p))?i.push(p):o.push(p));let f=e.matched[a];f&&(t.matched.find(g=>mn(g,f))||s.push(f))}return[o,i,s]}var rp=()=>location.protocol+"//"+location.host;function Qa(e,t){let{pathname:o,search:i,hash:s}=t,r=e.indexOf("#");if(r>-1){let a=s.includes(e.slice(r))?e.slice(r).length:1,p=s.slice(a);return p[0]!=="/"&&(p="/"+p),ri(p,"")}return ri(o,e)+i+s}function ap(e,t,o,i){let s=[],r=[],a=null,p=({state:m})=>{let E=Qa(e,location),P=o.value,k=t.value,v=0;if(m){if(o.value=E,t.value=m,a&&a===P){a=null;return}v=k?m.position-k.position:0}else i(E);s.forEach(S=>{S(o.value,P,{delta:v,type:os.pop,direction:v?v>0?ss.forward:ss.back:ss.unknown})})};function f(){a=o.value}function g(m){s.push(m);let E=()=>{let P=s.indexOf(m);P>-1&&s.splice(P,1)};return r.push(E),E}function y(){if(document.visibilityState==="hidden"){let{history:m}=window;if(!m.state)return;m.replaceState(Oe({},m.state,{scroll:go()}),"")}}function b(){for(let m of r)m();r=[],window.removeEventListener("popstate",p),window.removeEventListener("pagehide",y),document.removeEventListener("visibilitychange",y)}return window.addEventListener("popstate",p),window.addEventListener("pagehide",y),document.addEventListener("visibilitychange",y),{pauseListeners:f,listen:g,destroy:b}}function Fa(e,t,o,i=!1,s=!1){return{back:e,current:t,forward:o,replaced:i,position:window.history.length,scroll:s?go():null}}function lp(e){let{history:t,location:o}=window,i={value:Qa(e,o)},s={value:t.state};s.value||r(i.value,{back:null,current:i.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function r(f,g,y){let b=e.indexOf("#"),m=b>-1?(o.host&&document.querySelector("base")?e:e.slice(b))+f:rp()+e+f;try{t[y?"replaceState":"pushState"](g,"",m),s.value=g}catch(E){console.error(E),o[y?"replace":"assign"](m)}}function a(f,g){r(f,Oe({},t.state,Fa(s.value.back,f,s.value.forward,!0),g,{position:s.value.position}),!0),i.value=f}function p(f,g){let y=Oe({},s.value,t.state,{forward:f,scroll:go()});r(y.current,y,!0),r(f,Oe({},Fa(i.value,f,null),{position:y.position+1},g),!1),i.value=f}return{location:i,state:s,push:p,replace:a}}function Xa(e){e=Aa(e);let t=lp(e),o=ap(e,t.state,t.location,t.replace);function i(r,a=!0){a||o.pauseListeners(),history.go(r)}let s=Oe({locatLine truncated
`)),e.options=Object.assign({},e.options,y.options),a.restore()})}p();let f=null;e.saveDefault=g=>{if(g&&g.preventDefault&&g.preventDefault(),e.saving)return;let y=a.checkpoint(),b={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",b).then(()=>{a.accept(y),e.saving=!1,e.message=e.unsavedChanges?null:"Saved",f&&i.cancel(f),f=i(()=>{e.message=null},2500)},m=>{e.saving=!1;let E=m&&m.data&&m.data.error,P="Unable to save your defaults. Please try again.";Promise.all([o("ERRORS."+E),o("ERRORS.unknown_error")]).then(([k,v])=>{e.error=E&&k!==v?k:P},()=>{e.error=P})})},e.deleteAccount=()=>{e.deletingAccount||!e.confirmDeleteAccount||e.deleteUsername!==e.user?.username||(e.deletingAccount=!0,t.delete("/api/user").then(()=>{window.location.href="/"},()=>{e.deletingAccount=!1,e.deleteError="Unable to delete the account. Please try again."}))}},cl=function(e,t,o){e.repoId=null,e.repoUrl=null,e.claim=()=>{t.post("/api/repo/claim",{repoId:e.repoId,repoUrl:e.repoUrl}).then(i=>{o.url("/dashboard")},i=>{e.error=i.data,e.claimForm.repoUrl.setValidity("not_found",!1),e.claimForm.repoId.setValidity("not_found",!1)})}},pl=function(e,t,o,i,s){e.user&&!e.user.status&&o.url("/dashboard"),e.watch("user.status",()=>{e.user&&!e.user.status&&o.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(p){e.feature=p},e.featureHref=function(p){return p.needsUser&&!e.user?"/signin":p.href},e.featureTarget=function(p){return p.needsUser&&!e.user?"_self":p.target||void 0},e.featureKeydown=function(p,f){let g={ArrowDown:1,ArrowRight:1,ArrowUp:-1,ArrowLeft:-1,Home:"first",End:"last"}[p.key];if(g===void 0)return;p.preventDefault();let y=e.features.length,b=g==="first"?0:g==="last"?y-1:(f+g+y)%y;e.feature=e.features[b].key,s(()=>{let m=i.document.getElementById("feature-tab-"+e.feature);m&&m.focus()})},e.demoText=`# DeepLearnUtils
`+JSON.stringify(t):""}`},[nt.NAVIGATION_GUARD_REDIRECT]({from:e,to:t}){return`Redirected from "${e.fullPath}" to "${Uh(t)}" via a navigation guard.`},[nt.NAVIGATION_ABORTED]({from:e,to:t}){return`Navigation aborted from "${e.fullPath}" to "${t.fullPath}" via a navigation guard.`},[nt.NAVIGATION_CANCELLED]({from:e,to:t}){return`Navigation cancelled from "${e.fullPath}" to "${t.fullPath}" with a new navigation.`},[nt.NAVIGATION_DUPLICATED]({from:e,to:t}){return`Avoided redundant navigation to current location: "${e.fullPath}".`}};function Yn(e,t){return je(new Error,{type:e,[Od]:!0},t)}function rn(e,t){return e instanceof Error&&Od in e&&(t==null||!!(e.type&t))}var Lh=["params","query","hash"];function Uh(e){if(typeof e=="string")return e;if(e.path!=null)return e.path;let t={};for(let s of Lh)s in e&&(t[s]=e[s]);return JSON.stringify(t,null,2)}function Pd(e){let t={};if(e===""||e==="?")return t;let s=(e[0]==="?"?e.slice(1):e).split("&");for(let i=0;i<s.length;++i){let o=s[i].replace(yd," "),r=o.indexOf("="),a=ws(r<0?o:o.slice(0,r)),u=r<0?null:ws(o.slice(r+1));if(a in t){let c=t[a];Lt(c)||(c=t[a]=[c]),c.push(u)}else t[a]=u}return t}function Mr(e){let t="";for(let s in e){let i=e[s];if(s=Ah(s),i==null){i!==void 0&&(t+=(t.length?"&":"")+s);continue}(Lt(i)?i.map(o=>o&&Rr(o)):[i&&Rr(i)]).forEach(o=>{o!==void 0&&(t+=(t.length?"&":"")+s,o!=null&&(t+="="+o))})}return t}function Id(e){let t={};for(let s in e){let i=e[s];i!==void 0&&(t[s]=Lt(i)?i.map(o=>o==null?null:""+o):i==null?i:""+i)}return t}var Md=Symbol(""),Vr=Symbol(""),yi=Symbol(""),bi=Symbol(""),wi=Symbol("");function Cs(){let e=[];function t(i){return e.push(i),()=>{let o=e.indexOf(i);o>-1&&e.splice(o,1)}}function s(){e=[]}return{add:t,list:()=>e.slice(),reset:s}}function mn(e,t,s,i,o,r=a=>a()){let a=i&&(i.enterCallbacks[o]=i.enterCallbacks[o]||[]);return()=>new Promise((u,c)=>{let m=h=>{h===!1?c(Yn(nt.NAVIGATION_ABORTED,{from:s,to:t})):h instanceof Error?c(h):$h(h)?c(Yn(nt.NAVIGATION_GUARD_REDIRECT,{from:t,to:h})):(a&&i.enterCallbacks[o]===a&&typeof h=="function"&&a.push(h),u())},g=r(()=>e.call(i&&i.instances[o],t,s,m)),v=Promise.resolve(g);e.length<3&&(v=v.then(m)),v.catch(h=>c(h))})}function ki(e,t,s,i,o=r=>r()){let r=[];for(let a of e)for(let u in a.components){let c=a.components[u];if(!(t!=="beforeRouteEnter"&&!a.instances[u]))if(gd(c)){let m=(c.__vccOpts||c)[t];m&&r.push(mn(m,s,i,a,u,o))}else{let m=c();r.push(()=>m.then(g=>{if(!g)throw new Error(`Couldn't resolve component "${u}" at "${a.path}"`);let v=bh(g)?g.default:g;a.mods[u]=g,a.components[u]=v;let h=(v.__vccOpts||v)[t];return h&&mn(h,s,i,a,u,o)()}))}}return r}function Vd(e,t){let s=[],i=[],o=[],r=Math.max(t.matched.length,e.matched.length);for(let a=0;a<r;a++){let u=t.matched[a];u&&(e.matched.find(m=>Kn(m,u))?i.push(u):s.push(u));let c=e.matched[a];c&&(t.matched.find(m=>Kn(m,c))||o.push(c))}return[s,i,o]}var Fh=()=>location.protocol+"//"+location.host;function Wd(e,t){let{pathname:s,search:i,hash:o}=t,r=e.indexOf("#");if(r>-1){let a=o.includes(e.slice(r))?e.slice(r).length:1,u=o.slice(a);return u[0]!=="/"&&(u="/"+u),_r(u,"")}return _r(s,e)+i+o}function Bh(e,t,s,i){let o=[],r=[],a=null,u=({state:h})=>{let k=Wd(e,location),A=s.value,w=t.value,b=0;if(h){if(s.value=k,t.value=h,a&&a===A){a=null;return}b=w?h.position-w.position:0}else i(k);o.forEach(E=>{E(s.value,A,{delta:b,type:gi.pop,direction:b?b>0?vi.forward:vi.back:vi.unknown})})};function c(){a=s.value}function m(h){o.push(h);let k=()=>{let A=o.indexOf(h);A>-1&&o.splice(A,1)};return r.push(k),k}function g(){if(document.visibilityState==="hidden"){let{history:h}=window;if(!h.state)return;h.replaceState(je({},h.state,{scroll:mo()}),"")}}function v(){for(let h of r)h();r=[],window.removeEventListener("popstate",u),window.removeEventListener("pagehide",g),document.removeEventListener("visibilitychange",g)}return window.addEventListener("popstate",u),window.addEventListener("pagehide",g),document.addEventListener("visibilitychange",g),{pauseListeners:c,listen:m,destroy:v}}function qd(e,t,s,i=!1,o=!1){return{back:e,current:t,forward:s,replaced:i,position:window.history.length,scroll:o?mo():null}}function zh(e){let{history:t,location:s}=window,i={value:Wd(e,s)},o={value:t.state};o.value||r(i.value,{back:null,current:i.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function r(c,m,g){let v=e.indexOf("#"),h=v>-1?(s.host&&document.querySelector("base")?e:e.slice(v))+c:Fh()+e+c;try{t[g?"replaceState":"pushState"](m,"",h),o.value=m}catch(k){console.error(k),s[g?"replace":"assign"](h)}}function a(c,m){r(c,je({},t.state,qd(o.value.back,c,o.value.forward,!0),m,{position:o.value.position}),!0),i.value=c}function u(c,m){let g=je({},o.value,t.state,{forward:c,scroll:mo()});r(g.current,g,!0),r(c,je({},qd(i.value,c,null),{position:g.position+1},m),!1),i.value=c}return{location:i,state:o,push:u,replace:a}}function Kd(e){e=Rd(e);let t=zh(e),s=Bh(e,t.state,t.location,t.replace);function i(r,a=!0){a||s.pauseListeners(),history.go(r)}let o=je({locatLine truncated
`)},Kr=class{constructor(t){We(this,"gen");We(this,"threads",[]);We(this,"match",!1);We(this,"runs",[]);We(this,"ids",[]);this.gen=t}get dead(){return!this.threads.length&&!this.match&&!this.runs.length}},fu=(e,t)=>e.ids.length!==t.ids.length||e.runs.length!==t.runs.length||e.ids.some((s,i)=>s!==t.ids[i])?!1:e.runs.every(s=>t.runs.some(i=>i.neg===s.neg&&fu(i.state,s.state))),ru=e=>({has:new Float64Array(e),seen:new Float64Array(e),gen:0}),Zn,_n,Yr,Xr,bo=class{constructor(t,s,i){Ie(this,_n);We(this,"dots");We(this,"dotStart");Ie(this,Zn);this.dots=t,this.dotStart=s,qe(this,Zn,i)}state(){return new Kr(++oe(this,Zn).gen)}done(t){return t.ids=t.threads.map(s=>s.id).sort((s,i)=>s-i),t.match&&t.ids.unshift(Wr.id),t}restricted(t,s){return s&&(this.dots||this.dotStart&&t===0)}add(t,s,i,o){switch(s.t){case"split":if(!Me(this,_n,Yr).call(this,t,s))return;for(let a of s.out)this.add(t,a,i,o);return;case"neg":if(!Me(this,_n,Yr).call(this,t,s))return;let r=this.state();return this.add(r,s.sub,i,!1),this.done(r),this.addRun(t,{t:"run",neg:s,state:r},i,o);case"star":if(this.restricted(i,o))return;Me(this,_n,Xr).call(this,t,s)&&this.add(t,s.next,i,o);return;case"match":t.match=!0;return;default:Me(this,_n,Xr).call(this,t,s)}}addRun(t,s,i,o){for(let r of t.runs)if(r.neg===s.neg&&fu(r.state,s.state))return;t.runs.push(s),s.state.match||this.add(t,s.neg.next,i,o)}step(t,s,i,o){let r=this.state();for(let a of t.threads)switch(a.t){case"lit":Zr(a,s)&&this.add(r,a.next,i+1,o);break;case"any":this.restricted(i,o)||this.add(r,a.next,i+1,o);break;case"class":!this.restricted(i,o)&&a.re.test(s)&&this.add(r,a.next,i+1,o);break;case"star":this.restricted(i,o)||this.add(r,a,i+1,o)}if(!this.restricted(i,o))for(let a of t.runs){if(a.state.dead){this.addRun(r,a,i+1,o);continue}let u=this.step(a.state,s,i,!1);this.addRun(r,{t:"run",neg:a.neg,state:u},i+1,o)}return this.done(r)}};Zn=new WeakMap,_n=new WeakSet,Yr=function(t,s){let{seen:i}=oe(this,Zn);return i[s.id]===t.gen?!1:(i[s.id]=t.gen,!0)},Xr=function(t,s){let{has:i}=oe(this,Zn);return i[s.id]===t.gen?!1:(i[s.id]=t.gen,t.threads.push(s),!0)};var hu=e=>{let t=e.ids.join();if(!e.runs.length)return t;let s=e.runs.map(i=>`${i.neg.id}(${hu(i.state)})`);return`${t}|${s.sort().join("|")}`},Um=1<<18,Es,Ss,Nn,xn,Rn,Dn,Tn,Kt,Qr,Ri,mu,Jr=class{constructor(t,s){Ie(this,Kt);Ie(this,Es);Ie(this,Ss,new Map);Ie(this,Nn,0);Ie(this,xn);Ie(this,Rn);Ie(this,Dn);Ie(this,Tn);qe(this,Es,t),qe(this,Dn,new bo(!1,!1,s)),qe(this,Tn,new bo(!1,!0,s))}start(t){if(t){if(oe(this,Rn))return oe(this,Rn);let i=oe(this,Tn).state();return oe(this,Tn).add(i,oe(this,Es),0,!0),qe(this,Rn,Me(this,Kt,Qr).call(this,oe(this,Tn).done(i)))}if(oe(this,xn))return oe(this,xn);let s=oe(this,Dn).state();return oe(this,Dn).add(s,oe(this,Es),0,!0),qe(this,xn,Me(this,Kt,Ri).call(this,oe(this,Dn).done(s)))}next(t,s){let i=s.charCodeAt(0),o=i<128?void 0:t.next.get(s);if(o)return o;let r=t===oe(this,Rn)?Me(this,Kt,Ri).call(this,oe(this,Tn).step(t.state,s,0,!0)):Me(this,Kt,Ri).call(this,oe(this,Dn).step(t.state,s,1,!0));return i<128?(t.ascii||(t.ascii=new Array(128),qe(this,Nn,oe(this,Nn)+128)),t.ascii[i]=r):t.next.set(s,r),ba(this,Nn)._++,r}};Es=new WeakMap,Ss=new WeakMap,Nn=new WeakMap,xn=new WeakMap,Rn=new WeakMap,Dn=new WeakMap,Tn=new WeakMap,Kt=new WeakSet,Qr=function(t){return{state:t,match:t.match,dead:t.dead,next:new Map}},Ri=function(t){let s=hu(t),i=oe(this,Ss).get(s);if(i)return i;oe(this,Nn)>Um&&Me(this,Kt,mu).call(this);let o=Me(this,Kt,Qr).call(this,t);return oe(this,Ss).set(s,o),qe(this,Nn,oe(this,Nn)+(s.length+1)),o},mu=function(){oe(this,Ss).clear(),qe(this,Nn,0),qe(this,xn,void 0),qe(this,Rn,void 0)};var Fm=e=>{let t=[];for(let s=e;s.t!=="match";s=s.next){if(s.t==="split"||s.t==="neg")return;t.push(s)}return t},Bm=(e,t,s,i)=>{let o=0,r=s,a=-1,u=0;for(;r<i;){let c=e[o];if(c?.t==="star"){a=o++,u=r;continue}let m=t[r];if(c&&(c.t==="any"||c.t==="lit"&&Zr(c,m)||c.t==="class"&&c.re.test(m))){o++,r++;continue}if(a===-1)return!1;o=a+1,r=++u}for(;e[o]?.t==="star";)o++;return o===e.length},gu=e=>{let t=0,s=0;for(let i of e){let[o,r]=zm(i);t+=o,s+=r}return[t,s]},zm=e=>{if(e.t==="star")return[0,1/0];if(e.t!=="ext")return[1,1];if(e.type==="!")return[0,1/0];let t=e.alts.map(gu),s=Math.min(...t.map(r=>r[0])),i=Math.max(...t.map(r=>r[1])),o=i===0?0:1/0;return e.type==="@"?[s,i]:e.type==="?"?[0,i]:e.type==="*"?[0,o]:[s,o]},au=(e,t,s)=>{for(let i=0;i<e.length;i++)if(!Zr(e[i],t[s+i]))return!1;return!0},Hm=/[/\ud800-\udfff]/,jm=/[\ud800-\udfff]/,Ni=e=>jm.test(e)?[...e]:e,lu=e=>{if(e.includes("/"))throw new Error("can only match a single path portion, got: "+e)},An,Ns,es,Di,ts,ko,Ti,ns,Co,Eo,So,yn,an,Rs,Ds,No,Ai,Wt,ss,yo,wo=class{constructor(t,s={}){Ie(this,ss);We(this,"pattern");We(this,"options");Ie(this,An);Ie(this,Ns);Ie(this,es);Ie(this,Di);Ie(this,ts);Ie(this,ko,!1);Ie(this,Ti);Ie(this,ns);Ie(this,Co,!1);Ie(this,Eo,0);Ie(this,So,1/0);Ie(this,yn,[]);Ie(this,an,[]);Ie(this,Rs);Ie(this,Ds);Ie(this,No,!1);Ie(this,Ai);Ie(this,Wt);if(t.includes Line truncated
`).forEach((s,i)=>{let{term:o}=ua(s.trim());if(!o)return;let r=[];for(let a=0;a<o.length;a++){if(o[a]==="\\"){a++;continue}Iu.has(o[a])&&!r.includes(o[a])&&r.push(o[a])}r.length&&t.push({line:i,term:o,symbols:r})}),t}function Vu(e,t){let s=String(e||"").split(`
`),i=s[t];if(i===void 0)return e;let{term:o}=ua(i.trim());if(!o)return e;let r="";for(let u=0;u<o.length;u++){if(o[u]==="\\"){r+=o.slice(u,u+2),u++;continue}r+=Iu.has(o[u])||o[u]==="."?"\\"+o[u]:o[u]}let a=i.indexOf(o);return s[t]=i.slice(0,a)+r+i.slice(a+o.length),s.join(`
`)}var Oo={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.",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:"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.",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:"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.",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 is invalid; expected the form 'owner/name'.",repoId_not_defined:"A repository ID must be provided.",repoUrl_not_defined:"The repository URL needs to be defined.",source_not_provided:"A repository source must be provided.",github_rate_limit_exceeded:"GitHub temporarily blocked the request because we hit its API rate limit. Wait a few minutes and try again. If the problem persists and you contact GitHub Support, include the request ID and timestamp shown in GitHub's response (the 'X-GitHub-Request-Id' header).",rate_limited:"GitHub API rate limit reached. The repository will be available shortly \u2014 please wait a moment and refresh.",repoId_already_used:"The repository ID is already used.",invalid_repoId:"The format of the repository ID is invalid.",unsupported_source:"The repository source type is not supported.",branch_not_specified:"The branch is not specified.",branch_not_found:"The branch of the repository cannot be found.",commit_not_specified:"A commit must be specified.",commit_not_found:"The configured commit no longer exists in the source repository. It may have been force-pushed, rebased, or removed.",repo_renamed:"The source repository appears to have been renamed or moved on GitHub. Please refresh and try again \u2014 the cached name has been updated.",invalid_commit_format:"The commit hash format is invalid. It must be a hexadecimal string.",pull_request_not_found:"The requested pull request could not be found.",pull_request_expired:"This pull request has expired and is no longer available.",pull_request_not_ready:"This pull request is still being prepared. Please t Line truncated
`)),e.options=Object.assign({},e.options,g.options),a.restore()})}u();let c=null;e.saveDefault=m=>{if(m&&m.preventDefault&&m.preventDefault(),e.saving)return;let g=a.checkpoint(),v={terms:e.terms.split(`
`).map(h=>h.trim()).filter(h=>h.length>0),options:e.options};e.saving=!0,e.error=null,t.post("/api/user/default",v).then(()=>{a.accept(g),e.saving=!1,e.message=e.unsavedChanges?null:"Saved",c&&i.cancel(c),c=i(()=>{e.message=null},2500)},h=>{e.saving=!1;let k=h&&h.data&&h.data.error,A="Unable to save your defaults. Please try again.";Promise.all([s("ERRORS."+k),s("ERRORS.unknown_error")]).then(([w,b])=>{e.error=k&&w!==b?w:A},()=>{e.error=A})})},e.deleteAccount=()=>{e.deletingAccount||!e.confirmDeleteAccount||e.deleteUsername!==e.user?.username||(e.deletingAccount=!0,t.delete("/api/user").then(()=>{window.location.href="/"},()=>{e.deletingAccount=!1,e.deleteError="Unable to delete the account. Please try again."}))}},ju=function(e,t,s){e.repoId=null,e.repoUrl=null,e.claim=()=>{t.post("/api/repo/claim",{repoId:e.repoId,repoUrl:e.repoUrl}).then(i=>{s.url("/dashboard")},i=>{e.error=i.data,e.claimForm.repoUrl.setValidity("not_found",!1),e.claimForm.repoId.setValidity("not_found",!1)})}},Gu=function(e,t,s,i,o){e.user&&!e.user.status&&s.url("/dashboard"),e.watch("user.status",()=>{e.user&&!e.user.status&&s.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,c){let m={ArrowDown:1,ArrowRight:1,ArrowUp:-1,ArrowLeft:-1,Home:"first",End:"last"}[u.key];if(m===void 0)return;u.preventDefault();let g=e.features.length,v=m==="first"?0:m==="last"?g-1:(c+m+g)%g;e.feature=e.features[v].key,o(()=>{let h=i.document.getElementById("feature-tab-"+e.feature);h&&h.focus()})},e.demoText=`# DeepLearnUtils
Developed by Jane Smith at MIT CSAIL.
See Smith et al., "Attention That Works," 2026.
Contact: jane.smith@mit.edu`,e.demoTerms="Jane Smith, Smith, MIT CSAIL, jane.smith@mit.edu",e.demoParts=function(){let p=(e.demoTerms||"").split(/[,\n]/).map(m=>m.trim()).filter(Boolean).sort((m,E)=>E.length-m.length),f=m=>m.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");if(!p.length)return[{text:e.demoText}];let g=new RegExp("("+p.map(f).join("|")+")","gi"),y={},b=0;return(e.demoText||"").split(g).filter(m=>m!=="").map(m=>{let E=p.find(P=>P.toLowerCase()===m.toLowerCase());return E?(y[E.toLowerCase()]||(y[E.toLowerCase()]=++b),{text:String(y[E.toLowerCase()]),redacted:!0,original:m}):{text:m}})},e.demoCount=()=>e.demoParts().filter(p=>p.redacted).length,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 r(){t.get("/api/stat/").then(p=>{e.stat=p.data,e.cards[0].total=p.data.nbRepositories,e.cards[1].total=p.data.nbUsers,e.cards[2].total=p.data.nbPageViews,e.cards[3].total=p.data.nbPullRequests}).catch(()=>{})}r();function a(p){let f={series:p,bars:[],viewW:100,deltaToday:0,pctChange:0,pctAbs:0,isUp:!0};if(!p||p.length<2)return f;let g=new Array(p.length-1);for(let k=1;k<p.length;k++)g[k-1]=p[k]-p[k-1];let y=g.length,b=Math.max.apply(null,g),m=Math.min.apply(null,g),E=Math.min(0,m),P=b-E||1;f.viewW=y*2,f.bars=new Array(y);for(let k=0;k<y;k++){let v=(g[k]-E)/P,S=Math.max(1.5,v*34);f.bars[k]={x:(k*2+.25).toFixed(2),y:(36-S).toFixed(2),w:"1.5",h:S.toFixed(2)}}if(f.deltaToday=g[y-1],y>=2){let k=g[y-2];k&&(f.pctChange=(f.deltaToday-k)/k*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(p=>{let f=p.data||[];e.history={repositories:a(f.map(g=>g.nbRepositories||0)),users:a(f.map(g=>g.nbUsers||0)),pageViews:a(f.map(g=>g.nbPageViews||0)),pullRequests:a(f.map(g=>g.nbPullRequests||0))}}).catch(()=>{})},fl=function(e,t,o,i,s,r){let a=pt();e.on("routeLeave",function(){$('[data-toggle="tooltip"]').tooltip("dispose")}),e.watch("user.status",()=>{e.user==null&&o.url("/")}),e.user==null&&o.url("/"),a.timeout(()=>{$('[data-toggle="tooltip"]').tooltip()},250),e.quotaExpanded=!1,e.closeQuota=()=>{e.quotaExpanded=!1,Ge(()=>document.querySelector(".dashboard-quota > summary")?.focus())},xt()(document,"click",R=>{e.quotaExpanded&&!R.target.closest?.(".dashboard-quota")&&(e.quotaExpanded=!1)}),e.filtersExpanded=!1,e.projectView="all",e.selectedProject=null,e.projectName="",e.nameSaving=!1,e.nameError="",e.nameMessage="",e.needsAttention=R=>R.status==="error"||R._broken||f(R.status)==="progress"&&R._stale,e.attentionCount=()=>e.dashboardTotals?.attention??e.items.filter(e.needsAttention).length,e.hasProjects=()=>(e.dashboardTotals?.total??e.items.length)>0,e.setProjectView=R=>{e.projectView=R,R==="attention"&&(e.filters.status.error=!0,e.filters.status.progress=!0)},e.projectDetailsId=R=>"project-details-"+encodeURIComponent(R._type+":"+(R._id||R._source||"unknown")),e.showProjectDetails=async R=>{e.selectedProject=R,e.projectName=R.projectName||"",e.nameError="",e.nameMessage="",await Ge();let K=document.getElementById(e.projectDetailsId(R));K?.focus(),K?.scrollIntoView?.({block:"nearest"})},e.closeProjectDetails=R=>{e.selectedProject=null,Ge(()=>document.querySelector(`[data-project-actions="${encodeURIComponent(R._type+":"+R._id)}"]`)?.focus())},e.saveProjectName=async R=>{if(e.nameSaving||!R._id)return;let K=e.projectName.trim();if(K.length>100){e.nameError="Use 100 characters or fewer.";return}e.nameSaving=!0,e.nameError="",e.nameMessage="";try{let te=await t.post("/api/user/project-name",{type:R._type,id:R._id,name:K});R.projectName=te.data.name,R._label=R.projectName||R._fallbackLabel,e.selectedProject===R&&(e.nameMessage=K?"Project name saved.":"Default project name restored."),_||(e.dashboardCursor=null,await L(),e.selectedProject===R&&(e.selectedProject=e.items.find(ve=>ve._type===R._type&&ve._id===R._id)||null))}catch{e.selectedProject===R&&(e.nameError="The project name could not be saved. Try again.")}finally{e.nameSaving=!1}},e.copyingId=null,e.copyLink=async R=>{if(!R._viewUrl||e.copyingId)return;let K=new URL(R._viewUrl,s.location.origin).href;e.copyingId=R._type+":"+R._id;try{await al(K),e.addToast({title:"Link copied",body:"The anonymous link is ready to share."})}catch{e.addToast({title:"Copy this anonymous link",body:K})}finally{e.copyingId=null}},e.items=[],e.search="",e.loading=!0,e.statusKeyLabels={ready:"Ready",progress:"In progress",error:"Error",expired:"Expired",removed:"Removed"};let p=["queue","download","downloaded","preparing","anonymizing"];function f(R){return R==="ready"||R==="error"?R:R==="expired"||R==="expiring"?"expired":R==="removed"||R==="removing"?"removed":(p.indexOf(R)>-1,"progress")}let g=7200*1e3,y="dashboard.filterPrefs",b={typeFilter:"all",filters:{status:{ready:!0,progress:!0,error:!0,e Line truncated
`)),e.options=Object.assign({},e.options,D.options),e.options.expirationDate=D.options&&D.options.expirationDate?new Date(D.options.expirationDate):G(),!i.repoId&&!i.pullRequestId&&!i.gistId&&!e.anonymize?.terms?.dirty&&(e.terms=e.defaultTerms),w&&w()})}function x(w,A,D){e.anonymize&&e.anonymize[w]&&e.anonymize[w].setValidity(A,D)}function ue(w){try{let A=parseGithubUrl(w);if(A&&A.owner&&A.repo)return A.owner+"/"+A.repo}catch{}return null}e.accessRepairAllowed=!1,e.repairingGitHubAccess=!1,e.accessRepairMessage="",e.repairGitHubAccess=async()=>{if(!e.accessRepairAllowed||e.repairingGitHubAccess||!e.githubConnections?.appEnabled||!i.repoId||e.role!=="owner"||e.githubConnection!=="github-app"||ue(e.sourceUrl)!==e._originalFullName)return;e.repairingGitHubAccess=!0,e.accessRepairMessage="";let w=m();try{let A=await t.get("/github/connections");if(e.githubConnections=A.data,!A.data.appEnabled)return;let D=await t.post("/github/connections/migrate",{type:"repository",id:i.repoId,connection:"github-app"},{headers:{"X-CSRF-Token":A.data.csrf}});if(!b(w))return;e.error=null,D.data.fullName&&(e._originalFullName=D.data.fullName,e.source.fullName=D.data.fullName,e.sourceUrl="https://github.com/"+D.data.fullName),e.accessRepairMessage="GitHub access repaired. Your anonymous URL and published commit are unchanged.",await e.urlSelected(!0)}catch{b(w)&&(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(w)}},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 be()}catch{}}};function he(){return e.reconnectingSource||!e.isUpdate||!e._originalRepositoryID?void 0:ue(e.sourceUrl)===e._originalFullName?e._originalRepositoryID:void 0}async function Ee(){e._preservingDraft=!0;try{await e.urlSelected(!0)}finally{e._preservingDraft=!1}}async function ye(){let w=new URLSearchParams(window.location.search).get("billingDraft");if(w){v.restore();try{let D=(await t.get("/api/billing/draft/"+encodeURIComponent(w))).data;if(D.path!==s.path())throw new Error("Wrong task");S=D.values.conference||null;for(let I of["sourceUrl","terms","repoId","source","options","conference","githubConnection"])Object.prototype.hasOwnProperty.call(D.values,I)&&(e[I]=D.values[I]);return e.options?.expirationDate&&(e.options.expirationDate=new Date(e.options.expirationDate)),_=D.id,M=JSON.stringify(v.checkpoint()),e.draftRestored=!0,e.hostingReview=!0,e.sourceUrl&&await Ee(),s.replace?.(s.path()),!0}catch{e.billingError="The checkout draft could not be restored. Retry by reloading this page; any local draft is still available."}}let A;try{A=JSON.parse(sessionStorage.getItem("github-access-draft")||"null")}catch{return!1}if(!A||A.path!==s.path()||Date.now()-A.savedAt>=30*6e4)return v.restore()?(e.sourceUrl&&await Ee(),!0):!1;v.restore();for(let D of["sourceUrl","terms","repoId","pullRequestId","gistId","source","options","conference","githubConnection"])Object.prototype.hasOwnProperty.call(A.draft,D)&&(e[D]=A.draft[D]);return e.options.expirationDate&&(e.options.expirationDate=new Date(e.options.expirationDate)),await Ee(),sessionStorage.removeItem("github-access-draft"),!0}ve(()=>{!i.repoId&&!i.pullRequestId&&!i.gistId&&a(ye,0),i.repoId&&i.repoId!=""&&(e.isUpdate=!0,e.detectedType="repo",e.repoId=i.repoId,t.get("/api/repo/"+e.repoId).then(async w=>{e.accessRepairAllowed=!["removed","archived","preparing","queue","download","removing","expiring"].includes(w.data.status),e.githubConnection=w.data.connection||"oauth",e.sourceUrl="https://github.com/"+w.data.source.fullName,e._originalFullName=w.data.source.fullName,e.terms=w.data.options.terms.filter(A=>A).join(`
`),e.source=w.data.source,e.role=w.data.role||"owner",e._existingNever=w.data.options.expirationMode==="never",e.coauthors=w.data.coauthors||[],e._originalBranch=w.data.source.branch,e.options=Object.assign({},e.options,w.data.options),e.conference=w.data.conference,e._originalConference=w.data.conference,e.repositoryID=w.data.source.repositoryID,e._originalRepositoryID=w.data.source.repositoryID,w.data.options.expirationDate&&(e.options.expirationDate=new Date(w.data.options.expirationDate)),P=k(parseGithubUrl(e.sourceUrl)),!await ye()&&(await Promise.all([be(),Le()]),F())},()=>{s.url("/404")})),i.pullRequestId&&i.pullRequestId!=""&&(e.isUpdate=!0,e.detectedType="pr",e.pullRequestId=i.pullRequestId,t.get("/api/pr/"+e.pullRequestId).then(async w=>{if(e.githubConnection=w.data.connection||"oauth",e.sourceUrl="https://github.com/"+w.data.source.repositoryFullName+"/pull/"+w.data.source.pullRequestId,e.terms=w.data.options.terms.filter(A=>A).join(`
`),e.source=w.data.source,e.options=Object.assign({},e.options,w.data.options),e.conference=w.data.conference,e._originalConference=w.data.conference,w.data.options.expirationDate&&(e.options.expirationDate=new Date(w.data.options.expirationDate)),P=k(parseGithubUrl(e.sourceUrl)),!await ye())try{await X()}catch{}},()=>{s.url("/404")})),i.gistId&&i.gistId!=""&&(e.isUpdate=!0,e.detectedType="gist",e.gistId=i.gistId,t.get("/api/gist/"+e.gistId).then(async w=>{e.sourceUrl="https://gist.github.com/"+w.data.source.gistId,e.terms=w.data.options.terms.filter(A=>A).join(`
`),e.source=w.data.source,e.options=Object.assign({},e.options,w.data.options),e.conference=w.data.conference,e._originalConference=w.data.conference,w.data.options.expirationDate&&(e.options.expirationDate=new Date(w.data.options.expirationDate)),P=k(parseGithubUrl(e.sourceUrl)),!await ye()&&await Q()},()=>{s.url("/404")}))}),t.get("/github/connections").then(w=>{e.githubConnections=w.data,!i.repoId&&!i.pullRequestId&&!i.gistId&&e.githubConnection===void 0&&w.data.appEnabled&&w.data.appConnected&&(e.githubConnection="github-app",e.sourceUrl&&e.workspaceOpen&&Ee())}).catch(()=>{}),e.urlSelected=async(w=!1)=>{let A=++f;e.previousConfigurations=[],e.previousConfigurationId="";let D;try{D=parseGithubUrl(e.sourceUrl.trim())}catch{e.sourceLoading=!1,Me.cancel(),U.cancel(),de.cancel(),e.previewStatus="idle",e.sourceUrlError=e.sourceUrl?"Please provide a valid GitHub URL.":"",x("sourceUrl","github",!1);return}let I=k(D),z=w||P===I;P=I,e.sourceUrlError="",x("sourceUrl","github",!0);let B=document.activeElement?.id==="sourceUrl-landing";e.workspaceOpen=!0,setTimeout(()=>{let ie=window.document.getElementById("sourceUrl");if(ie){try{ie.setSelectionRange(0,0)}catch{}ie.scrollLeft=0}},50),B&&a(()=>document.getElementById("sourceUrl")?.focus(),0),e.reconnectingSource=!1,e.reconnectRepositoryId=void 0,!z&&!e.isUpdate&&(e.repoId="",e.pullRequestId="",e.gistId=""),e.details=null,e.branches=[],z||(e.source={type:"GitHubStream",branch:"",commit:""}),Me.cancel(),U.cancel(),de.cancel(),J.clear(),H.clear(),e.previewStatus="idle",e.anonymize_readme="",e.readme="",e.html_readme="",e.detectedType=null,e.gistOAuthRequired=!1,e.gistAppRequired=!1,e._preservingDraft=z;try{D.gistId&&!D.repo?(e.detectedType="gist",e.source={gistId:D.gistId},await Q()):D.pullRequestId?(e.detectedType="pr",e.source={repositoryFullName:D.owner+"/"+D.repo,pullRequestId:D.pullRequestId},await X()):(e.detectedType="repo",te(),await Promise.all([be(),Le()]),F())}catch{}finally{A===f&&(e._preservingDraft=!1)}$('[data-toggle="tooltip"]').tooltip()},$('[data-toggle="tooltip"]').tooltip(),e.watch("source.branch",async()=>{if(e.detectedType!=="repo")return;let w=e.branches.filter(D=>D.name==e.source.branch)[0];if(!w)return;!(!e.reconnectingSource&&e.isUpdate&&e._originalBranch===e.source.branch&&e.source.commit)&&!(e._preservingDraft&&e.source.commit)&&(e.source.commit=w.commit),e.readme=w.readme,await Le(),F()}),e.getBranches=async w=>{let A=parseGithubUrl(e.sourceUrl),D=m();try{let I=await t.get(`/api/repo/${A.owner}/${A.repo}/branches`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&i.repoId&&ue(e.sourceUrl)===e._originalFullName?i.repoId:void 0,connection:e.githubConnection,force:w===!0||e.reconnectingSource?"1":"0",repositoryID:he()}});if(!b(D))return;e.branches=I.data,e.sourceUnreachable=!1,e.source.branch||(e.source.branch=e.details.defaultBranch);let z=e.branches.filter(B=>B.name==e.source.branch);z.length>0&&(!(!e.reconnectingSource&&!w&&e.isUpdate&&!e.options.update&&e._originalBranch===e.source.branch&&e.source.commit)&&!(e._preservingDraft&&e.source.commit)&&(e.source.commit=z[0].commit),e.readme=z[0].readme,await Le(w))}catch(I){if(!b(D))return;e.branches=[],e.sourceUnreachable=I&&(I.status===404||I.data&&I.data.error==="repo_not_found");let z=I&&I.data&&I.data.error||(I&&I.status===404?"repo_not_found":"unknown_error");r("ERRORS."+z).then(B=>{e.toasts=e.toasts||[],e.addToast({title:"Error",date:new Date,body:B}),e.error=B},console.error),typeof x=="function"&&x("sourceUrl","missing",!1)}finally{E(D)}};async function be(){let w=parseGithubUrl(e.sourceUrl),A=m();try{N();let D=await t.get(`/api/repo/${w.owner}/${w.repo}/`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&i.repoId&&ue(e.sourceUrl)===e._originalFullName?i.repoId:void 0,connection:e.githubConnection,repositoryID:he(),force:"1"}});if(!b(A))return;e.details=D.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(D){if(!b(A))return;throw D.data&&(r("ERRORS."+D.data.error).then(I=>{e.addToast({title:"Error",date:new Date,body:I}),e.error=I},console.error),j(D.data.error)),x("sourceUrl","missing",!1),D}finally{E(A)}}async function Le(w){if(e.readme&&!w)return e.readme;let A=parseGithubUrl(e.sourceUrl),D=m();try{let I=await t.get(`/api/repo/${A.owner}/${A.repo}/readme`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&i.repoId&&ue(e.sourceUrl)===e._originalFullName?i.repoId:void 0,connection:e.githubConnection,force:w===!0?"1":"0",branch:e.source.branch,repositoryID:he()}});b(D,!0)&&(e.readme=I.data)}catch{b(D,!0)&&(e.readme="")}finally{E(D)}}function ze(){let w={terms:e.terms?e.terms.split(`
`):[],image:!!e.options.image,link:!!e.options.link,repoId:e.repoId};e.source&&e.source.branch&&(w.branchName=e.source.branch);try{let A=parseGithubUrl(e.sourceUrl);w.repoName=`${A.owner}/${A.repo}`}catch{}return w}function He(w,A,D){let I=null,z=0,B=()=>{if(e.detectedType!==w)return;I&&a.cancel(I);let ie=++z;e.previewStatus="loading",I=a(()=>{I=null;let Z=A();if(!Z){e.previewStatus="idle";return}t.post("/api/anonymize-preview",Z).then(le=>{ie===z&&(D(le.data,Z),e.previewStatus="ready")}).catch(()=>{ie===z&&(e.previewStatus="error")})},200)};return B.cancel=()=>{z++,I&&a.cancel(I),I=null},e.on("dispose",B.cancel),B}e.retryPreview=()=>{e.detectedType==="repo"&&Me(),e.detectedType==="pr"&&U(),e.detectedType==="gist"&&de()};let Me=He("repo",()=>e.readme?{content:e.readme,options:ze()}:null,w=>{if(typeof w?.content!="string")throw Error("Invalid preview response");e.anonymize_readme=w.content;let A="";try{let I=parseGithubUrl(e.sourceUrl),z=e.source.branch||e.details&&e.details.defaultBranch||"main";A=`https://github.com/${I.owner}/${I.repo}/raw/${z}/`}catch{}let D=renderMD(e.anonymize_readme,A);e.html_readme=D,a(Prism.highlightAll,150)});function F(){!e.anonymize||!e.anonymize.terms||(e.termsRegexWarning=!!e.terms&&!!e.terms.match(/[-[\]{}()*+?.,\\^$|#]/g),Me())}async function X(){let w=parseGithubUrl(e.sourceUrl),A=m();try{N();let D=await t.get(`/api/pr/${w.owner}/${w.repo}/${w.pullRequestId}`,{params:{connection:e.githubConnection}});if(!b(A))return;e.details=D.data,e.pullRequestId||(e.pullRequestId=w.repo+"-PR"+w.pullRequestId+"-"+generateRandomId(4))}catch(D){if(!b(A))return;throw D.data&&(r("ERRORS."+D.data.error).then(I=>{e.addToast({title:"Error",date:new Date,body:I}),e.error=I},console.error),j(D.data.error)),x("sourceUrl","missing",!1),D}finally{E(A)}}let J=Ue(new Map);function ne(){let w=new Set,A=e.details&&e.details.pullRequest;if(!A)return w;typeof A.title=="string"&&w.add(A.title),typeof A.body=="string"&&w.add(A.body),typeof A.diff=="string"&&w.add(A.diff);let D=A.comments||[];for(let I of D)typeof I.author=="string"&&w.add(I.author),typeof I.body=="string"&&w.add(I.body);return w}let U=He("pr",()=>{let w=ne(),A=Array.from(w);return A.length===0?null:{contents:A,options:ze()}},(w,A)=>{if(!Array.isArray(w?.contents)||w.contents.length!==A.contents.length||w.contents.some(z=>typeof z!="string"))throw Error("Invalid preview response");let D=A.contents,I=new Map;for(let z=0;z<D.length&&z<w.contents.length;z++)I.set(D[z],w.contents[z]);J.clear(),I.forEach((z,B)=>J.set(B,z))});e.anonymizePrContent=function(w){return w&&(J.has(w)?J.get(w):"")};async function Q(){let w=parseGithubUrl(e.sourceUrl),A=m();try{N(),e.gistOAuthRequired=!1,e.gistAppRequired=!1;let D=await t.get(`/api/gist/source/${w.gistId}`);if(!b(A))return;e.details=D.data,e.gistId||(e.gistId="gist-"+w.gistId.substring(0,6)+"-"+generateRandomId(4))}catch(D){if(!b(A))return;if(D.data?.error==="github_app_reconnect_required"){e.gistAppRequired=!0,x("sourceUrl","missing",!1);return}if(D.data?.error==="github_oauth_required"){e.gistOAuthRequired=!0,x("sourceUrl","missing",!1);return}throw D.data&&(r("ERRORS."+D.data.error).then(I=>{e.addToast({title:"Error",date:new Date,body:I}),e.error=I},console.error),j(D.data.error)),x("sourceUrl","missing",!1),D}finally{E(A)}}let H=Ue(new Map);function re(){let w=new Set,A=e.details&&e.details.gist;if(!A)return w;typeof A.description=="string"&&w.add(A.description),typeof A.ownerLogin=="string"&&w.add(A.ownerLogin);let D=A.files||[];for(let z of D)typeof z.filename=="string"&&w.add(z.filename),typeof z.content=="string"&&w.add(z.content);let I=A.comments||[];for(let z of I)typeof z.author=="string"&&w.add(z.author),typeof z.body=="string"&&w.add(z.body);return w}let de=He("gist",()=>{let w=re(),A=Array.from(w);return A.length===0?null:{contents:A,options:ze()}},(w,A)=>{if(!Array.isArray(w?.contents)||w.contents.length!==A.contents.length||w.contents.some(z=>typeof z!="string"))throw Error("Invalid preview response");let D=A.contents,I=new Map;for(let z=0;z<D.length&&z<w.contents.length;z++)I.set(D[z],w.contents[z]);H.clear(),I.forEach((z,B)=>H.set(B,z)),Ne()});e.anonymizeGistContent=function(w){return w&&(H.has(w)?H.get(w):"")},e.previewGistFiles=[];function Ne(){let w=e.details&&e.details.gist&&e.details.gist.files||[];e.previewGistFiles=w.map(A=>({filename:e.anonymizeGistContent(A.filename),content:e.anonymizeGistContent(A.content),language:A.language}))}e.watch("details.gist.files",Ne,!0),e.watch("terms",Ne);function C(){let w=e.conference;if(e.conference_data=null,!w)return;let A=w===S||e.isUpdate&&w===e._originalConference;w!==S&&(S=null),t.get("/api/conferences/"+w).then(D=>{e.conference===w&&(e.conference_data=D.data,e.conference_data.startDate=new Date(e.conference_data.startDate),e.conference_data.endDate=new Date(e.conference_data.endDate),!A&&(e.options.expirationDate=new Date(e.conference_data.endDate),e.options.expirationMode="remove",e.options.update=e.conference_data.options.update,e.optio Line truncated
`).filter(B=>B),connection:e.githubConnection,fullName:`${D.owner}/${D.repo}`,repository:e.sourceUrl,reconnectRepositoryId:e.reconnectRepositoryId,options:e.options,source:e.source,conference:e.conference};e.details&&(I.options.pageSource=e.details.pageSource),N();let z=e.isUpdate?"/api/repo/"+e.repoId:"/api/repo/";t.post(z,I,{headers:{"Content-Type":"application/json"}}).then(()=>{v.clear(),window.location.href="/status/"+e.repoId},B=>{B.data&&(r("ERRORS."+B.data.error).then(ie=>{e.error=ie},console.error),j(B.data.error),["quota_exceeded","subscription_required_for_never_expiration"].includes(B.data.error)&&(B.data.error==="subscription_required_for_never_expiration"&&(e._existingNever=!1),e.hostingQuotaBlocked=!0,e.hostingReview=!0,Ge(()=>document.getElementById("repository-hosting")?.scrollIntoView({block:"center"}))))}).finally(()=>{A.disabled=!1})},e.anonymizeGist=w=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(V())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let A=w.currentTarget||w.target.closest?.("button")||w.target;A.disabled=!0;let D=parseGithubUrl(e.sourceUrl),I={gistId:e.gistId,terms:e.terms.trim().split(`
`).filter(B=>B),source:{gistId:D.gistId},options:e.options,conference:e.conference};N();let z=e.isUpdate?"/api/gist/"+e.gistId:"/api/gist/";t.post(z,I,{headers:{"Content-Type":"application/json"}}).then(()=>{v.clear(),window.location.href="/gist/"+e.gistId},B=>{B.data&&(r("ERRORS."+B.data.error).then(ie=>{e.error=ie},console.error),j(B.data.error))}).finally(()=>{A.disabled=!1})},e.anonymizePullRequest=w=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(V())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let A=w.currentTarget||w.target.closest?.("button")||w.target;A.disabled=!0;let D=parseGithubUrl(e.sourceUrl),I={pullRequestId:e.pullRequestId,connection:e.githubConnection,terms:e.terms.trim().split(`
`).filter(B=>B),source:{repositoryFullName:`${D.owner}/${D.repo}`,pullRequestId:D.pullRequestId},options:e.options,conference:e.conference};N();let z=e.isUpdate?"/api/pr/"+e.pullRequestId:"/api/pr/";t.post(z,I,{headers:{"Content-Type":"application/json"}}).then(()=>{v.clear(),window.location.href="/pr/"+e.pullRequestId},B=>{B.data&&(r("ERRORS."+B.data.error).then(ie=>{e.error=ie},console.error),j(B.data.error))}).finally(()=>{A.disabled=!1})},e.watch("conference",()=>{C()}),e.watch("terms",()=>{e.detectedType==="repo"&&F(),e.detectedType==="pr"&&U(),e.detectedType==="gist"&&de()}),e.watch("options.image",()=>{e.detectedType==="repo"&&F(),e.detectedType==="pr"&&U(),e.detectedType==="gist"&&de()}),e.watch("options.link",()=>{e.detectedType==="repo"&&F(),e.detectedType==="pr"&&U(),e.detectedType==="gist"&&de()}),e.watch("details",()=>{e.detectedType==="pr"&&U(),e.detectedType==="gist"&&de()},!0)},gi=function(e,t,o,i,s,r){let a=pt();il();let p=xt();e.on("dark-mode",(F,X)=>{e.aceOption&&(X?e.aceOption.theme="nord_dark":e.aceOption.theme="chrome")});let f=0,g=null,y=null;e.fileLoadingSlow=!1,e.fileReceivedBytes=0;function b(){g&&(g.resolve(),g=null),y&&(a.timeout.cancel(y),y=null)}let m=!1;e.on("dispose",()=>{m=!0,f++,b(),E&&E.resolve()}),e.files=[],e.isMac=/Mac|iPhone|iPad|iPod/.test(navigator.platform||navigator.userAgent),e.fileSearchQuery="",e.fileSearchResults=null,e.fileSearchLoading=!1,p(document,"click",F=>{e.symbolsOpen&&!F.target.closest?.(".symbols")&&(e.symbolsOpen=!1),e.moreOpen&&!F.target.closest?.(".tb-more")&&(e.moreOpen=!1),e.tocOpen&&!F.target.closest?.(".tb-toc-m")&&(e.tocOpen=!1),e.gotoOpen&&F.target.isConnected&&!F.target.closest?.(".goto-pop, .btn-goto, .tb-more")&&(e.gotoOpen=!1),e.accountOpen&&!F.target.closest?.(".acct")&&(e.accountOpen=!1),e.helpOpen&&!F.target.closest?.(".vb-help")&&(e.helpOpen=!1)}),p(document,"keydown",F=>{F.key==="Escape"&&(e.symbolsOpen=!1,e.moreOpen=!1,e.tocOpen=!1,e.gotoOpen=!1,e.accountOpen=!1,e.helpOpen=!1),(F.ctrlKey||F.metaKey)&&!F.altKey&&F.key&&F.key.toLowerCase()==="f"&&e.type==="html"&&window.document.querySelector(".reading-layout")&&(F.preventDefault(),e.toggleMdFind(!0))}),p(document,"keydown",function(F){if((F.metaKey||F.ctrlKey)&&F.key==="k"){F.preventDefault();var X=document.querySelector(".tree-search-input");X&&(X.focus(),X.select())}});var E=null;e.onFileSearchChange=function(){E&&(E.resolve(),E=null);let F=e.fileSearchQuery;if(!F||F.length<2){e.fileSearchResults=null,e.fileSearchLoading=!1;return}e.fileSearchLoading=!0;let X=r.defer();E=X,t.get(`/api/repo/${e.repoId}/files/search?q=${encodeURIComponent(F)}`,{timeout:X.promise}).then(function(J){if(!(m||E!==X)){E=null,e.fileSearchLoading=!1;var ne={};e.files.forEach(function(I){ne[(I.path||"")+"/"+I.name]=!0});for(var U=[],Q={},H=0;H<J.data.length;H++){var re=J.data[H];if(re.path)for(var de=re.path.split("/"),Ne="",C=0;C<de.length;C++){var N=Ne;Ne=Ne?Ne+"/"+de[C]:de[C];var V=N+"/"+de[C];!ne[V]&&!Q[V]&&(Q[V]=!0,U.push({name:de[C],path:N}))}}U.sort(function(I,z){return(I.path||"").split("/").length-(z.path||"").split("/").length}),U.length>0&&e.files.push.apply(e.files,U);for(var j=[],w=0;w<J.data.length;w++){var A=J.data[w],D=(A.path||"")+"/"+A.name;!ne[D]&&A.size!=null&&(j.push(A),ne[D]=!0)}j.length>0&&e.files.push.apply(e.files,j),e.fileSearchResults=J.data}},function(){!m&&E===X&&(E=null,e.fileSearchLoading=!1,e.fileSearchResults=[])})};let P={yml:"yaml",txt:"text",py:"python",js:"javascript",ts:"typescript"},k=["license","txt"],v=["png","jpg","jpeg","gif","svg","ico","bmp","tiff","tif","webp","avif","heif","heic"],S=["wav","mp3","ogg","wma","flac","aac","m4a"],_=["mp4","avi","webm","mov","mpg","mpeg","mkv","flv","wmv","3gp","3g2","m4v","f4v","f4p","f4a","f4b"];e.on("routeUpdate",function(F,X){if(e.repoId!=i.repoId)return Me();if((i.path||"")!=e.filePath){window.matchMedia?.("(max-width: 767px)").matches&&(e.sidebarCollapsed=!0),e.filePath=i.path||"",e.paths=e.filePath.split("/").filter(J=>J&&J.trim().length>0),He();for(let J=0;J<e.paths.length-1;J++){let ne=J>0?e.paths.slice(0,J).join("/"):"";e.files.some(Q=>Q.path===ne)||e.getFiles(ne)}}});function M(){if(e.paths[0]!="")return;let F=["readme.md","readme.txt","readme.org","readme.1st","readme"],X={};for(let ne of e.files)ne.name.toLowerCase().indexOf("readme")>-1&&(X[ne.name.toLowerCase()]=ne.name);let J=null;for(let ne of F)if(X[ne]){J=ne;break}if(!J&&Object.keys(X).length>0&&(J=Object.keys(X)[0]),J){let ne=o.url();ne[ne.length-1]!="/"&&(ne+="/"),o.url(ne+encodePathForUrl(X[J]))}}e.fileCounts=null;let L=0,q=new Set,G=!1;e.getFiles=function(F,X=!1){let J=e.repoId,ne=L;return t.get(`/api/repo/${e.repoId}/files/?path=${encodeURIComponent(F)}&v=${e.options.lastUpdateDate}`).then(function(U){if(m||J!==e.repoId||ne!==L)return[];let Q=F||"";return e.files=e.files.filter(H=>H.path!==Q),e.files.push(...U.data),se(Q,ne),U.data},function(U){if(m||J!==e.repoId||ne!==L)return[];X||(e.type="error",e.content=vi(U),e.files=[])})};function se(F,X){if(G||q.has Line truncated
`).forEach((X,J)=>{for(let[ne,U]of ue){let Q=ne.exec(X);if(Q&&!/^(if|for|while|switch|return|catch)$/.test(Q[1])){F.push({name:Q[1],kind:U,line:J+1});break}}}),he={content:e.content,list:F.slice(0,300)},he.list},e.goToSymbol=function(F){e.symbolsOpen=!1;let X=e.codeEditor;X&&(X.scrollToLine(F-1,!0,!0,()=>{}),X.gotoLine(F,0,!0),window.history.replaceState(null,"",window.location.pathname+window.location.search+"#L"+F),window.dispatchEvent(new HashChangeEvent("hashchange")))},e.gotoLine=function(){e.codeEditor&&(e.moreOpen=!1,e.gotoError="",e.gotoValue=String(e.codeEditor.getCursorPosition().row+1),e.gotoOpen=!0,setTimeout(()=>{let F=window.document.getElementById("goto-input");F&&(F.focus(),F.select())},0))},e.closeGoto=function(){e.gotoOpen=!1,e.gotoError="",e.codeEditor?.focus()},e.submitGoto=function(){let F=e.codeEditor;if(!F)return;let X=/^\s*:?\s*(\d+)\s*(?:[:,]\s*(\d+))?\s*$/.exec(e.gotoValue||""),J=F.session.getLength();if(!X||+X[1]<1||+X[1]>J){e.gotoError="Enter a line from 1 to "+J;return}F.gotoLine(+X[1],X[2]?Math.max(0,+X[2]-1):0,!0),e.gotoOpen=!1,e.gotoError="",F.focus()},e.rootEntries=function(){return[...e.files||[]].sort((F,X)=>{let J=F.size==null,ne=X.size==null;return J!==ne?J?-1:1:F.name.localeCompare(X.name)})},e.formatSize=function(F){if(F==null)return"";if(F<1024)return F+" B";let X=F/1024;return X<1024?X.toFixed(1)+" KB":(X/1024).toFixed(1)+" MB"},e.fileSize=function(F){if(!F)return null;let X=F.replace(/^\/+/,""),J=(e.files||[]).find(ne=>(ne.path?ne.path+"/":"")+ne.name===X);return J&&J.size!=null?J.size:null},e.revealFolder=function(F){e.sidebarHidden=!1,e.sidebarCollapsed=!1,Ge(()=>{let X=window.document.querySelector('.files a[data-path="/'+(window.CSS?.escape?window.CSS.escape(F):F)+'"]');X&&(X.closest("li")?.classList.contains("open")||X.click(),X.scrollIntoView({block:"nearest"}),X.focus())})},e.redactionCount=function(){return typeof e.content!="string"?0:((e.type==="html"?e.content.replace(/<[^>]*>/g," "):e.content).match(bo)||[]).length},e.renderRedacted=sl;let Ee=F=>F.toLowerCase().trim().replace(/[^a-z0-9\s-]/g,"").replace(/\s+/g,"-").slice(0,60)||"section";e.renderReadme=function(F){let X=e.renderRedacted(F);if(!X||typeof window.DOMParser!="function")return X;let J=new window.DOMParser().parseFromString("<div>"+X+"</div>","text/html"),ne={};return J.querySelectorAll("h1, h2, h3").forEach(U=>{let Q=U.id||Ee(U.textContent);ne[Q]?Q+="-"+ ++ne[Q]:ne[Q]=1,U.id=Q}),J.body.firstChild.innerHTML};let ye={content:null,list:[]};e.readmeToc=function(){if(e.type!=="html"||typeof e.content!="string")return[];if(ye.content===e.content)return ye.list;let X=[...new window.DOMParser().parseFromString("<div>"+e.renderReadme(e.sanitize?e.sanitize(e.content):e.content)+"</div>","text/html").querySelectorAll("h2, h3")].map(J=>({id:J.id,text:J.textContent.trim(),level:J.tagName==="H3"?3:2})).slice(0,40);return ye={content:e.content,list:X},X},e.activeHeading=null,p(window,"scroll",()=>{let F=e.readmeToc?e.readmeToc():[];if(!F.length)return;let X=150,J="",ne="";for(let U of F){let Q=window.document.getElementById(U.id);if(!Q)continue;let H=Q.getBoundingClientRect().top;H<X?J=U.id:!ne&&H<window.innerHeight-80&&(ne=U.id)}ne&&(J=ne),e.activeHeading!==J&&(e.activeHeading=J)},{capture:!0,passive:!0}),e.scrollToHeading=function(F){if(!F){(window.document.querySelector(".explorer-content, .file-card-body, .main-pane")||window).scrollTo({top:0,behavior:"smooth"}),e.activeHeading="";return}let X=window.document.getElementById(F);X&&X.scrollIntoView({behavior:"smooth",block:"start"}),e.activeHeading=F},e.redactParts=function(F){let X=[],J=0,ne,U=/\bXXXX-(\d+)\b/g;for(F=String(F||"");ne=U.exec(F);)ne.index>J&&X.push({t:F.slice(J,ne.index)}),X.push({n:ne[1]}),J=ne.index+ne[0].length;return J<F.length&&X.push({t:F.slice(J)}),X},e.pathCopied=!1,e.copyPath=async function(){window.navigator.clipboard?.writeText&&(await window.navigator.clipboard.writeText(e.filePath||""),e.pathCopied=!0,setTimeout(()=>{e.pathCopied=!1},1600))},e.contentCopied=!1,e.copyContent=async function(){if(typeof e.content!="string"||!window.navigator.clipboard?.writeText)return;let F=e.content;if(e.type==="html"&&e.url)try{F=await(await window.fetch(e.url,{credentials:"same-origin"})).text()}catch{return}await window.navigator.clipboard.writeText(F),e.contentCopied=!0,setTimeout(()=>{e.contentCopied=!1},1600)};function be(F){return P[F]?P[F]:F}function Le(F){return F=="pdf"?"pdf":F=="html"||F=="htm"?"html-doc":F=="md"?"md":F=="org"?"org":F=="ipynb"?"IPython":k.indexOf(F)>-1?"text":v.indexOf(F)>-1?"image":_.indexOf(F)>-1?"media":S.indexOf(F)>-1?"audio":"code"}function ze(F,X){let J=f;if(!F){e.type="error",e.content="no_file_selected";return}let ne=e.type;(ne==="code"||ne==="text")&&ko().catch(()=>{}),e.type="loading",e.content="loading",e.fileLoadingSlow=!1,e.fileReceivedBytes=0;let U=r.defer();g=U,y=a.timeout(()=>{!m&&J===f&&e.type==="loading"&&(e.fileLoadingSlow=!0)},1500);let Q=X&&X.sha||"0";t.get(`/api/repo/${e.repoId}/file/${encodePaLine truncated
`+k.join(`
`)],{type:"text/csv"}),S=document.createElement("a");S.href=URL.createObjectURL(v),S.download=i.username+"-repositories.csv",S.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(P=>{E&&(E.document.open(),E.document.write('<pre style="font:13px monospace;padding:16px;white-space:pre-wrap">'+JSON.stringify(P.data,null,2).replace(/[<>]/g,k=>k==="<"?"&lt;":"&gt;")+"</pre>"),E.document.close())},P=>{let k=P&&P.data?JSON.stringify(P.data,null,2):String(P);E&&(E.document.body.innerHTML='<pre style="color:#B42318;padding:16px">'+k+"</pre>")})};function f(m){t.get("/api/admin/users/"+m+"/repos",{}).then(E=>{e.repositories=E.data},E=>{console.error(E)})}function g(m){t.get("/api/admin/users/"+m,{}).then(E=>{e.userInfo=E.data},E=>{console.error(E)})}g(i.username),f(i.username),e.banUser=()=>{confirm(`Ban user ${i.username}?`)&&t.post(`/api/admin/users/${i.username}/ban`).then(()=>g(i.username),m=>console.error(m))},e.activateUser=()=>{t.post(`/api/admin/users/${i.username}/activate`).then(()=>g(i.username),m=>console.error(m))},e.promoteUser=()=>{confirm(`Promote ${i.username} to admin?`)&&t.post(`/api/admin/users/${i.username}/promote`).then(()=>g(i.username),m=>console.error(m))},e.demoteUser=()=>{confirm(`Remove admin privileges from ${i.username}?`)&&t.post(`/api/admin/users/${i.username}/demote`).then(()=>g(i.username),m=>console.error(m))},e.tokens=[],e.tokenForm={name:"",plaintext:null};function y(){t.get("/api/admin/tokens").then(m=>{e.tokens=m.data||[]},m=>{m.status!==401&&m.status!==403&&console.error(m)})}y(),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="",y()},m=>console.error(m))},e.revokeToken=m=>{confirm(`Revoke token "${m.name}"?`)&&t.delete("/api/admin/tokens/"+m.id).then(()=>y(),E=>console.error(E))},e.removeCache=m=>{confirm("Remove cached files for "+m.repoId+"?")&&t.delete("/api/admin/repos/"+m.repoId).then(()=>f(i.username),E=>console.error(E))},e.removeRepository=m=>{confirm("Remove repository "+m.repoId+"?")&&t.delete("/api/repo/"+m.repoId+"/").then(()=>f(i.username),E=>console.error(E))},e.updateRepository=m=>{let E=Ue({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(P=>{P.data.status=="ready"?E.title=`${m.repoId} is refreshed.`:E.title=`Refreshing of ${m.repoId}.`},P=>{E.title=`Error during the refresh of ${m.repoId}.`,E.body=P.body})},e.getGitHubRepositories=m=>{t.get(`/api/user/${e.userInfo.username}/all_repositories`,{params:{force:"1"}}).then(E=>{e.userInfo.repositories=E.data})};let b=null;e.watch("query",()=>{s.timeout.cancel(b),b=s.timeout(()=>{f(i.username)},500)},!0)},Sl=function(e,t,o){let i=pt(),s=xt();e.Math=Math,e.watch("user.status",()=>{e.user==null&&o.url("/")}),e.user==null&&o.url("/"),e.conferences=[],e.total=-1,e.totalPage=0,e.statusCounts=[];let r=P=>{if(P.key==="/"&&!["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName)){P.preventDefault();let k=document.querySelector('.admin-filter-toolbar input[type="search"]');k&&k.focus()}};s(document,"keydown",r),e.on("dispose",()=>document.removeEventListener("keydown",r)),e.clearFilter=P=>{P==="dateRange"?(e.query.dateFrom="",e.query.dateTo=""):e.query[P]="",e.query.page=1},e.chips=[];let a=()=>{let P=[];(e.query.dateFrom||e.query.dateTo)&&P.push({key:"dateRange",label:"Date",value:(e.query.dateFrom||"\u2026")+" \u2013 "+(e.query.dateTo||"\u2026")}),e.chips=P};e.statusCountFor=P=>{let k=(e.statusCounts||[]).find(v=>v._id===P);return k?k.count:0},e.toggleSortDirection=()=>{e.query.direction=e.query.direction==="asc"?"desc":"asc"},e.sortBy=P=>{e.query.sort===P?e.query.direction=e.query.direction==="asc"?"desc":"asc":(e.query.sort=P,e.query.direction="desc"),e.query.page=1},e.sortIcon=P=>e.query.sort===P?e.query.direction==="asc"?"fa-arrow-up":"fa-arrow-down":"";let p="admin.conferences.filterPrefs",f={page:1,limit:25,sort:"name",direction:"asc",search:"",dateFrom:"",dateTo:"",ready:!0,expired:!0,removed:!1,error:!0,preparing:!0},g=loadFilterPrefs(p)||{};e.query=Object.assign({},f,g,{page:1,search:""});let y=o.search();y.search&&(e.query.search=y.search);let b="admin.conferences.presets";e.presets=JSON.parse(localStorage.getItem(b)||"[]"),e.savePreset=()=>{let P=window.prompt("Preset name:");if(!P)return;let k=Object.assign({},e.query);delete k.page,e.presets=(e.presets||[]).filter(v=>v.name!==P),e.presets.push({name:P,query:k}),localStorage.setItem(b,JSON.stringify(e.presets))},e.applyPreset=P=>{Object.assign(e.query,P.query,{page:1})},e.deletePreset=P=>{e.presets=(e.presets||[]).filter(k=>k.name!==P.name),localStorage.setItem(b,JS Line truncated
`).map((Ee,ye)=>ye===0?Ee:he+Ee).join(`
`)}else typeof R=="number"||typeof R=="boolean"?ue=String(R):ue=JSON.stringify(R);se.push(`${ve}${ue}${x}`)}),se.push("}"),se.join(`
`)}function g(S){let _=[],M="",L=/(\w+):(>=|<=|!=|>|<|=)?([^\s]+)/g,q=0,G;for(;G=L.exec(S);)M+=S.slice(q,G.index),q=L.lastIndex,_.push({key:G[1],op:G[2]||"=",val:G[3]});return M+=S.slice(q),{filters:_,free:M.trim().toLowerCase()}}function y(S,_){for(let M of _.filters){let L=(G,se,ee)=>{let R=parseFloat(G),K=parseFloat(se);return ee==="="?String(G)===String(se):ee==="!="?String(G)!==String(se):ee===">="?R>=K:ee==="<="?R<=K:ee===">"?R>K:ee==="<"?R<K:!0},q;if(M.key==="code")q=S.displayMessage;else if(M.key==="module")q=S.module;else if(M.key==="status")q=S._status;else if(M.key==="url")q=S._url;else if(M.key==="repo")q=S._repoId;else if(M.key==="level")q=S.level;else continue;if(q==null||!L(q,M.val,M.op))return!1}return!(_.free&&((S.displayMessage||"")+" "+(S.module||"")+" "+(S._url||"")+" "+JSON.stringify(S.raw||[])).toLowerCase().indexOf(_.free)===-1)}function b(){let S=g(e.query.search||"");e.parsedFilterCount=S.filters.length;let _=e.query.bucket,M=e.entries.filter(ee=>_&&ee._bucket!==_?!1:y(ee,S)),L=e.query.group;if(L){let ee=te=>L==="module"?te.module:te.displayMessage||te.message||"_",R=new Map;for(let te of M){let ve=ee(te);if(R.has(ve)){let x=R.get(ve);x.count++,x._related.push(te),new Date(te.ts)>new Date(x.ts)&&(x.ts=te.ts,x._url=te._url,x._status=te._status),new Date(te.ts)<new Date(x._firstSeen)&&(x._firstSeen=te.ts)}else{let x=Object.assign({},te);x._key=`${L}:${ve}`,x._related=[te],x._firstSeen=te.ts,x._lastHourCount=0,x.count=1,R.set(ve,x)}}let K=Date.now()-3600*1e3;for(let te of R.values())te._lastHourCount=te._related.filter(ve=>new Date(ve.ts).getTime()>=K).length;M=Array.from(R.values())}else M=M.map((ee,R)=>(ee._key="row:"+R+":"+ee.ts,ee._related=[ee],ee._firstSeen=ee.ts,ee._lastHourCount=0,ee.count=1,ee));let q=ee=>({error:0,warn:1,info:2})[ee._bucket]??1;e.query.sort==="count"?M.sort((ee,R)=>q(ee)-q(R)||R.count-ee.count||new Date(R.ts)-new Date(ee.ts)):M.sort((ee,R)=>q(ee)-q(R)||new Date(R.ts)-new Date(ee.ts)),e.visible=M;let G=!!(e.query.bucket||(e.query.search||"").trim()),se=!G&&(e.stats?.severity?.error||0)>0&&!M.some(ee=>ee._bucket==="error")&&e.entries.length<1500;(G&&!M.length||se)&&e.canLoadMore?.()&&!e._autoLoading&&e.entries.length<2500&&(e._autoLoading=!0,m(!0))}function m(S){let _=S?e.entries.length:0,M=S?e.pageSize:Math.max(e.pageSize,e.entries.length||e.pageSize);t.get("/api/admin/errors",{params:{offset:_,limit:M}}).then(L=>{let q=(L.data.entries||[]).map(p);e.entries=S?e.entries.concat(q):q,e.available=!!L.data.available,e.cap=L.data.max||e.cap,e.total=L.data.total||e.entries.length,e._autoLoading=!1,b()},L=>{e._autoLoading=!1,console.error(L)})}e.loadMore=()=>m(!0),e.canLoadMore=()=>e.entries.length<e.total;function E(){t.get("/api/admin/errors/stats").then(S=>{let _=S.data||{},M=_.prev24h?Math.round((_.last24h-_.prev24h)/_.prev24h*100):0;e.stats={last24h:_.last24h||0,prev24h:_.prev24h||0,delta:M,severity:_.severity||{error:0,warn:0,info:0},unique:_.unique||{error:0,warn:0,info:0},buckets:_.buckets||[],dropped:_.dropped||0},b()},S=>console.error(S))}function P(){m(),E()}e.barPx=(S,_)=>{let M=e.stats.buckets||[],L=0,q=0;for(let R of M)L=Math.max(L,(R.error||0)+(R.warn||0)),q=Math.max(q,R.info||0);let G=S[_]||0;if(!G)return 0;if(_==="info")return q?Math.max(2,Math.round(G/q*(L?16:60))):0;let se=(S.error||0)+(S.warn||0),ee=Math.round(se/L*44);return Math.max(4,Math.round(G/se*ee))},e.bucketTitle=S=>`${new Date(S.hour).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})} \xB7 ${S.error||0} err \xB7 ${S.warn||0} warn \xB7 ${S.info||0} info`,e.toggle=S=>{e.expanded[S._key]=!e.expanded[S._key]},e.setBucket=S=>{e.query.bucket=S},e.refreshNow=P,e.clearAll=()=>{confirm("Clear all captured errors?")&&t.delete("/api/admin/errors").then(P,S=>console.error(S))},e.exportCsv=()=>{let S=["ts","level","module","displayMessage","_status","_url","_repoId"],_=[S.join(",")];for(let G of e.visible)_.push(S.map(se=>{let ee=G[se]==null?"":String(G[se]);return/[",\n]/.test(ee)?`"${ee.replace(/"/g,'""')}"`:ee}).join(","));let M=new Blob([_.join(`
`)],{type:"text/csv;charset=utf-8"}),L=URL.createObjectURL(M),q=document.createElement("a");q.href=L,q.download=`errors-${new Date().toISOString().slice(0,19)}.csv`,document.body.appendChild(q),q.click(),document.body.removeChild(q),URL.revokeObjectURL(L)};function k(S){e.copyHint=`${S} copied`,s.timeout(()=>{e.copyHint=""},1500)}e.copyJson=S=>{navigator.clipboard.writeText(S._detailJson).then(()=>k("JSON"))},e.copyCurl=S=>{if(!S._url)return;let M=`curl -X ${S._method||"GET"} '${window.location.origin}${S._url}'`;navigator.clipboard.writeText(M).then(()=>k("curl"))},P();let v=i(()=>{e.query.autoRefresh&&P()},15e3);e.on("dispose",()=>i.cancel(v)),e.watch("query.search",b),e.watch("query.bucket",b),e.watch("query.sort",b),e.watch("query.group",b)},Dl=function(e,t,o,i){if(e.Math=Math,e.watch("user.status",()=>{e.user==null&&o.url("/")}),e.user==null){o.url("/");return}e.data=null,e.loading=!0,e.error=null,e.performance=null,e.performanceMinutes=15,e.performanceTab="routes",e.cacheReport=null,e.cacheError=null,e.cacheMinutes=60,e.cacheTraffic="all",e.ovView=["performance","cache"].includes((window.location.hash||"").slice(1))?window.location.hash.slice(1):"summary",e.setOvView=function(v){e.ovView=v;try{window.history.replaceState(null,"",v==="summary"?window.location.pathname:"#"+v)}catch{}};var s=!1;e.loadCache=function(){if(!s){s=!0;var v=e.cacheMinutes;t.get("/api/admin/cache",{params:{minutes:v}}).then(function(S){v===e.cacheMinutes&&(e.cacheReport=S.data,e.cacheError=S.data.available?null:S.data.reason||"Cache monitoring is unavailable.")},function(){e.cacheError="Could not refresh cache monitoring. Displayed values may be stale."}).finally(function(){s=!1,v!==e.cacheMinutes&&e.loadCache()})}},e.cacheRows=function(){return(e.cacheReport?.rows||[]).filter(function(v){return e.cacheTraffic==="all"||v.traffic===e.cacheTraffic})},e.cacheRate=function(v,S){var _=e.cacheRows(),M=function(G){return _.filter(function(se){return se.name===G}).reduce(function(se,ee){return se+ee[S]},0)},L=M(v+"_hit"),q=M(v+"_miss");return L+q?(100*L/(L+q)).toFixed(1)+"%":"No samples"},e.cacheEventName=function(v){return v.replaceAll("_"," ")},e.cacheP95=function(v){var S=0,_=e.cacheReport?.latencyBucketsMs||[];if(!v.count)return"No samples";if(!v.ms)return"Not timed";for(var M=0;M<=_.length;M++)if(S+=v["b"+M]||0,S>=Math.ceil(v.count*.95))return M<_.length?"\u2264 "+_[M]+" ms":"> 10 s";return"No samples"},e.performanceError=null,e.formatMs=function(v){return v==null?"":v<1e3?v+" ms":+(v/1e3).toFixed(1)+" s"},e.latencyBound=function(v,S){return v.count?v[S]==null?"> 60 s":"\u2264 "+e.formatMs(v[S]):"No samples"},e.firstByteBound=function(v){return e.latencyBound({count:v.firstByteCount,p95UpperMs:v.firstByteP95UpperMs},"p95UpperMs")},e.sampleAge=function(v){return Math.max(0,Math.round((Date.now()-v.sampledAt)/1e3))},e.peakRss=function(v){return(e.performance.runtimeSeries||[]).filter(function(S){return S.instance===v.instance}).reduce(function(S,_){return Math.max(S,_.rss)},v.memory.rss)},e.performanceWarning=function(v){return e.sampleAge(v)>45||v.droppedBatches||v.droppedMetrics||v.sockets?.closeWait>0||v.eventLoop?.p95Ms>100||v.memoryLimitBytes&&v.memory.rss>v.memoryLimitBytes*.8};var r=!1;e.loadPerformance=function(){var v=e.performanceMinutes;e.performance?.windowMinutes&&e.performance.windowMinutes!==v&&(e.performance=null),!r&&(r=!0,t.get("/api/admin/performance",{params:{minutes:v}}).then(function(S){v===e.performanceMinutes&&(e.performance=S.data,e.performanceError=S.data.available?null:"Performance monitoring is unavailable. Request history may be incomplete.")},function(){v===e.performanceMinutes&&(e.performanceError="Could not refresh performance monitoring. Displayed samples may be stale.")}).finally(function(){r=!1,v!==e.performanceMinutes&&e.loadPerformance()}))};function a(v){if(v==null)return"\u2014";for(var S=["B","KB","MB","GB","TB"],_=0,M=v;M>=1024&&_<S.length-1;)M/=1024,_++;return M.toFixed(_>0?1:0)+" "+S[_]}e.humanBytes=a;function p(v){if(!v)return"\u2014";var S=Math.floor(v/86400),_=Math.floor(v%86400/3600),M=Math.floor(v%3600/60);return S>0?S+"d "+(_<10?"0":"")+_+"h":_>0?_+"h "+(M<10?"0":"")+M+"m":M+"m"}e.humanDuration=p;function f(v){return v==null?"\u2014":v>=1e6?(v/1e6).toFixed(1)+"M":v>=1e3?(v/1e3).toFixed(1)+"K":String(v)}e.humanNum=f,e.queueTotal=function(v){return v?(v.waiting||0)+(v.active||0)+(v.delayed||0)+(v.failed||0):0},e.statusCount=function(v){if(!e.data||!e.data.repos)return 0;for(var S=e.data.repos.statusBreakdown||[],_=0;_<S.length;_++)if(S[_]._id===v)return S[_].count;return 0},e.barPct=function(v){var S=e.data&&e.data.repos?e.data.repos.total:0;if(!S)return 0;var _=[v];v==="expired"&&_.push("expiring"),v==="removed"&&_.push("removing"),v==="preparing"&&_.push("download");var M=0;return _.forEach(function(L){M+=e.statusCount(L)}),Math.max(.4,M/S*100)},e.errPct=function(v){if(!e.data||!e.data.errors)return 0;var S=Math.max(e.data.errors.severity.error,e.data.errors.severity.warn,e.data.erro Line truncated
Contact: jane.smith@mit.edu`,e.demoTerms="Jane Smith, Smith, MIT CSAIL, jane.smith@mit.edu",e.demoParts=function(){let u=(e.demoTerms||"").split(/[,\n]/).map(h=>h.trim()).filter(Boolean).sort((h,k)=>k.length-h.length),c=h=>h.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");if(!u.length)return[{text:e.demoText}];let m=new RegExp("("+u.map(c).join("|")+")","gi"),g={},v=0;return(e.demoText||"").split(m).filter(h=>h!=="").map(h=>{let k=u.find(A=>A.toLowerCase()===h.toLowerCase());return k?(g[k.toLowerCase()]||(g[k.toLowerCase()]=++v),{text:String(g[k.toLowerCase()]),redacted:!0,original:h}):{text:h}})},e.demoCount=()=>e.demoParts().filter(u=>u.redacted).length,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 r(){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}).catch(()=>{})}r();function a(u){let c={series:u,bars:[],viewW:100,deltaToday:0,pctChange:0,pctAbs:0,isUp:!0};if(!u||u.length<2)return c;let m=new Array(u.length-1);for(let w=1;w<u.length;w++)m[w-1]=u[w]-u[w-1];let g=m.length,v=Math.max.apply(null,m),h=Math.min.apply(null,m),k=Math.min(0,h),A=v-k||1;c.viewW=g*2,c.bars=new Array(g);for(let w=0;w<g;w++){let b=(m[w]-k)/A,E=Math.max(1.5,b*34);c.bars[w]={x:(w*2+.25).toFixed(2),y:(36-E).toFixed(2),w:"1.5",h:E.toFixed(2)}}if(c.deltaToday=m[g-1],g>=2){let w=m[g-2];w&&(c.pctChange=(c.deltaToday-w)/w*100)}return c.pctAbs=Math.round(Math.abs(c.pctChange)),c.isUp=c.pctChange>=0,c}e.history={repositories:a([]),users:a([]),pageViews:a([]),pullRequests:a([])},t.get("/api/stat/history?days=60").then(u=>{let c=u.data||[];e.history={repositories:a(c.map(m=>m.nbRepositories||0)),users:a(c.map(m=>m.nbUsers||0)),pageViews:a(c.map(m=>m.nbPageViews||0)),pullRequests:a(c.map(m=>m.nbPullRequests||0))}}).catch(()=>{})},Wu=function(e,t,s,i,o,r){let a=At();e.on("routeLeave",function(){$('[data-toggle="tooltip"]').tooltip("dispose")}),e.watch("user.status",()=>{e.user==null&&s.url("/")}),e.user==null&&s.url("/"),a.timeout(()=>{$('[data-toggle="tooltip"]').tooltip()},250),e.quotaExpanded=!1,e.closeQuota=()=>{e.quotaExpanded=!1,it(()=>document.querySelector(".dashboard-quota > summary")?.focus())},vn()(document,"click",D=>{e.quotaExpanded&&!D.target.closest?.(".dashboard-quota")&&(e.quotaExpanded=!1)}),e.filtersExpanded=!1,e.projectView="all",e.selectedProject=null,e.projectName="",e.nameSaving=!1,e.nameError="",e.nameMessage="",e.needsAttention=D=>D.status==="error"||D._broken||c(D.status)==="progress"&&D._stale,e.attentionCount=()=>e.dashboardTotals?.attention??e.items.filter(e.needsAttention).length,e.hasProjects=()=>(e.dashboardTotals?.total??e.items.length)>0,e.setProjectView=D=>{e.projectView=D,D==="attention"&&(e.filters.status.error=!0,e.filters.status.progress=!0)},e.projectDetailsId=D=>"project-details-"+encodeURIComponent(D._type+":"+(D._id||D._source||"unknown")),e.showProjectDetails=async D=>{e.selectedProject=D,e.projectName=D.projectName||"",e.nameError="",e.nameMessage="",await it();let X=document.getElementById(e.projectDetailsId(D));X?.focus(),X?.scrollIntoView?.({block:"nearest"})},e.closeProjectDetails=D=>{e.selectedProject=null,it(()=>document.querySelector(`[data-project-actions="${encodeURIComponent(D._type+":"+D._id)}"]`)?.focus())},e.saveProjectName=async D=>{if(e.nameSaving||!D._id)return;let X=e.projectName.trim();if(X.length>100){e.nameError="Use 100 characters or fewer.";return}e.nameSaving=!0,e.nameError="",e.nameMessage="";try{let le=await t.post("/api/user/project-name",{type:D._type,id:D._id,name:X});D.projectName=le.data.name,D._label=D.projectName||D._fallbackLabel,e.selectedProject===D&&(e.nameMessage=X?"Project name saved.":"Default project name restored."),N||(e.dashboardCursor=null,await q(),e.selectedProject===D&&(e.selectedProject=e.items.find(Ee=>Ee._type===D._type&&Ee._id===D._id)||null))}catch{e.selectedProject===D&&(e.nameError="The project name could not be saved. Try again.")}finally{e.nameSaving=!1}},e.copyingId=null,e.copyLink=async D=>{if(!D._viewUrl||e.copyingId)return;let X=new URL(D._viewUrl,o.location.origin).href;e.copyingId=D._type+":"+D._id;try{await Fu(X),e.addToast({title:"Link copied",body:"The anonymous link is ready to share."})}catch{e.addToast({title:"Copy this anonymous link",body:X})}finally{e.copyingId=null}},e.items=[],e.search="",e.loading=!0,e.statusKeyLabels={ready:"Ready",progress:"In progress",error:"Error",expired:"Expired",removed:"Removed"};let u=["queue","download","downloaded","preparing","anonymizing"];function c(D){return D==="ready"||D==="error"?D:D==="expired"||D==="expiring"?"expired":D==="removed"||D==="removing"?"removed":(u.indexOf(D)>-1,"progress")}let m=7200*1e3,g="dashboard.filterPrefs",v={typeFilter:"all",filters:{status:{ready:!0,progress:!0,error:!0,e Line truncated
`)),e.options=Object.assign({},e.options,z.options),e.options.expirationDate=z.options&&z.options.expirationDate?new Date(z.options.expirationDate):j(),!i.repoId&&!i.pullRequestId&&!i.gistId&&!e.anonymize?.terms?.dirty&&(e.terms=e.defaultTerms),S&&S()})}function re(S,V,z){e.anonymize&&e.anonymize[S]&&e.anonymize[S].setValidity(V,z)}function me(S){try{let V=parseGithubUrl(S);if(V&&V.owner&&V.repo)return V.owner+"/"+V.repo}catch{}return null}e.accessRepairAllowed=!1,e.repairingGitHubAccess=!1,e.accessRepairMessage="",e.repairGitHubAccess=async()=>{if(!e.accessRepairAllowed||e.repairingGitHubAccess||!e.githubConnections?.appEnabled||!i.repoId||e.role!=="owner"||e.githubConnection!=="github-app"||me(e.sourceUrl)!==e._originalFullName)return;e.repairingGitHubAccess=!0,e.accessRepairMessage="";let S=h();try{let V=await t.get("/github/connections");if(e.githubConnections=V.data,!V.data.appEnabled)return;let z=await t.post("/github/connections/migrate",{type:"repository",id:i.repoId,connection:"github-app"},{headers:{"X-CSRF-Token":V.data.csrf}});if(!v(S))return;e.error=null,z.data.fullName&&(e._originalFullName=z.data.fullName,e.source.fullName=z.data.fullName,e.sourceUrl="https://github.com/"+z.data.fullName),e.accessRepairMessage="GitHub access repaired. Your anonymous URL and published commit are unchanged.",await e.urlSelected(!0)}catch{v(S)&&(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,k(S)}},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 Re()}catch{}}};function ke(){return e.reconnectingSource||!e.isUpdate||!e._originalRepositoryID?void 0:me(e.sourceUrl)===e._originalFullName?e._originalRepositoryID:void 0}async function _e(){e._preservingDraft=!0;try{await e.urlSelected(!0)}finally{e._preservingDraft=!1}}async function Ne(){let S=new URLSearchParams(window.location.search).get("billingDraft");if(S){b.restore();try{let z=(await t.get("/api/billing/draft/"+encodeURIComponent(S))).data;if(z.path!==o.path())throw new Error("Wrong task");E=z.values.conference||null;for(let Z of["sourceUrl","terms","repoId","source","options","conference","githubConnection"])Object.prototype.hasOwnProperty.call(z.values,Z)&&(e[Z]=z.values[Z]);return e.options?.expirationDate&&(e.options.expirationDate=new Date(e.options.expirationDate)),N=z.id,O=JSON.stringify(b.checkpoint()),e.draftRestored=!0,e.hostingReview=!0,e.sourceUrl&&await _e(),o.replace?.(o.path()),!0}catch{e.billingError="The checkout draft could not be restored. Retry by reloading this page; any local draft is still available."}}let V;try{V=JSON.parse(sessionStorage.getItem("github-access-draft")||"null")}catch{return!1}if(!V||V.path!==o.path()||Date.now()-V.savedAt>=30*6e4)return b.restore()?(e.sourceUrl&&await _e(),!0):!1;b.restore();for(let z of["sourceUrl","terms","repoId","pullRequestId","gistId","source","options","conference","githubConnection"])Object.prototype.hasOwnProperty.call(V.draft,z)&&(e[z]=V.draft[z]);return e.options.expirationDate&&(e.options.expirationDate=new Date(e.options.expirationDate)),await _e(),sessionStorage.removeItem("github-access-draft"),!0}Ee(()=>{!i.repoId&&!i.pullRequestId&&!i.gistId&&a(Ne,0),i.repoId&&i.repoId!=""&&(e.isUpdate=!0,e.detectedType="repo",e.repoId=i.repoId,t.get("/api/repo/"+e.repoId).then(async S=>{e.accessRepairAllowed=!["removed","archived","preparing","queue","download","removing","expiring"].includes(S.data.status),e.githubConnection=S.data.connection||"oauth",e.sourceUrl="https://github.com/"+S.data.source.fullName,e._originalFullName=S.data.source.fullName,e.terms=S.data.options.terms.filter(V=>V).join(`
`),e.source=S.data.source,e.role=S.data.role||"owner",e._existingNever=S.data.options.expirationMode==="never",e.coauthors=S.data.coauthors||[],e._originalBranch=S.data.source.branch,e.options=Object.assign({},e.options,S.data.options),e.conference=S.data.conference,e._originalConference=S.data.conference,e.repositoryID=S.data.source.repositoryID,e._originalRepositoryID=S.data.source.repositoryID,S.data.options.expirationDate&&(e.options.expirationDate=new Date(S.data.options.expirationDate)),A=w(parseGithubUrl(e.sourceUrl)),!await Ne()&&(await Promise.all([Re(),Je()]),H())},()=>{o.url("/404")})),i.pullRequestId&&i.pullRequestId!=""&&(e.isUpdate=!0,e.detectedType="pr",e.pullRequestId=i.pullRequestId,t.get("/api/pr/"+e.pullRequestId).then(async S=>{if(e.githubConnection=S.data.connection||"oauth",e.sourceUrl="https://github.com/"+S.data.source.repositoryFullName+"/pull/"+S.data.source.pullRequestId,e.terms=S.data.options.terms.filter(V=>V).join(`
`),e.source=S.data.source,e.options=Object.assign({},e.options,S.data.options),e.conference=S.data.conference,e._originalConference=S.data.conference,S.data.options.expirationDate&&(e.options.expirationDate=new Date(S.data.options.expirationDate)),A=w(parseGithubUrl(e.sourceUrl)),!await Ne())try{await ee()}catch{}},()=>{o.url("/404")})),i.gistId&&i.gistId!=""&&(e.isUpdate=!0,e.detectedType="gist",e.gistId=i.gistId,t.get("/api/gist/"+e.gistId).then(async S=>{e.sourceUrl="https://gist.github.com/"+S.data.source.gistId,e.terms=S.data.options.terms.filter(V=>V).join(`
`),e.source=S.data.source,e.options=Object.assign({},e.options,S.data.options),e.conference=S.data.conference,e._originalConference=S.data.conference,S.data.options.expirationDate&&(e.options.expirationDate=new Date(S.data.options.expirationDate)),A=w(parseGithubUrl(e.sourceUrl)),!await Ne()&&await pe()},()=>{o.url("/404")}))}),t.get("/github/connections").then(S=>{e.githubConnections=S.data,!i.repoId&&!i.pullRequestId&&!i.gistId&&e.githubConnection===void 0&&S.data.appEnabled&&S.data.appConnected&&(e.githubConnection="github-app",e.sourceUrl&&e.workspaceOpen&&_e())}).catch(()=>{}),e.urlSelected=async(S=!1)=>{let V=++c;e.previousConfigurations=[],e.previousConfigurationId="";let z;try{z=parseGithubUrl(e.sourceUrl.trim())}catch{e.sourceLoading=!1,M.cancel(),ne.cancel(),Le.cancel(),e.previewStatus="idle",e.sourceUrlError=e.sourceUrl?"Please provide a valid GitHub URL.":"",re("sourceUrl","github",!1);return}let Z=w(z),fe=S||A===Z;A=Z,e.sourceUrlError="",re("sourceUrl","github",!0);let be=document.activeElement?.id==="sourceUrl-landing";e.workspaceOpen=!0,setTimeout(()=>{let Ze=window.document.getElementById("sourceUrl");if(Ze){try{Ze.setSelectionRange(0,0)}catch{}Ze.scrollLeft=0}},50),be&&a(()=>document.getElementById("sourceUrl")?.focus(),0),e.reconnectingSource=!1,e.reconnectRepositoryId=void 0,!fe&&!e.isUpdate&&(e.repoId="",e.pullRequestId="",e.gistId=""),e.details=null,e.branches=[],fe||(e.source={type:"GitHubStream",branch:"",commit:""}),M.cancel(),ne.cancel(),Le.cancel(),K.clear(),ye.clear(),e.previewStatus="idle",e.anonymize_readme="",e.readme="",e.html_readme="",e.detectedType=null,e.gistOAuthRequired=!1,e.gistAppRequired=!1,e._preservingDraft=fe;try{z.gistId&&!z.repo?(e.detectedType="gist",e.source={gistId:z.gistId},await pe()):z.pullRequestId?(e.detectedType="pr",e.source={repositoryFullName:z.owner+"/"+z.repo,pullRequestId:z.pullRequestId},await ee()):(e.detectedType="repo",le(),await Promise.all([Re(),Je()]),H())}catch{}finally{V===c&&(e._preservingDraft=!1)}$('[data-toggle="tooltip"]').tooltip()},$('[data-toggle="tooltip"]').tooltip(),e.watch("source.branch",async()=>{if(e.detectedType!=="repo")return;let S=e.branches.filter(z=>z.name==e.source.branch)[0];if(!S)return;!(!e.reconnectingSource&&e.isUpdate&&e._originalBranch===e.source.branch&&e.source.commit)&&!(e._preservingDraft&&e.source.commit)&&(e.source.commit=S.commit),e.readme=S.readme,await Je(),H()}),e.getBranches=async S=>{let V=parseGithubUrl(e.sourceUrl),z=h();try{let Z=await t.get(`/api/repo/${V.owner}/${V.repo}/branches`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&i.repoId&&me(e.sourceUrl)===e._originalFullName?i.repoId:void 0,connection:e.githubConnection,force:S===!0||e.reconnectingSource?"1":"0",repositoryID:ke()}});if(!v(z))return;e.branches=Z.data,e.sourceUnreachable=!1,e.source.branch||(e.source.branch=e.details.defaultBranch);let fe=e.branches.filter(be=>be.name==e.source.branch);fe.length>0&&(!(!e.reconnectingSource&&!S&&e.isUpdate&&!e.options.update&&e._originalBranch===e.source.branch&&e.source.commit)&&!(e._preservingDraft&&e.source.commit)&&(e.source.commit=fe[0].commit),e.readme=fe[0].readme,await Je(S))}catch(Z){if(!v(z))return;e.branches=[],e.sourceUnreachable=Z&&(Z.status===404||Z.data&&Z.data.error==="repo_not_found");let fe=Z&&Z.data&&Z.data.error||(Z&&Z.status===404?"repo_not_found":"unknown_error");r("ERRORS."+fe).then(be=>{e.toasts=e.toasts||[],e.addToast({title:"Error",date:new Date,body:be}),e.error=be},console.error),typeof re=="function"&&re("sourceUrl","missing",!1)}finally{k(z)}};async function Re(){let S=parseGithubUrl(e.sourceUrl),V=h();try{Ye();let z=await t.get(`/api/repo/${S.owner}/${S.repo}/`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&i.repoId&&me(e.sourceUrl)===e._originalFullName?i.repoId:void 0,connection:e.githubConnection,repositoryID:ke(),force:"1"}});if(!v(V))return;e.details=z.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(z){if(!v(V))return;throw z.data&&(r("ERRORS."+z.data.error).then(Z=>{e.addToast({title:"Error",date:new Date,body:Z}),e.error=Z},console.error),lt(z.data.error)),re("sourceUrl","missing",!1),z}finally{k(V)}}async function Je(S){if(e.readme&&!S)return e.readme;let V=parseGithubUrl(e.sourceUrl),z=h();try{let Z=await t.get(`/api/repo/${V.owner}/${V.repo}/readme`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&i.repoId&&me(e.sourceUrl)===e._originalFullName?i.repoId:void 0,connection:e.githubConnection,force:S===!0?"1":"0",branch:e.source.branch,repositoryID:ke()}});v(z,!0)&&(e.readme=Z.data)}catch{v(z,!0)&&(e.readme="")}finally{k(z)}}let Ke={magicalBraces:!0},rt=S=>S.startsWith("/")&&!S.endsWith("/")&&On(os(S.slice(1),Ke),Ke)===S.slice(1),Qe=()=>Object.keys(e.preserve.picked).filter(S=>e. Line truncated
`).map(S=>S.trim()).filter(Boolean),te=null,L=0,x=null,B=()=>!1;function ue(){let S=L+"\0"+e.preserve.patterns;if(S!==x){x=S;try{B=da(la([...Qe(),...Q()]))}catch{B=()=>!1}}return B}function we(S){let V=new Map([["",{dirs:[],files:[]}]]);for(let z of S){let Z=z.split("/"),fe="";for(let be=0;be<Z.length-1;be++){let Ze=Z.slice(0,be+1).join("/");V.has(Ze)||(V.set(Ze,{dirs:[],files:[]}),V.get(fe).dirs.push(Ze)),fe=Ze}V.get(fe).files.push(z)}for(let z of V.values())z.dirs.sort();return{files:S,dirs:V,descendants:new Map}}function Pe(S){return te.descendants.has(S)||te.descendants.set(S,te.files.filter(V=>V.startsWith(S+"/"))),te.descendants.get(S)}let C=S=>ue()(S);function R(S){let V=Pe(S),z=0;for(let Z of V)C(Z)&&z++;return z===0?"none":z===V.length?"all":"some"}e.preserve={open:!1,loading:!1,error:"",truncated:!1,commit:"",search:"",expanded:{},picked:{},patterns:"",patternsOpen:!1},e.preserveSummary=()=>{let S=(e.options?.preserveFiles||[]).map(V=>String(V).trim()).filter(Boolean).map(V=>rt(V)?os(V.slice(1),Ke):V);return S.length?S.slice(0,2).join(", ")+(S.length>2?` and ${S.length-2} more`:""):"None. Every file is redacted."};async function P(){let S=e.source?.commit;if(!(te&&e.preserve.commit===S)){e.preserve.loading=!0,e.preserve.error="",te=null;try{let V=parseGithubUrl(e.sourceUrl),z=await t.get(`/api/repo/${V.owner}/${V.repo}/tree`,{params:{commit:S,connection:e.githubConnection,anonymizedRepoId:e.isUpdate&&i.repoId&&me(e.sourceUrl)===e._originalFullName?i.repoId:void 0,repositoryID:ke()}});if(e.source?.commit!==S)return;te=hs(we(z.data.files||[])),e.preserve.commit=S,e.preserve.truncated=!!z.data.truncated}catch{e.preserve.error="The file list could not be loaded from GitHub. You can still use patterns.",e.preserve.patternsOpen=!0}finally{e.preserve.loading=!1}}}e.openPreserveFiles=()=>{let S={},V=[];for(let Z of e.options?.preserveFiles||[]){let fe=String(Z).trim();fe&&(!V.length&&rt(fe)?S[os(fe.slice(1),Ke)]=!0:V.push(fe))}let z={};for(let Z of Object.keys(S)){let fe=Z.split("/");for(let be=1;be<fe.length;be++)z[fe.slice(0,be).join("/")]=!0}Object.assign(e.preserve,{open:!0,search:"",picked:S,expanded:z,patterns:V.join(`
`),patternsOpen:V.length>0}),L++,a(()=>{let Z=document.getElementById("preserve-files-dialog");Z?.showModal&&!Z.open&&Z.showModal(),document.getElementById("preserve-files-search")?.focus()},0),P()},e.closePreserveFiles=()=>{document.getElementById("preserve-files-dialog")?.close?.(),e.preserve.open=!1},e.savePreserveFiles=()=>{e.options.preserveFiles=la([...Qe(),...Q()]),e.closePreserveFiles()},e.preserveRows=()=>{if(!te)return[];let S=ue(),V=(be,Ze,kn)=>{let wt=!!e.preserve.picked[be],qn=S(be);return{kind:"file",path:be,label:kn,depth:Ze,state:qn?"all":"none",locked:!wt&&qn,note:!wt&&qn?"matched by a pattern":wt&&!qn?"excluded by a pattern":""}},z=String(e.preserve.search||"").trim().toLowerCase();if(z)return te.files.filter(be=>be.toLowerCase().includes(z)).slice(0,300).map(be=>V(be,0,be));let Z=[],fe=(be,Ze)=>{let kn=te.dirs.get(be);for(let wt of kn.dirs){let qn=!!e.preserve.expanded[wt],ga=Q().includes(U(wt));Z.push({kind:"dir",path:wt,label:wt.slice(be?be.length+1:0)+"/",depth:Ze,open:qn,state:R(wt),locked:!1,note:ga?"whole folder":""}),qn&&fe(wt,Ze+1)}for(let wt of kn.files)Z.push(V(wt,Ze,wt.slice(be?be.length+1:0)))};return fe("",0),Z},e.preserveCount=()=>te?te.files.filter(C).length:0,e.togglePreserveDir=S=>{e.preserve.expanded[S]=!e.preserve.expanded[S]},e.togglePreserveFile=S=>{e.preserve.picked[S]=!e.preserve.picked[S],L++},e.togglePreserveFolder=S=>{let V=U(S),z=se(S),Z=Q().filter(be=>be!==V&&be!==z),fe=R(S)==="all"||Q().includes(V);for(let be of Pe(S))e.preserve.picked[be]=!1;L++,e.preserve.patterns=(fe?Z:[...Z,V]).join(`
`),fe&&Pe(S).some(C)&&(e.preserve.patterns=[...Z,z].join(`
`))};let G=[".github","","docs"].flatMap(S=>["README.md","README","README.markdown","README.rst","README.txt","readme.md"].map(V=>(S?S+"/":"")+V));e.readmePreserved=()=>{if(e.detectedType!=="repo")return!1;let S=(e.options?.preserveFiles||[]).map(V=>String(V).trim()).filter(Boolean);if(!S.length)return!1;try{let V=da(S);return G.some(z=>V(z))}catch{return!1}};function F(){let S={terms:e.terms&&!e.readmePreserved()?e.terms.split(`
`):[],image:!!e.options.image,link:!!e.options.link,repoId:e.repoId};e.source&&e.source.branch&&(S.branchName=e.source.branch);try{let V=parseGithubUrl(e.sourceUrl);S.repoName=`${V.owner}/${V.repo}`}catch{}return S}function Y(S,V,z){let Z=null,fe=0,be=()=>{if(e.detectedType!==S)return;Z&&a.cancel(Z);let Ze=++fe;e.previewStatus="loading",Z=a(()=>{Z=null;let kn=V();if(!kn){e.previewStatus="idle";return}t.post("/api/anonymize-preview",kn).then(wt=>{Ze===fe&&(z(wt.data,kn),e.previewStatus="ready")}).catch(()=>{Ze===fe&&(e.previewStatus="error")})},200)};return be.cancel=()=>{fe++,Z&&a.cancel(Z),Z=null},e.on("dispose",be.cancel),be}e.retryPreview=()=>{e.detectedType==="repo"&&M(),e.detectedType==="pr"&&ne(),e.detectedType==="gist"&&Le()};let M=Y("repo",()=>e.readme?{content:e.readme,options:F()}:null,S=>{if(typeof S?.content!="string")throw Error("Invalid preview response");e.anonymize_readme=S.content;let V="";try{let Z=parseGithubUrl(e.sourceUrl),fe=e.source.branch||e.details&&e.details.defaultBranch||"main";V=`https://github.com/${Z.owner}/${Z.repo}/raw/${fe}/`}catch{}let z=renderMD(e.anonymize_readme,V);e.html_readme=z,a(Prism.highlightAll,150)});function H(){!e.anonymize||!e.anonymize.terms||M()}async function ee(){let S=parseGithubUrl(e.sourceUrl),V=h();try{Ye();let z=await t.get(`/api/pr/${S.owner}/${S.repo}/${S.pullRequestId}`,{params:{connection:e.githubConnection}});if(!v(V))return;e.details=z.data,e.pullRequestId||(e.pullRequestId=S.repo+"-PR"+S.pullRequestId+"-"+generateRandomId(4))}catch(z){if(!v(V))return;throw z.data&&(r("ERRORS."+z.data.error).then(Z=>{e.addToast({title:"Error",date:new Date,body:Z}),e.error=Z},console.error),lt(z.data.error)),re("sourceUrl","missing",!1),z}finally{k(V)}}let K=et(new Map);function he(){let S=new Set,V=e.details&&e.details.pullRequest;if(!V)return S;typeof V.title=="string"&&S.add(V.title),typeof V.body=="string"&&S.add(V.body),typeof V.diff=="string"&&S.add(V.diff);let z=V.comments||[];for(let Z of z)typeof Z.author=="string"&&S.add(Z.author),typeof Z.body=="string"&&S.add(Z.body);return S}let ne=Y("pr",()=>{let S=he(),V=Array.from(S);return V.length===0?null:{contents:V,options:F()}},(S,V)=>{if(!Array.isArray(S?.contents)||S.contents.length!==V.contents.length||S.contents.some(fe=>typeof fe!="string"))throw Error("Invalid preview response");let z=V.contents,Z=new Map;for(let fe=0;fe<z.length&&fe<S.contents.length;fe++)Z.set(z[fe],S.contents[fe]);K.clear(),Z.forEach((fe,be)=>K.set(be,fe))});e.anonymizePrContent=function(S){return S&&(K.has(S)?K.get(S):"")};async function pe(){let S=parseGithubUrl(e.sourceUrl),V=h();try{Ye(),e.gistOAuthRequired=!1,e.gistAppRequired=!1;let z=await t.get(`/api/gist/source/${S.gistId}`);if(!v(V))return;e.details=z.data,e.gistId||(e.gistId="gist-"+S.gistId.substring(0,6)+"-"+generateRandomId(4))}catch(z){if(!v(V))return;if(z.data?.error==="github_app_reconnect_required"){e.gistAppRequired=!0,re("sourceUrl","missing",!1);return}if(z.data?.error==="github_oauth_required"){e.gistOAuthRequired=!0,re("sourceUrl","missing",!1);return}throw z.data&&(r("ERRORS."+z.data.error).then(Z=>{e.addToast({title:"Error",date:new Date,body:Z}),e.error=Z},console.error),lt(z.data.error)),re("sourceUrl","missing",!1),z}finally{k(V)}}let ye=et(new Map);function Te(){let S=new Set,V=e.details&&e.details.gist;if(!V)return S;typeof V.description=="string"&&S.add(V.description),typeof V.ownerLogin=="string"&&S.add(V.ownerLogin);let z=V.files||[];for(let fe of z)typeof fe.filename=="string"&&S.add(fe.filename),typeof fe.content=="string"&&S.add(fe.content);let Z=V.comments||[];for(let fe of Z)typeof fe.author=="string"&&S.add(fe.author),typeof fe.body=="string"&&S.add(fe.body);return S}let Le=Y("gist",()=>{let S=Te(),V=Array.from(S);return V.length===0?null:{contents:V,options:F()}},(S,V)=>{if(!Array.isArray(S?.contents)||S.contents.length!==V.contents.length||S.contents.some(fe=>typeof fe!="string"))throw Error("Invalid preview response");let z=V.contents,Z=new Map;for(let fe=0;fe<z.length&&fe<S.contents.length;fe++)Z.set(z[fe],S.contents[fe]);ye.clear(),Z.forEach((fe,be)=>ye.set(be,fe)),Be()});e.anonymizeGistContent=function(S){return S&&(ye.has(S)?ye.get(S):"")},e.previewGistFiles=[];function Be(){let S=e.details&&e.details.gist&&e.details.gist.files||[];e.previewGistFiles=S.map(V=>({filename:e.anonymizeGistContent(V.filename),content:e.anonymizeGistContent(V.content),language:V.language}))}e.watch("details.gist.files",Be,!0),e.watch("terms",Be);function st(){let S=e.conference;if(e.conference_data=null,!S)return;let V=S===E||e.isUpdate&&S===e._originalConference;S!==E&&(E=null),t.get("/api/conferences/"+S).then(z=>{e.conference===S&&(e.conference_data=z.data,e.conference_data.startDate=new Date(e.conference_data.startDate),e.conference_data.endDate=new Date(e.conference_data.endDate),!V&&(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.confere Line truncated
`).filter(be=>be),connection:e.githubConnection,fullName:`${z.owner}/${z.repo}`,repository:e.sourceUrl,reconnectRepositoryId:e.reconnectRepositoryId,options:e.options,source:e.source,conference:e.conference};e.details&&(Z.options.pageSource=e.details.pageSource),Ye();let fe=e.isUpdate?"/api/repo/"+e.repoId:"/api/repo/";t.post(fe,Z,{headers:{"Content-Type":"application/json"}}).then(()=>{b.clear(),window.location.href="/status/"+e.repoId},be=>{be.data&&(r("ERRORS."+be.data.error).then(Ze=>{e.error=Ze},console.error),lt(be.data.error),["quota_exceeded","subscription_required_for_never_expiration"].includes(be.data.error)&&(be.data.error==="subscription_required_for_never_expiration"&&(e._existingNever=!1),e.hostingQuotaBlocked=!0,e.hostingReview=!0,it(()=>document.getElementById("repository-hosting")?.scrollIntoView({block:"center"}))))}).finally(()=>{V.disabled=!1})},e.anonymizeGist=S=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(bt())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let V=S.currentTarget||S.target.closest?.("button")||S.target;V.disabled=!0;let z=parseGithubUrl(e.sourceUrl),Z={gistId:e.gistId,terms:e.terms.trim().split(`
`).filter(be=>be),source:{gistId:z.gistId},options:e.options,conference:e.conference};Ye();let fe=e.isUpdate?"/api/gist/"+e.gistId:"/api/gist/";t.post(fe,Z,{headers:{"Content-Type":"application/json"}}).then(()=>{b.clear(),window.location.href="/gist/"+e.gistId},be=>{be.data&&(r("ERRORS."+be.data.error).then(Ze=>{e.error=Ze},console.error),lt(be.data.error))}).finally(()=>{V.disabled=!1})},e.anonymizePullRequest=S=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(bt())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let V=S.currentTarget||S.target.closest?.("button")||S.target;V.disabled=!0;let z=parseGithubUrl(e.sourceUrl),Z={pullRequestId:e.pullRequestId,connection:e.githubConnection,terms:e.terms.trim().split(`
`).filter(be=>be),source:{repositoryFullName:`${z.owner}/${z.repo}`,pullRequestId:z.pullRequestId},options:e.options,conference:e.conference};Ye();let fe=e.isUpdate?"/api/pr/"+e.pullRequestId:"/api/pr/";t.post(fe,Z,{headers:{"Content-Type":"application/json"}}).then(()=>{b.clear(),window.location.href="/pr/"+e.pullRequestId},be=>{be.data&&(r("ERRORS."+be.data.error).then(Ze=>{e.error=Ze},console.error),lt(be.data.error))}).finally(()=>{V.disabled=!1})},e.watch("conference",()=>{st()}),e.termHints=[],e.matchTermAsWritten=S=>{e.terms=Vu(e.terms,S)},e.watch("options.preserveFiles",()=>{e.detectedType==="repo"&&M()}),e.watch("terms",()=>{e.termHints=Mu(e.terms),e.detectedType==="repo"&&H(),e.detectedType==="pr"&&ne(),e.detectedType==="gist"&&Le()}),e.watch("options.image",()=>{e.detectedType==="repo"&&H(),e.detectedType==="pr"&&ne(),e.detectedType==="gist"&&Le()}),e.watch("options.link",()=>{e.detectedType==="repo"&&H(),e.detectedType==="pr"&&ne(),e.detectedType==="gist"&&Le()}),e.watch("details",()=>{e.detectedType==="pr"&&ne(),e.detectedType==="gist"&&Le()},!0)},pa=function(e,t,s,i,o,r){let a=At();Lu();let u=vn();e.on("dark-mode",(U,se)=>{e.aceOption&&(se?e.aceOption.theme="nord_dark":e.aceOption.theme="chrome")});let c=0,m=null,g=null;e.fileLoadingSlow=!1,e.fileReceivedBytes=0;function v(){m&&(m.resolve(),m=null),g&&(a.timeout.cancel(g),g=null)}let h=!1;e.on("dispose",()=>{h=!0,c++,v(),k&&k.resolve()}),e.files=[],e.isMac=/Mac|iPhone|iPad|iPod/.test(navigator.platform||navigator.userAgent),e.fileSearchQuery="",e.fileSearchResults=null,e.fileSearchLoading=!1,u(document,"click",U=>{e.symbolsOpen&&!U.target.closest?.(".symbols")&&(e.symbolsOpen=!1),e.moreOpen&&!U.target.closest?.(".tb-more")&&(e.moreOpen=!1),e.tocOpen&&!U.target.closest?.(".tb-toc-m")&&(e.tocOpen=!1),e.gotoOpen&&U.target.isConnected&&!U.target.closest?.(".goto-pop, .btn-goto, .tb-more")&&(e.gotoOpen=!1),e.accountOpen&&!U.target.closest?.(".acct")&&(e.accountOpen=!1),e.helpOpen&&!U.target.closest?.(".vb-help")&&(e.helpOpen=!1)}),u(document,"keydown",U=>{U.key==="Escape"&&(e.symbolsOpen=!1,e.moreOpen=!1,e.tocOpen=!1,e.gotoOpen=!1,e.accountOpen=!1,e.helpOpen=!1),(U.ctrlKey||U.metaKey)&&!U.altKey&&U.key&&U.key.toLowerCase()==="f"&&e.type==="html"&&window.document.querySelector(".reading-layout")&&(U.preventDefault(),e.toggleMdFind(!0))}),u(document,"keydown",function(U){if((U.metaKey||U.ctrlKey)&&U.key==="k"){U.preventDefault();var se=document.querySelector(".tree-search-input");se&&(se.focus(),se.select())}});var k=null;e.onFileSearchChange=function(){k&&(k.resolve(),k=null);let U=e.fileSearchQuery;if(!U||U.length<2){e.fileSearchResults=null,e.fileSearchLoading=!1;return}e.fileSearchLoading=!0;let se=r.defer();k=se,t.get(`/api/repo/${e.repoId}/files/search?q=${encodeURIComponent(U)}`,{timeout:se.promise}).then(function(Q){if(!(h||k!==se)){k=null,e.fileSearchLoading=!1;var te={};e.files.forEach(function(H){te[(H.path||"")+"/"+H.name]=!0});for(var L=[],x={},B=0;B<Q.data.length;B++){var ue=Q.data[B];if(ue.path)for(var we=ue.path.split("/"),Pe="",C=0;C<we.length;C++){var R=Pe;Pe=Pe?Pe+"/"+we[C]:we[C];var P=R+"/"+we[C];!te[P]&&!x[P]&&(x[P]=!0,L.push({name:we[C],path:R}))}}L.sort(function(H,ee){return(H.path||"").split("/").length-(ee.path||"").split("/").length}),L.length>0&&e.files.push.apply(e.files,L);for(var G=[],F=0;F<Q.data.length;F++){var Y=Q.data[F],M=(Y.path||"")+"/"+Y.name;!te[M]&&Y.size!=null&&(G.push(Y),te[M]=!0)}G.length>0&&e.files.push.apply(e.files,G),e.fileSearchResults=Q.data}},function(){!h&&k===se&&(k=null,e.fileSearchLoading=!1,e.fileSearchResults=[])})};let A={yml:"yaml",txt:"text",py:"python",js:"javascript",ts:"typescript"},w=["license","txt"],b=["png","jpg","jpeg","gif","svg","ico","bmp","tiff","tif","webp","avif","heif","heic"],E=["wav","mp3","ogg","wma","flac","aac","m4a"],N=["mp4","avi","webm","mov","mpg","mpeg","mkv","flv","wmv","3gp","3g2","m4v","f4v","f4p","f4a","f4b"];e.on("routeUpdate",function(U,se){if(e.repoId!=i.repoId)return Qe();if((i.path||"")!=e.filePath){window.matchMedia?.("(max-width: 767px)").matches&&(e.sidebarCollapsed=!0),e.filePath=i.path||"",e.paths=e.filePath.split("/").filter(Q=>Q&&Q.trim().length>0),rt();for(let Q=0;Q<e.paths.length-1;Q++){let te=Q>0?e.paths.slice(0,Q).join("/"):"";e.files.some(x=>x.path===te)||e.getFiles(te)}}});function O(){if(e.paths[0]!="")return;let U=["readme.md","readme.txt","readme.org","readme.1st","readme"],se={};for(let te of e.files)te.name.toLowerCase().indexOf("readme")>-1&&(se[te.name.toLowerCase()]=te.name);let Q=null;for(let te of U)if(se[te]){Q=te;break}if(!Q&&Object.keys(se).length>0&&(Q=Object.keys(se)[0]),Q){let te=s.url();te[te.length-1]!="/"&&(te+="/"),s.url(te+encodePathForUrl(se[Q]))}}e.fileCounts=null;let q=0,I=new Set,j=!1;e.getFiles=function(U,se=!1){let Q=e.repoId,te=q;return t.get(`/api/repo/${e.repoId}/files/?path=${encodeURIComponent(U)}&v=${e.options.lastUpdateDate}`).then(function(L){if(h||Q!==e.repoId||te!==q)return[];let x=U||"";return e.files=e.file Line truncated
`).forEach((se,Q)=>{for(let[te,L]of me){let x=te.exec(se);if(x&&!/^(if|for|while|switch|return|catch)$/.test(x[1])){U.push({name:x[1],kind:L,line:Q+1});break}}}),ke={content:e.content,list:U.slice(0,300)},ke.list},e.goToSymbol=function(U){e.symbolsOpen=!1;let se=e.codeEditor;se&&(se.scrollToLine(U-1,!0,!0,()=>{}),se.gotoLine(U,0,!0),window.history.replaceState(null,"",window.location.pathname+window.location.search+"#L"+U),window.dispatchEvent(new HashChangeEvent("hashchange")))},e.gotoLine=function(){e.codeEditor&&(e.moreOpen=!1,e.gotoError="",e.gotoValue=String(e.codeEditor.getCursorPosition().row+1),e.gotoOpen=!0,setTimeout(()=>{let U=window.document.getElementById("goto-input");U&&(U.focus(),U.select())},0))},e.closeGoto=function(){e.gotoOpen=!1,e.gotoError="",e.codeEditor?.focus()},e.submitGoto=function(){let U=e.codeEditor;if(!U)return;let se=/^\s*:?\s*(\d+)\s*(?:[:,]\s*(\d+))?\s*$/.exec(e.gotoValue||""),Q=U.session.getLength();if(!se||+se[1]<1||+se[1]>Q){e.gotoError="Enter a line from 1 to "+Q;return}U.gotoLine(+se[1],se[2]?Math.max(0,+se[2]-1):0,!0),e.gotoOpen=!1,e.gotoError="",U.focus()},e.rootEntries=function(){return[...e.files||[]].sort((U,se)=>{let Q=U.size==null,te=se.size==null;return Q!==te?Q?-1:1:U.name.localeCompare(se.name)})},e.formatSize=function(U){if(U==null)return"";if(U<1024)return U+" B";let se=U/1024;return se<1024?se.toFixed(1)+" KB":(se/1024).toFixed(1)+" MB"},e.fileSize=function(U){if(!U)return null;let se=U.replace(/^\/+/,""),Q=(e.files||[]).find(te=>(te.path?te.path+"/":"")+te.name===se);return Q&&Q.size!=null?Q.size:null},e.revealFolder=function(U){e.sidebarHidden=!1,e.sidebarCollapsed=!1,it(()=>{let se=window.document.querySelector('.files a[data-path="/'+(window.CSS?.escape?window.CSS.escape(U):U)+'"]');se&&(se.closest("li")?.classList.contains("open")||se.click(),se.scrollIntoView({block:"nearest"}),se.focus())})},e.redactionCount=function(){return typeof e.content!="string"?0:((e.type==="html"?e.content.replace(/<[^>]*>/g," "):e.content).match(Po)||[]).length},e.renderRedacted=$u;let _e=U=>U.toLowerCase().trim().replace(/[^a-z0-9\s-]/g,"").replace(/\s+/g,"-").slice(0,60)||"section";e.renderReadme=function(U){let se=e.renderRedacted(U);if(!se||typeof window.DOMParser!="function")return se;let Q=new window.DOMParser().parseFromString("<div>"+se+"</div>","text/html"),te={};return Q.querySelectorAll("h1, h2, h3").forEach(L=>{let x=L.id||_e(L.textContent);te[x]?x+="-"+ ++te[x]:te[x]=1,L.id=x}),Q.body.firstChild.innerHTML};let Ne={content:null,list:[]};e.readmeToc=function(){if(e.type!=="html"||typeof e.content!="string")return[];if(Ne.content===e.content)return Ne.list;let se=[...new window.DOMParser().parseFromString("<div>"+e.renderReadme(e.sanitize?e.sanitize(e.content):e.content)+"</div>","text/html").querySelectorAll("h2, h3")].map(Q=>({id:Q.id,text:Q.textContent.trim(),level:Q.tagName==="H3"?3:2})).slice(0,40);return Ne={content:e.content,list:se},se},e.activeHeading=null,u(window,"scroll",()=>{let U=e.readmeToc?e.readmeToc():[];if(!U.length)return;let se=150,Q="",te="";for(let L of U){let x=window.document.getElementById(L.id);if(!x)continue;let B=x.getBoundingClientRect().top;B<se?Q=L.id:!te&&B<window.innerHeight-80&&(te=L.id)}te&&(Q=te),e.activeHeading!==Q&&(e.activeHeading=Q)},{capture:!0,passive:!0}),e.scrollToHeading=function(U){if(!U){(window.document.querySelector(".explorer-content, .file-card-body, .main-pane")||window).scrollTo({top:0,behavior:"smooth"}),e.activeHeading="";return}let se=window.document.getElementById(U);se&&se.scrollIntoView({behavior:"smooth",block:"start"}),e.activeHeading=U},e.redactParts=function(U){let se=[],Q=0,te,L=/\bXXXX-(\d+)\b/g;for(U=String(U||"");te=L.exec(U);)te.index>Q&&se.push({t:U.slice(Q,te.index)}),se.push({n:te[1]}),Q=te.index+te[0].length;return Q<U.length&&se.push({t:U.slice(Q)}),se},e.pathCopied=!1,e.copyPath=async function(){window.navigator.clipboard?.writeText&&(await window.navigator.clipboard.writeText(e.filePath||""),e.pathCopied=!0,setTimeout(()=>{e.pathCopied=!1},1600))},e.contentCopied=!1,e.copyContent=async function(){if(typeof e.content!="string"||!window.navigator.clipboard?.writeText)return;let U=e.content;if(e.type==="html"&&e.url)try{U=await(await window.fetch(e.url,{credentials:"same-origin"})).text()}catch{return}await window.navigator.clipboard.writeText(U),e.contentCopied=!0,setTimeout(()=>{e.contentCopied=!1},1600)};function Re(U){return A[U]?A[U]:U}function Je(U){return U=="pdf"?"pdf":U=="html"||U=="htm"?"html-doc":U=="md"?"md":U=="org"?"org":U=="ipynb"?"IPython":w.indexOf(U)>-1?"text":b.indexOf(U)>-1?"image":N.indexOf(U)>-1?"media":E.indexOf(U)>-1?"audio":"code"}function Ke(U,se){let Q=c;if(!U){e.type="error",e.content="no_file_selected";return}let te=e.type;(te==="code"||te==="text")&&Mo().catch(()=>{}),e.type="loading",e.content="loading",e.fileLoadingSlow=!1,e.fileReceivedBytes=0;let L=r.defer();m=L,g=a.timeout(()=>{!h&&Q===c&&e.type==="loading"&&(e.fileLoadingSlow=!0)},1500);let x=se&&se.sha|| Line truncated
`+w.join(`
`)],{type:"text/csv"}),E=document.createElement("a");E.href=URL.createObjectURL(b),E.download=i.username+"-repositories.csv",E.click()},e.showStatusMessage=h=>{let k=h.statusMessage||"(no message)";window.prompt(`Status message for ${h.repoId} (${h.status}):`,k)},e.fetchGithubInfo=h=>{let k=window.open("","_blank");k&&k.document.write("<pre>Loading GitHub info for "+h.repoId+"...</pre>"),t.get("/api/admin/repos/"+h.repoId+"/github").then(A=>{k&&(k.document.open(),k.document.write('<pre style="font:13px monospace;padding:16px;white-space:pre-wrap">'+JSON.stringify(A.data,null,2).replace(/[<>]/g,w=>w==="<"?"&lt;":"&gt;")+"</pre>"),k.document.close())},A=>{let w=A&&A.data?JSON.stringify(A.data,null,2):String(A);k&&(k.document.body.innerHTML='<pre style="color:#B42318;padding:16px">'+w+"</pre>")})};function c(h){t.get("/api/admin/users/"+h+"/repos",{}).then(k=>{e.repositories=k.data},k=>{console.error(k)})}function m(h){t.get("/api/admin/users/"+h,{}).then(k=>{e.userInfo=k.data},k=>{console.error(k)})}m(i.username),c(i.username),e.banUser=()=>{confirm(`Ban user ${i.username}?`)&&t.post(`/api/admin/users/${i.username}/ban`).then(()=>m(i.username),h=>console.error(h))},e.activateUser=()=>{t.post(`/api/admin/users/${i.username}/activate`).then(()=>m(i.username),h=>console.error(h))},e.promoteUser=()=>{confirm(`Promote ${i.username} to admin?`)&&t.post(`/api/admin/users/${i.username}/promote`).then(()=>m(i.username),h=>console.error(h))},e.demoteUser=()=>{confirm(`Remove admin privileges from ${i.username}?`)&&t.post(`/api/admin/users/${i.username}/demote`).then(()=>m(i.username),h=>console.error(h))},e.tokens=[],e.tokenForm={name:"",plaintext:null};function g(){t.get("/api/admin/tokens").then(h=>{e.tokens=h.data||[]},h=>{h.status!==401&&h.status!==403&&console.error(h)})}g(),e.createToken=()=>{e.tokenForm.name&&t.post("/api/admin/tokens",{name:e.tokenForm.name}).then(h=>{e.tokenForm.plaintext=h.data.token,e.tokenForm.name="",g()},h=>console.error(h))},e.revokeToken=h=>{confirm(`Revoke token "${h.name}"?`)&&t.delete("/api/admin/tokens/"+h.id).then(()=>g(),k=>console.error(k))},e.removeCache=h=>{confirm("Remove cached files for "+h.repoId+"?")&&t.delete("/api/admin/repos/"+h.repoId).then(()=>c(i.username),k=>console.error(k))},e.removeRepository=h=>{confirm("Remove repository "+h.repoId+"?")&&t.delete("/api/repo/"+h.repoId+"/").then(()=>c(i.username),k=>console.error(k))},e.updateRepository=h=>{let k=et({title:`Refreshing ${h.repoId}...`,date:new Date,body:`The repository ${h.repoId} is going to be refreshed.`});e.toasts.push(k),t.post(`/api/repo/${h.repoId}/refresh`).then(A=>{A.data.status=="ready"?k.title=`${h.repoId} is refreshed.`:k.title=`Refreshing of ${h.repoId}.`},A=>{k.title=`Error during the refresh of ${h.repoId}.`,k.body=A.body})},e.getGitHubRepositories=h=>{t.get(`/api/user/${e.userInfo.username}/all_repositories`,{params:{force:"1"}}).then(k=>{e.userInfo.repositories=k.data})};let v=null;e.watch("query",()=>{o.timeout.cancel(v),v=o.timeout(()=>{c(i.username)},500)},!0)},sc=function(e,t,s){let i=At(),o=vn();e.Math=Math,e.watch("user.status",()=>{e.user==null&&s.url("/")}),e.user==null&&s.url("/"),e.conferences=[],e.total=-1,e.totalPage=0,e.statusCounts=[];let r=A=>{if(A.key==="/"&&!["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName)){A.preventDefault();let w=document.querySelector('.admin-filter-toolbar input[type="search"]');w&&w.focus()}};o(document,"keydown",r),e.on("dispose",()=>document.removeEventListener("keydown",r)),e.clearFilter=A=>{A==="dateRange"?(e.query.dateFrom="",e.query.dateTo=""):e.query[A]="",e.query.page=1},e.chips=[];let a=()=>{let A=[];(e.query.dateFrom||e.query.dateTo)&&A.push({key:"dateRange",label:"Date",value:(e.query.dateFrom||"\u2026")+" \u2013 "+(e.query.dateTo||"\u2026")}),e.chips=A};e.statusCountFor=A=>{let w=(e.statusCounts||[]).find(b=>b._id===A);return w?w.count:0},e.toggleSortDirection=()=>{e.query.direction=e.query.direction==="asc"?"desc":"asc"},e.sortBy=A=>{e.query.sort===A?e.query.direction=e.query.direction==="asc"?"desc":"asc":(e.query.sort=A,e.query.direction="desc"),e.query.page=1},e.sortIcon=A=>e.query.sort===A?e.query.direction==="asc"?"fa-arrow-up":"fa-arrow-down":"";let u="admin.conferences.filterPrefs",c={page:1,limit:25,sort:"name",direction:"asc",search:"",dateFrom:"",dateTo:"",ready:!0,expired:!0,removed:!1,error:!0,preparing:!0},m=loadFilterPrefs(u)||{};e.query=Object.assign({},c,m,{page:1,search:""});let g=s.search();g.search&&(e.query.search=g.search);let v="admin.conferences.presets";e.presets=JSON.parse(localStorage.getItem(v)||"[]"),e.savePreset=()=>{let A=window.prompt("Preset name:");if(!A)return;let w=Object.assign({},e.query);delete w.page,e.presets=(e.presets||[]).filter(b=>b.name!==A),e.presets.push({name:A,query:w}),localStorage.setItem(v,JSON.stringify(e.presets))},e.applyPreset=A=>{Object.assign(e.query,A.query,{page:1})},e.deletePreset=A=>{e.presets=(e.presets||[]).filter(w=>w.name!==A.name),localStorage.setItem(v,JS Line truncated
`).map((_e,Ne)=>Ne===0?_e:ke+_e).join(`
`)}else typeof D=="number"||typeof D=="boolean"?me=String(D):me=JSON.stringify(D);de.push(`${Ee}${me}${re}`)}),de.push("}"),de.join(`
`)}function m(E){let N=[],O="",q=/(\w+):(>=|<=|!=|>|<|=)?([^\s]+)/g,I=0,j;for(;j=q.exec(E);)O+=E.slice(I,j.index),I=q.lastIndex,N.push({key:j[1],op:j[2]||"=",val:j[3]});return O+=E.slice(I),{filters:N,free:O.trim().toLowerCase()}}function g(E,N){for(let O of N.filters){let q=(j,de,ie)=>{let D=parseFloat(j),X=parseFloat(de);return ie==="="?String(j)===String(de):ie==="!="?String(j)!==String(de):ie===">="?D>=X:ie==="<="?D<=X:ie===">"?D>X:ie==="<"?D<X:!0},I;if(O.key==="code")I=E.displayMessage;else if(O.key==="module")I=E.module;else if(O.key==="status")I=E._status;else if(O.key==="url")I=E._url;else if(O.key==="repo")I=E._repoId;else if(O.key==="level")I=E.level;else continue;if(I==null||!q(I,O.val,O.op))return!1}return!(N.free&&((E.displayMessage||"")+" "+(E.module||"")+" "+(E._url||"")+" "+JSON.stringify(E.raw||[])).toLowerCase().indexOf(N.free)===-1)}function v(){let E=m(e.query.search||"");e.parsedFilterCount=E.filters.length;let N=e.query.bucket,O=e.entries.filter(ie=>N&&ie._bucket!==N?!1:g(ie,E)),q=e.query.group;if(q){let ie=le=>q==="module"?le.module:le.displayMessage||le.message||"_",D=new Map;for(let le of O){let Ee=ie(le);if(D.has(Ee)){let re=D.get(Ee);re.count++,re._related.push(le),new Date(le.ts)>new Date(re.ts)&&(re.ts=le.ts,re._url=le._url,re._status=le._status),new Date(le.ts)<new Date(re._firstSeen)&&(re._firstSeen=le.ts)}else{let re=Object.assign({},le);re._key=`${q}:${Ee}`,re._related=[le],re._firstSeen=le.ts,re._lastHourCount=0,re.count=1,D.set(Ee,re)}}let X=Date.now()-3600*1e3;for(let le of D.values())le._lastHourCount=le._related.filter(Ee=>new Date(Ee.ts).getTime()>=X).length;O=Array.from(D.values())}else O=O.map((ie,D)=>(ie._key="row:"+D+":"+ie.ts,ie._related=[ie],ie._firstSeen=ie.ts,ie._lastHourCount=0,ie.count=1,ie));let I=ie=>({error:0,warn:1,info:2})[ie._bucket]??1;e.query.sort==="count"?O.sort((ie,D)=>I(ie)-I(D)||D.count-ie.count||new Date(D.ts)-new Date(ie.ts)):O.sort((ie,D)=>I(ie)-I(D)||new Date(D.ts)-new Date(ie.ts)),e.visible=O;let j=!!(e.query.bucket||(e.query.search||"").trim()),de=!j&&(e.stats?.severity?.error||0)>0&&!O.some(ie=>ie._bucket==="error")&&e.entries.length<1500;(j&&!O.length||de)&&e.canLoadMore?.()&&!e._autoLoading&&e.entries.length<2500&&(e._autoLoading=!0,h(!0))}function h(E){let N=E?e.entries.length:0,O=E?e.pageSize:Math.max(e.pageSize,e.entries.length||e.pageSize);t.get("/api/admin/errors",{params:{offset:N,limit:O}}).then(q=>{let I=(q.data.entries||[]).map(u);e.entries=E?e.entries.concat(I):I,e.available=!!q.data.available,e.cap=q.data.max||e.cap,e.total=q.data.total||e.entries.length,e._autoLoading=!1,v()},q=>{e._autoLoading=!1,console.error(q)})}e.loadMore=()=>h(!0),e.canLoadMore=()=>e.entries.length<e.total;function k(){t.get("/api/admin/errors/stats").then(E=>{let N=E.data||{},O=N.prev24h?Math.round((N.last24h-N.prev24h)/N.prev24h*100):0;e.stats={last24h:N.last24h||0,prev24h:N.prev24h||0,delta:O,severity:N.severity||{error:0,warn:0,info:0},unique:N.unique||{error:0,warn:0,info:0},buckets:N.buckets||[],dropped:N.dropped||0},v()},E=>console.error(E))}function A(){h(),k()}e.barPx=(E,N)=>{let O=e.stats.buckets||[],q=0,I=0;for(let D of O)q=Math.max(q,(D.error||0)+(D.warn||0)),I=Math.max(I,D.info||0);let j=E[N]||0;if(!j)return 0;if(N==="info")return I?Math.max(2,Math.round(j/I*(q?16:60))):0;let de=(E.error||0)+(E.warn||0),ie=Math.round(de/q*44);return Math.max(4,Math.round(j/de*ie))},e.bucketTitle=E=>`${new Date(E.hour).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})} \xB7 ${E.error||0} err \xB7 ${E.warn||0} warn \xB7 ${E.info||0} info`,e.toggle=E=>{e.expanded[E._key]=!e.expanded[E._key]},e.setBucket=E=>{e.query.bucket=E},e.refreshNow=A,e.clearAll=()=>{confirm("Clear all captured errors?")&&t.delete("/api/admin/errors").then(A,E=>console.error(E))},e.exportCsv=()=>{let E=["ts","level","module","displayMessage","_status","_url","_repoId"],N=[E.join(",")];for(let j of e.visible)N.push(E.map(de=>{let ie=j[de]==null?"":String(j[de]);return/[",\n]/.test(ie)?`"${ie.replace(/"/g,'""')}"`:ie}).join(","));let O=new Blob([N.join(`
`)],{type:"text/csv;charset=utf-8"}),q=URL.createObjectURL(O),I=document.createElement("a");I.href=q,I.download=`errors-${new Date().toISOString().slice(0,19)}.csv`,document.body.appendChild(I),I.click(),document.body.removeChild(I),URL.revokeObjectURL(q)};function w(E){e.copyHint=`${E} copied`,o.timeout(()=>{e.copyHint=""},1500)}e.copyJson=E=>{navigator.clipboard.writeText(E._detailJson).then(()=>w("JSON"))},e.copyCurl=E=>{if(!E._url)return;let O=`curl -X ${E._method||"GET"} '${window.location.origin}${E._url}'`;navigator.clipboard.writeText(O).then(()=>w("curl"))},A();let b=i(()=>{e.query.autoRefresh&&A()},15e3);e.on("dispose",()=>i.cancel(b)),e.watch("query.search",v),e.watch("query.bucket",v),e.watch("query.sort",v),e.watch("query.group",v)},rc=function(e,t,s,i){if(e.Math=Math,e.watch("user.status",()=>{e.user==null&&s.url("/")}),e.user==null){s.url("/");return}e.data=null,e.loading=!0,e.error=null,e.performance=null,e.performanceMinutes=15,e.performanceTab="routes",e.cacheReport=null,e.cacheError=null,e.cacheMinutes=60,e.cacheTraffic="all",e.ovView=["performance","cache"].includes((window.location.hash||"").slice(1))?window.location.hash.slice(1):"summary",e.setOvView=function(b){e.ovView=b;try{window.history.replaceState(null,"",b==="summary"?window.location.pathname:"#"+b)}catch{}};var o=!1;e.loadCache=function(){if(!o){o=!0;var b=e.cacheMinutes;t.get("/api/admin/cache",{params:{minutes:b}}).then(function(E){b===e.cacheMinutes&&(e.cacheReport=E.data,e.cacheError=E.data.available?null:E.data.reason||"Cache monitoring is unavailable.")},function(){e.cacheError="Could not refresh cache monitoring. Displayed values may be stale."}).finally(function(){o=!1,b!==e.cacheMinutes&&e.loadCache()})}},e.cacheRows=function(){return(e.cacheReport?.rows||[]).filter(function(b){return e.cacheTraffic==="all"||b.traffic===e.cacheTraffic})},e.cacheRate=function(b,E){var N=e.cacheRows(),O=function(j){return N.filter(function(de){return de.name===j}).reduce(function(de,ie){return de+ie[E]},0)},q=O(b+"_hit"),I=O(b+"_miss");return q+I?(100*q/(q+I)).toFixed(1)+"%":"No samples"},e.cacheEventName=function(b){return b.replaceAll("_"," ")},e.cacheP95=function(b){var E=0,N=e.cacheReport?.latencyBucketsMs||[];if(!b.count)return"No samples";if(!b.ms)return"Not timed";for(var O=0;O<=N.length;O++)if(E+=b["b"+O]||0,E>=Math.ceil(b.count*.95))return O<N.length?"\u2264 "+N[O]+" ms":"> 10 s";return"No samples"},e.performanceError=null,e.formatMs=function(b){return b==null?"":b<1e3?b+" ms":+(b/1e3).toFixed(1)+" s"},e.latencyBound=function(b,E){return b.count?b[E]==null?"> 60 s":"\u2264 "+e.formatMs(b[E]):"No samples"},e.firstByteBound=function(b){return e.latencyBound({count:b.firstByteCount,p95UpperMs:b.firstByteP95UpperMs},"p95UpperMs")},e.sampleAge=function(b){return Math.max(0,Math.round((Date.now()-b.sampledAt)/1e3))},e.peakRss=function(b){return(e.performance.runtimeSeries||[]).filter(function(E){return E.instance===b.instance}).reduce(function(E,N){return Math.max(E,N.rss)},b.memory.rss)},e.performanceWarning=function(b){return e.sampleAge(b)>45||b.droppedBatches||b.droppedMetrics||b.sockets?.closeWait>0||b.eventLoop?.p95Ms>100||b.memoryLimitBytes&&b.memory.rss>b.memoryLimitBytes*.8};var r=!1;e.loadPerformance=function(){var b=e.performanceMinutes;e.performance?.windowMinutes&&e.performance.windowMinutes!==b&&(e.performance=null),!r&&(r=!0,t.get("/api/admin/performance",{params:{minutes:b}}).then(function(E){b===e.performanceMinutes&&(e.performance=E.data,e.performanceError=E.data.available?null:"Performance monitoring is unavailable. Request history may be incomplete.")},function(){b===e.performanceMinutes&&(e.performanceError="Could not refresh performance monitoring. Displayed samples may be stale.")}).finally(function(){r=!1,b!==e.performanceMinutes&&e.loadPerformance()}))};function a(b){if(b==null)return"\u2014";for(var E=["B","KB","MB","GB","TB"],N=0,O=b;O>=1024&&N<E.length-1;)O/=1024,N++;return O.toFixed(N>0?1:0)+" "+E[N]}e.humanBytes=a;function u(b){if(!b)return"\u2014";var E=Math.floor(b/86400),N=Math.floor(b%86400/3600),O=Math.floor(b%3600/60);return E>0?E+"d "+(N<10?"0":"")+N+"h":N>0?N+"h "+(O<10?"0":"")+O+"m":O+"m"}e.humanDuration=u;function c(b){return b==null?"\u2014":b>=1e6?(b/1e6).toFixed(1)+"M":b>=1e3?(b/1e3).toFixed(1)+"K":String(b)}e.humanNum=c,e.queueTotal=function(b){return b?(b.waiting||0)+(b.active||0)+(b.delayed||0)+(b.failed||0):0},e.statusCount=function(b){if(!e.data||!e.data.repos)return 0;for(var E=e.data.repos.statusBreakdown||[],N=0;N<E.length;N++)if(E[N]._id===b)return E[N].count;return 0},e.barPct=function(b){var E=e.data&&e.data.repos?e.data.repos.total:0;if(!E)return 0;var N=[b];b==="expired"&&N.push("expiring"),b==="removed"&&N.push("removing"),b==="preparing"&&N.push("download");var O=0;return N.forEach(function(q){O+=e.statusCount(q)}),Math.max(.4,O/E*100)},e.errPct=function(b){if(!e.data||!e.data.errors)return 0;var E=Math.max(e.data.errors.severity.error,e.data.errors.severity.warn,e.data.erro Line truncated
`).length+1)),placeholder:`Jane Smith
MIT CSAIL
jane.smith@example.org`},null,2),[[s,{state:e.viewState,set:a=>{e.terms=a},value:e.terms,form:"anonymize",options:{debounce:250}}]]),t[86]||(t[86]=n("small",{class:"form-text text-muted"},"One term per line.",-1)),n("details",iN,[t[83]||(t[83]=n("summary",null,"Regex & replacement syntax",-1)),t[84]||(t[84]=h()),n("small",rN,[t[77]||(t[77]=h("Regex is supported. Replaced by ",-1)),n("code",null,u(e.site_options?.ANONYMIZATION_MASK)+"-[N]",1),t[78]||(t[78]=h(", or use ",-1)),t[79]||(t[79]=n("code",null,"term=>replacement",-1)),t[80]||(t[80]=h(" to pick your own (e.g. ",-1)),t[81]||(t[81]=n("code",null,"Anonymous=>ABC",-1)),t[82]||(t[82]=h(").",-1))])]),T(n("div",aN,"Regex characters detected. Escape them if unintentional.",512),[[Y,e.termsRegexWarning]]),T(n("div",lN,"Terms are in an invalid format.",512),[[Y,e.anonymize?.terms?.errors?.format]])])],512),[[Y,e.detectedType]]),T(n("section",dN,[t[107]||(t[107]=n("h2",{class:"paper-section-eyebrow"},"Display",-1)),T(n("div",null,[n("div",uN,[T(n("input",cN,null,512),[[s,{state:e.viewState,set:a=>{e.options.link=a},value:e.options?.link,form:"anonymize",options:{}}]]),t[88]||(t[88]=n("label",{class:"form-check-label",for:"link"},"Keep links",-1))]),n("div",pN,[T(n("input",fN,null,512),[[s,{state:e.viewState,set:a=>{e.options.image=a},value:e.options?.image,form:"anonymize",options:{}}]]),t[89]||(t[89]=n("label",{class:"form-check-label",for:"image"},"Display images",-1))]),n("div",mN,[T(n("input",hN,null,512),[[s,{state:e.viewState,set:a=>{e.options.pdf=a},value:e.options?.pdf,form:"anonymize",options:{}}]]),t[90]||(t[90]=n("label",{class:"form-check-label",for:"pdf"},"Display PDFs",-1))]),n("div",vN,[T(n("input",gN,null,512),[[s,{state:e.viewState,set:a=>{e.options.notebook=a},value:e.options?.notebook,form:"anonymize",options:{}}]]),t[91]||(t[91]=n("label",{class:"form-check-label",for:"notebook"},"Display Notebooks",-1))]),n("div",yN,[T(n("input",{class:"form-check-input",type:"checkbox",id:"page",name:"page",disabled:!e.details?.hasPage||e.details?.pageSource&&e.details?.pageSource?.branch!==e.source?.branch},null,8,bN),[[s,{state:e.viewState,set:a=>{e.options.page=a},value:e.options?.page,form:"anonymize",options:{}}]]),t[92]||(t[92]=n("label",{class:"form-check-label",for:"page"},"GitHub Pages",-1)),e.details?.hasPage?c("v-if",!0):(l(),d("small",wN,u(e.fmt?.translate("WARNINGS.page_not_enabled_on_repo")),1)),e.details?.hasPage&&e.details?.pageSource?.branch&&e.source?.branch&&e.details.pageSource.branch!==e.source.branch?(l(),d("small",kN,u(e.fmt?.translate("WARNINGS.page_branch_mismatch",{pageBranch:e.details?.pageSource?.branch,selectedBranch:e.source?.branch})),1)):c("v-if",!0)])],512),[[Y,e.detectedType==="repo"]]),e.detectedType==="repo"&&(e.options.image||e.options.pdf)?(l(),d("p",CN,[...t[93]||(t[93]=[h("Images and PDFs are served unchanged. Review their contents and metadata before sharing. ",-1),n("a",{href:"/faq#formats"},"Supported formats",-1)])])):c("v-if",!0),T(n("div",null,[n("div",EN,[T(n("input",SN,null,512),[[s,{state:e.viewState,set:a=>{e.options.title=a},value:e.options?.title,form:"anonymize",options:{}}]]),t[94]||(t[94]=n("label",{class:"form-check-label",for:"title-gist"},"Gist description",-1))]),n("div",NN,[T(n("input",RN,null,512),[[s,{state:e.viewState,set:a=>{e.options.content=a},value:e.options?.content,form:"anonymize",options:{}}]]),t[95]||(t[95]=n("label",{class:"form-check-label",for:"content-gist"},"File contents",-1))]),n("div",DN,[T(n("input",TN,null,512),[[s,{state:e.viewState,set:a=>{e.options.comments=a},value:e.options?.comments,form:"anonymize",options:{}}]]),t[96]||(t[96]=n("label",{class:"form-check-label",for:"comments-gist"},"Comments",-1))]),n("div",_N,[T(n("input",AN,null,512),[[s,{state:e.viewState,set:a=>{e.options.username=a},value:e.options?.username,form:"anonymize",options:{}}]]),t[97]||(t[97]=n("label",{class:"form-check-label",for:"username-gist"},"Usernames",-1))]),n("div",ON,[T(n("input",PN,null,512),[[s,{state:e.viewState,set:a=>{e.options.date=a},value:e.options?.date,form:"anonymize",options:{}}]]),t[98]||(t[98]=n("label",{class:"form-check-label",for:"date-gist"},"Dates",-1))]),n("div",IN,[T(n("input",MN,null,512),[[s,{state:e.viewState,set:a=>{e.options.origin=a},value:e.options?.origin,form:"anonymize",options:{}}]]),t[99]||(t[99]=n("label",{class:"form-check-label",for:"origin-gist"},"Source gist ID",-1))])],512),[[Y,e.detectedType==="gist"]]),T(n("div",null,[n("div",VN,[T(n("input",qN,null,512),[[s,{state:e.viewState,set:a=>{e.options.title=a},value:e.options?.title,form:"anonymize",options:{}}]]),t[100]||(t[100]=n("label",{class:"form-check-label",for:"title"},"PR title",-1))]),n("div",LN,[T(n("input",$N,null,512),[[s,{state:e.viewState,set:a=>{e.options.body=a},value:e.options?.body,form:"anonymize",options:{}}]]),t[101]||(t[101]=n("label",{class:"form-check-label",for:"body"},"PR body",-1))]),n("div",UN,[T(n("input",FN,null,512),[[s,{state:e.viewState,set:a=>{e.options.diff=a},value:e.op Line truncated
anonymous_github`)])])])])]),c(" Limitations "),n("h4",{class:"faq-cat"},[n("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[n("use",{href:"#ui-icon-warning"})]),h("Limitations ")]),n("div",{class:"panel-group",id:"faq-limitations",role:"tablist","aria-multiselectable":"true"},[n("div",{class:"panel panel-default mb-3"},[n("div",{class:"panel-heading p-3",role:"tab",id:"headingLimitation"},[n("h3",{class:"panel-title"},[n("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? ")])]),n("div",{id:"limitation",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingLimitation"},[n("div",{class:"panel-body p-3"},[n("ul",null,[n("li",null," Anonymous GitHub only anonymizes text-based files. Binary files (compiled executables, archives, etc.) are served as-is without anonymization. "),n("li",null," Files larger than 8 MB are not supported. "),n("li",null," Static site generators (such as Jekyll) used with GitHub Pages are not fully supported, although Markdown files are converted to HTML. "),n("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). ")])])])])]),c(" Privacy & Security "),n("h4",{class:"faq-cat"},[n("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[n("use",{href:"#ui-icon-shield"})]),h("Privacy & Security ")]),n("div",{class:"panel-group",id:"faq-privacy",role:"tablist","aria-multiselectable":"true"},[n("div",{class:"panel panel-default mb-3"},[n("div",{class:"panel-heading p-3",role:"tab",id:"headingData"},[n("h3",{class:"panel-title"},[n("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? ")])]),n("div",{id:"data",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingData"},[n("div",{class:"panel-body p-3"},[n("p",null," Repository data is used to provide the anonymization service. If you purchase a plan, Stripe processes payment and billing information. When a repository is removed or expires, only its configuration is retained. This makes it easy to restore the repository if needed and ensures that no future repository reuses the same ID. ")])])]),n("div",{class:"panel panel-default mb-3"},[n("div",{class:"panel-heading p-3",role:"tab",id:"headingPermissions"},[n("h3",{class:"panel-title"},[n("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? ")])]),n("div",{id:"permissions",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingPermissions"},[n("div",{class:"panel-body p-3"},[n("p",null,[h("The GitHub App has read-only access to the repositories you choose. You can change repository access on your "),n("a",{href:"/connections"},"GitHub connections"),h(" page.")]),n("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."),n("p",null,"Anonymous GitHub reads repository content. It never pushes, modifies, or deletes files on GitHub.")])])]),n("div",{class:"panel panel-default mb-3"},[n("div",{class:"panel-heading p-3",role:"tab",id:"headingViewer"},[n("h3",{class:"panel-title"},[n("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? ")])]),n("div",{id:"viewer",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingViewer"},[n("div",{class:"panel-body p-3"},[n("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. ")])])])]),c(" Self-Hosting "),n("h4",{class:"faq-cat"},[n("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[n("use",{href:"#project-icon-storage"})]),h("Self-Hosting ")]),n("div",{class:"panel-group",id:"faq-hosting",role:"tablist","aria-multiselectable":"true"},[n("div",{class:"panel panel-default mb-3"},[n("div",{class:"panel-heading p-3",role:"tab",id:"headingDeploy"},[n("h3",{class:"panel-title"},[n("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? ")])]),n("div",{id:"deploy",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingDeploy"},[n("div",{class:"panel-body p-3"},[n("p",null,[h(" Yes. Line truncated
jane.smith@example.org`},null,10,AT),[[o,{state:e.viewState,set:a=>{e.terms=a},value:e.terms,form:"anonymize",options:{debounce:250}}]]),t[94]||(t[94]=n("small",{class:"form-text text-muted"},"One term per line.",-1)),n("details",_T,[t[89]||(t[89]=n("summary",null,"Regex & replacement syntax",-1)),t[90]||(t[90]=y()),n("small",OT,[t[83]||(t[83]=y("Regex is supported. Replaced by ",-1)),n("code",null,p(e.site_options?.ANONYMIZATION_MASK)+"-[N]",1),t[84]||(t[84]=y(", or use ",-1)),t[85]||(t[85]=n("code",null,"term=>replacement",-1)),t[86]||(t[86]=y(" to pick your own (e.g. ",-1)),t[87]||(t[87]=n("code",null,"Anonymous=>ABC",-1)),t[88]||(t[88]=y(").",-1))])]),(l(!0),d(W,null,ae((e.termHints||[]).slice(0,3),a=>(l(),d("div",{class:"term-hint",key:a.line},[n("span",null,[t[91]||(t[91]=y("In ",-1)),n("code",null,p(a.term),1),t[92]||(t[92]=y(", ",-1)),n("code",null,p(a.symbols.join(" ")),1),y(" "+p(a.symbols.length>1?"are regex symbols":"is a regex symbol")+", so it may not match the text as written.",1)]),n("button",{type:"button",class:"btn btn-outline-ink btn-sm",onClick:u=>e.matchTermAsWritten(a.line)},"Match as written",8,PT)]))),128)),(e.termHints||[]).length>3?(l(),d("div",IT,p(e.termHints.length-3)+" more "+p(e.termHints.length-3===1?"term uses":"terms use")+" regex symbols.",1)):f("v-if",!0),T(n("div",MT,"Terms are in an invalid format.",512),[[J,e.anonymize?.terms?.errors?.format]])]),T(n("div",VT,[n("div",qT,[t[95]||(t[95]=n("span",{class:"paper-field-label",id:"preserve-files-label"},"Unredacted files",-1)),n("span",$T,p(e.preserveSummary()),1)]),n("button",{type:"button",class:"btn btn-outline-ink btn-sm","aria-describedby":"preserve-files-label",disabled:!e.source?.commit,onClick:t[19]||(t[19]=a=>e.openPreserveFiles())},p((e.options?.preserveFiles||[]).length?"Edit":"Choose files"),9,LT)],512),[[J,e.detectedType==="repo"]]),e.preserve?.open?(l(),d("dialog",{key:0,id:"preserve-files-dialog",class:"preserve-dialog","aria-labelledby":"preserve-files-title",onCancel:t[24]||(t[24]=ce(a=>e.closePreserveFiles(),["prevent"]))},[n("form",{onSubmit:t[23]||(t[23]=ce(a=>e.savePreserveFiles(),["prevent"]))},[t[99]||(t[99]=n("h2",{id:"preserve-files-title"},"Leave files unredacted",-1)),t[100]||(t[100]=n("p",{class:"preserve-intro"},"Checked files are shown exactly as written, for example a bibliography where redacted self-citations would reveal you. File names are still redacted.",-1)),T(n("input",{type:"search",id:"preserve-files-search",class:"form-control",placeholder:"Search files","aria-label":"Search files",autocomplete:"off","onUpdate:modelValue":t[20]||(t[20]=a=>e.preserve.search=a)},null,512),[[dt,e.preserve.search]]),n("div",UT,[e.preserve.loading?(l(),d("p",FT,"Loading files from GitHub\u2026")):e.preserve.error?(l(),d("p",BT,p(e.preserve.error),1)):(l(),d(W,{key:2},[(l(!0),d(W,null,ae(e.preserveRows(),(a,u)=>(l(),d("div",{class:"preserve-item",key:a.kind+":"+a.path,style:$e({paddingLeft:a.depth*18+6+"px"})},[a.kind==="dir"?(l(),d("button",{key:0,type:"button",class:"preserve-caret","aria-expanded":a.open?"true":"false","aria-label":(a.open?"Collapse ":"Expand ")+a.label,onClick:c=>e.togglePreserveDir(a.path)},p(a.open?"\u25BE":"\u25B8"),9,zT)):(l(),d("span",HT)),n("input",{type:"checkbox",id:"pf-"+u,"aria-label":a.kind==="dir"?"Leave folder "+a.path+" unredacted":null,checked:a.state==="all",".indeterminate":a.state==="some",disabled:a.locked,onChange:c=>a.kind==="dir"?e.togglePreserveFolder(a.path):e.togglePreserveFile(a.path)},null,40,jT),n("label",{for:a.kind==="file"?"pf-"+u:null,class:"preserve-name",onClick:c=>a.kind==="dir"&&e.togglePreserveDir(a.path)},p(a.label),9,GT),a.note?(l(),d("span",WT,p(a.note),1)):f("v-if",!0)],4))),128)),!e.preserve.loading&&!e.preserveRows().length?(l(),d("p",KT,p(e.preserve.search?"No file matches your search.":"No text files in this commit."),1)):f("v-if",!0)],64))]),e.preserve.truncated?(l(),d("p",YT,"This repository has too many files to list them all. Use a pattern for files you cannot find.")):f("v-if",!0),n("details",{class:"preserve-patterns",open:e.preserve.patternsOpen},[t[96]||(t[96]=n("summary",null,"Patterns",-1)),T(n("textarea",{class:"form-control",rows:"3","aria-label":"Patterns",placeholder:`*.bib
paper/appendix/**`,"onUpdate:modelValue":t[21]||(t[21]=a=>e.preserve.patterns=a)},null,512),[[dt,e.preserve.patterns]]),t[97]||(t[97]=n("small",{class:"form-text text-muted"},[y("One per line, as in .gitignore: "),n("code",null,"*.bib"),y(" matches in any folder; "),n("code",null,"/refs.bib"),y(" and "),n("code",null,"paper/refs.bib"),y(" match from the repository root; a folder name such as "),n("code",null,"drafts/"),y(" covers everything inside it; "),n("code",null,"!private.bib"),y(" excludes again.")],-1))],8,XT),n("div",JT,[n("span",QT,p(e.preserve.loading||e.preserve.error?"":e.preserveCount()+(e.preserveCount()===1?" file":" files")+" will be shown as written"),1),n("span",ZT,[n("button",{type:"button",class:"btn btn-outline-ink",onClick:t[22]||(t[22]=a=>e.closePreserveFiles())},"Cancel"),t[98]||(t[98]=n("button",{type:"submit",class:"btn btn-ink"},"Save",-1))])])],32)],32)):f("v-if",!0)],512),[[J,e.detectedType]]),T(n("section",xT,[t[121]||(t[121]=n("h2",{class:"paper-section-eyebrow"},"Display",-1)),T(n("div",null,[n("div",eA,[T(n("input",tA,null,512),[[o,{state:e.viewState,set:a=>{e.options.link=a},value:e.options?.link,form:"anonymize",options:{}}]]),t[102]||(t[102]=n("label",{class:"form-check-label",for:"link"},"Keep links",-1))]),n("div",nA,[T(n("input",sA,null,512),[[o,{state:e.viewState,set:a=>{e.options.image=a},value:e.options?.image,form:"anonymize",options:{}}]]),t[103]||(t[103]=n("label",{class:"form-check-label",for:"image"},"Display images",-1))]),n("div",oA,[T(n("input",iA,null,512),[[o,{state:e.viewState,set:a=>{e.options.pdf=a},value:e.options?.pdf,form:"anonymize",options:{}}]]),t[104]||(t[104]=n("label",{class:"form-check-label",for:"pdf"},"Display PDFs",-1))]),n("div",rA,[T(n("input",aA,null,512),[[o,{state:e.viewState,set:a=>{e.options.notebook=a},value:e.options?.notebook,form:"anonymize",options:{}}]]),t[105]||(t[105]=n("label",{class:"form-check-label",for:"notebook"},"Display Notebooks",-1))]),n("div",lA,[T(n("input",{class:"form-check-input",type:"checkbox",id:"page",name:"page",disabled:!e.details?.hasPage||e.details?.pageSource&&e.details?.pageSource?.branch!==e.source?.branch},null,8,dA),[[o,{state:e.viewState,set:a=>{e.options.page=a},value:e.options?.page,form:"anonymize",options:{}}]]),t[106]||(t[106]=n("label",{class:"form-check-label",for:"page"},"GitHub Pages",-1)),e.details?.hasPage?f("v-if",!0):(l(),d("small",uA,p(e.fmt?.translate("WARNINGS.page_not_enabled_on_repo")),1)),e.details?.hasPage&&e.details?.pageSource?.branch&&e.source?.branch&&e.details.pageSource.branch!==e.source.branch?(l(),d("small",cA,p(e.fmt?.translate("WARNINGS.page_branch_mismatch",{pageBranch:e.details?.pageSource?.branch,selectedBranch:e.source?.branch})),1)):f("v-if",!0)])],512),[[J,e.detectedType==="repo"]]),e.detectedType==="repo"&&(e.options.image||e.options.pdf)?(l(),d("p",pA,[...t[107]||(t[107]=[y("Images and PDFs are served unchanged. Review their contents and metadata before sharing. ",-1),n("a",{href:"/faq#formats"},"Supported formats",-1)])])):f("v-if",!0),T(n("div",null,[n("div",fA,[T(n("input",hA,null,512),[[o,{state:e.viewState,set:a=>{e.options.title=a},value:e.options?.title,form:"anonymize",options:{}}]]),t[108]||(t[108]=n("label",{class:"form-check-label",for:"title-gist"},"Gist description",-1))]),n("div",mA,[T(n("input",gA,null,512),[[o,{state:e.viewState,set:a=>{e.options.content=a},value:e.options?.content,form:"anonymize",options:{}}]]),t[109]||(t[109]=n("label",{class:"form-check-label",for:"content-gist"},"File contents",-1))]),n("div",vA,[T(n("input",yA,null,512),[[o,{state:e.viewState,set:a=>{e.options.comments=a},value:e.options?.comments,form:"anonymize",options:{}}]]),t[110]||(t[110]=n("label",{class:"form-check-label",for:"comments-gist"},"Comments",-1))]),n("div",bA,[T(n("input",wA,null,512),[[o,{state:e.viewState,set:a=>{e.options.username=a},value:e.options?.username,form:"anonymize",options:{}}]]),t[111]||(t[111]=n("label",{class:"form-check-label",for:"username-gist"},"Usernames",-1))]),n("div",kA,[T(n("input",CA,null,512),[[o,{state:e.viewState,set:a=>{e.options.date=a},value:e.options?.date,form:"anonymize",options:{}}]]),t[112]||(t[112]=n("label",{class:"form-check-label",for:"date-gist"},"Dates",-1))]),n("div",EA,[T(n("input",SA,null,512),[[o,{state:e.viewState,set:a=>{e.options.origin=a},value:e.options?.origin,form:"anonymize",options:{}}]]),t[113]||(t[113]=n("label",{class:"form-check-label",for:"origin-gist"},"Source gist ID",-1))])],512),[[J,e.detectedType==="gist"]]),T(n("div",null,[n("div",NA,[T(n("input",RA,null,512),[[o,{state:e.viewState,set:a=>{e.options.title=a},value:e.options?.title,form:"anonymize",options:{}}]]),t[114]||(t[114]=n("label",{class:"form-check-label",for:"title"},"PR title",-1))]),n("div",DA,[T(n("input",TA,null,512),[[o,{state:e.viewState,set:a=>{e.options.body=a},value:e.options?.body,form:"anonymize",options:{}}]]),t[115]||(t[115]=n("label",{class:"form-check-label",for:"body"},"PR body",-1))]),n("div",AA,[T(n("input" Line truncated
anonymous_github`)])])])])]),f(" Limitations "),n("h4",{class:"faq-cat"},[n("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[n("use",{href:"#ui-icon-warning"})]),y("Limitations ")]),n("div",{class:"panel-group",id:"faq-limitations",role:"tablist","aria-multiselectable":"true"},[n("div",{class:"panel panel-default mb-3"},[n("div",{class:"panel-heading p-3",role:"tab",id:"headingLimitation"},[n("h3",{class:"panel-title"},[n("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? ")])]),n("div",{id:"limitation",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingLimitation"},[n("div",{class:"panel-body p-3"},[n("ul",null,[n("li",null," Anonymous GitHub only anonymizes text-based files. Binary files (compiled executables, archives, etc.) are served as-is without anonymization. "),n("li",null," Files larger than 8 MB are not supported. "),n("li",null," Static site generators (such as Jekyll) used with GitHub Pages are not fully supported, although Markdown files are converted to HTML. "),n("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). ")])])])])]),f(" Privacy & Security "),n("h4",{class:"faq-cat"},[n("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[n("use",{href:"#ui-icon-shield"})]),y("Privacy & Security ")]),n("div",{class:"panel-group",id:"faq-privacy",role:"tablist","aria-multiselectable":"true"},[n("div",{class:"panel panel-default mb-3"},[n("div",{class:"panel-heading p-3",role:"tab",id:"headingData"},[n("h3",{class:"panel-title"},[n("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? ")])]),n("div",{id:"data",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingData"},[n("div",{class:"panel-body p-3"},[n("p",null," Repository data is used to provide the anonymization service. If you purchase a plan, Stripe processes payment and billing information. When a repository is removed or expires, only its configuration is retained. This makes it easy to restore the repository if needed and ensures that no future repository reuses the same ID. ")])])]),n("div",{class:"panel panel-default mb-3"},[n("div",{class:"panel-heading p-3",role:"tab",id:"headingPermissions"},[n("h3",{class:"panel-title"},[n("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? ")])]),n("div",{id:"permissions",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingPermissions"},[n("div",{class:"panel-body p-3"},[n("p",null,[y("The GitHub App has read-only access to the repositories you choose. You can change repository access on your "),n("a",{href:"/connections"},"GitHub connections"),y(" page.")]),n("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."),n("p",null,"Anonymous GitHub reads repository content. It never pushes, modifies, or deletes files on GitHub.")])])]),n("div",{class:"panel panel-default mb-3"},[n("div",{class:"panel-heading p-3",role:"tab",id:"headingViewer"},[n("h3",{class:"panel-title"},[n("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? ")])]),n("div",{id:"viewer",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingViewer"},[n("div",{class:"panel-body p-3"},[n("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. ")])])])]),f(" Self-Hosting "),n("h4",{class:"faq-cat"},[n("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[n("use",{href:"#project-icon-storage"})]),y("Self-Hosting ")]),n("div",{class:"panel-group",id:"faq-hosting",role:"tablist","aria-multiselectable":"true"},[n("div",{class:"panel panel-default mb-3"},[n("div",{class:"panel-heading p-3",role:"tab",id:"headingDeploy"},[n("h3",{class:"panel-title"},[n("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? ")])]),n("div",{id:"deploy",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingDeploy"},[n("div",{class:"panel-body p-3"},[n("p",null,[y(" Yes. 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[26]||(t[26]=me('<li class="nav-item d-none d-lg-block"><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"><svg class="ui-icon d-lg-none mr-1" aria-hidden="true"><use href="#ui-icon-bug"></use></svg>Report a bug </a></li><li class="nav-item nav-support-item d-none d-lg-block"><a class="nav-link nav-support-inline" href="https://ko-fi.com/tdurieux" target="_blank" rel="noopener" title="Donate on Ko-fi to help cover hosting costs"><svg class="ui-icon nav-heart" aria-hidden="true"><use href="#ui-icon-heart"></use></svg>Support </a></li>',2)),e.isDarkMode?c("v-if",!0):(l(),d("li",G5,[n("button",{type:"button",class:"nav-link nav-icon",title:"Switch to dark mode","aria-label":"Switch to dark mode",onClick:t[1]||(t[1]=o=>{e.darkMode(!0)})},[...t[19]||(t[19]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-moon"})],-1)])])])),e.isDarkMode?(l(),d("li",W5,[n("button",{type:"button",class:"nav-link nav-icon",title:"Switch to light mode","aria-label":"Switch to light mode",onClick:t[2]||(t[2]=o=>{e.darkMode(!1)})},[...t[20]||(t[20]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-sun"})],-1)])])])):c("v-if",!0),!e.user&&!e.isReviewerRoute?(l(),d("li",K5,[...t[21]||(t[21]=[n("a",{class:"nav-link btn-signin",target:"_self",href:"/signin","data-offset":"30"},[n("i",{class:"fab fa-github mr-1"}),h(" Sign in ")],-1)])])):c("v-if",!0),e.user?.username&&e.headerCanUpgrade&&!e.headerBillingPending?(l(),d("li",Y5,[n("a",{class:"nav-link nav-upgrade",href:"/profile?upgrade=1",onClick:t[3]||(t[3]=ae(o=>e.openHeaderUpgrade(),["prevent"]))},"Upgrade")])):c("v-if",!0),e.user?(l(),d("li",J5,[n("a",Q5,[e.user?.photo?(l(),d("img",{key:0,width:"22",height:"22",class:"rounded-circle",src:e.safeUrl(e.user?.photo)},null,8,X5)):c("v-if",!0),n("span",Z5,u(e.user?.username),1)]),n("div",x5,[n("h6",e8,"Signed in as @"+u(e.user?.username),1),t[23]||(t[23]=me('<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 um-extra" 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>',6)),e.headerShowSupport?(l(),d("a",t8,[...t[22]||(t[22]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-heart"})],-1),n("span",null,"Support the project",-1)])])):c("v-if",!0),t[24]||(t[24]=n("div",{class:"dropdown-divider"},null,-1)),t[25]||(t[25]=n("a",{class:"dropdown-item",href:"/api/user/logout",target:"_self"},[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-logout"})]),n("span",null,"Sign out")],-1))])])):c("v-if",!0)])])],2),e.generalMessage?(l(),d("div",{key:0,class:"navbar shadow generalMessage",innerHTML:e.sanitize(e.generalMessage)},null,8,n8)):c("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[8]||(t[8]=ae(o=>e.respondToEmailPrompt("later"),["prevent"]))},[n("form",{onSubmit:t[7]||(t[7]=ae(o=>e.respondToEmailPrompt("save"),["prevent"]))},[t[29]||(t[29]=n("h2",{id:"email-prompt-title"},"Stay informed about access problems",-1)),t[30]||(t[30]=n("p",{id:"email-prompt-reason"},"Get email alerts when your GitHub token or repository access fails.",-1)),t[31]||(t[31]=n("label",{for:"email-prompt-address"},"Email address",-1)),T(n("input",{id:"email-prompt-address",class:"form-control",type:"email",autocomplete:"email",maxlength:"254",required:"","onUpdate:modelValue":t[4]||(t[4]=o=>e.emailPromptAddress=o),disabled:e.emailPromptBusy},null,8,o8),[[ot,e.emailPromptAddress]]),e.emailPromptError?(l(),d("p",s8,u(e.emailPromptError),1)):c("v-if",!0),n("div",i8,[n("button",{type:"button",class:"btn btn-outline-ink",disabled:e.emailPromptBusy,onClick:t[5]||(t[5]=o=>e.respondToEma Line truncated
python experiments/run.py`),n("p",null,[h("Contact: "),n("span",{class:"redact",role:"img","aria-label":"Redacted term 3"},[n("i",null,"3")])])])])])])],-1))]),c(" Live stats "),n("section",h8,[t[9]||(t[9]=n("div",{class:"paper-stats-meta"},[n("div",{class:"paper-stats-meta-left"},[n("span",{class:"paper-stats-dot","aria-hidden":"true"}),h(" Live \xB7 last 60 days \xB7 updated daily")]),n("div",{class:"paper-stats-meta-right"},"Used by authors at ICSE \xB7 FSE \xB7 OOPSLA")],-1)),n("div",v8,[(l(!0),d(W,null,oe(e.cards,(o,i)=>(l(),d("div",{class:"paper-stat-card",key:o?.key},[n("div",{class:O(["paper-stat-value",{"is-pending":!e.stat}])},u(e.stat?e.fmt?.bigNum(o?.total):"\u2014"),3),n("div",g8,u(o?.label),1),e.history[o?.key].bars?.length>1?(l(),d("div",y8," +"+u(e.fmt?.number(e.history[o?.key].deltaToday))+" today ",1)):c("v-if",!0)]))),128))])]),c(" Before / after "),t[25]||(t[25]=n("section",{class:"paper-section-head paper-wrap"},[n("div",null,[n("div",{class:"paper-eyebrow"},"Try it"),n("h2",null,[h("The same repository, "),n("em",null,"minus you.")])]),n("p",null," Names, affiliations, emails, and any term you list are replaced across the README, source files, notebooks, and PDF links. Reviewers browse the real thing, not a zip. ")],-1)),n("div",b8,[n("div",w8,[t[10]||(t[10]=n("label",{for:"demo-terms"},[h("Terms to redact "),n("span",null,"comma-separated, try adding your own")],-1)),T(n("input",{id:"demo-terms",type:"text","onUpdate:modelValue":t[0]||(t[0]=o=>e.demoTerms=o),spellcheck:"false",autocomplete:"off"},null,512),[[ot,e.demoTerms]])]),n("div",k8,[n("div",C8,[t[12]||(t[12]=n("div",{class:"pane-header"},[n("span",{class:"pane-label"},[h("Your repository "),n("span",{class:"pane-edit-hint"},"\xB7 editable")]),n("span",{class:"pane-url"},"github.com/jane-smith/DeepLearnUtils")],-1)),n("div",E8,[n("div",S8,[(l(!0),d(W,null,oe(e.demoParts(),(o,i)=>(l(),d(W,{key:i},[o.redacted?(l(),d("mark",N8,u(o.original),1)):(l(),d(W,{key:1},[h(u(o.text),1)],64))],64))),128)),t[11]||(t[11]=h("\u200B",-1))]),T(n("textarea",{class:"pane-body demo-input","onUpdate:modelValue":t[1]||(t[1]=o=>e.demoText=o),spellcheck:"false","aria-label":"Sample README to anonymize"},null,512),[[ot,e.demoText]])])]),n("div",R8,[n("div",D8,[t[13]||(t[13]=n("span",{class:"pane-label"},"What reviewers see",-1)),n("span",T8,[n("span",_8,u(e.demoCount())+" redacted",1)])]),n("div",A8,[(l(!0),d(W,null,oe(e.demoParts(),(o,i)=>(l(),d(W,{key:i},[o.redacted?(l(),d("span",{key:0,class:"redact-chip",title:"Replaces \u201C"+o.original+"\u201D"},u(o.text),9,O8)):(l(),d(W,{key:1},[h(u(o.text),1)],64))],64))),128))])])])]),c(" What you get: one screenshot, three tabs "),t[26]||(t[26]=n("section",{class:"paper-section-head paper-wrap",id:"about"},[n("div",null,[n("div",{class:"paper-eyebrow"},"What you get"),n("h2",null,"Anonymize, review, manage.")]),n("p",null," Terms are redacted in text files. Enabled images and PDFs are served unchanged, so review them for identifying content before sharing. Monitor your mirror, update it, or remove it when the review is over. ")],-1)),n("section",P8,[n("div",I8,[(l(!0),d(W,null,oe(e.features,(o,i)=>(l(),d("div",{class:O(["paper-feature",{"is-on":e.feature===o?.key}]),key:o?.key},[n("button",{type:"button",class:"paper-feature-tab",role:"tab",onClick:s=>e.selectFeature(o.key),onKeydown:s=>e.featureKeydown(s,i),id:"feature-tab-"+o?.key,"aria-controls":"feature-panel-"+o?.key,"aria-selected":e.feature===o?.key,tabindex:e.feature===o?.key?0:-1},[n("span",V8,u(o?.num)+" \xB7 "+u(o?.eyebrow),1),n("span",q8,u(o?.title)+" "+u(o?.accent),1)],40,M8),n("div",L8,[n("span",$8,u(o?.title)+" "+u(o?.accent),1),n("p",null,u(o?.text),1),n("a",{class:"paper-link-arrow",href:e.safeUrl(e.featureHref(o)),target:e.featureTarget(o)},u(o?.cta)+" \u2192",9,U8)])],2))),128))]),n("div",F8,[(l(!0),d(W,null,oe(e.features,(o,i)=>T((l(),d("div",{class:"paper-feature-panel",role:"tabpanel",key:o?.key,id:"feature-panel-"+o?.key,"aria-labelledby":"feature-tab-"+o?.key},[n("div",z8,[n("div",H8,[t[14]||(t[14]=n("span",{class:"dots"},[n("i"),n("i"),n("i")],-1)),n("span",j8,u(o?.url),1)]),n("div",{class:O(["feat-mock","is-"+o?.key]),role:"img","aria-label":o?.alt},[o?.key==="anonymize"?(l(),d("div",W8,[...t[15]||(t[15]=[me('<div class="fm-label">GitHub repository</div><div class="fm-input">github.com/jane-smith/DeepLearnUtils</div><div class="fm-label">Terms to redact</div><div class="fm-chips"><span>Jane Smith</span><span>MIT CSAIL</span><span>jane.smith@mit.edu</span><span class="fm-chip-add">+ Add term</span></div><div class="fm-row"><div><div class="fm-label">Reviewers can see</div><div class="fm-toggles"><span class="is-on">Images</span><span class="is-on">PDFs</span><span>Links</span><span class="is-on">Notebooks</span></div></div><div><div class="fm-label">Expires</div><div class="fm-input fm-input-sm">Mar 31, 2027</div></div></div><div class="fm-actions"><span class="fm-share">anonymous.4open.science/r/paper-7f2a</span><span class="fm-btn"> Line truncated
label names the service and the tooltip says who to contact. `),t[26]||(t[26]=Ce('<li class="nav-item d-none d-lg-block"><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"><svg class="ui-icon d-lg-none mr-1" aria-hidden="true"><use href="#ui-icon-bug"></use></svg>Report a bug </a></li><li class="nav-item nav-support-item d-none d-lg-block"><a class="nav-link nav-support-inline" href="https://ko-fi.com/tdurieux" target="_blank" rel="noopener" title="Donate on Ko-fi to help cover hosting costs"><svg class="ui-icon nav-heart" aria-hidden="true"><use href="#ui-icon-heart"></use></svg>Support </a></li>',2)),e.isDarkMode?f("v-if",!0):(l(),d("li",V6,[n("button",{type:"button",class:"nav-link nav-icon",title:"Switch to dark mode","aria-label":"Switch to dark mode",onClick:t[1]||(t[1]=s=>{e.darkMode(!0)})},[...t[19]||(t[19]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-moon"})],-1)])])])),e.isDarkMode?(l(),d("li",q6,[n("button",{type:"button",class:"nav-link nav-icon",title:"Switch to light mode","aria-label":"Switch to light mode",onClick:t[2]||(t[2]=s=>{e.darkMode(!1)})},[...t[20]||(t[20]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-sun"})],-1)])])])):f("v-if",!0),!e.user&&!e.isReviewerRoute?(l(),d("li",$6,[...t[21]||(t[21]=[n("a",{class:"nav-link btn-signin",target:"_self",href:"/signin","data-offset":"30"},[n("i",{class:"fab fa-github mr-1"}),y(" Sign in ")],-1)])])):f("v-if",!0),e.user?.username&&e.headerCanUpgrade&&!e.headerBillingPending?(l(),d("li",L6,[n("a",{class:"nav-link nav-upgrade",href:"/profile?upgrade=1",onClick:t[3]||(t[3]=ce(s=>e.openHeaderUpgrade(),["prevent"]))},"Upgrade")])):f("v-if",!0),e.user?(l(),d("li",U6,[n("a",F6,[e.user?.photo?(l(),d("img",{key:0,width:"22",height:"22",class:"rounded-circle",src:e.safeUrl(e.user?.photo)},null,8,B6)):f("v-if",!0),n("span",z6,p(e.user?.username),1)]),n("div",H6,[n("h6",j6,"Signed in as @"+p(e.user?.username),1),t[23]||(t[23]=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 um-extra" 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>',6)),e.headerShowSupport?(l(),d("a",G6,[...t[22]||(t[22]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-heart"})],-1),n("span",null,"Support the project",-1)])])):f("v-if",!0),t[24]||(t[24]=n("div",{class:"dropdown-divider"},null,-1)),t[25]||(t[25]=n("a",{class:"dropdown-item",href:"/api/user/logout",target:"_self"},[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-logout"})]),n("span",null,"Sign out")],-1))])])):f("v-if",!0)])])],2),e.generalMessage?(l(),d("div",{key:0,class:"navbar shadow generalMessage",innerHTML:e.sanitize(e.generalMessage)},null,8,W6)):f("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[8]||(t[8]=ce(s=>e.respondToEmailPrompt("later"),["prevent"]))},[n("form",{onSubmit:t[7]||(t[7]=ce(s=>e.respondToEmailPrompt("save"),["prevent"]))},[t[29]||(t[29]=n("h2",{id:"email-prompt-title"},"Stay informed about access problems",-1)),t[30]||(t[30]=n("p",{id:"email-prompt-reason"},"Get email alerts when your GitHub token or repository access fails.",-1)),t[31]||(t[31]=n("label",{for:"email-prompt-address"},"Email address",-1)),T(n("input",{id:"email-prompt-address",class:"form-control",type:"email",autocomplete:"email",maxlength:"254",required:"","onUpdate:modelValue":t[4]||(t[4]=s=>e.emailPromptAddress=s),disabled:e.emailPromptBusy},null,8,K6),[[dt,e.emailPromptAddress]]),e.emailPromptError?(l(),d("p",Y6,p(e.emailPromptError),1)):f("v-if",!0),n("div",X6,[n("button",{type:"button",class:"btn btn-outline-ink",disabled:e.emailPromptBusy,onClick:t[5]||(t[5]=s=>e.respondToEma Line truncated
python experiments/run.py`),n("p",null,[y("Contact: "),n("span",{class:"redact",role:"img","aria-label":"Redacted term 3"},[n("i",null,"3")])])])])])])],-1))]),f(" Live stats "),n("section",iq,[t[9]||(t[9]=n("div",{class:"paper-stats-meta"},[n("div",{class:"paper-stats-meta-left"},[n("span",{class:"paper-stats-dot","aria-hidden":"true"}),y(" Live \xB7 last 60 days \xB7 updated daily")]),n("div",{class:"paper-stats-meta-right"},"Used by authors at ICSE \xB7 FSE \xB7 OOPSLA")],-1)),n("div",rq,[(l(!0),d(W,null,ae(e.cards,(s,i)=>(l(),d("div",{class:"paper-stat-card",key:s?.key},[n("div",{class:_(["paper-stat-value",{"is-pending":!e.stat}])},p(e.stat?e.fmt?.bigNum(s?.total):"\u2014"),3),n("div",aq,p(s?.label),1),e.history[s?.key].bars?.length>1?(l(),d("div",lq," +"+p(e.fmt?.number(e.history[s?.key].deltaToday))+" today ",1)):f("v-if",!0)]))),128))])]),f(" Before / after "),t[25]||(t[25]=n("section",{class:"paper-section-head paper-wrap"},[n("div",null,[n("div",{class:"paper-eyebrow"},"Try it"),n("h2",null,[y("The same repository, "),n("em",null,"minus you.")])]),n("p",null," Names, affiliations, emails, and any term you list are replaced across the README, source files, notebooks, and PDF links. Reviewers browse the real thing, not a zip. ")],-1)),n("div",dq,[n("div",uq,[t[10]||(t[10]=n("label",{for:"demo-terms"},[y("Terms to redact "),n("span",null,"comma-separated, try adding your own")],-1)),T(n("input",{id:"demo-terms",type:"text","onUpdate:modelValue":t[0]||(t[0]=s=>e.demoTerms=s),spellcheck:"false",autocomplete:"off"},null,512),[[dt,e.demoTerms]])]),n("div",cq,[n("div",pq,[t[12]||(t[12]=n("div",{class:"pane-header"},[n("span",{class:"pane-label"},[y("Your repository "),n("span",{class:"pane-edit-hint"},"\xB7 editable")]),n("span",{class:"pane-url"},"github.com/jane-smith/DeepLearnUtils")],-1)),n("div",fq,[n("div",hq,[(l(!0),d(W,null,ae(e.demoParts(),(s,i)=>(l(),d(W,{key:i},[s.redacted?(l(),d("mark",mq,p(s.original),1)):(l(),d(W,{key:1},[y(p(s.text),1)],64))],64))),128)),t[11]||(t[11]=y("\u200B",-1))]),T(n("textarea",{class:"pane-body demo-input","onUpdate:modelValue":t[1]||(t[1]=s=>e.demoText=s),spellcheck:"false","aria-label":"Sample README to anonymize"},null,512),[[dt,e.demoText]])])]),n("div",gq,[n("div",vq,[t[13]||(t[13]=n("span",{class:"pane-label"},"What reviewers see",-1)),n("span",yq,[n("span",bq,p(e.demoCount())+" redacted",1)])]),n("div",wq,[(l(!0),d(W,null,ae(e.demoParts(),(s,i)=>(l(),d(W,{key:i},[s.redacted?(l(),d("span",{key:0,class:"redact-chip",title:"Replaces \u201C"+s.original+"\u201D"},p(s.text),9,kq)):(l(),d(W,{key:1},[y(p(s.text),1)],64))],64))),128))])])])]),f(" What you get: one screenshot, three tabs "),t[26]||(t[26]=n("section",{class:"paper-section-head paper-wrap",id:"about"},[n("div",null,[n("div",{class:"paper-eyebrow"},"What you get"),n("h2",null,"Anonymize, review, manage.")]),n("p",null," Terms are redacted in text files. Enabled images and PDFs are served unchanged, so review them for identifying content before sharing. Monitor your mirror, update it, or remove it when the review is over. ")],-1)),n("section",Cq,[n("div",Eq,[(l(!0),d(W,null,ae(e.features,(s,i)=>(l(),d("div",{class:_(["paper-feature",{"is-on":e.feature===s?.key}]),key:s?.key},[n("button",{type:"button",class:"paper-feature-tab",role:"tab",onClick:o=>e.selectFeature(s.key),onKeydown:o=>e.featureKeydown(o,i),id:"feature-tab-"+s?.key,"aria-controls":"feature-panel-"+s?.key,"aria-selected":e.feature===s?.key,tabindex:e.feature===s?.key?0:-1},[n("span",Nq,p(s?.num)+" \xB7 "+p(s?.eyebrow),1),n("span",Rq,p(s?.title)+" "+p(s?.accent),1)],40,Sq),n("div",Dq,[n("span",Tq,p(s?.title)+" "+p(s?.accent),1),n("p",null,p(s?.text),1),n("a",{class:"paper-link-arrow",href:e.safeUrl(e.featureHref(s)),target:e.featureTarget(s)},p(s?.cta)+" \u2192",9,Aq)])],2))),128))]),n("div",_q,[(l(!0),d(W,null,ae(e.features,(s,i)=>T((l(),d("div",{class:"paper-feature-panel",role:"tabpanel",key:s?.key,id:"feature-panel-"+s?.key,"aria-labelledby":"feature-tab-"+s?.key},[n("div",Pq,[n("div",Iq,[t[14]||(t[14]=n("span",{class:"dots"},[n("i"),n("i"),n("i")],-1)),n("span",Mq,p(s?.url),1)]),n("div",{class:_(["feat-mock","is-"+s?.key]),role:"img","aria-label":s?.alt},[s?.key==="anonymize"?(l(),d("div",qq,[...t[15]||(t[15]=[Ce('<div class="fm-label">GitHub repository</div><div class="fm-input">github.com/jane-smith/DeepLearnUtils</div><div class="fm-label">Terms to redact</div><div class="fm-chips"><span>Jane Smith</span><span>MIT CSAIL</span><span>jane.smith@mit.edu</span><span class="fm-chip-add">+ Add term</span></div><div class="fm-row"><div><div class="fm-label">Reviewers can see</div><div class="fm-toggles"><span class="is-on">Images</span><span class="is-on">PDFs</span><span>Links</span><span class="is-on">Notebooks</span></div></div><div><div class="fm-label">Expires</div><div class="fm-input fm-input-sm">Mar 31, 2027</div></div></div><div class="fm-actions"><span class="fm-share">anonymous.4open.science/r/paper-7f2a</span><span class="fm-btn"> Line truncated
<span class="ln">2</span><span class="c"># Author: <span class="redact">XXXX-1</span>, <span class="redact">XXXX-2</span></span>
<span class="ln">3</span><span class="k">import</span> torch
<span class="ln">4</span><span class="k">from</span> utils <span class="k">import</span> load_config
@@ -37,14 +47,15 @@ python experiments/run.py`),n("p",null,[h("Contact: "),n("span",{class:"redact",
<span class="ln">7</span> model = build_model(config)
<span class="ln">8</span> <span class="k">for</span> epoch <span class="k">in</span> range(config.epochs):
<span class="ln">9</span> loss = step(model)
<span class="ln">10</span> log(<span class="s">&quot;epoch %d: %.3f&quot;</span>, epoch, loss)</pre></div>`,2)])])):(l(),d("div",Y8,[...t[17]||(t[17]=[me('<div class="fm-dash-head"><span>Project</span><span>Status</span><span>Views</span><span>Expires</span></div><div class="fm-dash-row"><span><b>DeepLearnUtils</b><i>paper-7f2a \xB7 ICSE 2027</i></span><span class="st is-ready">Ready</span><span>41</span><span>Mar 31, 2027</span></div><div class="fm-dash-row"><span><b>vision-bench#212</b><i>pull request \xB7 FSE 2027</i></span><span class="st is-ready">Ready</span><span>12</span><span>Never</span></div><div class="fm-dash-row"><span><b>graph-repair</b><i>gr-91ab</i></span><span class="st is-progress">Updating</span><span>5</span><span>Jan 5, 2027</span></div><div class="fm-dash-row is-muted"><span><b>JarSift</b><i>OOPSLA 2025</i></span><span class="st is-expired">Expired</span><span>72</span><span>Sep 28, 2026</span></div>',5)])]))],10,G8)])],8,B8)),[[Y,e.feature===o?.key]])),128))])]),c(" FAQ teaser "),t[27]||(t[27]=me('<section class="paper-qa paper-wrap" aria-labelledby="qa-heading"><div><div class="paper-eyebrow">Before you sign in</div><h2 id="qa-heading">The questions that come up most.</h2><a class="paper-link-arrow" href="/faq">Read the full FAQ \u2192</a></div><div><div class="q"><a href="/faq#permissions">What access does GitHub sign-in require?</a><p> The GitHub App has read-only access to gists and the repositories you choose. Legacy OAuth uses broader permissions. Anonymous GitHub never writes to your repositories. </p></div><div class="q"><a href="/faq#formats">Which file formats are supported?</a><p> Source code with syntax highlighting, Markdown, Jupyter notebooks, PDFs, images, and GitHub Pages sites. Text files are anonymized; enabled images and PDFs are served unchanged. </p></div><div class="q"><a href="/faq#expiration">What happens when an anonymized repository expires?</a><p> You choose: the mirror is removed, or visitors are redirected to the original GitHub repository once the review is over. </p></div></div></section><section class="paper-cta paper-wrap" aria-labelledby="cta-heading"><div><h2 id="cta-heading">Ready for review?</h2><p>Create an anonymous mirror in a couple of minutes. Reviewers just open the link.</p></div><div class="paper-cta-actions"><a class="btn-hero" href="/signin" target="_self"><i class="fab fa-github" aria-hidden="true"></i> Sign in with GitHub</a><a class="paper-link-arrow" href="/faq">Read the FAQ \u2192</a></div></section>',2)),n("footer",J8,[n("div",Q8,[t[21]||(t[21]=n("div",{class:"paper-footer-brand"},[n("div",{class:"paper-footer-mark"},[h("Anonymous "),n("em",null,"GitHub")]),n("p",{class:"paper-footer-tag"}," A read-only, identity-stripped mirror of your repository, built for double-anonymous peer review. ")],-1)),n("div",X8,[t[18]||(t[18]=n("div",{class:"paper-footer-head"},"Product",-1)),t[19]||(t[19]=n("a",{href:"/anonymize"},"Anonymize",-1)),e.user?(l(),d("a",Z8,"My work")):c("v-if",!0),e.user?(l(),d("a",x8,"Conferences")):c("v-if",!0),t[20]||(t[20]=n("a",{href:"/faq"},"FAQ",-1))]),t[22]||(t[22]=me('<div class="paper-footer-col"><div class="paper-footer-head">Project</div><a href="https://github.com/tdurieux/anonymous_github/" target="_blank" rel="noopener">Source code</a><a href="https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml" target="_blank" rel="noopener">Report a bug</a><a href="https://github.com/sponsors/tdurieux/" target="_blank" rel="noopener">Support</a></div><div class="paper-footer-col"><div class="paper-footer-head">Contact</div><a href="mailto:tdurieux@anonymous.4open.science">Email maintainer</a><a href="https://github.com/tdurieux" target="_blank" rel="noopener">@tdurieux</a></div>',2))]),t[24]||(t[24]=n("div",{class:"paper-footer-rule"},null,-1)),n("div",eM,[n("span",null,"\xA9 "+u(e.year||2026)+" Anonymous GitHub \xB7 GPL-3.0 licensed",1),t[23]||(t[23]=n("span",{class:"paper-footer-meta"},"Built for reviewers, by researchers.",-1))])])])}var tM={class:"paper-empty"},nM={class:"paper-empty-inner"},oM={key:0,class:"paper-eyebrow"},sM={key:1,class:"paper-eyebrow"},iM={key:2,class:"paper-empty-title"},rM=["textContent"];function Xl(e,t){return l(),d("div",tM,[n("div",nM,[e.error?c("v-if",!0):(l(),d("div",oM,"Working")),e.error?(l(),d("div",sM,"Error")):c("v-if",!0),e.error?c("v-if",!0):(l(),d("h1",iM,[...t[0]||(t[0]=[h(" Loading",-1),n("span",{class:"dot-anim"},"\u2026",-1)])])),e.error?(l(),d("h1",{key:3,class:"paper-empty-title",textContent:u(e.fmt.translate(e.error))},null,8,rM)):c("v-if",!0)])])}var aM={class:"container paper-page paper-settings"},lM={class:"paper-crumbs"},dM={class:"here"},uM={class:"paper-page-title"},cM={class:"paper-settings-body"},pM={class:"paper-settings-toc"},fM={href:"#conf-billing"},mM={class:"form needs-validation paper-settings-main",name:"conference",novalidate:""},hM={id:"conf-basics",class:"paper-settings-section"},vM={class:"form-group"},gM={class:"invalLine truncated
`).length))+" lines",1)):c("v-if",!0),e.type=="html"&&e.fileSize(e.filePath)!=null?(l(),d("span",TV,u(e.formatSize(e.fileSize(e.filePath))),1)):c("v-if",!0),e.redactionCount()?(l(),d("b",_V,u(e.redactionCount())+" redacted",1)):c("v-if",!0)]),T(n("button",{type:"button",class:"btn btn-sm btn-icon-only btn-ghost copy-path-btn","aria-label":e.pathCopied?"Path copied":"Copy file path",title:e.pathCopied?"Path copied":"Copy file path",onClick:t[2]||(t[2]=a=>e.copyPath())},[(l(),d("svg",OV,[n("use",{href:e.pathCopied?"#ui-icon-check":"#ui-icon-link"},null,8,PV)]))],8,AV),[[Y,e.filePath]])]),e.type!="html"&&typeof e.content=="string"?(l(),d("span",IV,[e.languageName?(l(),d(W,{key:0},[h(u(e.languageName),1),t[37]||(t[37]=n("span",{class:"sep"},"\xB7",-1))],64)):c("v-if",!0),h(u(e.fmt?.number(e.content.split(`
`).length))+" lines",1),n("span",MV,[t[38]||(t[38]=n("span",{class:"sep"},"\xB7",-1)),h(u(e.content.length<1024?e.content.length+" B":(e.content.length/1024).toFixed(1)+" KB"),1)]),e.redactionCount()?(l(),d(W,{key:1},[t[39]||(t[39]=n("span",{class:"sep"},"\xB7",-1)),n("span",VV,u(e.redactionCount())+" redacted",1)],64)):c("v-if",!0)])):c("v-if",!0),e.type=="html"?(l(),d("span",qV,[t[42]||(t[42]=h("Markdown",-1)),e.fileSize(e.filePath)!=null?(l(),d(W,{key:0},[t[40]||(t[40]=n("span",{class:"sep"},"\xB7",-1)),h(u(e.formatSize(e.fileSize(e.filePath))),1)],64)):c("v-if",!0),e.redactionCount()?(l(),d(W,{key:1},[t[41]||(t[41]=n("span",{class:"sep"},"\xB7",-1)),n("span",LV,u(e.redactionCount())+" redacted",1)],64)):c("v-if",!0)])):c("v-if",!0),n("div",$V,[e.type!="html"&&e.symbols().length>1?(l(),d("div",UV,[n("button",{type:"button",class:O(["btn btn-sm btn-ghost btn-symbols",{"is-on":e.symbolsOpen}]),"aria-expanded":e.symbolsOpen?"true":"false","aria-haspopup":"true",title:"Symbols in this file",onClick:t[3]||(t[3]=a=>e.symbolsOpen=!e.symbolsOpen)},[...t[43]||(t[43]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-list"})],-1),n("span",{class:"btn-find-label"},"Symbols",-1)])],10,FV),e.symbolsOpen?(l(),d("div",BV,[n("div",zV,u(e.symbols().length)+" "+u(e.symbols().length===1?"symbol":"symbols"),1),(l(!0),d(W,null,oe(e.symbols(),a=>(l(),d("button",{type:"button",class:"symbols-item",role:"menuitem",key:a.line+a.name,onClick:p=>e.goToSymbol(a.line)},[n("span",{class:O(["symbols-kind","is-"+a.kind])},u(a.kind==="class"?"C":a.kind==="function"?"\u0192":"v"),3),n("span",jV,u(a.name),1),n("span",GV,u(a.line),1)],8,HV))),128))])):c("v-if",!0)])):c("v-if",!0),e.type=="html"?(l(),d("button",{key:1,type:"button",class:O(["btn btn-sm btn-ghost btn-icon-only btn-find btn-md-find",{"is-on":e.mdFindOpen}]),"aria-label":"Find on this page",title:"Find on this page ("+(e.isMac?"\u2318":"Ctrl+")+"F)",onClick:t[4]||(t[4]=a=>e.toggleMdFind())},[...t[44]||(t[44]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-search"})],-1)])],10,WV)):c("v-if",!0),e.type!="html"?(l(),d("button",{key:2,type:"button",class:"btn btn-sm btn-ghost btn-icon-only btn-find","aria-label":"Find in file",title:"Find in file ("+(e.isMac?"\u2318":"Ctrl+")+"F)",onClick:t[5]||(t[5]=a=>e.findInFile())},[...t[45]||(t[45]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-search"})],-1)])],8,KV)):c("v-if",!0),e.type!="html"?(l(),d("button",{key:3,type:"button",class:"btn btn-sm btn-ghost btn-icon-only btn-goto","aria-label":"Go to line",title:"Go to line ("+(e.isMac?"\u2318":"Ctrl+")+"G)",onClick:t[6]||(t[6]=a=>e.gotoLine())},[...t[46]||(t[46]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-goto"})],-1)])],8,YV)):c("v-if",!0),e.type!="html"?(l(),d("button",{key:4,type:"button",class:O(["btn btn-sm btn-icon-only btn-ghost btn-toggle",{"is-on":e.wrapLines}]),"aria-pressed":e.wrapLines?"true":"false","aria-label":"Wrap long lines",title:"Wrap long lines (Alt+Z)",onClick:t[7]||(t[7]=a=>e.toggleWrap())},[...t[47]||(t[47]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-wrap"})],-1)])],10,JV)):c("v-if",!0),n("div",QV,[n("a",{target:"_self",class:"tb-seg-btn",title:e.type=="html"?"Open the Markdown source":"Open the raw file",href:e.safeUrl(e.url)},"Raw",8,XV),typeof e.content=="string"?(l(),d("button",{key:0,type:"button",class:"tb-seg-btn tb-seg-icon","aria-label":e.contentCopied?"Copied":"Copy file contents",title:e.contentCopied?"Copied":"Copy file contents",onClick:t[8]||(t[8]=a=>e.copyContent())},[(l(),d("svg",xV,[n("use",{href:e.contentCopied?"#ui-icon-check":"#project-icon-copy"},null,8,e6)]))],8,ZV)):c("v-if",!0),n("a",{target:"_self",class:"tb-seg-btn tb-seg-icon","aria-label":"Download file",title:"Download file",href:e.safeUrl(e.url+"&download=true")},[...t[48]||(t[48]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-download"})],-1)])],8,t6)]),typeof e.content=="string"?(l(),d("button",{key:5,type:"button",class:"btn btn-sm btn-icon-only btn-ghost tb-copy-m","aria-label":e.contentCopied?"Copied":"Copy file contents",onClick:t[9]||(t[9]=a=>e.copyContent())},[(l(),d("svg",o6,[n("use",{href:e.contentCopied?"#ui-icon-check":"#project-icon-copy"},null,8,s6)]))],8,n6)):c("v-if",!0),e.type=="html"&&e.readmeToc().length>=3?(l(),d("div",i6,[n("button",{type:"button",class:O(["btn btn-sm btn-icon-only btn-ghost tb-toc-btn",{"is-on":e.tocOpen}]),"aria-label":"On this page",title:"On this page","aria-haspopup":"true","aria-expanded":e.tocOpen?"true":"false",onClick:t[10]||(t[10]=ae(a=>{e.tocOpen=!e.tocOpen,e.moreOpen=!1},["stop"]))},[...t[49]||(t[49]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-outline"})],-1)])],10,r6),e.tocOpen?(l(),d("div",{key:0,class:"tb-menu tb-toc-menu",role:"menu",onClick:t[12]||(t[12]=a=>e.tocOpen=!1)},[t[50]||(t[50]=n("div",{class:"tb-menu-label"},"On this page",-1)),n("button Line truncated
`).length))+" lines",1)],64)):c("v-if",!0),h(" \xB7 "+u(e.type=="html"&&e.fileSize(e.filePath)!=null?e.formatSize(e.fileSize(e.filePath)):e.content.length<1024?e.content.length+" B":(e.content.length/1024).toFixed(1)+" KB"),1)])):c("v-if",!0),e.options?.publishedAt||e.options?.sourceCommitDate||e.options?.anonymizedAt||e.options?.lastUpdateDate?(l(),d("div",f6)):c("v-if",!0),e.type=="html"?(l(),d("button",{key:3,type:"button",role:"menuitem",onClick:t[14]||(t[14]=a=>e.toggleMdFind())},[...t[53]||(t[53]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-search"})],-1),h("Find in file",-1)])])):c("v-if",!0),e.type=="html"?(l(),d("div",m6)):c("v-if",!0),e.type!="html"?(l(),d("button",{key:5,type:"button",role:"menuitem",onClick:t[15]||(t[15]=a=>e.findInFile())},[...t[54]||(t[54]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-search"})],-1),h("Find in file",-1)])])):c("v-if",!0),e.type!="html"?(l(),d("button",{key:6,type:"button",role:"menuitem",onClick:t[16]||(t[16]=a=>e.gotoLine())},[...t[55]||(t[55]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-goto"})],-1),h("Go to line",-1)])])):c("v-if",!0),e.type!="html"?(l(),d("button",{key:7,type:"button",role:"menuitemcheckbox","aria-checked":e.wrapLines?"true":"false",onClick:t[17]||(t[17]=a=>e.toggleWrap())},[t[56]||(t[56]=n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-wrap"})],-1)),t[57]||(t[57]=h("Wrap lines",-1)),e.wrapLines?(l(),d("span",v6,"\u2713")):c("v-if",!0)],8,h6)):c("v-if",!0),e.type!="html"?(l(),d("div",g6)):c("v-if",!0),e.type=="html"?(l(),d("a",{key:9,role:"menuitem",target:"_self",href:e.safeUrl(e.url)},[...t[58]||(t[58]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-code"})],-1),h("View raw",-1)])],8,y6)):c("v-if",!0),e.type!="html"?(l(),d("a",{key:10,role:"menuitem",target:"_self",href:e.safeUrl(e.url)},[...t[59]||(t[59]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-code"})],-1),h("View raw",-1)])],8,b6)):c("v-if",!0),n("a",{role:"menuitem",target:"_self",href:e.safeUrl(e.url+"&download=true")},[...t[60]||(t[60]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-download"})],-1),h("Download file",-1)])],8,w6),e.options?.hasWebsite?(l(),d("a",{key:11,role:"menuitem",target:"_self",href:e.safeUrl("/w/"+e.repoId+"/")},[...t[61]||(t[61]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-globe"})],-1),h("Open website",-1)])],8,k6)):c("v-if",!0),e.options?.isAdmin||e.options?.isOwner?(l(),d("a",{key:12,role:"menuitem",href:e.safeUrl("/anonymize/"+e.repoId)},[...t[62]||(t[62]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-edit"})],-1),h("Edit anonymization",-1)])],8,C6)):c("v-if",!0),e.options?.download?(l(),d("a",{key:13,role:"menuitem",target:"_self",href:e.safeUrl("/api/repo/"+e.repoId+"/zip")},[...t[63]||(t[63]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-archive"})],-1),h("Download ZIP",-1)])],8,E6)):c("v-if",!0),n("button",{type:"button",role:"menuitem",onClick:t[18]||(t[18]=a=>e.copyPath())},[...t[64]||(t[64]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-link"})],-1),h("Copy file path",-1)])]),t[65]||(t[65]=n("div",{class:"tb-menu-sep"},null,-1)),t[66]||(t[66]=n("a",{role:"menuitem",href:"/faq"},[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-help"})]),h("FAQ")],-1)),t[67]||(t[67]=n("a",{role:"menuitem",href:"https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml",target:"_blank",rel:"noopener"},[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-bug"})]),h("Report a bug")],-1))])):c("v-if",!0)])]),e.gotoOpen&&e.type!="html"?(l(),d("form",{key:2,class:"goto-pop",role:"dialog","aria-label":"Go to line",onSubmit:t[22]||(t[22]=ae(a=>e.submitGoto(),["prevent"]))},[t[68]||(t[68]=n("label",{class:"goto-label",for:"goto-input"},"Go to line",-1)),T(n("input",{id:"goto-input",class:"goto-input",type:"text",inputmode:"numeric",autocomplete:"off",spellcheck:"false",placeholder:"1\u2013"+e.fmt?.number(typeof e.content=="string"?e.content.split(`
`).length:1),"aria-invalid":e.gotoError?"true":"false","onUpdate:modelValue":t[20]||(t[20]=a=>e.gotoValue=a),onKeydown:t[21]||(t[21]=ct(ae(a=>e.closeGoto(),["prevent","stop"]),["esc"]))},null,40,S6),[[ot,e.gotoValue]]),n("span",{class:O(["goto-hint",{"is-error":e.gotoError}])},u(e.gotoError||"Line, or line:column"),3)],32)):c("v-if",!0)]),e.type!="html"?T((l(),d("div",N6,null,512)),[[r,{content:e.content,options:e.aceOption}]]):c("v-if",!0),e.type=="html"&&e.mdFindOpen?(l(),d("div",R6,[n("input",{type:"search",class:"md-find-input",placeholder:"Find on this page","aria-label":"Find on this page",value:e.mdFindQuery,onInput:t[23]||(t[23]=a=>{e.mdFindQuery=a.target.value,e.runMdFind()}),onKeydown:[t[24]||(t[24]=ct(ae(a=>a.shiftKey?e.stepMdFind(-1):e.stepMdFind(1),["prevent"]),["enter"])),t[25]||(t[25]=ct(ae(a=>e.toggleMdFind(!1),["prevent"]),["esc"]))]},null,40,D6),n("span",T6,[n("button",{type:"button","aria-label":"Previous match",onClick:t[26]||(t[26]=a=>e.stepMdFind(-1)),disabled:!e.mdFindTotal},[...t[69]||(t[69]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-chevron-left"})],-1)])],8,_6),n("button",{type:"button","aria-label":"Next match",onClick:t[27]||(t[27]=a=>e.stepMdFind(1)),disabled:!e.mdFindTotal},[...t[70]||(t[70]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-chevron-right"})],-1)])],8,A6)]),n("span",O6,u(e.mdFindQuery?e.mdFindTotal?e.mdFindIndex+1+" of "+e.mdFindTotal:"No results":""),1),n("button",{type:"button",class:O(["md-find-opt",{"is-on":e.mdFindCase}]),"aria-pressed":e.mdFindCase?"true":"false",title:"Match case","aria-label":"Match case",onClick:t[28]||(t[28]=a=>{e.mdFindCase=!e.mdFindCase,e.runMdFind()})},"Aa",10,P6),n("button",{type:"button",class:"md-find-close","aria-label":"Close find",onClick:t[29]||(t[29]=a=>e.toggleMdFind(!1))},"\xD7")])):c("v-if",!0),e.type=="html"?(l(),d("div",I6,[n("div",{class:"file-content markdown-body",innerHTML:e.renderReadme(e.sanitize(e.content))},null,8,M6),e.readmeToc().length>=3?(l(),d("aside",V6,[t[71]||(t[71]=n("div",{class:"readme-toc-head"},"On this page",-1)),n("nav",q6,[n("a",{href:"#",class:O(["lvl-2 toc-top",{"is-active":!e.activeHeading}]),onClick:t[30]||(t[30]=ae(a=>e.scrollToHeading(null),["prevent"]))},"Introduction",2),(l(!0),d(W,null,oe(e.readmeToc(),(a,p)=>(l(),d("a",{key:a.id,href:"#"+a.id,class:O(["lvl-"+a.level,{"is-active":e.activeHeading===a.id}]),onClick:ae(f=>e.scrollToHeading(a.id),["prevent"])},u(a.text),11,L6))),128))])])):c("v-if",!0)])):c("v-if",!0)],2)):c("v-if",!0),e.type=="html-doc"&&!e.showSource&&e.content!=null?(l(),Bt(o,{key:2,content:e.content,"base-url":e.fileBaseUrl,"allow-scripts":e.allowScripts},null,8,["content","base-url","allow-scripts"])):c("v-if",!0),e.type=="image"?(l(),d("img",{key:3,class:"image-content",src:e.safeUrl(e.url)},null,8,$6)):c("v-if",!0),e.type=="media"?(l(),d("iframe",{key:4,class:"h-100 overflow-auto w-100 b-0",src:e.safeUrl(e.url)},null,8,U6)):c("v-if",!0),e.type=="pdf"?(l(),Bt(i,{key:5,src:e.safeUrl(e.url)},null,8,["src"])):c("v-if",!0),e.type=="audio"?(l(),d("div",F6,[n("audio",B6,[n("source",{src:e.safeUrl(e.url)},null,8,z6)])])):c("v-if",!0),e.type=="IPython"?(l(),d("div",H6,[De(s,{file:e.url,content:e.content},null,8,["file","content"])])):c("v-if",!0),e.type=="rate_limited"?(l(),d("div",j6,[n("div",G6,[t[74]||(t[74]=me('<div class="paper-ratelimit-head"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-hourglass"></use></svg><div><div class="paper-error-eyebrow">Temporarily paused</div><div class="paper-error-title">GitHub API rate limit reached</div></div></div>',1)),n("p",W6,[t[72]||(t[72]=h("This repository will be available in ",-1)),n("strong",null,u(e.rateLimitCountdown),1),t[73]||(t[73]=h(". The page will reload automatically.",-1))])])])):c("v-if",!0),e.type=="error"?(l(),d("div",K6,[n("section",Y6,[n("h1",J6,u(e.fmt.translate(e.isSourceAccessError()?"VIEWER_ERRORS.access_title":"VIEWER_ERRORS.title")),1),n("p",null,u(e.fmt.translate("ERRORS."+e.content)),1),e.isSourceAccessError()?(l(),d(W,{key:0},[n("p",null,u(e.fmt.translate("VIEWER_ERRORS.reader_help")),1),n("p",null,u(e.fmt.translate("VIEWER_ERRORS.owner_help")),1)],64)):c("v-if",!0),n("div",Q6,[e.isSourceAccessError()?c("v-if",!0):(l(),d("a",X6,"Back to home")),e.isSourceAccessError()?c("v-if",!0):(l(),d("a",Z6,"Read the FAQ")),n("button",{type:"button",class:"btn btn-primary",onClick:t[31]||(t[31]=a=>e.retryContent())},u(e.fmt.translate("VIEWER_ERRORS.retry")),1),e.isSourceAccessError()?(l(),d("a",x6,u(e.fmt.translate("VIEWER_ERRORS.dashboard")),1)):c("v-if",!0)])])])):c("v-if",!0),e.type=="loading"&&!e.error?(l(),d("section",eq,[n("div",tq,[n("strong",null,u(e.fmt.translate(e.fileReceivedBytes?"VIEWER_LOADING.receiving":"VIEWER_LOADING.loading")),1),n("span",nq,u(e.filePath),1),e.fileLoadingSlow?(l(),d("p",oq,u(e.fmt.translate("VIEWER_LOADING.slow")),1)):c("v-if",!0)]),n("div",sq,[(l(),d(W,null,oe(10,a=>n("span",{key:a})),64))])])):c("v-if",!0),e.type== Line truncated
<span class="ln">10</span> log(<span class="s">&quot;epoch %d: %.3f&quot;</span>, epoch, loss)</pre></div>`,2)])])):(l(),d("div",Lq,[...t[17]||(t[17]=[Ce('<div class="fm-dash-head"><span>Project</span><span>Status</span><span>Views</span><span>Expires</span></div><div class="fm-dash-row"><span><b>DeepLearnUtils</b><i>paper-7f2a \xB7 ICSE 2027</i></span><span class="st is-ready">Ready</span><span>41</span><span>Mar 31, 2027</span></div><div class="fm-dash-row"><span><b>vision-bench#212</b><i>pull request \xB7 FSE 2027</i></span><span class="st is-ready">Ready</span><span>12</span><span>Never</span></div><div class="fm-dash-row"><span><b>graph-repair</b><i>gr-91ab</i></span><span class="st is-progress">Updating</span><span>5</span><span>Jan 5, 2027</span></div><div class="fm-dash-row is-muted"><span><b>JarSift</b><i>OOPSLA 2025</i></span><span class="st is-expired">Expired</span><span>72</span><span>Sep 28, 2026</span></div>',5)])]))],10,Vq)])],8,Oq)),[[J,e.feature===s?.key]])),128))])]),f(" FAQ teaser "),t[27]||(t[27]=Ce('<section class="paper-qa paper-wrap" aria-labelledby="qa-heading"><div><div class="paper-eyebrow">Before you sign in</div><h2 id="qa-heading">The questions that come up most.</h2><a class="paper-link-arrow" href="/faq">Read the full FAQ \u2192</a></div><div><div class="q"><a href="/faq#permissions">What access does GitHub sign-in require?</a><p> The GitHub App has read-only access to gists and the repositories you choose. Legacy OAuth uses broader permissions. Anonymous GitHub never writes to your repositories. </p></div><div class="q"><a href="/faq#formats">Which file formats are supported?</a><p> Source code with syntax highlighting, Markdown, Jupyter notebooks, PDFs, images, and GitHub Pages sites. Text files are anonymized; enabled images and PDFs are served unchanged. </p></div><div class="q"><a href="/faq#expiration">What happens when an anonymized repository expires?</a><p> You choose: the mirror is removed, or visitors are redirected to the original GitHub repository once the review is over. </p></div></div></section><section class="paper-cta paper-wrap" aria-labelledby="cta-heading"><div><h2 id="cta-heading">Ready for review?</h2><p>Create an anonymous mirror in a couple of minutes. Reviewers just open the link.</p></div><div class="paper-cta-actions"><a class="btn-hero" href="/signin" target="_self"><i class="fab fa-github" aria-hidden="true"></i> Sign in with GitHub</a><a class="paper-link-arrow" href="/faq">Read the FAQ \u2192</a></div></section>',2)),n("footer",Uq,[n("div",Fq,[t[21]||(t[21]=n("div",{class:"paper-footer-brand"},[n("div",{class:"paper-footer-mark"},[y("Anonymous "),n("em",null,"GitHub")]),n("p",{class:"paper-footer-tag"}," A read-only, identity-stripped mirror of your repository, built for double-anonymous peer review. ")],-1)),n("div",Bq,[t[18]||(t[18]=n("div",{class:"paper-footer-head"},"Product",-1)),t[19]||(t[19]=n("a",{href:"/anonymize"},"Anonymize",-1)),e.user?(l(),d("a",zq,"My work")):f("v-if",!0),e.user?(l(),d("a",Hq,"Conferences")):f("v-if",!0),t[20]||(t[20]=n("a",{href:"/faq"},"FAQ",-1))]),t[22]||(t[22]=Ce('<div class="paper-footer-col"><div class="paper-footer-head">Project</div><a href="https://github.com/tdurieux/anonymous_github/" target="_blank" rel="noopener">Source code</a><a href="https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml" target="_blank" rel="noopener">Report a bug</a><a href="https://github.com/sponsors/tdurieux/" target="_blank" rel="noopener">Support</a></div><div class="paper-footer-col"><div class="paper-footer-head">Contact</div><a href="mailto:tdurieux@anonymous.4open.science">Email maintainer</a><a href="https://github.com/tdurieux" target="_blank" rel="noopener">@tdurieux</a></div>',2))]),t[24]||(t[24]=n("div",{class:"paper-footer-rule"},null,-1)),n("div",jq,[n("span",null,"\xA9 "+p(e.year||2026)+" Anonymous GitHub \xB7 GPL-3.0 licensed",1),t[23]||(t[23]=n("span",{class:"paper-footer-meta"},"Built for reviewers, by researchers.",-1))])])])}var Gq={class:"paper-empty"},Wq={class:"paper-empty-inner"},Kq={key:0,class:"paper-eyebrow"},Yq={key:1,class:"paper-eyebrow"},Xq={key:2,class:"paper-empty-title"},Jq=["textContent"];function _c(e,t){return l(),d("div",Gq,[n("div",Wq,[e.error?f("v-if",!0):(l(),d("div",Kq,"Working")),e.error?(l(),d("div",Yq,"Error")):f("v-if",!0),e.error?f("v-if",!0):(l(),d("h1",Xq,[...t[0]||(t[0]=[y(" Loading",-1),n("span",{class:"dot-anim"},"\u2026",-1)])])),e.error?(l(),d("h1",{key:3,class:"paper-empty-title",textContent:p(e.fmt.translate(e.error))},null,8,Jq)):f("v-if",!0)])])}var Qq={class:"container paper-page paper-settings"},Zq={class:"paper-crumbs"},xq={class:"here"},e$={class:"paper-page-title"},t$={class:"paper-settings-body"},n$={class:"paper-settings-toc"},s$={href:"#conf-billing"},o$={class:"form needs-validation paper-settings-main",name:"conference",novalidate:""},i$={id:"conf-basics",class:"paper-settings-section"},r$={class:"form-group"},a$={class:"invalLine truncated
`).length))+" lines",1)):f("v-if",!0),e.type=="html"&&e.fileSize(e.filePath)!=null?(l(),d("span",yL,p(e.formatSize(e.fileSize(e.filePath))),1)):f("v-if",!0),e.redactionCount()?(l(),d("b",bL,p(e.redactionCount())+" redacted",1)):f("v-if",!0)]),T(n("button",{type:"button",class:"btn btn-sm btn-icon-only btn-ghost copy-path-btn","aria-label":e.pathCopied?"Path copied":"Copy file path",title:e.pathCopied?"Path copied":"Copy file path",onClick:t[2]||(t[2]=a=>e.copyPath())},[(l(),d("svg",kL,[n("use",{href:e.pathCopied?"#ui-icon-check":"#ui-icon-link"},null,8,CL)]))],8,wL),[[J,e.filePath]])]),e.type!="html"&&typeof e.content=="string"?(l(),d("span",EL,[e.languageName?(l(),d(W,{key:0},[y(p(e.languageName),1),t[37]||(t[37]=n("span",{class:"sep"},"\xB7",-1))],64)):f("v-if",!0),y(p(e.fmt?.number(e.content.split(`
`).length))+" lines",1),n("span",SL,[t[38]||(t[38]=n("span",{class:"sep"},"\xB7",-1)),y(p(e.content.length<1024?e.content.length+" B":(e.content.length/1024).toFixed(1)+" KB"),1)]),e.redactionCount()?(l(),d(W,{key:1},[t[39]||(t[39]=n("span",{class:"sep"},"\xB7",-1)),n("span",NL,p(e.redactionCount())+" redacted",1)],64)):f("v-if",!0)])):f("v-if",!0),e.type=="html"?(l(),d("span",RL,[t[42]||(t[42]=y("Markdown",-1)),e.fileSize(e.filePath)!=null?(l(),d(W,{key:0},[t[40]||(t[40]=n("span",{class:"sep"},"\xB7",-1)),y(p(e.formatSize(e.fileSize(e.filePath))),1)],64)):f("v-if",!0),e.redactionCount()?(l(),d(W,{key:1},[t[41]||(t[41]=n("span",{class:"sep"},"\xB7",-1)),n("span",DL,p(e.redactionCount())+" redacted",1)],64)):f("v-if",!0)])):f("v-if",!0),n("div",TL,[e.type!="html"&&e.symbols().length>1?(l(),d("div",AL,[n("button",{type:"button",class:_(["btn btn-sm btn-ghost btn-symbols",{"is-on":e.symbolsOpen}]),"aria-expanded":e.symbolsOpen?"true":"false","aria-haspopup":"true",title:"Symbols in this file",onClick:t[3]||(t[3]=a=>e.symbolsOpen=!e.symbolsOpen)},[...t[43]||(t[43]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-list"})],-1),n("span",{class:"btn-find-label"},"Symbols",-1)])],10,_L),e.symbolsOpen?(l(),d("div",OL,[n("div",PL,p(e.symbols().length)+" "+p(e.symbols().length===1?"symbol":"symbols"),1),(l(!0),d(W,null,ae(e.symbols(),a=>(l(),d("button",{type:"button",class:"symbols-item",role:"menuitem",key:a.line+a.name,onClick:u=>e.goToSymbol(a.line)},[n("span",{class:_(["symbols-kind","is-"+a.kind])},p(a.kind==="class"?"C":a.kind==="function"?"\u0192":"v"),3),n("span",ML,p(a.name),1),n("span",VL,p(a.line),1)],8,IL))),128))])):f("v-if",!0)])):f("v-if",!0),e.type=="html"?(l(),d("button",{key:1,type:"button",class:_(["btn btn-sm btn-ghost btn-icon-only btn-find btn-md-find",{"is-on":e.mdFindOpen}]),"aria-label":"Find on this page",title:"Find on this page ("+(e.isMac?"\u2318":"Ctrl+")+"F)",onClick:t[4]||(t[4]=a=>e.toggleMdFind())},[...t[44]||(t[44]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-search"})],-1)])],10,qL)):f("v-if",!0),e.type!="html"?(l(),d("button",{key:2,type:"button",class:"btn btn-sm btn-ghost btn-icon-only btn-find","aria-label":"Find in file",title:"Find in file ("+(e.isMac?"\u2318":"Ctrl+")+"F)",onClick:t[5]||(t[5]=a=>e.findInFile())},[...t[45]||(t[45]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-search"})],-1)])],8,$L)):f("v-if",!0),e.type!="html"?(l(),d("button",{key:3,type:"button",class:"btn btn-sm btn-ghost btn-icon-only btn-goto","aria-label":"Go to line",title:"Go to line ("+(e.isMac?"\u2318":"Ctrl+")+"G)",onClick:t[6]||(t[6]=a=>e.gotoLine())},[...t[46]||(t[46]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-goto"})],-1)])],8,LL)):f("v-if",!0),e.type!="html"?(l(),d("button",{key:4,type:"button",class:_(["btn btn-sm btn-icon-only btn-ghost btn-toggle",{"is-on":e.wrapLines}]),"aria-pressed":e.wrapLines?"true":"false","aria-label":"Wrap long lines",title:"Wrap long lines (Alt+Z)",onClick:t[7]||(t[7]=a=>e.toggleWrap())},[...t[47]||(t[47]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-wrap"})],-1)])],10,UL)):f("v-if",!0),n("div",FL,[n("a",{target:"_self",class:"tb-seg-btn",title:e.type=="html"?"Open the Markdown source":"Open the raw file",href:e.safeUrl(e.url)},"Raw",8,BL),typeof e.content=="string"?(l(),d("button",{key:0,type:"button",class:"tb-seg-btn tb-seg-icon","aria-label":e.contentCopied?"Copied":"Copy file contents",title:e.contentCopied?"Copied":"Copy file contents",onClick:t[8]||(t[8]=a=>e.copyContent())},[(l(),d("svg",HL,[n("use",{href:e.contentCopied?"#ui-icon-check":"#project-icon-copy"},null,8,jL)]))],8,zL)):f("v-if",!0),n("a",{target:"_self",class:"tb-seg-btn tb-seg-icon","aria-label":"Download file",title:"Download file",href:e.safeUrl(e.url+"&download=true")},[...t[48]||(t[48]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-download"})],-1)])],8,GL)]),typeof e.content=="string"?(l(),d("button",{key:5,type:"button",class:"btn btn-sm btn-icon-only btn-ghost tb-copy-m","aria-label":e.contentCopied?"Copied":"Copy file contents",onClick:t[9]||(t[9]=a=>e.copyContent())},[(l(),d("svg",KL,[n("use",{href:e.contentCopied?"#ui-icon-check":"#project-icon-copy"},null,8,YL)]))],8,WL)):f("v-if",!0),e.type=="html"&&e.readmeToc().length>=3?(l(),d("div",XL,[n("button",{type:"button",class:_(["btn btn-sm btn-icon-only btn-ghost tb-toc-btn",{"is-on":e.tocOpen}]),"aria-label":"On this page",title:"On this page","aria-haspopup":"true","aria-expanded":e.tocOpen?"true":"false",onClick:t[10]||(t[10]=ce(a=>{e.tocOpen=!e.tocOpen,e.moreOpen=!1},["stop"]))},[...t[49]||(t[49]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-outline"})],-1)])],10,JL),e.tocOpen?(l(),d("div",{key:0,class:"tb-menu tb-toc-menu",role:"menu",onClick:t[12]||(t[12]=a=>e.tocOpen=!1)},[t[50]||(t[50]=n("div",{class:"tb-menu-label"},"On this page",-1)),n("button Line truncated
`).length))+" lines",1)],64)):f("v-if",!0),y(" \xB7 "+p(e.type=="html"&&e.fileSize(e.filePath)!=null?e.formatSize(e.fileSize(e.filePath)):e.content.length<1024?e.content.length+" B":(e.content.length/1024).toFixed(1)+" KB"),1)])):f("v-if",!0),e.options?.publishedAt||e.options?.sourceCommitDate||e.options?.anonymizedAt||e.options?.lastUpdateDate?(l(),d("div",sU)):f("v-if",!0),e.type=="html"?(l(),d("button",{key:3,type:"button",role:"menuitem",onClick:t[14]||(t[14]=a=>e.toggleMdFind())},[...t[53]||(t[53]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-search"})],-1),y("Find in file",-1)])])):f("v-if",!0),e.type=="html"?(l(),d("div",oU)):f("v-if",!0),e.type!="html"?(l(),d("button",{key:5,type:"button",role:"menuitem",onClick:t[15]||(t[15]=a=>e.findInFile())},[...t[54]||(t[54]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-search"})],-1),y("Find in file",-1)])])):f("v-if",!0),e.type!="html"?(l(),d("button",{key:6,type:"button",role:"menuitem",onClick:t[16]||(t[16]=a=>e.gotoLine())},[...t[55]||(t[55]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-goto"})],-1),y("Go to line",-1)])])):f("v-if",!0),e.type!="html"?(l(),d("button",{key:7,type:"button",role:"menuitemcheckbox","aria-checked":e.wrapLines?"true":"false",onClick:t[17]||(t[17]=a=>e.toggleWrap())},[t[56]||(t[56]=n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-wrap"})],-1)),t[57]||(t[57]=y("Wrap lines",-1)),e.wrapLines?(l(),d("span",rU,"\u2713")):f("v-if",!0)],8,iU)):f("v-if",!0),e.type!="html"?(l(),d("div",aU)):f("v-if",!0),e.type=="html"?(l(),d("a",{key:9,role:"menuitem",target:"_self",href:e.safeUrl(e.url)},[...t[58]||(t[58]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-code"})],-1),y("View raw",-1)])],8,lU)):f("v-if",!0),e.type!="html"?(l(),d("a",{key:10,role:"menuitem",target:"_self",href:e.safeUrl(e.url)},[...t[59]||(t[59]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-code"})],-1),y("View raw",-1)])],8,dU)):f("v-if",!0),n("a",{role:"menuitem",target:"_self",href:e.safeUrl(e.url+"&download=true")},[...t[60]||(t[60]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-download"})],-1),y("Download file",-1)])],8,uU),e.options?.hasWebsite?(l(),d("a",{key:11,role:"menuitem",target:"_self",href:e.safeUrl("/w/"+e.repoId+"/")},[...t[61]||(t[61]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-globe"})],-1),y("Open website",-1)])],8,cU)):f("v-if",!0),e.options?.isAdmin||e.options?.isOwner?(l(),d("a",{key:12,role:"menuitem",href:e.safeUrl("/anonymize/"+e.repoId)},[...t[62]||(t[62]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-edit"})],-1),y("Edit anonymization",-1)])],8,pU)):f("v-if",!0),e.options?.download?(l(),d("a",{key:13,role:"menuitem",target:"_self",href:e.safeUrl("/api/repo/"+e.repoId+"/zip")},[...t[63]||(t[63]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-archive"})],-1),y("Download ZIP",-1)])],8,fU)):f("v-if",!0),n("button",{type:"button",role:"menuitem",onClick:t[18]||(t[18]=a=>e.copyPath())},[...t[64]||(t[64]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-link"})],-1),y("Copy file path",-1)])]),t[65]||(t[65]=n("div",{class:"tb-menu-sep"},null,-1)),t[66]||(t[66]=n("a",{role:"menuitem",href:"/faq"},[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-help"})]),y("FAQ")],-1)),t[67]||(t[67]=n("a",{role:"menuitem",href:"https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml",target:"_blank",rel:"noopener"},[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-bug"})]),y("Report a bug")],-1))])):f("v-if",!0)])]),e.gotoOpen&&e.type!="html"?(l(),d("form",{key:2,class:"goto-pop",role:"dialog","aria-label":"Go to line",onSubmit:t[22]||(t[22]=ce(a=>e.submitGoto(),["prevent"]))},[t[68]||(t[68]=n("label",{class:"goto-label",for:"goto-input"},"Go to line",-1)),T(n("input",{id:"goto-input",class:"goto-input",type:"text",inputmode:"numeric",autocomplete:"off",spellcheck:"false",placeholder:"1\u2013"+e.fmt?.number(typeof e.content=="string"?e.content.split(`
`).length:1),"aria-invalid":e.gotoError?"true":"false","onUpdate:modelValue":t[20]||(t[20]=a=>e.gotoValue=a),onKeydown:t[21]||(t[21]=Tt(ce(a=>e.closeGoto(),["prevent","stop"]),["esc"]))},null,40,hU),[[dt,e.gotoValue]]),n("span",{class:_(["goto-hint",{"is-error":e.gotoError}])},p(e.gotoError||"Line, or line:column"),3)],32)):f("v-if",!0)]),e.type!="html"?T((l(),d("div",mU,null,512)),[[r,{content:e.content,options:e.aceOption}]]):f("v-if",!0),e.type=="html"&&e.mdFindOpen?(l(),d("div",gU,[n("input",{type:"search",class:"md-find-input",placeholder:"Find on this page","aria-label":"Find on this page",value:e.mdFindQuery,onInput:t[23]||(t[23]=a=>{e.mdFindQuery=a.target.value,e.runMdFind()}),onKeydown:[t[24]||(t[24]=Tt(ce(a=>a.shiftKey?e.stepMdFind(-1):e.stepMdFind(1),["prevent"]),["enter"])),t[25]||(t[25]=Tt(ce(a=>e.toggleMdFind(!1),["prevent"]),["esc"]))]},null,40,vU),n("span",yU,[n("button",{type:"button","aria-label":"Previous match",onClick:t[26]||(t[26]=a=>e.stepMdFind(-1)),disabled:!e.mdFindTotal},[...t[69]||(t[69]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-chevron-left"})],-1)])],8,bU),n("button",{type:"button","aria-label":"Next match",onClick:t[27]||(t[27]=a=>e.stepMdFind(1)),disabled:!e.mdFindTotal},[...t[70]||(t[70]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-chevron-right"})],-1)])],8,wU)]),n("span",kU,p(e.mdFindQuery?e.mdFindTotal?e.mdFindIndex+1+" of "+e.mdFindTotal:"No results":""),1),n("button",{type:"button",class:_(["md-find-opt",{"is-on":e.mdFindCase}]),"aria-pressed":e.mdFindCase?"true":"false",title:"Match case","aria-label":"Match case",onClick:t[28]||(t[28]=a=>{e.mdFindCase=!e.mdFindCase,e.runMdFind()})},"Aa",10,CU),n("button",{type:"button",class:"md-find-close","aria-label":"Close find",onClick:t[29]||(t[29]=a=>e.toggleMdFind(!1))},"\xD7")])):f("v-if",!0),e.type=="html"?(l(),d("div",EU,[n("div",{class:"file-content markdown-body",innerHTML:e.renderReadme(e.sanitize(e.content))},null,8,SU),e.readmeToc().length>=3?(l(),d("aside",NU,[t[71]||(t[71]=n("div",{class:"readme-toc-head"},"On this page",-1)),n("nav",RU,[n("a",{href:"#",class:_(["lvl-2 toc-top",{"is-active":!e.activeHeading}]),onClick:t[30]||(t[30]=ce(a=>e.scrollToHeading(null),["prevent"]))},"Introduction",2),(l(!0),d(W,null,ae(e.readmeToc(),(a,u)=>(l(),d("a",{key:a.id,href:"#"+a.id,class:_(["lvl-"+a.level,{"is-active":e.activeHeading===a.id}]),onClick:ce(c=>e.scrollToHeading(a.id),["prevent"])},p(a.text),11,DU))),128))])])):f("v-if",!0)])):f("v-if",!0)],2)):f("v-if",!0),e.type=="html-doc"&&!e.showSource&&e.content!=null?(l(),sn(s,{key:2,content:e.content,"base-url":e.fileBaseUrl,"allow-scripts":e.allowScripts},null,8,["content","base-url","allow-scripts"])):f("v-if",!0),e.type=="image"?(l(),d("img",{key:3,class:"image-content",src:e.safeUrl(e.url)},null,8,TU)):f("v-if",!0),e.type=="media"?(l(),d("iframe",{key:4,class:"h-100 overflow-auto w-100 b-0",src:e.safeUrl(e.url)},null,8,AU)):f("v-if",!0),e.type=="pdf"?(l(),sn(i,{key:5,src:e.safeUrl(e.url)},null,8,["src"])):f("v-if",!0),e.type=="audio"?(l(),d("div",_U,[n("audio",OU,[n("source",{src:e.safeUrl(e.url)},null,8,PU)])])):f("v-if",!0),e.type=="IPython"?(l(),d("div",IU,[Ue(o,{file:e.url,content:e.content},null,8,["file","content"])])):f("v-if",!0),e.type=="rate_limited"?(l(),d("div",MU,[n("div",VU,[t[74]||(t[74]=Ce('<div class="paper-ratelimit-head"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-hourglass"></use></svg><div><div class="paper-error-eyebrow">Temporarily paused</div><div class="paper-error-title">GitHub API rate limit reached</div></div></div>',1)),n("p",qU,[t[72]||(t[72]=y("This repository will be available in ",-1)),n("strong",null,p(e.rateLimitCountdown),1),t[73]||(t[73]=y(". The page will reload automatically.",-1))])])])):f("v-if",!0),e.type=="error"?(l(),d("div",$U,[n("section",LU,[n("h1",UU,p(e.fmt.translate(e.isSourceAccessError()?"VIEWER_ERRORS.access_title":"VIEWER_ERRORS.title")),1),n("p",null,p(e.fmt.translate("ERRORS."+e.content)),1),e.isSourceAccessError()?(l(),d(W,{key:0},[n("p",null,p(e.fmt.translate("VIEWER_ERRORS.reader_help")),1),n("p",null,p(e.fmt.translate("VIEWER_ERRORS.owner_help")),1)],64)):f("v-if",!0),n("div",FU,[e.isSourceAccessError()?f("v-if",!0):(l(),d("a",BU,"Back to home")),e.isSourceAccessError()?f("v-if",!0):(l(),d("a",zU,"Read the FAQ")),n("button",{type:"button",class:"btn btn-primary",onClick:t[31]||(t[31]=a=>e.retryContent())},p(e.fmt.translate("VIEWER_ERRORS.retry")),1),e.isSourceAccessError()?(l(),d("a",HU,p(e.fmt.translate("VIEWER_ERRORS.dashboard")),1)):f("v-if",!0)])])])):f("v-if",!0),e.type=="loading"&&!e.error?(l(),d("section",jU,[n("div",GU,[n("strong",null,p(e.fmt.translate(e.fileReceivedBytes?"VIEWER_LOADING.receiving":"VIEWER_LOADING.loading")),1),n("span",WU,p(e.filePath),1),e.fileLoadingSlow?(l(),d("p",KU,p(e.fmt.translate("VIEWER_LOADING.slow")),1)):f("v-if",!0)]),n("div",YU,[(l(),d(W,null,ae(10,a=>n("span",{key:a})),64))])])):f("v-if",!0),e.type== Line truncated
`).length+1)),placeholder:`Jane Smith
MIT CSAIL
jane.smith@example.org`},bL={class:"settings-syntax"},wL={class:"invalid-feedback"},kL={class:"settings-row"},CL={class:"settings-checks"},EL={class:"settings-check"},SL={class:"form-check-input",type:"checkbox",id:"link",name:"link"},NL={class:"settings-check"},RL={class:"form-check-input",type:"checkbox",id:"notebook",name:"notebook"},DL={class:"settings-check"},TL={class:"form-check-input",type:"checkbox",id:"image",name:"image"},_L={class:"settings-check"},AL={class:"form-check-input",type:"checkbox",id:"pdf",name:"pdf"},OL={class:"settings-check"},PL={class:"form-check-input",type:"checkbox",id:"loc",name:"loc"},IL={class:"settings-check"},ML={class:"form-check-input",type:"checkbox",id:"page",name:"page"},VL={class:"settings-row"},qL={class:"settings-check"},LL={class:"form-check-input",type:"checkbox",id:"update",name:"update"},$L={class:"settings-row"},UL={class:"form-control",id:"expiration",name:"expiration"},FL={class:"settings-help"},BL={class:"settings-save"},zL={class:"settings-save-status draft-status",role:"status"},HL={key:0},jL={key:1},GL={key:2},WL=["disabled"],KL={key:1,class:"settings-save-error",role:"alert"},YL=["aria-busy"],JL={key:0,role:"status"},QL={key:1,class:"settings-notice",role:"alert"},XL=["disabled"],ZL={key:2,class:"settings-notice",role:"status"},xL={key:3,class:"settings-notice",role:"status"},e$=["disabled"],t$={class:"settings-row"},n$={class:"settings-inline"},o$={key:0,class:"settings-help"},s$={key:0,class:"settings-help"},i$={id:"settings-quota"},r$={key:1,role:"status"},a$={key:1,class:"settings-notice"},l$={key:2,class:"settings-notice"},d$={key:3,class:"settings-notice"},u$={key:4,class:"settings-help"},c$={key:5,class:"settings-plan billing-plan"},p$={class:"settings-comparison"},f$={class:"settings-cycles"},m$=["checked","onChange"],h$={class:"settings-help"},v$={class:"settings-actions"},g$=["disabled"],y$={key:6,class:"settings-help"},b$={class:"settings-row"},w$={key:0,class:"settings-inline"},k$=["disabled"],C$={key:1,class:"settings-help"},E$=["disabled"],S$={key:4,class:"settings-row"},N$={class:"settings-inline"},R$=["disabled"],D$={key:0,class:"settings-pass"},T$={class:"settings-help"},_$=["disabled"],A$={key:5,class:"settings-row"},O$={class:"settings-help"},P$={id:"settings-account",class:"settings-account-panel"},I$={class:"paper-account-card"},M$=["src"],V$={class:"paper-account-identity"},q$={class:"paper-account-name"},L$=["disabled"],$$={key:0,role:"status"},U$={key:1,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},F$=["disabled"],B$={key:3,role:"status"},z$={class:"paper-danger-zone"},H$={key:0,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},j$=["textContent"],G$=["disabled"],W$={key:1,class:"settings-delete-confirm"},K$={for:"delete-username"},Y$={class:"settings-actions"},J$=["disabled"],Q$=["disabled"];function td(e,t){let o=We("quota-usage"),i=we("field"),s=we("form");return l(),d("div",pL,[n("header",fL,[t[20]||(t[20]=n("h1",null,"Settings",-1)),n("div",mL,[n("span",null,"@"+u(e.user?.username),1)])]),n("nav",hL,[(l(),d(W,null,oe([{id:"defaults",label:"Anonymization defaults"},{id:"billing",label:"Hosting & billing"},{id:"account",label:"Account"}],r=>n("button",{type:"button","aria-current":e.settingsTab===r.id?"page":null,onClick:a=>e.settingsTab=r.id},u(r.label),9,vL)),64))]),T(n("div",null,[t[41]||(t[41]=n("p",{class:"settings-scope"},"For new anonymizations only. Existing repositories keep their settings.",-1)),T((l(),d("form",{class:"form needs-validation",name:"defaultsForm",novalidate:"",onSubmit:t[1]||(t[1]=ae(r=>e.submitForm(r,()=>{e.saveDefault(r)}),["prevent"]))},[n("section",gL,[t[26]||(t[26]=n("div",null,[n("label",{class:"settings-label",for:"terms"},"Terms to redact"),n("p",{class:"settings-help"},"One term per line.")],-1)),n("div",null,[T(n("textarea",yL,null,512),[[i,{state:e.viewState,set:r=>{e.terms=r},value:e.terms,form:"defaultsForm",options:{debounce:250}}]]),n("details",bL,[t[25]||(t[25]=n("summary",null,"Regex & replacement syntax",-1)),n("p",null,[t[21]||(t[21]=h("Matches become ",-1)),n("code",null,u(e.site_options?.ANONYMIZATION_MASK||"XXX")+"-[N]",1),t[22]||(t[22]=h(". Use ",-1)),t[23]||(t[23]=n("code",null,"term=>replacement",-1)),t[24]||(t[24]=h(" for a custom replacement. Regex is supported.",-1))])]),T(n("div",wL,"Terms are in an invalid format.",512),[[Y,e.defaultsForm?.terms?.errors?.format]])])]),n("section",kL,[t[35]||(t[35]=n("h2",null,"Reviewer display",-1)),n("div",null,[n("div",CL,[n("label",EL,[T(n("input",SL,null,512),[[i,{state:e.viewState,set:r=>{e.options.link=r},value:e.options?.link,form:"defaultsForm",options:{}}]]),t[27]||(t[27]=h("Keep links",-1))]),n("label",NL,[T(n("input",RL,null,512),[[i,{state:e.viewState,set:r=>{e.options.notebook=r},value:e.options?.notebook,form:"defaultsForm",options:{}}]]),t[28]||(t[28]=h("Render notebooks",-1))]),n("label",DL,[T(n("input",TL,null,512),[[i,{state:e.viewState,set:r=>{e.options.image=r},value:e.options?.image Line truncated
`);for(let b=0;b<y.length;b++){let m=y[b];if(m.startsWith("diff --git")){g(),f();continue}if(m.startsWith("--- ")){r&&r.lines.length&&g(),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),p=parseInt(E[2],10)),f().lines.push({kind:"hunk",oldNo:"",newNo:"",text:m});continue}r&&(m.startsWith("+")?(r.lines.push({kind:"add",oldNo:"",newNo:p,text:m.slice(1)}),p++):m.startsWith("-")?(r.lines.push({kind:"remove",oldNo:a,newNo:"",text:m.slice(1)}),a++):(r.lines.push({kind:"ctx",oldNo:a,newNo:p,text:m.startsWith(" ")?m.slice(1):m}),a++,p++))}}return o(s,r),s.join("")}})({trustAsHtml:e=>e});function gF(e,t){return e==null?"":Number(e).toLocaleString(void 0,t==null?{}:{minimumFractionDigits:t,maximumFractionDigits:t})}function yF(e){return String(e??"").toUpperCase()}function bF(e,t,o=0){return(e||[]).slice(o,o+t)}function wF(e,t){return Array.isArray(e)?typeof t=="function"?e.filter(t):e:[]}function kF(e,t){if(!t)return e||[];let o=Array.isArray(t)?t:[t];return[...e||[]].sort((i,s)=>{for(let r of o){let a=r[0]==="-"?-1:1;r=r.replace(/^[+-]/,"");let p=r.split(".").reduce((g,y)=>g?.[y],i),f=r.split(".").reduce((g,y)=>g?.[y],s);if(typeof p=="string"&&(p=p.toLowerCase()),typeof f=="string"&&(f=f.toLowerCase()),p!==f)return(p==null?-1:f==null?1:p<f?-1:1)*a}return 0})}function CF(e,t){if(!e)return"";let o=new Date(e);if(isNaN(o))return String(e);if(!t||t==="mediumDate")return o.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"});let i={yyyy:o.getFullYear(),MMM:o.toLocaleDateString(void 0,{month:"short"}),MM:String(o.getMonth()+1).padStart(2,"0"),dd:String(o.getDate()).padStart(2,"0"),d:o.getDate(),HH:String(o.getHours()).padStart(2,"0"),mm:String(o.getMinutes()).padStart(2,"0"),ss:String(o.getSeconds()).padStart(2,"0")};return t.replace(/yyyy|MMM|MM|dd|HH|mm|ss|d/g,s=>i[s])}function EF(e,t){return(t?.[e]??t?.[e===1?"one":"other"]??"").replace(/\{\}/g,e??0)}var dd={name:"htmlDoc",props:["content","baseUrl","allowScripts"],setup(e){let t=et(null);return Ft(()=>{let i=[t.value][0];i.classList.add("html-doc");function s(){i.innerHTML="";let r=e.content;if(typeof r!="string")return;let a=document.createElement("iframe");a.className="html-doc-frame",a.setAttribute("title","Rendered HTML document");let p=["allow-popups","allow-popups-to-escape-sandbox"];e.allowScripts&&p.push("allow-scripts","allow-forms","allow-modals"),a.setAttribute("sandbox",p.join(" ")),a.setAttribute("referrerpolicy","no-referrer"),i.appendChild(a);let f="";e.baseUrl&&(f='<base href="'+e.baseUrl.replace(/&/g,"&amp;").replace(/"/g,"&quot;")+'">'),a.srcdoc=f+r}Fe(()=>e.content,s,{immediate:!0}),Fe(()=>e.baseUrl,s,{immediate:!0}),Fe(()=>e.allowScripts,s,{immediate:!0})}),()=>Se("html-doc",{ref:t})}};var ud={name:"pdfviewer",props:["src"],setup(e){let t=et(null);return Ft(()=>{let o=[t.value],i=400,s=[.5,.75,1,1.25,1.5,2,3],r=1e3,a=o[0];a.classList.add("pdf-viewer");let p=null,f=[],g=!1,y=null,b=1,m=1,E=0,P=0,k=612/792,v=0,S=null,_=new Map,M=0;function L(C){let N=_.get(C);N&&(N.cancelled=!0,N.task?.cancel?.(),_.delete(C));let V=C.querySelector("canvas");V&&(V.width=0,V.height=0),C.innerHTML="",delete C.dataset.state}let q=document.createElement("div");q.className="pdf-toolbar";let G=document.createElement("div");G.className="pdf-pages",G.tabIndex=0,G.setAttribute("aria-label","PDF pages"),a.appendChild(q),a.appendChild(G);function se(C,N,V){let j=document.createElement("button");return j.type="button",j.className="pdf-toolbar-btn",j.title=N,j.setAttribute("aria-label",N),j.innerHTML='<i class="fas '+C+'"></i>',j.addEventListener("click",V),j}let ee=se("fa-chevron-up","Previous page",function(){ze(m-1)}),R=se("fa-chevron-down","Next page",function(){ze(m+1)}),K=document.createElement("input");K.type="text",K.className="pdf-toolbar-page",K.setAttribute("aria-label","Page number"),K.title="Page number \u2014 type a page and press Enter",K.addEventListener("keydown",function(C){C.key==="Enter"&&(ze(parseInt(K.value,10)),K.blur())}),K.addEventListener("blur",function(){K.value=String(m)});let te=document.createElement("span");te.className="pdf-toolbar-count";let ve=se("fa-search-minus","Zoom out",function(){re(s[Math.max(0,ye()-1)])}),x=se("fa-search-plus","Zoom in",function(){re(s[Math.min(s.length-1,ye()+1)])}),ue=document.createElement("button");ue.type="button",ue.className="pdf-toolbar-btn pdf-toolbar-zoom",ue.title="Reset zoom to fit the width",ue.setAttribute("aria-label","Reset zoom to fit the width"),ue.addEventListener("click",function(){re(1)}),q.appendChild(ee),q.appendChild(R);let he=document.createElement("span");he.className="pdf-toolbar-group",he.appendC Line truncated
jane.smith@example.org`},null,8,l7),[[i,{state:e.viewState,set:r=>{e.terms=r},value:e.terms,form:"defaultsForm",options:{debounce:250}}]]),n("details",d7,[t[25]||(t[25]=n("summary",null,"Regex & replacement syntax",-1)),n("p",null,[t[21]||(t[21]=y("Matches become ",-1)),n("code",null,p(e.site_options?.ANONYMIZATION_MASK||"XXX")+"-[N]",1),t[22]||(t[22]=y(". Use ",-1)),t[23]||(t[23]=n("code",null,"term=>replacement",-1)),t[24]||(t[24]=y(" for a custom replacement. Regex is supported.",-1))])]),T(n("div",u7,"Terms are in an invalid format.",512),[[J,e.defaultsForm?.terms?.errors?.format]])])]),n("section",c7,[t[35]||(t[35]=n("h2",null,"Reviewer display",-1)),n("div",null,[n("div",p7,[n("label",f7,[T(n("input",h7,null,512),[[i,{state:e.viewState,set:r=>{e.options.link=r},value:e.options?.link,form:"defaultsForm",options:{}}]]),t[27]||(t[27]=y("Keep links",-1))]),n("label",m7,[T(n("input",g7,null,512),[[i,{state:e.viewState,set:r=>{e.options.notebook=r},value:e.options?.notebook,form:"defaultsForm",options:{}}]]),t[28]||(t[28]=y("Render notebooks",-1))]),n("label",v7,[T(n("input",y7,null,512),[[i,{state:e.viewState,set:r=>{e.options.image=r},value:e.options?.image,form:"defaultsForm",options:{}}]]),t[29]||(t[29]=y("Show images",-1))]),n("label",b7,[T(n("input",w7,null,512),[[i,{state:e.viewState,set:r=>{e.options.pdf=r},value:e.options?.pdf,form:"defaultsForm",options:{}}]]),t[30]||(t[30]=y("Show PDFs",-1))]),n("label",k7,[T(n("input",C7,null,512),[[i,{state:e.viewState,set:r=>{e.options.loc=r},value:e.options?.loc,form:"defaultsForm",options:{}}]]),t[31]||(t[31]=y("Show line counts",-1))]),n("label",E7,[T(n("input",S7,null,512),[[i,{state:e.viewState,set:r=>{e.options.page=r},value:e.options?.page,form:"defaultsForm",options:{}}]]),t[32]||(t[32]=y("GitHub Pages",-1))])]),t[33]||(t[33]=n("p",{class:"settings-help"},"Images and PDFs are not anonymized.",-1)),t[34]||(t[34]=n("p",{class:"settings-help"},"GitHub Pages must use the anonymized branch.",-1))])]),n("section",N7,[t[38]||(t[38]=n("h2",null,"Source updates",-1)),n("div",null,[n("label",R7,[T(n("input",D7,null,512),[[i,{state:e.viewState,set:r=>{e.options.update=r},value:e.options?.update,form:"defaultsForm",options:{}}]]),t[36]||(t[36]=y("Auto-update from GitHub",-1))]),t[37]||(t[37]=n("p",{class:"settings-help"},"Latest commit, at most once an hour.",-1))])]),n("section",T7,[t[40]||(t[40]=n("label",{class:"settings-label",for:"expiration"},"On expiration",-1)),n("div",null,[T((l(),d("select",A7,[...t[39]||(t[39]=[n("option",{value:"redirect"},"Redirect visitors to the GitHub repository",-1),n("option",{value:"remove",selected:""},"Remove the anonymized repository",-1)])])),[[i,{state:e.viewState,set:r=>{e.options.expirationMode=r},value:e.options?.expirationMode,form:"defaultsForm",options:{}}]]),n("p",_7,p(e.options.expirationMode==="redirect"?"Redirecting reveals the original repository. Choose the date per anonymization.":"Set the expiration date for each repository."),1)])]),n("footer",O7,[n("div",P7,[e.draftRestored?(l(),d("span",I7,"Your unsaved draft was restored.")):e.unsavedChanges?(l(),d("span",M7,"Unsaved changes"+p(e.draftSaved?" \xB7 Draft saved in this tab":""),1)):(l(),d("span",V7,p(e.message?"Defaults saved":"All changes saved"),1))]),e.draftRestored||e.unsavedChanges?(l(),d("button",{key:0,type:"button",class:"draft-discard",onClick:t[0]||(t[0]=r=>e.discardDraft())},"Discard changes")):f("v-if",!0),n("button",{id:"save",type:"submit",class:"btn btn-ink",disabled:e.saving},p(e.saving?"Saving\u2026":"Save defaults"),9,q7),e.error?(l(),d("div",$7,p(e.error),1)):f("v-if",!0)])],32)),[[o,e.viewState]])],512),[[J,e.settingsTab==="defaults"]]),T(n("section",{id:"settings-billing","aria-busy":e.billingLoading||e.billingBusy},[t[64]||(t[64]=n("p",{class:"settings-scope"},"Your plan and usage. Reviewer access is always free.",-1)),e.billingLoading?(l(),d("p",U7,"Loading billing\u2026")):f("v-if",!0),e.billingError?(l(),d("div",F7,[y(p(e.billingError)+" ",1),n("button",{type:"button",class:"btn btn-outline-ink",onClick:t[2]||(t[2]=r=>e.loadBilling()),disabled:e.billingBusy},"Try again",8,B7)])):f("v-if",!0),e.billingNotice?(l(),d("p",z7,p(e.billingNotice),1)):f("v-if",!0),e.billingPending?(l(),d("div",H7,[t[42]||(t[42]=n("strong",null,"Confirming your payment",-1)),t[43]||(t[43]=n("p",null,"Your allowance will update after confirmation. Please do not pay again.",-1)),n("button",{type:"button",class:"btn btn-outline-ink",onClick:t[3]||(t[3]=r=>e.refreshBilling()),disabled:e.billingBusy},"Check payment status",8,j7)])):f("v-if",!0),n("section",G7,[t[57]||(t[57]=n("h2",null,"Current plan",-1)),n("div",null,[n("div",W7,[n("div",null,[n("strong",null,p(e.profileAuthorGrant()?"Author subscription":e.billing?.enabled?"Free":"Account allowance"),1),e.profileAuthorGrant()?(l(),d("p",K7,p(e.profileAuthorGrant().cancelAtPeriodEnd?"Renewal cancelled \xB7 Access until ":"Paid access through ")+p(e.billingDate(e.profileAuthorGrant().until)),1)):f("v-if",!0)]),e. Line truncated
`);for(let v=0;v<g.length;v++){let h=g[v];if(h.startsWith("diff --git")){m(),c();continue}if(h.startsWith("--- ")){r&&r.lines.length&&m(),c().oldPath=h.replace(/^--- (a\/)?/,"").trim();continue}if(h.startsWith("+++ ")){c().newPath=h.replace(/^\+\+\+ (b\/)?/,"").trim();continue}if(!(h.startsWith("index ")||h.startsWith("similarity index")||h.startsWith("rename ")||h.startsWith("new file mode")||h.startsWith("deleted file mode")||h.startsWith("Binary files"))){if(h.startsWith("@@")){let k=h.match(/@@\s+-(\d+)(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/);k&&(a=parseInt(k[1],10),u=parseInt(k[2],10)),c().lines.push({kind:"hunk",oldNo:"",newNo:"",text:h});continue}r&&(h.startsWith("+")?(r.lines.push({kind:"add",oldNo:"",newNo:u,text:h.slice(1)}),u++):h.startsWith("-")?(r.lines.push({kind:"remove",oldNo:a,newNo:"",text:h.slice(1)}),a++):(r.lines.push({kind:"ctx",oldNo:a,newNo:u,text:h.startsWith(" ")?h.slice(1):h}),a++,u++))}}return s(o,r),o.join("")}})({trustAsHtml:e=>e});function aH(e,t){return e==null?"":Number(e).toLocaleString(void 0,t==null?{}:{minimumFractionDigits:t,maximumFractionDigits:t})}function lH(e){return String(e??"").toUpperCase()}function dH(e,t,s=0){return(e||[]).slice(s,s+t)}function uH(e,t){return Array.isArray(e)?typeof t=="function"?e.filter(t):e:[]}function cH(e,t){if(!t)return e||[];let s=Array.isArray(t)?t:[t];return[...e||[]].sort((i,o)=>{for(let r of s){let a=r[0]==="-"?-1:1;r=r.replace(/^[+-]/,"");let u=r.split(".").reduce((m,g)=>m?.[g],i),c=r.split(".").reduce((m,g)=>m?.[g],o);if(typeof u=="string"&&(u=u.toLowerCase()),typeof c=="string"&&(c=c.toLowerCase()),u!==c)return(u==null?-1:c==null?1:u<c?-1:1)*a}return 0})}function pH(e,t){if(!e)return"";let s=new Date(e);if(isNaN(s))return String(e);if(!t||t==="mediumDate")return s.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"});let i={yyyy:s.getFullYear(),MMM:s.toLocaleDateString(void 0,{month:"short"}),MM:String(s.getMonth()+1).padStart(2,"0"),dd:String(s.getDate()).padStart(2,"0"),d:s.getDate(),HH:String(s.getHours()).padStart(2,"0"),mm:String(s.getMinutes()).padStart(2,"0"),ss:String(s.getSeconds()).padStart(2,"0")};return t.replace(/yyyy|MMM|MM|dd|HH|mm|ss|d/g,o=>i[o])}function fH(e,t){return(t?.[e]??t?.[e===1?"one":"other"]??"").replace(/\{\}/g,e??0)}var zc={name:"htmlDoc",props:["content","baseUrl","allowScripts"],setup(e){let t=gt(null);return nn(()=>{let i=[t.value][0];i.classList.add("html-doc");function o(){i.innerHTML="";let r=e.content;if(typeof r!="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"),i.appendChild(a);let c="";e.baseUrl&&(c='<base href="'+e.baseUrl.replace(/&/g,"&amp;").replace(/"/g,"&quot;")+'">'),a.srcdoc=c+r}tt(()=>e.content,o,{immediate:!0}),tt(()=>e.baseUrl,o,{immediate:!0}),tt(()=>e.allowScripts,o,{immediate:!0})}),()=>Oe("html-doc",{ref:t})}};var Hc={name:"pdfviewer",props:["src"],setup(e){let t=gt(null);return nn(()=>{let s=[t.value],i=400,o=[.5,.75,1,1.25,1.5,2,3],r=1e3,a=s[0];a.classList.add("pdf-viewer");let u=null,c=[],m=!1,g=null,v=1,h=1,k=0,A=0,w=612/792,b=0,E=null,N=new Map,O=0;function q(C){let R=N.get(C);R&&(R.cancelled=!0,R.task?.cancel?.(),N.delete(C));let P=C.querySelector("canvas");P&&(P.width=0,P.height=0),C.innerHTML="",delete C.dataset.state}let I=document.createElement("div");I.className="pdf-toolbar";let j=document.createElement("div");j.className="pdf-pages",j.tabIndex=0,j.setAttribute("aria-label","PDF pages"),a.appendChild(I),a.appendChild(j);function de(C,R,P){let G=document.createElement("button");return G.type="button",G.className="pdf-toolbar-btn",G.title=R,G.setAttribute("aria-label",R),G.innerHTML='<i class="fas '+C+'"></i>',G.addEventListener("click",P),G}let ie=de("fa-chevron-up","Previous page",function(){Ke(h-1)}),D=de("fa-chevron-down","Next page",function(){Ke(h+1)}),X=document.createElement("input");X.type="text",X.className="pdf-toolbar-page",X.setAttribute("aria-label","Page number"),X.title="Page number \u2014 type a page and press Enter",X.addEventListener("keydown",function(C){C.key==="Enter"&&(Ke(parseInt(X.value,10)),X.blur())}),X.addEventListener("blur",function(){X.value=String(h)});let le=document.createElement("span");le.className="pdf-toolbar-count";let Ee=de("fa-search-minus","Zoom out",function(){ue(o[Math.max(0,Ne()-1)])}),re=de("fa-search-plus","Zoom in",function(){ue(o[Math.min(o.length-1,Ne()+1)])}),me=document.createElement("button");me.type="button",me.className="pdf-toolbar-btn pdf-toolbar-zoom",me.title="Reset zoom to fit the width",me.setAttribute("aria-label","Reset zoom to fit the width"),me.addEventListener("click",function(){ue(1)}),I.appendChild(ie),I.appendChild(D);let ke=document.createElement("span");ke.className="pdf-toolbar-group",ke.append Line truncated
/*! Bundled license information:
@vue/shared/dist/shared.esm-bundler.js:
+1
View File
@@ -610,6 +610,7 @@ export default class Repository {
filePath: filePath,
cacheGeneration: `${this.model.treeGeneration || "legacy"}:${this.model.anonymizeDate?.toISOString() || ""}`,
terms: this.options.terms,
preserveFiles: this.options.preserveFiles || [],
cacheRevision: this.model.contentCacheRevision,
image: this.options.image,
link: this.options.link,
+12 -4
View File
@@ -16,6 +16,7 @@ import { lookup as lookupMime } from "mime-types";
import config from "../config";
import { TermPresenceIndex } from "./term-presence";
import { isPreservedPath } from "./preserve-files";
import {
parseTermSpec,
termVariants,
@@ -154,6 +155,11 @@ export class AnonymizeTransformer extends Transform {
private spoolOperation?: Promise<void>;
private readonly memoryThreshold = 256 * 1024;
private readonly bufferWholeStream: boolean;
// Options actually applied to the content. Identical to `opt` except that
// files matching `preserveFiles` drop their terms (#941). `opt` keeps the
// full configuration because it is forwarded to the streamer and zip
// builder, which re-evaluate it per file.
private readonly contentOpt: ConstructorParameters<typeof ContentAnonimizer>[0];
constructor(
readonly opt: {
@@ -161,9 +167,11 @@ export class AnonymizeTransformer extends Transform {
cacheGeneration?: string;
cacheRevision?: string;
decisionManaged?: boolean;
preserveFiles?: string[];
} & ConstructorParameters<typeof ContentAnonimizer>[0]
) {
super();
this.contentOpt = isPreservedPath(opt.filePath, opt.preserveFiles) ? { ...opt, terms: [] } : opt;
// Tri-state: name-based check returns true (known text), false (known
// binary), or null (name inconclusive). For null we defer to a content
// sniff on the first chunk in _transform — known binary extensions
@@ -171,14 +179,14 @@ export class AnonymizeTransformer extends Transform {
// reach the sniff path (#493).
this.nameVerdict = classifyByName(this.opt.filePath);
if (this.nameVerdict !== null) this.isText = this.nameVerdict;
this.anonimizer = new ContentAnonimizer(this.opt);
this.anonimizer = new ContentAnonimizer(this.contentOpt);
// Matching a prefix in isolation can split even a fixed-length name or
// turn the split into a false word boundary. Preserve the complete text
// whenever a rewrite is enabled, with MAX_FILE_SIZE as a hard limit.
this.bufferWholeStream =
opt.link === false || opt.image === false ||
(opt.terms || []).length > 0 || !!(opt.repoName && opt.branchName);
(this.contentOpt.terms || []).length > 0 || !!(opt.repoName && opt.branchName);
}
get wasAnonimized() {
@@ -247,8 +255,8 @@ export class AnonymizeTransformer extends Transform {
const output = join(this.spool, "output");
const started = performance.now();
const produce = () => anonymizeOnWorker({ input: join(this.spool!, "input"), output,
options: this.opt, maxOutput: config.MAX_FILE_SIZE * 4, context: { mask: config.ANONYMIZATION_MASK, hostname: config.APP_HOSTNAME } }, this.wholeBytes, this.cancelled.signal);
void (this.opt.decisionManaged ? produce() : transformedFile(this.digest.digest("hex"), this.opt, output, produce))
options: this.contentOpt, maxOutput: config.MAX_FILE_SIZE * 4, context: { mask: config.ANONYMIZATION_MASK, hostname: config.APP_HOSTNAME } }, this.wholeBytes, this.cancelled.signal);
void (this.opt.decisionManaged ? produce() : transformedFile(this.digest.digest("hex"), this.contentOpt, output, produce))
.then(changed => {
if (this.destroyed) return;
this.anonimizer.wasAnonymized = changed;
@@ -76,6 +76,7 @@ const AnonymizedRepositorySchema = new Schema({
},
options: {
terms: [String],
preserveFiles: { type: [String], default: undefined },
expirationMode: { type: String },
expirationDate: Date,
update: Boolean,
@@ -49,6 +49,8 @@ export interface IAnonymizedRepository {
conference: string;
options: {
terms: string[];
/** Glob patterns of files whose content skips term redaction (#941). */
preserveFiles?: string[];
expirationMode: "never" | "redirect" | "remove";
expirationDate?: Date;
update: boolean;
+89
View File
@@ -0,0 +1,89 @@
import { Minimatch } from "minimatch";
/**
* Patterns for files whose content is served without term redaction (#941),
* e.g. a bibliography where redacted self-citations would reveal the authors.
* Paths are still anonymized; only file content is left untouched.
*
* Same rules as .gitignore: a pattern without "/" matches the file name in any
* folder (`*.bib`); a pattern containing "/" matches from the repository root
* (`paper/refs.bib`, `/refs.bib`, `paper/**`); a pattern that matches a
* folder covers everything inside it, and a trailing "/" matches folders only
* (`private/`); `!pattern` excludes again, and the last matching pattern wins. Picked files are stored as root-anchored
* paths with glob characters escaped by a backslash (`/paper/\{a,b\}.bib`).
*/
export const MAX_PRESERVE_PATTERNS = 200;
export const MAX_PRESERVE_PATTERN_LENGTH = 512;
function parsePattern(pattern: string) {
const negated = pattern.startsWith("!");
const rest = negated ? pattern.slice(1) : pattern;
const anchored = rest.startsWith("/");
const withSlash = anchored ? rest.slice(1) : rest;
const directoryOnly = withSlash.endsWith("/");
const body = directoryOnly ? withSlash.slice(0, -1) : withSlash;
return { negated, anchored, directoryOnly, body };
}
/**
* Drops repeated patterns but keeps the last copy: rules apply in order and
* the last match wins, so an earlier copy can never decide the result.
*/
export function dedupePreservePatterns(patterns: string[]): string[] {
return patterns.filter((pattern, index) => patterns.lastIndexOf(pattern) === index);
}
/** Returns the normalized patterns, or null when the input is invalid. */
export function normalizePreserveFiles(value: unknown): string[] | null {
if (value === undefined || value === null) return [];
if (!Array.isArray(value)) return null;
const patterns: string[] = [];
for (const raw of value) {
if (typeof raw !== "string") return null;
const pattern = raw.trim();
if (!pattern) continue;
if (pattern.length > MAX_PRESERVE_PATTERN_LENGTH) return null;
const { body } = parsePattern(pattern);
if (!body || body.split("/").some(segment => segment === ".." || segment === "")) return null;
patterns.push(pattern);
}
const unique = dedupePreservePatterns(patterns);
return unique.length > MAX_PRESERVE_PATTERNS ? null : unique;
}
/**
* Compiles the patterns once. The returned function applies them in order to
* `initial` (whether the file is already preserved), so a later `!pattern`
* can exclude what an earlier pattern included.
*/
export function compilePreserveMatcher(patterns: string[] | undefined): (filePath: string, initial?: boolean) => boolean {
const rules = (patterns || [])
.filter((pattern): pattern is string => typeof pattern === "string" && pattern.length > 0)
.map(pattern => {
const { negated, anchored, directoryOnly, body } = parsePattern(pattern);
return {
negated,
directoryOnly,
matcher: new Minimatch(body, { dot: true, nonegate: true, nocomment: true, matchBase: !anchored && !body.includes("/") }),
};
});
return (filePath: string, initial = false) => {
const path = (filePath || "").replace(/^\/+/, "");
if (!path) return false;
// A rule applies to a file when it matches the file or one of its folders.
const parts = path.split("/");
const folders = parts.slice(0, -1).map((_, i) => parts.slice(0, i + 1).join("/"));
let preserved = initial;
for (const rule of rules) {
if (rule.negated ? !preserved : preserved) continue;
const candidates = rule.directoryOnly ? folders : [...folders, path];
if (candidates.some(candidate => rule.matcher.match(candidate))) preserved = !rule.negated;
}
return preserved;
};
}
export function isPreservedPath(filePath: string | undefined, patterns: string[] | undefined): boolean {
if (!filePath || !patterns || patterns.length === 0) return false;
return compilePreserveMatcher(patterns)(filePath);
}
+53
View File
@@ -0,0 +1,53 @@
import { octokit } from "./GitHubUtils";
import AnonymousError from "./AnonymousError";
import { classifyByName } from "./anonymize-utils";
/** Enough for the picker; larger repositories fall back to patterns. */
export const SOURCE_FILE_LIST_LIMIT = 20000;
export interface SourceFileList {
files: string[];
truncated: boolean;
}
/**
* Text files of a commit, read from GitHub's recursive tree API. Used by the
* "Leave files unredacted" picker (#941) before the repository is downloaded.
* Known binary files are dropped: their content is never redacted anyway.
*/
export async function sourceFileList(opt: {
owner: string;
repo: string;
commit: string;
accessToken: string;
}): Promise<SourceFileList> {
const oct = octokit(opt.accessToken);
let data;
try {
// The commit field accepts abbreviated hashes; the tree API needs a full one.
let commit = opt.commit;
if (!/^[0-9a-f]{40}$/i.test(commit)) {
commit = (await oct.repos.getCommit({ owner: opt.owner, repo: opt.repo, ref: commit })).data.sha;
}
({ data } = await oct.git.getTree({
owner: opt.owner,
repo: opt.repo,
tree_sha: commit,
recursive: "true",
}));
} catch (error) {
const status = (error as { status?: number }).status;
if (status === 404 || status === 409 || status === 422) {
throw new AnonymousError("repo_not_found", { httpStatus: 404, cause: error as Error });
}
throw error;
}
const files: string[] = [];
for (const entry of data.tree) {
if (entry.type !== "blob" || !entry.path) continue;
if (entry.path === ".gitmodules" || classifyByName(entry.path) === false) continue;
if (files.length === SOURCE_FILE_LIST_LIMIT) return { files: files.sort(), truncated: true };
files.push(entry.path);
}
return { files: files.sort(), truncated: !!data.truncated };
}
+48
View File
@@ -0,0 +1,48 @@
import { parseTermSpec } from "./term-matching";
// Symbols that change what a term matches. "." is left out on purpose: it
// matches any character, which can only redact more (hartwell.edu also hides
// hartwell-edu), never less, so warning about every email and domain was
// noise. "-", "," and "#" are literal outside a character class.
const STRUCTURAL = new Set(["*", "+", "?", "(", ")", "[", "]", "{", "}", "|", "^", "$"]);
export interface TermHint {
/** Zero-based line in the terms text. */
line: number;
term: string;
symbols: string[];
}
/** Terms whose regex symbols probably were meant literally, e.g. "Smith (MIT)" or "C++". */
export function termHints(text: string | undefined): TermHint[] {
const hints: TermHint[] = [];
String(text || "").split("\n").forEach((line, index) => {
const { term } = parseTermSpec(line.trim());
if (!term) return;
const symbols: string[] = [];
for (let i = 0; i < term.length; i++) {
if (term[i] === "\\") { i++; continue; }
if (STRUCTURAL.has(term[i]) && !symbols.includes(term[i])) symbols.push(term[i]);
}
if (symbols.length) hints.push({ line: index, term, symbols });
});
return hints;
}
/** Rewrites one line so its term matches the text as written; keeps any "=>" replacement. */
export function escapeTermLine(text: string, line: number): string {
const lines = String(text || "").split("\n");
const raw = lines[line];
if (raw === undefined) return text;
const { term } = parseTermSpec(raw.trim());
if (!term) return text;
let escaped = "";
for (let i = 0; i < term.length; i++) {
if (term[i] === "\\") { escaped += term.slice(i, i + 2); i++; continue; }
escaped += STRUCTURAL.has(term[i]) || term[i] === "." ? "\\" + term[i] : term[i];
}
// Splice by index: String.replace would expand "$&", "$'" and "$1" in the term.
const start = raw.indexOf(term);
lines[line] = raw.slice(0, start) + escaped + raw.slice(start + term.length);
return lines.join("\n");
}
+6
View File
@@ -1,6 +1,7 @@
import * as express from "express";
import { getRepo, getUser, handleError, isOwnerCoauthorOrAdmin } from "./route-utils";
import AnonymousError from "../../core/AnonymousError";
import { normalizePreserveFiles } from "../../core/preserve-files";
import RepoModel from "../../core/model/anonymizedRepositories/anonymizedRepositories.model";
const router = express.Router();
@@ -17,6 +18,11 @@ export function maintenanceSettings(body: unknown): Record<string, unknown> {
if (key === "terms") {
if (!Array.isArray(value) || value.length > 1000 ||
!value.every(t => typeof t === "string" && t.length > 0 && t.length <= 1000)) throw invalid();
} else if (key === "preserveFiles") {
const patterns = normalizePreserveFiles(value);
if (!Array.isArray(value) || patterns === null) throw invalid();
updates["options.preserveFiles"] = patterns;
continue;
} else if (!toggles.includes(key) || typeof value !== "boolean") throw invalid();
updates[`options.${key}`] = value;
}
+32
View File
@@ -30,6 +30,8 @@ import RepositoryModel from "../../core/model/repositories/repositories.model";
import { RepositoryStatus } from "../../core/types";
import { octokit, getRedisGateResetAt, getToken } from "../../core/GitHubUtils";
import { createLogger } from "../../core/logger";
import { normalizePreserveFiles } from "../../core/preserve-files";
import { sourceFileList } from "../../core/source-file-list";
const logger = createLogger("route:repo");
@@ -350,6 +352,27 @@ router.get(
}
);
// Text files of a source commit, for the "Leave files unredacted" picker (#941).
router.get(
"/:owner/:repo/tree",
async (req, res) => {
try {
const commit = typeof req.query.commit === "string" ? req.query.commit : "";
if (!/^[0-9a-f]{6,40}$/i.test(commit)) throw appError("invalid_commit_format", 400);
const token = await previewToken(req);
res.set("Cache-Control", "private, no-store");
res.json(await sourceFileList({
owner: req.params.owner,
repo: req.params.repo,
commit,
accessToken: token,
}));
} catch (error) {
handleError(error, res, req);
}
}
);
// get repository information
router.get("/:repoId/", async (req, res) => {
try {
@@ -428,6 +451,14 @@ function validateNewRepo(repoUpdate: any): void {
httpStatus: 400,
});
}
const preserveFiles = normalizePreserveFiles(repoUpdate.options.preserveFiles);
if (preserveFiles === null) {
throw new AnonymousError("invalid_preserve_files_format", {
object: repoUpdate,
httpStatus: 400,
});
}
repoUpdate.options.preserveFiles = preserveFiles;
if (!/^[a-fA-F0-9]+$/.test(repoUpdate.source.commit)) {
throw new AnonymousError("invalid_commit_format", {
object: repoUpdate,
@@ -446,6 +477,7 @@ function updateRepoModel(
model.source.branch = repoUpdate.source.branch;
model.options = {
terms: repoUpdate.terms,
preserveFiles: normalizePreserveFiles(repoUpdate.options.preserveFiles) || [],
expirationMode: repoUpdate.options.expirationMode,
expirationDate: repoUpdate.options.expirationDate
? new Date(repoUpdate.options.expirationDate)
+100
View File
@@ -5,6 +5,10 @@ const path = require("path");
const { setImmediate } = require("timers");
const { URLSearchParams } = require("node:url");
const source = fs.readFileSync(path.join(__dirname, "../public/script/app.js"), "utf8");
require("ts-node/register/transpile-only");
const minimatch = require("minimatch");
const { compilePreserveMatcher, dedupePreservePatterns } = require("../src/core/preserve-files");
const { termHints, escapeTermLine } = require("../src/core/term-hints");
function harness(date) {
const defs = {}, routes = {}, timers = new Map();
@@ -18,6 +22,8 @@ function harness(date) {
$: () => ({ on() {}, tooltip() {} }),
setTimeout: fn => { timers.set(++timerId, fn); return timerId; },
clearTimeout: id => timers.delete(id), setInterval: () => 0, clearInterval() {},
markRaw: value => value, globEscape: minimatch.escape, globUnescape: minimatch.unescape,
compilePreserveMatcher, dedupePreservePatterns, termHints, escapeTermLine,
};
context.createTimers = () => ({ timeout: Object.assign(context.setTimeout, { cancel: context.clearTimeout }), interval: Object.assign(context.setInterval, { cancel: context.clearInterval }) });
context.createListeners = () => (target, name, callback) => target.addEventListener(name, callback);
@@ -133,6 +139,100 @@ describe("frontend production regressions", function () {
expect(h.routes[route].preserveExplorer).to.equal(false);
}
});
it("saves picked files as anchored, escaped paths and folders as patterns (#941)", async function () {
const h = harness(); const timeout = () => 0; timeout.cancel = () => {};
h.context.document.getElementById = () => null;
h.defs.anonymizeController(h.scope, h.http, {}, {}, {}, () => {}, timeout);
h.scope.options.preserveFiles = ["*.bib"];
h.scope.source = { commit: "a".repeat(40) };
h.scope.sourceUrl = "https://github.com/owner/repo";
h.scope.openPreserveFiles();
const request = h.requests.at(-1);
expect(request.url).to.equal("/api/repo/owner/repo/tree");
expect(request.body.params.commit).to.equal("a".repeat(40));
request.resolve({ data: { files: ["configs/a.yaml", "configs/b.yaml", "paper/[draft].tex", "paper/refs.bib"], truncated: false } });
await h.flush();
expect(h.scope.preserveCount()).to.equal(1);
h.scope.togglePreserveFile("paper/[draft].tex");
h.scope.togglePreserveFolder("configs");
expect(h.scope.preserveCount()).to.equal(4);
h.scope.savePreserveFiles();
expect(Array.from(h.scope.options.preserveFiles)).to.deep.equal(["/paper/\\[draft\\].tex", "*.bib", "/configs/**"]);
expect(h.scope.preserveSummary()).to.equal("paper/[draft].tex, *.bib and 1 more");
});
it("lets a later !pattern exclude a picked file, and keeps braces literal (#941)", async function () {
const h = harness(); const timeout = () => 0; timeout.cancel = () => {};
h.context.document.getElementById = () => null;
h.defs.anonymizeController(h.scope, h.http, {}, {}, {}, () => {}, timeout);
h.scope.options.preserveFiles = ["/paper/\\{a,b\\}.bib", "!a.bib"];
h.scope.source = { commit: "a".repeat(40) };
h.scope.sourceUrl = "https://github.com/owner/repo";
h.scope.openPreserveFiles();
expect(h.scope.preserve.picked["paper/{a,b}.bib"]).to.equal(true);
h.requests.at(-1).resolve({ data: { files: ["a.bib", "paper/a.bib", "paper/{a,b}.bib"], truncated: false } });
await h.flush();
expect(h.scope.preserveCount()).to.equal(1);
h.scope.togglePreserveFile("a.bib");
expect(h.scope.preserveCount()).to.equal(1);
});
it("keeps folder rules as patterns and counts them like the server (#941)", async function () {
const h = harness(); const timeout = () => 0; timeout.cancel = () => {};
h.context.document.getElementById = () => null;
h.defs.anonymizeController(h.scope, h.http, {}, {}, {}, () => {}, timeout);
h.scope.options.preserveFiles = ["/paper/", "/refs.bib"];
h.scope.source = { commit: "abc123" };
h.scope.sourceUrl = "https://github.com/owner/repo";
h.scope.openPreserveFiles();
expect(Object.keys(h.scope.preserve.picked)).to.deep.equal([]);
expect(h.scope.preserve.patterns).to.equal("/paper/\n/refs.bib");
h.requests.at(-1).resolve({ data: { files: ["paper/a.tex", "paper/b/c.tex", "refs.bib", "x.tex"], truncated: false } });
await h.flush();
expect(h.scope.preserveCount()).to.equal(3);
const paper = h.scope.preserveRows().find((row) => row.path === "paper");
expect(paper.state).to.equal("all");
});
it("unchecking a folder overrides broader rules (#941)", async function () {
const h = harness(); const timeout = () => 0; timeout.cancel = () => {};
h.context.document.getElementById = () => null;
h.defs.anonymizeController(h.scope, h.http, {}, {}, {}, () => {}, timeout);
h.scope.options.preserveFiles = ["*.bib"];
h.scope.source = { commit: "abc123" };
h.scope.sourceUrl = "https://github.com/owner/repo";
h.scope.openPreserveFiles();
h.requests.at(-1).resolve({ data: { files: ["paper/refs.bib", "refs.bib"], truncated: false } });
await h.flush();
expect(h.scope.preserveCount()).to.equal(2);
h.scope.togglePreserveFolder("paper");
expect(h.scope.preserveCount()).to.equal(1);
h.scope.togglePreserveFolder("paper");
expect(h.scope.preserveCount()).to.equal(2);
h.scope.togglePreserveFolder("paper");
h.scope.savePreserveFiles();
expect(Array.from(h.scope.options.preserveFiles)).to.deep.equal(["*.bib", "!/paper/"]);
});
it("keeps the order of saved rules when the picker opens and saves (#941)", function () {
const h = harness(); const timeout = () => 0; timeout.cancel = () => {};
h.context.document.getElementById = () => null;
h.defs.anonymizeController(h.scope, h.http, {}, {}, {}, () => {}, timeout);
h.scope.options.preserveFiles = ["/a.bib", "*.bib", "!/refs.bib", "/refs.bib"];
h.scope.source = { commit: "a".repeat(40) };
h.scope.sourceUrl = "https://github.com/owner/repo";
h.scope.openPreserveFiles();
expect(Object.keys(h.scope.preserve.picked)).to.deep.equal(["a.bib"]);
expect(h.scope.preserve.patterns).to.equal("*.bib\n!/refs.bib\n/refs.bib");
h.scope.savePreserveFiles();
expect(Array.from(h.scope.options.preserveFiles)).to.deep.equal(["/a.bib", "*.bib", "!/refs.bib", "/refs.bib"]);
});
it("shows the README unredacted in the preview when it is an unredacted file (#941)", function () {
const h = harness(); const timeout = () => 0; timeout.cancel = () => {};
h.defs.anonymizeController(h.scope, h.http, {}, {}, {}, () => {}, timeout);
h.scope.detectedType = "repo";
h.scope.options.preserveFiles = ["*.bib"];
expect(h.scope.readmePreserved()).to.equal(false);
h.scope.options.preserveFiles = ["/README.md"];
expect(h.scope.readmePreserved()).to.equal(true);
expect(typeof h.watches["options.preserveFiles"]).to.equal("function");
});
it("includes PR comment authors and bodies in the preview batch", async function () {
const h = harness(); const pending = new Map(); let id = 0;
const timeout = fn => { pending.set(++id, fn); return id; }; timeout.cancel = id => pending.delete(id);
+8
View File
@@ -114,6 +114,14 @@ describe("maintenance settings patch", () => {
"options.terms": [], "options.update": false,
});
});
it("normalizes preserveFiles patterns (#941)", () => {
expect(maintenanceSettings({ preserveFiles: [" refs.bib ", ""] })).to.deep.equal({
"options.preserveFiles": ["refs.bib"],
});
for (const body of [{ preserveFiles: "refs.bib" }, { preserveFiles: null }, { preserveFiles: ["../x"] }]) {
expect(() => maintenanceSettings(body)).to.throw("invalid_settings");
}
});
it("rejects source changes, arbitrary option paths, invalid types and oversized terms", () => {
for (const body of [null, [], {}, { source: {} }, { "options.update": true },
{ image: "false" }, { terms: [1] }, { terms: [""] }, { terms: ["a".repeat(1001)] },
+133
View File
@@ -0,0 +1,133 @@
const { expect } = require("chai");
require("ts-node/register/transpile-only");
const {
isPreservedPath,
normalizePreserveFiles,
} = require("../src/core/preserve-files");
const { AnonymizeTransformer } = require("../src/core/anonymize-utils");
const { decisionKey } = require("../src/core/cached-response");
function run(options, input) {
const transformer = new AnonymizeTransformer(options);
const chunks = [];
return new Promise((resolve, reject) => {
transformer.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
transformer.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
transformer.on("error", reject);
transformer.end(Buffer.from(input));
});
}
describe("preserveFiles (#941)", function () {
describe("isPreservedPath", function () {
it("matches a bare name or glob in any folder", function () {
expect(isPreservedPath("refs.bib", ["refs.bib"])).to.equal(true);
expect(isPreservedPath("paper/refs.bib", ["refs.bib"])).to.equal(true);
expect(isPreservedPath("a/b/other.bib", ["*.bib"])).to.equal(true);
expect(isPreservedPath("paper/refs.tex", ["*.bib"])).to.equal(false);
});
it("anchors patterns containing a slash at the repository root", function () {
expect(isPreservedPath("paper/refs.bib", ["paper/refs.bib"])).to.equal(true);
expect(isPreservedPath("x/paper/refs.bib", ["paper/refs.bib"])).to.equal(false);
expect(isPreservedPath("paper/sub/a.bib", ["paper/**"])).to.equal(true);
});
it("anchors a leading slash at the root, like .gitignore", function () {
expect(isPreservedPath("refs.bib", ["/refs.bib"])).to.equal(true);
expect(isPreservedPath("paper/refs.bib", ["/refs.bib"])).to.equal(false);
expect(isPreservedPath("paper/refs.bib", ["/paper/refs.bib"])).to.equal(true);
});
it("matches picked paths escaped with backslashes, braces included", function () {
expect(isPreservedPath("paper/[draft].bib", ["/paper/\\[draft\\].bib"])).to.equal(true);
expect(isPreservedPath("paper/d.bib", ["/paper/\\[draft\\].bib"])).to.equal(false);
expect(isPreservedPath("paper/{draft,final}.bib", ["/paper/\\{draft,final\\}.bib"])).to.equal(true);
expect(isPreservedPath("paper/draft.bib", ["/paper/\\{draft,final\\}.bib"])).to.equal(false);
});
it("applies folder rules to everything inside, like .gitignore", function () {
expect(isPreservedPath("private/refs.bib", ["*.bib", "!private"])).to.equal(false);
expect(isPreservedPath("paper/private/refs.bib", ["*.bib", "!private/"])).to.equal(false);
expect(isPreservedPath("paper/refs.bib", ["*.bib", "!private"])).to.equal(true);
expect(isPreservedPath("paper/a/b.tex", ["paper"])).to.equal(true);
expect(isPreservedPath("x/paper/b.tex", ["/paper"])).to.equal(false);
expect(isPreservedPath("private.bib", ["*.bib", "!private/"])).to.equal(true);
expect(isPreservedPath("private/x.bib", ["/private/x.bib", "!/private/"])).to.equal(false);
});
it("applies !patterns as exclusions, last match wins", function () {
const patterns = ["*.bib", "!private.bib"];
expect(isPreservedPath("paper/refs.bib", patterns)).to.equal(true);
expect(isPreservedPath("paper/private.bib", patterns)).to.equal(false);
expect(isPreservedPath("README.md", patterns)).to.equal(false);
expect(isPreservedPath("paper/private.bib", ["!private.bib", "*.bib"])).to.equal(true);
expect(isPreservedPath("a/x.bib", ["a/**", "!a/*.bib"])).to.equal(false);
expect(isPreservedPath("#notes.txt", ["#notes.txt"])).to.equal(true);
});
it("matches dotfiles and ignores empty input", function () {
expect(isPreservedPath(".zenodo.json", ["*.json"])).to.equal(true);
expect(isPreservedPath("refs.bib", [])).to.equal(false);
expect(isPreservedPath("", ["*"])).to.equal(false);
expect(isPreservedPath("refs.bib", undefined)).to.equal(false);
});
});
describe("normalizePreserveFiles", function () {
it("trims, drops blanks and duplicates", function () {
expect(normalizePreserveFiles([" refs.bib ", "", "refs.bib", "*.bib"]))
.to.deep.equal(["refs.bib", "*.bib"]);
});
it("keeps the last copy of a repeated rule so the result does not change", function () {
const raw = ["!a.bib", "*.bib", "!a.bib"];
const normalized = normalizePreserveFiles(raw);
expect(normalized).to.deep.equal(["*.bib", "!a.bib"]);
expect(isPreservedPath("a.bib", normalized)).to.equal(isPreservedPath("a.bib", raw));
expect(isPreservedPath("a.bib", normalized)).to.equal(false);
expect(normalizePreserveFiles(undefined)).to.deep.equal([]);
expect(normalizePreserveFiles(["!private/", "paper/"])).to.deep.equal(["!private/", "paper/"]);
expect(normalizePreserveFiles(["/refs.bib", "!private.bib", "/a\\{b\\}"])).to.deep.equal(["/refs.bib", "!private.bib", "/a\\{b\\}"]);
});
it("rejects invalid input", function () {
expect(normalizePreserveFiles("refs.bib")).to.equal(null);
expect(normalizePreserveFiles([1])).to.equal(null);
expect(normalizePreserveFiles(["//x"])).to.equal(null);
expect(normalizePreserveFiles(["/"])).to.equal(null);
expect(normalizePreserveFiles(["../x"])).to.equal(null);
expect(normalizePreserveFiles(["!"])).to.equal(null);
expect(normalizePreserveFiles(["!/"])).to.equal(null);
expect(normalizePreserveFiles(["//"])).to.equal(null);
expect(normalizePreserveFiles(["!../x"])).to.equal(null);
expect(normalizePreserveFiles(["x".repeat(513)])).to.equal(null);
expect(normalizePreserveFiles(Array.from({ length: 201 }, (_, i) => `f${i}`))).to.equal(null);
});
});
describe("AnonymizeTransformer", function () {
const bib = "@article{smith2024, author = {Jane Smith}}";
it("leaves matching files unredacted", async function () {
const out = await run({ filePath: "paper/refs.bib", terms: ["Smith"], preserveFiles: ["*.bib"] }, bib);
expect(out).to.equal(bib);
});
it("still redacts files that do not match", async function () {
const out = await run({ filePath: "paper/main.tex", terms: ["Smith"], preserveFiles: ["*.bib"] }, "by Jane Smith");
expect(out).to.equal("by Jane XXXX-1");
});
it("keeps the full options for re-evaluation downstream", function () {
const t = new AnonymizeTransformer({ filePath: "refs.bib", terms: ["Smith"], preserveFiles: ["refs.bib"] });
expect(t.opt.terms).to.deep.equal(["Smith"]);
});
});
it("changes cache keys when the pattern list changes", function () {
const base = { filePath: "refs.bib", terms: ["Smith"] };
expect(decisionKey("d", { ...base, preserveFiles: [] }))
.to.not.equal(decisionKey("d", { ...base, preserveFiles: ["refs.bib"] }));
});
});
+57
View File
@@ -0,0 +1,57 @@
const { expect } = require("chai");
require("ts-node/register/transpile-only");
const GitHubUtils = require("../src/core/GitHubUtils");
const { sourceFileList, SOURCE_FILE_LIST_LIMIT } = require("../src/core/source-file-list");
describe("sourceFileList (#941)", function () {
const original = GitHubUtils.octokit;
let response;
let request;
beforeEach(() => {
GitHubUtils.octokit = () => ({
repos: { getCommit: async ({ ref }) => ({ data: { sha: ref.padEnd(40, "0") } }) },
git: { getTree: async (params) => {
request = params;
if (response instanceof Error) throw response;
return { data: response };
} },
});
});
afterEach(() => { GitHubUtils.octokit = original; });
const opt = { owner: "o", repo: "r", commit: "a".repeat(40), accessToken: "t" };
it("lists text files of the commit, sorted, without folders, submodules or binaries", async function () {
response = { truncated: false, tree: [
{ type: "tree", path: "paper" },
{ type: "blob", path: "paper/refs.bib" },
{ type: "blob", path: "README.md" },
{ type: "blob", path: "fig.png" },
{ type: "blob", path: ".gitmodules" },
{ type: "commit", path: "vendor/lib" },
] };
expect(await sourceFileList(opt)).to.deep.equal({ files: ["README.md", "paper/refs.bib"], truncated: false });
expect(request).to.include({ owner: "o", repo: "r", tree_sha: "a".repeat(40), recursive: "true" });
});
it("resolves an abbreviated commit hash before reading the tree", async function () {
response = { truncated: false, tree: [] };
await sourceFileList({ ...opt, commit: "abc123" });
expect(request.tree_sha).to.equal("abc123".padEnd(40, "0"));
});
it("reports GitHub truncation and caps the list", async function () {
response = { truncated: true, tree: [{ type: "blob", path: "a.txt" }] };
expect((await sourceFileList(opt)).truncated).to.equal(true);
response = { truncated: false, tree: Array.from({ length: SOURCE_FILE_LIST_LIMIT + 1 }, (_, i) => ({ type: "blob", path: `f${i}.txt` })) };
const capped = await sourceFileList(opt);
expect(capped.files).to.have.length(SOURCE_FILE_LIST_LIMIT);
expect(capped.truncated).to.equal(true);
});
it("maps a missing repository or commit to repo_not_found", async function () {
response = Object.assign(new Error("Not Found"), { status: 404 });
try { await sourceFileList(opt); expect.fail("should throw"); }
catch (error) { expect(error.message).to.equal("repo_not_found"); }
});
});
+31
View File
@@ -0,0 +1,31 @@
const { expect } = require("chai");
require("ts-node/register/transpile-only");
const { termHints, escapeTermLine } = require("../src/core/term-hints");
describe("term hints", function () {
it("ignores dots, hyphens and emails", function () {
expect(termHints("mchen-research\nhartwell.edu\nmaya.chen@cs.example.edu\nA, B #1")).to.deep.equal([]);
});
it("flags symbols that change what a term matches", function () {
expect(termHints("Maya Chen\nSmith (MIT)\nC++")).to.deep.equal([
{ line: 1, term: "Smith (MIT)", symbols: ["(", ")"] },
{ line: 2, term: "C++", symbols: ["+"] },
]);
});
it("skips escaped symbols and the replacement side", function () {
expect(termHints("Smith \\(MIT\\)\nAnon=>A (B)")).to.deep.equal([]);
});
it("escapes one line and keeps its replacement", function () {
expect(escapeTermLine("a\nSmith (MIT).x=>Anon (1)\nb", 1)).to.equal("a\nSmith \\(MIT\\)\\.x=>Anon (1)\nb");
expect(escapeTermLine("C\\+\\+ +", 0)).to.equal("C\\+\\+ \\+");
});
it("inserts terms containing $ sequences literally", function () {
expect(escapeTermLine("a$&b (x)", 0)).to.equal("a\\$&b \\(x\\)");
expect(escapeTermLine(" $'(y)=>z", 0)).to.equal(" \\$'\\(y\\)=>z");
expect(escapeTermLine("$1+", 0)).to.equal("\\$1\\+");
});
});