runlight 0.4.2

Privacy friendly web analytics that lives inside your Rust app: mount a route, add a script tag, read your stats at /runlight
Documentation
1
(function(){var n=window,a=document,m=navigator,i=location,k=a.currentScript;if(k){var s=function(e){return k.getAttribute("data-"+e)},R=k.src.replace(/s\.js(\?.*)?$/,""),E=R+"e",q=E.indexOf(i.origin+"/")?"text/plain":"application/json",L=s("site"),A=s("hash")!==null,H=s("manual")!==null,T=s("before-send"),$=function(e){return new RegExp("^"+e.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$")},K=(s("exclude")||"").split(",").filter(Boolean).map(function(e){return $(e.trim())}),N=!1,z=n.runlight&&n.runlight.q||[],b="__RUNLIGHT_RULES__",B=typeof b=="object"&&(b[L]||b[i.hostname.replace(/^www\./,"")]||b["*"])||[],F=/[?&]runlight=pick\b/.test(i.search)&&/[?&]runlight_ticket=/.test(i.search);if(F){var M=a.createElement("script");M.src=R+"pick.js"+i.search,a.head.appendChild(M)}var D=!1;try{var C=/[?&]runlight=(ignore|track)\b/.exec(i.search),x=localStorage;C&&(C[1]==="ignore"?x.setItem("runlight_ignore","1"):x.removeItem("runlight_ignore")),D=x.getItem("runlight_ignore")==="1"}catch(e){}var Q=F||m.webdriver||D||s("dnt")!==null&&(m.doNotTrack==="1"||n.doNotTrack==="1"),S=function(e,t){if(!(N||Q)){var r={k:e,u:w};L&&(r.s=L);for(var o in t)r[o]=t[o];if(T!==null)try{if(r=n[T](r),!r||r.constructor!==Object)return}catch(g){return}var l=new Blob([JSON.stringify(r)],{type:q});try{if(m.sendBeacon(E,l))return}catch(g){}n.fetch&&fetch(E,{method:"POST",body:l,keepalive:!0}).catch(function(){})}},W=function(){var e=new Uint8Array(6);return crypto.getRandomValues(e),Array.from(e,function(t){return(t+256).toString(36).slice(-2)}).join("")},G=s("404")!==null,w="",c="",f=0,d=0,y=0,X=function(){return a.visibilityState==="visible"&&a.hasFocus()},J=function(){d&&(f+=Date.now()-d),d=0},v=function(){!d&&X()&&(d=Date.now())},_=function(){J(),c&&f>=1e3&&(S("engagement",{i:c,e:f,d:y}),f=0)},P=function(){var e=a.documentElement,t=Math.max(e.scrollHeight,a.body?a.body.scrollHeight:0),r=n.scrollY+n.innerHeight,o=t>0?Math.min(100,Math.round(r/t*100)):100;o>y&&(y=o)},Z=function(){return i.origin+i.pathname+i.search+(A?i.hash:"")},h=function(e){var t=typeof e=="string"?new URL(e,i.href).href:Z();if(t!==w){var r=w||a.referrer;_(),w=t;var o=new URL(t).pathname;N=K.some(function(l){return l.test(o)}),c=W(),f=0,y=0,P(),v(),S("pageview",{i:c,r,t:a.title,w:screen.width,h:screen.height,l:m.language}),G&&u("404",{path:i.pathname}),G=!1}},u=function(e,t){typeof e!="string"||!e||S("event",{i:c,n:e,p:t&&typeof t=="object"?t:void 0})},V=function(e){var t=history[e];history[e]=function(){var r=t.apply(this,arguments);return setTimeout(h),r}};H||(V("pushState"),V("replaceState"),n.addEventListener("popstate",h),A&&n.addEventListener("hashchange",h)),a.addEventListener("visibilitychange",function(){a.visibilityState==="hidden"?_():v()}),n.addEventListener("pagehide",_),n.addEventListener("blur",J),n.addEventListener("focus",v),n.addEventListener("scroll",function(){P(),v()},{passive:!0}),a.addEventListener("pointerdown",v,!0),a.addEventListener("keydown",v,!0);var ee=/\.(pdf|zip|gz|tgz|dmg|pkg|exe|msi|apk|docx?|xlsx?|pptx?|csv|txt|rtf|epub|mp3|wav|mp4|mov|avi|mkv|psd|ai|svg|key|numbers|pages)$/i;a.addEventListener("click",function(e){var t=e.target;if(!(!t||!t.closest)){for(var r=t.closest("a[href]"),o=0;o<B.length;o++)try{var l=B[o],g=l[1];(l[0]==="s"?t.closest(g):r&&$(g).test(g.charAt(0)==="/"?r.pathname:r.href))&&u(l[2])}catch(te){}var p=t.closest("[data-runlight]");if(p){for(var Y={},U=0;U<p.attributes.length;U++){var I=p.attributes[U];I.name.indexOf("data-runlight-")===0&&(Y[I.name.slice(14)]=I.value)}u(p.getAttribute("data-runlight"),Y)}if(!(!r||p)){var O=r.href;/^https?:/.test(O)&&(s("downloads")!=="false"&&ee.test(r.pathname)?u("File download",{url:O}):s("outbound")!=="false"&&r.host!==i.host&&u("Outbound link",{url:O}))}}},!0),n.runlight=u,u.pageview=h,H||h();for(var j=0;j<z.length;j++)u.apply(null,z[j])}})();