Read-only access to the repositories you choose.
+Read-only access to gists and the repositories you choose.
{{ connections.appError }}. Reconnect to restore access.
For existing OAuth anonymizations and gists.
+For existing OAuth anonymizations.
This connection uses GitHub's broader repository permissions. Existing work keeps using it until you switch below.
{{ connections.oauthConnected ? 'Reconnect OAuth' : 'Connect legacy OAuth' }}{{ connections.gistCount }} gist(s) still require OAuth.
-Switch all dependent repositories before revoking access. Gists still require OAuth.
- +{{ connections.gistCount }} gist(s) use your GitHub App connection when available.
+Switch all dependent repositories before revoking access. Gists can use your GitHub App connection.
+- The GitHub App has read-only access to the repositories you choose. - Legacy OAuth uses broader permissions and is still needed for gists. + The GitHub App has read-only access to gists and the repositories you choose. + Legacy OAuth uses broader permissions. Anonymous GitHub never writes to your repositories.
Loading GitHub info for "+E.repoId+"..."),t.get("/api/admin/repos/"+E.repoId+"/github").then(R=>{k&&(k.document.open(),k.document.write('
'+JSON.stringify(R.data,null,2).replace(/[<>]/g,D=>D==="<"?"<":">")+""),k.document.close())},R=>{let D=R&&R.data?JSON.stringify(R.data,null,2):String(R);k&&(k.document.body.innerHTML='
'+D+"")})},e.statusCountFor=E=>{let k=(e.statusCounts||[]).find(R=>R._id===E);return k?k.count:0},e.statusStorageFor=E=>{let k=(e.statusCounts||[]).find(R=>R._id===E);return k?k.storage:0},e.isErrorsOnly=()=>e.query&&e.query.error&&!e.query.ready&&!e.query.preparing&&!e.query.expired&&!e.query.removed,e.toggleErrorsOnly=()=>{e.isErrorsOnly()?Object.assign(e.query,{ready:!1,preparing:!0,expired:!1,removed:!1,error:!0}):Object.assign(e.query,{ready:!1,preparing:!1,expired:!1,removed:!1,error:!0}),e.query.page=1},e.toggleSortDirection=()=>{e.query.direction=e.query.direction==="asc"?"desc":"asc"},e.sortBy=E=>{e.query.sort===E?e.query.direction=e.query.direction==="asc"?"desc":"asc":(e.query.sort=E,e.query.direction="desc"),e.query.page=1},e.sortIcon=E=>e.query.sort===E?e.query.direction==="asc"?"fa-arrow-up":"fa-arrow-down":"";let u="admin.repos.filterPrefs",f={page:1,limit:25,sort:"lastView",direction:"desc",search:"",owner:"",conference:"",dateFrom:"",dateTo:"",ready:!1,expired:!1,removed:!1,error:!0,preparing:!0},m=loadFilterPrefs(u)||{};e.query=Object.assign({},f,m,{page:1,search:""});let g=n.search();g.owner&&(e.query.owner=g.owner),g.conference&&(e.query.conference=g.conference),g.search&&(e.query.search=g.search);let w="admin.repos.presets";e.presets=JSON.parse(localStorage.getItem(w)||"[]"),e.savePreset=()=>{let E=window.prompt("Preset name:");if(!E)return;let k=Object.assign({},e.query);delete k.page,e.presets=(e.presets||[]).filter(R=>R.name!==E),e.presets.push({name:E,query:k}),localStorage.setItem(w,JSON.stringify(e.presets))},e.applyPreset=E=>{Object.assign(e.query,E.query,{page:1})},e.deletePreset=E=>{e.presets=(e.presets||[]).filter(k=>k.name!==E.name),localStorage.setItem(w,JSON.stringify(e.presets))},e.selectAllOnPage=()=>{e.allSelected=!e.allSelected,e.repositories.forEach(E=>{e.selected[E.repoId]=e.allSelected})},e.selectedCount=()=>Object.values(e.selected||{}).filter(Boolean).length,e.selectedRepos=()=>e.repositories.filter(E=>e.selected[E.repoId]),e.bulkRefresh=()=>{let E=e.selectedRepos();E.length&&confirm(`Force refresh ${E.length} repositories?`)&&E.forEach(k=>e.updateRepository(k))},e.bulkRemoveCache=()=>{let E=e.selectedRepos();E.length&&confirm(`Purge cache for ${E.length} repositories?`)&&E.forEach(k=>e.removeCache(k))},e.clearSelection=()=>{e.selected={},e.allSelected=!1},e.exportCsv=()=>{let E=new URLSearchParams(Object.entries(e.query).filter(([,k])=>k!==""&&k!==!1&&k!=null));E.set("format","csv"),E.set("limit","10000"),window.open("/api/admin/repos?"+E.toString(),"_blank")},e.removeCache=E=>{confirm("Remove cached files for "+E.repoId+"?")&&t.delete("/api/admin/repos/"+E.repoId).then(()=>h(),k=>console.error(k))},e.removeRepository=E=>{confirm("Remove repository "+E.repoId+"?")&&t.delete("/api/repo/"+E.repoId+"/").then(()=>h(),k=>console.error(k))},e.updateRepository=E=>{let k=He({title:`Refreshing ${E.repoId}...`,date:new Date,body:`The repository ${E.repoId} is going to be refreshed.`});e.toasts.push(k),t.post(`/api/repo/${E.repoId}/refresh`).then(R=>{R.data.status=="ready"?k.title=`${E.repoId} is refreshed.`:k.title=`Refreshing of ${E.repoId}.`},R=>{k.title=`Error during the refresh of ${E.repoId}.`,k.body=R.body})},e.fetchError=null;function h(){e.fetchError=null,t.get("/api/admin/repos",{params:e.query}).then(E=>{e.total=E.data.total,e.totalPage=Math.ceil(E.data.total/e.query.limit),e.repositories=E.data.results,e.statusCounts=E.data.statusCounts||[],e.totalSize=E.data.totalSize||0,e.allSelected=!1},E=>{e.fetchError=E&&E.data&&E.data.error||"Failed to load repositories",console.error(E)})}h();let b=null;e.watch("query",()=>{r.timeout.cancel(b),b=r.timeout(h,500);let{page:E,search:k,...R}=e.query;saveFilterPrefs(u,R),a()},!0),a()},Ja=function(e,t,n){let r=ct(),s=Kt();e.Math=Math,e.watch("user.status",()=>{e.user==null&&n.url("/")}),e.user==null&&n.url("/"),e.users=[],e.total=-1,e.totalPage=0,e.statusCounts=[],e.selected={},e.allSelected=!1;let i=h=>{if(h.key==="/"&&!["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName)){h.preventDefault();let b=document.querySelector('.admin-filter-toolbar input[type="search"]');b&&b.focus()}};s(document,"keydown",i),e.on("dispose",()=>document.removeEventListener("keydown",i)),e.clearFilter=h=>{h==="dateRange"?(e.query.dateFrom="",e.query.dateTo=""):e.query[h]="",e.query.page=1},e.chips=[];let a=()=>{let h=[];e.query.role&&h.push({key:"role",label:"Role",value:e.query.role}),e.chips=h};e.statusCountFor=h=>{let b=(e.statusCounts||[]).find(E=>E._id===h);return b?b.count:0},e.toggleSortDirection=()=>{e.query.direction=e.query.direction==="asc"?"desc":"asc"},e.sortBy=h=>{e.query.sort===h?e.query.direction=e.query.direction==="asc"?"desc":"asc":(e.query.sort=h,e.query.direction="desc"),e.query.page=1},e.sortIcon=h=>e.query.sort===h?e.query.direction==="asc"?"fa-arrow-up":"fa-arrow-down":"";let u="admin.users.filterPrefs",f={page:1,limit:25,sort:"username",direction:"asc",search:"",status:"",role:"",dateFrom:"",dateTo:""},m=loadFilterPrefs(u)||{};e.query=Object.assign({},f,m,{page:1,search:""}),e.selectAllOnPage=()=>{e.allSelected=!e.allSelected,e.users.forEach(h=>{e.selected[h.username]=e.allSelected})},e.selectedCount=()=>Object.values(e.selected||{}).filter(Boolean).length,e.selectedUsers=()=>e.users.filter(h=>e.selected[h.username]),e.banUser=h=>{confirm(`Ban user ${h.username}?`)&&t.post(`/api/admin/users/${h.username}/ban`).then(g,b=>console.error(b))},e.activateUser=h=>{t.post(`/api/admin/users/${h.username}/activate`).then(g,b=>console.error(b))},e.bulkBan=()=>{let h=e.selectedUsers();h.length&&confirm(`Ban ${h.length} users?`)&&h.forEach(b=>e.banUser(b))},e.exportCsv=()=>{let h=new URLSearchParams(Object.entries(e.query).filter(([,b])=>b!==""&&b!==!1&&b!=null));h.set("format","csv"),h.set("limit","10000"),window.open("/api/admin/users?"+h.toString(),"_blank")},e.fetchError=null;function g(){e.fetchError=null,t.get("/api/admin/users",{params:e.query}).then(h=>{e.total=h.data.total,e.totalPage=Math.ceil(h.data.total/e.query.limit),e.users=h.data.results,e.statusCounts=h.data.statusCounts||[],e.allSelected=!1},h=>{e.fetchError=h&&h.data&&h.data.error||"Failed to load users",console.error(h)})}g();let w=null;e.watch("query",()=>{r.timeout.cancel(w),w=r.timeout(g,500);let{page:h,search:b,...E}=e.query;saveFilterPrefs(u,E),a()},!0),a()},Qa=function(e,t,n,r){let s=ct();e.watch("user.status",()=>{e.user==null&&n.url("/")}),e.user==null&&n.url("/"),e.userInfo,e.repositories=[],e.search="",e.selected={},e.allSelected=!1;let i="admin.user.filterPrefs",a={filters:{status:{ready:!0,expired:!0,removed:!0,error:!0,preparing:!0}},sort:"anonymizeDate",direction:"desc"},u=loadFilterPrefs(i)||{};e.filters={status:Object.assign({},a.filters.status,u.filters&&u.filters.status||{})},e.query={sort:u.sort||a.sort,direction:u.direction||a.direction},e.orderBy=(e.query.direction==="asc"?"":"-")+e.query.sort,e.sortBy=h=>{e.query.sort===h?e.query.direction=e.query.direction==="asc"?"desc":"asc":(e.query.sort=h,e.query.direction="desc"),e.orderBy=(e.query.direction==="asc"?"":"-")+e.query.sort},e.sortIcon=h=>e.query.sort===h?e.query.direction==="asc"?"fa-arrow-up":"fa-arrow-down":"",e.watch("query",()=>{saveFilterPrefs(i,{filters:e.filters,sort:e.query.sort,direction:e.query.direction})},!0),e.watch("filters",()=>{saveFilterPrefs(i,{filters:e.filters,sort:e.query.sort,direction:e.query.direction})},!0),e.statusCountFor=h=>(e.repositories||[]).filter(b=>b.status===h).length,e.repoFiler=h=>e.filters.status[h.status]==!1?!1:!!(e.search.trim().length==0||h.source.fullName.indexOf(e.search)>-1||h.repoId.indexOf(e.search)>-1||h.statusMessage&&h.statusMessage.indexOf(e.search)>-1||h.conference&&h.conference.indexOf(e.search)>-1),e.selectAllOnPage=()=>{e.allSelected=!e.allSelected,(e.filteredRepositories||e.repositories).forEach(h=>{e.selected[h.repoId]=e.allSelected})},e.selectedCount=()=>Object.values(e.selected||{}).filter(Boolean).length,e.selectedRepos=()=>e.repositories.filter(h=>e.selected[h.repoId]),e.bulkRefresh=()=>{let h=e.selectedRepos();h.length&&confirm(`Force refresh ${h.length} repositories?`)&&h.forEach(b=>e.updateRepository(b))},e.bulkRemoveCache=()=>{let h=e.selectedRepos();h.length&&confirm(`Purge cache for ${h.length} repositories?`)&&h.forEach(b=>e.removeCache(b))},e.clearSelection=()=>{e.selected={},e.allSelected=!1},e.exportCsv=()=>{let h=e.filteredRepositories||e.repositories,E=["repoId","status","statusMessage","pageView","anonymizeDate","source.fullName","conference","size.storage"].join(","),k=h.map(T=>[T.repoId,T.status,T.statusMessage||"",T.pageView||0,T.anonymizeDate||"",T.source&&T.source.fullName||"",T.conference||"",T.size&&T.size.storage||0].map(P=>{let H=String(P??"");return/[",\n\r]/.test(H)?'"'+H.replace(/"/g,'""')+'"':H}).join(",")),R=new Blob([E+` @@ -18,13 +18,13 @@ while being at `).map((ue,pe)=>pe===0?ue:oe+ue).join(` `)}else typeof C=="number"||typeof C=="boolean"?Q=String(C):Q=JSON.stringify(C);ie.push(`${J}${Q}${ee}`)}),ie.push("}"),ie.join(` `)}function m(D){let T=[],P="",H=/(\w+):(>=|<=|!=|>|<|=)?([^\s]+)/g,q=0,U;for(;U=H.exec(D);)P+=D.slice(q,U.index),q=H.lastIndex,T.push({key:U[1],op:U[2]||"=",val:U[3]});return P+=D.slice(q),{filters:T,free:P.trim().toLowerCase()}}function g(D,T){for(let P of T.filters){let H=(U,ie,re)=>{let C=parseFloat(U),O=parseFloat(ie);return re==="="?String(U)===String(ie):re==="!="?String(U)!==String(ie):re===">="?C>=O:re==="<="?C<=O:re===">"?C>O:re==="<"?C
Manage how GitHub shares your code. Your anonymizations and URLs stay the same.
Sign in to create and manage your anonymizations.
Connect through the GitHub App with read-only repository access.
Sign in with GitHub Your existing anonymizations and connections stay with your account.',6)])])):p("v-if",!0),!e.site_options?.GITHUB_APP_ENABLED&&e.site_options?.GITHUB_OAUTH_ENABLED&&!e.accountRecovery?(l(),d("section",zp,[...t[3]||(t[3]=[o("div",{class:"connection-title"},[o("h2",null,"Continue with GitHub")],-1),o("p",null,"Sign in to access your account. GitHub OAuth includes write access to private repositories.",-1),o("a",{class:"connection-link",target:"_self",href:"/github/login"},[y("Sign in with GitHub "),o("svg",{class:"ui-icon","aria-hidden":"true"},[o("use",{href:"#ui-icon-arrow-right"})])],-1)])])):p("v-if",!0),e.site_options&&!e.site_options.GITHUB_APP_ENABLED&&!e.site_options.GITHUB_OAUTH_ENABLED?(l(),d("p",Hp,"GitHub sign-in is currently unavailable. Please try again later.")):p("v-if",!0)])])])}var jp={class:"paper-empty"};function nl(e,t){return l(),d("div",jp,[...t[0]||(t[0]=[ce('The anonymous mirror you\u2019re looking for has expired, been removed by its owner, or never existed. If you received this URL from an author, ask them to re-issue it.
Fill in the details \u2014 it only takes a minute.
Take ownership of an existing anonymized repository so it appears on your dashboard.
',3)),o("div",kN,[t[5]||(t[5]=o("p",{class:"paper-section-copy"},"Use this when an anonymization was created by a co-author or from another account. You must have access to the GitHub repository it was made from.",-1)),N((l(),d("form",{class:"form needs-validation",name:"claimForm",novalidate:"",onSubmit:t[0]||(t[0]=he(s=>e.submitForm(s,()=>{e.claim()}),["prevent"]))},[o("div",EN,[t[1]||(t[1]=o("label",{class:"paper-field-label",for:"repoUrl"},"GitHub repository URL",-1)),N(o("input",{type:"text",class:A(["form-control",{"is-invalid":e.claimForm?.repoUrl?.invalid&&(e.claimForm?.repoUrl?.touched||e.claimForm?.submitted)}]),name:"repoUrl",id:"repoUrl",required:""},null,2),[[n,{state:e.viewState,set:s=>{e.repoUrl=s},value:e.repoUrl,form:"claimForm",options:{}}]]),N(o("div",CN," No anonymization matches this repository and ID. Check both values and that you can access the repository on GitHub. ",512),[[Y,e.claimForm?.repoUrl?.errors?.not_found]])]),o("div",_N,[t[2]||(t[2]=o("label",{class:"paper-field-label",for:"repoId"},"Anonymized repository ID",-1)),N(o("input",{type:"text",class:A(["form-control",{"is-invalid":e.claimForm?.repoId?.invalid&&(e.claimForm?.repoId?.touched||e.claimForm?.submitted)}]),name:"repoId",id:"repoId",required:""},null,2),[[n,{state:e.viewState,set:s=>{e.repoId=s},value:e.repoId,form:"claimForm",options:{}}]]),t[3]||(t[3]=o("small",{id:"idHelp",class:"form-text text-muted"},[y("The ID is the last part of the anonymized URL: "),o("code",null,"anonymous.4open.science/r/Group anonymizations by venue, give chairs a shared dashboard, and set one expiry for every submission.
If something's missing, write to us \u2014 report a bug on GitHub.
Manage how GitHub shares your code. Your anonymizations and URLs stay the same.
Sign in to create and manage your anonymizations.
Connect through the GitHub App with read-only repository access.
Sign in with GitHub Your existing anonymizations and connections stay with your account.',6)])])):p("v-if",!0),!e.site_options?.GITHUB_APP_ENABLED&&e.site_options?.GITHUB_OAUTH_ENABLED&&!e.accountRecovery?(l(),d("section",zp,[...t[3]||(t[3]=[o("div",{class:"connection-title"},[o("h2",null,"Continue with GitHub")],-1),o("p",null,"Sign in to access your account. GitHub OAuth includes write access to private repositories.",-1),o("a",{class:"connection-link",target:"_self",href:"/github/login"},[y("Sign in with GitHub "),o("svg",{class:"ui-icon","aria-hidden":"true"},[o("use",{href:"#ui-icon-arrow-right"})])],-1)])])):p("v-if",!0),e.site_options&&!e.site_options.GITHUB_APP_ENABLED&&!e.site_options.GITHUB_OAUTH_ENABLED?(l(),d("p",Hp,"GitHub sign-in is currently unavailable. Please try again later.")):p("v-if",!0)])])])}var jp={class:"paper-empty"};function nl(e,t){return l(),d("div",jp,[...t[0]||(t[0]=[ce('The anonymous mirror you\u2019re looking for has expired, been removed by its owner, or never existed. If you received this URL from an author, ask them to re-issue it.
Fill in the details \u2014 it only takes a minute.
Take ownership of an existing anonymized repository so it appears on your dashboard.
',3)),o("div",EN,[t[5]||(t[5]=o("p",{class:"paper-section-copy"},"Use this when an anonymization was created by a co-author or from another account. You must have access to the GitHub repository it was made from.",-1)),N((l(),d("form",{class:"form needs-validation",name:"claimForm",novalidate:"",onSubmit:t[0]||(t[0]=he(s=>e.submitForm(s,()=>{e.claim()}),["prevent"]))},[o("div",CN,[t[1]||(t[1]=o("label",{class:"paper-field-label",for:"repoUrl"},"GitHub repository URL",-1)),N(o("input",{type:"text",class:A(["form-control",{"is-invalid":e.claimForm?.repoUrl?.invalid&&(e.claimForm?.repoUrl?.touched||e.claimForm?.submitted)}]),name:"repoUrl",id:"repoUrl",required:""},null,2),[[n,{state:e.viewState,set:s=>{e.repoUrl=s},value:e.repoUrl,form:"claimForm",options:{}}]]),N(o("div",_N," No anonymization matches this repository and ID. Check both values and that you can access the repository on GitHub. ",512),[[Y,e.claimForm?.repoUrl?.errors?.not_found]])]),o("div",SN,[t[2]||(t[2]=o("label",{class:"paper-field-label",for:"repoId"},"Anonymized repository ID",-1)),N(o("input",{type:"text",class:A(["form-control",{"is-invalid":e.claimForm?.repoId?.invalid&&(e.claimForm?.repoId?.touched||e.claimForm?.submitted)}]),name:"repoId",id:"repoId",required:""},null,2),[[n,{state:e.viewState,set:s=>{e.repoId=s},value:e.repoId,form:"claimForm",options:{}}]]),t[3]||(t[3]=o("small",{id:"idHelp",class:"form-text text-muted"},[y("The ID is the last part of the anonymized URL: "),o("code",null,"anonymous.4open.science/r/Group anonymizations by venue, give chairs a shared dashboard, and set one expiry for every submission.
If something's missing, write to us \u2014 report a bug on GitHub.

The GitHub App has read-only access to the repositories you choose. Legacy OAuth uses broader permissions and is still needed for gists. Anonymous GitHub never writes to your repositories.
Source code with syntax highlighting, Markdown, Jupyter notebooks, PDFs, images, and GitHub Pages sites. Text files are anonymized; enabled images and PDFs are served unchanged.
You choose: the mirror is removed, or visitors are redirected to the original GitHub repository once the review is over.
Track PR mirrors you\u2019ve created and their reviewer traffic.

The GitHub App has read-only access to gists and the repositories you choose. Legacy OAuth uses broader permissions. Anonymous GitHub never writes to your repositories.
Source code with syntax highlighting, Markdown, Jupyter notebooks, PDFs, images, and GitHub Pages sites. Text files are anonymized; enabled images and PDFs are served unchanged.
You choose: the mirror is removed, or visitors are redirected to the original GitHub repository once the review is over.
Track PR mirrors you\u2019ve created and their reviewer traffic.
Defaults applied to every new anonymization, your quotas, and your account.
',3)),o("div",EV,[N((l(),d("aside",CV,[...t[4]||(t[4]=[ce('A small team keeps this running. If it helps you, please consider contributing back \u2014 in code, ideas, or coffee.
Collaborate by implementing new features and fixing bugs. Help with new file formats or deployment is welcome.
Open on GitHubTell us about bugs and missing features in Anonymous GitHub itself. Questions about an anonymized repository go to its authors.
File an issueServer costs hover around $25 a month. Any contribution helps keep the lights on.
GitHub Sponsors| '+(u.oldNo||"")+' | '+(u.newNo||"")+' | '+(u.kind==="add"?"+":u.kind==="remove"?"-":u.kind==="hunk"?"@":"")+' | '+t(u.text)+" |
Defaults applied to every new anonymization, your quotas, and your account.
',3)),o("div",CV,[N((l(),d("aside",_V,[...t[4]||(t[4]=[ce('A small team keeps this running. If it helps you, please consider contributing back \u2014 in code, ideas, or coffee.
Collaborate by implementing new features and fixing bugs. Help with new file formats or deployment is welcome.
Open on GitHubTell us about bugs and missing features in Anonymous GitHub itself. Questions about an anonymized repository go to its authors.
File an issueServer costs hover around $25 a month. Any contribution helps keep the lights on.
GitHub Sponsors| '+(u.oldNo||"")+' | '+(u.newNo||"")+' | '+(u.kind==="add"?"+":u.kind==="remove"?"-":u.kind==="hunk"?"@":"")+' | '+t(u.text)+" |