fix: isolate website limits and scope explorer counts

This commit is contained in:
Thomas Durieux committed 2026-11-03 15:03:23 +00:00
1 parent 77e22a87e8
commit d4b9fd85e7
13 files changed
+360 -32

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
# Website requests and folder counts
Website assets under `/w/` have a separate Redis-backed request budget. The
default `WEBSITE_RATE_LIMIT=2000` allows 2,000 requests per visitor in 15 minutes,
including signed-out visitors. Requests across repositories share this budget.
They do not consume the `/api` or `/github` allowance. Website slowdown, access
checks, file-size limits and streaming protections still apply. Rejections
include `Retry-After` and the existing JSON `rate_limited` response.
Visitor identity uses the existing trusted-proxy address resolver. Do not trust
arbitrary forwarding headers or change `TRUST_PROXY` without verifying the
actual proxy chain. API and maintenance-token rate policies are unchanged.
The explorer requests `/api/repo/:repoId/files/counts?path=…` after loading each
directory, once per directory per viewer initialization. The path is the same
anonymized path used for browsing. A response contains recursive file counts for
that directory and its immediate children, rather than a repository-wide map.
Counts use the captured active tree generation and sum anonymized child-name
collisions. Entering a colliding directory resolves the same original directory
as browsing it. No original paths are returned.
The aggregation has a two-second database deadline, allows disk spill, and
returns at most 10,000 child groups plus the parent total. It still scans files
in the requested subtree; root counts can scan the whole active tree. No
cross-request cache bypasses authorization or retains counts from old snapshots.
The legacy endpoint without `path` retains its existing bounded response.
Counts are optional. If a count request fails, the explorer continues browsing
without unavailable badges and stops issuing further count requests until the
viewer is reinitialized. It does not label the number of loaded tree entries as
the repository's total file count. File listing guards remain in place.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"core.min.js": "core.4a77c8ac41.min.js",
"vendor.min.js": "vendor.0b27dbacff.min.js",
"vendor.min.js": "vendor.5616fbf9b5.min.js",
"mermaid.min.js": "mermaid.a7356d5ed1.min.js",
"all.min.css": "all.c9afb0c819.min.css",
"markdown.min.js": "markdown.6c8dfb7b1d.min.js",
+1 -1
View File
@@ -21,7 +21,7 @@
</div>
<div class="leftCol-project-header">
<span class="project-name" v-text="repoId" :title="repoId"></span>
<span class="project-file-count">{{ fileCounts?.[''] || files?.length }} files</span>
<span class="project-file-count" v-if="fileCounts?.[''] != null">{{ fileCounts[''] }} files</span>
<span class="project-expiry" v-if="options?.expirationDate" :title="options.expirationDate">
<svg class="ui-icon" aria-hidden="true"><use href="#project-icon-clock"></use></svg>
Available until {{ fmt?.date(options.expirationDate) }}
+20 -8
View File
@@ -2718,32 +2718,42 @@ export const exploreController = function (state, http, location, params, html,
}
}
state.fileCounts = null;
let listingGeneration = 0;
let countRequests = new Set();
let countsUnavailable = false;
state.getFiles = function (path) {
const repoId = state.repoId;
const generation = listingGeneration;
return http.get(
`/api/repo/${state.repoId}/files/?path=${encodeURIComponent(path)}&v=${state.options.lastUpdateDate}`
).then(function (res) {
if (destroyed || repoId !== state.repoId) return [];
if (destroyed || repoId !== state.repoId || generation !== listingGeneration) return [];
const normalized = path || "";
state.files = state.files.filter((f) => f.path !== normalized);
state.files.push(...res.data);
fetchFileCounts(normalized, generation);
return res.data;
}, function (err) {
if (destroyed || repoId !== state.repoId) return [];
if (destroyed || repoId !== state.repoId || generation !== listingGeneration) return [];
state.type = "error";
state.content = viewerErrorCode(err);
state.files = [];
});
};
function fetchFileCounts() {
function fetchFileCounts(path, generation) {
if (countsUnavailable || countRequests.has(path)) return;
countRequests.add(path);
const repoId = state.repoId;
http.get(
`/api/repo/${state.repoId}/files/counts`
`/api/repo/${state.repoId}/files/counts?path=${encodeURIComponent(path)}`
).then(function (res) {
if (destroyed || repoId !== state.repoId) return;
state.fileCounts = res.data;
if (destroyed || repoId !== state.repoId || generation !== listingGeneration) return;
state.fileCounts = { ...state.fileCounts, ...res.data };
}, function () {
state.fileCounts = {};
if (destroyed || repoId !== state.repoId || generation !== listingGeneration) return;
// Counts are optional. Do not retry a guarded or rate-limited query
// every time a visitor opens another directory.
countsUnavailable = true;
});
}
@@ -3140,6 +3150,9 @@ export const exploreController = function (state, http, location, params, html,
state.files = [];
state.content = null;
state.fileCounts = null;
listingGeneration++;
countRequests = new Set();
countsUnavailable = false;
state.fileSearchQuery = "";
state.onFileSearchChange();
state.repoId = params.repoId;
@@ -3149,7 +3162,6 @@ export const exploreController = function (state, http, location, params, html,
const repoId = state.repoId;
getOptions(function (options) {
fetchFileCounts();
var chain = promises.resolve();
for (let i = 0; i < state.paths.length; i++) {
const path = i > 0 ? state.paths.slice(0, i).join("/") : "";
+21 -21
View File
@@ -1,30 +1,30 @@
"use strict";(()=>{var Sd=Object.defineProperty;var _d=(e,t)=>{for(var o in t)Sd(e,o,{get:t[o],enumerable:!0})};var ce=["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 pe={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 Ei(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 Ci(e,t){let{http:o,promises:i,window:s}=t,r=t.takeReviewHandoff(),a=r?{clientId:r.clientId,intentId:r.intentId}:null,c,f,g,y,b,h=!0,E,_=i.defer(),m=()=>[...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 C=()=>h&&e.user?.username===b;function N(){h=!1,r=c=f=void 0,_.resolve(),s.clearTimeout(E)}e.on("dispose",N),e.on("routeLeave",N),e.watch(()=>e.user?.username,L=>{!b&&L?b=L:b&&L!==b&&(N(),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 O=()=>({timeout:_.promise,headers:{"Content-Type":"application/json","X-Review-CSRF":f}}),q=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(!h||!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,c=void 0,e.acceptAccess=e.acceptRetention=!1,e.expired=!1,s.clearTimeout(E),y||(y=m());try{let U=(await o.get("/api/review-consent/csrf",{timeout:_.promise})).data;if(!C())return;if(f=U.csrf,e.handoffEnabled=U.handoffEnabled===!0,!/^[a-f0-9]{64}$/.test(f||""))throw new Error("invalid_csrf");let z=(await o.post("/api/review-consent/preview",{repositoryId:L,intent:{...r,requestId:y}},O())).data;if(!C())return;if(!z||typeof z.ticket!="string"||!z.ticket||z.ticket.length>8192||typeof z.repositoryName!="string"||!["restricted-review","anonymous-link"].includes(z.policy?.access)||!Number.isSafeInteger(z.policy.version)||!Number.isFinite(Date.parse(z.policy.retainUntil))||!Number.isFinite(Date.parse(z.expiresAt))||Date.parse(z.expiresAt)<=Date.now()||Date.parse(z.expiresAt)>Date.now()+6e5)throw new Error("invalid_preview");c=z.ticket,g=m(),e.preview={repositoryName:z.repositoryName,policy:{...z.policy},expiresAt:z.expiresAt},E=s.setTimeout(()=>{h&&(e.expired=!0)},Math.max(0,Date.parse(z.expiresAt)-Date.now()))}catch(U){C()&&(e.error=q(U))}finally{C()&&(e.busy=!1)}},e.confirmConsent=async()=>{if(!(!C()||e.busy||e.saved||!c||!e.acceptAccesLine truncated
`))),e[Bt]=Tn(s);let r=i||s.props&&s.props.type==="number";tn(e,t?"change":"input",a=>{a.target.composing||e[Bt](Xs(e.value,o,r))}),(o||r)&&tn(e,"change",()=>{e.value=Xs(e.value,o,r)}),t||(tn(e,"compositionstart",Dc),tn(e,"compositionend",ua),tn(e,"change",ua))},mounted(e,{value:t,modifiers:{trim:o,number:i}}){let s=t??"",r=e[Qo];delete e[Qo],r!==void 0&&(e.type==="text"||e.type==="textarea")&&e.value!==r?e[Bt](Xs(e.value,o,i)):e.value=s},beforeUpdate(e,{value:t,oldValue:o,modifiers:{lazy:i,trim:s,number:r}},a){if(e[Bt]=Tn(a),e.composing)return;let c=(r||e.type==="number")&&!/^0\d/.test(e.value)?En(e.value):e.value,f=t??"";if(c===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)}},xs={deep:!0,created(e,t,o){e[Bt]=Tn(o),tn(e,"change",()=>{let i=e._modelValue,s=mo(e),r=e.checked,a=e[Bt];if(he(i)){let c=So(i,s),f=c!==-1;if(r&&!f)a(i.concat(s));else if(!r&&f){let g=[...i];g.splice(c,1),a(g)}}else if(Ct(i)){let c=new Set(i);r?c.add(s):c.delete(s),a(c)}else a(va(e,r))})},mounted:ca,beforeUpdate(e,t,o){e[Bt]=Tn(o),ca(e,t,o)}};function ca(e,{value:t,oldValue:o},i){e._modelValue=t;let s;if(he(t))s=So(t,i.props.value)>-1;else if(Ct(t))s=t.has(i.props.value);else{if(t===o)return;s=St(t,va(e,!0))}e.checked!==s&&(e.checked=s)}var pn={deep:!0,created(e,{value:t,modifiers:{number:o}},i){e._modelValue=t,tn(e,"change",()=>{let s=Array.prototype.filter.call(e.options,f=>f.selected).map(f=>o?En(mo(f)):mo(f)),r=e.multiple,a=r?Ct(e._modelValue)?new Set(s):s:s[0],c=e._pendingValue=[r,r?he(a)?s.slice():s:a];try{e[Bt](a)}finally{Ke(()=>{e._pendingValue===c&&(e._pendingValue=void 0)})}}),e[Bt]=Tn(i)},mounted(e,{value:t}){pa(e,t)},beforeUpdate(e,{value:t},o){e._modelValue=t,e[Bt]=Tn(o)},updated(e,{value:t}){let o=e._pendingValue;e._pendingValue=void 0,(!o||o[0]!==e.multiple||!Tc(t,o[1],o[0]))&&pa(e,t)}};function Tc(e,t,o){if(!o)return St(e,t);if(he(e))return St(e,t);if(Ct(e)){if(e.size!==t.length)return!1;for(let i of t)if(!e.has(i))return!1;return!0}return!1}function pa(e,t){let o=e.multiple,i=he(t);if(!(o&&!i&&!Ct(t))){for(let s=0,r=e.options.length;s<r;s++){let a=e.options[s],c=mo(a);if(o)if(i){let f=typeof c;f==="string"||f==="number"?a.selected=t.some(g=>String(g)===String(c)):a.selected=So(t,c)>-1}else a.selected=t.has(c);else if(St(mo(a),t)){e.selectedIndex!==s&&(e.selectedIndex=s);return}}!o&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function mo(e){return"_value"in e?e._value:e.value}function va(e,t){let o=t?"_trueValue":"_falseValue";return o in e?e[o]:t}var Ac=["ctrl","shift","alt","meta"],Oc={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)=>Ac.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 c=Oc[t[a]];if(c&&c(s,t))return}return e(s,...r)}))},Pc={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},An=(e,t)=>{let o=e._withKeys||(e._withKeys={}),i=t.join(".");return o[i]||(o[i]=(s=>{if(!("key"in s))return;let r=Ot(s.key);if(t.some(a=>a===r||Pc[a]===r))return e(s)}))},Ic=je({patchProp:_c},dc),fa;function Vc(){return fa||(fa=Wr(Ic))}var ga=((...e)=>{let t=Vc().createApp(...e),{mount:o}=t;return t.mount=i=>{let s=Mc(i);if(!s)return;let r=t._component;!ye(r)&&!r.render&&!r.template&&(r.template=s.innerHTML),s.nodeType===1&&(s.textContent="");let a=o(s,!1,qc(s));return s instanceof Element&&(s.removeAttribute("v-cloak"),s.setAttribute("data-v-app","")),a},t});function qc(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function Mc(e){return Le(e)?document.querySelector(e):e}var mn=typeof document<"u";function ba(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&&ba(e.default)}var Ae=Object.assign;function Zo(e,t){let o={};for(let i in t){let s=t[i];o[i]=kt(s)?s.map(e):e(s)}return o}var Pn=()=>{},kt=Array.isArray;function ni(e,t){let o={};for(let i in e)o[i]=i in t?t[i]:e[i];return o}var wa=/#/g,$c=/&/g,Lc=/\//g,Fc=/=/g,Bc=/\?/g,ka=/\+/g,Hc=/%5B/g,zc=/%5D/g,Ea=/%5E/g,jc=/%60/g,Ca=/%7B/g,Gc=/%7C/g,Sa=/%7D/g,Wc=/%20/g;function oi(e){return e==null?"":encodeURI(""+e).replace(Gc,"|").replace(Hc,"[").replace(zc,"]")}function _a(e){return oi(e).replace(Ca,"{").replace(Sa,"}").replace(Ea,"^")}function ei(e){return oi(e).replace(ka,"%2B").replace(Wc,"+").replace(wa,"%23").replace($c,"%26").replace(jc,"`").replace(Ca,"{").replace(Sa,"}").replace(Ea,"^")}function Kc(e){return ei(e).replace(Fc,"%3D")}function Yc(e){return oLine truncated
"use strict";(()=>{var Sd=Object.defineProperty;var _d=(e,t)=>{for(var o in t)Sd(e,o,{get:t[o],enumerable:!0})};var ce=["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 pe={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 Ei(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 Ci(e,t){let{http:o,promises:i,window:s}=t,r=t.takeReviewHandoff(),a=r?{clientId:r.clientId,intentId:r.intentId}:null,c,f,g,y,b,h=!0,E,_=i.defer(),m=()=>[...s.crypto.getRandomValues(new Uint8Array(16))].map(U=>U.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 C=()=>h&&e.user?.username===b;function N(){h=!1,r=c=f=void 0,_.resolve(),s.clearTimeout(E)}e.on("dispose",N),e.on("routeLeave",N),e.watch(()=>e.user?.username,U=>{!b&&U?b=U:b&&U!==b&&(N(),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 A=()=>({timeout:_.promise,headers:{"Content-Type":"application/json","X-Review-CSRF":f}}),M=U=>U?.status===404?"Artifact linking is not available on this server.":U?.status===401?"Sign in, then open a new artifact link from your submission.":U?.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;b=e.user.username;let U=e.repositoryId.trim();if(!/^[A-Za-z0-9_-]{3,128}$/.test(U)){e.error="Enter the anonymous repository ID from its URL.";return}e.busy=!0,e.error="",e.preview=null,c=void 0,e.acceptAccess=e.acceptRetention=!1,e.expired=!1,s.clearTimeout(E),y||(y=m());try{let q=(await o.get("/api/review-consent/csrf",{timeout:_.promise})).data;if(!C())return;if(f=q.csrf,e.handoffEnabled=q.handoffEnabled===!0,!/^[a-f0-9]{64}$/.test(f||""))throw new Error("invalid_csrf");let B=(await o.post("/api/review-consent/preview",{repositoryId:U,intent:{...r,requestId:y}},A())).data;if(!C())return;if(!B||typeof B.ticket!="string"||!B.ticket||B.ticket.length>8192||typeof B.repositoryName!="string"||!["restricted-review","anonymous-link"].includes(B.policy?.access)||!Number.isSafeInteger(B.policy.version)||!Number.isFinite(Date.parse(B.policy.retainUntil))||!Number.isFinite(Date.parse(B.expiresAt))||Date.parse(B.expiresAt)<=Date.now()||Date.parse(B.expiresAt)>Date.now()+6e5)throw new Error("invalid_preview");c=B.ticket,g=m(),e.preview={repositoryName:B.repositoryName,policy:{...B.policy},expiresAt:B.expiresAt},E=s.setTimeout(()=>{h&&(e.expired=!0)},Math.max(0,Date.parse(B.expiresAt)-Date.now()))}catch(q){C()&&(e.error=M(q))}finally{C()&&(e.busy=!1)}},e.confirmConsent=async()=>{if(!(!C()||e.busy||e.saved||!c||!e.acceptAccesLine truncated
`))),e[Bt]=Tn(s);let r=i||s.props&&s.props.type==="number";tn(e,t?"change":"input",a=>{a.target.composing||e[Bt](Xs(e.value,o,r))}),(o||r)&&tn(e,"change",()=>{e.value=Xs(e.value,o,r)}),t||(tn(e,"compositionstart",Dc),tn(e,"compositionend",ua),tn(e,"change",ua))},mounted(e,{value:t,modifiers:{trim:o,number:i}}){let s=t??"",r=e[Qo];delete e[Qo],r!==void 0&&(e.type==="text"||e.type==="textarea")&&e.value!==r?e[Bt](Xs(e.value,o,i)):e.value=s},beforeUpdate(e,{value:t,oldValue:o,modifiers:{lazy:i,trim:s,number:r}},a){if(e[Bt]=Tn(a),e.composing)return;let c=(r||e.type==="number")&&!/^0\d/.test(e.value)?En(e.value):e.value,f=t??"";if(c===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)}},xs={deep:!0,created(e,t,o){e[Bt]=Tn(o),tn(e,"change",()=>{let i=e._modelValue,s=mo(e),r=e.checked,a=e[Bt];if(he(i)){let c=So(i,s),f=c!==-1;if(r&&!f)a(i.concat(s));else if(!r&&f){let g=[...i];g.splice(c,1),a(g)}}else if(Ct(i)){let c=new Set(i);r?c.add(s):c.delete(s),a(c)}else a(va(e,r))})},mounted:ca,beforeUpdate(e,t,o){e[Bt]=Tn(o),ca(e,t,o)}};function ca(e,{value:t,oldValue:o},i){e._modelValue=t;let s;if(he(t))s=So(t,i.props.value)>-1;else if(Ct(t))s=t.has(i.props.value);else{if(t===o)return;s=St(t,va(e,!0))}e.checked!==s&&(e.checked=s)}var pn={deep:!0,created(e,{value:t,modifiers:{number:o}},i){e._modelValue=t,tn(e,"change",()=>{let s=Array.prototype.filter.call(e.options,f=>f.selected).map(f=>o?En(mo(f)):mo(f)),r=e.multiple,a=r?Ct(e._modelValue)?new Set(s):s:s[0],c=e._pendingValue=[r,r?he(a)?s.slice():s:a];try{e[Bt](a)}finally{Ke(()=>{e._pendingValue===c&&(e._pendingValue=void 0)})}}),e[Bt]=Tn(i)},mounted(e,{value:t}){pa(e,t)},beforeUpdate(e,{value:t},o){e._modelValue=t,e[Bt]=Tn(o)},updated(e,{value:t}){let o=e._pendingValue;e._pendingValue=void 0,(!o||o[0]!==e.multiple||!Tc(t,o[1],o[0]))&&pa(e,t)}};function Tc(e,t,o){if(!o)return St(e,t);if(he(e))return St(e,t);if(Ct(e)){if(e.size!==t.length)return!1;for(let i of t)if(!e.has(i))return!1;return!0}return!1}function pa(e,t){let o=e.multiple,i=he(t);if(!(o&&!i&&!Ct(t))){for(let s=0,r=e.options.length;s<r;s++){let a=e.options[s],c=mo(a);if(o)if(i){let f=typeof c;f==="string"||f==="number"?a.selected=t.some(g=>String(g)===String(c)):a.selected=So(t,c)>-1}else a.selected=t.has(c);else if(St(mo(a),t)){e.selectedIndex!==s&&(e.selectedIndex=s);return}}!o&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function mo(e){return"_value"in e?e._value:e.value}function va(e,t){let o=t?"_trueValue":"_falseValue";return o in e?e[o]:t}var Ac=["ctrl","shift","alt","meta"],Oc={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)=>Ac.some(o=>e[`${o}Key`]&&!t.includes(o))},de=(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 c=Oc[t[a]];if(c&&c(s,t))return}return e(s,...r)}))},Pc={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},An=(e,t)=>{let o=e._withKeys||(e._withKeys={}),i=t.join(".");return o[i]||(o[i]=(s=>{if(!("key"in s))return;let r=Ot(s.key);if(t.some(a=>a===r||Pc[a]===r))return e(s)}))},Ic=je({patchProp:_c},dc),fa;function Vc(){return fa||(fa=Wr(Ic))}var ga=((...e)=>{let t=Vc().createApp(...e),{mount:o}=t;return t.mount=i=>{let s=Mc(i);if(!s)return;let r=t._component;!ye(r)&&!r.render&&!r.template&&(r.template=s.innerHTML),s.nodeType===1&&(s.textContent="");let a=o(s,!1,qc(s));return s instanceof Element&&(s.removeAttribute("v-cloak"),s.setAttribute("data-v-app","")),a},t});function qc(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function Mc(e){return Le(e)?document.querySelector(e):e}var mn=typeof document<"u";function ba(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&&ba(e.default)}var Oe=Object.assign;function Zo(e,t){let o={};for(let i in t){let s=t[i];o[i]=kt(s)?s.map(e):e(s)}return o}var Pn=()=>{},kt=Array.isArray;function ni(e,t){let o={};for(let i in e)o[i]=i in t?t[i]:e[i];return o}var wa=/#/g,$c=/&/g,Lc=/\//g,Fc=/=/g,Bc=/\?/g,ka=/\+/g,Hc=/%5B/g,zc=/%5D/g,Ea=/%5E/g,jc=/%60/g,Ca=/%7B/g,Gc=/%7C/g,Sa=/%7D/g,Wc=/%20/g;function oi(e){return e==null?"":encodeURI(""+e).replace(Gc,"|").replace(Hc,"[").replace(zc,"]")}function _a(e){return oi(e).replace(Ca,"{").replace(Sa,"}").replace(Ea,"^")}function ei(e){return oi(e).replace(ka,"%2B").replace(Wc,"+").replace(wa,"%23").replace($c,"%26").replace(jc,"`").replace(Ca,"{").replace(Sa,"}").replace(Ea,"^")}function Kc(e){return ei(e).replace(Fc,"%3D")}function Yc(e){return oLine truncated
${JSON.stringify(e)}${t?`
while being at
`+JSON.stringify(t):""}`},[ze.NAVIGATION_GUARD_REDIRECT]({from:e,to:t}){return`Redirected from "${e.fullPath}" to "${op(t)}" via a navigation guard.`},[ze.NAVIGATION_ABORTED]({from:e,to:t}){return`Navigation aborted from "${e.fullPath}" to "${t.fullPath}" via a navigation guard.`},[ze.NAVIGATION_CANCELLED]({from:e,to:t}){return`Navigation cancelled from "${e.fullPath}" to "${t.fullPath}" with a new navigation.`},[ze.NAVIGATION_DUPLICATED]({from:e,to:t}){return`Avoided redundant navigation to current location: "${e.fullPath}".`}};function hn(e,t){return Ae(new Error,{type:e,[Va]:!0},t)}function Ht(e,t){return e instanceof Error&&Va in e&&(t==null||!!(e.type&t))}var np=["params","query","hash"];function op(e){if(typeof e=="string")return e;if(e.path!=null)return e.path;let t={};for(let o of np)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(ka," "),r=s.indexOf("="),a=On(r<0?s:s.slice(0,r)),c=r<0?null:On(s.slice(r+1));if(a in t){let f=t[a];kt(f)||(f=t[a]=[f]),f.push(c)}else t[a]=c}return t}function li(e){let t="";for(let o in e){let i=e[o];if(o=Kc(o),i==null){i!==void 0&&(t+=(t.length?"&":"")+o);continue}(kt(i)?i.map(s=>s&&ei(s)):[i&&ei(i)]).forEach(s=>{s!==void 0&&(t+=(t.length?"&":"")+o,s!=null&&(t+="="+s))})}return t}function Ma(e){let t={};for(let o in e){let i=e[o];i!==void 0&&(t[o]=kt(i)?i.map(s=>s==null?null:""+s):i==null?i:""+i)}return t}var Ua=Symbol(""),di=Symbol(""),ns=Symbol(""),os=Symbol(""),ss=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 Qt(e,t,o,i,s,r=a=>a()){let a=i&&(i.enterCallbacks[s]=i.enterCallbacks[s]||[]);return()=>new Promise((c,f)=>{let g=h=>{h===!1?f(hn(ze.NAVIGATION_ABORTED,{from:o,to:t})):h instanceof Error?f(h):tp(h)?f(hn(ze.NAVIGATION_GUARD_REDIRECT,{from:t,to:h})):(a&&i.enterCallbacks[s]===a&&typeof h=="function"&&a.push(h),c())},y=r(()=>e.call(i&&i.instances[s],t,o,g)),b=Promise.resolve(y);e.length<3&&(b=b.then(g)),b.catch(h=>f(h))})}function is(e,t,o,i,s=r=>r()){let r=[];for(let a of e)for(let c in a.components){let f=a.components[c];if(!(t!=="beforeRouteEnter"&&!a.instances[c]))if(ba(f)){let g=(f.__vccOpts||f)[t];g&&r.push(Qt(g,o,i,a,c,s))}else{let g=f();r.push(()=>g.then(y=>{if(!y)throw new Error(`Couldn't resolve component "${c}" at "${a.path}"`);let b=Uc(y)?y.default:y;a.mods[c]=y,a.components[c]=b;let h=(b.__vccOpts||b)[t];return h&&Qt(h,o,i,a,c,s)()}))}}return r}function $a(e,t){let o=[],i=[],s=[],r=Math.max(t.matched.length,e.matched.length);for(let a=0;a<r;a++){let c=t.matched[a];c&&(e.matched.find(g=>fn(g,c))?i.push(c):o.push(c));let f=e.matched[a];f&&(t.matched.find(g=>fn(g,f))||s.push(f))}return[o,i,s]}var sp=()=>location.protocol+"//"+location.host;function Ja(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,c=s.slice(a);return c[0]!=="/"&&(c="/"+c),si(c,"")}return si(o,e)+i+s}function ip(e,t,o,i){let s=[],r=[],a=null,c=({state:h})=>{let E=Ja(e,location),_=o.value,m=t.value,C=0;if(h){if(o.value=E,t.value=h,a&&a===_){a=null;return}C=m?h.position-m.position:0}else i(E);s.forEach(N=>{N(o.value,_,{delta:C,type:es.pop,direction:C?C>0?ts.forward:ts.back:ts.unknown})})};function f(){a=o.value}function g(h){s.push(h);let E=()=>{let _=s.indexOf(h);_>-1&&s.splice(_,1)};return r.push(E),E}function y(){if(document.visibilityState==="hidden"){let{history:h}=window;if(!h.state)return;h.replaceState(Ae({},h.state,{scroll:vo()}),"")}}function b(){for(let h of r)h();r=[],window.removeEventListener("popstate",c),window.removeEventListener("pagehide",y),document.removeEventListener("visibilitychange",y)}return window.addEventListener("popstate",c),window.addEventListener("pagehide",y),document.addEventListener("visibilitychange",y),{pauseListeners:f,listen:g,destroy:b}}function La(e,t,o,i=!1,s=!1){return{back:e,current:t,forward:o,replaced:i,position:window.history.length,scroll:s?vo():null}}function rp(e){let{history:t,location:o}=window,i={value:Ja(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("#"),h=b>-1?(o.host&&document.querySelector("base")?e:e.slice(b))+f:sp()+e+f;try{t[y?"replaceState":"pushState"](g,"",h),s.value=g}catch(E){console.error(E),o[y?"replace":"assign"](h)}}function a(f,g){r(f,Ae({},t.state,La(s.value.back,f,s.value.forward,!0),g,{position:s.value.position}),!0),i.value=f}function c(f,g){let y=Ae({},s.value,t.state,{forward:f,scroll:vo()});r(y.current,y,!0),r(f,Ae({},La(i.value,f,null),{position:y.position+1},g),!1),i.value=f}return{location:i,state:s,push:c,replace:a}}function Qa(e){e=Ta(e);let t=rp(e),o=ip(e,t.state,t.location,t.replace);function i(r,a=!0){a||o.pauseListeners(),history.go(r)}let s=Ae({locatLine truncated
`+JSON.stringify(t):""}`},[He.NAVIGATION_GUARD_REDIRECT]({from:e,to:t}){return`Redirected from "${e.fullPath}" to "${op(t)}" via a navigation guard.`},[He.NAVIGATION_ABORTED]({from:e,to:t}){return`Navigation aborted from "${e.fullPath}" to "${t.fullPath}" via a navigation guard.`},[He.NAVIGATION_CANCELLED]({from:e,to:t}){return`Navigation cancelled from "${e.fullPath}" to "${t.fullPath}" with a new navigation.`},[He.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 np=["params","query","hash"];function op(e){if(typeof e=="string")return e;if(e.path!=null)return e.path;let t={};for(let o of np)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(ka," "),r=s.indexOf("="),a=On(r<0?s:s.slice(0,r)),c=r<0?null:On(s.slice(r+1));if(a in t){let f=t[a];kt(f)||(f=t[a]=[f]),f.push(c)}else t[a]=c}return t}function li(e){let t="";for(let o in e){let i=e[o];if(o=Kc(o),i==null){i!==void 0&&(t+=(t.length?"&":"")+o);continue}(kt(i)?i.map(s=>s&&ei(s)):[i&&ei(i)]).forEach(s=>{s!==void 0&&(t+=(t.length?"&":"")+o,s!=null&&(t+="="+s))})}return t}function Ma(e){let t={};for(let o in e){let i=e[o];i!==void 0&&(t[o]=kt(i)?i.map(s=>s==null?null:""+s):i==null?i:""+i)}return t}var Ua=Symbol(""),di=Symbol(""),ns=Symbol(""),os=Symbol(""),ss=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 Qt(e,t,o,i,s,r=a=>a()){let a=i&&(i.enterCallbacks[s]=i.enterCallbacks[s]||[]);return()=>new Promise((c,f)=>{let g=h=>{h===!1?f(hn(He.NAVIGATION_ABORTED,{from:o,to:t})):h instanceof Error?f(h):tp(h)?f(hn(He.NAVIGATION_GUARD_REDIRECT,{from:t,to:h})):(a&&i.enterCallbacks[s]===a&&typeof h=="function"&&a.push(h),c())},y=r(()=>e.call(i&&i.instances[s],t,o,g)),b=Promise.resolve(y);e.length<3&&(b=b.then(g)),b.catch(h=>f(h))})}function is(e,t,o,i,s=r=>r()){let r=[];for(let a of e)for(let c in a.components){let f=a.components[c];if(!(t!=="beforeRouteEnter"&&!a.instances[c]))if(ba(f)){let g=(f.__vccOpts||f)[t];g&&r.push(Qt(g,o,i,a,c,s))}else{let g=f();r.push(()=>g.then(y=>{if(!y)throw new Error(`Couldn't resolve component "${c}" at "${a.path}"`);let b=Uc(y)?y.default:y;a.mods[c]=y,a.components[c]=b;let h=(b.__vccOpts||b)[t];return h&&Qt(h,o,i,a,c,s)()}))}}return r}function $a(e,t){let o=[],i=[],s=[],r=Math.max(t.matched.length,e.matched.length);for(let a=0;a<r;a++){let c=t.matched[a];c&&(e.matched.find(g=>fn(g,c))?i.push(c):o.push(c));let f=e.matched[a];f&&(t.matched.find(g=>fn(g,f))||s.push(f))}return[o,i,s]}var sp=()=>location.protocol+"//"+location.host;function Ja(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,c=s.slice(a);return c[0]!=="/"&&(c="/"+c),si(c,"")}return si(o,e)+i+s}function ip(e,t,o,i){let s=[],r=[],a=null,c=({state:h})=>{let E=Ja(e,location),_=o.value,m=t.value,C=0;if(h){if(o.value=E,t.value=h,a&&a===_){a=null;return}C=m?h.position-m.position:0}else i(E);s.forEach(N=>{N(o.value,_,{delta:C,type:es.pop,direction:C?C>0?ts.forward:ts.back:ts.unknown})})};function f(){a=o.value}function g(h){s.push(h);let E=()=>{let _=s.indexOf(h);_>-1&&s.splice(_,1)};return r.push(E),E}function y(){if(document.visibilityState==="hidden"){let{history:h}=window;if(!h.state)return;h.replaceState(Oe({},h.state,{scroll:vo()}),"")}}function b(){for(let h of r)h();r=[],window.removeEventListener("popstate",c),window.removeEventListener("pagehide",y),document.removeEventListener("visibilitychange",y)}return window.addEventListener("popstate",c),window.addEventListener("pagehide",y),document.addEventListener("visibilitychange",y),{pauseListeners:f,listen:g,destroy:b}}function La(e,t,o,i=!1,s=!1){return{back:e,current:t,forward:o,replaced:i,position:window.history.length,scroll:s?vo():null}}function rp(e){let{history:t,location:o}=window,i={value:Ja(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("#"),h=b>-1?(o.host&&document.querySelector("base")?e:e.slice(b))+f:sp()+e+f;try{t[y?"replaceState":"pushState"](g,"",h),s.value=g}catch(E){console.error(E),o[y?"replace":"assign"](h)}}function a(f,g){r(f,Oe({},t.state,La(s.value.back,f,s.value.forward,!0),g,{position:s.value.position}),!0),i.value=f}function c(f,g){let y=Oe({},s.value,t.state,{forward:f,scroll:vo()});r(y.current,y,!0),r(f,Oe({},La(i.value,f,null),{position:y.position+1},g),!1),i.value=f}return{location:i,state:s,push:c,replace:a}}function Qa(e){e=Ta(e);let t=rp(e),o=ip(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()})}c();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(h=>h.trim()).filter(h=>h.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)},h=>{e.saving=!1;let E=h&&h.data&&h.data.error,_="Unable to save your defaults. Please try again.";Promise.all([o("ERRORS."+E),o("ERRORS.unknown_error")]).then(([m,C])=>{e.error=E&&m!==C?m:_},()=>{e.error=_})})},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."}))}},dl=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)})}},ul=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(c){e.feature=c},e.featureHref=function(c){return c.needsUser&&!e.user?"/signin":c.href},e.featureTarget=function(c){return c.needsUser&&!e.user?"_self":c.target||void 0},e.featureKeydown=function(c,f){let g={ArrowDown:1,ArrowRight:1,ArrowUp:-1,ArrowLeft:-1,Home:"first",End:"last"}[c.key];if(g===void 0)return;c.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 h=i.document.getElementById("feature-tab-"+e.feature);h&&h.focus()})},e.cards=[{key:"repositories",total:0,label:"repositories anonymized"},{key:"users",total:0,label:"researchers"},{key:"pageViews",total:0,label:"page views"},{key:"pullRequests",total:0,label:"pull requests"}];function r(){t.get("/api/stat/").then(c=>{e.stat=c.data,e.cards[0].total=c.data.nbRepositories,e.cards[1].total=c.data.nbUsers,e.cards[2].total=c.data.nbPageViews,e.cards[3].total=c.data.nbPullRequests})}r();function a(c){let f={series:c,bars:[],viewW:100,deltaToday:0,pctChange:0,pctAbs:0,isUp:!0};if(!c||c.length<2)return f;let g=new Array(c.length-1);for(let m=1;m<c.length;m++)g[m-1]=c[m]-c[m-1];let y=g.length,b=Math.max.apply(null,g),h=Math.min.apply(null,g),E=Math.min(0,h),_=b-E||1;f.viewW=y*2,f.bars=new Array(y);for(let m=0;m<y;m++){let C=(g[m]-E)/_,N=Math.max(1.5,C*34);f.bars[m]={x:(m*2+.25).toFixed(2),y:(36-N).toFixed(2),w:"1.5",h:N.toFixed(2)}}if(f.deltaToday=g[y-1],y>=2){let m=g[y-2];m&&(f.pctChange=(f.deltaToday-m)/m*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(c=>{let f=c.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))}})},cl=function(e,t,o,i,s,r){let a=ut();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,Ke(()=>document.querySelector(".dashboard-quota > summary")?.focus())},Zt()(document,"click",R=>{e.quotaExpanded&&!R.target.closest?.(".dashboard-quota")&&(e.quotaExpanded=!1)}),e.filtersExpanded=!1,e.projectView="all",e.selectedProject=null,e. Line truncated
`)),e.options=Object.assign({},e.options,A.options),e.options.expirationDate=A.options&&A.options.expirationDate?new Date(A.options.expirationDate):z(),!i.repoId&&!i.pullRequestId&&!i.gistId&&!e.anonymize?.terms?.dirty&&(e.terms=e.defaultTerms),w&&w()})}function G(w,T,A){e.anonymize&&e.anonymize[w]&&e.anonymize[w].setValidity(T,A)}function J(w){try{let T=parseGithubUrl(w);if(T&&T.owner&&T.repo)return T.owner+"/"+T.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"||J(e.sourceUrl)!==e._originalFullName)return;e.repairingGitHubAccess=!0,e.accessRepairMessage="";let w=h();try{let T=await t.get("/github/connections");if(e.githubConnections=T.data,!T.data.appEnabled)return;let A=await t.post("/github/connections/migrate",{type:"repository",id:i.repoId,connection:"github-app"},{headers:{"X-CSRF-Token":T.data.csrf}});if(!b(w))return;e.error=null,A.data.fullName&&(e._originalFullName=A.data.fullName,e.source.fullName=A.data.fullName,e.sourceUrl="https://github.com/"+A.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 le()}catch{}}};function ie(){return e.reconnectingSource||!e.isUpdate||!e._originalRepositoryID?void 0:J(e.sourceUrl)===e._originalFullName?e._originalRepositoryID:void 0}async function ue(){e._preservingDraft=!0;try{await e.urlSelected(!0)}finally{e._preservingDraft=!1}}async function de(){let w=new URLSearchParams(window.location.search).get("billingDraft");if(w){C.restore();try{let A=(await t.get("/api/billing/draft/"+encodeURIComponent(w))).data;if(A.path!==s.path())throw new Error("Wrong task");N=A.values.conference||null;for(let I of["sourceUrl","terms","repoId","source","options","conference","githubConnection"])Object.prototype.hasOwnProperty.call(A.values,I)&&(e[I]=A.values[I]);return e.options?.expirationDate&&(e.options.expirationDate=new Date(e.options.expirationDate)),O=A.id,q=JSON.stringify(C.checkpoint()),e.draftRestored=!0,e.hostingReview=!0,e.sourceUrl&&await ue(),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 T;try{T=JSON.parse(sessionStorage.getItem("github-access-draft")||"null")}catch{return!1}if(!T||T.path!==s.path()||Date.now()-T.savedAt>=30*6e4)return C.restore()?(e.sourceUrl&&await ue(),!0):!1;C.restore();for(let A of["sourceUrl","terms","repoId","pullRequestId","gistId","source","options","conference","githubConnection"])Object.prototype.hasOwnProperty.call(T.draft,A)&&(e[A]=T.draft[A]);return e.options.expirationDate&&(e.options.expirationDate=new Date(e.options.expirationDate)),await ue(),sessionStorage.removeItem("github-access-draft"),!0}X(()=>{!i.repoId&&!i.pullRequestId&&!i.gistId&&a(de,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(T=>T).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)),_=m(parseGithubUrl(e.sourceUrl)),!await de()&&(await Promise.all([le(),_e()]),Ne())},()=>{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(T=>T).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)),_=m(parseGithubUrl(e.sourceUrl)),!await de())try{await Be()}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(T=>T).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)),_=m(parseGithubUrl(e.sourceUrl)),!await de()&&await ee()},()=>{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&&ue())}).catch(()=>{}),e.urlSelected=async(w=!1)=>{let T=++f;e.previousConfigurations=[],e.previousConfigurationId="";let A;try{A=parseGithubUrl(e.sourceUrl.trim())}catch{e.sourceLoading=!1,De.cancel(),H.cancel(),ve.cancel(),e.previewStatus="idle",e.sourceUrlError=e.sourceUrl?"Please provide a valid GitHub URL.":"",G("sourceUrl","github",!1);return}let I=m(A),B=w||_===I;_=I,e.sourceUrlError="",G("sourceUrl","github",!0);let F=document.activeElement?.id==="sourceUrl-landing";e.workspaceOpen=!0,F&&a(()=>document.getElementById("sourceUrl")?.focus(),0),e.reconnectingSource=!1,e.reconnectRepositoryId=void 0,!B&&!e.isUpdate&&(e.repoId="",e.pullRequestId="",e.gistId=""),e.details=null,e.branches=[],B||(e.source={type:"GitHubStream",branch:"",commit:""}),De.cancel(),H.cancel(),ve.cancel(),Me.clear(),Q.clear(),e.previewStatus="idle",e.anonymize_readme="",e.readme="",e.html_readme="",e.detectedType=null,e.gistOAuthRequired=!1,e.gistAppRequired=!1,e._preservingDraft=B;try{A.gistId&&!A.repo?(e.detectedType="gist",e.source={gistId:A.gistId},await ee()):A.pullRequestId?(e.detectedType="pr",e.source={repositoryFullName:A.owner+"/"+A.repo,pullRequestId:A.pullRequestId},await Be()):(e.detectedType="repo",Y(),await Promise.all([le(),_e()]),Ne())}catch{}finally{T===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(A=>A.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 _e(),Ne()}),e.getBranches=async w=>{let T=parseGithubUrl(e.sourceUrl),A=h();try{let I=await t.get(`/api/repo/${T.owner}/${T.repo}/branches`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&i.repoId&&J(e.sourceUrl)===e._originalFullName?i.repoId:void 0,connection:e.githubConnection,force:w===!0||e.reconnectingSource?"1":"0",repositoryID:ie()}});if(!b(A))return;e.branches=I.data,e.sourceUnreachable=!1,e.source.branch||(e.source.branch=e.details.defaultBranch);let B=e.branches.filter(F=>F.name==e.source.branch);B.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=B[0].commit),e.readme=B[0].readme,await _e(w))}catch(I){if(!b(A))return;e.branches=[],e.sourceUnreachable=I&&(I.status===404||I.data&&I.data.error==="repo_not_found");let B=I&&I.data&&I.data.error||(I&&I.status===404?"repo_not_found":"unknown_error");r("ERRORS."+B).then(F=>{e.toasts=e.toasts||[],e.addToast({title:"Error",date:new Date,body:F}),e.error=F},console.error),typeof G=="function"&&G("sourceUrl","missing",!1)}finally{E(A)}};async function le(){let w=parseGithubUrl(e.sourceUrl),T=h();try{S();let A=await t.get(`/api/repo/${w.owner}/${w.repo}/`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&i.repoId&&J(e.sourceUrl)===e._originalFullName?i.repoId:void 0,connection:e.githubConnection,repositoryID:ie(),force:"1"}});if(!b(T))return;e.details=A.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(A){if(!b(T))return;throw A.data&&(r("ERRORS."+A.data.error).then(I=>{e.addToast({title:"Error",date:new Date,body:I}),e.error=I},console.error),j(A.data.error)),G("sourceUrl","missing",!1),A}finally{E(T)}}async function _e(w){if(e.readme&&!w)return e.readme;let T=parseGithubUrl(e.sourceUrl),A=h();try{let I=await t.get(`/api/repo/${T.owner}/${T.repo}/readme`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&i.repoId&&J(e.sourceUrl)===e._originalFullName?i.repoId:void 0,connection:e.githubConnection,force:w===!0?"1":"0",branch:e.source.branch,repositoryID:ie()}});b(A,!0)&&(e.readme=I.data)}catch{b(A,!0)&&(e.readme="")}finally{E(A)}}function Ve(){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 T=parseGithubUrl(e.sourceUrl);w.repoName=`${T.owner}/${T.repo}`}catch{}return w}function $e(w,T,A){let I=null,B=0,F=()=>{if(e.detectedType!==w)return;I&&a.cancel(I);let se=++B;e.previewStatus="loading",I=a(()=>{I=null;let Z=T();if(!Z){e.previewStatus="idle";return}t.post("/api/anonymize-preview",Z).then(re=>{se===B&&(A(re.data,Z),e.previewStatus="ready")}).catch(()=>{se===B&&(e.previewStatus="error")})},200)};return F.cancel=()=>{B++,I&&a.cancel(I),I=null},e.on("dispose",F.cancel),F}e.retryPreview=()=>{e.detectedType==="repo"&&De(),e.detectedType==="pr"&&H(),e.detectedType==="gist"&&ve()};let De=$e("repo",()=>e.readme?{content:e.readme,options:Ve()}:null,w=>{if(typeof w?.content!="string")throw Error("Invalid preview response");e.anonymize_readme=w.content;let T="";try{let I=parseGithubUrl(e.sourceUrl),B=e.source.branch||e.details&&e.details.defaultBranch||"main";T=`https://github.com/${I.owner}/${I.repo}/raw/${B}/`}catch{}let A=renderMD(e.anonymize_readme,T);e.html_readme=A,a(Prism.highlightAll,150)});function Ne(){!e.anonymize||!e.anonymize.terms||(e.termsRegexWarning=!!e.terms&&!!e.terms.match(/[-[\]{}()*+?.,\\^$|#]/g),De())}async function Be(){let w=parseGithubUrl(e.sourceUrl),T=h();try{S();let A=await t.get(`/api/pr/${w.owner}/${w.repo}/${w.pullRequestId}`,{params:{connection:e.githubConnection}});if(!b(T))return;e.details=A.data,e.pullRequestId||(e.pullRequestId=w.repo+"-PR"+w.pullRequestId+"-"+generateRandomId(4))}catch(A){if(!b(T))return;throw A.data&&(r("ERRORS."+A.data.error).then(I=>{e.addToast({title:"Error",date:new Date,body:I}),e.error=I},console.error),j(A.data.error)),G("sourceUrl","missing",!1),A}finally{E(T)}}let Me=Fe(new Map);function ke(){let w=new Set,T=e.details&&e.details.pullRequest;if(!T)return w;typeof T.title=="string"&&w.add(T.title),typeof T.body=="string"&&w.add(T.body),typeof T.diff=="string"&&w.add(T.diff);let A=T.comments||[];for(let I of A)typeof I.author=="string"&&w.add(I.author),typeof I.body=="string"&&w.add(I.body);return w}let H=$e("pr",()=>{let w=ke(),T=Array.from(w);return T.length===0?null:{contents:T,options:Ve()}},(w,T)=>{if(!Array.isArray(w?.contents)||w.contents.length!==T.contents.length||w.contents.some(B=>typeof B!="string"))throw Error("Invalid preview response");let A=T.contents,I=new Map;for(let B=0;B<A.length&&B<w.contents.length;B++)I.set(A[B],w.contents[B]);Me.clear(),I.forEach((B,F)=>Me.set(F,B))});e.anonymizePrContent=function(w){return w&&(Me.has(w)?Me.get(w):"")};async function ee(){let w=parseGithubUrl(e.sourceUrl),T=h();try{S(),e.gistOAuthRequired=!1,e.gistAppRequired=!1;let A=await t.get(`/api/gist/source/${w.gistId}`);if(!b(T))return;e.details=A.data,e.gistId||(e.gistId="gist-"+w.gistId.substring(0,6)+"-"+generateRandomId(4))}catch(A){if(!b(T))return;if(A.data?.error==="github_app_reconnect_required"){e.gistAppRequired=!0,G("sourceUrl","missing",!1);return}if(A.data?.error==="github_oauth_required"){e.gistOAuthRequired=!0,G("sourceUrl","missing",!1);return}throw A.data&&(r("ERRORS."+A.data.error).then(I=>{e.addToast({title:"Error",date:new Date,body:I}),e.error=I},console.error),j(A.data.error)),G("sourceUrl","missing",!1),A}finally{E(T)}}let Q=Fe(new Map);function oe(){let w=new Set,T=e.details&&e.details.gist;if(!T)return w;typeof T.description=="string"&&w.add(T.description),typeof T.ownerLogin=="string"&&w.add(T.ownerLogin);let A=T.files||[];for(let B of A)typeof B.filename=="string"&&w.add(B.filename),typeof B.content=="string"&&w.add(B.content);let I=T.comments||[];for(let B of I)typeof B.author=="string"&&w.add(B.author),typeof B.body=="string"&&w.add(B.body);return w}let ve=$e("gist",()=>{let w=oe(),T=Array.from(w);return T.length===0?null:{contents:T,options:Ve()}},(w,T)=>{if(!Array.isArray(w?.contents)||w.contents.length!==T.contents.length||w.contents.some(B=>typeof B!="string"))throw Error("Invalid preview response");let A=T.contents,I=new Map;for(let B=0;B<A.length&&B<w.contents.length;B++)I.set(A[B],w.contents[B]);Q.clear(),I.forEach((B,F)=>Q.set(F,B)),Ce()});e.anonymizeGistContent=function(w){return w&&(Q.has(w)?Q.get(w):"")},e.previewGistFiles=[];function Ce(){let w=e.details&&e.details.gist&&e.details.gist.files||[];e.previewGistFiles=w.map(T=>({filename:e.anonymizeGistContent(T.filename),content:e.anonymizeGistContent(T.content),language:T.language}))}e.watch("details.gist.files",Ce,!0),e.watch("terms",Ce);function k(){let w=e.conference;if(e.conference_data=null,!w)return;let T=w===N||e.isUpdate&&w===e._originalConference;w!==N&&(N=null),t.get("/api/conferences/"+w).then(A=>{e.conference===w&&(e.conference_data=A.data,e.conference_data.startDate=new Date(e.conference_data.startDate),e.conference_data.endDate=new Date(e.conference_data.endDate),!T&&(e.options.expirationDate=new Date(e.conference_data.endDate),e.options.expirationMode="remove",e.options.update=e.conference_data.options.update Line truncated
`).filter(F=>F),connection:e.githubConnection,fullName:`${A.owner}/${A.repo}`,repository:e.sourceUrl,reconnectRepositoryId:e.reconnectRepositoryId,options:e.options,source:e.source,conference:e.conference};e.details&&(I.options.pageSource=e.details.pageSource),S();let B=e.isUpdate?"/api/repo/"+e.repoId:"/api/repo/";t.post(B,I,{headers:{"Content-Type":"application/json"}}).then(()=>{C.clear(),window.location.href="/status/"+e.repoId},F=>{F.data&&(r("ERRORS."+F.data.error).then(se=>{e.error=se},console.error),j(F.data.error),["quota_exceeded","subscription_required_for_never_expiration"].includes(F.data.error)&&(F.data.error==="subscription_required_for_never_expiration"&&(e._existingNever=!1),e.hostingQuotaBlocked=!0,e.hostingReview=!0,Ke(()=>document.getElementById("repository-hosting")?.scrollIntoView({block:"center"}))))}).finally(()=>{T.disabled=!1})},e.anonymizeGist=w=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(M())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let T=w.currentTarget||w.target.closest?.("button")||w.target;T.disabled=!0;let A=parseGithubUrl(e.sourceUrl),I={gistId:e.gistId,terms:e.terms.trim().split(`
`).filter(F=>F),source:{gistId:A.gistId},options:e.options,conference:e.conference};S();let B=e.isUpdate?"/api/gist/"+e.gistId:"/api/gist/";t.post(B,I,{headers:{"Content-Type":"application/json"}}).then(()=>{C.clear(),window.location.href="/gist/"+e.gistId},F=>{F.data&&(r("ERRORS."+F.data.error).then(se=>{e.error=se},console.error),j(F.data.error))}).finally(()=>{T.disabled=!1})},e.anonymizePullRequest=w=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(M())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let T=w.currentTarget||w.target.closest?.("button")||w.target;T.disabled=!0;let A=parseGithubUrl(e.sourceUrl),I={pullRequestId:e.pullRequestId,connection:e.githubConnection,terms:e.terms.trim().split(`
`).filter(F=>F),source:{repositoryFullName:`${A.owner}/${A.repo}`,pullRequestId:A.pullRequestId},options:e.options,conference:e.conference};S();let B=e.isUpdate?"/api/pr/"+e.pullRequestId:"/api/pr/";t.post(B,I,{headers:{"Content-Type":"application/json"}}).then(()=>{C.clear(),window.location.href="/pr/"+e.pullRequestId},F=>{F.data&&(r("ERRORS."+F.data.error).then(se=>{e.error=se},console.error),j(F.data.error))}).finally(()=>{T.disabled=!1})},e.watch("conference",()=>{k()}),e.watch("terms",()=>{e.detectedType==="repo"&&Ne(),e.detectedType==="pr"&&H(),e.detectedType==="gist"&&ve()}),e.watch("options.image",()=>{e.detectedType==="repo"&&Ne(),e.detectedType==="pr"&&H(),e.detectedType==="gist"&&ve()}),e.watch("options.link",()=>{e.detectedType==="repo"&&Ne(),e.detectedType==="pr"&&H(),e.detectedType==="gist"&&ve()}),e.watch("details",()=>{e.detectedType==="pr"&&H(),e.detectedType==="gist"&&ve()},!0)},mi=function(e,t,o,i,s,r){let a=ut();window.Prism?.hooks&&!window.Prism.redactionHook&&(window.Prism.hooks.add("complete",V=>ol(V.element)),window.Prism.redactionHook=!0);let c=Zt();e.on("dark-mode",(V,Y)=>{e.aceOption&&(Y?e.aceOption.theme="nord_dark":e.aceOption.theme="chrome")});let f=0,g=!1;e.on("dispose",()=>{g=!0,f++,y&&y.resolve()}),e.files=[],e.isMac=/Mac|iPhone|iPad|iPod/.test(navigator.platform||navigator.userAgent),e.fileSearchQuery="",e.fileSearchResults=null,e.fileSearchLoading=!1,c(document,"keydown",function(V){if((V.metaKey||V.ctrlKey)&&V.key==="k"){V.preventDefault();var Y=document.querySelector(".tree-search-input");Y&&(Y.focus(),Y.select())}});var y=null;e.onFileSearchChange=function(){y&&(y.resolve(),y=null);let V=e.fileSearchQuery;if(!V||V.length<2){e.fileSearchResults=null,e.fileSearchLoading=!1;return}e.fileSearchLoading=!0;let Y=r.defer();y=Y,t.get(`/api/repo/${e.repoId}/files/search?q=${encodeURIComponent(V)}`,{timeout:Y.promise}).then(function(X){if(!(g||y!==Y)){y=null,e.fileSearchLoading=!1;var G={};e.files.forEach(function(H){G[(H.path||"")+"/"+H.name]=!0});for(var J=[],ie={},ue=0;ue<X.data.length;ue++){var de=X.data[ue];if(de.path)for(var le=de.path.split("/"),_e="",Ve=0;Ve<le.length;Ve++){var $e=_e;_e=_e?_e+"/"+le[Ve]:le[Ve];var De=$e+"/"+le[Ve];!G[De]&&!ie[De]&&(ie[De]=!0,J.push({name:le[Ve],path:$e}))}}J.sort(function(H,ee){return(H.path||"").split("/").length-(ee.path||"").split("/").length}),J.length>0&&e.files.push.apply(e.files,J);for(var Ne=[],Be=0;Be<X.data.length;Be++){var Me=X.data[Be],ke=(Me.path||"")+"/"+Me.name;!G[ke]&&Me.size!=null&&(Ne.push(Me),G[ke]=!0)}Ne.length>0&&e.files.push.apply(e.files,Ne),e.fileSearchResults=X.data}},function(){!g&&y===Y&&(y=null,e.fileSearchLoading=!1,e.fileSearchResults=[])})};let b={yml:"yaml",txt:"text",py:"python",js:"javascript",ts:"typescript"},h=["license","txt"],E=["png","jpg","jpeg","gif","svg","ico","bmp","tiff","tif","webp","avif","heif","heic"],_=["wav","mp3","ogg","wma","flac","aac","m4a"],m=["mp4","avi","webm","mov","mpg","mpeg","mkv","flv","wmv","3gp","3g2","m4v","f4v","f4p","f4a","f4b"];e.on("routeUpdate",function(V,Y){if(e.repoId!=i.repoId)return R();if((i.path||"")!=e.filePath){e.filePath=i.path||"",e.paths=e.filePath.split("/").filter(X=>X&&X.trim().length>0),x();for(let X=0;X<e.paths.length-1;X++){let G=X>0?e.paths.slice(0,X).join("/"):"";e.files.some(ie=>ie.path===G)||e.getFiles(G)}}});function C(){if(e.paths[0]!="")return;let V=["readme.md","readme.txt","readme.org","readme.1st","readme"],Y={};for(let G of e.files)G.name.toLowerCase().indexOf("readme")>-1&&(Y[G.name.toLowerCase()]=G.name);let X=null;for(let G of V)if(Y[G]){X=G;break}if(!X&&Object.keys(Y).length>0&&(X=Object.keys(Y)[0]),X){let G=o.url();G[G.length-1]!="/"&&(G+="/"),o.url(G+encodePathForUrl(Y[X]))}}e.fileCounts=null,e.getFiles=function(V){let Y=e.repoId;return t.get(`/api/repo/${e.repoId}/files/?path=${encodeURIComponent(V)}&v=${e.options.lastUpdateDate}`).then(function(X){if(g||Y!==e.repoId)return[];let G=V||"";return e.files=e.files.filter(J=>J.path!==G),e.files.push(...X.data),X.data},function(X){if(g||Y!==e.repoId)return[];e.type="error",e.content=hi(X),e.files=[]})};function N(){let V=e.repoId;t.get(`/api/repo/${e.repoId}/files/counts`).then(function(Y){g||V!==e.repoId||(e.fileCounts=Y.data)},function(){e.fileCounts={}})}function O(){return e.files.filter(V=>V.name==e.paths[e.paths.length-1]&&V.path==e.paths.slice(0,e.paths.length-1).join("/"))[0]}var q=null;e.on("dispose",function(){q&&a.interval.cancel(q)});function L(V){if(g)return;let Y=e.repoId;t.get(`/api/repo/${e.repoId}/options`).then(X=>{if(!(g||Y!==e.repoId)){if(e.options=X.data,e.options.url){window.location=e.options.url;return}V&&V(X.data)}},X=>{if(!(g||Y!==e.repoId)){var G=X.data||{};if(G.error==="rate_limited"&&G.resetAt){let ie=function(){var ue=Math.max(0,Math.ceil((e.rateLimitResetAt-Date.now())/1e3));if(ue<=0)e.rateLimitCountdown="",e.rateLimitResetAt=0,q&&(a.interval.cancel(q),q=null),L(V);else{var de=Math.floor(ue/60),le=ue%60;e.rateLimitCountdown=de>0?de+"m "+le+"s":le+"s"}};var J= Line truncated
`).map(h=>h.trim()).filter(h=>h.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)},h=>{e.saving=!1;let E=h&&h.data&&h.data.error,_="Unable to save your defaults. Please try again.";Promise.all([o("ERRORS."+E),o("ERRORS.unknown_error")]).then(([m,C])=>{e.error=E&&m!==C?m:_},()=>{e.error=_})})},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."}))}},dl=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)})}},ul=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(c){e.feature=c},e.featureHref=function(c){return c.needsUser&&!e.user?"/signin":c.href},e.featureTarget=function(c){return c.needsUser&&!e.user?"_self":c.target||void 0},e.featureKeydown=function(c,f){let g={ArrowDown:1,ArrowRight:1,ArrowUp:-1,ArrowLeft:-1,Home:"first",End:"last"}[c.key];if(g===void 0)return;c.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 h=i.document.getElementById("feature-tab-"+e.feature);h&&h.focus()})},e.cards=[{key:"repositories",total:0,label:"repositories anonymized"},{key:"users",total:0,label:"researchers"},{key:"pageViews",total:0,label:"page views"},{key:"pullRequests",total:0,label:"pull requests"}];function r(){t.get("/api/stat/").then(c=>{e.stat=c.data,e.cards[0].total=c.data.nbRepositories,e.cards[1].total=c.data.nbUsers,e.cards[2].total=c.data.nbPageViews,e.cards[3].total=c.data.nbPullRequests})}r();function a(c){let f={series:c,bars:[],viewW:100,deltaToday:0,pctChange:0,pctAbs:0,isUp:!0};if(!c||c.length<2)return f;let g=new Array(c.length-1);for(let m=1;m<c.length;m++)g[m-1]=c[m]-c[m-1];let y=g.length,b=Math.max.apply(null,g),h=Math.min.apply(null,g),E=Math.min(0,h),_=b-E||1;f.viewW=y*2,f.bars=new Array(y);for(let m=0;m<y;m++){let C=(g[m]-E)/_,N=Math.max(1.5,C*34);f.bars[m]={x:(m*2+.25).toFixed(2),y:(36-N).toFixed(2),w:"1.5",h:N.toFixed(2)}}if(f.deltaToday=g[y-1],y>=2){let m=g[y-2];m&&(f.pctChange=(f.deltaToday-m)/m*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(c=>{let f=c.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))}})},cl=function(e,t,o,i,s,r){let a=ut();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,Ke(()=>document.querySelector(".dashboard-quota > summary")?.focus())},Zt()(document,"click",R=>{e.quotaExpanded&&!R.target.closest?.(".dashboard-quota")&&(e.quotaExpanded=!1)}),e.filtersExpanded=!1,e.projectView="all",e.selectedProject=null,e. Line truncated
`)),e.options=Object.assign({},e.options,O.options),e.options.expirationDate=O.options&&O.options.expirationDate?new Date(O.options.expirationDate):B(),!i.repoId&&!i.pullRequestId&&!i.gistId&&!e.anonymize?.terms?.dirty&&(e.terms=e.defaultTerms),w&&w()})}function z(w,T,O){e.anonymize&&e.anonymize[w]&&e.anonymize[w].setValidity(T,O)}function J(w){try{let T=parseGithubUrl(w);if(T&&T.owner&&T.repo)return T.owner+"/"+T.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"||J(e.sourceUrl)!==e._originalFullName)return;e.repairingGitHubAccess=!0,e.accessRepairMessage="";let w=h();try{let T=await t.get("/github/connections");if(e.githubConnections=T.data,!T.data.appEnabled)return;let O=await t.post("/github/connections/migrate",{type:"repository",id:i.repoId,connection:"github-app"},{headers:{"X-CSRF-Token":T.data.csrf}});if(!b(w))return;e.error=null,O.data.fullName&&(e._originalFullName=O.data.fullName,e.source.fullName=O.data.fullName,e.sourceUrl="https://github.com/"+O.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 re()}catch{}}};function Q(){return e.reconnectingSource||!e.isUpdate||!e._originalRepositoryID?void 0:J(e.sourceUrl)===e._originalFullName?e._originalRepositoryID:void 0}async function te(){e._preservingDraft=!0;try{await e.urlSelected(!0)}finally{e._preservingDraft=!1}}async function X(){let w=new URLSearchParams(window.location.search).get("billingDraft");if(w){C.restore();try{let O=(await t.get("/api/billing/draft/"+encodeURIComponent(w))).data;if(O.path!==s.path())throw new Error("Wrong task");N=O.values.conference||null;for(let I of["sourceUrl","terms","repoId","source","options","conference","githubConnection"])Object.prototype.hasOwnProperty.call(O.values,I)&&(e[I]=O.values[I]);return e.options?.expirationDate&&(e.options.expirationDate=new Date(e.options.expirationDate)),A=O.id,M=JSON.stringify(C.checkpoint()),e.draftRestored=!0,e.hostingReview=!0,e.sourceUrl&&await te(),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 T;try{T=JSON.parse(sessionStorage.getItem("github-access-draft")||"null")}catch{return!1}if(!T||T.path!==s.path()||Date.now()-T.savedAt>=30*6e4)return C.restore()?(e.sourceUrl&&await te(),!0):!1;C.restore();for(let O of["sourceUrl","terms","repoId","pullRequestId","gistId","source","options","conference","githubConnection"])Object.prototype.hasOwnProperty.call(T.draft,O)&&(e[O]=T.draft[O]);return e.options.expirationDate&&(e.options.expirationDate=new Date(e.options.expirationDate)),await te(),sessionStorage.removeItem("github-access-draft"),!0}ve(()=>{!i.repoId&&!i.pullRequestId&&!i.gistId&&a(X,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(T=>T).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)),_=m(parseGithubUrl(e.sourceUrl)),!await X()&&(await Promise.all([re(),Ee()]),_e())},()=>{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(T=>T).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)),_=m(parseGithubUrl(e.sourceUrl)),!await X())try{await ze()}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(T=>T).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)),_=m(parseGithubUrl(e.sourceUrl)),!await X()&&await se()},()=>{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&&te())}).catch(()=>{}),e.urlSelected=async(w=!1)=>{let T=++f;e.previousConfigurations=[],e.previousConfigurationId="";let O;try{O=parseGithubUrl(e.sourceUrl.trim())}catch{e.sourceLoading=!1,Se.cancel(),H.cancel(),ue.cancel(),e.previewStatus="idle",e.sourceUrlError=e.sourceUrl?"Please provide a valid GitHub URL.":"",z("sourceUrl","github",!1);return}let I=m(O),F=w||_===I;_=I,e.sourceUrlError="",z("sourceUrl","github",!0);let L=document.activeElement?.id==="sourceUrl-landing";e.workspaceOpen=!0,L&&a(()=>document.getElementById("sourceUrl")?.focus(),0),e.reconnectingSource=!1,e.reconnectRepositoryId=void 0,!F&&!e.isUpdate&&(e.repoId="",e.pullRequestId="",e.gistId=""),e.details=null,e.branches=[],F||(e.source={type:"GitHubStream",branch:"",commit:""}),Se.cancel(),H.cancel(),ue.cancel(),Ue.clear(),Y.clear(),e.previewStatus="idle",e.anonymize_readme="",e.readme="",e.html_readme="",e.detectedType=null,e.gistOAuthRequired=!1,e.gistAppRequired=!1,e._preservingDraft=F;try{O.gistId&&!O.repo?(e.detectedType="gist",e.source={gistId:O.gistId},await se()):O.pullRequestId?(e.detectedType="pr",e.source={repositoryFullName:O.owner+"/"+O.repo,pullRequestId:O.pullRequestId},await ze()):(e.detectedType="repo",ie(),await Promise.all([re(),Ee()]),_e())}catch{}finally{T===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(O=>O.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 Ee(),_e()}),e.getBranches=async w=>{let T=parseGithubUrl(e.sourceUrl),O=h();try{let I=await t.get(`/api/repo/${T.owner}/${T.repo}/branches`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&i.repoId&&J(e.sourceUrl)===e._originalFullName?i.repoId:void 0,connection:e.githubConnection,force:w===!0||e.reconnectingSource?"1":"0",repositoryID:Q()}});if(!b(O))return;e.branches=I.data,e.sourceUnreachable=!1,e.source.branch||(e.source.branch=e.details.defaultBranch);let F=e.branches.filter(L=>L.name==e.source.branch);F.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=F[0].commit),e.readme=F[0].readme,await Ee(w))}catch(I){if(!b(O))return;e.branches=[],e.sourceUnreachable=I&&(I.status===404||I.data&&I.data.error==="repo_not_found");let F=I&&I.data&&I.data.error||(I&&I.status===404?"repo_not_found":"unknown_error");r("ERRORS."+F).then(L=>{e.toasts=e.toasts||[],e.addToast({title:"Error",date:new Date,body:L}),e.error=L},console.error),typeof z=="function"&&z("sourceUrl","missing",!1)}finally{E(O)}};async function re(){let w=parseGithubUrl(e.sourceUrl),T=h();try{S();let O=await t.get(`/api/repo/${w.owner}/${w.repo}/`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&i.repoId&&J(e.sourceUrl)===e._originalFullName?i.repoId:void 0,connection:e.githubConnection,repositoryID:Q(),force:"1"}});if(!b(T))return;e.details=O.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(O){if(!b(T))return;throw O.data&&(r("ERRORS."+O.data.error).then(I=>{e.addToast({title:"Error",date:new Date,body:I}),e.error=I},console.error),G(O.data.error)),z("sourceUrl","missing",!1),O}finally{E(T)}}async function Ee(w){if(e.readme&&!w)return e.readme;let T=parseGithubUrl(e.sourceUrl),O=h();try{let I=await t.get(`/api/repo/${T.owner}/${T.repo}/readme`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&i.repoId&&J(e.sourceUrl)===e._originalFullName?i.repoId:void 0,connection:e.githubConnection,force:w===!0?"1":"0",branch:e.source.branch,repositoryID:Q()}});b(O,!0)&&(e.readme=I.data)}catch{b(O,!0)&&(e.readme="")}finally{E(O)}}function Te(){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 T=parseGithubUrl(e.sourceUrl);w.repoName=`${T.owner}/${T.repo}`}catch{}return w}function Ae(w,T,O){let I=null,F=0,L=()=>{if(e.detectedType!==w)return;I&&a.cancel(I);let ae=++F;e.previewStatus="loading",I=a(()=>{I=null;let x=T();if(!x){e.previewStatus="idle";return}t.post("/api/anonymize-preview",x).then(le=>{ae===F&&(O(le.data,x),e.previewStatus="ready")}).catch(()=>{ae===F&&(e.previewStatus="error")})},200)};return L.cancel=()=>{F++,I&&a.cancel(I),I=null},e.on("dispose",L.cancel),L}e.retryPreview=()=>{e.detectedType==="repo"&&Se(),e.detectedType==="pr"&&H(),e.detectedType==="gist"&&ue()};let Se=Ae("repo",()=>e.readme?{content:e.readme,options:Te()}:null,w=>{if(typeof w?.content!="string")throw Error("Invalid preview response");e.anonymize_readme=w.content;let T="";try{let I=parseGithubUrl(e.sourceUrl),F=e.source.branch||e.details&&e.details.defaultBranch||"main";T=`https://github.com/${I.owner}/${I.repo}/raw/${F}/`}catch{}let O=renderMD(e.anonymize_readme,T);e.html_readme=O,a(Prism.highlightAll,150)});function _e(){!e.anonymize||!e.anonymize.terms||(e.termsRegexWarning=!!e.terms&&!!e.terms.match(/[-[\]{}()*+?.,\\^$|#]/g),Se())}async function ze(){let w=parseGithubUrl(e.sourceUrl),T=h();try{S();let O=await t.get(`/api/pr/${w.owner}/${w.repo}/${w.pullRequestId}`,{params:{connection:e.githubConnection}});if(!b(T))return;e.details=O.data,e.pullRequestId||(e.pullRequestId=w.repo+"-PR"+w.pullRequestId+"-"+generateRandomId(4))}catch(O){if(!b(T))return;throw O.data&&(r("ERRORS."+O.data.error).then(I=>{e.addToast({title:"Error",date:new Date,body:I}),e.error=I},console.error),G(O.data.error)),z("sourceUrl","missing",!1),O}finally{E(T)}}let Ue=Fe(new Map);function Ie(){let w=new Set,T=e.details&&e.details.pullRequest;if(!T)return w;typeof T.title=="string"&&w.add(T.title),typeof T.body=="string"&&w.add(T.body),typeof T.diff=="string"&&w.add(T.diff);let O=T.comments||[];for(let I of O)typeof I.author=="string"&&w.add(I.author),typeof I.body=="string"&&w.add(I.body);return w}let H=Ae("pr",()=>{let w=Ie(),T=Array.from(w);return T.length===0?null:{contents:T,options:Te()}},(w,T)=>{if(!Array.isArray(w?.contents)||w.contents.length!==T.contents.length||w.contents.some(F=>typeof F!="string"))throw Error("Invalid preview response");let O=T.contents,I=new Map;for(let F=0;F<O.length&&F<w.contents.length;F++)I.set(O[F],w.contents[F]);Ue.clear(),I.forEach((F,L)=>Ue.set(L,F))});e.anonymizePrContent=function(w){return w&&(Ue.has(w)?Ue.get(w):"")};async function se(){let w=parseGithubUrl(e.sourceUrl),T=h();try{S(),e.gistOAuthRequired=!1,e.gistAppRequired=!1;let O=await t.get(`/api/gist/source/${w.gistId}`);if(!b(T))return;e.details=O.data,e.gistId||(e.gistId="gist-"+w.gistId.substring(0,6)+"-"+generateRandomId(4))}catch(O){if(!b(T))return;if(O.data?.error==="github_app_reconnect_required"){e.gistAppRequired=!0,z("sourceUrl","missing",!1);return}if(O.data?.error==="github_oauth_required"){e.gistOAuthRequired=!0,z("sourceUrl","missing",!1);return}throw O.data&&(r("ERRORS."+O.data.error).then(I=>{e.addToast({title:"Error",date:new Date,body:I}),e.error=I},console.error),G(O.data.error)),z("sourceUrl","missing",!1),O}finally{E(T)}}let Y=Fe(new Map);function Z(){let w=new Set,T=e.details&&e.details.gist;if(!T)return w;typeof T.description=="string"&&w.add(T.description),typeof T.ownerLogin=="string"&&w.add(T.ownerLogin);let O=T.files||[];for(let F of O)typeof F.filename=="string"&&w.add(F.filename),typeof F.content=="string"&&w.add(F.content);let I=T.comments||[];for(let F of I)typeof F.author=="string"&&w.add(F.author),typeof F.body=="string"&&w.add(F.body);return w}let ue=Ae("gist",()=>{let w=Z(),T=Array.from(w);return T.length===0?null:{contents:T,options:Te()}},(w,T)=>{if(!Array.isArray(w?.contents)||w.contents.length!==T.contents.length||w.contents.some(F=>typeof F!="string"))throw Error("Invalid preview response");let O=T.contents,I=new Map;for(let F=0;F<O.length&&F<w.contents.length;F++)I.set(O[F],w.contents[F]);Y.clear(),I.forEach((F,L)=>Y.set(L,F)),be()});e.anonymizeGistContent=function(w){return w&&(Y.has(w)?Y.get(w):"")},e.previewGistFiles=[];function be(){let w=e.details&&e.details.gist&&e.details.gist.files||[];e.previewGistFiles=w.map(T=>({filename:e.anonymizeGistContent(T.filename),content:e.anonymizeGistContent(T.content),language:T.language}))}e.watch("details.gist.files",be,!0),e.watch("terms",be);function k(){let w=e.conference;if(e.conference_data=null,!w)return;let T=w===N||e.isUpdate&&w===e._originalConference;w!==N&&(N=null),t.get("/api/conferences/"+w).then(O=>{e.conference===w&&(e.conference_data=O.data,e.conference_data.startDate=new Date(e.conference_data.startDate),e.conference_data.endDate=new Date(e.conference_data.endDate),!T&&(e.options.expirationDate=new Date(e.conference_data.endDate),e.options.expirationMode="remove",e.options.update=e.conference_data.options.update,e Line truncated
`).filter(L=>L),connection:e.githubConnection,fullName:`${O.owner}/${O.repo}`,repository:e.sourceUrl,reconnectRepositoryId:e.reconnectRepositoryId,options:e.options,source:e.source,conference:e.conference};e.details&&(I.options.pageSource=e.details.pageSource),S();let F=e.isUpdate?"/api/repo/"+e.repoId:"/api/repo/";t.post(F,I,{headers:{"Content-Type":"application/json"}}).then(()=>{C.clear(),window.location.href="/status/"+e.repoId},L=>{L.data&&(r("ERRORS."+L.data.error).then(ae=>{e.error=ae},console.error),G(L.data.error),["quota_exceeded","subscription_required_for_never_expiration"].includes(L.data.error)&&(L.data.error==="subscription_required_for_never_expiration"&&(e._existingNever=!1),e.hostingQuotaBlocked=!0,e.hostingReview=!0,Ke(()=>document.getElementById("repository-hosting")?.scrollIntoView({block:"center"}))))}).finally(()=>{T.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 T=w.currentTarget||w.target.closest?.("button")||w.target;T.disabled=!0;let O=parseGithubUrl(e.sourceUrl),I={gistId:e.gistId,terms:e.terms.trim().split(`
`).filter(L=>L),source:{gistId:O.gistId},options:e.options,conference:e.conference};S();let F=e.isUpdate?"/api/gist/"+e.gistId:"/api/gist/";t.post(F,I,{headers:{"Content-Type":"application/json"}}).then(()=>{C.clear(),window.location.href="/gist/"+e.gistId},L=>{L.data&&(r("ERRORS."+L.data.error).then(ae=>{e.error=ae},console.error),G(L.data.error))}).finally(()=>{T.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 T=w.currentTarget||w.target.closest?.("button")||w.target;T.disabled=!0;let O=parseGithubUrl(e.sourceUrl),I={pullRequestId:e.pullRequestId,connection:e.githubConnection,terms:e.terms.trim().split(`
`).filter(L=>L),source:{repositoryFullName:`${O.owner}/${O.repo}`,pullRequestId:O.pullRequestId},options:e.options,conference:e.conference};S();let F=e.isUpdate?"/api/pr/"+e.pullRequestId:"/api/pr/";t.post(F,I,{headers:{"Content-Type":"application/json"}}).then(()=>{C.clear(),window.location.href="/pr/"+e.pullRequestId},L=>{L.data&&(r("ERRORS."+L.data.error).then(ae=>{e.error=ae},console.error),G(L.data.error))}).finally(()=>{T.disabled=!1})},e.watch("conference",()=>{k()}),e.watch("terms",()=>{e.detectedType==="repo"&&_e(),e.detectedType==="pr"&&H(),e.detectedType==="gist"&&ue()}),e.watch("options.image",()=>{e.detectedType==="repo"&&_e(),e.detectedType==="pr"&&H(),e.detectedType==="gist"&&ue()}),e.watch("options.link",()=>{e.detectedType==="repo"&&_e(),e.detectedType==="pr"&&H(),e.detectedType==="gist"&&ue()}),e.watch("details",()=>{e.detectedType==="pr"&&H(),e.detectedType==="gist"&&ue()},!0)},mi=function(e,t,o,i,s,r){let a=ut();window.Prism?.hooks&&!window.Prism.redactionHook&&(window.Prism.hooks.add("complete",z=>ol(z.element)),window.Prism.redactionHook=!0);let c=Zt();e.on("dark-mode",(z,J)=>{e.aceOption&&(J?e.aceOption.theme="nord_dark":e.aceOption.theme="chrome")});let f=0,g=!1;e.on("dispose",()=>{g=!0,f++,y&&y.resolve()}),e.files=[],e.isMac=/Mac|iPhone|iPad|iPod/.test(navigator.platform||navigator.userAgent),e.fileSearchQuery="",e.fileSearchResults=null,e.fileSearchLoading=!1,c(document,"keydown",function(z){if((z.metaKey||z.ctrlKey)&&z.key==="k"){z.preventDefault();var J=document.querySelector(".tree-search-input");J&&(J.focus(),J.select())}});var y=null;e.onFileSearchChange=function(){y&&(y.resolve(),y=null);let z=e.fileSearchQuery;if(!z||z.length<2){e.fileSearchResults=null,e.fileSearchLoading=!1;return}e.fileSearchLoading=!0;let J=r.defer();y=J,t.get(`/api/repo/${e.repoId}/files/search?q=${encodeURIComponent(z)}`,{timeout:J.promise}).then(function(Q){if(!(g||y!==J)){y=null,e.fileSearchLoading=!1;var te={};e.files.forEach(function(Z){te[(Z.path||"")+"/"+Z.name]=!0});for(var X=[],re={},Ee=0;Ee<Q.data.length;Ee++){var Te=Q.data[Ee];if(Te.path)for(var Ae=Te.path.split("/"),Se="",_e=0;_e<Ae.length;_e++){var ze=Se;Se=Se?Se+"/"+Ae[_e]:Ae[_e];var Ue=ze+"/"+Ae[_e];!te[Ue]&&!re[Ue]&&(re[Ue]=!0,X.push({name:Ae[_e],path:ze}))}}X.sort(function(Z,ue){return(Z.path||"").split("/").length-(ue.path||"").split("/").length}),X.length>0&&e.files.push.apply(e.files,X);for(var Ie=[],H=0;H<Q.data.length;H++){var se=Q.data[H],Y=(se.path||"")+"/"+se.name;!te[Y]&&se.size!=null&&(Ie.push(se),te[Y]=!0)}Ie.length>0&&e.files.push.apply(e.files,Ie),e.fileSearchResults=Q.data}},function(){!g&&y===J&&(y=null,e.fileSearchLoading=!1,e.fileSearchResults=[])})};let b={yml:"yaml",txt:"text",py:"python",js:"javascript",ts:"typescript"},h=["license","txt"],E=["png","jpg","jpeg","gif","svg","ico","bmp","tiff","tif","webp","avif","heif","heic"],_=["wav","mp3","ogg","wma","flac","aac","m4a"],m=["mp4","avi","webm","mov","mpg","mpeg","mkv","flv","wmv","3gp","3g2","m4v","f4v","f4p","f4a","f4b"];e.on("routeUpdate",function(z,J){if(e.repoId!=i.repoId)return ve();if((i.path||"")!=e.filePath){e.filePath=i.path||"",e.paths=e.filePath.split("/").filter(Q=>Q&&Q.trim().length>0),ie();for(let Q=0;Q<e.paths.length-1;Q++){let te=Q>0?e.paths.slice(0,Q).join("/"):"";e.files.some(re=>re.path===te)||e.getFiles(te)}}});function C(){if(e.paths[0]!="")return;let z=["readme.md","readme.txt","readme.org","readme.1st","readme"],J={};for(let te of e.files)te.name.toLowerCase().indexOf("readme")>-1&&(J[te.name.toLowerCase()]=te.name);let Q=null;for(let te of z)if(J[te]){Q=te;break}if(!Q&&Object.keys(J).length>0&&(Q=Object.keys(J)[0]),Q){let te=o.url();te[te.length-1]!="/"&&(te+="/"),o.url(te+encodePathForUrl(J[Q]))}}e.fileCounts=null;let N=0,A=new Set,M=!1;e.getFiles=function(z){let J=e.repoId,Q=N;return t.get(`/api/repo/${e.repoId}/files/?path=${encodeURIComponent(z)}&v=${e.options.lastUpdateDate}`).then(function(te){if(g||J!==e.repoId||Q!==N)return[];let X=z||"";return e.files=e.files.filter(re=>re.path!==X),e.files.push(...te.data),U(X,Q),te.data},function(te){if(g||J!==e.repoId||Q!==N)return[];e.type="error",e.content=hi(te),e.files=[]})};function U(z,J){if(M||A.has(z))return;A.add(z);let Q=e.repoId;t.get(`/api/repo/${e.repoId}/files/counts?path=${encodeURIComponent(z)}`).then(function(te){g||Q!==e.repoId||J!==N||(e.fileCounts={...e.fileCounts,...te.data})},function(){g||Q!==e.repoId||J!==N||(M=!0)})}function q(){return e.files.filter(z=>z.name==e.paths[e.paths.length-1]&&z.path==e.paths.slice(0,e.paths.length-1).join("/"))[0]}var B=null;e.on("dispose",function(){B&&a.interval.cancel(B)});function oe(z){if(g)return;let J=e.repoId;t.get(`/api/repo/${e.repoId}/options`).then(Q=>{if(!(g||J!==e.repoId)){if(e.options=Q.data,e.options.url){window.location=e.options.url;return}z&&z(Q.data)}},Q=>{if(!(g||J!==e.repoId)){var te=Q.data||{};if(te.error==="rate_limited"&&te.resetAt){let re=function(){var Ee=Math.max(0,Math.ceil((e.rateLimitResetAt-Date.now())/1e3));if(E Line truncated
`+m.join(`
`)],{type:"text/csv"}),N=document.createElement("a");N.href=URL.createObjectURL(C),N.download=i.username+"-repositories.csv",N.click()},e.showStatusMessage=h=>{let E=h.statusMessage||"(no message)";window.prompt(`Status message for ${h.repoId} (${h.status}):`,E)},e.fetchGithubInfo=h=>{let E=window.open("","_blank");E&&E.document.write("<pre>Loading GitHub info for "+h.repoId+"...</pre>"),t.get("/api/admin/repos/"+h.repoId+"/github").then(_=>{E&&(E.document.open(),E.document.write('<pre style="font:13px monospace;padding:16px;white-space:pre-wrap">'+JSON.stringify(_.data,null,2).replace(/[<>]/g,m=>m==="<"?"&lt;":"&gt;")+"</pre>"),E.document.close())},_=>{let m=_&&_.data?JSON.stringify(_.data,null,2):String(_);E&&(E.document.body.innerHTML='<pre style="color:#B42318;padding:16px">'+m+"</pre>")})};function f(h){t.get("/api/admin/users/"+h+"/repos",{}).then(E=>{e.repositories=E.data},E=>{console.error(E)})}function g(h){t.get("/api/admin/users/"+h,{}).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),h=>console.error(h))},e.activateUser=()=>{t.post(`/api/admin/users/${i.username}/activate`).then(()=>g(i.username),h=>console.error(h))},e.promoteUser=()=>{confirm(`Promote ${i.username} to admin?`)&&t.post(`/api/admin/users/${i.username}/promote`).then(()=>g(i.username),h=>console.error(h))},e.demoteUser=()=>{confirm(`Remove admin privileges from ${i.username}?`)&&t.post(`/api/admin/users/${i.username}/demote`).then(()=>g(i.username),h=>console.error(h))},e.tokens=[],e.tokenForm={name:"",plaintext:null};function y(){t.get("/api/admin/tokens").then(h=>{e.tokens=h.data||[]},h=>{h.status!==401&&h.status!==403&&console.error(h)})}y(),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="",y()},h=>console.error(h))},e.revokeToken=h=>{confirm(`Revoke token "${h.name}"?`)&&t.delete("/api/admin/tokens/"+h.id).then(()=>y(),E=>console.error(E))},e.removeCache=h=>{confirm("Remove cached files for "+h.repoId+"?")&&t.delete("/api/admin/repos/"+h.repoId).then(()=>f(i.username),E=>console.error(E))},e.removeRepository=h=>{confirm("Remove repository "+h.repoId+"?")&&t.delete("/api/repo/"+h.repoId+"/").then(()=>f(i.username),E=>console.error(E))},e.updateRepository=h=>{let E=Fe({title:`Refreshing ${h.repoId}...`,date:new Date,body:`The repository ${h.repoId} is going to be refreshed.`});e.toasts.push(E),t.post(`/api/repo/${h.repoId}/refresh`).then(_=>{_.data.status=="ready"?E.title=`${h.repoId} is refreshed.`:E.title=`Refreshing of ${h.repoId}.`},_=>{E.title=`Error during the refresh of ${h.repoId}.`,E.body=_.body})},e.getGitHubRepositories=h=>{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)},El=function(e,t,o){let i=ut(),s=Zt();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=_=>{if(_.key==="/"&&!["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName)){_.preventDefault();let m=document.querySelector('.admin-filter-toolbar input[type="search"]');m&&m.focus()}};s(document,"keydown",r),e.on("dispose",()=>document.removeEventListener("keydown",r)),e.clearFilter=_=>{_==="dateRange"?(e.query.dateFrom="",e.query.dateTo=""):e.query[_]="",e.query.page=1},e.chips=[];let a=()=>{let _=[];(e.query.dateFrom||e.query.dateTo)&&_.push({key:"dateRange",label:"Date",value:(e.query.dateFrom||"\u2026")+" \u2013 "+(e.query.dateTo||"\u2026")}),e.chips=_};e.statusCountFor=_=>{let m=(e.statusCounts||[]).find(C=>C._id===_);return m?m.count:0},e.toggleSortDirection=()=>{e.query.direction=e.query.direction==="asc"?"desc":"asc"},e.sortBy=_=>{e.query.sort===_?e.query.direction=e.query.direction==="asc"?"desc":"asc":(e.query.sort=_,e.query.direction="desc"),e.query.page=1},e.sortIcon=_=>e.query.sort===_?e.query.direction==="asc"?"fa-arrow-up":"fa-arrow-down":"";let c="admin.conferences.filterPrefs",f={page:1,limit:25,sort:"name",direction:"asc",search:"",dateFrom:"",dateTo:"",ready:!1,expired:!1,removed:!1,error:!0,preparing:!0},g=loadFilterPrefs(c)||{};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 _=window.prompt("Preset name:");if(!_)return;let m=Object.assign({},e.query);delete m.page,e.presets=(e.presets||[]).filter(C=>C.name!==_),e.presets.push({name:_,query:m}),localStorage.setItem(b,JSON.stringify(e.presets))},e.applyPreset=_=>{Object.assign(e.query,_.query,{page:1})},e.deletePreset=_=>{e.presets=(e.presets||[]).filter(m=>m.name!==_.name),localStorage.setItem(b,JS Line truncated
`).map((ue,de)=>de===0?ue:ie+ue).join(`
`)}else typeof R=="number"||typeof R=="boolean"?J=String(R):J=JSON.stringify(R);ne.push(`${X}${J}${G}`)}),ne.push("}"),ne.join(`
`)}function g(N){let O=[],q="",L=/(\w+):(>=|<=|!=|>|<|=)?([^\s]+)/g,U=0,z;for(;z=L.exec(N);)q+=N.slice(U,z.index),U=L.lastIndex,O.push({key:z[1],op:z[2]||"=",val:z[3]});return q+=N.slice(U),{filters:O,free:q.trim().toLowerCase()}}function y(N,O){for(let q of O.filters){let L=(z,ne,x)=>{let R=parseFloat(z),V=parseFloat(ne);return x==="="?String(z)===String(ne):x==="!="?String(z)!==String(ne):x===">="?R>=V:x==="<="?R<=V:x===">"?R>V:x==="<"?R<V:!0},U;if(q.key==="code")U=N.displayMessage;else if(q.key==="module")U=N.module;else if(q.key==="status")U=N._status;else if(q.key==="url")U=N._url;else if(q.key==="repo")U=N._repoId;else if(q.key==="level")U=N.level;else continue;if(U==null||!L(U,q.val,q.op))return!1}return!(O.free&&((N.displayMessage||"")+" "+(N.module||"")+" "+(N._url||"")+" "+JSON.stringify(N.raw||[])).toLowerCase().indexOf(O.free)===-1)}function b(){let N=g(e.query.search||"");e.parsedFilterCount=N.filters.length;let O=e.query.bucket,q=e.entries.filter(U=>O&&U._bucket!==O?!1:y(U,N)),L=e.query.group;if(L){let U=x=>L==="module"?x.module:x.displayMessage||x.message||"_",z=new Map;for(let x of q){let R=U(x);if(z.has(R)){let V=z.get(R);V.count++,V._related.push(x),new Date(x.ts)>new Date(V.ts)&&(V.ts=x.ts,V._url=x._url,V._status=x._status),new Date(x.ts)<new Date(V._firstSeen)&&(V._firstSeen=x.ts)}else{let V=Object.assign({},x);V._key=`${L}:${R}`,V._related=[x],V._firstSeen=x.ts,V._lastHourCount=0,V.count=1,z.set(R,V)}}let ne=Date.now()-3600*1e3;for(let x of z.values())x._lastHourCount=x._related.filter(R=>new Date(R.ts).getTime()>=ne).length;q=Array.from(z.values())}else q=q.map((U,z)=>(U._key="row:"+z+":"+U.ts,U._related=[U],U._firstSeen=U.ts,U._lastHourCount=0,U.count=1,U));e.query.sort==="count"?q.sort((U,z)=>z.count-U.count||new Date(z.ts)-new Date(U.ts)):q.sort((U,z)=>new Date(z.ts)-new Date(U.ts)),e.visible=q}function h(N){let O=N?e.entries.length:0,q=N?e.pageSize:Math.max(e.pageSize,e.entries.length||e.pageSize);t.get("/api/admin/errors",{params:{offset:O,limit:q}}).then(L=>{let U=(L.data.entries||[]).map(c);e.entries=N?e.entries.concat(U):U,e.available=!!L.data.available,e.cap=L.data.max||e.cap,e.total=L.data.total||e.entries.length,b()},L=>console.error(L))}e.loadMore=()=>h(!0),e.canLoadMore=()=>e.entries.length<e.total;function E(){t.get("/api/admin/errors/stats").then(N=>{let O=N.data||{},q=O.prev24h?Math.round((O.last24h-O.prev24h)/O.prev24h*100):0;e.stats={last24h:O.last24h||0,prev24h:O.prev24h||0,delta:q,severity:O.severity||{error:0,warn:0,info:0},unique:O.unique||{error:0,warn:0,info:0},buckets:O.buckets||[],dropped:O.dropped||0}},N=>console.error(N))}function _(){h(),E()}e.barPx=(N,O)=>{let q=e.stats.buckets||[],L=0;for(let x of q)L=Math.max(L,(x.error||0)+(x.warn||0)+(x.info||0));if(!L)return 0;let U=(N.error||0)+(N.warn||0)+(N.info||0);if(!U)return 0;let z=Math.round(U/L*60),ne=N[O]||0;return Math.round(ne/U*z)},e.bucketTitle=N=>`${new Date(N.hour).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})} \xB7 ${N.error||0} err \xB7 ${N.warn||0} warn \xB7 ${N.info||0} info`,e.toggle=N=>{e.expanded[N._key]=!e.expanded[N._key]},e.setBucket=N=>{e.query.bucket=N},e.refreshNow=_,e.clearAll=()=>{confirm("Clear all captured errors?")&&t.delete("/api/admin/errors").then(_,N=>console.error(N))},e.exportCsv=()=>{let N=["ts","level","module","displayMessage","_status","_url","_repoId"],O=[N.join(",")];for(let z of e.visible)O.push(N.map(ne=>{let x=z[ne]==null?"":String(z[ne]);return/[",\n]/.test(x)?`"${x.replace(/"/g,'""')}"`:x}).join(","));let q=new Blob([O.join(`
`)],{type:"text/csv;charset=utf-8"}),L=URL.createObjectURL(q),U=document.createElement("a");U.href=L,U.download=`errors-${new Date().toISOString().slice(0,19)}.csv`,document.body.appendChild(U),U.click(),document.body.removeChild(U),URL.revokeObjectURL(L)};function m(N){e.copyHint=`${N} copied`,s.timeout(()=>{e.copyHint=""},1500)}e.copyJson=N=>{navigator.clipboard.writeText(N._detailJson).then(()=>m("JSON"))},e.copyCurl=N=>{if(!N._url)return;let q=`curl -X ${N._method||"GET"} '${window.location.origin}${N._url}'`;navigator.clipboard.writeText(q).then(()=>m("curl"))},_();let C=i(()=>{e.query.autoRefresh&&_()},15e3);e.on("dispose",()=>i.cancel(C)),e.watch("query.search",b),e.watch("query.bucket",b),e.watch("query.sort",b),e.watch("query.group",b)},_l=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";var s=!1;e.loadCache=function(){if(!s){s=!0;var m=e.cacheMinutes;t.get("/api/admin/cache",{params:{minutes:m}}).then(function(C){m===e.cacheMinutes&&(e.cacheReport=C.data,e.cacheError=C.data.available?null:C.data.reason||"Cache monitoring is unavailable.")},function(){e.cacheError="Could not refresh cache monitoring. Displayed values may be stale."}).finally(function(){s=!1,m!==e.cacheMinutes&&e.loadCache()})}},e.cacheRows=function(){return(e.cacheReport?.rows||[]).filter(function(m){return e.cacheTraffic==="all"||m.traffic===e.cacheTraffic})},e.cacheRate=function(m,C){var N=e.cacheRows(),O=function(U){return N.filter(function(z){return z.name===U}).reduce(function(z,ne){return z+ne[C]},0)},q=O(m+"_hit"),L=O(m+"_miss");return q+L?(100*q/(q+L)).toFixed(1)+"%":"No samples"},e.cacheEventName=function(m){return m.replaceAll("_"," ")},e.cacheP95=function(m){var C=0,N=e.cacheReport?.latencyBucketsMs||[];if(!m.count)return"No samples";if(!m.ms)return"Not timed";for(var O=0;O<=N.length;O++)if(C+=m["b"+O]||0,C>=Math.ceil(m.count*.95))return O<N.length?"\u2264 "+N[O]+" ms":"> 10 s";return"No samples"},e.performanceError=null,e.formatMs=function(m){return m==null?"":m<1e3?m+" ms":+(m/1e3).toFixed(1)+" s"},e.latencyBound=function(m,C){return m.count?m[C]==null?"> 60 s":"\u2264 "+e.formatMs(m[C]):"No samples"},e.firstByteBound=function(m){return e.latencyBound({count:m.firstByteCount,p95UpperMs:m.firstByteP95UpperMs},"p95UpperMs")},e.sampleAge=function(m){return Math.max(0,Math.round((Date.now()-m.sampledAt)/1e3))},e.peakRss=function(m){return(e.performance.runtimeSeries||[]).filter(function(C){return C.instance===m.instance}).reduce(function(C,N){return Math.max(C,N.rss)},m.memory.rss)},e.performanceWarning=function(m){return e.sampleAge(m)>45||m.droppedBatches||m.droppedMetrics||m.sockets?.closeWait>0||m.eventLoop.p95Ms>100||m.memoryLimitBytes&&m.memory.rss>m.memoryLimitBytes*.8};var r=!1;e.loadPerformance=function(){var m=e.performanceMinutes;e.performance?.windowMinutes&&e.performance.windowMinutes!==m&&(e.performance=null),!r&&(r=!0,t.get("/api/admin/performance",{params:{minutes:m}}).then(function(C){m===e.performanceMinutes&&(e.performance=C.data,e.performanceError=C.data.available?null:"Performance monitoring is unavailable. Request history may be incomplete.")},function(){m===e.performanceMinutes&&(e.performanceError="Could not refresh performance monitoring. Displayed samples may be stale.")}).finally(function(){r=!1,m!==e.performanceMinutes&&e.loadPerformance()}))};function a(m){if(m==null)return"\u2014";for(var C=["B","KB","MB","GB","TB"],N=0,O=m;O>=1024&&N<C.length-1;)O/=1024,N++;return O.toFixed(N>0?1:0)+" "+C[N]}e.humanBytes=a;function c(m){if(!m)return"\u2014";var C=Math.floor(m/86400),N=Math.floor(m%86400/3600),O=Math.floor(m%3600/60);return C>0?C+"d "+(N<10?"0":"")+N+"h":N>0?N+"h "+(O<10?"0":"")+O+"m":O+"m"}e.humanDuration=c;function f(m){return m==null?"\u2014":m>=1e6?(m/1e6).toFixed(1)+"M":m>=1e3?(m/1e3).toFixed(1)+"K":String(m)}e.humanNum=f,e.queueTotal=function(m){return m?(m.waiting||0)+(m.active||0)+(m.delayed||0)+(m.failed||0):0},e.statusCount=function(m){if(!e.data||!e.data.repos)return 0;for(var C=e.data.repos.statusBreakdown||[],N=0;N<C.length;N++)if(C[N]._id===m)return C[N].count;return 0},e.barPct=function(m){var C=e.data&&e.data.repos?e.data.repos.total:0;if(!C)return 0;var N=[m];m==="expired"&&N.push("expiring"),m==="removed"&&N.push("removing"),m==="preparing"&&N.push("download");var O=0;return N.forEach(function(q){O+=e.statusCount(q)}),Math.max(.4,O/C*100)},e.errPct=function(m){if(!e.data||!e.data.errors)return 0;var C=Math.max(e.data.errors.severity.error,e.data.errors.severity.warn,e.data.errors.severity.info,1);return e.data.errors.severity[m]/C*100};function g(m){var C=m||[];return C.map(function(N,O){var q=C[O-1]||{},L=Object.assign({},N);return L.dailyRepositories=O?Math.max(0,(N.nbRepositories||0)-(q.nbRepositories||0)):0,L.dailyUsers=O? Line truncated
anonymous_github`)])])])])]),p(" Limitations "),n("h4",{class:"faq-cat"},[n("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[n("use",{href:"#ui-icon-warning"})]),v("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). ")])])])])]),p(" Privacy & Security "),n("h4",{class:"faq-cat"},[n("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[n("use",{href:"#ui-icon-shield"})]),v("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 \u2014 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,[v("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"),v(" 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. ")])])])]),p(" Self-Hosting "),n("h4",{class:"faq-cat"},[n("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[n("use",{href:"#project-icon-storage"})]),v("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,[v( Line truncated
`)],{type:"text/csv"}),N=document.createElement("a");N.href=URL.createObjectURL(C),N.download=i.username+"-repositories.csv",N.click()},e.showStatusMessage=h=>{let E=h.statusMessage||"(no message)";window.prompt(`Status message for ${h.repoId} (${h.status}):`,E)},e.fetchGithubInfo=h=>{let E=window.open("","_blank");E&&E.document.write("<pre>Loading GitHub info for "+h.repoId+"...</pre>"),t.get("/api/admin/repos/"+h.repoId+"/github").then(_=>{E&&(E.document.open(),E.document.write('<pre style="font:13px monospace;padding:16px;white-space:pre-wrap">'+JSON.stringify(_.data,null,2).replace(/[<>]/g,m=>m==="<"?"&lt;":"&gt;")+"</pre>"),E.document.close())},_=>{let m=_&&_.data?JSON.stringify(_.data,null,2):String(_);E&&(E.document.body.innerHTML='<pre style="color:#B42318;padding:16px">'+m+"</pre>")})};function f(h){t.get("/api/admin/users/"+h+"/repos",{}).then(E=>{e.repositories=E.data},E=>{console.error(E)})}function g(h){t.get("/api/admin/users/"+h,{}).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),h=>console.error(h))},e.activateUser=()=>{t.post(`/api/admin/users/${i.username}/activate`).then(()=>g(i.username),h=>console.error(h))},e.promoteUser=()=>{confirm(`Promote ${i.username} to admin?`)&&t.post(`/api/admin/users/${i.username}/promote`).then(()=>g(i.username),h=>console.error(h))},e.demoteUser=()=>{confirm(`Remove admin privileges from ${i.username}?`)&&t.post(`/api/admin/users/${i.username}/demote`).then(()=>g(i.username),h=>console.error(h))},e.tokens=[],e.tokenForm={name:"",plaintext:null};function y(){t.get("/api/admin/tokens").then(h=>{e.tokens=h.data||[]},h=>{h.status!==401&&h.status!==403&&console.error(h)})}y(),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="",y()},h=>console.error(h))},e.revokeToken=h=>{confirm(`Revoke token "${h.name}"?`)&&t.delete("/api/admin/tokens/"+h.id).then(()=>y(),E=>console.error(E))},e.removeCache=h=>{confirm("Remove cached files for "+h.repoId+"?")&&t.delete("/api/admin/repos/"+h.repoId).then(()=>f(i.username),E=>console.error(E))},e.removeRepository=h=>{confirm("Remove repository "+h.repoId+"?")&&t.delete("/api/repo/"+h.repoId+"/").then(()=>f(i.username),E=>console.error(E))},e.updateRepository=h=>{let E=Fe({title:`Refreshing ${h.repoId}...`,date:new Date,body:`The repository ${h.repoId} is going to be refreshed.`});e.toasts.push(E),t.post(`/api/repo/${h.repoId}/refresh`).then(_=>{_.data.status=="ready"?E.title=`${h.repoId} is refreshed.`:E.title=`Refreshing of ${h.repoId}.`},_=>{E.title=`Error during the refresh of ${h.repoId}.`,E.body=_.body})},e.getGitHubRepositories=h=>{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)},El=function(e,t,o){let i=ut(),s=Zt();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=_=>{if(_.key==="/"&&!["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName)){_.preventDefault();let m=document.querySelector('.admin-filter-toolbar input[type="search"]');m&&m.focus()}};s(document,"keydown",r),e.on("dispose",()=>document.removeEventListener("keydown",r)),e.clearFilter=_=>{_==="dateRange"?(e.query.dateFrom="",e.query.dateTo=""):e.query[_]="",e.query.page=1},e.chips=[];let a=()=>{let _=[];(e.query.dateFrom||e.query.dateTo)&&_.push({key:"dateRange",label:"Date",value:(e.query.dateFrom||"\u2026")+" \u2013 "+(e.query.dateTo||"\u2026")}),e.chips=_};e.statusCountFor=_=>{let m=(e.statusCounts||[]).find(C=>C._id===_);return m?m.count:0},e.toggleSortDirection=()=>{e.query.direction=e.query.direction==="asc"?"desc":"asc"},e.sortBy=_=>{e.query.sort===_?e.query.direction=e.query.direction==="asc"?"desc":"asc":(e.query.sort=_,e.query.direction="desc"),e.query.page=1},e.sortIcon=_=>e.query.sort===_?e.query.direction==="asc"?"fa-arrow-up":"fa-arrow-down":"";let c="admin.conferences.filterPrefs",f={page:1,limit:25,sort:"name",direction:"asc",search:"",dateFrom:"",dateTo:"",ready:!1,expired:!1,removed:!1,error:!0,preparing:!0},g=loadFilterPrefs(c)||{};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 _=window.prompt("Preset name:");if(!_)return;let m=Object.assign({},e.query);delete m.page,e.presets=(e.presets||[]).filter(C=>C.name!==_),e.presets.push({name:_,query:m}),localStorage.setItem(b,JSON.stringify(e.presets))},e.applyPreset=_=>{Object.assign(e.query,_.query,{page:1})},e.deletePreset=_=>{e.presets=(e.presets||[]).filter(m=>m.name!==_.name),localStorage.setItem(b,JS Line truncated
`).map((te,X)=>X===0?te:Q+te).join(`
`)}else typeof R=="number"||typeof R=="boolean"?J=String(R):J=JSON.stringify(R);oe.push(`${ve}${J}${z}`)}),oe.push("}"),oe.join(`
`)}function g(N){let A=[],M="",U=/(\w+):(>=|<=|!=|>|<|=)?([^\s]+)/g,q=0,B;for(;B=U.exec(N);)M+=N.slice(q,B.index),q=U.lastIndex,A.push({key:B[1],op:B[2]||"=",val:B[3]});return M+=N.slice(q),{filters:A,free:M.trim().toLowerCase()}}function y(N,A){for(let M of A.filters){let U=(B,oe,ee)=>{let R=parseFloat(B),j=parseFloat(oe);return ee==="="?String(B)===String(oe):ee==="!="?String(B)!==String(oe):ee===">="?R>=j:ee==="<="?R<=j:ee===">"?R>j:ee==="<"?R<j:!0},q;if(M.key==="code")q=N.displayMessage;else if(M.key==="module")q=N.module;else if(M.key==="status")q=N._status;else if(M.key==="url")q=N._url;else if(M.key==="repo")q=N._repoId;else if(M.key==="level")q=N.level;else continue;if(q==null||!U(q,M.val,M.op))return!1}return!(A.free&&((N.displayMessage||"")+" "+(N.module||"")+" "+(N._url||"")+" "+JSON.stringify(N.raw||[])).toLowerCase().indexOf(A.free)===-1)}function b(){let N=g(e.query.search||"");e.parsedFilterCount=N.filters.length;let A=e.query.bucket,M=e.entries.filter(q=>A&&q._bucket!==A?!1:y(q,N)),U=e.query.group;if(U){let q=ee=>U==="module"?ee.module:ee.displayMessage||ee.message||"_",B=new Map;for(let ee of M){let R=q(ee);if(B.has(R)){let j=B.get(R);j.count++,j._related.push(ee),new Date(ee.ts)>new Date(j.ts)&&(j.ts=ee.ts,j._url=ee._url,j._status=ee._status),new Date(ee.ts)<new Date(j._firstSeen)&&(j._firstSeen=ee.ts)}else{let j=Object.assign({},ee);j._key=`${U}:${R}`,j._related=[ee],j._firstSeen=ee.ts,j._lastHourCount=0,j.count=1,B.set(R,j)}}let oe=Date.now()-3600*1e3;for(let ee of B.values())ee._lastHourCount=ee._related.filter(R=>new Date(R.ts).getTime()>=oe).length;M=Array.from(B.values())}else M=M.map((q,B)=>(q._key="row:"+B+":"+q.ts,q._related=[q],q._firstSeen=q.ts,q._lastHourCount=0,q.count=1,q));e.query.sort==="count"?M.sort((q,B)=>B.count-q.count||new Date(B.ts)-new Date(q.ts)):M.sort((q,B)=>new Date(B.ts)-new Date(q.ts)),e.visible=M}function h(N){let A=N?e.entries.length:0,M=N?e.pageSize:Math.max(e.pageSize,e.entries.length||e.pageSize);t.get("/api/admin/errors",{params:{offset:A,limit:M}}).then(U=>{let q=(U.data.entries||[]).map(c);e.entries=N?e.entries.concat(q):q,e.available=!!U.data.available,e.cap=U.data.max||e.cap,e.total=U.data.total||e.entries.length,b()},U=>console.error(U))}e.loadMore=()=>h(!0),e.canLoadMore=()=>e.entries.length<e.total;function E(){t.get("/api/admin/errors/stats").then(N=>{let A=N.data||{},M=A.prev24h?Math.round((A.last24h-A.prev24h)/A.prev24h*100):0;e.stats={last24h:A.last24h||0,prev24h:A.prev24h||0,delta:M,severity:A.severity||{error:0,warn:0,info:0},unique:A.unique||{error:0,warn:0,info:0},buckets:A.buckets||[],dropped:A.dropped||0}},N=>console.error(N))}function _(){h(),E()}e.barPx=(N,A)=>{let M=e.stats.buckets||[],U=0;for(let ee of M)U=Math.max(U,(ee.error||0)+(ee.warn||0)+(ee.info||0));if(!U)return 0;let q=(N.error||0)+(N.warn||0)+(N.info||0);if(!q)return 0;let B=Math.round(q/U*60),oe=N[A]||0;return Math.round(oe/q*B)},e.bucketTitle=N=>`${new Date(N.hour).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})} \xB7 ${N.error||0} err \xB7 ${N.warn||0} warn \xB7 ${N.info||0} info`,e.toggle=N=>{e.expanded[N._key]=!e.expanded[N._key]},e.setBucket=N=>{e.query.bucket=N},e.refreshNow=_,e.clearAll=()=>{confirm("Clear all captured errors?")&&t.delete("/api/admin/errors").then(_,N=>console.error(N))},e.exportCsv=()=>{let N=["ts","level","module","displayMessage","_status","_url","_repoId"],A=[N.join(",")];for(let B of e.visible)A.push(N.map(oe=>{let ee=B[oe]==null?"":String(B[oe]);return/[",\n]/.test(ee)?`"${ee.replace(/"/g,'""')}"`:ee}).join(","));let M=new Blob([A.join(`
`)],{type:"text/csv;charset=utf-8"}),U=URL.createObjectURL(M),q=document.createElement("a");q.href=U,q.download=`errors-${new Date().toISOString().slice(0,19)}.csv`,document.body.appendChild(q),q.click(),document.body.removeChild(q),URL.revokeObjectURL(U)};function m(N){e.copyHint=`${N} copied`,s.timeout(()=>{e.copyHint=""},1500)}e.copyJson=N=>{navigator.clipboard.writeText(N._detailJson).then(()=>m("JSON"))},e.copyCurl=N=>{if(!N._url)return;let M=`curl -X ${N._method||"GET"} '${window.location.origin}${N._url}'`;navigator.clipboard.writeText(M).then(()=>m("curl"))},_();let C=i(()=>{e.query.autoRefresh&&_()},15e3);e.on("dispose",()=>i.cancel(C)),e.watch("query.search",b),e.watch("query.bucket",b),e.watch("query.sort",b),e.watch("query.group",b)},_l=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";var s=!1;e.loadCache=function(){if(!s){s=!0;var m=e.cacheMinutes;t.get("/api/admin/cache",{params:{minutes:m}}).then(function(C){m===e.cacheMinutes&&(e.cacheReport=C.data,e.cacheError=C.data.available?null:C.data.reason||"Cache monitoring is unavailable.")},function(){e.cacheError="Could not refresh cache monitoring. Displayed values may be stale."}).finally(function(){s=!1,m!==e.cacheMinutes&&e.loadCache()})}},e.cacheRows=function(){return(e.cacheReport?.rows||[]).filter(function(m){return e.cacheTraffic==="all"||m.traffic===e.cacheTraffic})},e.cacheRate=function(m,C){var N=e.cacheRows(),A=function(q){return N.filter(function(B){return B.name===q}).reduce(function(B,oe){return B+oe[C]},0)},M=A(m+"_hit"),U=A(m+"_miss");return M+U?(100*M/(M+U)).toFixed(1)+"%":"No samples"},e.cacheEventName=function(m){return m.replaceAll("_"," ")},e.cacheP95=function(m){var C=0,N=e.cacheReport?.latencyBucketsMs||[];if(!m.count)return"No samples";if(!m.ms)return"Not timed";for(var A=0;A<=N.length;A++)if(C+=m["b"+A]||0,C>=Math.ceil(m.count*.95))return A<N.length?"\u2264 "+N[A]+" ms":"> 10 s";return"No samples"},e.performanceError=null,e.formatMs=function(m){return m==null?"":m<1e3?m+" ms":+(m/1e3).toFixed(1)+" s"},e.latencyBound=function(m,C){return m.count?m[C]==null?"> 60 s":"\u2264 "+e.formatMs(m[C]):"No samples"},e.firstByteBound=function(m){return e.latencyBound({count:m.firstByteCount,p95UpperMs:m.firstByteP95UpperMs},"p95UpperMs")},e.sampleAge=function(m){return Math.max(0,Math.round((Date.now()-m.sampledAt)/1e3))},e.peakRss=function(m){return(e.performance.runtimeSeries||[]).filter(function(C){return C.instance===m.instance}).reduce(function(C,N){return Math.max(C,N.rss)},m.memory.rss)},e.performanceWarning=function(m){return e.sampleAge(m)>45||m.droppedBatches||m.droppedMetrics||m.sockets?.closeWait>0||m.eventLoop.p95Ms>100||m.memoryLimitBytes&&m.memory.rss>m.memoryLimitBytes*.8};var r=!1;e.loadPerformance=function(){var m=e.performanceMinutes;e.performance?.windowMinutes&&e.performance.windowMinutes!==m&&(e.performance=null),!r&&(r=!0,t.get("/api/admin/performance",{params:{minutes:m}}).then(function(C){m===e.performanceMinutes&&(e.performance=C.data,e.performanceError=C.data.available?null:"Performance monitoring is unavailable. Request history may be incomplete.")},function(){m===e.performanceMinutes&&(e.performanceError="Could not refresh performance monitoring. Displayed samples may be stale.")}).finally(function(){r=!1,m!==e.performanceMinutes&&e.loadPerformance()}))};function a(m){if(m==null)return"\u2014";for(var C=["B","KB","MB","GB","TB"],N=0,A=m;A>=1024&&N<C.length-1;)A/=1024,N++;return A.toFixed(N>0?1:0)+" "+C[N]}e.humanBytes=a;function c(m){if(!m)return"\u2014";var C=Math.floor(m/86400),N=Math.floor(m%86400/3600),A=Math.floor(m%3600/60);return C>0?C+"d "+(N<10?"0":"")+N+"h":N>0?N+"h "+(A<10?"0":"")+A+"m":A+"m"}e.humanDuration=c;function f(m){return m==null?"\u2014":m>=1e6?(m/1e6).toFixed(1)+"M":m>=1e3?(m/1e3).toFixed(1)+"K":String(m)}e.humanNum=f,e.queueTotal=function(m){return m?(m.waiting||0)+(m.active||0)+(m.delayed||0)+(m.failed||0):0},e.statusCount=function(m){if(!e.data||!e.data.repos)return 0;for(var C=e.data.repos.statusBreakdown||[],N=0;N<C.length;N++)if(C[N]._id===m)return C[N].count;return 0},e.barPct=function(m){var C=e.data&&e.data.repos?e.data.repos.total:0;if(!C)return 0;var N=[m];m==="expired"&&N.push("expiring"),m==="removed"&&N.push("removing"),m==="preparing"&&N.push("download");var A=0;return N.forEach(function(M){A+=e.statusCount(M)}),Math.max(.4,A/C*100)},e.errPct=function(m){if(!e.data||!e.data.errors)return 0;var C=Math.max(e.data.errors.severity.error,e.data.errors.severity.warn,e.data.errors.severity.info,1);return e.data.errors.severity[m]/C*100};function g(m){var C=m||[];return C.map(function(N,A){var M=C[A-1]||{},U=Object.assign({},N);return U.dailyRepositories=A?Math.max(0,(N.nbRepositories||0)-(M.nbRepositories||0)):0,U.dailyUsers=A? Line truncated
anonymous_github`)])])])])]),p(" Limitations "),n("h4",{class:"faq-cat"},[n("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[n("use",{href:"#ui-icon-warning"})]),v("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). ")])])])])]),p(" Privacy & Security "),n("h4",{class:"faq-cat"},[n("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[n("use",{href:"#ui-icon-shield"})]),v("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 \u2014 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,[v("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"),v(" 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. ")])])])]),p(" Self-Hosting "),n("h4",{class:"faq-cat"},[n("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[n("use",{href:"#project-icon-storage"})]),v("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,[v( 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[18]||(t[18]=n("li",{class:"nav-item d-none d-lg-block"},[n("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"},[n("svg",{class:"ui-icon d-lg-none mr-1","aria-hidden":"true"},[n("use",{href:"#ui-icon-bug"})]),v("Report a bug ")])],-1)),e.isDarkMode?p("v-if",!0):(l(),d("li",G3,[n("a",{class:"nav-link nav-icon",href:"#",title:"Switch to dark mode","aria-label":"Switch to dark mode",role:"button",onClick:t[0]||(t[0]=ae(o=>{e.darkMode(!0)},["prevent"]))},[...t[14]||(t[14]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-moon"})],-1)])])])),e.isDarkMode?(l(),d("li",W3,[n("a",{class:"nav-link nav-icon",href:"#",title:"Switch to light mode","aria-label":"Switch to light mode",role:"button",onClick:t[1]||(t[1]=ae(o=>{e.darkMode(!1)},["prevent"]))},[...t[15]||(t[15]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-sun"})],-1)])])])):p("v-if",!0),!e.user&&!e.isReviewerRoute?(l(),d("li",K3,[...t[16]||(t[16]=[n("a",{class:"nav-link btn-signin",target:"_self",href:"/signin","data-offset":"30"},[n("i",{class:"fab fa-github mr-1"}),v(" Sign in ")],-1)])])):p("v-if",!0),e.user?.username&&e.headerCanUpgrade&&!e.headerBillingPending?(l(),d("li",Y3,[n("a",{class:"nav-link nav-upgrade",href:"/profile?upgrade=1",onClick:t[2]||(t[2]=ae(o=>e.openHeaderUpgrade(),["prevent"]))},"Upgrade")])):p("v-if",!0),e.user?(l(),d("li",J3,[n("a",Q3,[e.user?.photo?(l(),d("img",{key:0,width:"22",height:"22",class:"rounded-circle",src:e.safeUrl(e.user?.photo)},null,8,X3)):p("v-if",!0),n("span",Z3,u(e.user?.username),1)]),n("div",x3,[n("h6",e5,"Signed in as @"+u(e.user?.username),1),t[17]||(t[17]=fe('<a class="dropdown-item" href="/profile"><svg class="ui-icon" aria-hidden="true"><use href="#project-icon-filter"></use></svg><span>Settings<small>Defaults, quotas, account</small></span></a><a class="dropdown-item" href="/connections"><i class="fab fa-github" aria-hidden="true"></i><span>GitHub connections<small>Repository access and OAuth</small></span></a><a class="dropdown-item" href="/claim"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-link"></use></svg><span>Claim an anonymization<small>Attach an existing mirror to your account</small></span></a><div class="dropdown-divider"></div><a class="dropdown-item" href="https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml" target="_blank" rel="noopener"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-bug"></use></svg><span>Report a bug<small>About this service, not a paper</small></span></a><a class="dropdown-item" href="https://github.com/tdurieux/anonymous_github/" target="_blank" rel="noopener"><i class="fab fa-github" aria-hidden="true"></i><span>Source code</span></a><a class="dropdown-item" href="https://ko-fi.com/tdurieux" target="_blank" rel="noopener"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-heart"></use></svg><span>Support the project</span></a><div class="dropdown-divider"></div><a class="dropdown-item" href="/api/user/logout" target="_self"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-logout"></use></svg><span>Sign out</span></a>',9))])])):p("v-if",!0)])])],2),e.generalMessage?(l(),d("div",{key:0,class:"navbar shadow generalMessage",innerHTML:e.sanitize(e.generalMessage)},null,8,t5)):p("v-if",!0),e.emailPromptOpen?(l(),d("dialog",{key:1,id:"email-prompt",class:"email-prompt","aria-labelledby":"email-prompt-title","aria-describedby":"email-prompt-reason",onCancel:t[7]||(t[7]=ae(o=>e.respondToEmailPrompt("later"),["prevent"]))},[n("form",{onSubmit:t[6]||(t[6]=ae(o=>e.respondToEmailPrompt("save"),["prevent"]))},[t[20]||(t[20]=n("h2",{id:"email-prompt-title"},"Stay informed about access problems",-1)),t[21]||(t[21]=n("p",{id:"email-prompt-reason"},"Get email alerts when your GitHub token or repository access fails.",-1)),t[22]||(t[22]=n("label",{for:"email-prompt-address"},"Email address",-1)),D(n("input",{id:"email-prompt-address",class:"form-control",type:"email",autocomplete:"email",maxlength:"254",required:"","onUpdate:modelValue":t[3]||(t[3]=o=>e.emailPromptAddress=o),disabled:e.emailPromptBusy},null,8,n5),[[wt,e.emailPromptAddress]]),e.emailPromptError?(l(),d("p",o5,u(e.emailPromptError),1)):p("v-if",!0),n("div",s5,[n("button",{type:"button",class:"btn btn-outline-ink",disabled:e.emailPromptBusy,onClick:t[4]||(t[4]=o=>e.respondToEmailPrompt("later"))},"Remind me later",8,i5),n("button",{type:"button",class:"btn btn-outline-ink",disabled:e.emailPromptBusy,onClick:t[5]||(t[5]=o=>e.respondToEmailPrompt("never"))},"Never",8,r5),n("button",{type:"submit",class:"btn btn-ink",disabled:e.emailPromptBusy},u(e.emailPromptBusy?"Saving\u2026":"Save"),9,a5)]) Line truncated
label names the service and the tooltip says who to contact. `),t[18]||(t[18]=n("li",{class:"nav-item d-none d-lg-block"},[n("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"},[n("svg",{class:"ui-icon d-lg-none mr-1","aria-hidden":"true"},[n("use",{href:"#ui-icon-bug"})]),v("Report a bug ")])],-1)),e.isDarkMode?p("v-if",!0):(l(),d("li",G3,[n("a",{class:"nav-link nav-icon",href:"#",title:"Switch to dark mode","aria-label":"Switch to dark mode",role:"button",onClick:t[0]||(t[0]=de(o=>{e.darkMode(!0)},["prevent"]))},[...t[14]||(t[14]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-moon"})],-1)])])])),e.isDarkMode?(l(),d("li",W3,[n("a",{class:"nav-link nav-icon",href:"#",title:"Switch to light mode","aria-label":"Switch to light mode",role:"button",onClick:t[1]||(t[1]=de(o=>{e.darkMode(!1)},["prevent"]))},[...t[15]||(t[15]=[n("svg",{class:"ui-icon","aria-hidden":"true"},[n("use",{href:"#ui-icon-sun"})],-1)])])])):p("v-if",!0),!e.user&&!e.isReviewerRoute?(l(),d("li",K3,[...t[16]||(t[16]=[n("a",{class:"nav-link btn-signin",target:"_self",href:"/signin","data-offset":"30"},[n("i",{class:"fab fa-github mr-1"}),v(" Sign in ")],-1)])])):p("v-if",!0),e.user?.username&&e.headerCanUpgrade&&!e.headerBillingPending?(l(),d("li",Y3,[n("a",{class:"nav-link nav-upgrade",href:"/profile?upgrade=1",onClick:t[2]||(t[2]=de(o=>e.openHeaderUpgrade(),["prevent"]))},"Upgrade")])):p("v-if",!0),e.user?(l(),d("li",J3,[n("a",Q3,[e.user?.photo?(l(),d("img",{key:0,width:"22",height:"22",class:"rounded-circle",src:e.safeUrl(e.user?.photo)},null,8,X3)):p("v-if",!0),n("span",Z3,u(e.user?.username),1)]),n("div",x3,[n("h6",e5,"Signed in as @"+u(e.user?.username),1),t[17]||(t[17]=fe('<a class="dropdown-item" href="/profile"><svg class="ui-icon" aria-hidden="true"><use href="#project-icon-filter"></use></svg><span>Settings<small>Defaults, quotas, account</small></span></a><a class="dropdown-item" href="/connections"><i class="fab fa-github" aria-hidden="true"></i><span>GitHub connections<small>Repository access and OAuth</small></span></a><a class="dropdown-item" href="/claim"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-link"></use></svg><span>Claim an anonymization<small>Attach an existing mirror to your account</small></span></a><div class="dropdown-divider"></div><a class="dropdown-item" href="https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml" target="_blank" rel="noopener"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-bug"></use></svg><span>Report a bug<small>About this service, not a paper</small></span></a><a class="dropdown-item" href="https://github.com/tdurieux/anonymous_github/" target="_blank" rel="noopener"><i class="fab fa-github" aria-hidden="true"></i><span>Source code</span></a><a class="dropdown-item" href="https://ko-fi.com/tdurieux" target="_blank" rel="noopener"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-heart"></use></svg><span>Support the project</span></a><div class="dropdown-divider"></div><a class="dropdown-item" href="/api/user/logout" target="_self"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-logout"></use></svg><span>Sign out</span></a>',9))])])):p("v-if",!0)])])],2),e.generalMessage?(l(),d("div",{key:0,class:"navbar shadow generalMessage",innerHTML:e.sanitize(e.generalMessage)},null,8,t5)):p("v-if",!0),e.emailPromptOpen?(l(),d("dialog",{key:1,id:"email-prompt",class:"email-prompt","aria-labelledby":"email-prompt-title","aria-describedby":"email-prompt-reason",onCancel:t[7]||(t[7]=de(o=>e.respondToEmailPrompt("later"),["prevent"]))},[n("form",{onSubmit:t[6]||(t[6]=de(o=>e.respondToEmailPrompt("save"),["prevent"]))},[t[20]||(t[20]=n("h2",{id:"email-prompt-title"},"Stay informed about access problems",-1)),t[21]||(t[21]=n("p",{id:"email-prompt-reason"},"Get email alerts when your GitHub token or repository access fails.",-1)),t[22]||(t[22]=n("label",{for:"email-prompt-address"},"Email address",-1)),D(n("input",{id:"email-prompt-address",class:"form-control",type:"email",autocomplete:"email",maxlength:"254",required:"","onUpdate:modelValue":t[3]||(t[3]=o=>e.emailPromptAddress=o),disabled:e.emailPromptBusy},null,8,n5),[[wt,e.emailPromptAddress]]),e.emailPromptError?(l(),d("p",o5,u(e.emailPromptError),1)):p("v-if",!0),n("div",s5,[n("button",{type:"button",class:"btn btn-outline-ink",disabled:e.emailPromptBusy,onClick:t[4]||(t[4]=o=>e.respondToEmailPrompt("later"))},"Remind me later",8,i5),n("button",{type:"button",class:"btn btn-outline-ink",disabled:e.emailPromptBusy,onClick:t[5]||(t[5]=o=>e.respondToEmailPrompt("never"))},"Never",8,r5),n("button",{type:"submit",class:"btn btn-ink",disabled:e.emailPromptBusy},u(e.emailPromptBusy?"Saving\u2026":"Save"),9,a5)]) Line truncated
MIT CSAIL
jane.smith@example.org`},I8={class:"settings-syntax"},V8={class:"invalid-feedback"},q8={class:"settings-row"},M8={class:"settings-checks"},U8={class:"settings-check"},$8={class:"form-check-input",type:"checkbox",id:"link",name:"link"},L8={class:"settings-check"},F8={class:"form-check-input",type:"checkbox",id:"notebook",name:"notebook"},B8={class:"settings-check"},H8={class:"form-check-input",type:"checkbox",id:"image",name:"image"},z8={class:"settings-check"},j8={class:"form-check-input",type:"checkbox",id:"pdf",name:"pdf"},G8={class:"settings-check"},W8={class:"form-check-input",type:"checkbox",id:"loc",name:"loc"},K8={class:"settings-check"},Y8={class:"form-check-input",type:"checkbox",id:"page",name:"page"},J8={class:"settings-row"},Q8={class:"settings-check"},X8={class:"form-check-input",type:"checkbox",id:"update",name:"update"},Z8={class:"settings-row"},x8={class:"form-control",id:"expiration",name:"expiration"},eM={class:"settings-help"},tM={class:"settings-save"},nM={class:"settings-save-status draft-status",role:"status"},oM={key:0},sM={key:1},iM={key:2},rM=["disabled"],aM={key:1,class:"settings-save-error",role:"alert"},lM=["aria-busy"],dM={key:0,role:"status"},uM={key:1,class:"settings-notice",role:"alert"},cM=["disabled"],pM={key:2,class:"settings-notice",role:"status"},fM={key:3,class:"settings-notice",role:"status"},hM=["disabled"],mM={class:"settings-row"},vM={class:"settings-inline"},gM={key:0,class:"settings-help"},yM={key:0,class:"settings-help"},bM={id:"settings-quota"},wM={key:1,role:"status"},kM={key:1,class:"settings-notice"},EM={key:2,class:"settings-notice"},CM={key:3,class:"settings-notice"},SM={key:4,class:"settings-help"},_M={key:5,class:"settings-plan billing-plan"},NM={class:"settings-comparison"},RM={class:"settings-cycles"},DM=["checked","onChange"],TM={class:"settings-help"},AM={class:"settings-actions"},OM=["disabled"],PM={key:6,class:"settings-help"},IM={class:"settings-row"},VM={key:0,class:"settings-inline"},qM=["disabled"],MM={key:1,class:"settings-help"},UM=["disabled"],$M={key:4,class:"settings-row"},LM={class:"settings-inline"},FM=["disabled"],BM={key:0,class:"settings-pass"},HM={class:"settings-help"},zM=["disabled"],jM={key:5,class:"settings-row"},GM={class:"settings-help"},WM={id:"settings-account",class:"settings-account-panel"},KM={class:"paper-account-card"},YM=["src"],JM={class:"paper-account-identity"},QM={class:"paper-account-name"},XM=["disabled"],ZM={key:0,role:"status"},xM={key:1,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},e6=["disabled"],t6={key:3,role:"status"},n6={class:"paper-danger-zone"},o6={key:0,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},s6=["textContent"],i6=["disabled"],r6={key:1,class:"settings-delete-confirm"},a6={for:"delete-username"},l6={class:"settings-actions"},d6=["disabled"],u6=["disabled"];function xl(e,t){let o=Ge("quota-usage"),i=ge("field"),s=ge("form");return l(),d("div",N8,[n("header",R8,[t[20]||(t[20]=n("h1",null,"Settings",-1)),n("div",D8,[n("span",null,"@"+u(e.user?.username),1)])]),n("nav",T8,[(l(),d(K,null,te([{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,A8)),64))]),D(n("div",null,[t[41]||(t[41]=n("p",{class:"settings-scope"},"For new anonymizations only. Existing repositories keep their settings.",-1)),D((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",O8,[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,[D(n("textarea",P8,null,512),[[i,{state:e.viewState,set:r=>{e.terms=r},value:e.terms,form:"defaultsForm",options:{debounce:250}}]]),n("details",I8,[t[25]||(t[25]=n("summary",null,"Regex & replacement syntax",-1)),n("p",null,[t[21]||(t[21]=v("Matches become ",-1)),n("code",null,u(e.site_options?.ANONYMIZATION_MASK||"XXX")+"-[N]",1),t[22]||(t[22]=v(". Use ",-1)),t[23]||(t[23]=n("code",null,"term=>replacement",-1)),t[24]||(t[24]=v(" for a custom replacement. Regex is supported.",-1))])]),D(n("div",V8,"Terms are in an invalid format.",512),[[W,e.defaultsForm?.terms?.errors?.format]])])]),n("section",q8,[t[35]||(t[35]=n("h2",null,"Reviewer display",-1)),n("div",null,[n("div",M8,[n("label",U8,[D(n("input",$8,null,512),[[i,{state:e.viewState,set:r=>{e.options.link=r},value:e.options?.link,form:"defaultsForm",options:{}}]]),t[27]||(t[27]=v("Keep links",-1))]),n("label",L8,[D(n("input",F8,null,512),[[i,{state:e.viewState,set:r=>{e.options.notebook=r},value:e.options?.notebook,form:"defaultsForm",options:{}}]]),t[28]||(t[28]=v("Render notebooks",-1))]),n("label",B8,[D(n("input",H8,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 h=y[b];if(h.startsWith("diff --git")){g(),f();continue}if(h.startsWith("--- ")){r&&r.lines.length&&g(),f().oldPath=h.replace(/^--- (a\/)?/,"").trim();continue}if(h.startsWith("+++ ")){f().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 E=h.match(/@@\s+-(\d+)(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/);E&&(a=parseInt(E[1],10),c=parseInt(E[2],10)),f().lines.push({kind:"hunk",oldNo:"",newNo:"",text:h});continue}r&&(h.startsWith("+")?(r.lines.push({kind:"add",oldNo:"",newNo:c,text:h.slice(1)}),c++):h.startsWith("-")?(r.lines.push({kind:"remove",oldNo:a,newNo:"",text:h.slice(1)}),a++):(r.lines.push({kind:"ctx",oldNo:a,newNo:c,text:h.startsWith(" ")?h.slice(1):h}),a++,c++))}}return o(s,r),s.join("")}})({trustAsHtml:e=>e});function OU(e,t){return e==null?"":Number(e).toLocaleString(void 0,t==null?{}:{minimumFractionDigits:t,maximumFractionDigits:t})}function PU(e){return String(e??"").toUpperCase()}function IU(e,t,o=0){return(e||[]).slice(o,o+t)}function VU(e,t){return Array.isArray(e)?typeof t=="function"?e.filter(t):e:[]}function qU(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 c=r.split(".").reduce((g,y)=>g?.[y],i),f=r.split(".").reduce((g,y)=>g?.[y],s);if(typeof c=="string"&&(c=c.toLowerCase()),typeof f=="string"&&(f=f.toLowerCase()),c!==f)return(c==null?-1:f==null?1:c<f?-1:1)*a}return 0})}function MU(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 UU(e,t){return(t?.[e]??t?.[e===1?"one":"other"]??"").replace(/\{\}/g,e??0)}var ad={name:"htmlDoc",props:["content","baseUrl","allowScripts"],setup(e){let t=et(null);return Lt(()=>{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 c=["allow-popups","allow-popups-to-escape-sandbox"];e.allowScripts&&c.push("allow-scripts","allow-forms","allow-modals"),a.setAttribute("sandbox",c.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}He(()=>e.content,s,{immediate:!0}),He(()=>e.baseUrl,s,{immediate:!0}),He(()=>e.allowScripts,s,{immediate:!0})}),()=>be("html-doc",{ref:t})}};var ld={name:"pdfviewer",props:["src"],setup(e){let t=et(null);return Lt(()=>{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 c=null,f=[],g=!1,y=null,b=1,h=1,E=0,_=0,m=612/792,C=0,N=null,O=new Map,q=0;function L(k){let S=O.get(k);S&&(S.cancelled=!0,S.task?.cancel?.(),O.delete(k));let M=k.querySelector("canvas");M&&(M.width=0,M.height=0),k.innerHTML="",delete k.dataset.state}let U=document.createElement("div");U.className="pdf-toolbar";let z=document.createElement("div");z.className="pdf-pages",z.tabIndex=0,z.setAttribute("aria-label","PDF pages"),a.appendChild(U),a.appendChild(z);function ne(k,S,M){let j=document.createElement("button");return j.type="button",j.className="pdf-toolbar-btn",j.title=S,j.setAttribute("aria-label",S),j.innerHTML='<i class="fas '+k+'"></i>',j.addEventListener("click",M),j}let x=ne("fa-chevron-up","Previous page",function(){Ve(h-1)}),R=ne("fa-chevron-down","Next page",function(){Ve(h+1)}),V=document.createElement("input");V.type="text",V.className="pdf-toolbar-page",V.setAttribute("aria-label","Page number"),V.title="Page number \u2014 type a page and press Enter",V.addEventListener("keydown",function(k){k.key==="Enter"&&(Ve(parseInt(V.value,10)),V.blur())}),V.addEventListener("blur",function(){V.value=String(h)});let Y=document.createElement("span");Y.className="pdf-toolbar-count";let X=ne("fa-search-minus","Zoom out",function(){oe(s[Math.max(0,de()-1)])}),G=ne("fa-search-plus","Zoom in",function(){oe(s[Math.min(s.length-1,de()+1)])}),J=document.createElement("button");J.type="button",J.className="pdf-toolbar-btn pdf-toolbar-zoom",J.title="Reset zoom to fit the width",J.setAttribute("aria-label","Reset zoom to fit the width"),J.addEventListener("click",function(){oe(1)}),U.appendChild(x),U.appendChild(R);let ie=document.createElement("span");ie.className="pdf-toolbar-group",ie.appendChild(V),ie. Line truncated
jane.smith@example.org`},I8={class:"settings-syntax"},V8={class:"invalid-feedback"},q8={class:"settings-row"},M8={class:"settings-checks"},U8={class:"settings-check"},$8={class:"form-check-input",type:"checkbox",id:"link",name:"link"},L8={class:"settings-check"},F8={class:"form-check-input",type:"checkbox",id:"notebook",name:"notebook"},B8={class:"settings-check"},H8={class:"form-check-input",type:"checkbox",id:"image",name:"image"},z8={class:"settings-check"},j8={class:"form-check-input",type:"checkbox",id:"pdf",name:"pdf"},G8={class:"settings-check"},W8={class:"form-check-input",type:"checkbox",id:"loc",name:"loc"},K8={class:"settings-check"},Y8={class:"form-check-input",type:"checkbox",id:"page",name:"page"},J8={class:"settings-row"},Q8={class:"settings-check"},X8={class:"form-check-input",type:"checkbox",id:"update",name:"update"},Z8={class:"settings-row"},x8={class:"form-control",id:"expiration",name:"expiration"},eM={class:"settings-help"},tM={class:"settings-save"},nM={class:"settings-save-status draft-status",role:"status"},oM={key:0},sM={key:1},iM={key:2},rM=["disabled"],aM={key:1,class:"settings-save-error",role:"alert"},lM=["aria-busy"],dM={key:0,role:"status"},uM={key:1,class:"settings-notice",role:"alert"},cM=["disabled"],pM={key:2,class:"settings-notice",role:"status"},fM={key:3,class:"settings-notice",role:"status"},hM=["disabled"],mM={class:"settings-row"},vM={class:"settings-inline"},gM={key:0,class:"settings-help"},yM={key:0,class:"settings-help"},bM={id:"settings-quota"},wM={key:1,role:"status"},kM={key:1,class:"settings-notice"},EM={key:2,class:"settings-notice"},CM={key:3,class:"settings-notice"},SM={key:4,class:"settings-help"},_M={key:5,class:"settings-plan billing-plan"},NM={class:"settings-comparison"},RM={class:"settings-cycles"},DM=["checked","onChange"],TM={class:"settings-help"},AM={class:"settings-actions"},OM=["disabled"],PM={key:6,class:"settings-help"},IM={class:"settings-row"},VM={key:0,class:"settings-inline"},qM=["disabled"],MM={key:1,class:"settings-help"},UM=["disabled"],$M={key:4,class:"settings-row"},LM={class:"settings-inline"},FM=["disabled"],BM={key:0,class:"settings-pass"},HM={class:"settings-help"},zM=["disabled"],jM={key:5,class:"settings-row"},GM={class:"settings-help"},WM={id:"settings-account",class:"settings-account-panel"},KM={class:"paper-account-card"},YM=["src"],JM={class:"paper-account-identity"},QM={class:"paper-account-name"},XM=["disabled"],ZM={key:0,role:"status"},xM={key:1,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},e6=["disabled"],t6={key:3,role:"status"},n6={class:"paper-danger-zone"},o6={key:0,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},s6=["textContent"],i6=["disabled"],r6={key:1,class:"settings-delete-confirm"},a6={for:"delete-username"},l6={class:"settings-actions"},d6=["disabled"],u6=["disabled"];function xl(e,t){let o=Ge("quota-usage"),i=ge("field"),s=ge("form");return l(),d("div",N8,[n("header",R8,[t[20]||(t[20]=n("h1",null,"Settings",-1)),n("div",D8,[n("span",null,"@"+u(e.user?.username),1)])]),n("nav",T8,[(l(),d(K,null,ne([{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,A8)),64))]),D(n("div",null,[t[41]||(t[41]=n("p",{class:"settings-scope"},"For new anonymizations only. Existing repositories keep their settings.",-1)),D((l(),d("form",{class:"form needs-validation",name:"defaultsForm",novalidate:"",onSubmit:t[1]||(t[1]=de(r=>e.submitForm(r,()=>{e.saveDefault(r)}),["prevent"]))},[n("section",O8,[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,[D(n("textarea",P8,null,512),[[i,{state:e.viewState,set:r=>{e.terms=r},value:e.terms,form:"defaultsForm",options:{debounce:250}}]]),n("details",I8,[t[25]||(t[25]=n("summary",null,"Regex & replacement syntax",-1)),n("p",null,[t[21]||(t[21]=v("Matches become ",-1)),n("code",null,u(e.site_options?.ANONYMIZATION_MASK||"XXX")+"-[N]",1),t[22]||(t[22]=v(". Use ",-1)),t[23]||(t[23]=n("code",null,"term=>replacement",-1)),t[24]||(t[24]=v(" for a custom replacement. Regex is supported.",-1))])]),D(n("div",V8,"Terms are in an invalid format.",512),[[W,e.defaultsForm?.terms?.errors?.format]])])]),n("section",q8,[t[35]||(t[35]=n("h2",null,"Reviewer display",-1)),n("div",null,[n("div",M8,[n("label",U8,[D(n("input",$8,null,512),[[i,{state:e.viewState,set:r=>{e.options.link=r},value:e.options?.link,form:"defaultsForm",options:{}}]]),t[27]||(t[27]=v("Keep links",-1))]),n("label",L8,[D(n("input",F8,null,512),[[i,{state:e.viewState,set:r=>{e.options.notebook=r},value:e.options?.notebook,form:"defaultsForm",options:{}}]]),t[28]||(t[28]=v("Render notebooks",-1))]),n("label",B8,[D(n("input",H8,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 h=y[b];if(h.startsWith("diff --git")){g(),f();continue}if(h.startsWith("--- ")){r&&r.lines.length&&g(),f().oldPath=h.replace(/^--- (a\/)?/,"").trim();continue}if(h.startsWith("+++ ")){f().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 E=h.match(/@@\s+-(\d+)(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/);E&&(a=parseInt(E[1],10),c=parseInt(E[2],10)),f().lines.push({kind:"hunk",oldNo:"",newNo:"",text:h});continue}r&&(h.startsWith("+")?(r.lines.push({kind:"add",oldNo:"",newNo:c,text:h.slice(1)}),c++):h.startsWith("-")?(r.lines.push({kind:"remove",oldNo:a,newNo:"",text:h.slice(1)}),a++):(r.lines.push({kind:"ctx",oldNo:a,newNo:c,text:h.startsWith(" ")?h.slice(1):h}),a++,c++))}}return o(s,r),s.join("")}})({trustAsHtml:e=>e});function OU(e,t){return e==null?"":Number(e).toLocaleString(void 0,t==null?{}:{minimumFractionDigits:t,maximumFractionDigits:t})}function PU(e){return String(e??"").toUpperCase()}function IU(e,t,o=0){return(e||[]).slice(o,o+t)}function VU(e,t){return Array.isArray(e)?typeof t=="function"?e.filter(t):e:[]}function qU(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 c=r.split(".").reduce((g,y)=>g?.[y],i),f=r.split(".").reduce((g,y)=>g?.[y],s);if(typeof c=="string"&&(c=c.toLowerCase()),typeof f=="string"&&(f=f.toLowerCase()),c!==f)return(c==null?-1:f==null?1:c<f?-1:1)*a}return 0})}function MU(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 UU(e,t){return(t?.[e]??t?.[e===1?"one":"other"]??"").replace(/\{\}/g,e??0)}var ad={name:"htmlDoc",props:["content","baseUrl","allowScripts"],setup(e){let t=et(null);return Lt(()=>{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 c=["allow-popups","allow-popups-to-escape-sandbox"];e.allowScripts&&c.push("allow-scripts","allow-forms","allow-modals"),a.setAttribute("sandbox",c.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}Be(()=>e.content,s,{immediate:!0}),Be(()=>e.baseUrl,s,{immediate:!0}),Be(()=>e.allowScripts,s,{immediate:!0})}),()=>we("html-doc",{ref:t})}};var ld={name:"pdfviewer",props:["src"],setup(e){let t=et(null);return Lt(()=>{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 c=null,f=[],g=!1,y=null,b=1,h=1,E=0,_=0,m=612/792,C=0,N=null,A=new Map,M=0;function U(k){let S=A.get(k);S&&(S.cancelled=!0,S.task?.cancel?.(),A.delete(k));let V=k.querySelector("canvas");V&&(V.width=0,V.height=0),k.innerHTML="",delete k.dataset.state}let q=document.createElement("div");q.className="pdf-toolbar";let B=document.createElement("div");B.className="pdf-pages",B.tabIndex=0,B.setAttribute("aria-label","PDF pages"),a.appendChild(q),a.appendChild(B);function oe(k,S,V){let G=document.createElement("button");return G.type="button",G.className="pdf-toolbar-btn",G.title=S,G.setAttribute("aria-label",S),G.innerHTML='<i class="fas '+k+'"></i>',G.addEventListener("click",V),G}let ee=oe("fa-chevron-up","Previous page",function(){Te(h-1)}),R=oe("fa-chevron-down","Next page",function(){Te(h+1)}),j=document.createElement("input");j.type="text",j.className="pdf-toolbar-page",j.setAttribute("aria-label","Page number"),j.title="Page number \u2014 type a page and press Enter",j.addEventListener("keydown",function(k){k.key==="Enter"&&(Te(parseInt(j.value,10)),j.blur())}),j.addEventListener("blur",function(){j.value=String(h)});let ie=document.createElement("span");ie.className="pdf-toolbar-count";let ve=oe("fa-search-minus","Zoom out",function(){Z(s[Math.max(0,X()-1)])}),z=oe("fa-search-plus","Zoom in",function(){Z(s[Math.min(s.length-1,X()+1)])}),J=document.createElement("button");J.type="button",J.className="pdf-toolbar-btn pdf-toolbar-zoom",J.title="Reset zoom to fit the width",J.setAttribute("aria-label","Reset zoom to fit the width"),J.addEventListener("click",function(){Z(1)}),q.appendChild(ee),q.appendChild(R);let Q=document.createElement("span");Q.className="pdf-toolbar-group",Q.appendChild(j),Q.appe Line truncated
/*! Bundled license information:
@vue/shared/dist/shared.esm-bundler.js:
+3
View File
@@ -98,6 +98,8 @@ interface Config {
*/
TRUST_PROXY: string;
RATE_LIMIT: number;
/** Website requests per visitor per 15 minutes, independent of the API. */
WEBSITE_RATE_LIMIT: number;
}
const config: Config = {
BILLING_ENABLED: false,
@@ -171,6 +173,7 @@ const config: Config = {
// entries. Set a plain number to restore the legacy hop-count behavior.
TRUST_PROXY: "loopback,uniquelocal,cloudflare",
RATE_LIMIT: 350,
WEBSITE_RATE_LIMIT: 2000,
APP_HOSTNAME: "anonymous.4open.science",
DB_USERNAME: "admin",
DB_PASSWORD: "password",
+52
View File
@@ -0,0 +1,52 @@
import Repository from "./Repository";
import AnonymizedFile from "./AnonymizedFile";
import AnonymousError from "./AnonymousError";
import FileModel from "./model/files/files.model";
import { FILE_LISTING_LIMIT } from "./file-tree";
import { anonymizePathCompiled, compileTerms } from "./anonymize-utils";
/** Only return the current folder and its immediate children, never a whole tree. */
export async function folderCounts(repo: Repository, requestedPath: unknown): Promise<Record<string, number>> {
if (typeof requestedPath !== "string" || requestedPath.length > 4096 ||
requestedPath.split("/").some(part => part === "." || part === "..") ||
(requestedPath !== "" && (requestedPath.startsWith("/") || requestedPath.endsWith("/")))) {
throw new AnonymousError("invalid_path", { httpStatus: 400 });
}
let originalPath = "";
if (requestedPath) {
// Use the same collision resolution as browsing that anonymized directory.
const directory = await new AnonymizedFile({ repository: repo, anonymizedPath: requestedPath }).getFileInfo();
if (directory.size != null) throw new AnonymousError("folder_not_supported", { httpStatus: 404 });
originalPath = [directory.path, directory.name].filter(Boolean).join("/");
}
const prefix = originalPath ? originalPath + "/" : "";
const escapedPrefix = prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const prefixLength = Array.from(prefix).length;
const rows = await FileModel.aggregate<{ _id: string; count: number }>([
{ $match: {
repoId: repo.repoId,
treeGeneration: repo.model.treeGeneration || { $exists: false },
size: { $ne: null },
...(originalPath ? { $or: [{ path: originalPath }, { path: { $regex: "^" + escapedPrefix } }] } : {}),
} },
{ $project: { child: { $cond: [
{ $eq: ["$path", originalPath] }, "",
{ $arrayElemAt: [{ $split: [{ $substrCP: ["$path", prefixLength,
{ $subtract: [{ $strLenCP: "$path" }, prefixLength] }] }, "/"] }, 0] },
] } } },
{ $group: { _id: "$child", count: { $sum: 1 } } },
{ $limit: FILE_LISTING_LIMIT + 1 },
]).option({ maxTimeMS: 2000, allowDiskUse: true }).exec();
if (rows.length > FILE_LISTING_LIMIT) throw new AnonymousError("file_listing_too_large", { httpStatus: 413 });
const counts: Record<string, number> = Object.create(null);
const compiled = compileTerms(repo.options.terms || []);
let total = 0;
for (const row of rows) {
total += row.count;
if (!row._id) continue;
const anonymousPath = anonymizePathCompiled(prefix + row._id, compiled);
counts[anonymousPath] = (counts[anonymousPath] || 0) + row.count;
}
counts[requestedPath] = total;
return counts;
}
+6 -1
View File
@@ -43,6 +43,7 @@ import { getUser } from "./routes/route-utils";
import config from "../config";
import { resolveTrustProxy } from "./trustProxy";
import { requestRateLimitKey } from "./rate-limit-key";
import { createWebsiteRateLimiter } from "./website-rate-limit";
import { createLogger, serializeError } from "../core/logger";
import { serverOptions } from "./server-options";
import { monitorRequests } from "../core/request-monitoring";
@@ -238,6 +239,10 @@ export default async function start() {
maxDelayMs: 5000,
keyGenerator: apiRateKey,
});
const websiteRate = createWebsiteRateLimiter(new RedisStore({
prefix: "website-rate:",
sendCommand: (...args: string[]) => redisClient.sendCommand(args),
}));
app.use("/github", rate, speedLimiter, githubAppRouter);
app.use("/github", rate, speedLimiter, connectionRouter);
@@ -288,7 +293,7 @@ export default async function start() {
});
// web view
app.use("/w/", rate, webViewSpeedLimiter, router.webview);
app.use("/w/", websiteRate, webViewSpeedLimiter, router.webview);
// Hashed assets (e.g. core.a1b2c3d4e5.min.js) — immutable, cache for 1 year.
// Strip the hash from the filename and serve the underlying file.
+3
View File
@@ -1,4 +1,5 @@
import { FILE_LISTING_LIMIT } from "../../core/file-tree";
import { folderCounts as scopedFolderCounts } from "../../core/folder-counts";
import { repositoryFailureStatus } from "../../core/repository-failure-status";
import { anonymizePath } from "../../core/anonymize-utils";
import * as express from "express";
@@ -214,6 +215,8 @@ router.get(
const repo = await getRepo(req, res);
if (!repo) return;
try {
if (req.query?.path !== undefined) return res.json(await scopedFolderCounts(repo, req.query.path));
// Retain the guarded legacy response for clients requesting all counts.
const repoId = repo.repoId;
const results = await FileModel.aggregate([
{ $match: { repoId, treeGeneration: repo.model.treeGeneration || { $exists: false }, size: { $ne: null } } },
+20
View File
@@ -0,0 +1,20 @@
import rateLimit, { Store } from "express-rate-limit";
import config from "../config";
import { requestRateLimitKey } from "./rate-limit-key";
import { sendRequestRateLimit } from "./request-rate-limit";
/** A page's images and scripts must not consume its visitor's API budget. */
export function createWebsiteRateLimiter(store?: Store) {
if (!Number.isSafeInteger(config.WEBSITE_RATE_LIMIT) || config.WEBSITE_RATE_LIMIT <= 0) {
throw new Error("WEBSITE_RATE_LIMIT must be a positive integer");
}
return rateLimit({
windowMs: 15 * 60_000,
limit: config.WEBSITE_RATE_LIMIT,
keyGenerator: requestRateLimitKey,
standardHeaders: "draft-6",
legacyHeaders: false,
handler: sendRequestRateLimit,
...(store ? { store } : {}),
});
}
+100
View File
@@ -0,0 +1,100 @@
const { expect } = require("chai");
require("ts-node/register/transpile-only");
const mongoose = require("mongoose");
const db = require("../src/server/database");
const Repository = require("../src/core/Repository").default;
const Repo = require("../src/core/model/anonymizedRepositories/anonymizedRepositories.model").default;
const File = require("../src/core/model/files/files.model").default;
const Path = require("../src/core/model/anonymized-path").default;
const { folderCounts } = require("../src/core/folder-counts");
const { FILE_LISTING_LIMIT } = require("../src/core/file-tree");
const uri = process.env.PERFORMANCE_MONGO_URI;
describe("folder count request validation", () => {
for (const value of [[], {}, 1, "../private", "a/../b", "/src", "src/", "x".repeat(4097)]) {
it(`rejects invalid scope ${JSON.stringify(value).slice(0, 30)}`, async () => {
const error = await folderCounts({}, value).then(() => null, error => error);
expect(error.message).to.equal("invalid_path"); expect(error.httpStatus).to.equal(400);
});
}
});
(uri ? describe : describe.skip)("scoped folder counts with MongoDB", function () {
this.timeout(60000);
let repo;
before(async () => {
if (!/\/perf_test_[A-Za-z0-9_-]+(?:\?|$)/.test(uri)) throw Error("An isolated perf_test_ database is required");
await mongoose.connect(uri); db.isConnected = true;
await Promise.all([Repo, File, Path].map(model => model.createIndexes()));
});
after(async () => { db.isConnected = false; await mongoose.connection.dropDatabase(); await mongoose.disconnect(); });
beforeEach(async () => {
await Promise.all([Repo, File, Path].map(model => model.deleteMany({})));
repo = new Repository(await Repo.create({ repoId: "counts", owner: new mongoose.Types.ObjectId(), status: "ready",
statusDate: new Date(), anonymizeDate: new Date(), treeGeneration: "active", source: { type: "GitHubStream", repositoryName: "fixture/repo" }, options: { terms: [] } }));
});
const insert = rows => File.insertMany(rows.map(row => ({ repoId: "counts", treeGeneration: "active", ...row })));
it("returns only the current directory and immediate children across a large deep tree", async () => {
await insert([{ name: "src", path: "" }, { name: "root.txt", path: "", size: 1 }]);
for (let offset = 0; offset < 12000; offset += 500) await insert(Array.from({ length: 500 }, (_, i) => ({
name: "file.txt", path: `src/deep/folder${offset + i}`, size: 1,
})));
await insert([{ name: "ignored.txt", path: "staged", size: 1, treeGeneration: "staged" },
{ name: "ignored.txt", path: "old", size: 1, treeGeneration: "old" }]);
expect(await folderCounts(repo, "")).to.deep.equal({ "": 12001, src: 12000 });
expect(await folderCounts(repo, "src")).to.deep.equal({ src: 12000, "src/deep": 12000 });
});
it("escapes regex punctuation and handles Unicode scopes and empty directories", async () => {
await insert([{ path: "", name: "猫.[x]" }, { path: "猫.[x]", name: "empty" },
{ path: "猫.[x]/child", name: "a", size: 0 }, { path: "猫.[x]", name: "b", size: 2 },
{ path: "猫Xx/not-this-folder", name: "no", size: 3 }]);
expect(await folderCounts(repo, "猫.[x]")).to.deep.equal({ "猫.[x]": 2, "猫.[x]/child": 1 });
expect(await folderCounts(repo, "猫.[x]/empty")).to.deep.equal({ "猫.[x]/empty": 0 });
});
it("anonymizes child keys, sums collisions and resolves the same directory as browsing", async () => {
repo.model.options.terms = ["Alice|Bob"];
await repo.model.save();
await insert([{ name: "Alice", path: "" }, { name: "Bob", path: "" },
{ name: "one", path: "Alice/sub", size: 1 }, { name: "two", path: "Bob/sub", size: 1 }]);
const root = await folderCounts(repo, "");
expect(root).to.deep.equal({ "": 2, "XXXX-1": 2 });
const scoped = await folderCounts(repo, "XXXX-1");
expect(scoped).to.deep.equal({ "XXXX-1": 1, "XXXX-1/sub": 1 });
expect(JSON.stringify(scoped)).not.to.match(/Alice|Bob/);
});
it("uses the active generation on each request without reusing obsolete counts", async () => {
await insert([{ path: "old", name: "a", size: 1 }]);
expect(await folderCounts(repo, "")).to.deep.equal({ "": 1, old: 1 });
await insert([{ path: "new", name: "b", size: 1, treeGeneration: "replacement" },
{ path: "new", name: "c", size: 1, treeGeneration: "replacement" }]);
repo.model.treeGeneration = "replacement"; await repo.model.save();
expect(await folderCounts(new Repository(await Repo.findById(repo.model._id)), "")).to.deep.equal({ "": 2, new: 2 });
});
it("keeps a hard bound for over-wide responses", async () => {
for (let offset = 0; offset <= FILE_LISTING_LIMIT; offset += 500) await insert(Array.from({
length: Math.min(500, FILE_LISTING_LIMIT + 1 - offset),
}, (_, i) => ({ name: "a", path: `folder${offset + i}`, size: 1 })));
const error = await folderCounts(repo, "").then(() => null, error => error);
expect(error.message).to.equal("file_listing_too_large"); expect(error.httpStatus).to.equal(413);
});
it("runs the scoped route only after authorization and rejects object scopes", async () => {
const utils = require("../src/server/routes/route-utils");
const original = { getRepo: utils.getRepo, handleError: utils.handleError };
const router = require("../src/server/routes/repository-public").default;
const handler = router.stack.find(layer => layer.route?.path === "/:repoId/files/counts").route.stack.at(-1).handle;
const res = { header() {}, json() { throw Error("must not return counts"); } };
try {
utils.getRepo = async () => null;
await handler({ query: { path: {} } }, res);
utils.getRepo = async () => repo; utils.handleError = error => { throw error; };
const error = await handler({ query: { path: {} } }, res).then(() => null, error => error);
expect(error.httpStatus).to.equal(400);
} finally { Object.assign(utils, original); }
});
});
+50
View File
@@ -1618,6 +1618,56 @@ describe("Vue 3 UI", function () {
expect(ui.errors).to.deep.equal([]);
});
it("loads scoped folder counts lazily without delaying content and does not refetch on reopen", async function () {
let finishRootCounts;
ui = await browser("/r/test/hello.txt", {
"/api/repo/test/files/": request => request.url.searchParams.get("path") === "src"
? [{ name: "a.txt", path: "src", size: 3 }, { name: "b.txt", path: "src", size: 3 }]
: [{ name: "hello.txt", path: "", size: 3 }, { name: "src", path: "" }],
"/api/repo/test/files/counts": request => request.url.searchParams.get("path") === "src"
? { src: 2 } : new Promise(resolve => { finishRootCounts = resolve; }),
});
expect(ui.window.document.querySelector(".project-file-count")).to.equal(null);
expect(ui.requests.filter(r => /files\/counts$/.test(r.url.pathname)).map(r => r.url.searchParams.get("path"))).to.deep.equal([""]);
finishRootCounts({ "": 3, src: 2 });
await delay(30);
expect(ui.window.document.querySelector(".project-file-count").textContent).to.equal("3 files");
const folder = () => ui.window.document.querySelector('tree a[data-path="/src"]');
folder().click(); await delay(90);
expect(ui.window.document.querySelector('tree a[data-path="/src/a.txt"]')).not.to.equal(null);
folder().click(); await delay(10); folder().click(); await delay(10);
expect(ui.requests.filter(r => /files\/counts$/.test(r.url.pathname)).map(r => r.url.searchParams.get("path"))).to.deep.equal(["", "src"]);
expect(ui.errors).to.deep.equal([]);
});
for (const status of [413, 429, 503]) it(`keeps browsing without count badges or retries after counts return ${status}`, async function () {
ui = await browser("/r/test/hello.txt", {
"/api/repo/test/files/": request => request.url.searchParams.get("path") === "src"
? [{ name: "a.txt", path: "src", size: 3 }]
: [{ name: "hello.txt", path: "", size: 3 }, { name: "src", path: "" }],
"/api/repo/test/files/counts": { __status: status, body: { error: "file_listing_too_large" } },
});
await delay(20);
expect(ui.window.document.querySelector(".project-file-count")).to.equal(null);
ui.window.document.querySelector('tree a[data-path="/src"]').click(); await delay(30);
expect(ui.window.document.querySelector('tree a[data-path="/src/a.txt"]')).not.to.equal(null);
expect(ui.requests.filter(r => /files\/counts$/.test(r.url.pathname))).to.have.length(1);
expect(ui.window.document.querySelector(".tree-count")).to.equal(null);
expect(ui.errors).to.deep.equal([]);
});
it("ignores a previous repository's delayed counts after navigation", async function () {
let finish;
ui = await browser("/r/test/hello.txt", {
"/api/repo/test/files/counts": () => new Promise(resolve => { finish = resolve; }),
"/api/repo/other/files/counts": { "": 9 },
});
await ui.go("/r/other/hello.txt");
finish({ "": 999 }); await delay(30);
expect(ui.window.document.querySelector(".project-file-count").textContent).to.equal("9 files");
expect(ui.errors).to.deep.equal([]);
});
it("starts folders collapsed and opens the selected file's ancestors", async function () {
ui = await browser("/r/test/hello.txt", {
"/api/repo/test/files/": [
+52
View File
@@ -0,0 +1,52 @@
/* global fetch */
const { expect } = require("chai");
const express = require("express");
const { rateLimit } = require("express-rate-limit");
require("ts-node/register/transpile-only");
const config = require("../src/config").default;
const { createWebsiteRateLimiter } = require("../src/server/website-rate-limit");
const { requestRateLimitKey } = require("../src/server/rate-limit-key");
describe("website request budget", function () {
it("isolates page bursts from the API and keeps a shared website cap across repositories", async () => {
const previous = config.WEBSITE_RATE_LIMIT;
config.WEBSITE_RATE_LIMIT = 3;
const app = express();
app.set("trust proxy", "loopback");
app.use("/api", rateLimit({ windowMs: 60000, limit: 1, keyGenerator: requestRateLimitKey }), (_req, res) => res.send("api"));
app.use("/w", createWebsiteRateLimiter(), (_req, res) => res.send("asset"));
let server;
await new Promise(resolve => { server = app.listen(0, "127.0.0.1", resolve); });
const get = (path, ip = "192.0.2.1", forged = "198.51.100.1") => fetch(`http://127.0.0.1:${server.address().port}${path}`, {
headers: { "x-forwarded-for": ip, "cf-connecting-ip": forged },
});
try {
for (const path of ["/w/one/index.html", "/w/one/image.webp", "/w/two/style.css"]) expect((await get(path)).status).to.equal(200);
const blocked = await get("/w/three/app.js", "192.0.2.1", "198.51.100.2");
expect(blocked.status).to.equal(429);
expect(Number(blocked.headers.get("retry-after"))).to.be.greaterThan(0);
expect((await blocked.json()).error).to.equal("rate_limited");
expect((await get("/api/options")).status).to.equal(200);
expect((await get("/api/options")).status).to.equal(429);
expect((await get("/w/one/image.webp", "192.0.2.2")).status).to.equal(200);
// Exhausting this visitor's API allowance does not consume website hits.
expect((await get("/api/options", "192.0.2.3")).status).to.equal(200);
expect((await get("/api/options", "192.0.2.3")).status).to.equal(429);
expect((await get("/w/one/image.webp", "192.0.2.3")).status).to.equal(200);
} finally {
config.WEBSITE_RATE_LIMIT = previous;
server.closeAllConnections();
await new Promise(resolve => server.close(resolve));
}
});
it("refuses disabled or invalid website limits", () => {
const previous = config.WEBSITE_RATE_LIMIT;
try {
for (const value of [0, -1, 1.5, NaN]) {
config.WEBSITE_RATE_LIMIT = value;
expect(() => createWebsiteRateLimiter()).to.throw("positive integer");
}
} finally { config.WEBSITE_RATE_LIMIT = previous; }
});
});